~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
59 lines · 2.3 KB Raw History
import { Popover } from '@base-ui/react/popover';
import { CheckIcon, PaletteIcon } from 'lucide-react';
import { useSyncExternalStore } from 'react';
import { applyTheme, onTheme, themeId, themes } from '#/lib/theme.js';
import { cn } from '#/lib/utils.js';

/**
 * Which palette the page paints in. The account may publish its own beside
 * the ones the page ships, and a reader's pick is theirs: it is remembered
 * in this browser and never written back.
 */
export function ThemeMenu() {
  const chosen = useSyncExternalStore(onTheme, themeId, () => '');
  const all = themes();

  return (
    <Popover.Root>
      <Popover.Trigger
        aria-label="Theme"
        title="Theme"
        className="flex size-7 cursor-pointer items-center justify-center rounded-sm text-faint outline-none transition-colors hover:bg-accent hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50"
      >
        <PaletteIcon className="size-4" />
      </Popover.Trigger>
      <Popover.Portal>
        <Popover.Positioner className="z-50" sideOffset={6} align="end">
          <Popover.Popup className="w-56 rounded-md border border-border bg-card p-1 shadow-lg outline-none">
            {all.map((one) => (
              <button
                key={one.id || 'system'}
                type="button"
                onClick={() => applyTheme(one.id)}
                className={cn(
                  'flex w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-[13px]',
                  one.id === chosen
                    ? 'bg-accent text-foreground'
                    : 'text-muted-foreground hover:bg-accent/60 hover:text-foreground',
                )}
              >
                <CheckIcon
                  className={cn(
                    'size-3.5 shrink-0',
                    one.id === chosen ? 'opacity-100' : 'opacity-0',
                  )}
                />
                <span className="min-w-0 flex-1 truncate">{one.name}</span>
                {one.published && (
                  <span className="shrink-0 text-[10px] text-faint uppercase tracking-[0.12em]">
                    yours
                  </span>
                )}
              </button>
            ))}
          </Popover.Popup>
        </Popover.Positioner>
      </Popover.Portal>
    </Popover.Root>
  );
}