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
-
-
+
+
+
{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 }