Files
EpicNext-Cms/src/lib/theme-presets.ts
T
Simo f7b3845131 Close the web-feasible 100% gaps: REST write/token API, tickets, draw-badge, /me, sanitisation, dusk, radio SSE
Final parity push (web-tier only):
- REST API write + token auth: POST /api/tokens (issue a personal_access_token
  for the session user), Bearer auth via src/lib/api-auth.ts, POST
  /api/articles/[slug]/comment, GET/DELETE /api/me/tokens, full tickets API
  (/api/tickets +[id] +[id]/reply), radio current-dj/points/points-leaderboard/
  embed-config + POST shouts, and a real-time /api/radio/stream (SSE). 31 public
  API routes total.
- Pages: /draw-badge (buy a custom profile badge → credits + RCON), /me
  dashboard (stats + online friends + referral claim). Wired into the nav.
- HTML sanitisation (sanitize-html) — the HTMLPurifier equivalent — applied to
  writeable boxes + article bodies before dangerouslySetInnerHTML.
- "Dusk" dark theme preset + a default-dark site option honoured by the
  no-flash boot script.

Verified live (prod, amx_test): token issue → Bearer endpoint 200, no-token
401; /api/me/tokens lists it; current-dj/leaderboard JSON; /me + /draw-badge
200; reverted the test user + tokens. tsc 0, vitest 49/49, next build 0.
2026-06-29 18:15:01 +02:00

244 lines
7.3 KiB
TypeScript

// Theme constants shared by the admin Theme page and its server action. Kept in
// a plain module because a "use server" file may only export async functions.
// Selectable body fonts. Web-safe stacks render with no extra request; the few
// Google fonts load via a <link> ThemeVars injects when chosen.
export const FONTS: Record<string, { label: string; stack: string; google?: string }> = {
nunito: { label: "Nunito (default)", stack: 'var(--font-nunito), "Nunito", sans-serif' },
system: { label: "System", stack: 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif' },
inter: {
label: "Inter",
stack: '"Inter", sans-serif',
google: "Inter:wght@400;600;700;800",
},
poppins: {
label: "Poppins",
stack: '"Poppins", sans-serif',
google: "Poppins:wght@400;600;700;800",
},
roboto: { label: "Roboto", stack: '"Roboto", sans-serif', google: "Roboto:wght@400;500;700" },
georgia: { label: "Georgia (serif)", stack: 'Georgia, "Times New Roman", serif' },
trebuchet: { label: "Trebuchet", stack: '"Trebuchet MS", Verdana, sans-serif' },
verdana: { label: "Verdana", stack: "Verdana, Geneva, sans-serif" },
comic: { label: "Comic (retro)", stack: '"Comic Sans MS", "Comic Sans", cursive' },
mono: { label: "Monospace", stack: '"Courier New", ui-monospace, monospace' },
};
// The colour settings ThemeVars injects into :root. Editing these recolours the
// whole site live (ThemeVars reads them on every request).
export const THEME_COLOR_KEYS = [
"color_primary",
"color_background",
"color_surface",
"color_dropdown",
"color_navbar",
"color_navbar_text",
"color_text",
"color_text_muted",
"color_accent",
"button_primary_color",
"button_text_color",
"border_color",
] as const;
// Curated palettes (faithful to the atom theme presets). Each is a full set of
// the colour keys above so applying one fully reskins the site.
export const PRESETS: Record<string, Record<string, string>> = {
"Atom (golden)": {
color_primary: "#f59e0b",
color_background: "#f8fafc",
color_surface: "#ffffff",
color_dropdown: "#ffffff",
color_navbar: "#ffffff",
color_navbar_text: "#1e293b",
color_text: "#0f172a",
color_text_muted: "#64748b",
color_accent: "#10b981",
button_primary_color: "#f59e0b",
button_text_color: "#1e293b",
border_color: "#eeb425",
},
Midnight: {
color_primary: "#eeb425",
color_background: "#0f1117",
color_surface: "#171a21",
color_dropdown: "#1f242d",
color_navbar: "#171a21",
color_navbar_text: "#e5e7eb",
color_text: "#e5e7eb",
color_text_muted: "#9ca3af",
color_accent: "#22c55e",
button_primary_color: "#eeb425",
button_text_color: "#1a1a2e",
border_color: "#eeb425",
},
Ocean: {
color_primary: "#0ea5e9",
color_background: "#f0f9ff",
color_surface: "#ffffff",
color_dropdown: "#ffffff",
color_navbar: "#ffffff",
color_navbar_text: "#0c4a6e",
color_text: "#082f49",
color_text_muted: "#64748b",
color_accent: "#14b8a6",
button_primary_color: "#0ea5e9",
button_text_color: "#ffffff",
border_color: "#38bdf8",
},
Forest: {
color_primary: "#16a34a",
color_background: "#f3faf4",
color_surface: "#ffffff",
color_dropdown: "#ffffff",
color_navbar: "#ffffff",
color_navbar_text: "#14532d",
color_text: "#052e16",
color_text_muted: "#5f6b63",
color_accent: "#84cc16",
button_primary_color: "#16a34a",
button_text_color: "#ffffff",
border_color: "#22c55e",
},
Sunset: {
color_primary: "#f97316",
color_background: "#fff7ed",
color_surface: "#ffffff",
color_dropdown: "#ffffff",
color_navbar: "#ffffff",
color_navbar_text: "#7c2d12",
color_text: "#431407",
color_text_muted: "#78716c",
color_accent: "#ec4899",
button_primary_color: "#f97316",
button_text_color: "#ffffff",
border_color: "#fb923c",
},
Candy: {
color_primary: "#ec4899",
color_background: "#fdf2f8",
color_surface: "#ffffff",
color_dropdown: "#ffffff",
color_navbar: "#ffffff",
color_navbar_text: "#831843",
color_text: "#500724",
color_text_muted: "#9d6b80",
color_accent: "#a855f7",
button_primary_color: "#ec4899",
button_text_color: "#ffffff",
border_color: "#f472b6",
},
Galaxy: {
color_primary: "#a855f7",
color_background: "#0b0a1f",
color_surface: "#171430",
color_dropdown: "#211d44",
color_navbar: "#171430",
color_navbar_text: "#e9e5ff",
color_text: "#e9e5ff",
color_text_muted: "#a39dcf",
color_accent: "#22d3ee",
button_primary_color: "#a855f7",
button_text_color: "#ffffff",
border_color: "#7c3aed",
},
Royal: {
color_primary: "#4f46e5",
color_background: "#f5f6ff",
color_surface: "#ffffff",
color_dropdown: "#ffffff",
color_navbar: "#ffffff",
color_navbar_text: "#1e1b4b",
color_text: "#1e1b4b",
color_text_muted: "#636681",
color_accent: "#d97706",
button_primary_color: "#4f46e5",
button_text_color: "#ffffff",
border_color: "#818cf8",
},
Cyberpunk: {
color_primary: "#f0db4f",
color_background: "#0d0221",
color_surface: "#190933",
color_dropdown: "#241046",
color_navbar: "#190933",
color_navbar_text: "#f0db4f",
color_text: "#f5e9ff",
color_text_muted: "#b08fd6",
color_accent: "#ff2a6d",
button_primary_color: "#ff2a6d",
button_text_color: "#ffffff",
border_color: "#05d9e8",
},
Neon: {
color_primary: "#39ff14",
color_background: "#0a0a0a",
color_surface: "#141414",
color_dropdown: "#1d1d1d",
color_navbar: "#141414",
color_navbar_text: "#39ff14",
color_text: "#e8ffe8",
color_text_muted: "#7fae7f",
color_accent: "#ff00ff",
button_primary_color: "#39ff14",
button_text_color: "#0a0a0a",
border_color: "#39ff14",
},
Coffee: {
color_primary: "#a16207",
color_background: "#f5efe6",
color_surface: "#fffaf2",
color_dropdown: "#fffaf2",
color_navbar: "#fffaf2",
color_navbar_text: "#3f2d1c",
color_text: "#3f2d1c",
color_text_muted: "#8a7560",
color_accent: "#15803d",
button_primary_color: "#a16207",
button_text_color: "#ffffff",
border_color: "#ca8a04",
},
Arctic: {
color_primary: "#0891b2",
color_background: "#eef6fb",
color_surface: "#ffffff",
color_dropdown: "#ffffff",
color_navbar: "#ffffff",
color_navbar_text: "#0e3a4f",
color_text: "#0e3a4f",
color_text_muted: "#5b7585",
color_accent: "#6366f1",
button_primary_color: "#0891b2",
button_text_color: "#ffffff",
border_color: "#67e8f9",
},
Christmas: {
color_primary: "#dc2626",
color_background: "#f4faf4",
color_surface: "#ffffff",
color_dropdown: "#ffffff",
color_navbar: "#0f3d24",
color_navbar_text: "#ffffff",
color_text: "#14321f",
color_text_muted: "#5f7a68",
color_accent: "#15803d",
button_primary_color: "#dc2626",
button_text_color: "#ffffff",
border_color: "#16a34a",
},
Dusk: {
color_primary: "#e8a33d",
color_background: "#1b2230",
color_surface: "#232c3d",
color_dropdown: "#2b3548",
color_navbar: "#232c3d",
color_navbar_text: "#dfe5ef",
color_text: "#dfe5ef",
color_text_muted: "#94a0b5",
color_accent: "#5eb0c9",
button_primary_color: "#e8a33d",
button_text_color: "#1b2230",
border_color: "#e8a33d",
},
};