Skip to content

Instantly share code, notes, and snippets.

@fauxparse
Last active August 10, 2026 03:59
Show Gist options
  • Select an option

  • Save fauxparse/6558206ebe165423549b2aab8983e575 to your computer and use it in GitHub Desktop.

Select an option

Save fauxparse/6558206ebe165423549b2aab8983e575 to your computer and use it in GitHub Desktop.
Mechanē issue 189 replacement theme candidate preview
<!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