mancala/apps/frontend/src/theme/themes.ts

111 lines
3.8 KiB
TypeScript
Raw Normal View History

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 <html>.
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 <html> 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}`;
}