From a406e0022963f00d8ea0ec9253e2bfbc435fd168 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Wed, 25 Feb 2026 16:18:33 -0800 Subject: [PATCH] Add local label --- frontend/src/utils/localLabel.ts | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 frontend/src/utils/localLabel.ts diff --git a/frontend/src/utils/localLabel.ts b/frontend/src/utils/localLabel.ts new file mode 100644 index 0000000..6de520b --- /dev/null +++ b/frontend/src/utils/localLabel.ts @@ -0,0 +1,48 @@ +const LOCAL_LABEL_KEY = 'remoteterm-local-label'; + +export interface LocalLabel { + text: string; + color: string; +} + +const DEFAULT_LABEL: LocalLabel = { text: '', color: '#062d60' }; + +export function getLocalLabel(): LocalLabel { + try { + const raw = localStorage.getItem(LOCAL_LABEL_KEY); + if (!raw) return DEFAULT_LABEL; + const parsed = JSON.parse(raw) as Partial; + return { + text: typeof parsed.text === 'string' ? parsed.text : '', + color: typeof parsed.color === 'string' ? parsed.color : DEFAULT_LABEL.color, + }; + } catch { + return DEFAULT_LABEL; + } +} + +export function setLocalLabel(text: string, color: string): void { + try { + localStorage.setItem(LOCAL_LABEL_KEY, JSON.stringify({ text, color })); + } catch { + // localStorage may be unavailable + } +} + +/** + * Returns 'white' or 'black' for best contrast against the given hex color. + * Uses WCAG relative luminance formula. + */ +export function getContrastTextColor(hexColor: string): string { + const hex = hexColor.replace('#', ''); + const r = parseInt(hex.substring(0, 2), 16) / 255; + const g = parseInt(hex.substring(2, 4), 16) / 255; + const b = parseInt(hex.substring(4, 6), 16) / 255; + + // sRGB to linear + const toLinear = (c: number) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4); + const luminance = 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b); + + // WCAG threshold: luminance > 0.179 → dark text, else light text + return luminance > 0.179 ? 'black' : 'white'; +}