feat : improve UX/UI

This commit is contained in:
2026-10-05 20:01:41 +07:00 Unverified
parent 2f1fe0ab76
commit 3c3b104779
9 changed files with 168 additions and 182 deletions
+33 -36
View File
@@ -13,6 +13,7 @@ import {
CopyIcon,
GripVerticalIcon,
HeartPulseIcon,
MousePointerClickIcon,
PlusIcon,
RefreshCcwIcon,
SearchIcon,
@@ -130,6 +131,7 @@ import { Separator } from "@/components/ui/separator";
import { Skeleton } from "@/components/ui/skeleton";
import { Toggle } from "@/components/ui/toggle";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
Dialog,
DialogContent,
@@ -918,17 +920,17 @@ function SortableConditionTab({
<div
ref={setNodeRef}
style={{ transform: CSS.Transform.toString(transform), transition }}
className={cn("flex shrink-0 items-center rounded-md border", isDragging && "z-10 opacity-60")}
className={cn("flex shrink-0 items-center rounded-md", isDragging && "z-10 opacity-60")}
>
<ToggleGroupItem
<TabsTrigger
value={item.clientId}
className="border-0 aria-pressed:bg-primary aria-pressed:text-primary-foreground"
onClick={onSelect}
onDoubleClick={onRename}
>
<MousePointerClickIcon aria-hidden="true" data-icon="inline-start" />
{label}
{index === 0 ? <Badge variant={active ? "secondary" : "outline"}>Default</Badge> : null}
</ToggleGroupItem>
</TabsTrigger>
<SimpleTooltip text={`ลากเพื่อจัดลำดับ ${label}`}>
<Button
type="button"
@@ -980,26 +982,23 @@ function SortableConditionSwitcher({
}}
>
<SortableContext items={items.map((item) => item.clientId)} strategy={rectSortingStrategy}>
<ToggleGroup
aria-label={ariaLabel}
variant="outline"
value={activeId ? [activeId] : []}
onValueChange={(values) => {
const index = items.findIndex((item) => item.clientId === values[0]);
if (index !== -1) onActiveIndexChange(index);
}}
>
{items.map((item, index) => (
<SortableConditionTab
key={item.clientId}
item={item}
index={index}
active={item.clientId === activeId}
onSelect={() => onActiveIndexChange(index)}
onRename={() => onRename(index)}
/>
))}
</ToggleGroup>
<Tabs value={activeId} onValueChange={(value) => {
const index = items.findIndex((item) => item.clientId === value);
if (index !== -1) onActiveIndexChange(index);
}}>
<TabsList aria-label={ariaLabel} className="shrink-0 gap-1">
{items.map((item, index) => (
<SortableConditionTab
key={item.clientId}
item={item}
index={index}
active={item.clientId === activeId}
onSelect={() => onActiveIndexChange(index)}
onRename={() => onRename(index)}
/>
))}
</TabsList>
</Tabs>
</SortableContext>
</DndContext>
</ScrollableNav>
@@ -3812,18 +3811,16 @@ function TeamEditor({
</Button>
{activeImportGuide.groups.length > 1 ? (
<ScrollableNav ariaLabel="เลือกเงื่อนไขทีม" className="w-full min-w-0">
<ToggleGroup
aria-label="เลือกเงื่อนไขทีม"
variant="outline"
value={[guideImportCondition]}
onValueChange={(values) => { if (values[0]) setGuideImportCondition(values[0]); }}
>
{activeImportGuide.groups.map((group, index) => (
<ToggleGroupItem key={group.id} value={String(index)} className="aria-pressed:bg-primary aria-pressed:text-primary-foreground">
{group.name || `Condition ${index + 1}`}
</ToggleGroupItem>
))}
</ToggleGroup>
<Tabs value={guideImportCondition} onValueChange={setGuideImportCondition}>
<TabsList aria-label="เลือกเงื่อนไขทีม">
{activeImportGuide.groups.map((group, index) => (
<TabsTrigger key={group.id} value={String(index)}>
<MousePointerClickIcon aria-hidden="true" data-icon="inline-start" />
{group.name || `Condition ${index + 1}`}
</TabsTrigger>
))}
</TabsList>
</Tabs>
</ScrollableNav>
) : null}
<div className="flex min-w-0 items-center gap-2">
+12 -38
View File
@@ -49,14 +49,6 @@ import {
InputGroupAddon,
InputGroupInput,
} from "@/components/ui/input-group";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Spinner } from "@/components/ui/spinner";
import { useAdminPresence } from "@/hooks/use-presence";
import type { CatalogSyncJob } from "@/lib/catalog/sync";
@@ -86,7 +78,6 @@ export function StructuredDashboard({
const router = useRouter();
const [pending, startTransition] = useTransition();
const [query, setQuery] = useState("");
const [sort, setSort] = useState("default");
const [syncJob, setSyncJob] = useState<CatalogSyncJob | null>(null);
const presence = useAdminPresence(null);
const catalogReady = Boolean(catalogVersion);
@@ -95,10 +86,7 @@ export function StructuredDashboard({
const search = searchItems(guides, query,
(guide) => `${guide.name} ${guide.characterKey} ${guide.overview}`,
(guide) => [guide.name]);
const filteredGuides = sort === "default" ? search.items : [...search.items].sort((left, right) => {
const order = left.name.localeCompare(right.name, "th", { numeric: true });
return sort === "name-asc" ? order : -order;
});
const filteredGuides = search.items;
useEffect(() => {
if (!syncJobId || !syncJobStatus || ["completed", "unchanged", "cancelled", "error"].includes(syncJobStatus)) return;
@@ -198,31 +186,17 @@ export function StructuredDashboard({
</Card>
) : null}
{guides.length ? (
<div className="flex flex-col gap-3 sm:flex-row sm:items-center">
<InputGroup className="h-11 max-w-2xl flex-1">
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
<InputGroupInput
value={query}
onChange={(event) => setQuery(event.target.value)}
placeholder="ค้นหาตัวละคร…"
aria-label="ค้นหาตัวละคร"
/>
</InputGroup>
<Select value={sort} onValueChange={(value) => value && setSort(value)}>
<SelectTrigger aria-label="เรียง Guide" className="h-11 w-full sm:w-44">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="default">เรียงตามเดิม</SelectItem>
<SelectItem value="name-asc">ชื่อ ก-ฮ</SelectItem>
<SelectItem value="name-desc">ชื่อ ฮ-ก</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
<InputGroup className="h-11 max-w-2xl">
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
<InputGroupInput
value={query}
onChange={(event) => setQuery(event.target.value)}
placeholder="ค้นหาตัวละคร…"
aria-label="ค้นหาตัวละคร"
/>
</InputGroup>
) : null}
{filteredGuides.length ? (