Additional changes to the Cyberpunk theme, to make it even more cyberpunk.

This commit is contained in:
Brian Fertig 2026-08-28 13:34:08 -06:00
parent 304d750ec5
commit 15bfcfa064
4 changed files with 168 additions and 2 deletions

View File

@ -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 ------------------------------- */ /* ------------------------------ Vaporwave ------------------------------- */
/* The retro face carries the whole deck: Righteous (a rounded, retro-futur- /* The retro face carries the whole deck: Righteous (a rounded, retro-futur-

View File

@ -29,7 +29,8 @@ import {
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { getBrighterColor, getComplementaryColor, getGroupColor } from "@/lib/colors"; 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 { useBoard } from "@/components/board/board-context";
import { useBoardView } from "@/components/board/board-view-provider"; import { useBoardView } from "@/components/board/board-view-provider";
import { useHoldOnComplete } from "@/components/hold-on-complete"; 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.) // card ever ringing itself while it's the one being moved.)
const isDropTarget = isOver && !isDragging; 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; const borderColor = isDark ? color.dark : color.light;
// The card fill is a calm, hand-picked tint of the same stroke color // 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 // (`soft` / `softDark` in lib/colors.ts), blended a little into the theme's

View File

@ -38,6 +38,16 @@ export function isDarkTheme(): boolean {
return DARK_SURFACES.includes(resolveTheme(theme)); 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. * The `data-color-mode` value the markdown editor/preview widgets expect.
* They only understand light/dark, so the light looks (default, sunset, * They only understand light/dark, so the light looks (default, sunset,

View File

@ -48,6 +48,24 @@ export const GROUP_COLORS: GroupColor[] = [
{ key: "pink", label: "Pink", light: "#d63f8f", dark: "#f472b6", soft: "#fadfee", softDark: "#37202e" }, { 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<string, GroupColor> = {
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<string, GroupColor> = Object.fromEntries( const GROUP_COLOR_MAP: Record<string, GroupColor> = Object.fromEntries(
GROUP_COLORS.map((c) => [c.key, c]) 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]; 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) --- // --- 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 // Derived at runtime by rotating a base color's hue 180° and pulling the