theme_utils.ts (3555B)
1 import type { ThemeKey, ThemeMode } from "../core/types.js"; 2 import { parse_theme_key } from "../core/utils.js"; 3 import { theme_layouts } from "../layout/index.js"; 4 import type { ThemeLayoutKey, ThemeVariable } from "../layout/types.js"; 5 import { theme_presets } from "../presets/index.js"; 6 import type { HslTuple, OsThemePreset } from "../presets/types.js"; 7 8 export const theme_modes: ThemeMode[] = ["dark", "light"]; 9 10 const theme_layer_order: Array<keyof OsThemePreset> = ["ly0", "ly1", "ly2"]; 11 12 export interface ThemeColorEntry { 13 layer_key: keyof OsThemePreset; 14 category: "surfaces" | "glyphs"; 15 token_key: string; 16 } 17 18 export const tabs = (n: number): string => " ".repeat(n); 19 20 export const format_hsl = (tuple: HslTuple): string => { 21 const [h, s, l] = tuple; 22 return `hsl(${h}, ${s}%, ${l}%)`; 23 }; 24 25 export const to_css_name_suffix = (key: string): string => { 26 const trimmed_key = key.replace(/^_+/, ""); 27 if (trimmed_key.length === 0) { 28 return ""; 29 } 30 return `-${trimmed_key.replace(/_/g, "-")}`; 31 }; 32 33 export const collect_theme_color_entries = ( 34 theme: OsThemePreset 35 ): ThemeColorEntry[] => { 36 const entries: ThemeColorEntry[] = []; 37 38 for (const layer_key of theme_layer_order) { 39 const layer = theme[layer_key]; 40 41 const surface_keys = Object.keys( 42 layer.surfaces 43 ) as Array<keyof typeof layer.surfaces>; 44 for (const surface_key of surface_keys) { 45 entries.push({ 46 layer_key, 47 category: "surfaces", 48 token_key: String(surface_key) 49 }); 50 } 51 52 const glyph_keys = Object.keys( 53 layer.glyphs 54 ) as Array<keyof typeof layer.glyphs>; 55 for (const glyph_key of glyph_keys) { 56 entries.push({ 57 layer_key, 58 category: "glyphs", 59 token_key: String(glyph_key) 60 }); 61 } 62 } 63 64 return entries; 65 }; 66 67 export const select_theme_presets_keys = ( 68 presets: string[] | undefined 69 ): ThemeKey[] => { 70 const all_keys = Object.keys(theme_presets); 71 if (!presets || presets.length === 0) { 72 return all_keys.map(parse_theme_key); 73 } 74 75 const trimmed_presets = presets 76 .map(preset => preset.trim()) 77 .filter(preset => preset.length > 0); 78 79 if (trimmed_presets.length === 0) { 80 return all_keys.map(parse_theme_key); 81 } 82 83 const unknown_presets = trimmed_presets.filter( 84 preset => !all_keys.includes(preset) 85 ); 86 if (unknown_presets.length > 0) { 87 throw new Error( 88 `Unknown theme preset(s): ${unknown_presets.join(", ")}` 89 ); 90 } 91 92 return all_keys 93 .filter(key => trimmed_presets.includes(key)) 94 .map(parse_theme_key); 95 }; 96 97 export const select_theme_layout_keys = ( 98 presets: string[] | undefined 99 ): ThemeLayoutKey[] => { 100 const all_keys = Object.keys(theme_layouts) as ThemeLayoutKey[]; 101 102 if (!presets || presets.length === 0) { 103 return all_keys; 104 } 105 106 const trimmed_presets = presets 107 .map(preset => preset.trim()) 108 .filter(preset => preset.length > 0); 109 110 if (trimmed_presets.length === 0) { 111 return all_keys; 112 } 113 114 const unknown_presets = trimmed_presets.filter( 115 preset => !all_keys.includes(preset as ThemeLayoutKey) 116 ); 117 118 if (unknown_presets.length > 0) { 119 throw new Error( 120 `Unknown layout preset(s): ${unknown_presets.join(", ")}` 121 ); 122 } 123 124 return all_keys.filter(key => trimmed_presets.includes(key)); 125 }; 126 127 export const collect_layout_variables = ( 128 keys: ThemeLayoutKey[] 129 ): ThemeVariable[] => { 130 const variables: ThemeVariable[] = []; 131 132 for (const key of keys) { 133 const layout = theme_layouts[key]; 134 variables.push(...layout.variables); 135 } 136 137 return variables; 138 };