SPB Git forge
28commits 1branches 0releases
7.7 MBsize
maindefault branch
10 days agolast push
Python 66.3% TypeScript 22.7% JavaScript 8.6% HTML 1.4% CSS 0.7%
1.6 KB · 44 lines tsx
Raw Blame History
1'use client';2import { Rows3, Rows4 } from 'lucide-react';3import { useEffect, useState } from 'react';4import { cn } from '@/lib/cn';5import { DENSITY_KEY } from '@/lib/prepaint';67export type Density = 'comfortable' | 'compact';89export function readDensity(): Density {10  try {11    return localStorage.getItem(DENSITY_KEY) === 'compact' ? 'compact' : 'comfortable';12  } catch {13    return 'comfortable';14  }15}16export function setDensity(d: Density) {17  try {18    if (d === 'compact') localStorage.setItem(DENSITY_KEY, d);19    else localStorage.removeItem(DENSITY_KEY);20  } catch {21    /* ignore */22  }23  if (d === 'compact') document.documentElement.setAttribute('data-density', d);24  else document.documentElement.removeAttribute('data-density');25  window.dispatchEvent(new CustomEvent('ca-density-change'));26}2728export function DensityToggle({ className }: { className?: string }) {29  const [d, setD] = useState<Density>('comfortable');30  useEffect(() => {31    const read = () => setD(readDensity());32    read();33    window.addEventListener('ca-density-change', read);34    return () => window.removeEventListener('ca-density-change', read);35  }, []);36  const next: Density = d === 'compact' ? 'comfortable' : 'compact';37  const Icon = d === 'compact' ? Rows4 : Rows3;38  return (39    <button type="button" onClick={() => setDensity(next)} className={cn('hidden size-10 items-center justify-center rounded-sm text-ink-2 hover:bg-surface-2 hover:text-ink md:flex', className)} aria-label={`Density: ${d} — switch to ${next}`} title={`Density: ${d}`}>40      <Icon className="size-[18px]" aria-hidden />41    </button>42  );43}44