New themes

This commit is contained in:
Brian Fertig 2026-08-28 12:24:52 -06:00
parent be6926c027
commit 80176636b7
4 changed files with 513 additions and 20 deletions

View File

@ -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 pinklavendermint 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 <html>, 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 <html>, 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 pinklavendermint 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;

View File

@ -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 (
<html
lang="en"
className={`${inter.variable} ${figtree.variable} ${jetbrainsMono.variable} ${architectsDaughter.variable} ${vt323.variable} h-full antialiased`}
className={`${inter.variable} ${figtree.variable} ${jetbrainsMono.variable} ${architectsDaughter.variable} ${vt323.variable} ${righteous.variable} ${orbitron.variable} ${caveat.variable} h-full antialiased`}
suppressHydrationWarning
>
<body className="min-h-full flex flex-col">
{/* 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 <html> (class + color-scheme). */}
<script
dangerouslySetInnerHTML={{
__html: `!(function(){try{var r=document.documentElement,c=['theme-default','theme-sunset','theme-meadow','theme-honey','theme-rose','theme-lavender','theme-slate','theme-blueprint','dark','ocean','theme-pine','theme-plum','theme-midnight','theme-ember','theme-rosewood','theme-cyberpunk','light'];for(var i=0;i<c.length;i++){r.classList.remove(c[i]);}var v=null;try{v=localStorage.getItem('theme');}catch(e){}var m={default:'theme-default',sunset:'theme-sunset',meadow:'theme-meadow',honey:'theme-honey',rose:'theme-rose',lavender:'theme-lavender',slate:'theme-slate',blueprint:'theme-blueprint',dark:'dark',ocean:'ocean',pine:'theme-pine',plum:'theme-plum',midnight:'theme-midnight',ember:'theme-ember',rosewood:'theme-rosewood',cyberpunk:'theme-cyberpunk'};var d=['dark','ocean','pine','plum','midnight','ember','rosewood','cyberpunk'];if(v==='system'||!v){v=window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'default';}if(m[v]){r.classList.add(m[v]);r.style.colorScheme=d.indexOf(v)>=0?'dark':'light';}}catch(e){}})();`,
__html: `!(function(){try{var r=document.documentElement,c=['theme-default','theme-sunset','theme-meadow','theme-honey','theme-rose','theme-lavender','theme-slate','theme-blueprint','theme-vaporwave','theme-notebook','dark','ocean','theme-pine','theme-plum','theme-midnight','theme-ember','theme-rosewood','theme-cyberpunk','theme-starfield','light'];for(var i=0;i<c.length;i++){r.classList.remove(c[i]);}var v=null;try{v=localStorage.getItem('theme');}catch(e){}var m={default:'theme-default',sunset:'theme-sunset',meadow:'theme-meadow',honey:'theme-honey',rose:'theme-rose',lavender:'theme-lavender',slate:'theme-slate',blueprint:'theme-blueprint',vaporwave:'theme-vaporwave',notebook:'theme-notebook',dark:'dark',ocean:'ocean',pine:'theme-pine',plum:'theme-plum',midnight:'theme-midnight',ember:'theme-ember',rosewood:'theme-rosewood',cyberpunk:'theme-cyberpunk',starfield:'theme-starfield'};var d=['dark','ocean','pine','plum','midnight','ember','rosewood','cyberpunk','starfield'];if(v==='system'||!v){v=window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'default';}if(m[v]){r.classList.add(m[v]);r.style.colorScheme=d.indexOf(v)>=0?'dark':'light';}}catch(e){}})();`,
}}
/>
<ThemeProvider defaultTheme="system">

View File

@ -38,6 +38,8 @@ export const THEMES = [
"lavender",
"slate",
"blueprint",
"vaporwave",
"notebook",
"dark",
"ocean",
"pine",
@ -46,6 +48,7 @@ export const THEMES = [
"ember",
"rosewood",
"cyberpunk",
"starfield",
] as const;
export type ThemeName = (typeof THEMES)[number];
export type RawTheme = ThemeName | "system";
@ -60,6 +63,8 @@ const THEME_CLASSES: Record<ThemeName, string> = {
lavender: "theme-lavender",
slate: "theme-slate",
blueprint: "theme-blueprint",
vaporwave: "theme-vaporwave",
notebook: "theme-notebook",
dark: "dark",
ocean: "ocean",
pine: "theme-pine",
@ -68,6 +73,7 @@ const THEME_CLASSES: Record<ThemeName, string> = {
ember: "theme-ember",
rosewood: "theme-rosewood",
cyberpunk: "theme-cyberpunk",
starfield: "theme-starfield",
};
const ALL_CLASSES = Object.values(THEME_CLASSES);
/* Themes whose *surfaces* are dark (see app/globals.css). The single source
@ -82,6 +88,7 @@ export const DARK_SURFACES: ThemeName[] = [
"ember",
"rosewood",
"cyberpunk",
"starfield",
];
interface ThemeContextValue {

View File

@ -20,6 +20,9 @@ import {
Wine,
DraftingCompass,
CircuitBoard,
Disc3,
Orbit,
NotebookText,
} from "lucide-react";
import { useTheme } from "@/components/theme/theme-provider";
@ -52,6 +55,8 @@ const LIGHT_OPTIONS: ThemeOption[] = [
{ value: "lavender", label: "Lavender", icon: Flower2, swatch: "#7c3aed" },
{ value: "slate", label: "Slate", icon: Mountain, swatch: "#4a6d9c" },
{ value: "blueprint", label: "Blueprint", icon: DraftingCompass, swatch: "#2b4bc4" },
{ value: "vaporwave", label: "Vaporwave", icon: Disc3, swatch: "#e879f9" },
{ value: "notebook", label: "Notebook", icon: NotebookText, swatch: "#3b5fc4" },
];
const DARK_OPTIONS: ThemeOption[] = [
{ value: "dark", label: "Dark", icon: Moon, swatch: "#7c83f2" },
@ -62,6 +67,7 @@ const DARK_OPTIONS: ThemeOption[] = [
{ value: "ember", label: "Ember", icon: Flame, swatch: "#fbbf24" },
{ value: "rosewood", label: "Rosewood", icon: Wine, swatch: "#fb7185" },
{ value: "cyberpunk", label: "Cyberpunk", icon: CircuitBoard, swatch: "#ff2bd6" },
{ value: "starfield", label: "Starfield", icon: Orbit, swatch: "#38bdf8" },
];
const ALL_OPTIONS = [...LIGHT_OPTIONS, ...DARK_OPTIONS];