From 1e302d2aa2e0e9fa80a0b0d3cc45343204743a05 Mon Sep 17 00:00:00 2001 From: Amirhossein Khalili Date: Fri, 12 Jun 2026 21:35:17 +0330 Subject: [PATCH] fix(admin): polish mobile layout and actions --- src/views/AdminBlog.tsx | 133 +++++++++++++++++++++--------- src/views/AdminBlogCategories.tsx | 22 ++++- src/views/AdminBlogEditor.tsx | 8 +- src/views/AdminBlogTags.tsx | 4 +- src/views/AdminLayout.tsx | 62 ++++++++------ 5 files changed, 153 insertions(+), 76 deletions(-) diff --git a/src/views/AdminBlog.tsx b/src/views/AdminBlog.tsx index 699d8d7..4a8650d 100644 --- a/src/views/AdminBlog.tsx +++ b/src/views/AdminBlog.tsx @@ -11,6 +11,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { useToast } from "@/hooks/use-toast"; import { formatJalali, resolveErrorMessage } from "@/lib/utils"; @@ -91,37 +92,41 @@ export default function AdminBlog() { }; return ( -
+
-

مدیریت بلاگ

پیش‌نویس‌ها، صف بررسی، انتشار و اصلاح نوشته‌ها.

+
- کل: {posts.length} - بررسی: {stats.submitted ?? 0} - منتشر: {stats.published ?? 0} - اصلاح: {stats.changes_requested ?? 0} + کل: {posts.length} + بررسی: {stats.submitted ?? 0} + منتشر: {stats.published ?? 0} + اصلاح: {stats.changes_requested ?? 0}
-
+
+ نوشته‌ها + دسترسی نویسنده‌ها به نوشته‌های خودشان محدود می‌شود. +
+
- setSearch(event.target.value)} placeholder="جستجو..." className="w-64 text-right" /> + setSearch(event.target.value)} placeholder="جستجو..." className="w-full text-right sm:w-64" />
-
- نوشته‌ها - دسترسی نویسنده‌ها به نوشته‌های خودشان محدود می‌شود. -
@@ -143,35 +144,87 @@ export default function AdminBlog() {
) : posts.length ? ( posts.map((post) => ( -
-
- - - {post.status === "draft" || post.status === "changes_requested" ? ( - - ) : null} - {canReview && post.status === "submitted" ? ( - <> - - - - ) : null} -
+
-
- {statusLabels[post.status] ?? post.status} +

{post.title}

+ {statusLabels[post.status] ?? post.status}

{post.updated_at ? formatJalali(post.updated_at, false) : ""}

+
+ + + + + پیش‌نمایش + + + + + + + ویرایش + + + {post.status === "draft" || post.status === "changes_requested" ? ( + + + + + ارسال برای بررسی + + ) : null} + + {canReview && post.status === "submitted" ? ( + <> + + + + + ) : null} +
)) ) : ( diff --git a/src/views/AdminBlogCategories.tsx b/src/views/AdminBlogCategories.tsx index fe98b97..784dac5 100644 --- a/src/views/AdminBlogCategories.tsx +++ b/src/views/AdminBlogCategories.tsx @@ -53,6 +53,11 @@ export default function AdminBlogCategories() { }); const categories = useMemo(() => categoriesQuery.data ?? [], [categoriesQuery.data]); + const rootCategories = useMemo(() => categories.filter((category) => !category.parent_id), [categories]); + const editingHasChildren = useMemo( + () => Boolean(editing && categories.some((category) => category.parent_id === editing.id)), + [categories, editing], + ); const visibleCategories = useMemo(() => { const needle = search.trim().toLowerCase(); if (!needle) return categories; @@ -166,7 +171,7 @@ export default function AdminBlogCategories() {
) : visibleCategories.length ? ( -
+
@@ -217,7 +222,7 @@ export default function AdminBlogCategories() { {deletedQuery.data?.length ? ( -
+
{deletedQuery.data.map((category) => (
{category.name} @@ -251,15 +256,24 @@ export default function AdminBlogCategories() {
- setForm((prev) => ({ ...prev, parent_id: value }))} + disabled={editingHasChildren} + > بدون والد - {categories.filter((item) => item.id !== editing?.id).map((category) => ( + {rootCategories.filter((item) => item.id !== editing?.id).map((category) => ( {category.name} ))} + {editingHasChildren ? ( +

+ دسته‌بندی‌هایی که زیرمجموعه دارند باید در سطح ریشه باقی بمانند. +

+ ) : null}
diff --git a/src/views/AdminBlogEditor.tsx b/src/views/AdminBlogEditor.tsx index 2628f76..1e8425c 100644 --- a/src/views/AdminBlogEditor.tsx +++ b/src/views/AdminBlogEditor.tsx @@ -226,9 +226,9 @@ export default function AdminBlogEditor({ postId }: Props) {
-
- {form.status || "draft"} +

{isNew ? "نوشته جدید" : "ویرایش نوشته"}

+ {form.status || "draft"}

نوشتن مارک‌داون، پیش‌نمایش زنده و تنظیمات انتشار در یک محیط مینیمال. @@ -311,7 +311,7 @@ export default function AdminBlogEditor({ postId }: Props) {

-
+
{tags.map((tag) => { const selected = selectedTagIds.includes(tag.id); return ( @@ -332,7 +332,7 @@ export default function AdminBlogEditor({ postId }: Props) { {canAssignWriters ? (
-
+
{users.map((writer) => { const selected = selectedWriterIds.includes(writer.id); const fullName = [writer.first_name, writer.last_name].filter(Boolean).join(" ") || writer.username; diff --git a/src/views/AdminBlogTags.tsx b/src/views/AdminBlogTags.tsx index 8dfae9a..6520fd2 100644 --- a/src/views/AdminBlogTags.tsx +++ b/src/views/AdminBlogTags.tsx @@ -150,7 +150,7 @@ export default function AdminBlogTags() {
) : visibleTags.length ? ( -
+
@@ -197,7 +197,7 @@ export default function AdminBlogTags() { {deletedQuery.data?.length ? ( -
+
{deletedQuery.data.map((tag) => (
{tag.name} diff --git a/src/views/AdminLayout.tsx b/src/views/AdminLayout.tsx index d7ab169..e5ef9ba 100644 --- a/src/views/AdminLayout.tsx +++ b/src/views/AdminLayout.tsx @@ -80,7 +80,7 @@ export default function AdminLayout({ children }: { children: ReactNode }) {
-
-
+
+

پنل مدیریت

-
- {visibleNavItems.map((item) => { - const Icon = item.icon; - return ( - - cn( - "flex shrink-0 items-center gap-1 rounded-full px-3 py-2 text-xs", - isActive || isItemActive(item.to) - ? "bg-primary text-primary-foreground" - : "bg-muted text-muted-foreground", - ) - } - > - - {item.label} - - ); - })} -
+

مدیریت بخش‌های سامانه

-
+
{children}
+
+ +
); }