export const DEFAULT_PORTAL_COLOR = "#69c350" export function normalizePortalColor(value: unknown): string | null { if (typeof value !== "string") return null const color = value.trim().toLowerCase() return /^#[0-9a-f]{6}$/.test(color) ? color : null } export function getPortalColor(config: any): string { // Older tenant records contain the misspelled key from the original schema. return normalizePortalColor(config?.primaryColor) || normalizePortalColor(config?.primayColor) || DEFAULT_PORTAL_COLOR } export function portalThemeStyle(value: unknown): Record { const color = normalizePortalColor(value) || DEFAULT_PORTAL_COLOR const rgb = [1, 3, 5].map(offset => parseInt(color.slice(offset, offset + 2), 16) / 255) const linear = rgb.map(channel => channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4) const luminance = linear[0] * 0.2126 + linear[1] * 0.7152 + linear[2] * 0.0722 const style: Record = { "--ui-primary": color, "--portal-accent-contrast": luminance > 0.179 ? "#000000" : "#ffffff", } const shades = { 50: 5, 100: 10, 200: 25, 300: 45, 400: 70, 500: 100, 600: 80, 700: 65, 800: 50, 900: 35, 950: 20 } for (const [shade, percent] of Object.entries(shades)) { style[`--ui-color-primary-${shade}`] = Number(shade) === 500 ? color : `color-mix(in srgb, ${color} ${percent}%, ${Number(shade) < 500 ? "white" : "black"})` } return style }