fix(admin-dashboard): make charts RTL-safe

This commit is contained in:
2026-06-15 17:28:55 +03:30
parent 83321c1d39
commit 9f07c0740d

View File

@@ -254,7 +254,7 @@ function FilterCard({
function ChartViewport({ children, minWidth = 560 }: { children: React.ReactNode; minWidth?: number }) {
return (
<div className="overflow-x-auto overflow-y-hidden pb-2">
<div className="overflow-x-auto overflow-y-hidden pb-2" dir="ltr">
<div style={{ minWidth }}>{children}</div>
</div>
);
@@ -357,15 +357,24 @@ function HorizontalBarCard({
className="w-full"
style={{ height: chartHeight(data.length) }}
>
<BarChart data={data} layout="vertical" margin={{ top: 12, right: 16, bottom: 24, left: 20 }}>
<BarChart data={data} layout="vertical" margin={{ top: 12, right: axisWidth(data) + 10, bottom: 24, left: 20 }}>
<CartesianGrid horizontal={false} strokeDasharray="3 3" />
<XAxis type="number" tickFormatter={(value) => valueFormatter ? valueFormatter(Number(value)) : formatNumberPersian(Number(value))} />
<XAxis
type="number"
reversed
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={(value) => valueFormatter ? valueFormatter(Number(value)) : formatNumberPersian(Number(value))}
/>
<YAxis
dataKey="label"
type="category"
orientation="right"
width={axisWidth(data)}
tickLine={false}
axisLine={false}
tickMargin={10}
tickFormatter={(value) => truncateLabel(String(value))}
/>
<ChartTooltip content={<CustomValueTooltip unit={unit} formatter={valueFormatter} />} />
@@ -410,16 +419,24 @@ function TrendLineCard({
) : (
<ChartViewport>
<ChartContainer config={{ value: { label: "مقدار", color } }} className="h-[300px] w-full">
<LineChart data={data} margin={{ top: 16, right: 18, bottom: 32, left: 26 }}>
<LineChart data={data} margin={{ top: 16, right: 76, bottom: 32, left: 18 }}>
<CartesianGrid vertical={false} strokeDasharray="3 3" />
<XAxis
dataKey="date"
tickLine={false}
axisLine={false}
minTickGap={34}
tickMargin={10}
tickFormatter={formatJalaliTick}
/>
<YAxis width={76} tickFormatter={(value) => valueFormatter(Number(value))} />
<YAxis
orientation="right"
width={76}
tickLine={false}
axisLine={false}
tickMargin={10}
tickFormatter={(value) => valueFormatter(Number(value))}
/>
<ChartTooltip
content={({ active, payload }) => {
if (!active || !payload?.length) return null;
@@ -464,12 +481,28 @@ function StatusChartCard({
<>
<ChartViewport minWidth={460}>
<ChartContainer config={{ value: { label: "تعداد", color: PALETTE.teal } }} className="h-[300px] w-full">
<BarChart data={data} margin={{ top: 14, right: 14, bottom: 44, left: 22 }}>
<CartesianGrid vertical={false} strokeDasharray="3 3" />
<XAxis dataKey="label" tickLine={false} axisLine={false} tickFormatter={(value) => truncateLabel(String(value), 14)} />
<YAxis width={64} tickFormatter={(value) => formatNumberPersian(Number(value))} />
<ChartTooltip content={<ChartTooltipContent hideLabel />} />
<Bar dataKey="value" radius={[8, 8, 0, 0]}>
<BarChart data={data} layout="vertical" margin={{ top: 14, right: 118, bottom: 28, left: 18 }}>
<CartesianGrid horizontal={false} strokeDasharray="3 3" />
<XAxis
type="number"
reversed
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={(value) => formatNumberPersian(Number(value))}
/>
<YAxis
dataKey="label"
type="category"
orientation="right"
width={108}
tickLine={false}
axisLine={false}
tickMargin={10}
tickFormatter={(value) => truncateLabel(String(value), 14)}
/>
<ChartTooltip content={<CustomValueTooltip />} />
<Bar dataKey="value" radius={[8, 8, 8, 8]}>
{data.map((_, index) => (
<Cell key={index} fill={STATUS_COLORS[index % STATUS_COLORS.length]} />
))}
@@ -505,10 +538,17 @@ function ActivityTrendCard({ data }: { data: BlogAnalyticsSchema["activity_trend
}}
className="h-[320px] w-full"
>
<LineChart data={data} margin={{ top: 16, right: 18, bottom: 32, left: 26 }}>
<LineChart data={data} margin={{ top: 16, right: 64, bottom: 32, left: 18 }}>
<CartesianGrid vertical={false} strokeDasharray="3 3" />
<XAxis dataKey="date" tickLine={false} axisLine={false} tickFormatter={formatJalaliTick} minTickGap={34} />
<YAxis width={64} tickFormatter={(value) => formatNumberPersian(Number(value))} />
<XAxis dataKey="date" tickLine={false} axisLine={false} tickFormatter={formatJalaliTick} minTickGap={34} tickMargin={10} />
<YAxis
orientation="right"
width={64}
tickLine={false}
axisLine={false}
tickMargin={10}
tickFormatter={(value) => formatNumberPersian(Number(value))}
/>
<ChartTooltip content={<ChartTooltipContent />} />
<Line type="monotone" dataKey="likes" stroke="var(--color-likes)" strokeWidth={3} dot={false} />
<Line type="monotone" dataKey="saves" stroke="var(--color-saves)" strokeWidth={3} dot={false} />
@@ -663,7 +703,7 @@ function UsersSection() {
});
return (
<div className="space-y-6">
<div className="space-y-6" dir="rtl">
<FilterCard title="فیلتر کاربران" description="این فیلتر فقط روی کاربران و تاریخ عضویت آن‌ها اعمال می‌شود.">
<DateRangeFilter value={filters} onChange={setFilters} onReset={() => setFilters({ from: "", to: "" })} />
</FilterCard>
@@ -854,7 +894,7 @@ export default function AdminDashboard() {
</div>
</div>
<Tabs defaultValue="users" className="space-y-6">
<Tabs dir="rtl" defaultValue="users" className="space-y-6">
<TabsList className="grid h-auto w-full grid-cols-3 rounded-2xl p-1 sm:w-fit">
<TabsTrigger value="users" className="gap-2 rounded-xl py-2">
<UsersRound className="h-4 w-4" />