fix(admin-dashboard): make charts RTL-safe
This commit is contained in:
@@ -254,7 +254,7 @@ function FilterCard({
|
|||||||
|
|
||||||
function ChartViewport({ children, minWidth = 560 }: { children: React.ReactNode; minWidth?: number }) {
|
function ChartViewport({ children, minWidth = 560 }: { children: React.ReactNode; minWidth?: number }) {
|
||||||
return (
|
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 style={{ minWidth }}>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -357,15 +357,24 @@ function HorizontalBarCard({
|
|||||||
className="w-full"
|
className="w-full"
|
||||||
style={{ height: chartHeight(data.length) }}
|
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" />
|
<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
|
<YAxis
|
||||||
dataKey="label"
|
dataKey="label"
|
||||||
type="category"
|
type="category"
|
||||||
|
orientation="right"
|
||||||
width={axisWidth(data)}
|
width={axisWidth(data)}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
|
tickMargin={10}
|
||||||
tickFormatter={(value) => truncateLabel(String(value))}
|
tickFormatter={(value) => truncateLabel(String(value))}
|
||||||
/>
|
/>
|
||||||
<ChartTooltip content={<CustomValueTooltip unit={unit} formatter={valueFormatter} />} />
|
<ChartTooltip content={<CustomValueTooltip unit={unit} formatter={valueFormatter} />} />
|
||||||
@@ -410,16 +419,24 @@ function TrendLineCard({
|
|||||||
) : (
|
) : (
|
||||||
<ChartViewport>
|
<ChartViewport>
|
||||||
<ChartContainer config={{ value: { label: "مقدار", color } }} className="h-[300px] w-full">
|
<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" />
|
<CartesianGrid vertical={false} strokeDasharray="3 3" />
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="date"
|
dataKey="date"
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
minTickGap={34}
|
minTickGap={34}
|
||||||
|
tickMargin={10}
|
||||||
tickFormatter={formatJalaliTick}
|
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
|
<ChartTooltip
|
||||||
content={({ active, payload }) => {
|
content={({ active, payload }) => {
|
||||||
if (!active || !payload?.length) return null;
|
if (!active || !payload?.length) return null;
|
||||||
@@ -464,12 +481,28 @@ function StatusChartCard({
|
|||||||
<>
|
<>
|
||||||
<ChartViewport minWidth={460}>
|
<ChartViewport minWidth={460}>
|
||||||
<ChartContainer config={{ value: { label: "تعداد", color: PALETTE.teal } }} className="h-[300px] w-full">
|
<ChartContainer config={{ value: { label: "تعداد", color: PALETTE.teal } }} className="h-[300px] w-full">
|
||||||
<BarChart data={data} margin={{ top: 14, right: 14, bottom: 44, left: 22 }}>
|
<BarChart data={data} layout="vertical" margin={{ top: 14, right: 118, bottom: 28, left: 18 }}>
|
||||||
<CartesianGrid vertical={false} strokeDasharray="3 3" />
|
<CartesianGrid horizontal={false} strokeDasharray="3 3" />
|
||||||
<XAxis dataKey="label" tickLine={false} axisLine={false} tickFormatter={(value) => truncateLabel(String(value), 14)} />
|
<XAxis
|
||||||
<YAxis width={64} tickFormatter={(value) => formatNumberPersian(Number(value))} />
|
type="number"
|
||||||
<ChartTooltip content={<ChartTooltipContent hideLabel />} />
|
reversed
|
||||||
<Bar dataKey="value" radius={[8, 8, 0, 0]}>
|
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) => (
|
{data.map((_, index) => (
|
||||||
<Cell key={index} fill={STATUS_COLORS[index % STATUS_COLORS.length]} />
|
<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"
|
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" />
|
<CartesianGrid vertical={false} strokeDasharray="3 3" />
|
||||||
<XAxis dataKey="date" tickLine={false} axisLine={false} tickFormatter={formatJalaliTick} minTickGap={34} />
|
<XAxis dataKey="date" tickLine={false} axisLine={false} tickFormatter={formatJalaliTick} minTickGap={34} tickMargin={10} />
|
||||||
<YAxis width={64} tickFormatter={(value) => formatNumberPersian(Number(value))} />
|
<YAxis
|
||||||
|
orientation="right"
|
||||||
|
width={64}
|
||||||
|
tickLine={false}
|
||||||
|
axisLine={false}
|
||||||
|
tickMargin={10}
|
||||||
|
tickFormatter={(value) => formatNumberPersian(Number(value))}
|
||||||
|
/>
|
||||||
<ChartTooltip content={<ChartTooltipContent />} />
|
<ChartTooltip content={<ChartTooltipContent />} />
|
||||||
<Line type="monotone" dataKey="likes" stroke="var(--color-likes)" strokeWidth={3} dot={false} />
|
<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} />
|
<Line type="monotone" dataKey="saves" stroke="var(--color-saves)" strokeWidth={3} dot={false} />
|
||||||
@@ -663,7 +703,7 @@ function UsersSection() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6" dir="rtl">
|
||||||
<FilterCard title="فیلتر کاربران" description="این فیلتر فقط روی کاربران و تاریخ عضویت آنها اعمال میشود.">
|
<FilterCard title="فیلتر کاربران" description="این فیلتر فقط روی کاربران و تاریخ عضویت آنها اعمال میشود.">
|
||||||
<DateRangeFilter value={filters} onChange={setFilters} onReset={() => setFilters({ from: "", to: "" })} />
|
<DateRangeFilter value={filters} onChange={setFilters} onReset={() => setFilters({ from: "", to: "" })} />
|
||||||
</FilterCard>
|
</FilterCard>
|
||||||
@@ -854,7 +894,7 @@ export default function AdminDashboard() {
|
|||||||
</div>
|
</div>
|
||||||
</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">
|
<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">
|
<TabsTrigger value="users" className="gap-2 rounded-xl py-2">
|
||||||
<UsersRound className="h-4 w-4" />
|
<UsersRound className="h-4 w-4" />
|
||||||
|
|||||||
Reference in New Issue
Block a user