fix: preserve chart width on mobile
This commit is contained in:
@@ -71,131 +71,140 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<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">
|
||||
دادهای برای این بازه ثبت نشده است.
|
||||
</div>
|
||||
{:else}
|
||||
<svg
|
||||
viewBox={`0 0 ${width} ${height}`}
|
||||
class="h-auto min-h-[280px] w-full overflow-visible"
|
||||
role="img"
|
||||
aria-label="روند پرداختهای موفق"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="payment-area" x1="0" x2="0" y1="0" y2="1">
|
||||
<stop offset="0" stop-color="var(--primary)" stop-opacity=".22" />
|
||||
<stop offset="1" stop-color="var(--primary)" stop-opacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
{#each [0, 1, 2, 3, 4] as row}
|
||||
{@const y = pad.top + (row * (height - pad.top - pad.bottom)) / 4}
|
||||
<!-- svelte-ignore a11y_no_noninteractive_tabindex (the horizontally scrollable chart must be keyboard reachable) -->
|
||||
<div
|
||||
class="w-full overflow-x-auto overscroll-x-contain"
|
||||
dir="ltr"
|
||||
role="region"
|
||||
aria-label="نمودار روند پرداختهای موفق، قابل پیمایش افقی"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="relative min-h-[290px] min-w-[760px] md:min-w-0">
|
||||
{#if data.length === 0}
|
||||
<div class="text-muted-foreground grid h-[260px] place-items-center text-sm">
|
||||
دادهای برای این بازه ثبت نشده است.
|
||||
</div>
|
||||
{:else}
|
||||
<svg
|
||||
viewBox={`0 0 ${width} ${height}`}
|
||||
class="h-auto min-h-[280px] w-full overflow-visible"
|
||||
role="img"
|
||||
aria-label="روند پرداختهای موفق"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="payment-area" x1="0" x2="0" y1="0" y2="1">
|
||||
<stop offset="0" stop-color="var(--primary)" stop-opacity=".22" />
|
||||
<stop offset="1" stop-color="var(--primary)" stop-opacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
{#each [0, 1, 2, 3, 4] as row}
|
||||
{@const y = pad.top + (row * (height - pad.top - pad.bottom)) / 4}
|
||||
<line
|
||||
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={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}
|
||||
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">{axisLabel(tick)}</text
|
||||
>
|
||||
{/each}
|
||||
<text
|
||||
x={tick.x}
|
||||
y={height - pad.bottom + 18}
|
||||
x={(pad.left + width - pad.right) / 2}
|
||||
y={height - 5}
|
||||
fill="var(--muted-foreground)"
|
||||
font-size="9"
|
||||
font-size="10"
|
||||
text-anchor="middle"
|
||||
direction="rtl">{axisLabel(tick)}</text
|
||||
direction="rtl">{periodType === 'DAY' ? 'ساعت' : 'تاریخ'}</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">{periodType === 'DAY' ? 'ساعت' : 'تاریخ'}</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.bottom} L ${positions[0]?.x} ${height - pad.bottom} Z`}
|
||||
fill="url(#payment-area)"
|
||||
/>
|
||||
<path
|
||||
d={path}
|
||||
fill="none"
|
||||
stroke="var(--primary)"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="chart-line"
|
||||
/>
|
||||
{#each positions as point, index}
|
||||
<circle
|
||||
cx={point.x}
|
||||
cy={point.y}
|
||||
r={active === index ? 6 : 3.5}
|
||||
fill="var(--card)"
|
||||
<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.bottom} L ${positions[0]?.x} ${height - pad.bottom} Z`}
|
||||
fill="url(#payment-area)"
|
||||
/>
|
||||
<path
|
||||
d={path}
|
||||
fill="none"
|
||||
stroke="var(--primary)"
|
||||
stroke-width="3"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
aria-label={`${fullPointLabel(point)}، ${formatValue(point.bankPaidSessions)} پرداخت موفق`}
|
||||
onmouseenter={() => (active = index)}
|
||||
onmouseleave={() => (active = null)}
|
||||
onfocus={() => (active = index)}
|
||||
onblur={() => (active = null)}
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="chart-line"
|
||||
/>
|
||||
{/each}
|
||||
</svg>
|
||||
{#if active !== null && positions[active]}
|
||||
<div
|
||||
class="pointer-events-none absolute z-10 w-44 transition-[left,top,transform] duration-150 ease-out motion-reduce:transition-none"
|
||||
style={tooltipPosition(positions[active])}
|
||||
dir="rtl"
|
||||
>
|
||||
{#each positions as point, index}
|
||||
<circle
|
||||
cx={point.x}
|
||||
cy={point.y}
|
||||
r={active === index ? 6 : 3.5}
|
||||
fill="var(--card)"
|
||||
stroke="var(--primary)"
|
||||
stroke-width="3"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
aria-label={`${fullPointLabel(point)}، ${formatValue(point.bankPaidSessions)} پرداخت موفق`}
|
||||
onmouseenter={() => (active = index)}
|
||||
onmouseleave={() => (active = null)}
|
||||
onfocus={() => (active = index)}
|
||||
onblur={() => (active = null)}
|
||||
/>
|
||||
{/each}
|
||||
</svg>
|
||||
{#if active !== null && positions[active]}
|
||||
<div
|
||||
class="rounded-md bg-zinc-950 p-3 text-right text-xs leading-6 text-white shadow-xl"
|
||||
transition:scale={{ duration: 150, start: 0.96 }}
|
||||
class="pointer-events-none absolute z-10 w-44 transition-[left,top,transform] duration-150 ease-out motion-reduce:transition-none"
|
||||
style={tooltipPosition(positions[active])}
|
||||
dir="rtl"
|
||||
>
|
||||
<strong class="block">{fullPointLabel(positions[active])}</strong>
|
||||
<span class="block text-white/75"
|
||||
>{formatValue(positions[active].bankPaidSessions)} پرداخت موفق</span
|
||||
<div
|
||||
class="rounded-md bg-zinc-950 p-3 text-right text-xs leading-6 text-white shadow-xl"
|
||||
transition:scale={{ duration: 150, start: 0.96 }}
|
||||
>
|
||||
<span class="block text-white/75">{formatMoney(positions[active].bankPaidAmountRial)}</span>
|
||||
<strong class="block">{fullPointLabel(positions[active])}</strong>
|
||||
<span class="block text-white/75"
|
||||
>{formatValue(positions[active].bankPaidSessions)} پرداخت موفق</span
|
||||
>
|
||||
<span class="block text-white/75">{formatMoney(positions[active].bankPaidAmountRial)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -28,5 +28,9 @@ describe('PaymentHistoryChart', () => {
|
||||
expect(screen.getByText('۰۰:۰۰')).not.toBeNull();
|
||||
expect(screen.getByText('۱۲:۰۰')).not.toBeNull();
|
||||
expect(screen.getByText('ساعت')).not.toBeNull();
|
||||
|
||||
const scrollRegion = screen.getByRole('region', { name: /قابل پیمایش افقی/ });
|
||||
expect(scrollRegion.className).toContain('overflow-x-auto');
|
||||
expect(scrollRegion.firstElementChild?.className).toContain('min-w-[760px]');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user