fix(admin): improve responsive UI styles of admin blog page

This commit is contained in:
2026-06-12 22:02:40 +03:30
parent eb28a00abd
commit cb8eeadba9

View File

@@ -3,6 +3,7 @@
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { BookOpenText, CheckCircle2, Clock3, Edit, Eye, Loader2, Plus, Send, XCircle } from "lucide-react"; import { BookOpenText, CheckCircle2, Clock3, Edit, Eye, Loader2, Plus, Send, XCircle } from "lucide-react";
import { Link } from "@/lib/router"; import { Link } from "@/lib/router";
import BlogThumbnail from "@/components/BlogThumbnail";
import { useAuth } from "@/contexts/AuthContext"; import { useAuth } from "@/contexts/AuthContext";
import { api } from "@/lib/api"; import { api } from "@/lib/api";
import type * as Types from "@/lib/types"; import type * as Types from "@/lib/types";
@@ -123,7 +124,6 @@ export default function AdminBlog() {
<CardDescription>دسترسی نویسندهها به نوشتههای خودشان محدود میشود.</CardDescription> <CardDescription>دسترسی نویسندهها به نوشتههای خودشان محدود میشود.</CardDescription>
</div> </div>
<div className="flex flex-col gap-2 sm:flex-row"> <div className="flex flex-col gap-2 sm:flex-row">
<Button variant="outline" onClick={loadPosts}>جستجو</Button>
<Input value={search} onChange={(event) => setSearch(event.target.value)} placeholder="جستجو..." className="w-full text-right sm:w-64" /> <Input value={search} onChange={(event) => setSearch(event.target.value)} placeholder="جستجو..." className="w-full text-right sm:w-64" />
<Select value={status} onValueChange={setStatus}> <Select value={status} onValueChange={setStatus}>
<SelectTrigger className="w-full sm:w-48"><SelectValue /></SelectTrigger> <SelectTrigger className="w-full sm:w-48"><SelectValue /></SelectTrigger>
@@ -144,84 +144,102 @@ export default function AdminBlog() {
<div className="flex justify-center py-10"><Loader2 className="h-5 w-5 animate-spin" /></div> <div className="flex justify-center py-10"><Loader2 className="h-5 w-5 animate-spin" /></div>
) : posts.length ? ( ) : posts.length ? (
posts.map((post) => ( posts.map((post) => (
<div key={post.id} className="flex gap-3 rounded-2xl border p-4 flex-row items-center justify-between"> <div key={post.id} className="flex flex-col gap-4 rounded-2xl border p-3 sm:p-4 md:flex-row md:items-center md:justify-between">
<div className="text-right"> <div className="flex min-w-0 flex-1 items-start gap-3 md:gap-4">
<div className="flex flex-col-reverse md:flex-row flex-wrap items-start gap-2"> <BlogThumbnail
<h3 className="font-semibold">{post.title}</h3> post={post}
<Badge variant={post.status === "published" ? "default" : "secondary"}>{statusLabels[post.status] ?? post.status}</Badge> imageUrl={post.absolute_featured_image_thumbnail_url || post.absolute_featured_image_preview_url || post.absolute_featured_image_url || post.featured_image}
className="h-20 w-24 shrink-0 rounded-xl sm:h-24 sm:w-36 md:h-28 md:w-44"
imageClassName="group-hover:scale-100"
/>
<div className="min-w-0 flex-1 text-right">
<div className="flex flex-col-reverse flex-wrap items-start gap-2 sm:flex-row sm:items-center">
<h3 className="line-clamp-2 font-semibold leading-7">{post.title}</h3>
<Badge variant={post.status === "published" ? "default" : "secondary"}>{statusLabels[post.status] ?? post.status}</Badge>
</div>
<p className="mt-1 text-xs text-muted-foreground">
{post.updated_at ? formatJalali(post.updated_at, false) : ""}
</p>
</div> </div>
<p className="mt-1 text-xs text-muted-foreground">
{post.updated_at ? formatJalali(post.updated_at, false) : ""}
</p>
</div> </div>
<div className="grid grid-cols-2 grid-flow-col grid-rows-2 gap-2 md:flex md:flex-row md:flex-wrap" dir="ltr"> <div className="flex flex-wrap gap-2 md:grid md:grid-cols-2 md:grid-rows-2" dir="ltr">
<Tooltip> <div className="flex flex-1 basis-[calc(33.333%-0.5rem)] md:col-start-1 md:row-start-1 md:block md:basis-auto">
<TooltipTrigger asChild>
<Button variant="outline" size="sm" asChild className="w-full md:w-auto">
<Link
to={`/admin/blog/${post.id}/preview`}
aria-label="پیش‌نمایش"
className="flex justify-center"
>
<Eye className="h-4 w-4" />
</Link>
</Button>
</TooltipTrigger>
<TooltipContent>پیشنمایش</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="secondary" size="sm" asChild className="w-full md:w-auto">
<Link
to={`/admin/blog/${post.id}/edit`}
aria-label="ویرایش"
className="flex justify-center"
>
<Edit className="h-4 w-4" />
</Link>
</Button>
</TooltipTrigger>
<TooltipContent>ویرایش</TooltipContent>
</Tooltip>
{post.status === "draft" || post.status === "changes_requested" ? (
<Tooltip> <Tooltip>
<TooltipTrigger asChild> <TooltipTrigger asChild>
<Button <Button variant="outline" size="sm" asChild className="w-full">
size="sm" <Link
onClick={() => submitPost(post.id)} to={`/admin/blog/${post.id}/preview`}
disabled={actingId === post.id} aria-label="پیش‌نمایش"
aria-label="ارسال برای بررسی" className="flex justify-center"
className="w-full md:w-auto" >
> <Eye className="h-4 w-4" />
<Send className="h-4 w-4" /> </Link>
</Button> </Button>
</TooltipTrigger> </TooltipTrigger>
<TooltipContent>ارسال برای بررسی</TooltipContent> <TooltipContent>پیشنمایش</TooltipContent>
</Tooltip> </Tooltip>
</div>
<div className="flex flex-1 basis-[calc(33.333%-0.5rem)] md:col-start-1 md:row-start-2 md:block md:basis-auto">
<Tooltip>
<TooltipTrigger asChild>
<Button variant="secondary" size="sm" asChild className="w-full">
<Link
to={`/admin/blog/${post.id}/edit`}
aria-label="ویرایش"
className="flex justify-center"
>
<Edit className="h-4 w-4" />
</Link>
</Button>
</TooltipTrigger>
<TooltipContent>ویرایش</TooltipContent>
</Tooltip>
</div>
{post.status === "draft" || post.status === "changes_requested" ? (
<div className="flex flex-1 basis-[calc(33.333%-0.5rem)] md:col-start-2 md:row-start-1 md:block md:basis-auto">
<Tooltip>
<TooltipTrigger asChild>
<Button
size="sm"
onClick={() => submitPost(post.id)}
disabled={actingId === post.id}
aria-label="ارسال برای بررسی"
className="w-full"
>
<Send className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>ارسال برای بررسی</TooltipContent>
</Tooltip>
</div>
) : null} ) : null}
{canReview && post.status === "submitted" ? ( {canReview && post.status === "submitted" ? (
<> <>
<Button <div className="flex flex-1 basis-[calc(33.333%-0.5rem)] md:col-start-2 md:row-start-1 md:block md:basis-auto">
size="sm" <Button
onClick={() => reviewPost(post.id, "publish")} size="sm"
disabled={actingId === post.id} onClick={() => reviewPost(post.id, "publish")}
className="w-full md:w-auto" disabled={actingId === post.id}
> className="w-full"
انتشار >
</Button> انتشار
</Button>
</div>
<Button <div className="flex flex-1 basis-[calc(33.333%-0.5rem)] md:col-start-2 md:row-start-2 md:block md:basis-auto">
size="sm" <Button
variant="outline" size="sm"
onClick={() => reviewPost(post.id, "request_changes")} variant="outline"
disabled={actingId === post.id} onClick={() => reviewPost(post.id, "request_changes")}
className="w-full md:w-auto" disabled={actingId === post.id}
> className="w-full"
درخواست اصلاح >
</Button> درخواست اصلاح
</Button>
</div>
</> </>
) : null} ) : null}
</div> </div>