From 17894db3e9e8441801532b32f155744590f4bcd1 Mon Sep 17 00:00:00 2001 From: openhands Date: Mon, 13 Jul 2026 19:58:38 +0200 Subject: [PATCH] Improve theme editor clarity with labels and descriptions - Add a description to every color field explaining what it affects - Regroup colors into Page & text / Buttons & links / Gradients with explanatory section intros for both light and dark mode - Add section intros for light, dark, and admin (HK) modes - Widen color field layout and show descriptions under each label --- src/app/admin/theme/page.tsx | 166 ++++++++++++++++++++++------------- 1 file changed, 103 insertions(+), 63 deletions(-) diff --git a/src/app/admin/theme/page.tsx b/src/app/admin/theme/page.tsx index 707252e4..f5ae142c 100644 --- a/src/app/admin/theme/page.tsx +++ b/src/app/admin/theme/page.tsx @@ -6,39 +6,39 @@ import { FONTS, PRESETS } from "@/lib/theme-presets"; export const dynamic = "force-dynamic"; export const metadata = { title: "Theme" }; -const COLOR_FIELDS: { key: string; label: string; def: string }[] = [ - { key: "color_primary", label: "Primary", def: "#f59e0b" }, - { key: "color_accent", label: "Accent", def: "#10b981" }, - { key: "border_color", label: "Border (golden)", def: "#eeb425" }, - { key: "color_background", label: "Background", def: "#f8fafc" }, - { key: "color_surface", label: "Surface / cards", def: "#ffffff" }, - { key: "color_dropdown", label: "Dropdown", def: "#ffffff" }, - { key: "color_navbar", label: "Navbar", def: "#ffffff" }, - { key: "color_navbar_text", label: "Navbar text", def: "#1e293b" }, - { key: "color_text", label: "Text", def: "#0f172a" }, - { key: "color_text_muted", label: "Muted text", def: "#64748b" }, - { key: "color_success", label: "Success", def: "#16a34a" }, - { key: "color_warning", label: "Warning", def: "#eab308" }, - { key: "color_error", label: "Error", def: "#ef4444" }, - { key: "color_info", label: "Info", def: "#0ea5e9" }, +const COLOR_FIELDS: { key: string; label: string; def: string; desc: string }[] = [ + { key: "color_background", label: "Page background", def: "#f8fafc", desc: "Main page background behind all content" }, + { key: "color_surface", label: "Card / surface", def: "#ffffff", desc: "Cards, panels, and elevated surfaces" }, + { key: "color_dropdown", label: "Dropdown menu", def: "#ffffff", desc: "Dropdown menus and input backgrounds" }, + { key: "color_navbar", label: "Navbar bar", def: "#ffffff", desc: "Top navigation bar background" }, + { key: "color_navbar_text", label: "Navbar text", def: "#1e293b", desc: "Text color in the navigation bar" }, + { key: "color_text", label: "Body text", def: "#0f172a", desc: "Main body text — must contrast with background/surface" }, + { key: "color_text_muted", label: "Muted text", def: "#64748b", desc: "Secondary text, labels, hints — lighter than body text" }, + { key: "color_primary", label: "Primary accent", def: "#f59e0b", desc: "Main brand color, highlights, active elements" }, + { key: "color_accent", label: "Secondary accent", def: "#10b981", desc: "Secondary brand color, success-oriented highlights" }, + { key: "border_color", label: "Border (golden)", def: "#eeb425", desc: "Borders, dividers, outlines" }, + { key: "color_success", label: "Success", def: "#16a34a", desc: "Positive status (green)" }, + { key: "color_warning", label: "Warning", def: "#eab308", desc: "Warning status (yellow)" }, + { key: "color_error", label: "Error", def: "#ef4444", desc: "Error status (red)" }, + { key: "color_info", label: "Info", def: "#0ea5e9", desc: "Info status (blue)" }, ]; -const BUTTON_FIELDS: { key: string; label: string; def: string }[] = [ - { key: "button_primary_color", label: "Primary button", def: "#f59e0b" }, - { key: "button_text_color", label: "Button text", def: "#1e293b" }, - { key: "button_secondary_color", label: "Secondary button", def: "#22c55e" }, - { key: "button_secondary_text_color", label: "Secondary text", def: "#ffffff" }, - { key: "button_danger_color", label: "Danger button", def: "#ef4444" }, - { key: "button_danger_text_color", label: "Danger text", def: "#ffffff" }, - { key: "button_outline_color", label: "Outline button", def: "#eeb425" }, - { key: "button_outline_text_color", label: "Outline text", def: "#1a1a2e" }, - { key: "link_color", label: "Link", def: "#eeb425" }, - { key: "link_hover_color", label: "Link hover", def: "#cf9d15" }, +const BUTTON_FIELDS: { key: string; label: string; def: string; desc: string }[] = [ + { key: "button_primary_color", label: "Primary button", def: "#f59e0b", desc: "Main call-to-action button background" }, + { key: "button_text_color", label: "Button text", def: "#1e293b", desc: "Text on primary buttons — must contrast with button color" }, + { key: "button_secondary_color", label: "Secondary button", def: "#22c55e", desc: "Secondary action button background" }, + { key: "button_secondary_text_color", label: "Secondary text", def: "#ffffff", desc: "Text on secondary buttons" }, + { key: "button_danger_color", label: "Danger button", def: "#ef4444", desc: "Destructive action button (delete, ban)" }, + { key: "button_danger_text_color", label: "Danger text", def: "#ffffff", desc: "Text on danger buttons" }, + { key: "button_outline_color", label: "Outline border", def: "#eeb425", desc: "Outline button border color" }, + { key: "button_outline_text_color", label: "Outline text", def: "#1a1a2e", desc: "Text on outline buttons" }, + { key: "link_color", label: "Link", def: "#eeb425", desc: "Hyperlink text color" }, + { key: "link_hover_color", label: "Link hover", def: "#cf9d15", desc: "Hyperlink text on hover" }, ]; -const GRADIENT_FIELDS: { key: string; label: string; def: string }[] = [ - { key: "gradient_from", label: "Gradient from", def: "#f59e0b" }, - { key: "gradient_to", label: "Gradient to", def: "#10b981" }, +const GRADIENT_FIELDS: { key: string; label: string; def: string; desc: string }[] = [ + { key: "gradient_from", label: "Gradient start", def: "#f59e0b", desc: "Left/top color of card header and hero gradients" }, + { key: "gradient_to", label: "Gradient end", def: "#10b981", desc: "Right/bottom color of card header and hero gradients" }, ]; const HEADINGS: { key: string; label: string; def: string }[] = [ @@ -47,13 +47,13 @@ const HEADINGS: { key: string; label: string; def: string }[] = [ { key: "size_heading_h3", label: "H3", def: "18" }, ]; -const ADMIN_FIELDS: { key: string; label: string; def: string }[] = [ - { key: "admin_canvas", label: "Admin canvas", def: "#0f172a" }, - { key: "admin_surface", label: "Admin surface", def: "#1e293b" }, - { key: "admin_text", label: "Admin text", def: "#f1f5f9" }, - { key: "admin_text_muted", label: "Admin muted text", def: "#94a3b8" }, - { key: "admin_border", label: "Admin border", def: "#334155" }, - { key: "admin_sidebar_bg", label: "Admin sidebar", def: "#0f172a" }, +const ADMIN_FIELDS: { key: string; label: string; def: string; desc: string }[] = [ + { key: "admin_canvas", label: "Page background", def: "#0f172a", desc: "Main admin page background" }, + { key: "admin_surface", label: "Card / panel", def: "#1e293b", desc: "Admin cards, tables, and panel backgrounds" }, + { key: "admin_text", label: "Body text", def: "#f1f5f9", desc: "Main admin text — must contrast with canvas/surface" }, + { key: "admin_text_muted", label: "Muted text", def: "#94a3b8", desc: "Secondary labels, hints, descriptions" }, + { key: "admin_border", label: "Border", def: "#334155", desc: "Table borders, dividers, input outlines" }, + { key: "admin_sidebar_bg", label: "Sidebar", def: "#0f172a", desc: "Left navigation sidebar background" }, ]; const ALL_COLORS = [...COLOR_FIELDS, ...BUTTON_FIELDS, ...GRADIENT_FIELDS]; @@ -62,30 +62,55 @@ function toHex(value: string | null, def: string): string { return value && /^#[0-9a-fA-F]{6}$/.test(value) ? value : def; } +interface ThemeField { + key: string; + label: string; + def: string; + desc: string; +} + function colorGrid( - fields: { key: string; label: string; def: string }[], + fields: ThemeField[], current: Record, suffix = "", + bgHint?: string, ) { return (
- {fields.map((f) => ( - - ))} + {fields.map((f) => { + const val = toHex(current[f.key], f.def); + return ( +
+ +
+ {f.label} + + {f.desc} + +
+
+ ); + })}
); } @@ -182,44 +207,59 @@ export default async function AdminTheme({
-

Light mode

+

☀ Light mode

+

+ These colors are used when visitors view your site in light mode (default). Make sure body text contrasts well + with both the page background and card surface. +

+
-

{t("colours")}

+

Page & text colors

+

+ Backgrounds, surfaces, and text colors. Text colors must contrast with their backgrounds for readability. +

{colorGrid(COLOR_FIELDS, current)}
-

{t("buttonsLinks")}

+

Buttons & links

+

+ Button backgrounds, text on buttons, and link colors. Button text must contrast with its button background. +

{colorGrid(BUTTON_FIELDS, current)}
-

Gradient mix

+

Gradients

- Control the card header and hero background gradients. + Card header and hero section gradient. These blend from start → end across headings and banners.

{colorGrid(GRADIENT_FIELDS, current)}
-

Admin panel (HK)

+

🛠 Admin panel (HK)

+

+ Override colors for the Housekeeping admin panel. These apply across both light and dark modes. Leave empty to + use auto-derived defaults. +

-

- Colors for the Housekeeping admin panel. These override the defaults derived from light/dark mode palettes. -

{colorGrid(ADMIN_FIELDS, current)}
-

Dark mode

+

🌙 Dark mode

+

+ These colors are used when visitors switch to dark mode. Dark backgrounds need lighter text for good contrast. +

-

{t("colours")}

+

Page & text colors

{colorGrid(COLOR_FIELDS, currentDark, "_dark")}
-

{t("buttonsLinks")}

+

Buttons & links

{colorGrid(BUTTON_FIELDS, currentDark, "_dark")}
-

Gradient mix

+

Gradients

{colorGrid(GRADIENT_FIELDS, currentDark, "_dark")}