diff --git a/README.md b/README.md index 2aa7a4a..5575a1d 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,39 @@ Any command that produces a scrollable page supports `--slides` to generate a sl https://github.com/user-attachments/assets/342d3558-5fcf-4fb2-bc03-f0dd5b9e35dc +## Themes + +You can set a preferred color palette so every generated page uses consistent colors. Create a config file in your project: + +```bash +# .claude/visual-explainer.local.md +--- +theme: dracula +--- +``` + +The agent reads this file and applies the theme's colors instead of picking its own. Fonts, layout, and animations are still chosen freely — only the color palette is fixed. + +**Available themes:** + +| Theme | Style | Primary mode | +|-------|-------|-------------| +| `dracula` | Purple/pink/cyan on cool dark | Dark | +| `nord` | Arctic frost blues with aurora accents | Dark | +| `one-dark` | Atom's blue/green/purple palette | Dark | +| `catppuccin-mocha` | Soothing pastels on warm dark | Dark | +| `tokyo-night` | Downtown Tokyo blues and purples | Dark | +| `gruvbox-dark` | Retro groove warm oranges and greens | Dark | +| `synthwave-84` | Neon pink/cyan/yellow on deep purple | Dark | +| `solarized-light` | Ethan Schoonover's precise CIELAB palette | Light | +| `github-light` | GitHub Primer clean blues and greens | Light | +| `catppuccin-latte` | Soothing pastels on warm light | Light | +| `gruvbox-light` | Retro groove faded earth tones | Light | + +Every theme includes both light and dark mode support via `prefers-color-scheme`. Every generated page includes an interactive theme picker with all 11 themes. + +**Adding custom themes:** Create a new file in `themes/.md` following the same structure as existing themes. Define CSS custom properties (using the same variable names) and Mermaid themeVariables. + ## How It Works ``` @@ -106,6 +139,9 @@ plugins/ │ ├── libraries.md (Mermaid, Chart.js, fonts) │ ├── responsive-nav.md (sticky TOC for multi-section pages) │ └── slide-patterns.md (slide engine, transitions, presets) + ├── themes/ ← 11 pre-built color themes + │ ├── dracula.md, nord.md, one-dark.md, ... + │ └── (add custom themes here) ├── templates/ ← reference templates with different palettes │ ├── architecture.html │ ├── mermaid-flowchart.html @@ -122,7 +158,6 @@ The skill routes to the right approach automatically: Mermaid for flowcharts and ## Limitations - Requires a browser to view -- Switching OS theme requires a page refresh for Mermaid SVGs - Results vary by model capability ## Credits diff --git a/plugins/visual-explainer/SKILL.md b/plugins/visual-explainer/SKILL.md index a0e2b10..5bde696 100644 --- a/plugins/visual-explainer/SKILL.md +++ b/plugins/visual-explainer/SKILL.md @@ -64,6 +64,95 @@ For prose accents, see "Prose Page Elements" in `./references/css-patterns.md`. Vary the choice each time. If the last diagram was dark and technical, make the next one light and editorial. The swap test: if you replaced your styling with a generic dark theme and nobody would notice the difference, you haven't designed anything. +**Interactive theme picker (always include).** Every generated page must include an interactive theme picker — a fixed row of 11 colored circle buttons (one per theme) that swap CSS custom properties on `` and re-render Mermaid diagrams live. Read all 11 theme files from `./themes/` to extract the exact CSS variable values for each. The active theme button gets a white ring (`outline: 2px solid #fff`). Pick one theme as the default on load. + +Available themes (read from `./themes/.md`): `dracula`, `nord`, `one-dark`, `catppuccin-mocha`, `tokyo-night`, `gruvbox-dark`, `synthwave-84`, `solarized-light`, `github-light`, `catppuccin-latte`, `gruvbox-light`. + +**Implementation pattern:** +```js +const themes = { + 'tokyo-night': { '--bg': '#1a1b26', '--surface': '#24283b', /* ... all vars */ }, + // ... one entry per theme, values from theme files +}; +const mermaidThemeVars = { + 'tokyo-night': { background: '#1a1b26', primaryColor: '...', /* ... */ }, + // ... +}; + +function applyTheme(name) { + const vars = themes[name]; + Object.entries(vars).forEach(([k, v]) => document.documentElement.style.setProperty(k, v)); + document.querySelectorAll('.theme-btn').forEach(b => + b.style.outline = b.dataset.theme === name ? '2px solid #fff' : 'none'); + // Re-render Mermaid diagrams (read from data-source, NOT el.textContent — + // after first render el.textContent is SVG, not the diagram source) + mermaid.initialize({ startOnLoad: false, theme: 'base', themeVariables: mermaidThemeVars[name] }); + for (const el of document.querySelectorAll('.mermaid')) { + el.removeAttribute('data-processed'); + const { svg } = await mermaid.render(el.id + '-svg', el.dataset.source); + el.innerHTML = svg; + } +} + +// Initial render — must save source to data-source BEFORE replacing innerHTML +async function renderMermaid() { + const themeKey = getCurrentTheme(); + initMermaid(themeKey); + for (const el of document.querySelectorAll('.mermaid')) { + if (!el.dataset.source) el.dataset.source = el.textContent; // save once + // Mermaid 11 uses htmlLabels (foreignObject) — literal \n in source is NOT + // interpreted as a line break. Convert to
before render. + const src = el.dataset.source.replaceAll('\\n', '
'); + const { svg } = await mermaid.render(el.id + '-svg', src); + el.innerHTML = svg; + } +} +``` + +**Critical:** Always save `el.textContent` to `el.dataset.source` before the first render. After render, `el.textContent` becomes SVG text — if re-render reads that instead of the original source, Mermaid throws "Syntax error in text". + +**`\n` in node labels:** Mermaid 11 renders flowchart labels as HTML inside ``. Literal `\n` (two chars: backslash + n) in the diagram source is NOT converted to a line break — it appears as `\n` in the output. Always preprocess: `src.replaceAll('\\n', '
')` before passing to `mermaid.render()`. Place the picker in a fixed header bar or sticky top strip; keep it out of the document flow so it doesn't break page layout. + +**Static config override.** If `.claude/visual-explainer.local.md` has a `theme:` field, use that theme as the default selected theme in the picker (not as a static override — the picker is always present). + +**Font pair picker (always include).** Every generated page must also include a font pair switcher — a row of small `Aa` chips (each rendered in its respective display font) that swap `--font-sans` and `--font-mono` CSS variables on `` and re-render Mermaid diagrams live. Place it in the same fixed panel as the theme picker, below the theme dots. + +Use `--font-sans` and `--font-mono` CSS variables throughout: `body { font-family: var(--font-sans), system-ui, sans-serif; }` and all monospace elements `font-family: var(--font-mono), monospace`. Pass the current `--font-mono` value into Mermaid's `fontFamily` themeVariable: `getComputedStyle(document.documentElement).getPropertyValue('--font-mono').trim()`. + +Default font pairs to offer (load all via a single Google Fonts URL). List the default first in the HTML so it occupies the top-left chip position: +- **Outfit / Cascadia Code** — clean, modern, excellent code readability **(default)** +- **Space Grotesk / Fira Code** — rounded, friendly +- **IBM Plex Sans / IBM Plex Mono** — systematic, professional +- **Fraunces / JetBrains Mono** — editorial serif +- **DM Sans / DM Mono** — minimal, clean +- **Syne / JetBrains Mono** — geometric, technical + +Set matching defaults in `:root`: `--font-sans: 'Outfit'; --font-mono: 'Cascadia Code';` + +Use Google Fonts only — never system fonts like Consolas (Windows-only). Cascadia Code is the preferred developer mono and is available on Google Fonts. + +```js +const fontPairs = { + 'cascadia': { sans: "'Outfit'", mono: "'Cascadia Code'" }, + 'space-grotesk': { sans: "'Space Grotesk'", mono: "'Fira Code'" }, + 'ibm': { sans: "'IBM Plex Sans'", mono: "'IBM Plex Mono'" }, + 'fraunces': { sans: "'Fraunces'", mono: "'JetBrains Mono'" }, + 'dm': { sans: "'DM Sans'", mono: "'DM Mono'" }, + 'syne': { sans: "'Syne'", mono: "'JetBrains Mono'" }, +}; + +document.querySelectorAll('.font-opt').forEach(opt => { + opt.addEventListener('click', function() { + const pair = fontPairs[this.dataset.font]; + document.documentElement.style.setProperty('--font-sans', pair.sans); + document.documentElement.style.setProperty('--font-mono', pair.mono); + document.querySelectorAll('.font-opt').forEach(o => o.classList.remove('active')); + this.classList.add('active'); + setTimeout(renderMermaid, 100); // re-render with new fontFamily + }); +}); +``` + ### 2. Structure **Read the reference material** before generating. Don't memorize it — read it each time to absorb the patterns. @@ -398,6 +487,7 @@ See `./commands/share.md` for the `/share` command template. Before delivering, verify: - **The squint test**: Blur your eyes. Can you still perceive hierarchy? Are sections visually distinct? - **The swap test**: Would replacing your fonts and colors with a generic dark theme make this indistinguishable from a template? If yes, push the aesthetic further. +- **Theme picker present**: Every page must have the interactive 11-theme picker. Verify buttons render and switching works (CSS vars swap, Mermaid re-renders). - **Both themes**: Toggle your OS between light and dark mode. Both should look intentional, not broken. - **Information completeness**: Does the diagram actually convey what the user asked for? Pretty but incomplete is a failure. - **No overflow**: Resize the browser to different widths. No content should clip or escape its container. Every grid and flex child needs `min-width: 0`. Side-by-side panels need `overflow-wrap: break-word`. Never use `display: flex` on `
  • ` for marker characters — it creates anonymous flex items that can't shrink, causing lines with many inline `` badges to overflow. Use absolute positioning for markers instead. See the Overflow Protection section in `./references/css-patterns.md`. diff --git a/plugins/visual-explainer/references/css-patterns.md b/plugins/visual-explainer/references/css-patterns.md index d20e004..c36c63e 100644 --- a/plugins/visual-explainer/references/css-patterns.md +++ b/plugins/visual-explainer/references/css-patterns.md @@ -6,6 +6,8 @@ Reusable patterns for layout, connectors, theming, and visual effects in self-co Always define both light and dark palettes via custom properties. Start with whichever fits the chosen aesthetic, ensure both work. +If a theme is active (configured in `.claude/visual-explainer.local.md`), replace the example palette below with the theme's CSS custom properties. The variable names are identical, so all patterns in this file work unchanged. Read the theme file from `./themes/.md` for the exact values. + ```css :root { --font-body: 'Outfit', system-ui, sans-serif; diff --git a/plugins/visual-explainer/themes/catppuccin-latte.md b/plugins/visual-explainer/themes/catppuccin-latte.md new file mode 100644 index 0000000..45cee89 --- /dev/null +++ b/plugins/visual-explainer/themes/catppuccin-latte.md @@ -0,0 +1,90 @@ +# Catppuccin Latte + +Light-first theme based on [Catppuccin Latte](https://catppuccin.com/palette/). Soothing pastel colors on a warm, light background. The lightest of the four Catppuccin flavors. + +## CSS Custom Properties + +Primary mode is light. Dark mode via `@media (prefers-color-scheme: dark)`. + +```css +:root { + --bg: #eff1f5; + --surface: #ccd0da; + --surface-elevated: #ffffff; + --border: rgba(0, 0, 0, 0.08); + --border-bright: rgba(0, 0, 0, 0.15); + --text: #4c4f69; + --text-dim: #9ca0b0; + --accent: #8839ef; + --accent-dim: rgba(136, 57, 239, 0.10); + + --node-a: #1e66f5; + --node-a-dim: rgba(30, 102, 245, 0.10); + --node-b: #40a02b; + --node-b-dim: rgba(64, 160, 43, 0.10); + --node-c: #ea76cb; + --node-c-dim: rgba(234, 118, 203, 0.10); + + --green: #40a02b; + --green-dim: rgba(64, 160, 43, 0.10); + --red: #d20f39; + --red-dim: rgba(210, 15, 57, 0.10); + --orange: #fe640b; + --orange-dim: rgba(254, 100, 11, 0.10); +} + +@media (prefers-color-scheme: dark) { + :root { + --bg: #1e1e2e; + --surface: #313244; + --surface-elevated: #45475a; + --border: rgba(255, 255, 255, 0.06); + --border-bright: rgba(255, 255, 255, 0.12); + --text: #cdd6f4; + --text-dim: #6c7086; + --accent: #cba6f7; + --accent-dim: rgba(203, 166, 247, 0.12); + + --node-a: #89b4fa; + --node-a-dim: rgba(137, 180, 250, 0.12); + --node-b: #a6e3a1; + --node-b-dim: rgba(166, 227, 161, 0.12); + --node-c: #f5c2e7; + --node-c-dim: rgba(245, 194, 231, 0.12); + + --green: #a6e3a1; + --green-dim: rgba(166, 227, 161, 0.12); + --red: #f38ba8; + --red-dim: rgba(243, 139, 168, 0.12); + --orange: #fab387; + --orange-dim: rgba(250, 179, 135, 0.12); + } +} +``` + +## Mermaid themeVariables + +Use with `theme: 'base'` in Mermaid configuration. + +```json +{ + "primaryColor": "#ccd0da", + "primaryTextColor": "#4c4f69", + "primaryBorderColor": "#9ca0b0", + "secondaryColor": "#8839ef", + "secondaryTextColor": "#eff1f5", + "secondaryBorderColor": "#8839ef", + "tertiaryColor": "#eff1f5", + "tertiaryTextColor": "#4c4f69", + "tertiaryBorderColor": "#9ca0b0", + "lineColor": "#9ca0b0", + "textColor": "#4c4f69", + "mainBkg": "#ccd0da", + "nodeBorder": "#9ca0b0", + "clusterBkg": "#eff1f5", + "clusterBorder": "#9ca0b0", + "titleColor": "#4c4f69", + "edgeLabelBackground": "#eff1f5", + "nodeTextColor": "#4c4f69" +} +``` diff --git a/plugins/visual-explainer/themes/catppuccin-mocha.md b/plugins/visual-explainer/themes/catppuccin-mocha.md new file mode 100644 index 0000000..ca44160 --- /dev/null +++ b/plugins/visual-explainer/themes/catppuccin-mocha.md @@ -0,0 +1,90 @@ +# Catppuccin Mocha + +Dark-first theme based on [Catppuccin Mocha](https://catppuccin.com/palette/). Soothing pastel colors on a deep, warm dark background. The darkest of the four Catppuccin flavors. + +## CSS Custom Properties + +Primary mode is dark. Light mode via `@media (prefers-color-scheme: light)`. + +```css +:root { + --bg: #1e1e2e; + --surface: #313244; + --surface-elevated: #45475a; + --border: rgba(255, 255, 255, 0.06); + --border-bright: rgba(255, 255, 255, 0.12); + --text: #cdd6f4; + --text-dim: #6c7086; + --accent: #cba6f7; + --accent-dim: rgba(203, 166, 247, 0.12); + + --node-a: #89b4fa; + --node-a-dim: rgba(137, 180, 250, 0.12); + --node-b: #a6e3a1; + --node-b-dim: rgba(166, 227, 161, 0.12); + --node-c: #f5c2e7; + --node-c-dim: rgba(245, 194, 231, 0.12); + + --green: #a6e3a1; + --green-dim: rgba(166, 227, 161, 0.12); + --red: #f38ba8; + --red-dim: rgba(243, 139, 168, 0.12); + --orange: #fab387; + --orange-dim: rgba(250, 179, 135, 0.12); +} + +@media (prefers-color-scheme: light) { + :root { + --bg: #eff1f5; + --surface: #ccd0da; + --surface-elevated: #ffffff; + --border: rgba(0, 0, 0, 0.08); + --border-bright: rgba(0, 0, 0, 0.15); + --text: #4c4f69; + --text-dim: #9ca0b0; + --accent: #8839ef; + --accent-dim: rgba(136, 57, 239, 0.10); + + --node-a: #1e66f5; + --node-a-dim: rgba(30, 102, 245, 0.10); + --node-b: #40a02b; + --node-b-dim: rgba(64, 160, 43, 0.10); + --node-c: #ea76cb; + --node-c-dim: rgba(234, 118, 203, 0.10); + + --green: #40a02b; + --green-dim: rgba(64, 160, 43, 0.10); + --red: #d20f39; + --red-dim: rgba(210, 15, 57, 0.10); + --orange: #fe640b; + --orange-dim: rgba(254, 100, 11, 0.10); + } +} +``` + +## Mermaid themeVariables + +Use with `theme: 'base'` in Mermaid configuration. + +```json +{ + "primaryColor": "#313244", + "primaryTextColor": "#cdd6f4", + "primaryBorderColor": "#6c7086", + "secondaryColor": "#cba6f7", + "secondaryTextColor": "#1e1e2e", + "secondaryBorderColor": "#cba6f7", + "tertiaryColor": "#1e1e2e", + "tertiaryTextColor": "#cdd6f4", + "tertiaryBorderColor": "#6c7086", + "lineColor": "#6c7086", + "textColor": "#cdd6f4", + "mainBkg": "#313244", + "nodeBorder": "#6c7086", + "clusterBkg": "#1e1e2e", + "clusterBorder": "#6c7086", + "titleColor": "#cdd6f4", + "edgeLabelBackground": "#1e1e2e", + "nodeTextColor": "#cdd6f4" +} +``` diff --git a/plugins/visual-explainer/themes/dracula.md b/plugins/visual-explainer/themes/dracula.md new file mode 100644 index 0000000..be81c4c --- /dev/null +++ b/plugins/visual-explainer/themes/dracula.md @@ -0,0 +1,90 @@ +# Dracula + +Dark-first theme based on the [official Dracula palette](https://draculatheme.com/spec). Rich purples, pinks, and cyans on a cool dark background. The light variant uses the official Alucard palette. + +## CSS Custom Properties + +Primary mode is dark. Light mode via `@media (prefers-color-scheme: light)`. + +```css +:root { + --bg: #282a36; + --surface: #44475a; + --surface-elevated: #4d5066; + --border: rgba(255, 255, 255, 0.08); + --border-bright: rgba(255, 255, 255, 0.15); + --text: #f8f8f2; + --text-dim: #6272a4; + --accent: #bd93f9; + --accent-dim: rgba(189, 147, 249, 0.12); + + --node-a: #8be9fd; + --node-a-dim: rgba(139, 233, 253, 0.12); + --node-b: #50fa7b; + --node-b-dim: rgba(80, 250, 123, 0.12); + --node-c: #ff79c6; + --node-c-dim: rgba(255, 121, 198, 0.12); + + --green: #50fa7b; + --green-dim: rgba(80, 250, 123, 0.12); + --red: #ff5555; + --red-dim: rgba(255, 85, 85, 0.12); + --orange: #ffb86c; + --orange-dim: rgba(255, 184, 108, 0.12); +} + +@media (prefers-color-scheme: light) { + :root { + --bg: #fffbeb; + --surface: #fff8dc; + --surface-elevated: #ffffff; + --border: rgba(0, 0, 0, 0.08); + --border-bright: rgba(0, 0, 0, 0.15); + --text: #1f1f1f; + --text-dim: #6c664b; + --accent: #644ac9; + --accent-dim: rgba(100, 74, 201, 0.10); + + --node-a: #036a96; + --node-a-dim: rgba(3, 106, 150, 0.10); + --node-b: #14710a; + --node-b-dim: rgba(20, 113, 10, 0.10); + --node-c: #a3144d; + --node-c-dim: rgba(163, 20, 77, 0.10); + + --green: #14710a; + --green-dim: rgba(20, 113, 10, 0.10); + --red: #cb3a2a; + --red-dim: rgba(203, 58, 42, 0.10); + --orange: #a34d14; + --orange-dim: rgba(163, 77, 20, 0.10); + } +} +``` + +## Mermaid themeVariables + +Use with `theme: 'base'` in Mermaid configuration. + +```json +{ + "primaryColor": "#44475a", + "primaryTextColor": "#f8f8f2", + "primaryBorderColor": "#6272a4", + "secondaryColor": "#bd93f9", + "secondaryTextColor": "#f8f8f2", + "secondaryBorderColor": "#bd93f9", + "tertiaryColor": "#282a36", + "tertiaryTextColor": "#f8f8f2", + "tertiaryBorderColor": "#6272a4", + "lineColor": "#6272a4", + "textColor": "#f8f8f2", + "mainBkg": "#44475a", + "nodeBorder": "#6272a4", + "clusterBkg": "#282a36", + "clusterBorder": "#6272a4", + "titleColor": "#f8f8f2", + "edgeLabelBackground": "#282a36", + "nodeTextColor": "#f8f8f2" +} +``` diff --git a/plugins/visual-explainer/themes/github-light.md b/plugins/visual-explainer/themes/github-light.md new file mode 100644 index 0000000..800d28e --- /dev/null +++ b/plugins/visual-explainer/themes/github-light.md @@ -0,0 +1,90 @@ +# GitHub Light + +Light-first theme based on [GitHub's Primer design system](https://primer.style/). Clean, minimal, and professional with GitHub's signature blue accent. + +## CSS Custom Properties + +Primary mode is light. Dark mode via `@media (prefers-color-scheme: dark)`. + +```css +:root { + --bg: #ffffff; + --surface: #f6f8fa; + --surface-elevated: #ffffff; + --border: rgba(0, 0, 0, 0.08); + --border-bright: #d0d7de; + --text: #1f2328; + --text-dim: #656d76; + --accent: #0969da; + --accent-dim: rgba(9, 105, 218, 0.10); + + --node-a: #0969da; + --node-a-dim: rgba(9, 105, 218, 0.10); + --node-b: #1a7f37; + --node-b-dim: rgba(26, 127, 55, 0.10); + --node-c: #8250df; + --node-c-dim: rgba(130, 80, 223, 0.10); + + --green: #1a7f37; + --green-dim: rgba(26, 127, 55, 0.10); + --red: #cf222e; + --red-dim: rgba(207, 34, 46, 0.10); + --orange: #bc4c00; + --orange-dim: rgba(188, 76, 0, 0.10); +} + +@media (prefers-color-scheme: dark) { + :root { + --bg: #0d1117; + --surface: #161b22; + --surface-elevated: #1c2333; + --border: rgba(255, 255, 255, 0.06); + --border-bright: #30363d; + --text: #e6edf3; + --text-dim: #8b949e; + --accent: #58a6ff; + --accent-dim: rgba(88, 166, 255, 0.12); + + --node-a: #58a6ff; + --node-a-dim: rgba(88, 166, 255, 0.12); + --node-b: #3fb950; + --node-b-dim: rgba(63, 185, 80, 0.12); + --node-c: #bc8cff; + --node-c-dim: rgba(188, 140, 255, 0.12); + + --green: #3fb950; + --green-dim: rgba(63, 185, 80, 0.12); + --red: #f85149; + --red-dim: rgba(248, 81, 73, 0.12); + --orange: #d29922; + --orange-dim: rgba(210, 153, 34, 0.12); + } +} +``` + +## Mermaid themeVariables + +Use with `theme: 'base'` in Mermaid configuration. + +```json +{ + "primaryColor": "#f6f8fa", + "primaryTextColor": "#1f2328", + "primaryBorderColor": "#d0d7de", + "secondaryColor": "#0969da", + "secondaryTextColor": "#ffffff", + "secondaryBorderColor": "#0969da", + "tertiaryColor": "#ffffff", + "tertiaryTextColor": "#1f2328", + "tertiaryBorderColor": "#d0d7de", + "lineColor": "#656d76", + "textColor": "#1f2328", + "mainBkg": "#f6f8fa", + "nodeBorder": "#d0d7de", + "clusterBkg": "#ffffff", + "clusterBorder": "#d0d7de", + "titleColor": "#1f2328", + "edgeLabelBackground": "#ffffff", + "nodeTextColor": "#1f2328" +} +``` diff --git a/plugins/visual-explainer/themes/gruvbox-dark.md b/plugins/visual-explainer/themes/gruvbox-dark.md new file mode 100644 index 0000000..d70901f --- /dev/null +++ b/plugins/visual-explainer/themes/gruvbox-dark.md @@ -0,0 +1,90 @@ +# Gruvbox Dark + +Dark-first theme based on [Gruvbox](https://github.com/morhetz/gruvbox). Retro groove colors with warm earthy tones — oranges, yellows, and greens on a dark brown background. + +## CSS Custom Properties + +Primary mode is dark. Light mode via `@media (prefers-color-scheme: light)`. + +```css +:root { + --bg: #282828; + --surface: #3c3836; + --surface-elevated: #504945; + --border: rgba(255, 255, 255, 0.06); + --border-bright: rgba(255, 255, 255, 0.12); + --text: #ebdbb2; + --text-dim: #a89984; + --accent: #fe8019; + --accent-dim: rgba(254, 128, 25, 0.12); + + --node-a: #83a598; + --node-a-dim: rgba(131, 165, 152, 0.12); + --node-b: #b8bb26; + --node-b-dim: rgba(184, 187, 38, 0.12); + --node-c: #d3869b; + --node-c-dim: rgba(211, 134, 155, 0.12); + + --green: #b8bb26; + --green-dim: rgba(184, 187, 38, 0.12); + --red: #fb4934; + --red-dim: rgba(251, 73, 52, 0.12); + --orange: #fe8019; + --orange-dim: rgba(254, 128, 25, 0.12); +} + +@media (prefers-color-scheme: light) { + :root { + --bg: #fbf1c7; + --surface: #ebdbb2; + --surface-elevated: #ffffff; + --border: rgba(0, 0, 0, 0.08); + --border-bright: rgba(0, 0, 0, 0.15); + --text: #3c3836; + --text-dim: #7c6f64; + --accent: #af3a03; + --accent-dim: rgba(175, 58, 3, 0.10); + + --node-a: #076678; + --node-a-dim: rgba(7, 102, 120, 0.10); + --node-b: #79740e; + --node-b-dim: rgba(121, 116, 14, 0.10); + --node-c: #8f3f71; + --node-c-dim: rgba(143, 63, 113, 0.10); + + --green: #79740e; + --green-dim: rgba(121, 116, 14, 0.10); + --red: #9d0006; + --red-dim: rgba(157, 0, 6, 0.10); + --orange: #af3a03; + --orange-dim: rgba(175, 58, 3, 0.10); + } +} +``` + +## Mermaid themeVariables + +Use with `theme: 'base'` in Mermaid configuration. + +```json +{ + "primaryColor": "#3c3836", + "primaryTextColor": "#ebdbb2", + "primaryBorderColor": "#a89984", + "secondaryColor": "#fe8019", + "secondaryTextColor": "#282828", + "secondaryBorderColor": "#fe8019", + "tertiaryColor": "#282828", + "tertiaryTextColor": "#ebdbb2", + "tertiaryBorderColor": "#a89984", + "lineColor": "#a89984", + "textColor": "#ebdbb2", + "mainBkg": "#3c3836", + "nodeBorder": "#a89984", + "clusterBkg": "#282828", + "clusterBorder": "#a89984", + "titleColor": "#ebdbb2", + "edgeLabelBackground": "#282828", + "nodeTextColor": "#ebdbb2" +} +``` diff --git a/plugins/visual-explainer/themes/gruvbox-light.md b/plugins/visual-explainer/themes/gruvbox-light.md new file mode 100644 index 0000000..9b3ed42 --- /dev/null +++ b/plugins/visual-explainer/themes/gruvbox-light.md @@ -0,0 +1,90 @@ +# Gruvbox Light + +Light-first theme based on [Gruvbox](https://github.com/morhetz/gruvbox). Retro groove colors with warm, creamy backgrounds and earthy faded accent tones. + +## CSS Custom Properties + +Primary mode is light. Dark mode via `@media (prefers-color-scheme: dark)`. + +```css +:root { + --bg: #fbf1c7; + --surface: #ebdbb2; + --surface-elevated: #ffffff; + --border: rgba(0, 0, 0, 0.08); + --border-bright: rgba(0, 0, 0, 0.15); + --text: #3c3836; + --text-dim: #7c6f64; + --accent: #af3a03; + --accent-dim: rgba(175, 58, 3, 0.10); + + --node-a: #076678; + --node-a-dim: rgba(7, 102, 120, 0.10); + --node-b: #79740e; + --node-b-dim: rgba(121, 116, 14, 0.10); + --node-c: #8f3f71; + --node-c-dim: rgba(143, 63, 113, 0.10); + + --green: #79740e; + --green-dim: rgba(121, 116, 14, 0.10); + --red: #9d0006; + --red-dim: rgba(157, 0, 6, 0.10); + --orange: #af3a03; + --orange-dim: rgba(175, 58, 3, 0.10); +} + +@media (prefers-color-scheme: dark) { + :root { + --bg: #282828; + --surface: #3c3836; + --surface-elevated: #504945; + --border: rgba(255, 255, 255, 0.06); + --border-bright: rgba(255, 255, 255, 0.12); + --text: #ebdbb2; + --text-dim: #a89984; + --accent: #fe8019; + --accent-dim: rgba(254, 128, 25, 0.12); + + --node-a: #83a598; + --node-a-dim: rgba(131, 165, 152, 0.12); + --node-b: #b8bb26; + --node-b-dim: rgba(184, 187, 38, 0.12); + --node-c: #d3869b; + --node-c-dim: rgba(211, 134, 155, 0.12); + + --green: #b8bb26; + --green-dim: rgba(184, 187, 38, 0.12); + --red: #fb4934; + --red-dim: rgba(251, 73, 52, 0.12); + --orange: #fe8019; + --orange-dim: rgba(254, 128, 25, 0.12); + } +} +``` + +## Mermaid themeVariables + +Use with `theme: 'base'` in Mermaid configuration. + +```json +{ + "primaryColor": "#ebdbb2", + "primaryTextColor": "#3c3836", + "primaryBorderColor": "#7c6f64", + "secondaryColor": "#af3a03", + "secondaryTextColor": "#fbf1c7", + "secondaryBorderColor": "#af3a03", + "tertiaryColor": "#fbf1c7", + "tertiaryTextColor": "#3c3836", + "tertiaryBorderColor": "#7c6f64", + "lineColor": "#7c6f64", + "textColor": "#3c3836", + "mainBkg": "#ebdbb2", + "nodeBorder": "#7c6f64", + "clusterBkg": "#fbf1c7", + "clusterBorder": "#7c6f64", + "titleColor": "#3c3836", + "edgeLabelBackground": "#fbf1c7", + "nodeTextColor": "#3c3836" +} +``` diff --git a/plugins/visual-explainer/themes/nord.md b/plugins/visual-explainer/themes/nord.md new file mode 100644 index 0000000..fae9c81 --- /dev/null +++ b/plugins/visual-explainer/themes/nord.md @@ -0,0 +1,90 @@ +# Nord + +Dark-first theme based on the [official Nord palette](https://www.nordtheme.com/). An arctic, north-bluish color palette with frost blues and aurora accents. Clean and minimal. + +## CSS Custom Properties + +Primary mode is dark. Light mode via `@media (prefers-color-scheme: light)`. + +```css +:root { + --bg: #2e3440; + --surface: #3b4252; + --surface-elevated: #434c5e; + --border: rgba(255, 255, 255, 0.06); + --border-bright: rgba(255, 255, 255, 0.12); + --text: #eceff4; + --text-dim: #4c566a; + --accent: #88c0d0; + --accent-dim: rgba(136, 192, 208, 0.12); + + --node-a: #88c0d0; + --node-a-dim: rgba(136, 192, 208, 0.12); + --node-b: #a3be8c; + --node-b-dim: rgba(163, 190, 140, 0.12); + --node-c: #b48ead; + --node-c-dim: rgba(180, 142, 173, 0.12); + + --green: #a3be8c; + --green-dim: rgba(163, 190, 140, 0.12); + --red: #bf616a; + --red-dim: rgba(191, 97, 106, 0.12); + --orange: #d08770; + --orange-dim: rgba(208, 135, 112, 0.12); +} + +@media (prefers-color-scheme: light) { + :root { + --bg: #eceff4; + --surface: #e5e9f0; + --surface-elevated: #ffffff; + --border: rgba(0, 0, 0, 0.08); + --border-bright: rgba(0, 0, 0, 0.15); + --text: #2e3440; + --text-dim: #4c566a; + --accent: #5e81ac; + --accent-dim: rgba(94, 129, 172, 0.10); + + --node-a: #5e81ac; + --node-a-dim: rgba(94, 129, 172, 0.10); + --node-b: #a3be8c; + --node-b-dim: rgba(163, 190, 140, 0.10); + --node-c: #b48ead; + --node-c-dim: rgba(180, 142, 173, 0.10); + + --green: #a3be8c; + --green-dim: rgba(163, 190, 140, 0.10); + --red: #bf616a; + --red-dim: rgba(191, 97, 106, 0.10); + --orange: #d08770; + --orange-dim: rgba(208, 135, 112, 0.10); + } +} +``` + +## Mermaid themeVariables + +Use with `theme: 'base'` in Mermaid configuration. + +```json +{ + "primaryColor": "#3b4252", + "primaryTextColor": "#eceff4", + "primaryBorderColor": "#4c566a", + "secondaryColor": "#88c0d0", + "secondaryTextColor": "#2e3440", + "secondaryBorderColor": "#88c0d0", + "tertiaryColor": "#2e3440", + "tertiaryTextColor": "#eceff4", + "tertiaryBorderColor": "#4c566a", + "lineColor": "#4c566a", + "textColor": "#eceff4", + "mainBkg": "#3b4252", + "nodeBorder": "#4c566a", + "clusterBkg": "#2e3440", + "clusterBorder": "#4c566a", + "titleColor": "#eceff4", + "edgeLabelBackground": "#2e3440", + "nodeTextColor": "#eceff4" +} +``` diff --git a/plugins/visual-explainer/themes/one-dark.md b/plugins/visual-explainer/themes/one-dark.md new file mode 100644 index 0000000..1756d2f --- /dev/null +++ b/plugins/visual-explainer/themes/one-dark.md @@ -0,0 +1,90 @@ +# One Dark + +Dark-first theme based on [Atom's One Dark](https://github.com/atom/one-dark-syntax) syntax theme. Cool blues, warm reds, and muted greens on a neutral dark background. + +## CSS Custom Properties + +Primary mode is dark. Light mode via `@media (prefers-color-scheme: light)`. + +```css +:root { + --bg: #282c34; + --surface: #2c313a; + --surface-elevated: #333842; + --border: rgba(255, 255, 255, 0.06); + --border-bright: rgba(255, 255, 255, 0.12); + --text: #abb2bf; + --text-dim: #5c6370; + --accent: #61afef; + --accent-dim: rgba(97, 175, 239, 0.12); + + --node-a: #61afef; + --node-a-dim: rgba(97, 175, 239, 0.12); + --node-b: #98c379; + --node-b-dim: rgba(152, 195, 121, 0.12); + --node-c: #c678dd; + --node-c-dim: rgba(198, 120, 221, 0.12); + + --green: #98c379; + --green-dim: rgba(152, 195, 121, 0.12); + --red: #e06c75; + --red-dim: rgba(224, 108, 117, 0.12); + --orange: #e5c07b; + --orange-dim: rgba(229, 192, 123, 0.12); +} + +@media (prefers-color-scheme: light) { + :root { + --bg: #fafafa; + --surface: #f0f0f0; + --surface-elevated: #ffffff; + --border: rgba(0, 0, 0, 0.08); + --border-bright: rgba(0, 0, 0, 0.15); + --text: #383a42; + --text-dim: #a0a1a7; + --accent: #4078f2; + --accent-dim: rgba(64, 120, 242, 0.10); + + --node-a: #4078f2; + --node-a-dim: rgba(64, 120, 242, 0.10); + --node-b: #50a14f; + --node-b-dim: rgba(80, 161, 79, 0.10); + --node-c: #a626a4; + --node-c-dim: rgba(166, 38, 164, 0.10); + + --green: #50a14f; + --green-dim: rgba(80, 161, 79, 0.10); + --red: #e45649; + --red-dim: rgba(228, 86, 73, 0.10); + --orange: #c18401; + --orange-dim: rgba(193, 132, 1, 0.10); + } +} +``` + +## Mermaid themeVariables + +Use with `theme: 'base'` in Mermaid configuration. + +```json +{ + "primaryColor": "#2c313a", + "primaryTextColor": "#abb2bf", + "primaryBorderColor": "#5c6370", + "secondaryColor": "#61afef", + "secondaryTextColor": "#282c34", + "secondaryBorderColor": "#61afef", + "tertiaryColor": "#282c34", + "tertiaryTextColor": "#abb2bf", + "tertiaryBorderColor": "#5c6370", + "lineColor": "#5c6370", + "textColor": "#abb2bf", + "mainBkg": "#2c313a", + "nodeBorder": "#5c6370", + "clusterBkg": "#282c34", + "clusterBorder": "#5c6370", + "titleColor": "#abb2bf", + "edgeLabelBackground": "#282c34", + "nodeTextColor": "#abb2bf" +} +``` diff --git a/plugins/visual-explainer/themes/solarized-light.md b/plugins/visual-explainer/themes/solarized-light.md new file mode 100644 index 0000000..245cd0d --- /dev/null +++ b/plugins/visual-explainer/themes/solarized-light.md @@ -0,0 +1,90 @@ +# Solarized Light + +Light-first theme based on [Solarized](https://ethanschoonover.com/solarized/) by Ethan Schoonover. Precise CIELAB lightness relationships with warm yellow-tinted backgrounds and carefully chosen accent colors. + +## CSS Custom Properties + +Primary mode is light. Dark mode via `@media (prefers-color-scheme: dark)`. + +```css +:root { + --bg: #fdf6e3; + --surface: #eee8d5; + --surface-elevated: #ffffff; + --border: rgba(0, 0, 0, 0.08); + --border-bright: rgba(0, 0, 0, 0.15); + --text: #657b83; + --text-dim: #93a1a1; + --accent: #268bd2; + --accent-dim: rgba(38, 139, 210, 0.10); + + --node-a: #268bd2; + --node-a-dim: rgba(38, 139, 210, 0.10); + --node-b: #859900; + --node-b-dim: rgba(133, 153, 0, 0.10); + --node-c: #d33682; + --node-c-dim: rgba(211, 54, 130, 0.10); + + --green: #859900; + --green-dim: rgba(133, 153, 0, 0.10); + --red: #dc322f; + --red-dim: rgba(220, 50, 47, 0.10); + --orange: #cb4b16; + --orange-dim: rgba(203, 75, 22, 0.10); +} + +@media (prefers-color-scheme: dark) { + :root { + --bg: #002b36; + --surface: #073642; + --surface-elevated: #0a4050; + --border: rgba(255, 255, 255, 0.06); + --border-bright: rgba(255, 255, 255, 0.12); + --text: #839496; + --text-dim: #586e75; + --accent: #268bd2; + --accent-dim: rgba(38, 139, 210, 0.12); + + --node-a: #268bd2; + --node-a-dim: rgba(38, 139, 210, 0.12); + --node-b: #859900; + --node-b-dim: rgba(133, 153, 0, 0.12); + --node-c: #d33682; + --node-c-dim: rgba(211, 54, 130, 0.12); + + --green: #859900; + --green-dim: rgba(133, 153, 0, 0.12); + --red: #dc322f; + --red-dim: rgba(220, 50, 47, 0.12); + --orange: #cb4b16; + --orange-dim: rgba(203, 75, 22, 0.12); + } +} +``` + +## Mermaid themeVariables + +Use with `theme: 'base'` in Mermaid configuration. + +```json +{ + "primaryColor": "#eee8d5", + "primaryTextColor": "#657b83", + "primaryBorderColor": "#93a1a1", + "secondaryColor": "#268bd2", + "secondaryTextColor": "#fdf6e3", + "secondaryBorderColor": "#268bd2", + "tertiaryColor": "#fdf6e3", + "tertiaryTextColor": "#657b83", + "tertiaryBorderColor": "#93a1a1", + "lineColor": "#93a1a1", + "textColor": "#657b83", + "mainBkg": "#eee8d5", + "nodeBorder": "#93a1a1", + "clusterBkg": "#fdf6e3", + "clusterBorder": "#93a1a1", + "titleColor": "#657b83", + "edgeLabelBackground": "#fdf6e3", + "nodeTextColor": "#657b83" +} +``` diff --git a/plugins/visual-explainer/themes/synthwave-84.md b/plugins/visual-explainer/themes/synthwave-84.md new file mode 100644 index 0000000..9424d15 --- /dev/null +++ b/plugins/visual-explainer/themes/synthwave-84.md @@ -0,0 +1,90 @@ +# Synthwave '84 + +Dark-first theme based on [SynthWave '84](https://github.com/robb0wen/synthwave-vscode). Neon pinks, cyans, and yellows on deep purple backgrounds. Evokes the retro-futuristic aesthetic of 1980s synthwave. + +## CSS Custom Properties + +Primary mode is dark. Light mode via `@media (prefers-color-scheme: light)`. + +```css +:root { + --bg: #262335; + --surface: #241b2f; + --surface-elevated: #2e2543; + --border: rgba(255, 255, 255, 0.08); + --border-bright: rgba(255, 255, 255, 0.15); + --text: #ffffff; + --text-dim: #848bbd; + --accent: #ff7edb; + --accent-dim: rgba(255, 126, 219, 0.12); + + --node-a: #36f9f6; + --node-a-dim: rgba(54, 249, 246, 0.12); + --node-b: #72f1b8; + --node-b-dim: rgba(114, 241, 184, 0.12); + --node-c: #fede5d; + --node-c-dim: rgba(254, 222, 93, 0.12); + + --green: #72f1b8; + --green-dim: rgba(114, 241, 184, 0.12); + --red: #fe4450; + --red-dim: rgba(254, 68, 80, 0.12); + --orange: #ff8b39; + --orange-dim: rgba(255, 139, 57, 0.12); +} + +@media (prefers-color-scheme: light) { + :root { + --bg: #f5f0ff; + --surface: #ece4f8; + --surface-elevated: #ffffff; + --border: rgba(0, 0, 0, 0.08); + --border-bright: rgba(0, 0, 0, 0.15); + --text: #262335; + --text-dim: #6b6499; + --accent: #b044a2; + --accent-dim: rgba(176, 68, 162, 0.10); + + --node-a: #0a8f8d; + --node-a-dim: rgba(10, 143, 141, 0.10); + --node-b: #1a8a5a; + --node-b-dim: rgba(26, 138, 90, 0.10); + --node-c: #9a7b00; + --node-c-dim: rgba(154, 123, 0, 0.10); + + --green: #1a8a5a; + --green-dim: rgba(26, 138, 90, 0.10); + --red: #c4222e; + --red-dim: rgba(196, 34, 46, 0.10); + --orange: #b85a10; + --orange-dim: rgba(184, 90, 16, 0.10); + } +} +``` + +## Mermaid themeVariables + +Use with `theme: 'base'` in Mermaid configuration. + +```json +{ + "primaryColor": "#241b2f", + "primaryTextColor": "#ffffff", + "primaryBorderColor": "#848bbd", + "secondaryColor": "#ff7edb", + "secondaryTextColor": "#262335", + "secondaryBorderColor": "#ff7edb", + "tertiaryColor": "#262335", + "tertiaryTextColor": "#ffffff", + "tertiaryBorderColor": "#848bbd", + "lineColor": "#848bbd", + "textColor": "#ffffff", + "mainBkg": "#241b2f", + "nodeBorder": "#848bbd", + "clusterBkg": "#262335", + "clusterBorder": "#848bbd", + "titleColor": "#ffffff", + "edgeLabelBackground": "#262335", + "nodeTextColor": "#ffffff" +} +``` diff --git a/plugins/visual-explainer/themes/tokyo-night.md b/plugins/visual-explainer/themes/tokyo-night.md new file mode 100644 index 0000000..1b6724b --- /dev/null +++ b/plugins/visual-explainer/themes/tokyo-night.md @@ -0,0 +1,90 @@ +# Tokyo Night + +Dark-first theme based on [Tokyo Night](https://github.com/tokyo-night/tokyo-night-vscode-theme). Inspired by the lights of downtown Tokyo at night. Cool blues and purples with warm accent colors. + +## CSS Custom Properties + +Primary mode is dark. Light mode via `@media (prefers-color-scheme: light)`. + +```css +:root { + --bg: #1a1b26; + --surface: #24283b; + --surface-elevated: #292e42; + --border: rgba(255, 255, 255, 0.06); + --border-bright: rgba(255, 255, 255, 0.12); + --text: #a9b1d6; + --text-dim: #565f89; + --accent: #7aa2f7; + --accent-dim: rgba(122, 162, 247, 0.12); + + --node-a: #7aa2f7; + --node-a-dim: rgba(122, 162, 247, 0.12); + --node-b: #9ece6a; + --node-b-dim: rgba(158, 206, 106, 0.12); + --node-c: #bb9af7; + --node-c-dim: rgba(187, 154, 247, 0.12); + + --green: #9ece6a; + --green-dim: rgba(158, 206, 106, 0.12); + --red: #f7768e; + --red-dim: rgba(247, 118, 142, 0.12); + --orange: #ff9e64; + --orange-dim: rgba(255, 158, 100, 0.12); +} + +@media (prefers-color-scheme: light) { + :root { + --bg: #e6e7ed; + --surface: #d5d6db; + --surface-elevated: #ffffff; + --border: rgba(0, 0, 0, 0.08); + --border-bright: rgba(0, 0, 0, 0.15); + --text: #343b58; + --text-dim: #6c6e75; + --accent: #2959aa; + --accent-dim: rgba(41, 89, 170, 0.10); + + --node-a: #2959aa; + --node-a-dim: rgba(41, 89, 170, 0.10); + --node-b: #385f0d; + --node-b-dim: rgba(56, 95, 13, 0.10); + --node-c: #5a3e8e; + --node-c-dim: rgba(90, 62, 142, 0.10); + + --green: #385f0d; + --green-dim: rgba(56, 95, 13, 0.10); + --red: #8c4351; + --red-dim: rgba(140, 67, 81, 0.10); + --orange: #965027; + --orange-dim: rgba(150, 80, 39, 0.10); + } +} +``` + +## Mermaid themeVariables + +Use with `theme: 'base'` in Mermaid configuration. + +```json +{ + "primaryColor": "#24283b", + "primaryTextColor": "#a9b1d6", + "primaryBorderColor": "#565f89", + "secondaryColor": "#7aa2f7", + "secondaryTextColor": "#1a1b26", + "secondaryBorderColor": "#7aa2f7", + "tertiaryColor": "#1a1b26", + "tertiaryTextColor": "#a9b1d6", + "tertiaryBorderColor": "#565f89", + "lineColor": "#565f89", + "textColor": "#a9b1d6", + "mainBkg": "#24283b", + "nodeBorder": "#565f89", + "clusterBkg": "#1a1b26", + "clusterBorder": "#565f89", + "titleColor": "#a9b1d6", + "edgeLabelBackground": "#1a1b26", + "nodeTextColor": "#a9b1d6" +} +```