134 lines
3.9 KiB
TypeScript
134 lines
3.9 KiB
TypeScript
import { getConfig } from '@/config/app-config'
|
|
import { colors } from '@/themeConfig'
|
|
|
|
export const DEFAULT_PRIMARY_COLOR = '#a72b77'
|
|
export const DEFAULT_SECONDARY_COLOR = '#a72b77'
|
|
export const DEFAULT_TERTIARY_COLOR = '#e0be7f'
|
|
export const DEFAULT_BACKGROUND_COLOR = '#ffffff'
|
|
|
|
function normalizeHex(value: unknown): string | null {
|
|
if (typeof value !== 'string') return null
|
|
|
|
const trimmed = value.trim()
|
|
if (!trimmed) return null
|
|
|
|
const withHash = trimmed.startsWith('#') ? trimmed : `#${trimmed}`
|
|
|
|
if (!/^#[0-9a-fA-F]{6}$/.test(withHash) && !/^#[0-9a-fA-F]{3}$/.test(withHash)) {
|
|
return null
|
|
}
|
|
|
|
if (withHash.length === 4) {
|
|
const [, r, g, b] = withHash
|
|
return `#${r}${r}${g}${g}${b}${b}`.toLowerCase()
|
|
}
|
|
|
|
return withHash.toLowerCase()
|
|
}
|
|
|
|
function lightenHex(hex: string, amount = 0.22): string {
|
|
const normalized = normalizeHex(hex)
|
|
if (!normalized) return hex
|
|
|
|
const num = parseInt(normalized.slice(1), 16)
|
|
const r = (num >> 16) & 255
|
|
const g = (num >> 8) & 255
|
|
const b = num & 255
|
|
|
|
const mix = (channel: number) => Math.round(channel + (255 - channel) * amount)
|
|
|
|
return `#${[mix(r), mix(g), mix(b)]
|
|
.map((channel) => channel.toString(16).padStart(2, '0'))
|
|
.join('')}`
|
|
}
|
|
|
|
function darkenHex(hex: string, amount = 0.22): string {
|
|
const normalized = normalizeHex(hex)
|
|
if (!normalized) return hex
|
|
|
|
const num = parseInt(normalized.slice(1), 16)
|
|
const r = Math.round(((num >> 16) & 255) * (1 - amount))
|
|
const g = Math.round(((num >> 8) & 255) * (1 - amount))
|
|
const b = Math.round((num & 255) * (1 - amount))
|
|
|
|
return `#${[r, g, b].map((channel) => channel.toString(16).padStart(2, '0')).join('')}`
|
|
}
|
|
|
|
export function getAppPrimaryColor(fallback = DEFAULT_PRIMARY_COLOR): string {
|
|
return (
|
|
normalizeHex(getConfig('color')) ||
|
|
normalizeHex(getConfig('primary_color')) ||
|
|
normalizeHex(getConfig('primary')) ||
|
|
fallback
|
|
)
|
|
}
|
|
|
|
export function getAppSecondaryColor(fallback = DEFAULT_SECONDARY_COLOR): string {
|
|
return (
|
|
normalizeHex(getConfig('secondary_color')) ||
|
|
normalizeHex(getConfig('secondary')) ||
|
|
getAppPrimaryColor(fallback)
|
|
)
|
|
}
|
|
|
|
export function getAppTertiaryColor(fallback = DEFAULT_TERTIARY_COLOR): string {
|
|
return (
|
|
normalizeHex(getConfig('tertiary_color')) ||
|
|
normalizeHex(getConfig('tertiary')) ||
|
|
fallback
|
|
)
|
|
}
|
|
|
|
export function getAppBackgroundColor(fallback = DEFAULT_BACKGROUND_COLOR): string {
|
|
return (
|
|
normalizeHex(getConfig('background_color')) ||
|
|
normalizeHex(getConfig('background')) ||
|
|
fallback
|
|
)
|
|
}
|
|
|
|
export function getAppPrimaryDark(fallback = '#711d4d'): string {
|
|
return darkenHex(getAppPrimaryColor(), 0.22) || fallback
|
|
}
|
|
|
|
export function getAppPrimaryLight(fallback = '#c45f9a'): string {
|
|
return lightenHex(getAppPrimaryColor(), 0.22) || fallback
|
|
}
|
|
|
|
function setCssVar(name: string, value: string) {
|
|
document.documentElement.style.setProperty(name, value)
|
|
}
|
|
|
|
export function applyBrandTheme() {
|
|
const primary = getAppPrimaryColor()
|
|
const secondary = getAppSecondaryColor()
|
|
const tertiary = getAppTertiaryColor()
|
|
const background = getAppBackgroundColor()
|
|
const primaryDark = getAppPrimaryDark()
|
|
const primaryLight = getAppPrimaryLight()
|
|
|
|
setCssVar('--app-primary-color', primary)
|
|
setCssVar('--app-secondary-color', secondary)
|
|
setCssVar('--app-tertiary-color', tertiary)
|
|
setCssVar('--app-background-color', background)
|
|
setCssVar('--app-primary-dark', primaryDark)
|
|
setCssVar('--app-primary-light', primaryLight)
|
|
|
|
colors.primary = primary
|
|
colors['primary-rgba'] = primary
|
|
colors.secondary = secondary
|
|
colors['secondary-rgba'] = secondary
|
|
colors.tertiary = tertiary
|
|
colors['tertiary-rgba'] = tertiary
|
|
|
|
const themeMeta = document.querySelector<HTMLMetaElement>('meta[name="theme-color"]')
|
|
if (themeMeta) {
|
|
themeMeta.content = primary
|
|
} else {
|
|
const meta = document.createElement('meta')
|
|
meta.name = 'theme-color'
|
|
meta.content = primary
|
|
document.head.appendChild(meta)
|
|
}
|
|
}
|