From 80176636b7a6a38a792185bd17ff312d0a8e30b7 Mon Sep 17 00:00:00 2001 From: Brian Fertig Date: Fri, 28 Aug 2026 12:24:52 -0600 Subject: [PATCH] New themes --- app/globals.css | 473 +++++++++++++++++++++++++++- app/layout.tsx | 47 ++- components/theme/theme-provider.tsx | 7 + components/theme/theme-toggle.tsx | 6 + 4 files changed, 513 insertions(+), 20 deletions(-) diff --git a/app/globals.css b/app/globals.css index b289f52..f22216c 100644 --- a/app/globals.css +++ b/app/globals.css @@ -6,8 +6,8 @@ /* "dark:" must be true for every dark-surfaced theme, not just .dark -- the dark looks (Dark, Ocean, Pine, Plum, Midnight, Ember, Rosewood, - Cyberpunk) all turn on dark utilities. */ -@custom-variant dark (&:is(.dark *, .ocean *, .theme-pine *, .theme-plum *, .theme-midnight *, .theme-ember *, .theme-rosewood *, .theme-cyberpunk *)); + Cyberpunk, Starfield) all turn on dark utilities. */ +@custom-variant dark (&:is(.dark *, .ocean *, .theme-pine *, .theme-plum *, .theme-midnight *, .theme-ember *, .theme-rosewood *, .theme-cyberpunk *, .theme-starfield *)); @theme inline { --color-background: var(--background); @@ -750,12 +750,152 @@ --sidebar-ring: oklch(0.85 0.14 195); } +/* Vaporwave -- pastel synthwave: a soft pink→lavender→mint sky, a hot-magenta + action color, an electric-cyan focus, and a rounded retro face (Righteous). + Light-surfaced; see the extras section for the pastel sky, the synthwave + sun, the soft glow, and the to-do treatment. */ +.theme-vaporwave { + color-scheme: light; + --background: oklch(0.92 0.045 320); + --foreground: oklch(0.32 0.09 335); + --card: oklch(0.972 0.012 330); + --card-foreground: oklch(0.32 0.09 335); + --popover: oklch(0.972 0.012 330); + --popover-foreground: oklch(0.32 0.09 335); + /* Hot magenta -- deep enough for a clean, WCAG-AA white label. */ + --primary: oklch(0.56 0.26 350); + --primary-foreground: oklch(0.99 0 0); + --secondary: oklch(0.9 0.045 325); + --secondary-foreground: oklch(0.34 0.09 335); + --muted: oklch(0.925 0.025 325); + --muted-foreground: oklch(0.47 0.08 335); + /* A cool mint accent so the hover state isn't just more pink. */ + --accent: oklch(0.89 0.055 200); + --accent-foreground: oklch(0.3 0.09 200); + --destructive: oklch(0.58 0.21 25); + --destructive-foreground: oklch(0.99 0 0); + --border: oklch(0.8 0.055 325); + --input: oklch(0.8 0.055 325); + /* Electric-cyan focus ring. */ + --ring: oklch(0.56 0.19 195); + --lane: oklch(1 0 0 / 6%); + --chart-1: oklch(0.6 0.24 350); + --chart-2: oklch(0.62 0.2 300); + --chart-3: oklch(0.62 0.18 200); + --chart-4: oklch(0.66 0.16 160); + --chart-5: oklch(0.72 0.15 90); + /* Soft, chrome-rounded corners. */ + --radius: 0.85rem; + --sidebar: oklch(0.89 0.05 325); + --sidebar-foreground: oklch(0.32 0.09 335); + --sidebar-primary: oklch(0.56 0.26 350); + --sidebar-primary-foreground: oklch(0.99 0 0); + --sidebar-accent: oklch(0.85 0.065 325); + --sidebar-accent-foreground: oklch(0.34 0.09 335); + --sidebar-border: oklch(0.8 0.055 325); + --sidebar-ring: oklch(0.56 0.19 195); +} + +/* Starfield -- deep space: near-black indigo, a warm star-gold action color, + a bright-cyan focus, and a sci-fi face (Orbitron). Dark-surfaced; see the + extras section for the starfield, the nebula glow, and the to-do treatment. + */ +.theme-starfield { + color-scheme: dark; + --background: oklch(0.14 0.035 270); + --foreground: oklch(0.9 0.025 250); + --card: oklch(0.185 0.04 270); + --card-foreground: oklch(0.9 0.025 250); + --popover: oklch(0.2 0.045 270); + --popover-foreground: oklch(0.9 0.025 250); + /* Star-gold -- a warm light against the cold void; carries dark ink. */ + --primary: oklch(0.78 0.15 82); + --primary-foreground: oklch(0.19 0.04 270); + --secondary: oklch(0.24 0.05 270); + --secondary-foreground: oklch(0.88 0.04 250); + --muted: oklch(0.21 0.045 270); + --muted-foreground: oklch(0.7 0.035 255); + --accent: oklch(0.27 0.06 270); + --accent-foreground: oklch(0.9 0.04 250); + --destructive: oklch(0.56 0.21 25); + --destructive-foreground: oklch(0.99 0 0); + --border: oklch(0.9 0.04 250 / 16%); + --input: oklch(0.9 0.04 250 / 13%); + /* Bright-cyan focus. */ + --ring: oklch(0.78 0.15 210); + --lane: oklch(1 0 0 / 5%); + --chart-1: oklch(0.78 0.15 210); + --chart-2: oklch(0.72 0.16 82); + --chart-3: oklch(0.7 0.16 290); + --chart-4: oklch(0.74 0.14 160); + --chart-5: oklch(0.8 0.12 30); + /* Medium, calm corners. */ + --radius: 0.7rem; + --sidebar: oklch(0.165 0.042 270); + --sidebar-foreground: oklch(0.9 0.025 250); + --sidebar-primary: oklch(0.78 0.15 82); + --sidebar-primary-foreground: oklch(0.19 0.04 270); + --sidebar-accent: oklch(0.27 0.06 270); + --sidebar-accent-foreground: oklch(0.9 0.04 250); + --sidebar-border: oklch(0.9 0.04 250 / 16%); + --sidebar-ring: oklch(0.78 0.15 210); +} + +/* Notebook -- stationery: a warm desk tone, white ruled-paper cards, a blue + ballpoint action color, a red margin rule, and a casual handwriting face + (Caveat). Light-surfaced; see the extras section for the ruled paper, the + margin line, and the highlighter to-do treatment. */ +.theme-notebook { + color-scheme: light; + --background: oklch(0.86 0.025 80); + --foreground: oklch(0.25 0.025 70); + --card: oklch(0.978 0.008 90); + --card-foreground: oklch(0.25 0.025 70); + --popover: oklch(0.978 0.008 90); + --popover-foreground: oklch(0.25 0.025 70); + /* Blue ballpoint ink -- deep enough for a clean white label. */ + --primary: oklch(0.46 0.13 255); + --primary-foreground: oklch(0.99 0 0); + --secondary: oklch(0.9 0.025 250); + --secondary-foreground: oklch(0.28 0.03 250); + --muted: oklch(0.93 0.012 90); + --muted-foreground: oklch(0.44 0.035 75); + /* A light blue, like a page highlight. */ + --accent: oklch(0.89 0.045 250); + --accent-foreground: oklch(0.3 0.05 250); + --destructive: oklch(0.57 0.21 25); + --destructive-foreground: oklch(0.99 0 0); + /* A pale blue rule line. */ + --border: oklch(0.79 0.035 250); + --input: oklch(0.79 0.035 250); + /* Blue-ink focus. */ + --ring: oklch(0.5 0.15 255); + --lane: oklch(1 0 0 / 5%); + --chart-1: oklch(0.5 0.13 255); + --chart-2: oklch(0.55 0.14 190); + --chart-3: oklch(0.6 0.13 80); + --chart-4: oklch(0.55 0.18 25); + --chart-5: oklch(0.58 0.14 130); + /* Slightly rounded paper corners. */ + --radius: 0.6rem; + --sidebar: oklch(0.83 0.028 80); + --sidebar-foreground: oklch(0.25 0.025 70); + --sidebar-primary: oklch(0.46 0.13 255); + --sidebar-primary-foreground: oklch(0.99 0 0); + --sidebar-accent: oklch(0.85 0.05 250); + --sidebar-accent-foreground: oklch(0.28 0.04 250); + --sidebar-border: oklch(0.78 0.035 250); + --sidebar-ring: oklch(0.5 0.15 255); +} + /* --------------------------------------------------------------------------- - EXTRA THEMES -- beyond tokens, Blueprint and Cyberpunk carry their own - fonts, backgrounds, and animations. Everything here is scoped under the - theme's own class on , so no other theme is touched. The reduced- - motion guard in @layer base still kills the animations for users who - ask for it (the static styling remains). + EXTRA THEMES -- beyond tokens, Blueprint, Cyberpunk, Vaporwave, Starfield, + and Notebook each carry their own fonts, backgrounds, and animations. + Everything here is scoped under the theme's own class on , so no + other theme is touched. The reduced-motion guard in @layer base still + kills the animations for users who ask for it (the static styling remains). + All the corner character comes from each theme's `--radius` token (the + `rounded-*` utilities scale from it), so no per-theme corner overrides. --------------------------------------------------------------------------- */ /* ------------------------------ Blueprint -------------------------------- */ @@ -1152,8 +1292,10 @@ html.theme-cyberpunk [data-todo-checkbox] svg { filter: drop-shadow(0 0 3px rgb(34 255 238 / 0.85)); } -/* The whole card glitches every so often -- a brief RGB-split, a skew, and a - sliced clip, then it settles back. Most of the cycle is calm; the burst is a +/* The whole card glitches every so often -- a brief RGB-split, a move, and a + skew, then it settles back. No clip-path: the card never gets sliced away, + it only jitters, skews, and throws a chromatic fringe, so the whole thing + stays visible the whole time. Most of the cycle is calm; the burst is a handful of held frames (steps, so it jitters rather than eases). Cards are phase-offset so a boardful of them don't all tear on the same beat. */ html.theme-cyberpunk [data-group-card] { @@ -1183,16 +1325,18 @@ html.theme-cyberpunk [data-group-card]:nth-child(3n) { } 88% { transform: translate(3px, -1px); - clip-path: inset(0 0 14% 0); filter: saturate(1.8); + box-shadow: + -3px 0 rgb(255 43 214 / 0.55), + 3px 0 rgb(34 255 238 / 0.55); } 89% { transform: translate(-1px, 1px) skewX(2deg); - clip-path: inset(12% 0 0 0); + filter: hue-rotate(14deg) saturate(1.5); } 90% { transform: translate(2px, -1px); - clip-path: inset(6% 0 18% 0); + filter: saturate(1.4); box-shadow: -4px 0 rgb(255 43 214 / 0.5), 4px 0 rgb(34 255 238 / 0.5); @@ -1207,6 +1351,311 @@ html.theme-cyberpunk [data-group-card]:nth-child(3n) { } } +/* ------------------------------ Vaporwave ------------------------------- */ + +/* The retro face carries the whole deck: Righteous (a rounded, retro-futur- + istic face) for headings AND for the body/to-do text, so everything reads + like a glossy 90s desktop, not just the title. Retarget the theme's font + variables so every `font-sans` surface (to-dos, buttons, nav, note editor) + and every `font-heading` title picks it up. */ +html.theme-vaporwave { + --font-sans: var(--font-vaporwave), "Trebuchet MS", "Segoe UI", sans-serif; + --font-heading: var(--font-vaporwave), "Trebuchet MS", "Segoe UI", sans-serif; +} +/* Righteous already runs a touch wide; a hair of tracking reads cleaner. */ +html.theme-vaporwave .font-heading { + letter-spacing: 0.015em; +} + +/* Pastel sky: a soft pink→lavender→mint wash, with a warm sunrise glow + bleeding down from the top. Sits on the token's background color. */ +html.theme-vaporwave body { + background-image: + radial-gradient( + 120% 55% at 50% -12%, + oklch(0.9 0.26 25 / 0.4) 0%, + oklch(0.9 0.24 345 / 0.22) 34%, + transparent 62% + ), + linear-gradient( + 180deg, + oklch(0.9 0.075 322) 0%, + oklch(0.945 0.05 292) 46%, + oklch(0.955 0.055 190) 100% + ); +} +/* Faint scanlines rolling slowly, like a monitor left on in the morning. */ +html.theme-vaporwave body::before { + content: ""; + position: fixed; + inset: 0; + z-index: -1; + pointer-events: none; + background-image: repeating-linear-gradient( + 0deg, + oklch(0.42 0.16 320 / 0.035) 0px, + oklch(0.42 0.16 320 / 0.035) 1px, + transparent 1px, + transparent 4px + ); + animation: vw-roll 16s linear infinite; +} +@keyframes vw-roll { + from { + background-position-y: 0px; + } + to { + background-position-y: 4px; + } +} + +/* Primary blooms with a soft magenta glow; focus glows electric cyan. */ +html.theme-vaporwave .bg-primary { + box-shadow: 0 4px 18px oklch(0.62 0.25 350 / 0.35); +} +html.theme-vaporwave :focus-visible { + box-shadow: + 0 0 0 3px color-mix(in oklch, var(--ring) 40%, transparent), + 0 0 14px oklch(0.56 0.19 195 / 0.5); +} + +/* To-do checkbox: rounded (the chrome look), a cyan glow that builds on + hover, and a magenta bloom the moment it's checked. (The check's own + stroke/fill already come from the group's accent color.) */ +html.theme-vaporwave [data-todo-checkbox] { + border-radius: 6px; +} +html.theme-vaporwave [data-todo-checkbox]:hover { + box-shadow: 0 0 10px oklch(0.56 0.19 195 / 0.5); +} +html.theme-vaporwave [data-todo-checkbox][aria-checked="true"] { + box-shadow: 0 0 12px oklch(0.62 0.25 350 / 0.55); +} +html.theme-vaporwave [data-todo-checkbox] svg { + filter: drop-shadow(0 0 3px oklch(0.56 0.19 195 / 0.8)); +} + +/* Completed to-do: the strike flickers with a soft neon glow before it + settles, like a sign powering down. */ +html.theme-vaporwave .line-through { + text-decoration-thickness: 1.5px; + animation: vw-flicker 420ms steps(6, jump-none) 1; +} +@keyframes vw-flicker { + 0%, + 100% { + text-shadow: none; + } + 20% { + text-shadow: 0 0 8px oklch(0.62 0.25 350 / 0.7); + } + 45% { + text-shadow: 0 0 3px oklch(0.56 0.19 195 / 0.6); + } + 70% { + text-shadow: 0 0 6px oklch(0.62 0.25 350 / 0.5); + } +} + +/* ------------------------------- Starfield ------------------------------ */ + +/* The sci-fi face carries the whole deck: Orbitron (a geometric, techy face) + for headings AND for the body/to-do text, so everything reads like a ship + console. Retarget the theme's font variables. */ +html.theme-starfield { + --font-sans: var(--font-starfield), "Segoe UI", system-ui, sans-serif; + --font-heading: var(--font-starfield), "Segoe UI", system-ui, sans-serif; +} +/* Orbitron is wide and angular; a touch of tracking sells the console feel. */ +html.theme-starfield .font-heading { + letter-spacing: 0.05em; +} + +/* The void: a deep indigo nebula fading to near-black at the edges. */ +html.theme-starfield body { + background-image: radial-gradient( + 120% 100% at 50% 0%, + oklch(0.23 0.08 272) 0%, + oklch(0.16 0.05 268) 55%, + oklch(0.12 0.04 262) 100% + ); +} + +/* A starfield: a tiled field of small stars at a couple of sizes/temperatures, + sitting behind the content (stars show in the void between surfaces). A + slow twinkle keeps it alive. */ +html.theme-starfield body::before { + content: ""; + position: fixed; + inset: 0; + z-index: -1; + pointer-events: none; + background-image: + radial-gradient(1px 1px at 20px 30px, oklch(0.98 0 0 / 0.95), transparent), + radial-gradient(1px 1px at 140px 110px, oklch(0.94 0.03 210 / 0.75), transparent), + radial-gradient(1.5px 1.5px at 230px 180px, oklch(0.9 0.06 85 / 0.7), transparent), + radial-gradient(1px 1px at 90px 210px, oklch(0.88 0.05 300 / 0.55), transparent), + radial-gradient(2px 2px at 200px 60px, oklch(0.96 0.02 210 / 0.5), transparent); + background-size: 280px 280px; + animation: sf-twinkle 7s ease-in-out infinite; +} +@keyframes sf-twinkle { + 0%, + 100% { + opacity: 0.5; + } + 50% { + opacity: 1; + } +} +/* The odd shooting star streaking across the void. */ +html.theme-starfield body::after { + content: ""; + position: fixed; + top: 14%; + left: -8%; + width: 110px; + height: 1.5px; + z-index: -1; + pointer-events: none; + border-radius: 999px; + background: linear-gradient(90deg, transparent, oklch(0.98 0 0 / 0.9)); + opacity: 0; + animation: sf-shoot 13s ease-in 3s infinite; +} +@keyframes sf-shoot { + 0% { + transform: translate(0, 0) rotate(-9deg); + opacity: 0; + } + 3% { + opacity: 0.9; + } + 11% { + transform: translate(64vw, 9vh) rotate(-9deg); + opacity: 0; + } + 100% { + opacity: 0; + } +} + +/* Star-gold primary blooms; focus glows bright cyan. */ +html.theme-starfield .bg-primary { + box-shadow: 0 0 16px oklch(0.78 0.15 82 / 0.32); +} +html.theme-starfield :focus-visible { + box-shadow: + 0 0 0 3px color-mix(in oklch, var(--ring) 40%, transparent), + 0 0 14px oklch(0.78 0.15 210 / 0.5); +} + +/* To-do checkbox: a crisp console box; a cyan glow builds on hover and blooms + when checked. (The check's own stroke/fill already come from the group's + accent color.) */ +html.theme-starfield [data-todo-checkbox] { + border-radius: 4px; +} +html.theme-starfield [data-todo-checkbox]:hover { + box-shadow: 0 0 10px oklch(0.78 0.15 210 / 0.5); +} +html.theme-starfield [data-todo-checkbox][aria-checked="true"] { + box-shadow: 0 0 12px oklch(0.78 0.15 210 / 0.6); +} +html.theme-starfield [data-todo-checkbox] svg { + filter: drop-shadow(0 0 3px oklch(0.78 0.15 210 / 0.85)); +} + +/* A completed to-do keeps a faint star-glow on its strike, like a name lit up + against the dark. */ +html.theme-starfield .line-through { + text-decoration-thickness: 1.5px; + text-shadow: 0 0 8px oklch(0.9 0.1 85 / 0.35); +} + +/* ------------------------------- Notebook ------------------------------- */ + +/* The pen script carries the whole deck: Caveat (a casual handwriting face) + for headings AND for the body/to-do text, so everything reads as written by + hand. Retarget the theme's font variables. Caveat runs light at small + sizes, so give the body a touch of weight. */ +html.theme-notebook { + --font-sans: var(--font-notebook), "Segoe Print", "Bradley Hand", cursive; + --font-heading: var(--font-notebook), "Segoe Print", "Bradley Hand", cursive; +} +html.theme-notebook body { + font-weight: 500; +} +html.theme-notebook .font-heading { + font-weight: 600; +} +/* A handwriting face crowds under the base's tight tracking -- relax it. */ +html.theme-notebook body, +html.theme-notebook h1, +html.theme-notebook h2, +html.theme-notebook h3, +html.theme-notebook h4 { + letter-spacing: 0; +} + +/* Warm desk: the paper cards read as sheets laid on a worktop. */ +html.theme-notebook body { + background-image: linear-gradient(180deg, oklch(0.88 0.024 82), oklch(0.84 0.028 80)); +} + +/* Ruled paper on the white card surfaces: blue rules + a red margin line on + the left, the classic notebook page. */ +html.theme-notebook [data-slot="card"], +html.theme-notebook [data-slot="dialog-content"] { + background-image: + linear-gradient(90deg, transparent 24px, oklch(0.6 0.19 25 / 0.4) 24px 26px, transparent 26px), + repeating-linear-gradient(180deg, transparent 0 27px, oklch(0.68 0.09 250 / 0.4) 27px 28px); +} +/* Group cards keep their own pastel tint (they read as index cards) but carry + a faint red margin line so they stay in the stationery family. */ +html.theme-notebook [data-group-card] { + background-image: linear-gradient(90deg, transparent 20px, oklch(0.6 0.19 25 / 0.3) 20px 22px, transparent 22px); +} + +/* Blue-ink focus. */ +html.theme-notebook .bg-primary { + box-shadow: 0 3px 14px oklch(0.46 0.13 255 / 0.28); +} +html.theme-notebook :focus-visible { + box-shadow: + 0 0 0 3px color-mix(in oklch, var(--ring) 35%, transparent), + 0 0 12px oklch(0.5 0.15 255 / 0.4); +} + +/* To-do checkbox: a printed box with a blue-ink stroke; a highlighter glow + builds on hover and marks the checked box. (The check's own stroke/fill + already come from the group's accent color.) */ +html.theme-notebook [data-todo-checkbox] { + border-radius: 4px; +} +html.theme-notebook [data-todo-checkbox]:hover { + box-shadow: 0 0 0 3px oklch(0.9 0.17 105 / 0.5); +} +html.theme-notebook [data-todo-checkbox][aria-checked="true"] { + box-shadow: 0 0 0 3px oklch(0.9 0.17 105 / 0.3); +} + +/* Completed to-do: a highlighter sweeps under the words, then the pen strikes + through -- the classic "done it, now cross it out" note. */ +html.theme-notebook .line-through { + text-decoration-thickness: 1.5px; + background-image: linear-gradient(0deg, oklch(0.93 0.19 105 / 0.4) 0 100%); + background-repeat: no-repeat; + background-size: 0% 60%; + background-position: 0 62%; + animation: nb-highlight 420ms ease-out forwards; +} +@keyframes nb-highlight { + to { + background-size: 100% 60%; + } +} + @layer base { * { @apply border-border outline-ring/50; diff --git a/app/layout.tsx b/app/layout.tsx index 1124769..80035b2 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,5 +1,14 @@ import type { Metadata, Viewport } from "next"; -import { Architects_Daughter, Figtree, Inter, JetBrains_Mono, VT323 } from "next/font/google"; +import { + Architects_Daughter, + Caveat, + Figtree, + Inter, + JetBrains_Mono, + Orbitron, + Righteous, + VT323, +} from "next/font/google"; import "./globals.css"; import { ThemeProvider } from "@/components/theme/theme-provider"; @@ -42,6 +51,27 @@ const vt323 = VT323({ weight: "400", }); +/** Vaporwave theme's retro face (see app/globals.css) -- a rounded, + * retro-futuristic face for the pastel synthwave look. */ +const righteous = Righteous({ + variable: "--font-vaporwave", + subsets: ["latin"], + weight: "400", +}); + +/** Starfield theme's sci-fi face (see app/globals.css). */ +const orbitron = Orbitron({ + variable: "--font-starfield", + subsets: ["latin"], +}); + +/** Notebook theme's handwriting face (see app/globals.css) -- a casual pen + * script for the stationery look. */ +const caveat = Caveat({ + variable: "--font-notebook", + subsets: ["latin"], +}); + export const metadata: Metadata = { title: "Organize", description: "An extended to-do list and notes organizer.", @@ -68,21 +98,22 @@ export default function RootLayout({ children }: LayoutProps<"/">) { return ( - {/* Sixteen looks: eight light (Default, Sunset, Meadow, Honey, Rosé, - Lavender, Slate, Blueprint) and eight dark (Dark, Ocean, Pine, - Plum, Midnight, Ember, Rosewood, Cyberpunk) -- complete token - sets in app/globals.css; Blueprint and Cyberpunk additionally - carry their own fonts, backgrounds, and animations. + {/* Nineteen looks: ten light (Default, Sunset, Meadow, Honey, Rosé, + Lavender, Slate, Blueprint, Vaporwave, Notebook) and nine dark + (Dark, Ocean, Pine, Plum, Midnight, Ember, Rosewood, Cyberpunk, + Starfield) -- complete token sets in app/globals.css; Blueprint, + Cyberpunk, Vaporwave, Starfield, and Notebook additionally carry + their own fonts, backgrounds, and animations. "system" resolves to Default/Dark by OS preference. No-FOUC theme restore: runs before first paint, applies the stored preference to (class + color-scheme). */}