clone

one developer profile for links and private tcp services, reached peer to peer over iroh with no open ports

main
devsite / web / theme.ts
theme.ts 2.1K
1import { element, query } from './shared';23function parseComputedColor(4 value: string,5): { rgb: [number, number, number]; alpha: number } | null {6 const match = value.match(7 /^rgba?\(\s*([\d.]+)[, ]+\s*([\d.]+)[, ]+\s*([\d.]+)(?:\s*[,/]\s*([\d.]+))?\s*\)$/i,8 );9 if (!match) return null;10 return {11 rgb: [Number(match[1]), Number(match[2]), Number(match[3])],12 alpha: match[4] === undefined ? 1 : Number(match[4]),13 };14}1516function logoBackground() {17 let node = document.querySelector('.brand');18 let alpha = 0;19 const premultiplied: [number, number, number] = [0, 0, 0];20 while (node instanceof Element) {21 const layer = parseComputedColor(getComputedStyle(node).backgroundColor);22 if (layer && layer.alpha > 0) {23 for (const channel of [0, 1, 2] as const) {24 premultiplied[channel] += (layer.rgb[channel] ?? 0) * layer.alpha * (1 - alpha);25 }26 alpha += layer.alpha * (1 - alpha);27 if (alpha >= 0.999) break;28 }29 node = node.parentElement;30 }31 return premultiplied.map((channel) => channel + 255 * (1 - alpha));32}3334export function updateLogoContrast() {35 if (!document.getElementById('dev-logo-ring')) return;36 const luminance = logoBackground()37 .map((channel) => channel / 255)38 .map((channel) => channel <= 0.0404539 ? channel / 12.9240 : ((channel + 0.055) / 1.055) ** 2.4)41 .reduce(42 (sum, channel, index) => sum + channel * ([0.2126, 0.7152, 0.0722][index] ?? 0),43 0,44 );45 document.documentElement.style.setProperty(46 '--devsite-logo-ring',47 luminance < 0.179 ? 'rgb(255,255,255)' : 'rgb(0,0,0)',48 );49}5051export function clearTheme() {52 query<HTMLElement>('.brand strong').hidden = false;53 delete document.documentElement.dataset.profile;54 delete document.documentElement.dataset.theme;55 element('profile-theme').textContent = '';56 const footer = element('page-footer');57 footer.replaceChildren();58 footer.hidden = true;59 requestAnimationFrame(updateLogoContrast);60}6162export function watchLogoContrast() {63 updateLogoContrast();64 matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () =>65 requestAnimationFrame(updateLogoContrast));66}