Files
frontend-svelte/src/features/DisplayFont/ui/FontSampler/FontSampler.svelte

171 lines
5.8 KiB
Svelte
Raw Normal View History

<!--
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/SetupFont/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
bg-paper dark:bg-dark-card
border border-subtle
hover:border-brand dark:hover:border-brand
hover:shadow-brand/10
hover:shadow-[5px_5px_0px_0px]
transition-all duration-200
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-[0.625rem] 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" class="text-nowrap font-mono">
{fontType}
</Badge>
{/if}
<!-- Provider badge -->
{#if providerBadge}
<Badge size="xs" variant="default" class="text-nowrap font-mono" 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-[0.4375rem] sm:text-[0.5rem] 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>