SPB Git forge

spb/ai-atlas

Public
41commits 1branches 0releases
4.6 MBsize
maindefault branch
12 days agolast push
HTML 77.2% TypeScript 10.5% Python 9.6% JavaScript 2.5%
2.5 KB · 65 lines typescript
Raw Blame History
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