pstream is dead; long live pstream taciturnaxolotl.github.io/pstream-ng/
at main 224 lines 5.9 kB view raw
1import merge from "lodash.merge"; 2import { createTheme } from "./types"; 3import { defaultTheme } from "./default"; 4import { colorToRgbString } from "../src/utils/color"; 5import { allThemes } from "./all"; 6 7const availableThemes = [ 8 { id: "default", theme: defaultTheme }, 9 ...allThemes.map((t) => ({ 10 id: t.name, 11 theme: { extend: t.extend }, 12 })), 13]; 14 15function cssVarName(path: string) { 16 return `--colors-${path}`; 17} 18 19// Generate the custom theme structure with CSS variables 20function generateCustomThemeStructure(theme: any, prefix = ""): any { 21 const result: any = {}; 22 for (const key in theme) { 23 if (typeof theme[key] === "object" && theme[key] !== null) { 24 result[key] = generateCustomThemeStructure( 25 theme[key], 26 `${prefix}${key}-`, 27 ); 28 } else { 29 result[key] = 30 `rgb(var(${cssVarName(`${prefix}${key}`)}) / <alpha-value>)`; 31 } 32 } 33 return result; 34} 35 36export const customTheme = createTheme({ 37 name: "custom", 38 extend: { 39 colors: generateCustomThemeStructure(defaultTheme.extend.colors), 40 }, 41}); 42 43// Define parts 44const parts = { 45 primary: [ 46 "lightBar.light", 47 "type.logo", 48 "buttons.primary", 49 "buttons.primaryText", 50 "buttons.primaryHover", 51 "buttons.toggle", 52 "buttons.toggleDisabled", 53 "buttons.purple", 54 "buttons.purpleHover", 55 "global.accentA", 56 "global.accentB", 57 "pill.highlight", 58 "progress.filled", 59 "video.audio.set", 60 "video.context.type.accent", 61 "video.context.sliderFilled", 62 "video.scraping.loading", 63 "onboarding.good", 64 "onboarding.best", 65 "onboarding.link", 66 "onboarding.barFilled", 67 "settings.sidebar.type.iconActivated", 68 "settings.sidebar.type.activated", 69 "type.link", 70 "type.linkHover", 71 "largeCard.icon", 72 "mediaCard.barFillColor", 73 ], 74 secondary: [ 75 "type.text", 76 "type.dimmed", 77 "type.secondary", 78 "type.emphasis", 79 "type.divider", 80 "type.danger", 81 "type.success", 82 "buttons.secondary", 83 "buttons.secondaryText", 84 "buttons.secondaryHover", 85 "buttons.danger", 86 "buttons.dangerHover", 87 "buttons.cancel", 88 "buttons.cancelHover", 89 "utils.divider", 90 "search.text", 91 "search.placeholder", 92 "search.icon", 93 "dropdown.text", 94 "dropdown.secondary", 95 "dropdown.border", 96 "authentication.border", 97 "authentication.inputBg", 98 "authentication.inputBgHover", 99 "authentication.wordBackground", 100 "authentication.copyText", 101 "authentication.copyTextHover", 102 "authentication.errorText", 103 "settings.sidebar.activeLink", 104 "settings.sidebar.badge", 105 "settings.sidebar.type.secondary", 106 "settings.sidebar.type.inactive", 107 "settings.sidebar.type.icon", 108 "settings.card.border", 109 "onboarding.bar", 110 "onboarding.divider", 111 "onboarding.border", 112 "errors.border", 113 "errors.type.secondary", 114 "about.circle", 115 "about.circleText", 116 "editBadge.bg", 117 "editBadge.bgHover", 118 "editBadge.text", 119 "progress.background", 120 "progress.preloaded", 121 "pill.background", 122 "pill.backgroundHover", 123 "pill.activeBackground", 124 "video.buttonBackground", 125 "video.autoPlay.background", 126 "video.autoPlay.hover", 127 "video.scraping.error", 128 "video.scraping.success", 129 "video.scraping.noresult", 130 "video.context.light", 131 "video.context.border", 132 "video.context.hoverColor", 133 "video.context.buttonFocus", 134 "video.context.inputBg", 135 "video.context.buttonOverInputHover", 136 "video.context.inputPlaceholder", 137 "video.context.cardBorder", 138 "video.context.slider", 139 "video.context.error", 140 "video.context.buttons.list", 141 "video.context.buttons.active", 142 "video.context.closeHover", 143 "video.context.type.main", 144 "video.context.type.secondary", 145 "mediaCard.barColor", 146 "mediaCard.badge", 147 "mediaCard.badgeText", 148 ], 149 tertiary: [ 150 "background.main", 151 "background.secondary", 152 "background.secondaryHover", 153 "background.accentA", 154 "background.accentB", 155 "modal.background", 156 "mediaCard.shadow", 157 "mediaCard.hoverBackground", 158 "mediaCard.hoverAccent", 159 "mediaCard.hoverShadow", 160 "search.background", 161 "search.hoverBackground", 162 "search.focused", 163 "dropdown.background", 164 "dropdown.altBackground", 165 "dropdown.hoverBackground", 166 "dropdown.contentBackground", 167 "dropdown.highlight", 168 "dropdown.highlightHover", 169 "largeCard.background", 170 "settings.card.background", 171 "settings.card.altBackground", 172 "settings.saveBar.background", 173 "onboarding.card", 174 "onboarding.cardHover", 175 "errors.card", 176 "themePreview.primary", 177 "themePreview.secondary", 178 "themePreview.ghost", 179 "video.scraping.card", 180 "video.context.background", 181 "video.context.flagBg", 182 ], 183}; 184 185function getNestedValue(obj: any, path: string) { 186 return path.split(".").reduce((o, i) => (o ? o[i] : undefined), obj); 187} 188 189function extractColors(theme: any, keys: string[]) { 190 const colors: Record<string, string> = {}; 191 // We need to flatten the structure to css vars 192 keys.forEach((key) => { 193 const value = getNestedValue(theme.extend.colors, key); 194 if (value) { 195 colors[cssVarName(key.replace(/\./g, "-"))] = colorToRgbString(value); 196 } 197 }); 198 return colors; 199} 200 201// Generate options for each part 202export const primaryOptions = availableThemes.map((t) => { 203 const merged = merge({}, defaultTheme, t.theme); 204 return { 205 id: t.id, 206 colors: extractColors(merged, parts.primary), 207 }; 208}); 209 210export const secondaryOptions = availableThemes.map((t) => { 211 const merged = merge({}, defaultTheme, t.theme); 212 return { 213 id: t.id, 214 colors: extractColors(merged, parts.secondary), 215 }; 216}); 217 218export const tertiaryOptions = availableThemes.map((t) => { 219 const merged = merge({}, defaultTheme, t.theme); 220 return { 221 id: t.id, 222 colors: extractColors(merged, parts.tertiary), 223 }; 224});