ui: migrate to shadcn/ui primitives across dialogs, filters, and forms

Adopts shadcn/ui components (Dialog, Button, Input, Select, Popover,
Command, Checkbox, Switch, Toggle, Calendar, etc.) across the app,
replacing hand-rolled modals, dropdowns, and form controls. Adds a
reusable cmdk-backed MultiSelect for the Type, Tags, and Flag filters
so all multi-value filter popovers share one component and layout.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-15 09:07:20 +02:00
parent 8529771122
commit 7efac4354e
51 changed files with 3032 additions and 1660 deletions

View File

@@ -2,6 +2,7 @@ import { useMemo, useState, useEffect, useCallback } from 'react'
import { Copy, Layers, Sparkles, Trash2, Loader2, Info, Crown } from 'lucide-react'
import clsx from 'clsx'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { Button } from '@/components/ui/button'
import {
useDuplicateGroupsQuery,
DUPLICATE_GROUPS_QUERY_KEY,
@@ -269,7 +270,9 @@ function DuplicateGroupSection({
)}
</span>
</div>
<button
<Button
variant="outline"
size="sm"
onClick={() => {
const discardIds = group.members
.filter((m) => m.id !== best.id)
@@ -278,16 +281,12 @@ function DuplicateGroupSection({
onKeepBest(discardIds)
}}
disabled={isPending}
className={clsx(
'flex items-center gap-1.5 rounded border border-border px-2 py-1 text-xs font-medium transition-colors',
'hover:border-reject/50 hover:bg-reject/10 hover:text-reject',
isPending && 'cursor-not-allowed opacity-50'
)}
className="hover:border-reject/50 hover:bg-reject/10 hover:text-reject"
title="Keep the highest-resolution copy and discard the rest"
>
<Trash2 className="h-3 w-3" />
<Trash2 className="mr-1.5 h-3 w-3" />
Keep best, discard {discardCount}
</button>
</Button>
</header>
<div