diff --git a/app/globals.css b/app/globals.css index f22216c..0840c3e 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1351,6 +1351,134 @@ html.theme-cyberpunk [data-group-card]:nth-child(3n) { } } +/* ------------------------------ Cyberpunk Markdown Terminal ------------------- */ + +/* Markdown preview in the notes dialog: a CRT terminal screen with phosphor- + green text on a deep black backdrop. The VT323 pixel face (already scoped + to this theme's --font-sans) carries the whole retro feel. */ +html.theme-cyberpunk .wmde-markdown { + font-family: var(--font-cyberpunk), ui-monospace, monospace; + color: #00ff41; + background: oklch(0.06 0.01 140); + text-shadow: + 0 0 4px rgb(0 255 65 / 0.35), + 0 0 12px rgb(0 255 65 / 0.12); + font-size: 0.8125rem; + letter-spacing: 0.02em; + line-height: 1.65; +} + +/* Editor chrome: the toolbar and editing surface inherit the terminal look. + Toolbar sits on a slightly brighter black; the editing surface is pure + phosphor-black with a faint scanline overlay. */ +html.theme-cyberpunk .w-md-editor { + font-family: var(--font-cyberpunk), ui-monospace, monospace; + --md-editor-font-family: var(--font-cyberpunk), ui-monospace, monospace; + color: #00ff41; + background: oklch(0.06 0.01 140); + border-color: #00ff41 / 22%; + text-shadow: 0 0 4px rgb(0 255 65 / 0.3); +} +html.theme-cyberpunk .w-md-editor .w-md-editor-toolbar { + background: oklch(0.09 0.01 140); + border-color: #00ff41 / 18%; + box-shadow: 0 0 8px rgb(0 255 65 / 0.08); +} +html.theme-cyberpunk .w-md-editor-toolbar-item, +html.theme-cyberpunk .w-md-editor-toolbar-item-icon { + color: #00cc33; +} +html.theme-cyberpunk .w-md-editor-toolbar-item-active, +html.theme-cyberpunk .w-md-editor-toolbar-item-active .w-md-editor-toolbar-item-icon { + color: #00ff41; + text-shadow: 0 0 6px rgb(0 255 65 / 0.6); +} +html.theme-cyberpunk .w-md-editor-text, +html.theme-cyberpunk .w-md-editor-text-pre, +html.theme-cyberpunk .w-md-editor-text-input { + color: #00ff41; + background: transparent; + font-family: var(--font-cyberpunk), ui-monospace, monospace; + text-shadow: 0 0 4px rgb(0 255 65 / 0.3); +} +html.theme-cyberpunk .w-md-editor-text-input::placeholder { + color: #00cc33 / 40%; +} + +/* Subtle CRT scanline texture over the editor surface (not the toolbar). + Fixed-position so it stays anchored to the screen, not the scrolling text. + Click-through via pointer-events so the textarea stays usable. */ +html.theme-cyberpunk .w-md-editor-text-wrapper::before { + content: ""; + position: absolute; + inset: 0; + pointer-events: none; + z-index: 5; + background: repeating-linear-gradient( + 0deg, + rgb(0 255 65 / 0.02) 0px, + rgb(0 255 65 / 0.02) 1px, + transparent 1px, + transparent 3px + ); +} + +/* Links glow a softer cyan-green so they stand out from body text, and the + terminal cursor (caret) gets a phosphor-green flicker on focus. */ +html.theme-cyberpunk .wmde-markdown a, +html.theme-cyberpunk .w-md-editor a { + color: #33ffaa; + text-shadow: 0 0 6px rgb(51 255 170 / 0.4); +} +html.theme-cyberpunk .wmde-markdown code, +html.theme-cyberpunk .w-md-editor-text-pre code, +html.theme-cyberpunk .w-md-editor-text-pre { + background: oklch(0.1 0.015 140); + color: #00ff41; + border: 1px solid #00ff41 / 20%; + text-shadow: 0 0 5px rgb(0 255 65 / 0.4); +} +html.theme-cyberpunk .wmde-markdown pre, +html.theme-cyberpunk .w-md-editor-text-pre { + background: oklch(0.05 0.005 140); + border-color: #00ff41 / 15%; +} +html.theme-cyberpunk .wmde-markdown blockquote { + border-color: #00ff41 / 30%; + color: #00cc33; +} +html.theme-cyberpunk .wmde-markdown hr { + background: #00ff41 / 25%; + box-shadow: 0 0 8px rgb(0 255 65 / 0.2); +} +html.theme-cyberpunk .wmde-markdown h1, +html.theme-cyberpunk .wmde-markdown h2, +html.theme-cyberpunk .wmde-markdown h3, +html.theme-cyberpunk .wmde-markdown h4, +html.theme-cyberpunk .wmde-markdown h5, +html.theme-cyberpunk .wmde-markdown h6 { + color: #00ff41; + text-shadow: + 0 0 6px rgb(0 255 65 / 0.5), + 0 0 16px rgb(0 255 65 / 0.2); + letter-spacing: 0.04em; +} + +/* Faint screen flicker on the preview pane — a slow, barely-visible pulse + like an old CRT phosphor dimming. Doesn't affect readability. */ +html.theme-cyberpunk .wmde-markdown { + animation: terminal-flicker 6s ease-in-out infinite; +} +@keyframes terminal-flicker { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.97; } +} + +/* Cursor caret: a block-style terminal cursor that blinks green. */ +html.theme-cyberpunk .w-md-editor-text-input::selection { + background: #00ff41 / 25%; +} + /* ------------------------------ Vaporwave ------------------------------- */ /* The retro face carries the whole deck: Righteous (a rounded, retro-futur- diff --git a/components/board/group-card.tsx b/components/board/group-card.tsx index f5f8159..385a397 100644 --- a/components/board/group-card.tsx +++ b/components/board/group-card.tsx @@ -29,7 +29,8 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { getBrighterColor, getComplementaryColor, getGroupColor } from "@/lib/colors"; -import { isDarkTheme } from "@/components/theme/use-dark-theme"; +import { isDarkTheme, isCyberpunkTheme } from "@/components/theme/use-dark-theme"; +import { getCyberpunkGroupColor } from "@/lib/colors"; import { useBoard } from "@/components/board/board-context"; import { useBoardView } from "@/components/board/board-view-provider"; import { useHoldOnComplete } from "@/components/hold-on-complete"; @@ -121,7 +122,9 @@ export function GroupCard({ group }: { group: GroupDTO }) { // card ever ringing itself while it's the one being moved.) const isDropTarget = isOver && !isDragging; - const color = getGroupColor(group.color); + const color = isCyberpunkTheme() + ? getCyberpunkGroupColor(group.color) + : getGroupColor(group.color); const borderColor = isDark ? color.dark : color.light; // The card fill is a calm, hand-picked tint of the same stroke color // (`soft` / `softDark` in lib/colors.ts), blended a little into the theme's diff --git a/components/theme/use-dark-theme.ts b/components/theme/use-dark-theme.ts index 34167fa..42b7347 100644 --- a/components/theme/use-dark-theme.ts +++ b/components/theme/use-dark-theme.ts @@ -38,6 +38,16 @@ export function isDarkTheme(): boolean { return DARK_SURFACES.includes(resolveTheme(theme)); } +/** True when the "cyberpunk" theme is active. Used to swap the neon + * color palette onto group cards only for that theme. + */ +export function isCyberpunkTheme(): boolean { + const mounted = useMounted(); + const { theme } = useTheme(); + if (!mounted) return false; + return resolveTheme(theme) === "cyberpunk"; +} + /** * The `data-color-mode` value the markdown editor/preview widgets expect. * They only understand light/dark, so the light looks (default, sunset, diff --git a/lib/colors.ts b/lib/colors.ts index 830d6ae..be3b036 100644 --- a/lib/colors.ts +++ b/lib/colors.ts @@ -48,6 +48,24 @@ export const GROUP_COLORS: GroupColor[] = [ { key: "pink", label: "Pink", light: "#d63f8f", dark: "#f472b6", soft: "#fadfee", softDark: "#37202e" }, ]; +// --- Cyberpunk neon palette --- +// A secondary palette used ONLY when the "cyberpunk" theme is active. +// These are high-saturation neon values (magenta, cyan, acid green, etc.) +// that give group cards that classic "neon in the night" look. The +// softDark fills are shifted well down in lightness so they read as a +// subtle glow against the near-black surfaces instead of washed-out pastels. + +const CYBERPUNK_PALETTE: Record = { + coral: { key: "coral", label: "Neon Pink", light: "#ff2a8f", dark: "#ff2a8f", soft: "#fadfee", softDark: "#3d1433" }, + amber: { key: "amber", label: "Acid Lime", light: "#a8ff00", dark: "#a8ff00", soft: "#eeffe0", softDark: "#2d3a12" }, + lime: { key: "lime", label: "Toxic Green", light: "#39ff14", dark: "#39ff14", soft: "#e0fde0", softDark: "#163d14" }, + teal: { key: "teal", label: "Electric Cyan",light: "#00fff0", dark: "#00fff0", soft: "#dffffa", softDark: "#0f3d3a" }, + sky: { key: "sky", label: "Voltage Blue",light: "#00aaff", dark: "#00aaff", soft: "#e0f0ff", softDark: "#12263d" }, + indigo: { key: "indigo", label: "Neon Purple", light: "#bf40ff", dark: "#bf40ff", soft: "#f0e0ff", softDark: "#2e1640" }, + violet: { key: "violet", label: "Neon Magenta",light: "#ff2aff", dark: "#ff2aff", soft: "#ffe0f5", softDark: "#3d1436" }, + pink: { key: "pink", label: "Deep Violet", light: "#8a2be2", dark: "#8a2be2", soft: "#e8d6ff", softDark: "#261236" }, +}; + const GROUP_COLOR_MAP: Record = Object.fromEntries( GROUP_COLORS.map((c) => [c.key, c]) ); @@ -58,6 +76,13 @@ export function getGroupColor(key: string): GroupColor { return GROUP_COLOR_MAP[key] ?? GROUP_COLORS[0]; } +/** Get the cyberpunk-neon variant of a group color. Used ONLY when the + * "cyberpunk" theme is active so groups read as neon tubes in the night. + */ +export function getCyberpunkGroupColor(key: string): GroupColor { + return CYBERPUNK_PALETTE[key] ?? CYBERPUNK_PALETTE["coral"]; +} + // --- Complementary accent (for the to-do progress pie on a Group card) --- // // Derived at runtime by rotating a base color's hue 180° and pulling the