mirror of
https://github.com/Since-3/since3-portal.git
synced 2026-10-12 19:51:17 +00:00
64 lines
2.5 KiB
TypeScript
64 lines
2.5 KiB
TypeScript
import type { CSSProperties } from "react"
|
|
import { getTemplate, templates } from "./registry"
|
|
import type { Palette, TemplateContent, TemplateDefinition } from "./types"
|
|
|
|
// Bibliothek: Jede Variante darf Paletten und Schriftpaare aller Vorlagen nutzen ("vorlage:schlüssel")
|
|
export const paletteLibrary = templates.flatMap((template) =>
|
|
template.palettes.map((palette) => ({ key: `${template.key}:${palette.key}`, template: template.name, palette }))
|
|
)
|
|
|
|
export const fontLibrary = templates.flatMap((template) =>
|
|
template.fonts.map((pair) => ({ key: `${template.key}:${pair.key}`, template: template.name, label: pair.label }))
|
|
)
|
|
|
|
export function resolvePalette(def: TemplateDefinition, key: string): Palette {
|
|
const own = def.palettes.find((palette) => palette.key === key)
|
|
if (own) return own
|
|
const [templateKey, paletteKey] = key.split(":")
|
|
return getTemplate(templateKey)?.palettes.find((palette) => palette.key === paletteKey) ?? def.palettes[0]
|
|
}
|
|
|
|
function luminance(hex: string) {
|
|
const [r, g, b] = [1, 3, 5].map((i) => {
|
|
const channel = parseInt(hex.slice(i, i + 2), 16) / 255
|
|
return channel <= 0.03928 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4
|
|
})
|
|
return 0.2126 * r + 0.7152 * g + 0.0722 * b
|
|
}
|
|
|
|
// Schwarz oder Weiß, je nachdem was auf der Farbe besser lesbar ist (WCAG-Luminanz)
|
|
const readableOn = (hex: string) => (luminance(hex) > 0.179 ? "#111111" : "#ffffff")
|
|
|
|
export function themeColors(def: TemplateDefinition, content: TemplateContent) {
|
|
const palette = resolvePalette(def, content.palette)
|
|
const { colors } = content
|
|
const bg = colors.bg || palette.bg
|
|
|
|
return {
|
|
bg,
|
|
fg: colors.fg || palette.fg,
|
|
muted: colors.muted || palette.muted,
|
|
surface: colors.surface || palette.surface,
|
|
accent: colors.accent || palette.accent,
|
|
dark: colors.bg ? luminance(bg) < 0.2 : Boolean(palette.dark),
|
|
}
|
|
}
|
|
|
|
export function accentColors(def: TemplateDefinition, content: TemplateContent) {
|
|
const { accent } = themeColors(def, content)
|
|
return { accent, accentFg: readableOn(accent) }
|
|
}
|
|
|
|
export function themeStyle(def: TemplateDefinition, content: TemplateContent): CSSProperties {
|
|
const theme = themeColors(def, content)
|
|
|
|
return {
|
|
"--t-bg": theme.bg,
|
|
"--t-fg": theme.fg,
|
|
"--t-muted": theme.muted,
|
|
"--t-surface": theme.surface,
|
|
"--t-accent": theme.accent,
|
|
"--t-accent-fg": readableOn(theme.accent),
|
|
colorScheme: theme.dark ? "dark" : "light",
|
|
} as CSSProperties
|
|
}
|