HTML 77.2%
TypeScript 10.5%
Python 9.6%
JavaScript 2.5%
1'use client';2/**3 * Display density — `comfortable` (default) · `compact` · `dense`. Persisted in `localStorage['aia-density']`, applied4 * before paint by `DENSITY_SCRIPT` as `<html data-density>` and read by globals.css through CSS variables5 * (`--d-cell-y` table cell padding, `--d-kv-y` key–value rows, `--d-section-y` section padding, `--d-base` font size).6 * Same pattern as the theme (`components/layout/theme.tsx`).7 */8import { useCallback, useEffect, useState } from 'react';9import { DENSITY_KEY } from './prepaint';1011export type Density = 'comfortable' | 'compact' | 'dense';12export { DENSITY_KEY, DENSITY_SCRIPT } from './prepaint';13export const DENSITIES: Density[] = ['comfortable', 'compact', 'dense'];14export const DENSITY_LABELS: Record<Density, string> = { comfortable: 'Comfortable', compact: 'Compact', dense: 'Dense' };15const EVENT = 'aia-density-change';1617export function readDensity(): Density {18 if (typeof window === 'undefined') return 'comfortable';19 const d = window.localStorage.getItem(DENSITY_KEY);20 return d === 'compact' || d === 'dense' ? d : 'comfortable';21}2223export function applyDensity(d: Density) {24 if (typeof document === 'undefined') return;25 if (d === 'comfortable') document.documentElement.removeAttribute('data-density');26 else document.documentElement.setAttribute('data-density', d);27}2829export function setDensity(d: Density) {30 try {31 if (d === 'comfortable') window.localStorage.removeItem(DENSITY_KEY);32 else window.localStorage.setItem(DENSITY_KEY, d);33 } catch {34 /* storage disabled */35 }36 applyDensity(d);37 window.dispatchEvent(new CustomEvent(EVENT));38}3940export function nextDensity(d: Density): Density {41 return DENSITIES[(DENSITIES.indexOf(d) + 1) % DENSITIES.length] as Density;42}4344/** React binding: `[density, set, cycle]`; `density` is `comfortable` during SSR/hydration. */45export function useDensity(): [Density, (d: Density) => void, () => void] {46 const [d, setD] = useState<Density>('comfortable');47 useEffect(() => {48 const sync = () => setD(readDensity());49 sync();50 applyDensity(readDensity());51 window.addEventListener(EVENT, sync);52 window.addEventListener('storage', sync);53 return () => {54 window.removeEventListener(EVENT, sync);55 window.removeEventListener('storage', sync);56 };57 }, []);58 const set = useCallback((n: Density) => {59 setDensity(n);60 setD(n);61 }, []);62 const cycle = useCallback(() => set(nextDensity(readDensity())), [set]);63 return [d, set, cycle];64}65