feat: clarify dashboard chart scales
This commit is contained in:
@@ -132,6 +132,7 @@ The approved Persian-first baseline remains authoritative where the shipped arti
|
|||||||
|
|
||||||
| Version | Date | Decision |
|
| Version | Date | Decision |
|
||||||
| ------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| 0.9.0 | 2026-08-20 | Added labeled X/Y axes and Persian ticks to the payment-history chart, and made the fee-share donut fluidly fill its dedicated visual column on larger viewports. |
|
||||||
| 0.8.0 | 2026-08-20 | Increased light-theme skeleton contrast, constrained and animated chart tooltips, made default period choices explicitly applicable, hid collapsed-sidebar labels, and strengthened the separation between period type and exact-period controls. |
|
| 0.8.0 | 2026-08-20 | Increased light-theme skeleton contrast, constrained and animated chart tooltips, made default period choices explicitly applicable, hid collapsed-sidebar labels, and strengthened the separation between period type and exact-period controls. |
|
||||||
| 0.7.0 | 2026-08-20 | Made period changes confirm-on-selection, moved narrow-screen filters into a bottom sheet, enlarged collapsed navigation targets, simplified focus rings, and promoted the fee-share chart into a dedicated visual column. |
|
| 0.7.0 | 2026-08-20 | Made period changes confirm-on-selection, moved narrow-screen filters into a bottom sheet, enlarged collapsed navigation targets, simplified focus rings, and promoted the fee-share chart into a dedicated visual column. |
|
||||||
| 0.6.0 | 2026-08-20 | Added full-span Jalali period selection, unified transaction status/amount controls, persistent skeleton states, custom RTL dropdowns, semantic peer/retry tones, and fee-share visualization; tightened the narrow navbar and 600px KPI breakpoint. |
|
| 0.6.0 | 2026-08-20 | Added full-span Jalali period selection, unified transaction status/amount controls, persistent skeleton states, custom RTL dropdowns, semantic peer/retry tones, and fee-share visualization; tightened the narrow navbar and 600px KPI breakpoint. |
|
||||||
@@ -289,7 +290,7 @@ Scope changes immediately replace data-dependent cards, tables, detail panels, a
|
|||||||
|
|
||||||
### Payment-History Chart
|
### Payment-History Chart
|
||||||
|
|
||||||
The signature chart is a blue line with outlined points, a low-opacity blue area, and dashed neutral gridlines. It follows a written title and reporting-period chip, provides focusable points with spoken values, and animates its initial trace once over 900ms while reduced-motion collapses the effect. Point tooltips use a short scale/fade transition, flip above or below according to vertical room, and clamp their center so the surface never leaves the chart wrapper.
|
The signature chart is a blue line with outlined points, a low-opacity blue area, dashed neutral gridlines, labeled X/Y axes, Persian date ticks, and successful-payment count ticks. It follows a written title and reporting-period chip, provides focusable points with spoken values, and animates its initial trace once over 900ms while reduced-motion collapses the effect. Point tooltips use a short scale/fade transition, flip above or below according to vertical room, and clamp their center so the surface never leaves the chart wrapper.
|
||||||
|
|
||||||
### Transaction Table
|
### Transaction Table
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<Card class={cn('rounded-lg shadow-xs', className)}>
|
<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">
|
<CardContent class="flex h-full flex-col items-center justify-center gap-5 p-6 text-center sm:p-8">
|
||||||
<div
|
<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"
|
role="img"
|
||||||
aria-label={`سهم کارمزد ${formatPercent(value)}`}
|
aria-label={`سهم کارمزد ${formatPercent(value)}`}
|
||||||
>
|
>
|
||||||
@@ -32,7 +32,9 @@
|
|||||||
class="transition-[stroke-dasharray] duration-700 motion-reduce:transition-none"
|
class="transition-[stroke-dasharray] duration-700 motion-reduce:transition-none"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</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>
|
||||||
<div class="max-w-sm min-w-0">
|
<div class="max-w-sm min-w-0">
|
||||||
<div class="flex items-center justify-center gap-1.5">
|
<div class="flex items-center justify-center gap-1.5">
|
||||||
@@ -54,3 +56,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.fee-donut-graphic {
|
||||||
|
width: clamp(10rem, 30vw, 20rem);
|
||||||
|
max-width: 100%;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -9,16 +9,27 @@
|
|||||||
let active = $state<number | null>(null);
|
let active = $state<number | null>(null);
|
||||||
|
|
||||||
const width = 760;
|
const width = 760;
|
||||||
const height = 250;
|
const height = 280;
|
||||||
const pad = { x: 34, y: 28 };
|
const pad = { top: 24, right: 24, bottom: 52, left: 68 };
|
||||||
const max = $derived(Math.max(1, ...data.map((point) => point.bankPaidSessions)));
|
const max = $derived(Math.max(1, ...data.map((point) => point.bankPaidSessions)));
|
||||||
const positions = $derived(
|
const positions = $derived(
|
||||||
data.map((point, index) => ({
|
data.map((point, index) => ({
|
||||||
...point,
|
...point,
|
||||||
x: pad.x + (index * (width - pad.x * 2)) / Math.max(1, data.length - 1),
|
x: pad.left + (index * (width - pad.left - pad.right)) / Math.max(1, data.length - 1),
|
||||||
y: height - pad.y - (point.bankPaidSessions / max) * (height - pad.y * 2),
|
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(
|
const path = $derived(
|
||||||
positions.map((point, index) => `${index ? 'L' : 'M'} ${point.x} ${point.y}`).join(' '),
|
positions.map((point, index) => `${index ? 'L' : 'M'} ${point.x} ${point.y}`).join(' '),
|
||||||
);
|
);
|
||||||
@@ -38,7 +49,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</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}
|
{#if data.length === 0}
|
||||||
<div class="text-muted-foreground grid h-[260px] place-items-center text-sm">
|
<div class="text-muted-foreground grid h-[260px] place-items-center text-sm">
|
||||||
دادهای برای این بازه ثبت نشده است.
|
دادهای برای این بازه ثبت نشده است.
|
||||||
@@ -46,7 +57,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<svg
|
<svg
|
||||||
viewBox={`0 0 ${width} ${height}`}
|
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"
|
role="img"
|
||||||
aria-label="روند پرداختهای موفق"
|
aria-label="روند پرداختهای موفق"
|
||||||
>
|
>
|
||||||
@@ -57,17 +68,64 @@
|
|||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
{#each [0, 1, 2, 3, 4] as row}
|
{#each [0, 1, 2, 3, 4] as row}
|
||||||
|
{@const y = pad.top + (row * (height - pad.top - pad.bottom)) / 4}
|
||||||
<line
|
<line
|
||||||
x1={pad.x}
|
x1={pad.left}
|
||||||
x2={width - pad.x}
|
x2={width - pad.right}
|
||||||
y1={pad.y + (row * (height - pad.y * 2)) / 4}
|
y1={y}
|
||||||
y2={pad.y + (row * (height - pad.y * 2)) / 4}
|
y2={y}
|
||||||
stroke="var(--border)"
|
stroke="var(--border)"
|
||||||
stroke-dasharray="4 6"
|
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}
|
{/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
|
<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)"
|
fill="url(#payment-area)"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
|
|||||||
Reference in New Issue
Block a user