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