Files
frontend-svelte/src/features/DisplayFont/ui/FontSampler/FontSampler.svelte
T
Ilia Mashkov 5b7ec03973 refactor: sweep call sites onto design-system utilities + bug fixes
Replace inline class clusters with the design-system utilities and
tokens established in the prior two commits. No behavior changes
intended beyond two real bug fixes.

Bug fixes:
- SampleList.svelte: 'border-border-subtle bg-background-40' was a
  silent no-op (both classes mis-spelled). Now 'border-subtle
  bg-background/40' applies as intended.
- FontList.svelte: 'h-[44px]' → 'h-11' (44px = 2.75rem = spacing-11,
  no need for arbitrary value).

Sweeps:
- TypographyMenu: popover + floating bar now use surface-popover /
  surface-floating + shadow-popover.
- FontList + FilterGroup: tertiary list buttons use the new
  Button layout="block-list-row" variant; skeleton fills use
  the skeleton-fill utility.
- Footer / BreadcrumbHeader: surface-floating absorbs the
  bg-surface/blur/border cluster. Footer bumped to z-20 with a
  comment explaining the stacking against SidebarContainer (z-40/50).
- FontSampler: surface-card + hover shadow-stamp-card token.
- SliderArea: surface-canvas, flex-center, shadow-floating-panel
  tokens (light + dark variants).
- Sidebar / Header / ButtonGroup / Layout / SidebarContainer:
  bg-surface dark:bg-dark-bg → surface-canvas (8 sites);
  SidebarContainer mobile panel uses shadow-overlay.
- Loader / Thumb: flex items-center justify-center → flex-center;
  Thumb durations → duration-fast.
- ComboControl: trigger uses surface-card-elevated when open,
  popover uses surface-card-elevated, label cluster → text-label-mono,
  flex-center for the trigger interior.
- Slider: shadow-sm → shadow-rest, duration-150 → duration-fast.
- text-secondary → text-subtle across Input, Slider, ComboControl
  (matches the rename in the styles commit).
- Link: reverted earlier surface-floating attempt — Link's original
  bg-surface/80 backdrop-blur pattern was thinner than surface-floating
  (no border, smaller blur), and the Footer was overlaying its own
  border-subtle on top, fighting the utility. Kept the original style.
2026-05-25 10:20:40 +03:00

169 lines
5.6 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
Component: FontSampler
Displays a sample text with a given font in a contenteditable element.
Visual design matches FontCard: sharp corners, red hover accent, header stats.
-->
<script lang="ts">
import {
FontApplicator,
type UnifiedFont,
} from '$entities/Font';
import { typographySettingsStore } from '$features/AdjustTypography/model';
import {
Badge,
ContentEditable,
Divider,
Footnote,
Stat,
} from '$shared/ui';
import { fly } from 'svelte/transition';
interface Props {
/**
* Font info
*/
font: UnifiedFont;
/**
* Sample text
*/
text: string;
/**
* Position index
* @default 0
*/
index?: number;
}
let { font, text = $bindable(), index = 0 }: Props = $props();
// Adjust the property name to match your UnifiedFont type
const fontType = $derived((font as any).type ?? (font as any).category ?? '');
// Extract provider badge with fallback
const providerBadge = $derived(
font.providerBadge
?? (font.provider === 'google' ? 'Google Fonts' : 'Fontshare'),
);
const stats = $derived([
{ label: 'SZ', value: `${typographySettingsStore.renderedSize}PX` },
{ label: 'WGT', value: `${typographySettingsStore.weight}` },
{ label: 'LH', value: typographySettingsStore.height?.toFixed(2) },
{ label: 'LTR', value: `${typographySettingsStore.spacing}` },
]);
</script>
<div
in:fly={{ y: 20, duration: 400, delay: index * 50 }}
class="
group relative
w-full h-full
surface-card
hover:border-brand dark:hover:border-brand
hover:shadow-stamp-card
transition-all duration-normal
overflow-hidden
flex flex-col
min-h-60
rounded-none
"
style:font-weight={typographySettingsStore.weight}
>
<!-- ── Header bar ─────────────────────────────────────────────────── -->
<div
class="
flex items-center justify-between
px-4 sm:px-5 md:px-6 py-3 sm:py-4
border-b border-subtle
bg-paper dark:bg-dark-card
"
>
<!-- Left: index · name · type badge · provider badge -->
<div class="flex items-center gap-2 sm:gap-4 min-w-0 shrink-0">
<span class="font-mono text-2xs tracking-widest text-neutral-400 uppercase leading-none shrink-0">
{String(index + 1).padStart(2, '0')}
</span>
<Divider orientation="vertical" class="h-3 shrink-0" />
<span
class="font-primary font-bold text-sm text-swiss-black dark:text-neutral-200 leading-none tracking-tight uppercase truncate"
>
{font.name}
</span>
{#if fontType}
<Badge size="xs" variant="default" nowrap>
{fontType}
</Badge>
{/if}
<!-- Provider badge -->
{#if providerBadge}
<Badge size="xs" variant="default" nowrap data-provider={font.provider}>
{providerBadge}
</Badge>
{/if}
</div>
<!-- Right: stats, hidden on mobile, fade in on group hover -->
<div
class="
flex-1 min-w-0
hidden md:block @container
opacity-50 group-hover:opacity-100
transition-opacity duration-200 ml-4
"
>
<!-- Switches: narrow → 2×2, wide enough → 1 row -->
<div
class="
max-w-64 ml-auto
grid grid-cols-2 gap-x-3 gap-y-2
@[160px]:grid-cols-4 @[160px]:gap-y-0
items-center
"
>
{#each stats as stat}
<Stat label={stat.label} value={stat.value} />
{/each}
</div>
</div>
</div>
<!-- ── Main content area ──────────────────────────────────────────── -->
<div class="flex-1 p-4 sm:p-5 md:p-8 flex items-center overflow-hidden bg-paper dark:bg-dark-card relative z-10">
<FontApplicator {font} weight={typographySettingsStore.weight}>
<ContentEditable
bind:text
fontSize={typographySettingsStore.renderedSize}
lineHeight={typographySettingsStore.height}
letterSpacing={typographySettingsStore.spacing}
/>
</FontApplicator>
</div>
<!-- ── Mobile stats footer (md:hidden — header stats take over above) -->
<div class="md:hidden px-4 sm:px-5 py-1.5 sm:py-2 border-t border-subtle flex gap-2 sm:gap-4 bg-paper dark:bg-dark-card mt-auto">
{#each stats as stat, i}
<Footnote class="text-5xs sm:text-4xs tracking-wider {i === 0 ? 'ml-auto' : ''}">
{stat.label}:{stat.value}
</Footnote>
{#if i < stats.length - 1}
<div class="w-px h-2 sm:h-2.5 self-center bg-black/10 dark:bg-white/10 hidden sm:block"></div>
{/if}
{/each}
</div>
<!-- ── Red hover line ─────────────────────────────────────────────── -->
<div
class="
absolute bottom-0 left-0 right-0
w-full h-0.5 bg-brand
scale-x-0 group-hover:scale-x-100
transition-transform cubic-bezier(0.25, 0.1, 0.25, 1) origin-left duration-400
z-10
"
>
</div>
</div>