style(tags): align tags page with list layout
This commit is contained in:
@@ -8,6 +8,7 @@ import { useWorkspace } from "../context/WorkspaceContext";
|
||||
import { useTranslation } from "../hooks/useTranslation";
|
||||
import { TAGS_CREATE, TAGS_EDIT, canDeleteWorkspaceResource, canWorkspace } from "../lib/permissions";
|
||||
import FilterBar from "../components/FilterBar";
|
||||
import { ListPageSkeleton } from "../components/ListPageSkeleton";
|
||||
import { Modal } from "../components/Modal";
|
||||
import { Pagination } from "../components/Pagination";
|
||||
import { Button } from "../components/ui/button";
|
||||
@@ -140,39 +141,50 @@ export default function Tags() {
|
||||
};
|
||||
|
||||
if (!activeWorkspace) {
|
||||
return <div className="p-6 text-center text-slate-500">{t.tags?.selectWorkspace || t.clients.selectWorkspace}</div>;
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl p-4 md:p-6">
|
||||
<div className="rounded-3xl border border-slate-200 bg-white p-6 text-slate-600 shadow-sm dark:border-slate-800 dark:bg-slate-900 dark:text-slate-300">
|
||||
{t.tags?.selectWorkspace || t.clients.selectWorkspace}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col p-6 min-h-[calc(100vh-73px)] bg-slate-50 dark:bg-slate-900">
|
||||
<div className="flex justify-between items-center mb-8 gap-4">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">{t.tags?.title || "Tags"}</h1>
|
||||
<p className="text-slate-500 dark:text-slate-400 mt-1">
|
||||
{t.tags?.description?.(activeWorkspace.name) || `Manage tags for ${activeWorkspace.name}`}
|
||||
</p>
|
||||
<div className="mx-auto flex min-h-full max-w-7xl flex-col p-4 md:p-6">
|
||||
<div className="flex flex-1 flex-col gap-5">
|
||||
<div className="rounded-3xl border border-slate-200 bg-white p-5 shadow-sm dark:border-slate-800 dark:bg-slate-900 sm:p-6">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">{t.tags?.title || "Tags"}</h1>
|
||||
<p className="mt-1 text-sm text-slate-500 dark:text-slate-400">
|
||||
{t.tags?.description?.(activeWorkspace.name) || `Manage tags for ${activeWorkspace.name}`}
|
||||
</p>
|
||||
</div>
|
||||
{canCreateTag && (
|
||||
<Button onClick={openCreateModal} size="icon" className="shrink-0 shadow-sm" title={t.tags?.create || "Create Tag"}>
|
||||
<Plus className="h-5 w-5" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{canCreateTag && (
|
||||
<Button onClick={openCreateModal} size="icon" className="shadow-sm shrink-0" title={t.tags?.create || "Create Tag"}>
|
||||
<Plus className="h-5 w-5" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<FilterBar
|
||||
searchQuery={searchQuery}
|
||||
setSearchQuery={setSearchQuery}
|
||||
ordering={ordering}
|
||||
setOrdering={setOrdering}
|
||||
orderingOptions={orderingOptions}
|
||||
searchPlaceholder={t.tags?.searchPlaceholder || "Search tags..."}
|
||||
/>
|
||||
<div className="rounded-3xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-900 sm:p-5">
|
||||
<FilterBar
|
||||
searchQuery={searchQuery}
|
||||
setSearchQuery={setSearchQuery}
|
||||
ordering={ordering}
|
||||
setOrdering={setOrdering}
|
||||
orderingOptions={orderingOptions}
|
||||
searchPlaceholder={t.tags?.searchPlaceholder || "Search tags..."}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="p-12 flex justify-center text-slate-500">{t.loading || "Loading..."}</div>
|
||||
) : (
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className="mb-6 grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4">
|
||||
{isLoading ? (
|
||||
<ListPageSkeleton variant="dense-grid" />
|
||||
) : (
|
||||
<div className="flex flex-1 flex-col gap-6">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4">
|
||||
{tags.map((tag) => {
|
||||
const canDeleteTag = canDeleteWorkspaceResource({
|
||||
workspaceRole,
|
||||
@@ -196,7 +208,13 @@ export default function Tags() {
|
||||
{(canEditTag || canDeleteTag) && (
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
{canEditTag && (
|
||||
<Button variant="ghost" size="icon" onClick={() => openEditModal(tag)} title={t.actions?.edit || "Edit"}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => openEditModal(tag)}
|
||||
className="h-8 w-8 text-slate-400 hover:bg-blue-50 hover:text-blue-600 dark:hover:bg-blue-900/20 dark:hover:text-blue-400"
|
||||
title={t.actions?.edit || "Edit"}
|
||||
>
|
||||
<Edit2 className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
@@ -205,9 +223,10 @@ export default function Tags() {
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setDeleteModal({ isOpen: true, tag })}
|
||||
className="h-8 w-8 text-slate-400 hover:bg-red-50 hover:text-red-600 dark:hover:bg-red-900/20 dark:hover:text-red-400"
|
||||
title={t.actions?.delete || "Delete"}
|
||||
>
|
||||
<Trash2 className="w-4 h-4 text-red-500" />
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
@@ -219,9 +238,9 @@ export default function Tags() {
|
||||
})}
|
||||
|
||||
{tags.length === 0 && (
|
||||
<div className="py-16 flex flex-col items-center justify-center border-2 border-dashed border-slate-200 dark:border-slate-800 rounded-2xl text-slate-500 dark:text-slate-400">
|
||||
<div className="col-span-full flex flex-1 flex-col items-center justify-center rounded-3xl border-2 border-dashed border-slate-200 bg-white py-16 text-slate-500 shadow-sm dark:border-slate-800 dark:bg-slate-900 dark:text-slate-400">
|
||||
<TagIcon className="w-10 h-10 mb-3" />
|
||||
<p>{t.tags?.emptyState || "No tags found"}</p>
|
||||
<p className="font-medium">{t.tags?.emptyState || "No tags found"}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -235,6 +254,7 @@ export default function Tags() {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
isOpen={isModalOpen}
|
||||
|
||||
Reference in New Issue
Block a user