import { Theme } from "@mancala/core"; // The web app's themes. Pages are coloured by the CSS variables of the theme's class (styles/app.css); the colours // here are for code that still reads core's Theme, such as PitAnimator. export type WebTheme = Theme & { // CSS class on . className: string; // Translation key of the theme's name. labelKey: string; // Colours of the theme's swatch. swatch: { board: string, accent: string }; }; const walnut: WebTheme = { id: "ceviz", name: "Ceviz", className: "t-ceviz", labelKey: "ThemeWalnut", swatch: { board: "#6e4a30", accent: "#f2b84b" }, themePreviewColor: "#6e4a30", background: "#1f1712", appBarBgColor: "#2a2019", textColor: "#2a1a0a", textLightColor: "#f6ead8", playerTurnColor: "#f2b84b", boardColor: "#6e4a30", pitColor: "#2c1d13", pitSelectedColor: "#f2b84b", stoneColor: "#e39a32", stoneLightColor: "#fff1c9", pitGameMoveAnimateColor: "#f2b84b", pitEmptyPitAnimateColor: "#ff8a73", pitLastStoneInBankPitAnimateColor: "#f2b84b", pitGetRivalStonePitAnimateColor: "#ff8a73", }; const night: WebTheme = { id: "gece", name: "Gece", className: "t-gece", labelKey: "ThemeNight", swatch: { board: "#1d2a4d", accent: "#e2b36a" }, themePreviewColor: "#1d2a4d", background: "#0c1220", appBarBgColor: "#141c30", textColor: "#241707", textLightColor: "#eef1f8", playerTurnColor: "#e2b36a", boardColor: "#1d2a4d", pitColor: "#0b1020", pitSelectedColor: "#e2b36a", stoneColor: "#dfe3ee", stoneLightColor: "#ffffff", pitGameMoveAnimateColor: "#e2b36a", pitEmptyPitAnimateColor: "#ff8a7a", pitLastStoneInBankPitAnimateColor: "#e2b36a", pitGetRivalStonePitAnimateColor: "#ff8a7a", }; const jade: WebTheme = { id: "yesim", name: "Yeşim", className: "t-yesim", labelKey: "ThemeJade", swatch: { board: "#cfd2c3", accent: "#2a7650" }, themePreviewColor: "#cfd2c3", background: "#e9ebe3", appBarBgColor: "#f7f8f3", textColor: "#1d2721", textLightColor: "#ffffff", playerTurnColor: "#2a7650", boardColor: "#cfd2c3", pitColor: "#c3c7b6", pitSelectedColor: "#2a7650", stoneColor: "#3f9f6f", stoneLightColor: "#e2ffee", pitGameMoveAnimateColor: "#2a7650", pitEmptyPitAnimateColor: "#b43a26", pitLastStoneInBankPitAnimateColor: "#2a7650", pitGetRivalStonePitAnimateColor: "#b43a26", }; // The first one is the default. export const webThemes: WebTheme[] = [walnut, night, jade]; export function getWebTheme(theme: Theme): WebTheme { return webThemes.find((webTheme) => webTheme.id === theme.id) ?? walnut; } // Puts the theme's class on and remembers the theme for the login pages. export function applyThemeClass(theme: Theme) { const root = document.documentElement; webThemes.forEach((webTheme) => root.classList.remove(webTheme.className)); root.classList.add(getWebTheme(theme).className); saveThemeCookie(theme); } const THEME_COOKIE = "mancala_theme"; const COOKIE_MAX_AGE_SECONDS = 365 * 24 * 60 * 60; // The Keycloak login pages are on another origin and read the theme from this cookie (docs/specs/theme-polish). // On localhost a host-only cookie reaches every port; on a domain the cookie is set for its last two labels, so // playmancala.app shares it with auth.playmancala.app. export function saveThemeCookie(theme: Theme) { const { hostname, protocol } = window.location; const isDomain = hostname.includes(".") && !/^[\d.]+$/.test(hostname); const domain = isDomain ? `; domain=${hostname.split(".").slice(-2).join(".")}` : ""; const secure = protocol === "https:" ? "; Secure" : ""; document.cookie = `${THEME_COOKIE}=${getWebTheme(theme).id}; path=/; max-age=${COOKIE_MAX_AGE_SECONDS}; SameSite=Lax${domain}${secure}`; }