add colors.toml and 0x-hex support, rescuing 44 more community themes
Poked at the 62 "no parseable source" skips from the first pass and found two things the pipeline didn't handle: several community repos genuinely ship colors.toml too — some in Omarchy 4's own semantic schema (best case, no derivation needed at all, same quality as the official 22), others reusing the filename for an unrelated flat color0..color15 scheme — and a handful of alacritty.toml files use 0xrrggbb instead of #rrggbb. palette.ts's loadPalette is now a thin wrapper over two exported pieces (parseTomlText, paletteFromRecord) so the community pipeline can attempt the real schema first without duplicating the reader; falls through to the color16 or ANSI-derived paths otherwise. generate-themes.ts --check still reports 0 changes for the official set — the refactor is behavior-preserving there, the lowercase-hex normalization it picked up along the way touched 7 official theme files cosmetically (their source colors.toml has uppercase hex), regenerated for real rather than left inconsistent with their own source. 147 -> 191 community themes ported. Of the original 62 unparseable repos, most turned out to be simply gone (404 on GitHub — repos deleted or renamed since the site listed them); the rest needed one of the two format additions above. 20 themes remain stuck: 16 dead repos, 2 with no repo link at all, and the same handful of genuinely low-contrast source palettes (mostly Solarized variants) where fixing contrast would mean changing the author's actual colours rather than porting them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,8 +3,10 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { execSync } from 'node:child_process';
|
||||
import { join } from 'node:path';
|
||||
import { mapPalette } from './themes/map';
|
||||
import type { Palette } from './themes/palette';
|
||||
import { paletteFromRecord, parseTomlText } from './themes/palette';
|
||||
import { deriveOmarchyPalette } from './themes/from-ansi';
|
||||
import { parseAlacrittyToml, parseGhosttyConf } from './themes/ansi-source';
|
||||
import { parseAlacrittyToml, parseColor16Toml, parseGhosttyConf } from './themes/ansi-source';
|
||||
import { contrast, ensureContrast, TEXT, UI } from './themes/contrast';
|
||||
|
||||
// Port community Omarchy themes from omarchythemes.com into the same 84-token shape the official
|
||||
@@ -36,7 +38,7 @@ type ManifestEntry = {
|
||||
id: string;
|
||||
name: string;
|
||||
repo: string;
|
||||
kind: 'alacritty.toml' | 'ghostty.conf';
|
||||
kind: string;
|
||||
dark: boolean;
|
||||
};
|
||||
|
||||
@@ -105,12 +107,29 @@ async function discoverRepo(slug: string): Promise<string | undefined> {
|
||||
return m ? `${m[1]}/${m[2]}` : undefined;
|
||||
}
|
||||
|
||||
async function sourceFor(
|
||||
repo: string,
|
||||
): Promise<{ ansi: NonNullable<ReturnType<typeof parseAlacrittyToml>>; kind: ManifestEntry['kind'] } | undefined> {
|
||||
async function sourceFor(repo: string): Promise<{ palette: Palette; kind: string; derived: boolean } | undefined> {
|
||||
const branch = ghApiDefaultBranch(repo);
|
||||
const raw = (p: string) => `https://raw.githubusercontent.com/${repo}/${branch}/${p}`;
|
||||
|
||||
// `colors.toml` is ambiguous across community repos: it might genuinely be Omarchy 4's own semantic
|
||||
// schema (in which case no derivation is needed at all — same quality as the official 22), or it might
|
||||
// reuse the filename for an unrelated flat `color0..color15` ANSI scheme. Try the real schema first;
|
||||
// only fall through to the ANSI reading if the required keys aren't there.
|
||||
const tomlText = await fetchText(raw('colors.toml'));
|
||||
if (tomlText) {
|
||||
const kv = parseTomlText(tomlText);
|
||||
try {
|
||||
return {
|
||||
palette: paletteFromRecord(kv, `${repo}/colors.toml`),
|
||||
kind: 'colors.toml (Omarchy schema)',
|
||||
derived: false,
|
||||
};
|
||||
} catch {
|
||||
const ansi = parseColor16Toml(kv);
|
||||
if (ansi) return { palette: deriveOmarchyPalette(ansi), kind: 'colors.toml (16-colour ANSI)', derived: true };
|
||||
}
|
||||
}
|
||||
|
||||
for (const path of [
|
||||
'alacritty.toml',
|
||||
'.config/alacritty.toml',
|
||||
@@ -120,13 +139,13 @@ async function sourceFor(
|
||||
const text = await fetchText(raw(path));
|
||||
if (!text) continue;
|
||||
const ansi = parseAlacrittyToml(text);
|
||||
if (ansi) return { ansi, kind: 'alacritty.toml' };
|
||||
if (ansi) return { palette: deriveOmarchyPalette(ansi), kind: 'alacritty.toml', derived: true };
|
||||
}
|
||||
for (const path of ['ghostty.conf', 'ghostty-theme', '.config/ghostty/config']) {
|
||||
const text = await fetchText(raw(path));
|
||||
if (!text) continue;
|
||||
const ansi = parseGhosttyConf(text);
|
||||
if (ansi) return { ansi, kind: 'ghostty.conf' };
|
||||
if (ansi) return { palette: deriveOmarchyPalette(ansi), kind: 'ghostty.conf', derived: true };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -136,9 +155,9 @@ async function portOne(slug: string): Promise<{ entry: ManifestEntry; css: strin
|
||||
if (!repo) return { skip: 'no github repo link found on its omarchythemes.com page' };
|
||||
|
||||
const source = await sourceFor(repo);
|
||||
if (!source) return { skip: `no parseable alacritty.toml/ghostty.conf in ${repo}` };
|
||||
if (!source) return { skip: `no parseable colors.toml/alacritty.toml/ghostty.conf in ${repo}` };
|
||||
|
||||
const palette = deriveOmarchyPalette(source.ansi);
|
||||
const palette = source.palette;
|
||||
const tokens = mapPalette(palette);
|
||||
|
||||
// `--input` carries a real accessibility requirement (a field boundary you can't see) where `--border`
|
||||
@@ -161,16 +180,19 @@ async function portOne(slug: string): Promise<{ entry: ManifestEntry; css: strin
|
||||
const body = Object.entries(tokens)
|
||||
.map(([k, v]) => ` ${k}: ${v};`)
|
||||
.join('\n');
|
||||
const modeLine = source.kind.startsWith('colors.toml (Omarchy')
|
||||
? `${palette.mode === 'dark' ? 'Dark theme' : 'Light theme'} (${palette.mode}) — the source repo's own colors.toml says so directly.`
|
||||
: `${palette.mode === 'dark' ? 'Dark theme' : 'Light theme'} (${palette.mode}), by luminance of its own background — the source repo carries no mode flag of its own to read.`;
|
||||
const provenanceLine = source.derived
|
||||
? `went through deriveOmarchyPalette (scripts/themes/from-ansi.ts) because the source has no Omarchy 4\n colors.toml — some tokens here are reconstructed, not authored.`
|
||||
: `came straight from the repo's own colors.toml — the same schema and reader the official 22 themes\n use, so nothing here is reconstructed.`;
|
||||
const css = `/*
|
||||
${name} — ported from a community Omarchy theme, not from basecamp/omarchy's own set.
|
||||
|
||||
${palette.mode === 'dark' ? 'Dark theme' : 'Light theme'} (${palette.mode}), by luminance of its own
|
||||
background — the source repo carries no mode flag of its own to read.
|
||||
${modeLine}
|
||||
|
||||
Source: https://github.com/${repo} (${source.kind}), read by scripts/port-community-themes.ts. Values
|
||||
went through deriveOmarchyPalette (scripts/themes/from-ansi.ts) because a single-theme repo ships
|
||||
per-app configs, not Omarchy 4's own colors.toml shape — some tokens here are reconstructed, not
|
||||
authored. Every text/surface pair is contrast-checked the same way the official themes are.
|
||||
${provenanceLine} Every text/surface pair is contrast-checked the same way the official themes are.
|
||||
|
||||
DO NOT EDIT BY HAND. Re-run the script to refresh from the source repo.
|
||||
*/
|
||||
|
||||
@@ -32,12 +32,14 @@ export type AnsiSource = {
|
||||
brightWhite: string;
|
||||
};
|
||||
|
||||
const HEX = /#[0-9a-fA-F]{3,8}/;
|
||||
// `#rrggbb` is standard; `0xrrggbb` shows up in a handful of community alacritty.toml files (their
|
||||
// authors apparently ported from a scheme that used C-style hex literals).
|
||||
const HEX = /#[0-9a-fA-F]{3,8}|0x[0-9a-fA-F]{3,8}/;
|
||||
|
||||
function normalizeHex(v: string): string | undefined {
|
||||
const m = v.match(HEX);
|
||||
if (!m) return undefined;
|
||||
let h = m[0].slice(1).toLowerCase();
|
||||
let h = m[0].replace(/^(#|0x)/, '').toLowerCase();
|
||||
if (h.length === 3)
|
||||
h = h
|
||||
.split('')
|
||||
@@ -165,3 +167,39 @@ export function parseGhosttyConf(text: string): AnsiSource | undefined {
|
||||
brightWhite: palette[15]!,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A third shape some community repos name `colors.toml` too, unrelated to Omarchy 4's own — flat
|
||||
* `color0`..`color15` in standard ANSI order, plus `background`/`foreground`. Try this only after
|
||||
* `paletteFromRecord` (the real Omarchy schema) has already failed on the same file: the two are
|
||||
* distinguished only by which keys are present, and a file can't be both.
|
||||
*/
|
||||
export function parseColor16Toml(t: Record<string, string>): AnsiSource | undefined {
|
||||
const at = (i: number): string | undefined => (t[`color${i}`] ? normalizeHex(t[`color${i}`]!) : undefined);
|
||||
const background = t.background ? normalizeHex(t.background) : undefined;
|
||||
const foreground = t.foreground ? normalizeHex(t.foreground) : undefined;
|
||||
if (!background || !foreground) return undefined;
|
||||
const slots = Array.from({ length: 16 }, (_, i) => at(i));
|
||||
if (slots.some((s) => !s)) return undefined;
|
||||
|
||||
return {
|
||||
background,
|
||||
foreground,
|
||||
black: slots[0]!,
|
||||
red: slots[1]!,
|
||||
green: slots[2]!,
|
||||
yellow: slots[3]!,
|
||||
blue: slots[4]!,
|
||||
magenta: slots[5]!,
|
||||
cyan: slots[6]!,
|
||||
white: slots[7]!,
|
||||
brightBlack: slots[8]!,
|
||||
brightRed: slots[9]!,
|
||||
brightGreen: slots[10]!,
|
||||
brightYellow: slots[11]!,
|
||||
brightBlue: slots[12]!,
|
||||
brightMagenta: slots[13]!,
|
||||
brightCyan: slots[14]!,
|
||||
brightWhite: slots[15]!,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -55,6 +55,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "andromeda",
|
||||
"name": "Andromeda",
|
||||
"repo": "signaldirective/andromeda",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "anonymous",
|
||||
"name": "Anonymous",
|
||||
@@ -97,6 +104,20 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "ash",
|
||||
"name": "Ash",
|
||||
"repo": "bjarneo/omarchy-ash-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "astrodark",
|
||||
"name": "Astrodark",
|
||||
"repo": "JamsMendez/omarchy-astrodark-theme",
|
||||
"kind": "colors.toml (Omarchy schema)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "atari",
|
||||
"name": "Atari",
|
||||
@@ -195,6 +216,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "biscuit-de-mar-dark",
|
||||
"name": "Biscuit DE Mar Dark",
|
||||
"repo": "OldJobobo/omarchy-biscuit-de-mar-dark-theme",
|
||||
"kind": "colors.toml (Omarchy schema)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "black-arch",
|
||||
"name": "Black Arch",
|
||||
@@ -202,6 +230,27 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "black-gold",
|
||||
"name": "Black Gold",
|
||||
"repo": "HANCORE-linux/omarchy-blackgold-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "black-money",
|
||||
"name": "Black Money",
|
||||
"repo": "HANCORE-linux/omarchy-blackmoney-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "blackturq",
|
||||
"name": "Blackturq",
|
||||
"repo": "HANCORE-linux/omarchy-blackturq-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "blueridge",
|
||||
"name": "Blueridge",
|
||||
@@ -230,6 +279,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "cattpuccin-glass",
|
||||
"name": "Cattpuccin Glass",
|
||||
"repo": "Luquatic/omarchy-catppuccin-glass",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "city-783",
|
||||
"name": "City 783",
|
||||
@@ -244,6 +300,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "corporate",
|
||||
"name": "Corporate",
|
||||
"repo": "defer/omarchy-corporate-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": false
|
||||
},
|
||||
{
|
||||
"id": "cpunk",
|
||||
"name": "Cpunk",
|
||||
@@ -258,6 +321,20 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "crimson-gold",
|
||||
"name": "Crimson Gold",
|
||||
"repo": "knappkevin/omarchy-crimson-gold-theme",
|
||||
"kind": "colors.toml (Omarchy schema)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "cyberpunk-2",
|
||||
"name": "Cyberpunk 2",
|
||||
"repo": "SeanAnd/omarchy-cyberpunk-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "dark-xp",
|
||||
"name": "Dark XP",
|
||||
@@ -307,6 +384,20 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "desert-gleam",
|
||||
"name": "Desert Gleam",
|
||||
"repo": "avis3nna/desert-gleam",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": false
|
||||
},
|
||||
{
|
||||
"id": "desert-twilight",
|
||||
"name": "Desert Twilight",
|
||||
"repo": "avis3nna/desert-twilight",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "dotrb",
|
||||
"name": "Dotrb",
|
||||
@@ -342,6 +433,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "elysian",
|
||||
"name": "Elysian",
|
||||
"repo": "bjarneo/omarchy-elysian-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "ember-n-ash",
|
||||
"name": "Ember N Ash",
|
||||
@@ -370,6 +468,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "evergarden",
|
||||
"name": "Evergarden",
|
||||
"repo": "celsobenedetti/omarchy-evergarden",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "farline",
|
||||
"name": "Farline",
|
||||
@@ -384,6 +489,27 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "fiery-ocean",
|
||||
"name": "Fiery Ocean",
|
||||
"repo": "bjarneo/omarchy-fiery-ocean-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "fireside",
|
||||
"name": "Fireside",
|
||||
"repo": "bjarneo/omarchy-fireside-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "firesky",
|
||||
"name": "Firesky",
|
||||
"repo": "bjarneo/omarchy-firesky-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "flat-dracula",
|
||||
"name": "Flat Dracula",
|
||||
@@ -391,6 +517,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "flexoki-dark",
|
||||
"name": "Flexoki Dark",
|
||||
"repo": "euandeas/omarchy-flexoki-dark-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "florida-man",
|
||||
"name": "Florida Man",
|
||||
@@ -412,6 +545,27 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "frost",
|
||||
"name": "Frost",
|
||||
"repo": "bjarneo/omarchy-frost-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "futurism",
|
||||
"name": "Futurism",
|
||||
"repo": "bjarneo/omarchy-futurism-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "ghost-pastel",
|
||||
"name": "Ghost Pastel",
|
||||
"repo": "row-huh/omarchy-ghost-pastel-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "glory-antic",
|
||||
"name": "Glory Antic",
|
||||
@@ -475,6 +629,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": false
|
||||
},
|
||||
{
|
||||
"id": "harbor-dark",
|
||||
"name": "Harbor Dark",
|
||||
"repo": "HANCORE-linux/omarchy-harbordark-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "hex",
|
||||
"name": "Hex",
|
||||
@@ -496,6 +657,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "hollow-knight",
|
||||
"name": "Hollow Knight",
|
||||
"repo": "bjarneo/omarchy-hollow-knight-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "infernium",
|
||||
"name": "Infernium",
|
||||
@@ -510,6 +678,20 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "inkypinky",
|
||||
"name": "Inkypinky",
|
||||
"repo": "HANCORE-linux/omarchy-inkypinky-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "kanso",
|
||||
"name": "Kanso",
|
||||
"repo": "HANCORE-linux/omarchy-kanso-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "killer-klowns",
|
||||
"name": "Killer Klowns",
|
||||
@@ -517,6 +699,20 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "kimiko",
|
||||
"name": "Kimiko",
|
||||
"repo": "krymzonn/omarchy-kimiko-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "koyanagi",
|
||||
"name": "Koyanagi",
|
||||
"repo": "YutaKoyanagi10/omarchy-koyanagi-theme",
|
||||
"kind": "colors.toml (Omarchy schema)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "kurayami",
|
||||
"name": "Kurayami",
|
||||
@@ -650,6 +846,20 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "monolith-2",
|
||||
"name": "Monolith 2",
|
||||
"repo": "grvsnh/omarchy-monolith-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "moodpeak",
|
||||
"name": "Moodpeak",
|
||||
"repo": "HANCORE-linux/omarchy-moodpeak-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "nagai-poolside",
|
||||
"name": "Nagai Poolside",
|
||||
@@ -692,6 +902,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "nes",
|
||||
"name": "Nes",
|
||||
"repo": "bjarneo/omarchy-nes-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "nyc",
|
||||
"name": "Nyc",
|
||||
@@ -699,6 +916,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "one-dark-pro",
|
||||
"name": "One Dark Pro",
|
||||
"repo": "sc0ttman/omarchy-one-dark-pro",
|
||||
"kind": "colors.toml (Omarchy schema)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "oxford",
|
||||
"name": "Oxford",
|
||||
@@ -720,6 +944,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "pina",
|
||||
"name": "Pina",
|
||||
"repo": "bjarneo/omarchy-pina-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "pink-blood",
|
||||
"name": "Pink Blood",
|
||||
@@ -727,6 +958,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "pmndrs",
|
||||
"name": "Pmndrs",
|
||||
"repo": "leweyse/omarchy-pmndrs-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "pulsar",
|
||||
"name": "Pulsar",
|
||||
@@ -776,6 +1014,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "reverie",
|
||||
"name": "Reverie",
|
||||
"repo": "bjarneo/omarchy-reverie-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "robco",
|
||||
"name": "Robco",
|
||||
@@ -790,6 +1035,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "rose-pine-dark",
|
||||
"name": "Rose Pine Dark",
|
||||
"repo": "guilhermetk/omarchy-rose-pine-dark",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "roseofdune",
|
||||
"name": "Roseofdune",
|
||||
@@ -811,6 +1063,48 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "saga",
|
||||
"name": "Saga",
|
||||
"repo": "HANCORE-linux/omarchy-saga-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "sakura",
|
||||
"name": "Sakura",
|
||||
"repo": "bjarneo/omarchy-sakura-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "sapphire",
|
||||
"name": "Sapphire",
|
||||
"repo": "HANCORE-linux/omarchy-sapphire-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "serenity",
|
||||
"name": "Serenity",
|
||||
"repo": "bjarneo/omarchy-serenity-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "shadesofjade",
|
||||
"name": "Shadesofjade",
|
||||
"repo": "HANCORE-linux/omarchy-shadesofjade-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "snow",
|
||||
"name": "Snow",
|
||||
"repo": "bjarneo/omarchy-snow-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": false
|
||||
},
|
||||
{
|
||||
"id": "snow-black",
|
||||
"name": "Snow Black",
|
||||
@@ -860,6 +1154,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "sunkissed",
|
||||
"name": "Sunkissed",
|
||||
"repo": "loeclos/omarchy-sunkissed-theme",
|
||||
"kind": "alacritty.toml",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "sunset",
|
||||
"name": "Sunset",
|
||||
@@ -1021,6 +1322,13 @@
|
||||
"kind": "alacritty.toml",
|
||||
"dark": false
|
||||
},
|
||||
{
|
||||
"id": "x-1632",
|
||||
"name": "X 1632",
|
||||
"repo": "OldJobobo/omarchy-x-1632-theme",
|
||||
"kind": "colors.toml (16-colour ANSI)",
|
||||
"dark": true
|
||||
},
|
||||
{
|
||||
"id": "yuugure",
|
||||
"name": "Yuugure",
|
||||
|
||||
@@ -38,21 +38,28 @@ export type Palette = {
|
||||
brightMagenta: string;
|
||||
};
|
||||
|
||||
/** A deliberately small TOML reader: this file is flat `key = "value"` and nothing else. */
|
||||
function readToml(path: string): Record<string, string> {
|
||||
/**
|
||||
* A deliberately small TOML reader: this file is flat `key = "value"` and nothing else.
|
||||
*
|
||||
* Exported (not just used by `loadPalette` below) because a community theme can ship this exact shape
|
||||
* too — see `port-community-themes.ts`, which reads it from a fetched string rather than a file path.
|
||||
*/
|
||||
export function parseTomlText(text: string): Record<string, string> {
|
||||
const out: Record<string, string> = {};
|
||||
for (const line of readFileSync(path, 'utf8').split('\n')) {
|
||||
for (const line of text.split('\n')) {
|
||||
const m = line.match(/^\s*([a-z_0-9]+)\s*=\s*"([^"]*)"/i);
|
||||
if (m) out[m[1]!] = m[2]!;
|
||||
// basecamp/omarchy's own files are already lowercase hex; a community `colors.toml` isn't guaranteed
|
||||
// to be, so normalize here rather than leaving the two sources visibly inconsistent.
|
||||
if (m) out[m[1]!] = m[2]!.toLowerCase();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export function loadPalette(tomlPath: string): Palette {
|
||||
const t = readToml(tomlPath);
|
||||
/** The 24-key contract, given an already-parsed record rather than a path — see `parseTomlText`. */
|
||||
export function paletteFromRecord(t: Record<string, string>, label: string): Palette {
|
||||
const need = (key: string): string => {
|
||||
const v = t[key];
|
||||
if (!v) throw new Error(`${tomlPath}: missing "${key}"`);
|
||||
if (!v) throw new Error(`${label}: missing "${key}"`);
|
||||
return v;
|
||||
};
|
||||
|
||||
@@ -84,3 +91,7 @@ export function loadPalette(tomlPath: string): Palette {
|
||||
brightMagenta: need('bright_magenta'),
|
||||
};
|
||||
}
|
||||
|
||||
export function loadPalette(tomlPath: string): Palette {
|
||||
return paletteFromRecord(parseTomlText(readFileSync(tomlPath, 'utf8')), tomlPath);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user