Last active
August 10, 2026 03:59
-
-
Save fauxparse/6558206ebe165423549b2aab8983e575 to your computer and use it in GitHub Desktop.
Mechanē issue 189 replacement theme candidate preview
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!doctype html> | |
| <meta charset="utf-8"> | |
| <title>Mechanē issue 189 theme replacement preview</title> | |
| <style> | |
| :root { font: 14px/1.45 system-ui, sans-serif; color: #f8fafc; background: #0f172a; } | |
| body { margin: 0; padding: 32px; } | |
| h1 { margin: 0 0 8px; } | |
| .note { color: #94a3b8; margin: 0 0 24px; } | |
| .candidate { margin: 24px 0 40px; } | |
| .candidate h2 { margin: 0 0 12px; } | |
| .modes { display: grid; grid-template-columns: repeat(2, minmax(320px, 1fr)); gap: 16px; } | |
| .mode { color: var(--fg); background: var(--bg); border: 1px solid color-mix(in oklab, var(--fg), transparent 78%); border-radius: 12px; padding: 16px; } | |
| .mode h3 { margin: 0 0 12px; font-size: 13px; color: var(--muted-fg); } | |
| .chrome { display: grid; grid-template-columns: 120px 1fr; gap: 12px; } | |
| nav { background: var(--surface); border-radius: 8px; padding: 10px; } | |
| nav strong { display: block; margin-bottom: 8px; } | |
| nav span { display: block; padding: 5px 7px; border-radius: 5px; color: var(--muted-fg); } | |
| nav span.active { color: var(--surface-fg); background: var(--primary); } | |
| main { display: grid; gap: 10px; } | |
| .card { background: var(--surface); color: var(--surface-fg); border: 1px solid var(--border); border-radius: 8px; padding: 12px; } | |
| .card h4 { margin: 0 0 5px; } | |
| .card p { color: var(--muted-fg); margin: 0 0 10px; } | |
| .buttons { display: flex; flex-wrap: wrap; gap: 7px; } | |
| button { border: 0; border-radius: 5px; padding: 6px 9px; color: var(--primary-fg); background: var(--primary); font: inherit; } | |
| button.secondary { color: var(--surface-fg); background: var(--secondary); } | |
| button.danger { color: #fff; background: var(--danger); } | |
| .nodes { display: flex; gap: 7px; flex-wrap: wrap; } | |
| .node { border: 2px solid var(--success); border-radius: 6px; padding: 7px 9px; } | |
| .node.primary { border-color: var(--primary); } | |
| .swatches { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; margin-top: 12px; } | |
| .swatch { min-width: 0; } | |
| .swatch i { display: block; aspect-ratio: 1.8; border-radius: 4px; border: 1px solid #0004; background: var(--swatch); } | |
| .swatch small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 3px; color: var(--muted-fg); } | |
| @media (max-width: 800px) { .modes { grid-template-columns: 1fr; } } | |
| </style> | |
| <h1>Issue 189: replacement-theme preview</h1> | |
| <p class="note">Source-palette comparison for the declared Base16/Base24 pairs. It exercises the shared semantic shape; numeric ramp generation remains the #186/#191 implementation step.</p> | |
| <div id="app"></div> | |
| <script> | |
| const themes = [ | |
| { | |
| key: "tokyo-night", label: "Tokyo Night", primary: "blue", | |
| dark: { bg: "#16161e", surface: "#1a1b26", muted: "#2f3549", mutedFg: "#787c99", fg: "#d5d6db", primary: "#7aa2f7", primaryFg: "#16161e", danger: "#f7768e", success: "#9ece6a", hues: ["#f7768e", "#ff9e64", "#e0af68", "#9ece6a", "#7dcfff", "#7aa2f7", "#bb9af7"] }, | |
| light: { bg: "#d5d6db", surface: "#cbccd1", muted: "#dfe0e5", mutedFg: "#4c505e", fg: "#1a1b26", primary: "#34548a", primaryFg: "#f8fafc", danger: "#8c4351", success: "#33635c", hues: ["#8c4351", "#965027", "#8f5e15", "#9ece6a", "#0f4b6e", "#34548a", "#5a4a78"] } | |
| }, | |
| { | |
| key: "catppuccin", label: "Catppuccin", primary: "purple", | |
| dark: { bg: "#1e1e2e", surface: "#181825", muted: "#313244", mutedFg: "#585b70", fg: "#cdd6f4", primary: "#cba6f7", primaryFg: "#1e1e2e", danger: "#f38ba8", success: "#a6e3a1", hues: ["#f38ba8", "#fab387", "#f9e2af", "#a6e3a1", "#94e2d5", "#89b4fa", "#cba6f7"] }, | |
| light: { bg: "#eff1f5", surface: "#e6e9ef", muted: "#ccd0da", mutedFg: "#6c6f85", fg: "#4c4f69", primary: "#8839ef", primaryFg: "#eff1f5", danger: "#d20f39", success: "#40a02b", hues: ["#d20f39", "#fe640b", "#df8e1d", "#40a02b", "#179299", "#1e66f5", "#8839ef"] } | |
| }, | |
| { | |
| key: "dracula", label: "Dracula / Alucard", primary: "purple", | |
| dark: { bg: "#282a36", surface: "#21222c", muted: "#44475a", mutedFg: "#6272a4", fg: "#f8f8f2", primary: "#bd93f9", primaryFg: "#282a36", danger: "#ff5555", success: "#50fa7b", hues: ["#ff5555", "#ffb86c", "#f1fa8c", "#50fa7b", "#8be9fd", "#bd93f9", "#ff79c6"] }, | |
| light: { bg: "#fffbeb", surface: "#ceccc0", muted: "#cfcfde", mutedFg: "#6c664b", fg: "#1f1f1f", primary: "#644ac9", primaryFg: "#fffbeb", danger: "#cb3a2a", success: "#14710a", hues: ["#cb3a2a", "#a34d14", "#846e15", "#14710a", "#036a96", "#644ac9", "#a3144d"] } | |
| }, | |
| { | |
| key: "gruvbox", label: "Gruvbox", primary: "orange", | |
| dark: { bg: "#282828", surface: "#3c3836", muted: "#504945", mutedFg: "#bdae93", fg: "#d5c4a1", primary: "#fe8019", primaryFg: "#282828", danger: "#fb4934", success: "#b8bb26", hues: ["#fb4934", "#fe8019", "#fabd2f", "#b8bb26", "#8ec07c", "#83a598", "#d3869b"] }, | |
| light: { bg: "#fbf1c7", surface: "#ebdbb2", muted: "#d5c4a1", mutedFg: "#665c54", fg: "#504945", primary: "#af3a03", primaryFg: "#fbf1c7", danger: "#9d0006", success: "#79740e", hues: ["#9d0006", "#af3a03", "#b57614", "#79740e", "#427b58", "#076678", "#8f3f71"] } | |
| } | |
| ]; | |
| const names = ["red", "orange", "yellow", "green", "aqua", "blue", "purple"]; | |
| const app = document.querySelector("#app"); | |
| for (const theme of themes) { | |
| const section = document.createElement("section"); | |
| section.className = "candidate"; | |
| section.innerHTML = `<h2>${theme.label} <small>(key: ${theme.key}, primary: ${theme.primary})</small></h2>`; | |
| const modes = document.createElement("div"); | |
| modes.className = "modes"; | |
| for (const modeName of ["dark", "light"]) { | |
| const colors = theme[modeName]; | |
| const mode = document.createElement("article"); | |
| mode.className = "mode"; | |
| mode.style.cssText = Object.entries({"--bg": colors.bg, "--surface": colors.surface, "--muted": colors.muted, "--muted-fg": colors.mutedFg, "--fg": colors.fg, "--surface-fg": colors.fg, "--primary": colors.primary, "--primary-fg": colors.primaryFg, "--danger": colors.danger, "--success": colors.success, "--secondary": colors.muted, "--border": colors.muted}).map(([name, value]) => `${name}:${value}`).join(";"); | |
| mode.innerHTML = `<h3>${modeName}</h3><div class="chrome"><nav><strong>Mechanē</strong><span class="active">Shows</span><span>Devices</span><span>Settings</span></nav><main><div class="card"><h4>Audience vote</h4><p>4 Scenes · 2 Devices · 1 Flow</p><div class="buttons"><button>Open Show</button><button class="secondary">Duplicate</button><button class="danger">Delete</button></div></div><div class="nodes"><span class="node primary">Flow</span><span class="node">Scene</span><span class="node">Source</span></div></main></div><div class="swatches">${colors.hues.map((color, index) => `<div class="swatch" style="--swatch:${color}"><i></i><small>${names[index]}</small></div>`).join("")}</div>`; | |
| modes.append(mode); | |
| } | |
| section.append(modes); | |
| app.append(section); | |
| } | |
| </script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment