From d2d06e15b6d19e3db92aa3b641d9f403cb384c76 Mon Sep 17 00:00:00 2001 From: Richard R Date: Mon, 1 Jun 2026 11:02:26 -0600 Subject: [PATCH] Converge choice and popover surfaces --- src/components/ColorPicker.tsx | 20 +- src/components/SettingsModal.tsx | 179 +++++++----------- src/components/admin/AdminProvidersPanel.tsx | 18 +- .../doclist/window/FinderSidebar.tsx | 4 +- src/components/ui/choice-tile.tsx | 32 ++++ src/components/ui/index.ts | 1 + 6 files changed, 130 insertions(+), 124 deletions(-) create mode 100644 src/components/ui/choice-tile.tsx diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx index 0ebadcb..d2d9077 100644 --- a/src/components/ColorPicker.tsx +++ b/src/components/ColorPicker.tsx @@ -4,6 +4,7 @@ import { useRef, useState, useEffect, useCallback } from 'react'; import { Popover, PopoverButton, PopoverPanel } from '@headlessui/react'; import { isLightColor, type CustomThemeColors } from '@/contexts/ThemeContext'; import { PaletteIcon } from '@/components/icons/Icons'; +import { IconButton, Input, cn, popoverPanelClass } from '@/components/ui'; /** * Curated swatch palettes per color role, sourced from existing themes @@ -78,7 +79,7 @@ export function ColorPicker({ value, field, label, onChange }: ColorPickerProps) return ( - +
{/* Label */}
@@ -101,14 +104,14 @@ export function ColorPicker({ value, field, label, onChange }: ColorPickerProps) {/* Eyedropper / native picker */}
- + - setHexInput(e.target.value)} @@ -166,7 +169,8 @@ export function ColorPicker({ value, field, label, onChange }: ColorPickerProps) }} spellCheck={false} maxLength={7} - className="flex-1 rounded-lg px-2 py-1 text-xs font-mono border border-line bg-background text-foreground focus:outline-none focus:ring-1 focus:ring-accent-line" + controlSize="sm" + className="flex-1 font-mono" />
diff --git a/src/components/SettingsModal.tsx b/src/components/SettingsModal.tsx index 16aaa9f..c010ad2 100644 --- a/src/components/SettingsModal.tsx +++ b/src/components/SettingsModal.tsx @@ -50,6 +50,7 @@ import { SidebarNavItem, SegmentedControl, Button, + ChoiceTile, IconButton, Input, ModalFrame, @@ -109,6 +110,54 @@ const CUSTOM_COLOR_FIELDS: { key: keyof CustomThemeColors; label: string }[] = [ { key: 'muted', label: 'Muted' }, ]; +function ThemeSwatches({ colors }: { colors: ThemeColorSet }) { + return ( +
+
+
+
+
+
+
+ ); +} + +function ThemeChoice({ + label, + colors, + selected, + onClick, + className, +}: { + label: string; + colors: ThemeColorSet; + selected: boolean; + onClick: () => void; + className?: string; +}) { + return ( + + {selected ? ( + + ) : ( + + )} + + {label} + + + + ); +} + type SectionId = 'api' | 'theme' | 'docs' | 'account' | 'admin'; type SidebarSection = { @@ -880,34 +929,13 @@ export function SettingsModal({ const colors = getThemeColors(systemTheme.id); const isActive = theme === systemTheme.id; return ( - + className="w-full" + /> ); })()}
@@ -921,37 +949,16 @@ export function SettingsModal({ return (
- + className="flex-1" + /> + /> ); })}
@@ -1065,35 +1050,13 @@ export function SettingsModal({ const colors = getThemeColors(t.id); const isActive = theme === t.id; return ( - + /> ); })}
diff --git a/src/components/admin/AdminProvidersPanel.tsx b/src/components/admin/AdminProvidersPanel.tsx index dec300d..2f61ba3 100644 --- a/src/components/admin/AdminProvidersPanel.tsx +++ b/src/components/admin/AdminProvidersPanel.tsx @@ -18,7 +18,11 @@ import { listboxOptionClass, listboxOptionsClass, Button, + IconButton, Input, + MenuItemClass, + cn, + menuPanelClass, } from '@/components/ui'; type ProviderType = TtsProviderId; @@ -641,7 +645,9 @@ export function AdminProvidersPanel() {
{({ active }) => ( @@ -678,7 +684,7 @@ export function AdminProvidersPanel() { type="button" onClick={() => setDefault(p.slug)} disabled={disabled} - className={`${disabled ? 'text-faint cursor-not-allowed' : active ? 'bg-offbase text-accent' : 'text-foreground'} flex w-full items-center gap-2 rounded-md px-2 py-2 text-xs`} + className={cn(MenuItemClass(active), disabled ? 'cursor-not-allowed text-faint' : '')} > Set as default @@ -689,7 +695,7 @@ export function AdminProvidersPanel() { @@ -700,7 +706,7 @@ export function AdminProvidersPanel() { diff --git a/src/components/doclist/window/FinderSidebar.tsx b/src/components/doclist/window/FinderSidebar.tsx index fc6dc56..a6383bd 100644 --- a/src/components/doclist/window/FinderSidebar.tsx +++ b/src/components/doclist/window/FinderSidebar.tsx @@ -7,7 +7,7 @@ import type { Folder, SidebarFilter } from '@/types/documents'; import { PDFIcon, EPUBIcon, FileIcon, DotsHorizontalIcon } from '@/components/icons/Icons'; import { FolderIcon, HomeIcon, ClockIcon, FolderPlusIcon } from './finderIcons'; import { DND_DOCUMENT, type DocumentDragItem } from '../dnd/dndTypes'; -import { IconButton, MenuItemClass, Sidebar as SidebarShell, SidebarNav, SidebarNavGroup, SidebarNavItem } from '@/components/ui'; +import { IconButton, MenuItemClass, Sidebar as SidebarShell, SidebarNav, SidebarNavGroup, SidebarNavItem, menuPanelClass } from '@/components/ui'; interface FinderSidebarProps { filter: SidebarFilter; @@ -222,7 +222,7 @@ export function FinderSidebar({ > {({ active }) => ( diff --git a/src/components/ui/choice-tile.tsx b/src/components/ui/choice-tile.tsx new file mode 100644 index 0000000..1e0dd23 --- /dev/null +++ b/src/components/ui/choice-tile.tsx @@ -0,0 +1,32 @@ +import type { ButtonHTMLAttributes, ReactNode } from 'react'; +import { cn } from './cn'; +import { focusRing, motionColors } from './tokens'; + +export function ChoiceTile({ + selected = false, + children, + className, + type = 'button', + ...props +}: ButtonHTMLAttributes & { + selected?: boolean; + children: ReactNode; +}) { + return ( + + ); +} diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index 7dddd6a..08926c5 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -1,5 +1,6 @@ export * from './badge'; export * from './button'; +export * from './choice-tile'; export * from './cn'; export * from './dialog'; export * from './divider';