feat(ComparisonView): add redesigned font comparison widget

This commit is contained in:
Ilia Mashkov
2026-03-02 22:18:05 +03:00
parent 6cd325ce38
commit ba186d00a1
14 changed files with 1884 additions and 0 deletions

View File

@@ -0,0 +1,110 @@
<!--
Component: Sidebar
Layout shell for the font comparison sidebar.
Owns the wrapper, header, and A/B side toggle.
Content (font list, controls) is injected via snippets.
-->
<script lang="ts">
import { cn } from '$shared/shadcn/utils/shadcn-utils';
import {
ButtonGroup,
Label,
ToggleButton,
} from '$shared/ui';
import type { Snippet } from 'svelte';
import {
type Side,
comparisonStore,
} from '../../model';
interface Props {
/**
* Main area snippet
*/
main?: Snippet;
/**
* Controls area snippet
*/
controls?: Snippet;
/**
* CSS classes
*/
class?: string;
}
let {
main,
controls,
class: className,
}: Props = $props();
</script>
<div
class={cn(
'flex flex-col h-full',
'w-80',
'bg-surface dark:bg-dark-bg',
'border-r border-black/5 dark:border-white/10',
'transition-colors duration-500',
className,
)}
>
<!-- ── Header: title + A/B toggle ────────────────────────────────── -->
<div
class="
p-6 shrink-0
border-b border-black/5 dark:border-white/10
bg-surface dark:bg-dark-bg
"
>
<!-- Title -->
<Label variant="default" size="lg" bold class="mb-6 block tracking-tight leading-none">
Configuration
</Label>
<!--
A/B side toggle.
Two ghost buttons (unsized) side by side in a bordered grid.
active prop drives white card state on the selected side.
No size prop → no square sizing, layout comes from class.
-->
<ButtonGroup>
<ToggleButton
active={comparisonStore.side === 'A'}
onclick={() => comparisonStore.side = 'A'}
class="flex-1 tracking-wide font-bold uppercase text-[0.625rem]"
>
<span>Left Font</span>
</ToggleButton>
<ToggleButton
class="flex-1 tracking-wide font-bold uppercase text-[0.625rem]"
active={comparisonStore.side === 'B'}
onclick={() => comparisonStore.side = 'B'}
>
<span class="uppercase">Right Font</span>
</ToggleButton>
</ButtonGroup>
</div>
<!-- ── Main: content area (no scroll - VirtualList handles scrolling) ─────────────────────────────── -->
<div class="flex-1 min-h-0 bg-surface dark:bg-dark-bg">
{#if main}
{@render main()}
{/if}
</div>
<!-- ── Bottom: fixed controls ─────────────────────────────────────── -->
{#if controls}
<div
class="
shrink-0 p-6
bg-surface dark:bg-dark-bg
border-t border-black/5 dark:border-white/10
z-10
"
>
{@render controls()}
</div>
{/if}
</div>