Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | 35x 35x 35x 35x 1505x 1505x 35x 35x 525x 35x 35x 525x 525x 525x 1505x 35x 1505x 35x 1515x 1515x 1506x 1506x 1505x 1505x 1505x 105x 105x 1400x 1400x 1400x 1400x 1400x 1400x 1400x 1505x | // SPDX-License-Identifier: MIT
/**
* Consolidated theme metadata derived from tokens.json.
*
* All display metadata (names, appearances, vendor groups) is computed from
* the canonical token data at module evaluation time. Consumers should import
* from here instead of maintaining their own hardcoded copies.
*
* Vendor order and ThemeId come from build-time codegen
* (`packages/core/src/themes/generated/metadata.ts`).
*/
import type { ThemeFlavor } from '../themes/types.js';
import { flavors, themeIds, packages } from '../tokens/index.js';
import { VENDOR_ORDER as GENERATED_VENDOR_ORDER } from './generated/metadata.js';
export type { ThemeId, VendorId } from './generated/metadata.js';
export {
THEME_IDS,
THEME_DESCRIPTIONS,
THEME_ICONS,
VENDOR_ICONS,
VENDOR_FAMILY_META,
} from './generated/metadata.js';
/** Default theme applied when no preference is stored. */
export const DEFAULT_THEME = 'catppuccin-mocha' as const;
/** All valid theme IDs (re-export for convenience). */
export const VALID_THEMES: readonly string[] = themeIds;
/** Set of valid theme IDs for O(1) lookup. */
export const VALID_THEME_SET: ReadonlySet<string> = /*#__PURE__*/ new Set(themeIds);
/** Full human-readable label for each theme (e.g., "Catppuccin Mocha"). */
export const THEME_NAMES: Readonly<Record<string, string>> = /*#__PURE__*/ Object.fromEntries(
flavors.map((f) => [f.id, f.label]),
);
/** Appearance (light/dark) for each theme. */
export const THEME_APPEARANCES: Readonly<Record<string, 'light' | 'dark'>> =
/*#__PURE__*/ Object.fromEntries(flavors.map((f) => [f.id, f.appearance]));
/**
* Ordered list of vendor IDs controlling display order in dropdowns.
* Generated from schema/tokens/_vendors.json — do not edit by hand.
*/
export const VENDOR_ORDER: readonly string[] = GENERATED_VENDOR_ORDER;
/** A vendor group with its display name and ordered theme IDs. */
export interface VendorGroup {
id: string;
displayName: string;
themeIds: string[];
}
/**
* Ordered array of vendor groups derived from packages + VENDOR_ORDER.
* The "(synced)" suffix is stripped from display names.
*/
// Dev-time validation: warn if packages has vendors not listed in VENDOR_ORDER
const _packageKeys = Object.keys(packages);
const _missingFromOrder = _packageKeys.filter((id) => !VENDOR_ORDER.includes(id));
Iif (_missingFromOrder.length > 0) {
console.warn(
`[metadata] VENDOR_ORDER is missing vendor IDs present in packages: ${_missingFromOrder.join(', ')}. ` +
'Append them to schema/tokens/_vendors.json and regenerate metadata.',
);
}
export const VENDOR_GROUPS: readonly VendorGroup[] = /*#__PURE__*/ VENDOR_ORDER.filter(
(id) => id in packages,
).map((id) => {
const pkg = packages[id]!;
return {
id,
displayName: pkg.name.replace(/\s*\(synced\)\s*/i, ''),
themeIds: pkg.flavors.flatMap((f) => (f ? [f.id] : [])),
};
});
/** O(1) flavor lookup by ID, built once at module evaluation time. */
const flavorById: ReadonlyMap<string, ThemeFlavor> = /*#__PURE__*/ new Map(
flavors.map((f) => [f.id, f]),
);
/** Cache for computed short labels. */
const shortLabelCache = new Map<string, string>();
/**
* Strip the vendor prefix from a theme label to produce a short label.
*
* For single-flavor vendors (e.g., "Dracula", "Nord") the full label is returned.
* For multi-flavor vendors the vendor name prefix is stripped:
* "Catppuccin Mocha" -> "Mocha"
* "Gruvbox Dark Hard" -> "Dark Hard"
*
* @param themeId - A valid theme ID
* @returns The short display label, or the full label if the theme is not found
*/
export function getShortLabel(themeId: string): string {
const cached = shortLabelCache.get(themeId);
if (cached !== undefined) return cached;
const flavor = flavorById.get(themeId);
if (!flavor) return themeId;
const vendorPkg = packages[flavor.vendor];
Iif (!vendorPkg) {
shortLabelCache.set(themeId, flavor.label);
return flavor.label;
}
// Single-flavor vendors keep their full label
if (vendorPkg.flavors.length === 1) {
shortLabelCache.set(themeId, flavor.label);
return flavor.label;
}
// Strip vendor display name prefix (case-insensitive, NFC-normalized for
// consistent handling of composed/decomposed Unicode accents).
const displayName = vendorPkg.name.replace(/\s*\(synced\)\s*/i, '').normalize('NFC');
const label = flavor.label;
let result: string;
if (label.normalize('NFC').toLowerCase().startsWith(displayName.toLowerCase())) {
const stripped = label.slice(displayName.length).trim();
result = stripped || label;
} else E{
result = label;
}
shortLabelCache.set(themeId, result);
return result;
}
/** Pre-computed short labels for all themes. */
export const THEME_SHORT_LABELS: Readonly<Record<string, string>> =
/*#__PURE__*/ Object.fromEntries(flavors.map((f) => [f.id, getShortLabel(f.id)]));
|