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