From 784153e9f62dbc7a0d03ab4a123a43be55d32f12 Mon Sep 17 00:00:00 2001 From: Citali Date: Sun, 21 Dec 2025 22:11:29 +0100 Subject: [PATCH] Change tabs list page --- bun.lock | 3 + package.json | 1 + src/app/tags/page.tsx | 35 ++++-- .../tags/{TagTable.tsx => TagTableAnimal.tsx} | 5 +- src/components/tags/TagTableMain.tsx | 100 ++++++++++++++++++ src/components/tags/TagTabs.tsx | 66 ++++++++++++ src/components/ui/tabs.tsx | 66 ++++++++++++ 7 files changed, 264 insertions(+), 12 deletions(-) rename src/components/tags/{TagTable.tsx => TagTableAnimal.tsx} (95%) create mode 100644 src/components/tags/TagTableMain.tsx create mode 100644 src/components/tags/TagTabs.tsx create mode 100644 src/components/ui/tabs.tsx diff --git a/bun.lock b/bun.lock index 2a61847..3fb7bb9 100644 --- a/bun.lock +++ b/bun.lock @@ -17,6 +17,7 @@ "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", @@ -365,6 +366,8 @@ "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="], + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="], diff --git a/package.json b/package.json index 0d74eb8..133a55c 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", diff --git a/src/app/tags/page.tsx b/src/app/tags/page.tsx index 4539939..ca96d2c 100644 --- a/src/app/tags/page.tsx +++ b/src/app/tags/page.tsx @@ -1,4 +1,5 @@ -import TagTable from "@/components/tags/TagTable"; +import TagTabs from "@/components/tags/TagTabs"; +import { Button } from "@/components/ui/button"; import { prisma } from "@/lib/prisma"; import { PlusCircleIcon } from "lucide-react"; import Link from "next/link"; @@ -15,17 +16,31 @@ export default async function ArtTagsPage() { }); return ( -
-
-

Art Tags

- - Add new tag - -
+
+
+
+

+ Art Tags +

+

+ Manage tags, aliases, categories, and usage across artworks. +

+
+ + +
+ {items.length > 0 ? ( - + ) : ( -

There are no tags yet. Consider adding some!

+

+ There are no tags yet. Consider adding some! +

)}
); diff --git a/src/components/tags/TagTable.tsx b/src/components/tags/TagTableAnimal.tsx similarity index 95% rename from src/components/tags/TagTable.tsx rename to src/components/tags/TagTableAnimal.tsx index 0453a53..ee7b2fc 100644 --- a/src/components/tags/TagTable.tsx +++ b/src/components/tags/TagTableAnimal.tsx @@ -18,6 +18,7 @@ type TagRow = { name: string; slug: string; parent: { id: string; name: string } | null; + isParent: boolean; showOnAnimalPage: boolean; aliases: { alias: string }[]; categories: { id: string; name: string }[]; @@ -59,7 +60,7 @@ function Chips({ ); } -export default function TagTable({ tags }: { tags: TagRow[] }) { +export default function TagTableAnimal({ tags }: { tags: TagRow[] }) { const handleDelete = (id: string) => { deleteTag(id); }; @@ -103,7 +104,7 @@ export default function TagTable({ tags }: { tags: TagRow[] }) { {t.parent.name} ) : ( - + {t.isParent ? "Parent" : "—"} )} diff --git a/src/components/tags/TagTableMain.tsx b/src/components/tags/TagTableMain.tsx new file mode 100644 index 0000000..4e9ab3d --- /dev/null +++ b/src/components/tags/TagTableMain.tsx @@ -0,0 +1,100 @@ +"use client"; + +import type { TagRow } from "@/components/tags/TagTabs"; +import { Button } from "@/components/ui/button"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { PencilIcon } from "lucide-react"; +import Link from "next/link"; + +function Chips({ + values, + empty = "—", + max = 4, + mono = false, +}: { + values: string[]; + empty?: string; + max?: number; + mono?: boolean; +}) { + if (values.length === 0) return {empty}; + + const shown = values.slice(0, max); + const extra = values.length - shown.length; + + return ( +
+ {shown.map((v) => ( + + {v} + + ))} + {extra > 0 ? +{extra} more : null} +
+ ); +} + +export default function TagTableMain({ tags }: { tags: TagRow[] }) { + return ( +
+ + + + Name + Slug + Aliases + Categories + Artworks + + + + + + {tags.map((t) => ( + + {t.name} + + + #{t.slug} + + + + a.alias)} mono max={5} /> + + + + c.name)} max={4} /> + + + + {t._count.artworks} + + + + + + + + + ))} + +
+
+ ); +} diff --git a/src/components/tags/TagTabs.tsx b/src/components/tags/TagTabs.tsx new file mode 100644 index 0000000..cea8e45 --- /dev/null +++ b/src/components/tags/TagTabs.tsx @@ -0,0 +1,66 @@ +"use client"; + +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import * as React from "react"; +// import TagTableMain from "@/components/tags/TagTableMain"; +// import TagTableAnimal from "@/components/tags/TagTableAnimal"; +import { Badge } from "@/components/ui/badge"; +import TagTableAnimal from "./TagTableAnimal"; +import TagTableMain from "./TagTableMain"; + +export type TagRow = { + id: string; + name: string; + slug: string; + parent: { id: string; name: string } | null; + isParent: boolean; + showOnAnimalPage: boolean; + aliases: { alias: string }[]; + categories: { id: string; name: string }[]; + _count: { artworks: number }; +}; + +function isAnimalStudiesTag(t: TagRow) { + // Recommended: primarily category-based; keep showOnAnimalPage as fallback. + const inCategory = t.categories.some((c) => c.name === "Animal Studies"); + // return inCategory || t.showOnAnimalPage; + return inCategory; +} + +export default function TagTabs({ tags }: { tags: TagRow[] }) { + const animal = React.useMemo(() => tags.filter(isAnimalStudiesTag), [tags]); + const normal = React.useMemo( + () => tags.filter((t) => !isAnimalStudiesTag(t)), + [tags, animal.length] + ); + + return ( + + + + All tags {tags.length} + + + + Animal Studies {animal.length} + + + + Other {normal.length} + + + + + + + + + + + + + + + + ); +} diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx new file mode 100644 index 0000000..497ba5e --- /dev/null +++ b/src/components/ui/tabs.tsx @@ -0,0 +1,66 @@ +"use client" + +import * as React from "react" +import * as TabsPrimitive from "@radix-ui/react-tabs" + +import { cn } from "@/lib/utils" + +function Tabs({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsList({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsTrigger({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Tabs, TabsList, TabsTrigger, TabsContent }