feat: clarify dashboard chart scales

This commit is contained in:
2026-08-20 23:01:06 +03:30
parent 05e4dcd123
commit 41fb25d0b0
3 changed files with 83 additions and 14 deletions

View File

@@ -13,7 +13,7 @@
<Card class={cn('rounded-lg shadow-xs', className)}>
<CardContent class="flex h-full flex-col items-center justify-center gap-5 p-6 text-center sm:p-8">
<div
class="relative grid size-40 shrink-0 place-items-center sm:size-48"
class="fee-donut-graphic relative grid shrink-0 place-items-center"
role="img"
aria-label={`سهم کارمزد ${formatPercent(value)}`}
>
@@ -32,7 +32,9 @@
class="transition-[stroke-dasharray] duration-700 motion-reduce:transition-none"
/>
</svg>
<strong class="absolute text-xl font-extrabold tabular-nums">{formatPercent(value)}</strong>
<strong class="absolute text-xl font-extrabold tabular-nums sm:text-2xl lg:text-3xl"
>{formatPercent(value)}</strong
>
</div>
<div class="max-w-sm min-w-0">
<div class="flex items-center justify-center gap-1.5">
@@ -54,3 +56,11 @@
</div>
</CardContent>
</Card>
<style>
.fee-donut-graphic {
width: clamp(10rem, 30vw, 20rem);
max-width: 100%;
aspect-ratio: 1;
}
</style>

View File

@@ -9,16 +9,27 @@
let active = $state<number | null>(null);
const width = 760;
const height = 250;
const pad = { x: 34, y: 28 };
const height = 280;
const pad = { top: 24, right: 24, bottom: 52, left: 68 };
const max = $derived(Math.max(1, ...data.map((point) => point.bankPaidSessions)));
const positions = $derived(
data.map((point, index) => ({
...point,
x: pad.x + (index * (width - pad.x * 2)) / Math.max(1, data.length - 1),
y: height - pad.y - (point.bankPaidSessions / max) * (height - pad.y * 2),
x: pad.left + (index * (width - pad.left - pad.right)) / Math.max(1, data.length - 1),
y: height - pad.bottom - (point.bankPaidSessions / max) * (height - pad.top - pad.bottom),
})),
);
const xTickIndexes = $derived.by(() => {
const tickCount = Math.min(6, data.length);
if (tickCount <= 1) return data.length ? [0] : [];
return [
...new Set(
Array.from({ length: tickCount }, (_, index) =>
Math.round((index * (data.length - 1)) / (tickCount - 1)),
),
),
];
});
const path = $derived(
positions.map((point, index) => `${index ? 'L' : 'M'} ${point.x} ${point.y}`).join(' '),
);
@@ -38,7 +49,7 @@
}
</script>
<div class="relative min-h-[260px] w-full overflow-hidden" dir="ltr">
<div class="relative min-h-[290px] w-full overflow-hidden" dir="ltr">
{#if data.length === 0}
<div class="text-muted-foreground grid h-[260px] place-items-center text-sm">
داده‌ای برای این بازه ثبت نشده است.
@@ -46,7 +57,7 @@
{:else}
<svg
viewBox={`0 0 ${width} ${height}`}
class="h-auto min-h-[250px] w-full overflow-visible"
class="h-auto min-h-[280px] w-full overflow-visible"
role="img"
aria-label="روند پرداخت‌های موفق"
>
@@ -57,17 +68,64 @@
</linearGradient>
</defs>
{#each [0, 1, 2, 3, 4] as row}
{@const y = pad.top + (row * (height - pad.top - pad.bottom)) / 4}
<line
x1={pad.x}
x2={width - pad.x}
y1={pad.y + (row * (height - pad.y * 2)) / 4}
y2={pad.y + (row * (height - pad.y * 2)) / 4}
x1={pad.left}
x2={width - pad.right}
y1={y}
y2={y}
stroke="var(--border)"
stroke-dasharray="4 6"
/>
<text x={pad.left - 10} y={y + 4} fill="var(--muted-foreground)" font-size="10" text-anchor="end"
>{formatValue(Math.round(max * (1 - row / 4)))}</text
>
{/each}
<line x1={pad.left} x2={pad.left} y1={pad.top} y2={height - pad.bottom} stroke="var(--border)" />
<line
x1={pad.left}
x2={width - pad.right}
y1={height - pad.bottom}
y2={height - pad.bottom}
stroke="var(--border)"
/>
{#each xTickIndexes as tickIndex}
{@const tick = positions[tickIndex]}
<line
x1={tick.x}
x2={tick.x}
y1={height - pad.bottom}
y2={height - pad.bottom + 5}
stroke="var(--border)"
/>
<text
x={tick.x}
y={height - pad.bottom + 18}
fill="var(--muted-foreground)"
font-size="9"
text-anchor="middle"
direction="rtl">{persianDate(tick.localDate)}</text
>
{/each}
<text
x={(pad.left + width - pad.right) / 2}
y={height - 5}
fill="var(--muted-foreground)"
font-size="10"
text-anchor="middle"
direction="rtl">تاریخ</text
>
<text
x={-((pad.top + height - pad.bottom) / 2)}
y="13"
fill="var(--muted-foreground)"
font-size="10"
text-anchor="middle"
transform="rotate(-90)"
direction="rtl">تعداد پرداخت موفق</text
>
<path
d={`${path} L ${positions.at(-1)?.x} ${height - pad.y} L ${positions[0]?.x} ${height - pad.y} Z`}
d={`${path} L ${positions.at(-1)?.x} ${height - pad.bottom} L ${positions[0]?.x} ${height - pad.bottom} Z`}
fill="url(#payment-area)"
/>
<path