Created
April 14, 2026 08:48
-
-
Save smallnest/e2e55b22e305b16daac696f2e3eb1242 to your computer and use it in GitHub Desktop.
light theme for Hermes 0.9.0 dashboard
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/web/index.html b/web/index.html | |
| index c9f0d18e..a8a1b922 100644 | |
| --- a/web/index.html | |
| +++ b/web/index.html | |
| @@ -5,6 +5,9 @@ | |
| <link rel="icon" type="image/svg+xml" href="/favicon.ico" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>Hermes Agent</title> | |
| + <link rel="preconnect" href="https://fonts.googleapis.com" /> | |
| + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> | |
| + <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" /> | |
| </head> | |
| <body> | |
| <div id="root"></div> | |
| diff --git a/web/src/App.tsx b/web/src/App.tsx | |
| index b2f76808..cb1ec8ab 100644 | |
| --- a/web/src/App.tsx | |
| +++ b/web/src/App.tsx | |
| @@ -39,8 +39,6 @@ export default function App() { | |
| const initialRef = useRef(true); | |
| useEffect(() => { | |
| - // Skip the animation key bump on initial mount to avoid re-mounting | |
| - // the default page component (which causes duplicate API requests). | |
| if (initialRef.current) { | |
| initialRef.current = false; | |
| return; | |
| @@ -52,48 +50,45 @@ export default function App() { | |
| return ( | |
| <div className="flex min-h-screen flex-col bg-background text-foreground"> | |
| - {/* Global grain + warm glow (matches landing page) */} | |
| + {/* Global grain + warm glow */} | |
| <div className="noise-overlay" /> | |
| <div className="warm-glow" /> | |
| - {/* ---- Header with grid-border nav ---- */} | |
| - <header className="sticky top-0 z-40 border-b border-border bg-background/90 backdrop-blur-sm"> | |
| - <div className="mx-auto flex h-12 max-w-[1400px] items-stretch"> | |
| + {/* ---- Header ---- */} | |
| + <header className="sticky top-0 z-40 border-b border-border bg-white/80 backdrop-blur-md"> | |
| + <div className="mx-auto flex h-12 max-w-[1400px] items-center px-4"> | |
| {/* Brand */} | |
| - <div className="flex items-center border-r border-border px-5 shrink-0"> | |
| - <span className="font-collapse text-xl font-bold tracking-wider uppercase blend-lighter"> | |
| - Hermes<br className="hidden sm:inline" /><span className="sm:hidden"> </span>Agent | |
| + <div className="flex items-center gap-2.5 shrink-0 mr-6"> | |
| + <div className="h-7 w-7 rounded-lg bg-primary flex items-center justify-center"> | |
| + <span className="text-white font-bold text-sm">H</span> | |
| + </div> | |
| + <span className="text-sm font-semibold tracking-tight"> | |
| + Hermes Agent | |
| </span> | |
| </div> | |
| - {/* Nav grid — Mondwest labels like the landing page nav */} | |
| - <nav className="flex items-stretch overflow-x-auto scrollbar-none"> | |
| + {/* Nav */} | |
| + <nav className="flex items-center gap-1 overflow-x-auto scrollbar-none"> | |
| {NAV_ITEMS.map(({ id, label, icon: Icon }) => ( | |
| <button | |
| key={id} | |
| type="button" | |
| onClick={() => setPage(id)} | |
| - className={`group relative inline-flex items-center gap-1.5 border-r border-border px-4 py-2 font-display text-[0.8rem] tracking-[0.12em] uppercase whitespace-nowrap transition-colors cursor-pointer shrink-0 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring ${ | |
| + className={`group relative inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${ | |
| page === id | |
| - ? "text-foreground" | |
| - : "text-muted-foreground hover:text-foreground" | |
| + ? "text-foreground bg-secondary" | |
| + : "text-muted-foreground hover:text-foreground hover:bg-secondary/60" | |
| }`} | |
| > | |
| - <Icon className="h-3.5 w-3.5" /> | |
| + <Icon className="h-4 w-4" /> | |
| {label} | |
| - {/* Hover highlight */} | |
| - <span className="absolute inset-0 bg-foreground pointer-events-none transition-opacity duration-150 group-hover:opacity-5 opacity-0" /> | |
| - {/* Active indicator — dither bar */} | |
| - {page === id && ( | |
| - <span className="absolute bottom-0 left-0 right-0 h-px bg-foreground" /> | |
| - )} | |
| </button> | |
| ))} | |
| </nav> | |
| {/* Version badge */} | |
| - <div className="ml-auto flex items-center px-4 text-muted-foreground"> | |
| - <span className="font-display text-[0.7rem] tracking-[0.15em] uppercase opacity-50"> | |
| + <div className="ml-auto flex items-center"> | |
| + <span className="text-xs text-muted-foreground"> | |
| Web UI | |
| </span> | |
| </div> | |
| @@ -109,12 +104,12 @@ export default function App() { | |
| </main> | |
| {/* ---- Footer ---- */} | |
| - <footer className="relative z-2 border-t border-border"> | |
| + <footer className="relative z-2 border-t border-border bg-white/50"> | |
| <div className="mx-auto flex max-w-[1400px] items-center justify-between px-6 py-3"> | |
| - <span className="font-display text-[0.8rem] tracking-[0.12em] uppercase opacity-50"> | |
| + <span className="text-xs text-muted-foreground"> | |
| Hermes Agent | |
| </span> | |
| - <span className="font-display text-[0.7rem] tracking-[0.15em] uppercase text-foreground/40"> | |
| + <span className="text-xs text-muted-foreground/60"> | |
| Nous Research | |
| </span> | |
| </div> | |
| diff --git a/web/src/components/AutoField.tsx b/web/src/components/AutoField.tsx | |
| index 67f6739e..bc574bed 100644 | |
| --- a/web/src/components/AutoField.tsx | |
| +++ b/web/src/components/AutoField.tsx | |
| @@ -85,7 +85,7 @@ export function AutoField({ | |
| <Label className="text-sm">{label}</Label> | |
| <FieldHint schema={schema} schemaKey={schemaKey} /> | |
| <textarea | |
| - className="flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" | |
| + className="flex min-h-[80px] w-full rounded-lg border border-input bg-white px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1" | |
| value={String(value ?? "")} | |
| onChange={(e) => onChange(e.target.value)} | |
| /> | |
| diff --git a/web/src/components/OAuthLoginModal.tsx b/web/src/components/OAuthLoginModal.tsx | |
| index 836ec4a1..0d16bb9a 100644 | |
| --- a/web/src/components/OAuthLoginModal.tsx | |
| +++ b/web/src/components/OAuthLoginModal.tsx | |
| @@ -192,7 +192,7 @@ export function OAuthLoginModal({ provider, onClose, onSuccess, onError }: Props | |
| aria-modal="true" | |
| aria-labelledby="oauth-modal-title" | |
| > | |
| - <div className="relative w-full max-w-md border border-border bg-card shadow-2xl"> | |
| + <div className="relative w-full max-w-md rounded-xl border border-border bg-card shadow-2xl"> | |
| <button | |
| type="button" | |
| onClick={handleClose} | |
| @@ -203,7 +203,7 @@ export function OAuthLoginModal({ provider, onClose, onSuccess, onError }: Props | |
| </button> | |
| <div className="p-6 flex flex-col gap-4"> | |
| <div> | |
| - <h2 id="oauth-modal-title" className="font-display text-base tracking-wider uppercase"> | |
| + <h2 id="oauth-modal-title" className="text-base font-semibold"> | |
| Connect {provider.name} | |
| </h2> | |
| {secondsLeft !== null && phase !== "approved" && phase !== "error" && ( | |
| diff --git a/web/src/components/Toast.tsx b/web/src/components/Toast.tsx | |
| index e6bb349e..39010ed4 100644 | |
| --- a/web/src/components/Toast.tsx | |
| +++ b/web/src/components/Toast.tsx | |
| @@ -24,10 +24,10 @@ export function Toast({ toast }: { toast: { message: string; type: "success" | " | |
| <div | |
| role="status" | |
| aria-live="polite" | |
| - className={`fixed top-16 right-4 z-50 border px-4 py-2.5 font-courier text-xs tracking-wider uppercase backdrop-blur-sm ${ | |
| + className={`fixed top-16 right-4 z-50 border rounded-lg px-4 py-2.5 text-sm font-medium shadow-lg backdrop-blur-sm ${ | |
| current.type === "success" | |
| - ? "bg-success/15 text-success border-success/30" | |
| - : "bg-destructive/15 text-destructive border-destructive/30" | |
| + ? "bg-white text-success border-success/20" | |
| + : "bg-white text-destructive border-destructive/20" | |
| }`} | |
| style={{ | |
| animation: visible ? "toast-in 200ms ease-out forwards" : "toast-out 200ms ease-in forwards", | |
| diff --git a/web/src/components/ui/badge.tsx b/web/src/components/ui/badge.tsx | |
| index 2f180510..dbabae11 100644 | |
| --- a/web/src/components/ui/badge.tsx | |
| +++ b/web/src/components/ui/badge.tsx | |
| @@ -2,16 +2,16 @@ import { cva, type VariantProps } from "class-variance-authority"; | |
| import { cn } from "@/lib/utils"; | |
| const badgeVariants = cva( | |
| - "inline-flex items-center border px-2 py-0.5 font-compressed text-[0.65rem] tracking-[0.15em] uppercase transition-colors", | |
| + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium transition-colors", | |
| { | |
| variants: { | |
| variant: { | |
| - default: "border-foreground/20 bg-foreground/10 text-foreground", | |
| + default: "border-primary/20 bg-primary/10 text-primary", | |
| secondary: "border-border bg-secondary text-secondary-foreground", | |
| - destructive: "border-destructive/30 bg-destructive/15 text-destructive", | |
| + destructive: "border-red-200 bg-red-50 text-red-600", | |
| outline: "border-border text-muted-foreground", | |
| - success: "grain border-emerald-600/30 bg-emerald-950/70 text-emerald-400", | |
| - warning: "border-warning/30 bg-warning/15 text-warning", | |
| + success: "border-emerald-200 bg-emerald-50 text-emerald-700", | |
| + warning: "border-amber-200 bg-amber-50 text-amber-700", | |
| }, | |
| }, | |
| defaultVariants: { | |
| diff --git a/web/src/components/ui/button.tsx b/web/src/components/ui/button.tsx | |
| index 38ca7101..09582024 100644 | |
| --- a/web/src/components/ui/button.tsx | |
| +++ b/web/src/components/ui/button.tsx | |
| @@ -2,21 +2,22 @@ import { cva, type VariantProps } from "class-variance-authority"; | |
| import { cn } from "@/lib/utils"; | |
| const buttonVariants = cva( | |
| - "inline-flex items-center justify-center gap-2 whitespace-nowrap font-display text-xs tracking-[0.1em] uppercase transition-colors cursor-pointer" | |
| - + " disabled:pointer-events-none disabled:opacity-50", | |
| + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium transition-colors cursor-pointer" | |
| + + " disabled:pointer-events-none disabled:opacity-50" | |
| + + " focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", | |
| { | |
| variants: { | |
| variant: { | |
| - default: "bg-foreground/90 text-background hover:bg-foreground", | |
| - destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", | |
| - outline: "border border-border bg-transparent hover:bg-foreground/10 hover:text-foreground", | |
| + default: "bg-primary text-primary-foreground hover:bg-primary/90", | |
| + destructive: "bg-red-600 text-white hover:bg-red-700", | |
| + outline: "border border-border bg-white hover:bg-secondary hover:text-secondary-foreground", | |
| secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", | |
| - ghost: "hover:bg-foreground/10 hover:text-foreground", | |
| - link: "text-foreground underline-offset-4 hover:underline", | |
| + ghost: "hover:bg-secondary hover:text-secondary-foreground", | |
| + link: "text-primary underline-offset-4 hover:underline", | |
| }, | |
| size: { | |
| default: "h-9 px-4 py-2", | |
| - sm: "h-8 px-3 text-[0.65rem]", | |
| + sm: "h-8 px-3 text-xs", | |
| lg: "h-10 px-8", | |
| icon: "h-9 w-9", | |
| }, | |
| diff --git a/web/src/components/ui/card.tsx b/web/src/components/ui/card.tsx | |
| index 7ff6a9ae..af731c48 100644 | |
| --- a/web/src/components/ui/card.tsx | |
| +++ b/web/src/components/ui/card.tsx | |
| @@ -4,7 +4,7 @@ export function Card({ className, ...props }: React.HTMLAttributes<HTMLDivElemen | |
| return ( | |
| <div | |
| className={cn( | |
| - "border border-border bg-card/80 text-card-foreground", | |
| + "rounded-xl border border-border bg-card text-card-foreground shadow-sm", | |
| className, | |
| )} | |
| {...props} | |
| @@ -17,11 +17,11 @@ export function CardHeader({ className, ...props }: React.HTMLAttributes<HTMLDiv | |
| } | |
| export function CardTitle({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) { | |
| - return <h3 className={cn("font-expanded text-sm font-bold tracking-[0.08em] uppercase blend-lighter", className)} {...props} />; | |
| + return <h3 className={cn("text-sm font-semibold tracking-tight", className)} {...props} />; | |
| } | |
| export function CardDescription({ className, ...props }: React.HTMLAttributes<HTMLParagraphElement>) { | |
| - return <p className={cn("font-display text-xs text-muted-foreground", className)} {...props} />; | |
| + return <p className={cn("text-sm text-muted-foreground", className)} {...props} />; | |
| } | |
| export function CardContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) { | |
| diff --git a/web/src/components/ui/input.tsx b/web/src/components/ui/input.tsx | |
| index 1e1199e6..f223a4f6 100644 | |
| --- a/web/src/components/ui/input.tsx | |
| +++ b/web/src/components/ui/input.tsx | |
| @@ -4,9 +4,9 @@ export function Input({ className, ...props }: React.InputHTMLAttributes<HTMLInp | |
| return ( | |
| <input | |
| className={cn( | |
| - "flex h-9 w-full border border-border bg-background/40 px-3 py-1 font-courier text-sm transition-colors", | |
| + "flex h-9 w-full rounded-lg border border-input bg-white px-3 py-1 text-sm transition-colors", | |
| "placeholder:text-muted-foreground", | |
| - "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-foreground/30 focus-visible:border-foreground/25", | |
| + "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:border-primary", | |
| "disabled:cursor-not-allowed disabled:opacity-50", | |
| className, | |
| )} | |
| diff --git a/web/src/components/ui/label.tsx b/web/src/components/ui/label.tsx | |
| index a18b2e5d..f5577fbb 100644 | |
| --- a/web/src/components/ui/label.tsx | |
| +++ b/web/src/components/ui/label.tsx | |
| @@ -4,7 +4,7 @@ export function Label({ className, ...props }: React.LabelHTMLAttributes<HTMLLab | |
| return ( | |
| <label | |
| className={cn( | |
| - "font-display text-xs tracking-[0.1em] uppercase leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", | |
| + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", | |
| className, | |
| )} | |
| {...props} | |
| diff --git a/web/src/components/ui/select.tsx b/web/src/components/ui/select.tsx | |
| index 0f42ef91..e136fdc6 100644 | |
| --- a/web/src/components/ui/select.tsx | |
| +++ b/web/src/components/ui/select.tsx | |
| @@ -4,8 +4,8 @@ export function Select({ className, ...props }: React.SelectHTMLAttributes<HTMLS | |
| return ( | |
| <select | |
| className={cn( | |
| - "flex h-9 w-full border border-border bg-background/40 px-3 py-1 font-courier text-sm", | |
| - "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-foreground/30 focus-visible:border-foreground/25", | |
| + "flex h-9 w-full rounded-lg border border-input bg-white px-3 py-1 text-sm", | |
| + "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:border-primary", | |
| "disabled:cursor-not-allowed disabled:opacity-50", | |
| className, | |
| )} | |
| diff --git a/web/src/components/ui/switch.tsx b/web/src/components/ui/switch.tsx | |
| index fe36c775..2e007c03 100644 | |
| --- a/web/src/components/ui/switch.tsx | |
| +++ b/web/src/components/ui/switch.tsx | |
| @@ -18,18 +18,18 @@ export function Switch({ | |
| aria-checked={checked} | |
| disabled={disabled} | |
| className={cn( | |
| - "peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center border border-border transition-colors", | |
| - "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-foreground/30", | |
| + "peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors", | |
| + "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", | |
| "disabled:cursor-not-allowed disabled:opacity-50", | |
| - checked ? "bg-foreground/15 border-foreground/30" : "bg-background", | |
| + checked ? "bg-primary" : "bg-muted", | |
| className, | |
| )} | |
| onClick={() => onCheckedChange(!checked)} | |
| > | |
| <span | |
| className={cn( | |
| - "pointer-events-none block h-3.5 w-3.5 transition-transform", | |
| - checked ? "translate-x-4 bg-foreground" : "translate-x-0.5 bg-muted-foreground", | |
| + "pointer-events-none block h-4 w-4 rounded-full bg-white shadow-sm transition-transform", | |
| + checked ? "translate-x-4" : "translate-x-0", | |
| )} | |
| /> | |
| </button> | |
| diff --git a/web/src/components/ui/tabs.tsx b/web/src/components/ui/tabs.tsx | |
| index 039af02f..1a8517e3 100644 | |
| --- a/web/src/components/ui/tabs.tsx | |
| +++ b/web/src/components/ui/tabs.tsx | |
| @@ -37,10 +37,10 @@ export function TabsTrigger({ | |
| <button | |
| type="button" | |
| className={cn( | |
| - "relative inline-flex items-center justify-center whitespace-nowrap px-3 py-1.5 font-display text-xs tracking-[0.1em] uppercase transition-all cursor-pointer", | |
| - "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", | |
| + "relative inline-flex items-center justify-center whitespace-nowrap px-3 py-1.5 text-sm font-medium transition-all cursor-pointer", | |
| + "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", | |
| active | |
| - ? "text-foreground after:absolute after:bottom-0 after:left-0 after:right-0 after:h-px after:bg-foreground" | |
| + ? "text-foreground after:absolute after:bottom-0 after:left-0 after:right-0 after:h-0.5 after:bg-primary after:rounded-full" | |
| : "hover:text-foreground", | |
| className, | |
| )} | |
| diff --git a/web/src/index.css b/web/src/index.css | |
| index 7846e9f9..74ed31d5 100644 | |
| --- a/web/src/index.css | |
| +++ b/web/src/index.css | |
| @@ -1,57 +1,46 @@ | |
| @import "tailwindcss"; | |
| /* ------------------------------------------------------------------ */ | |
| -/* Hermes Agent — Design tokens */ | |
| -/* Matched to hermes-agent.nousresearch.com (dark teal theme) */ | |
| +/* Hermes Agent — Modern Light Theme */ | |
| +/* Clean, minimal design inspired by Linear / Vercel / Stripe */ | |
| /* ------------------------------------------------------------------ */ | |
| -/* --- Font faces --- */ | |
| -@font-face { font-family: "Collapse"; src: url("/fonts/Collapse-Regular.woff2") format("woff2"); font-weight: 400; font-display: swap; } | |
| -@font-face { font-family: "Collapse"; src: url("/fonts/Collapse-Bold.woff2") format("woff2"); font-weight: 700; font-display: swap; } | |
| -@font-face { font-family: "Courier Prime"; src: url("/fonts/CourierPrime-Regular.woff2") format("woff2"); font-weight: 400; font-display: swap; } | |
| -@font-face { font-family: "Courier Prime"; src: url("/fonts/CourierPrime-Bold.woff2") format("woff2"); font-weight: 700; font-display: swap; } | |
| -@font-face { font-family: "RulesCompressed"; src: url("/fonts/RulesCompressed-Regular.woff2") format("woff2"); font-weight: 400; font-display: swap; } | |
| -@font-face { font-family: "RulesCompressed"; src: url("/fonts/RulesCompressed-Medium.woff2") format("woff2"); font-weight: 600; font-display: swap; } | |
| -@font-face { font-family: "RulesExpanded"; src: url("/fonts/RulesExpanded-Regular.woff2") format("woff2"); font-weight: 400; font-display: swap; } | |
| -@font-face { font-family: "RulesExpanded"; src: url("/fonts/RulesExpanded-Bold.woff2") format("woff2"); font-weight: 700; font-display: swap; } | |
| -@font-face { font-family: "Mondwest"; src: url("/fonts/Mondwest-Regular.woff2") format("woff2"); font-weight: 400; font-display: swap; } | |
| - | |
| @theme { | |
| - /* ---- Hermes palette (dark teal, from live site) ---- */ | |
| - --color-background: #041C1C; | |
| - --color-foreground: #ffe6cb; | |
| - --color-card: #062424; | |
| - --color-card-foreground: #ffe6cb; | |
| - --color-primary: #ffe6cb; | |
| - --color-primary-foreground: #041C1C; | |
| - --color-secondary: #0a2e2e; | |
| - --color-secondary-foreground: #ffe6cb; | |
| - --color-muted: #083030; | |
| - --color-muted-foreground: #8aaa9a; | |
| - --color-accent: #0c3838; | |
| - --color-accent-foreground: #ffe6cb; | |
| - --color-destructive: #fb2c36; | |
| - --color-destructive-foreground: #fff; | |
| - --color-success: #4ade80; | |
| - --color-warning: #ffbd38; | |
| - --color-border: color-mix(in srgb, #ffe6cb 15%, transparent); | |
| - --color-input: color-mix(in srgb, #ffe6cb 15%, transparent); | |
| - --color-ring: #ffe6cb; | |
| - --color-popover: #062424; | |
| - --color-popover-foreground: #ffe6cb; | |
| + /* ---- Light palette ---- */ | |
| + --color-background: #fafafa; | |
| + --color-foreground: #0f0f0f; | |
| + --color-card: #ffffff; | |
| + --color-card-foreground: #0f0f0f; | |
| + --color-primary: #6d5dfc; | |
| + --color-primary-foreground: #ffffff; | |
| + --color-secondary: #f4f4f5; | |
| + --color-secondary-foreground: #3f3f46; | |
| + --color-muted: #f4f4f5; | |
| + --color-muted-foreground: #71717a; | |
| + --color-accent: #f4f4f5; | |
| + --color-accent-foreground: #0f0f0f; | |
| + --color-destructive: #ef4444; | |
| + --color-destructive-foreground: #ffffff; | |
| + --color-success: #22c55e; | |
| + --color-warning: #f59e0b; | |
| + --color-border: #e4e4e7; | |
| + --color-input: #e4e4e7; | |
| + --color-ring: #6d5dfc; | |
| + --color-popover: #ffffff; | |
| + --color-popover-foreground: #0f0f0f; | |
| /* ---- Font stacks ---- */ | |
| - --font-sans: "Mondwest", Arial, sans-serif; | |
| - --font-mono: "Courier Prime", "Courier New", monospace; | |
| - --font-display: "Mondwest", Arial, sans-serif; | |
| - --font-expanded: "RulesExpanded", Arial, sans-serif; | |
| - --font-compressed: "RulesCompressed", Arial, sans-serif; | |
| + --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; | |
| + --font-mono: "JetBrains Mono", "SF Mono", "Fira Code", "Cascadia Code", monospace; | |
| + --font-display: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; | |
| + --font-expanded: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; | |
| + --font-compressed: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; | |
| } | |
| /* ---- Global body ---- */ | |
| body { | |
| margin: 0; | |
| - font-family: "Mondwest", Arial, sans-serif; | |
| + font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; | |
| background: var(--color-background); | |
| color: var(--color-foreground); | |
| -webkit-font-smoothing: antialiased; | |
| @@ -61,8 +50,8 @@ body { | |
| /* ---- Selection ---- */ | |
| ::selection { | |
| - background: var(--color-foreground); | |
| - color: var(--color-background); | |
| + background: oklch(0.55 0.18 270); | |
| + color: #fff; | |
| } | |
| /* ---- Scrollbars (thin, subtle) ---- */ | |
| @@ -71,19 +60,19 @@ body { | |
| scrollbar-color: transparent transparent; | |
| } | |
| *:hover { | |
| - scrollbar-color: color-mix(in srgb, var(--color-foreground) 15%, transparent) transparent; | |
| + scrollbar-color: color-mix(in srgb, var(--color-foreground) 12%, transparent) transparent; | |
| } | |
| html, body { | |
| - scrollbar-color: color-mix(in srgb, var(--color-foreground) 25%, transparent) transparent; | |
| + scrollbar-color: color-mix(in srgb, var(--color-foreground) 18%, transparent) transparent; | |
| } | |
| -::-webkit-scrollbar { width: 4px; height: 4px; } | |
| +::-webkit-scrollbar { width: 5px; height: 5px; } | |
| ::-webkit-scrollbar-track { background: transparent; } | |
| ::-webkit-scrollbar-thumb { | |
| - background: color-mix(in srgb, var(--color-foreground) 20%, transparent); | |
| - border-radius: 2px; | |
| + background: color-mix(in srgb, var(--color-foreground) 14%, transparent); | |
| + border-radius: 10px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| - background: color-mix(in srgb, var(--color-foreground) 35%, transparent); | |
| + background: color-mix(in srgb, var(--color-foreground) 25%, transparent); | |
| } | |
| /* ---- Hide scrollbar utility ---- */ | |
| @@ -97,11 +86,12 @@ html, body { | |
| /* ---- Code blocks ---- */ | |
| code { | |
| - font-family: "Courier Prime", "Courier New", monospace; | |
| + font-family: "JetBrains Mono", "SF Mono", "Fira Code", monospace; | |
| font-size: 0.85em; | |
| padding: 0.15em 0.4em; | |
| - border-radius: 0; | |
| - background: color-mix(in srgb, var(--color-foreground) 8%, transparent); | |
| + border-radius: 4px; | |
| + background: #f0f0f3; | |
| + color: #5b21b6; | |
| } | |
| /* ---- Dither texture ---- */ | |
| @@ -136,18 +126,12 @@ code { | |
| to { opacity: 0; transform: translateX(16px); } | |
| } | |
| -/* ---- Plus-lighter blend for headings ---- */ | |
| -.blend-lighter { | |
| - mix-blend-mode: plus-lighter; | |
| -} | |
| - | |
| /* ---- Font utilities ---- */ | |
| -.font-display { font-family: "Mondwest", Arial, sans-serif; } | |
| -.font-expanded { font-family: "RulesExpanded", Arial, sans-serif; } | |
| -.font-compressed { font-family: "RulesCompressed", Arial, sans-serif; } | |
| -.font-courier { font-family: "Courier Prime", "Courier New", monospace; } | |
| -.font-collapse { font-family: "Collapse", Arial, sans-serif; } | |
| -.font-mono-ui { font-family: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace; } | |
| +.font-display { font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } | |
| +.font-expanded { font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } | |
| +.font-compressed { font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } | |
| +.font-courier { font-family: "JetBrains Mono", "SF Mono", "Fira Code", monospace; } | |
| +.font-mono-ui { font-family: "JetBrains Mono", "SF Mono", "Cascadia Mono", Menlo, monospace; } | |
| /* ---- Subtle grain overlay for badges ---- */ | |
| .grain { | |
| @@ -157,32 +141,32 @@ code { | |
| content: ""; | |
| position: absolute; | |
| inset: 0; | |
| - opacity: 0.12; | |
| + opacity: 0.04; | |
| pointer-events: none; | |
| background: repeating-conic-gradient(currentColor 0% 25%, #0000 0% 50%) 0 0 / 2px 2px; | |
| } | |
| -/* ---- Global noise grain (canonical: color-dodge, #eaeaea, high density) ---- */ | |
| +/* ---- Subtle background texture (light) ---- */ | |
| .noise-overlay { | |
| pointer-events: none; | |
| position: fixed; | |
| inset: 0; | |
| z-index: 101; | |
| - mix-blend-mode: color-dodge; | |
| - opacity: 0.10; | |
| - background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' fill='%23eaeaea' filter='url(%23n)' opacity='0.6'/%3E%3C/svg%3E"); | |
| + mix-blend-mode: overlay; | |
| + opacity: 0.015; | |
| + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' fill='%23999' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E"); | |
| background-size: 512px 512px; | |
| } | |
| -/* ---- Vignette (canonical: top-left amber radial, lighten blend) ---- */ | |
| +/* ---- Warm glow — soft purple gradient for light theme ---- */ | |
| .warm-glow { | |
| pointer-events: none; | |
| position: fixed; | |
| inset: 0; | |
| z-index: 99; | |
| - mix-blend-mode: lighten; | |
| - opacity: 0.22; | |
| - background: radial-gradient(ellipse at 0% 0%, rgba(255,189,56,0.35) 0%, rgba(255,189,56,0) 60%); | |
| + mix-blend-mode: multiply; | |
| + opacity: 0.25; | |
| + background: radial-gradient(ellipse at 20% 0%, rgba(109, 93, 252, 0.12) 0%, rgba(109, 93, 252, 0) 55%); | |
| } | |
| /* ---- Reduced motion ---- */ | |
| diff --git a/web/src/pages/AnalyticsPage.tsx b/web/src/pages/AnalyticsPage.tsx | |
| index 9c3d6f99..cff33cc9 100644 | |
| --- a/web/src/pages/AnalyticsPage.tsx | |
| +++ b/web/src/pages/AnalyticsPage.tsx | |
| @@ -72,11 +72,11 @@ function TokenBarChart({ daily }: { daily: AnalyticsDailyEntry[] }) { | |
| </div> | |
| <div className="flex items-center gap-4 text-xs text-muted-foreground"> | |
| <div className="flex items-center gap-1.5"> | |
| - <div className="h-2.5 w-2.5 rounded-sm bg-[#ffe6cb]" /> | |
| + <div className="h-2.5 w-2.5 rounded-sm bg-primary/60" /> | |
| Input | |
| </div> | |
| <div className="flex items-center gap-1.5"> | |
| - <div className="h-2.5 w-2.5 rounded-sm bg-emerald-500" /> | |
| + <div className="h-2.5 w-2.5 rounded-sm bg-success" /> | |
| Output | |
| </div> | |
| </div> | |
| @@ -104,12 +104,12 @@ function TokenBarChart({ daily }: { daily: AnalyticsDailyEntry[] }) { | |
| </div> | |
| {/* Input bar */} | |
| <div | |
| - className="w-full bg-[#ffe6cb]/70" | |
| + className="w-full bg-primary/50" | |
| style={{ height: Math.max(inputH, total > 0 ? 1 : 0) }} | |
| /> | |
| {/* Output bar */} | |
| <div | |
| - className="w-full bg-emerald-500/70" | |
| + className="w-full bg-success/70" | |
| style={{ height: Math.max(outputH, d.output_tokens > 0 ? 1 : 0) }} | |
| /> | |
| </div> | |
| @@ -160,10 +160,10 @@ function DailyTable({ daily }: { daily: AnalyticsDailyEntry[] }) { | |
| <td className="py-2 pr-4 font-medium">{formatDate(d.day)}</td> | |
| <td className="text-right py-2 px-4 text-muted-foreground">{d.sessions}</td> | |
| <td className="text-right py-2 px-4"> | |
| - <span className="text-[#ffe6cb]">{formatTokens(d.input_tokens)}</span> | |
| + <span className="text-primary">{formatTokens(d.input_tokens)}</span> | |
| </td> | |
| <td className="text-right py-2 pl-4"> | |
| - <span className="text-emerald-400">{formatTokens(d.output_tokens)}</span> | |
| + <span className="text-success">{formatTokens(d.output_tokens)}</span> | |
| </td> | |
| </tr> | |
| ); | |
| @@ -209,9 +209,9 @@ function ModelTable({ models }: { models: AnalyticsModelEntry[] }) { | |
| </td> | |
| <td className="text-right py-2 px-4 text-muted-foreground">{m.sessions}</td> | |
| <td className="text-right py-2 pl-4"> | |
| - <span className="text-[#ffe6cb]">{formatTokens(m.input_tokens)}</span> | |
| + <span className="text-primary font-medium">{formatTokens(m.input_tokens)}</span> | |
| {" / "} | |
| - <span className="text-emerald-400">{formatTokens(m.output_tokens)}</span> | |
| + <span className="text-emerald-600">{formatTokens(m.output_tokens)}</span> | |
| </td> | |
| </tr> | |
| ))} | |
| diff --git a/web/src/pages/ConfigPage.tsx b/web/src/pages/ConfigPage.tsx | |
| index 2e75e1d1..d3720056 100644 | |
| --- a/web/src/pages/ConfigPage.tsx | |
| +++ b/web/src/pages/ConfigPage.tsx | |
| @@ -333,7 +333,7 @@ export default function ConfigPage() { | |
| </div> | |
| ) : ( | |
| <textarea | |
| - className="flex min-h-[600px] w-full bg-transparent px-4 py-3 text-sm font-mono leading-relaxed placeholder:text-muted-foreground focus-visible:outline-none border-t border-border" | |
| + className="flex min-h-[600px] w-full bg-white px-4 py-3 text-sm font-mono leading-relaxed placeholder:text-muted-foreground focus-visible:outline-none border-t border-border" | |
| value={yamlText} | |
| onChange={(e) => setYamlText(e.target.value)} | |
| spellCheck={false} | |
| diff --git a/web/src/pages/CronPage.tsx b/web/src/pages/CronPage.tsx | |
| index 418f3628..91dd8d8b 100644 | |
| --- a/web/src/pages/CronPage.tsx | |
| +++ b/web/src/pages/CronPage.tsx | |
| @@ -147,7 +147,7 @@ export default function CronPage() { | |
| <Label htmlFor="cron-prompt">Prompt</Label> | |
| <textarea | |
| id="cron-prompt" | |
| - className="flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" | |
| + className="flex min-h-[80px] w-full rounded-lg border border-input bg-white px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1" | |
| placeholder="What should the agent do on each run?" | |
| value={prompt} | |
| onChange={(e) => setPrompt(e.target.value)} | |
| diff --git a/web/src/pages/SkillsPage.tsx b/web/src/pages/SkillsPage.tsx | |
| index ab601c9f..1e13f762 100644 | |
| --- a/web/src/pages/SkillsPage.tsx | |
| +++ b/web/src/pages/SkillsPage.tsx | |
| @@ -403,7 +403,7 @@ export default function SkillsPage() { | |
| {ts.description} | |
| </p> | |
| {ts.enabled && !ts.configured && ( | |
| - <p className="text-[10px] text-amber-300/80 mb-2"> | |
| + <p className="text-[10px] text-amber-600 mb-2"> | |
| Setup needed | |
| </p> | |
| )} | |
| diff --git a/web/src/pages/StatusPage.tsx b/web/src/pages/StatusPage.tsx | |
| index 06fb7c25..4c958488 100644 | |
| --- a/web/src/pages/StatusPage.tsx | |
| +++ b/web/src/pages/StatusPage.tsx | |
| @@ -141,7 +141,7 @@ export default function StatusPage() { | |
| </CardHeader> | |
| <CardContent> | |
| - <div className="text-2xl font-bold font-display">{value}</div> | |
| + <div className="text-2xl font-bold">{value}</div> | |
| {badgeText && ( | |
| <Badge variant={badgeVariant} className="mt-2"> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| git apply hermes-dashboard-light-theme.patch | |
| cd web && npx vite build |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment