TorbatYar/frontend/modules/experience/features/designSystemPlayground.tsx
Mortezakoohjani 0eec9f729b feat(experience): deploy Experience frontend FE-11.0-11.5 portal
Commit completed Torbat Pages admin frontend module, BFF proxy, routes, and validation artifacts for official platform deploy.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 21:01:50 +03:30

216 lines
7.6 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState } from "react";
import { PageHeader, Card, CardContent, Button, Badge } from "@/components/ds";
import { ExperienceBreadcrumbs } from "@/modules/experience/components/ExperienceBreadcrumbs";
import {
ExperienceChart,
ExperienceEmptyState,
ExperienceKanban,
ExperienceMap,
ExperienceSkeleton,
ExperienceStatusChip,
ExperienceStatGrid,
ExperienceTablePage,
ExperienceThemeProvider,
ExperienceTimeline,
ExperienceFadeUp,
ExperienceFadeIn,
experienceTokens,
} from "@/modules/experience/design-system";
const demoChart = [
{ name: "فضاها", value: 3 },
{ name: "سایت", value: 5 },
{ name: "صفحات", value: 12 },
{ name: "فرم", value: 4 },
];
export function DesignSystemPlaygroundPage() {
const [dir, setDir] = useState<"rtl" | "ltr">("rtl");
const [brandAccent, setBrandAccent] = useState("#0891b2");
const [kanban, setKanban] = useState([
{
id: "draft",
title: "پیش‌نویس",
cards: [
{ id: "c1", title: "صفحه خانه", subtitle: "workspace-a" },
{ id: "c2", title: "فرم تماس", subtitle: "forms" },
],
},
{
id: "review",
title: "بازبینی",
cards: [{ id: "c3", title: "قالب رویداد", subtitle: "templates" }],
},
{
id: "live",
title: "منتشر",
cards: [{ id: "c4", title: "سایت اصلی", subtitle: "sites" }],
},
]);
return (
<ExperienceThemeProvider
direction={dir}
brand={{ accent: brandAccent, accentSoft: `${brandAccent}22` }}
tenantThemeId="playground"
>
<ExperienceFadeUp className="space-y-6">
<ExperienceBreadcrumbs current="سیستم طراحی" />
<PageHeader
title="زمین بازی سیستم طراحی"
description="کامپوننت‌های مستقل Experience — تم روشن/تیره از هدر، برند و جهت از این صفحه."
actions={
<div className="flex flex-wrap gap-2">
<Button
variant="outline"
size="sm"
onClick={() => setDir((d) => (d === "rtl" ? "ltr" : "rtl"))}
>
جهت: {dir.toUpperCase()}
</Button>
<label className="flex items-center gap-2 text-sm">
برند
<input
type="color"
value={brandAccent}
onChange={(e) => setBrandAccent(e.target.value)}
aria-label="رنگ برند"
className="h-8 w-10 cursor-pointer rounded border border-[var(--border)]"
/>
</label>
</div>
}
/>
<Card>
<CardContent className="space-y-3 p-4">
<h2 className="text-sm font-semibold">توکنها</h2>
<div className="flex flex-wrap gap-2">
{Object.entries(experienceTokens).map(([k, v]) => (
<Badge key={k} tone="default">
{k}: {v}
</Badge>
))}
<ExperienceStatusChip status="published" />
<ExperienceStatusChip status="draft" />
</div>
</CardContent>
</Card>
<ExperienceStatGrid
stats={[
{ label: "فضاهای کاری", value: "3" },
{ label: "سایت‌ها", value: "5" },
{ label: "صفحات", value: "12" },
{ label: "انتشار", value: "2" },
]}
/>
<div className="grid gap-4 lg:grid-cols-2">
<Card>
<CardContent className="p-4">
<h2 className="mb-3 text-sm font-semibold">نمودار</h2>
<ExperienceChart data={demoChart} ariaLabel="نمودار نمونه منابع" />
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<h2 className="mb-3 text-sm font-semibold">نقشه</h2>
<ExperienceMap
title="نقشه نمونه تربت"
markers={[
{ id: "1", label: "مرکز", lat: 35.25, lng: 59.22 },
{ id: "2", label: "شعبه", lat: 35.27, lng: 59.25 },
]}
/>
</CardContent>
</Card>
</div>
<Card>
<CardContent className="p-4">
<h2 className="mb-3 text-sm font-semibold">خط زمانی</h2>
<ExperienceTimeline
items={[
{
id: "t1",
title: "ایجاد فضای کاری",
description: "از API workspaces",
at: new Date().toISOString(),
tone: "success",
},
{
id: "t2",
title: "انتشار پیش‌نویس",
description: "publish-releases",
at: new Date(Date.now() - 3600_000).toISOString(),
tone: "warning",
},
]}
/>
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<h2 className="mb-3 text-sm font-semibold">کانبان</h2>
<ExperienceKanban
columns={kanban}
onMove={(cardId, fromId, toId) => {
setKanban((cols) => {
const next = cols.map((c) => ({ ...c, cards: [...c.cards] }));
const from = next.find((c) => c.id === fromId);
const to = next.find((c) => c.id === toId);
if (!from || !to) return cols;
const idx = from.cards.findIndex((c) => c.id === cardId);
if (idx < 0) return cols;
const [card] = from.cards.splice(idx, 1);
to.cards.push(card);
return next;
});
}}
/>
</CardContent>
</Card>
<div className="grid gap-4 lg:grid-cols-2">
<Card>
<CardContent className="p-4">
<h2 className="mb-3 text-sm font-semibold">جدول</h2>
<ExperienceTablePage
title="نمونه جدول"
rows={[
{ id: "1", name: "سایت اصلی", status: "published" },
{ id: "2", name: "لندینگ", status: "draft" },
]}
columns={[
{ key: "name", header: "نام" },
{
key: "status",
header: "وضعیت",
render: (row) => <ExperienceStatusChip status={String(row.status)} />,
},
]}
/>
</CardContent>
</Card>
<Card>
<CardContent className="space-y-4 p-4">
<h2 className="text-sm font-semibold">Empty / Skeleton / Motion</h2>
<ExperienceEmptyState title="نمونه Empty" description="برای لیست‌های خالی API." />
<ExperienceSkeleton rows={3} />
<ExperienceFadeIn>
<p className="text-sm text-[var(--muted)]">انیمیشن FadeIn فعال است.</p>
</ExperienceFadeIn>
</CardContent>
</Card>
</div>
</ExperienceFadeUp>
</ExperienceThemeProvider>
);
}
export default DesignSystemPlaygroundPage;