main
ts 109 lines 3.1 KB
Raw
1 import type { ColorAction, ColorKey, ColorType, ThemeColor } from "@/types/theme"
2 import { colord } from "colord"
3 import _get from "lodash/get"
4
5 export const COLOR_SHADES = ["005", "010", "015", "020", "030", "040", "050", "060", "070", "080", "090"] as const
6 const PATTERN_GROUP_REGEX = /\(([^)]+)\)/
7
8 export type ColorShade = (typeof COLOR_SHADES)[number]
9
10 export function toggleSidebarClass(
11 sidebarCollapsed: boolean,
12 elementId: string,
13 classOpen: string,
14 classClose: string
15 ) {
16 const el = window?.document?.getElementById(elementId)
17 if (!el) return
18
19 el.classList.toggle(classOpen, !sidebarCollapsed)
20 el.classList.toggle(classClose, sidebarCollapsed)
21 }
22
23 export function colorToArray(color: string, output: "rgb" | "hsl"): number[] {
24 const colorObject = colord(color)
25
26 switch (output) {
27 case "rgb": {
28 const { r, g, b } = colorObject.toRgb()
29 return [r, g, b]
30 }
31 case "hsl": {
32 const { h, s, l } = colorObject.toHsl()
33 return [h, s, l]
34 }
35 default:
36 throw new Error("Invalid output type")
37 }
38 }
39
40 export function exposure(color: string, amount: number): string {
41 return colord(color)
42 .lighten(amount) /* .desaturate(Math.abs(amount)) */
43 .toHex()
44 }
45
46 export function getColorAlphaShades(color: string): { [key in ColorShade]: string } {
47 return COLOR_SHADES.reduce<{ [key in ColorShade]: string }>(
48 (acc, shade) => {
49 acc[shade] = colord(color)
50 .alpha(Number.parseInt(shade, 10) / 100)
51 .toRgbString()
52 return acc
53 },
54 {} as { [key in ColorShade]: string }
55 )
56 }
57
58 export function getTypeValue(origin: object, val: string) {
59 if (val && val.indexOf("{") === 0) {
60 const path = val.replace("{", "").replace("}", "")
61 return _get(origin, path)
62 }
63
64 return val
65 }
66
67 export function getThemeColors(colors: Record<ColorType, string>) {
68 const colorActions: ColorAction[] = [
69 { scene: "", handler: color => color },
70 { scene: "Suppl", handler: color => exposure(color, 0.1) },
71 { scene: "Hover", handler: color => exposure(color, 0.08) },
72 { scene: "Pressed", handler: color => exposure(color, -0.05) }
73 ]
74
75 const themeColor: ThemeColor = {}
76
77 for (const colorName in colors) {
78 const colorValue = colors[colorName as ColorType]
79
80 colorActions.forEach(action => {
81 const colorKey: ColorKey = `${colorName as ColorType}Color${action.scene}`
82 themeColor[colorKey] = action.handler(colorValue)
83 })
84 }
85
86 return themeColor
87 }
88
89 /**
90 * Generates an array of strings by expanding all values enclosed in parentheses
91 *
92 * @param input - The string to process, e.g. "brand-(seablue|green)-(10|20|50)"
93 * @returns An array of expanded strings, e.g.
94 * ["brand-seablue-10", "brand-seablue-20", ..., "brand-green-50"]
95 */
96 export function expandPattern(input: string): string[] {
97 const match = input.match(PATTERN_GROUP_REGEX)
98 if (!match) {
99 // If there are no more parentheses, returns the input as an array
100 return [input]
101 }
102
103 // Expands the first group found
104 const [fullMatch, options] = match
105 const variants = options?.split("|") ?? [] // Splits the options by "|"
106
107 // Replaces the first group with each option and calls recursively
108 return variants.flatMap(option => expandPattern(input.replace(fullMatch, option)))
109 }