Compare commits

..

8 Commits

18 changed files with 60 additions and 40 deletions
+8 -1
View File
@@ -91,7 +91,6 @@
--space-4xl: 4rem; --space-4xl: 4rem;
/* Typography Scale */ /* Typography Scale */
--text-2xs: 0.625rem;
--text-xs: 0.75rem; --text-xs: 0.75rem;
--text-sm: 0.875rem; --text-sm: 0.875rem;
--text-base: 1rem; --text-base: 1rem;
@@ -205,6 +204,14 @@
--font-mono: 'Space Mono', monospace; --font-mono: 'Space Mono', monospace;
--font-primary: 'Space Grotesk', system-ui, -apple-system, 'Segoe UI', Inter, Roboto, Arial, sans-serif; --font-primary: 'Space Grotesk', system-ui, -apple-system, 'Segoe UI', Inter, Roboto, Arial, sans-serif;
--font-secondary: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif; --font-secondary: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;
/* Micro typography scale — extends Tailwind's text-xs (0.75rem) downward */
--font-size-5xs: 0.4375rem;
--font-size-4xs: 0.5rem;
--font-size-3xs: 0.5625rem;
--font-size-2xs: 0.625rem;
/* Monospace label tracking — used in Loader and Footnote */
--tracking-wider-mono: 0.2em;
} }
@layer base { @layer base {
@@ -82,7 +82,7 @@ const stats = $derived([
> >
<!-- Left: index · name · type badge · provider badge --> <!-- Left: index · name · type badge · provider badge -->
<div class="flex items-center gap-2 sm:gap-4 min-w-0 shrink-0"> <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"> <span class="font-mono text-2xs tracking-widest text-neutral-400 uppercase leading-none shrink-0">
{String(index + 1).padStart(2, '0')} {String(index + 1).padStart(2, '0')}
</span> </span>
<Divider orientation="vertical" class="h-3 shrink-0" /> <Divider orientation="vertical" class="h-3 shrink-0" />
@@ -94,14 +94,14 @@ const stats = $derived([
</span> </span>
{#if fontType} {#if fontType}
<Badge size="xs" variant="default" class="text-nowrap font-mono"> <Badge size="xs" variant="default" nowrap>
{fontType} {fontType}
</Badge> </Badge>
{/if} {/if}
<!-- Provider badge --> <!-- Provider badge -->
{#if providerBadge} {#if providerBadge}
<Badge size="xs" variant="default" class="text-nowrap font-mono" data-provider={font.provider}> <Badge size="xs" variant="default" nowrap data-provider={font.provider}>
{providerBadge} {providerBadge}
</Badge> </Badge>
{/if} {/if}
@@ -147,7 +147,7 @@ const stats = $derived([
<!-- ── Mobile stats footer (md:hidden — header stats take over above) --> <!-- ── 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"> <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} {#each stats as stat, i}
<Footnote class="text-[0.4375rem] sm:text-[0.5rem] tracking-wider {i === 0 ? 'ml-auto' : ''}"> <Footnote class="text-5xs sm:text-4xs tracking-wider {i === 0 ? 'ml-auto' : ''}">
{stat.label}:{stat.value} {stat.label}:{stat.value}
</Footnote> </Footnote>
{#if i < stats.length - 1} {#if i < stats.length - 1}
@@ -61,13 +61,10 @@ function handleReset() {
{#each SORT_OPTIONS as option} {#each SORT_OPTIONS as option}
<Button <Button
variant="ghost" variant="ghost"
size={isMobileOrTabletPortrait ? 'sm' : 'md'} size={isMobileOrTabletPortrait ? 'xs' : 'sm'}
active={sortStore.value === option} active={sortStore.value === option}
onclick={() => sortStore.set(option)} onclick={() => sortStore.set(option)}
class={cn( class="tracking-wide px-0"
'font-bold uppercase tracking-wide font-primary, px-0',
isMobileOrTabletPortrait ? 'text-[0.5625rem]' : 'text-[0.625rem]',
)}
> >
{option} {option}
</Button> </Button>
@@ -78,12 +75,9 @@ function handleReset() {
<!-- Reset_Filters --> <!-- Reset_Filters -->
<Button <Button
variant="ghost" variant="ghost"
size={isMobileOrTabletPortrait ? 'sm' : 'md'} size={isMobileOrTabletPortrait ? 'xs' : 'sm'}
onclick={handleReset} onclick={handleReset}
class={cn( class={cn('group font-mono tracking-widest text-neutral-400', isMobileOrTabletPortrait && 'px-0')}
'group text-[0.5625rem] md:text-[0.625rem] font-mono font-bold uppercase tracking-widest text-neutral-400',
isMobileOrTabletPortrait && 'px-0',
)}
iconPosition="left" iconPosition="left"
> >
{#snippet icon()} {#snippet icon()}
@@ -113,7 +113,7 @@ $effect(() => {
<div class="flex items-center gap-1.5"> <div class="flex items-center gap-1.5">
<Settings2Icon size={12} class="text-swiss-red" /> <Settings2Icon size={12} class="text-swiss-red" />
<span <span
class="text-[0.5625rem] font-mono uppercase tracking-widest font-bold text-swiss-black dark:text-neutral-200" class="text-3xs font-mono uppercase tracking-widest font-bold text-swiss-black dark:text-neutral-200"
> >
CONTROLS CONTROLS
</span> </span>
@@ -166,7 +166,7 @@ $effect(() => {
class="text-swiss-red" class="text-swiss-red"
/> />
<span <span
class="text-[0.5625rem] md:text-[0.625rem] font-mono uppercase tracking-widest font-bold hidden sm:inline whitespace-nowrap" class="text-3xs md:text-2xs font-mono uppercase tracking-widest font-bold hidden sm:inline whitespace-nowrap"
> >
GLOBAL_CONTROLS GLOBAL_CONTROLS
</span> </span>
+7
View File
@@ -37,6 +37,11 @@ interface Props extends HTMLAttributes<HTMLSpanElement> {
* @default false * @default false
*/ */
dot?: boolean; dot?: boolean;
/**
* Prevent text wrapping
* @default false
*/
nowrap?: boolean;
/** /**
* Content snippet * Content snippet
*/ */
@@ -51,6 +56,7 @@ let {
variant = 'default', variant = 'default',
size = 'xs', size = 'xs',
dot = false, dot = false,
nowrap = false,
children, children,
class: className, class: className,
...rest ...rest
@@ -63,6 +69,7 @@ let {
'font-mono uppercase tracking-wide', 'font-mono uppercase tracking-wide',
labelSizeConfig[size], labelSizeConfig[size],
badgeVariantConfig[variant], badgeVariantConfig[variant],
nowrap && 'text-nowrap',
className, className,
)} )}
{...rest} {...rest}
+5 -5
View File
@@ -150,11 +150,11 @@ const variantStyles: Record<ButtonVariant, string> = {
}; };
const sizeStyles: Record<ButtonSize, string> = { const sizeStyles: Record<ButtonSize, string> = {
xs: 'h-6 px-2 text-[9px] gap-1', xs: 'h-6 px-2 text-3xs gap-1',
sm: 'h-8 px-3 text-[10px] gap-1.5', sm: 'h-8 px-3 text-2xs gap-1.5',
md: 'h-10 px-4 text-[11px] gap-2', md: 'h-10 px-4 text-xs gap-2',
lg: 'h-12 px-6 text-[12px] gap-2', lg: 'h-12 px-6 text-xs gap-2',
xl: 'h-14 px-8 text-[13px] gap-2.5', xl: 'h-14 px-8 text-sm gap-2.5',
}; };
// Square padding for icon-only mode // Square padding for icon-only mode
@@ -93,7 +93,7 @@ const displayLabel = $derived(label ?? controlLabel ?? '');
step={control.step} step={control.step}
orientation="horizontal" orientation="horizontal"
/> />
<span class="font-mono text-[0.6875rem] text-secondary tabular-nums w-10 text-right shrink-0"> <span class="font-mono text-xs text-secondary tabular-nums w-10 text-right shrink-0">
{formattedValue()} {formattedValue()}
</span> </span>
</div> </div>
@@ -136,7 +136,7 @@ const displayLabel = $derived(label ?? controlLabel ?? '');
{#if displayLabel} {#if displayLabel}
<span <span
class=" class="
text-[0.5625rem] font-primary font-bold tracking-tight uppercase text-3xs font-primary font-bold tracking-tight uppercase
text-neutral-900 dark:text-neutral-100 text-neutral-900 dark:text-neutral-100
mb-0.5 leading-none mb-0.5 leading-none
" "
@@ -25,7 +25,7 @@ const { label, children, class: className }: Props = $props();
</script> </script>
<div class={cn('flex flex-col gap-3 py-6 border-b border-subtle last:border-0', className)}> <div class={cn('flex flex-col gap-3 py-6 border-b border-subtle last:border-0', className)}>
<div class="flex justify-between items-center text-[0.6875rem] font-primary font-bold tracking-tight text-neutral-900 dark:text-neutral-100 uppercase leading-none"> <div class="flex justify-between items-center text-xs font-primary font-bold tracking-tight text-neutral-900 dark:text-neutral-100 uppercase leading-none">
{label} {label}
</div> </div>
{@render children?.()} {@render children?.()}
+2 -2
View File
@@ -27,14 +27,14 @@ const { children, class: className, render }: Props = $props();
{#if render} {#if render}
{@render render({ {@render render({
class: cn( class: cn(
'font-mono text-[0.5625rem] sm:text-[0.625rem] lowercase tracking-[0.2em] text-text-soft', 'font-mono text-3xs sm:text-2xs lowercase tracking-wider-mono text-text-soft',
className, className,
), ),
})} })}
{:else if children} {:else if children}
<span <span
class={cn( class={cn(
'font-mono text-[0.5625rem] sm:text-[0.625rem] lowercase tracking-[0.2em] text-text-soft', 'font-mono text-3xs sm:text-2xs lowercase tracking-wider-mono text-text-soft',
className, className,
)} )}
> >
+1 -1
View File
@@ -148,7 +148,7 @@ const inputClasses = $derived(cn(
{#if helperText} {#if helperText}
<span <span
class={cn( class={cn(
'text-[0.625rem] font-mono tracking-wide px-1', 'text-2xs font-mono tracking-wide px-1',
error ? 'text-brand ' : 'text-secondary', error ? 'text-brand ' : 'text-secondary',
)} )}
> >
+8
View File
@@ -6,6 +6,7 @@
import { cn } from '$shared/shadcn/utils/shadcn-utils'; import { cn } from '$shared/shadcn/utils/shadcn-utils';
import type { Snippet } from 'svelte'; import type { Snippet } from 'svelte';
import { import {
type LabelFont,
type LabelSize, type LabelSize,
type LabelVariant, type LabelVariant,
labelSizeConfig, labelSizeConfig,
@@ -28,6 +29,11 @@ interface Props {
* @default true * @default true
*/ */
uppercase?: boolean; uppercase?: boolean;
/**
* Font family
* @default 'mono'
*/
font?: LabelFont;
/** /**
* Bold text * Bold text
* @default false * @default false
@@ -55,6 +61,7 @@ interface Props {
let { let {
variant = 'default', variant = 'default',
size = 'sm', size = 'sm',
font = 'mono',
uppercase = true, uppercase = true,
bold = false, bold = false,
icon, icon,
@@ -68,6 +75,7 @@ let {
class={cn( class={cn(
'font-mono tracking-widest leading-none', 'font-mono tracking-widest leading-none',
'inline-flex items-center gap-1.5', 'inline-flex items-center gap-1.5',
font === 'primary' && 'font-primary tracking-tight',
labelSizeConfig[size], labelSizeConfig[size],
labelVariantConfig[variant], labelVariantConfig[variant],
uppercase && 'uppercase', uppercase && 'uppercase',
+6 -4
View File
@@ -3,6 +3,8 @@
* Import from here in each component to keep maps DRY. * Import from here in each component to keep maps DRY.
*/ */
export type LabelFont = 'mono' | 'primary';
export type LabelVariant = export type LabelVariant =
| 'default' | 'default'
| 'accent' | 'accent'
@@ -14,10 +16,10 @@ export type LabelVariant =
export type LabelSize = 'xs' | 'sm' | 'md' | 'lg'; export type LabelSize = 'xs' | 'sm' | 'md' | 'lg';
export const labelSizeConfig: Record<LabelSize, string> = { export const labelSizeConfig: Record<LabelSize, string> = {
xs: 'text-[0.5rem]', xs: 'text-4xs',
sm: 'text-[0.5625rem] md:text-[0.625rem]', sm: 'text-3xs md:text-2xs',
md: 'text-[0.625rem] md:text-[0.6875rem]', md: 'text-2xs md:text-xs',
lg: 'text-[0.8rem] md:text-[0.875rem]', lg: 'text-sm',
}; };
export const labelVariantConfig: Record<LabelVariant, string> = { export const labelVariantConfig: Record<LabelVariant, string> = {
+1 -1
View File
@@ -71,7 +71,7 @@ let { size = 20, class: className = '', message = 'analyzing_data' }: Props = $p
<div class="w-px h-3 bg-text-muted/50"></div> <div class="w-px h-3 bg-text-muted/50"></div>
<!-- Message --> <!-- Message -->
<span class="font-mono text-[10px] uppercase tracking-[0.2em] text-text-subtle font-medium"> <span class="font-mono text-2xs uppercase tracking-wider-mono text-text-subtle font-medium">
{message} {message}
</span> </span>
</div> </div>
@@ -53,7 +53,7 @@ const indexStr = $derived(String(index).padStart(2, '0'));
</div> </div>
{#if subtitle} {#if subtitle}
<span class="text-neutral-300 dark:text-neutral-700 text-[0.625rem] hidden md:inline">/</span> <span class="text-neutral-300 dark:text-neutral-700 text-2xs hidden md:inline">/</span>
<Label variant="muted" size="sm">{subtitle}</Label> <Label variant="muted" size="sm">{subtitle}</Label>
{/if} {/if}
</div> </div>
@@ -13,7 +13,7 @@ interface Props {
const { text }: Props = $props(); const { text }: Props = $props();
</script> </script>
{#if text} {#if text}
<h2 class="text-3xl md:text-4xl lg:text-5xl font-['Space_Grotesk'] font-bold text-swiss-black dark:text-neutral-200 tracking-tight"> <h2 class="text-3xl md:text-4xl lg:text-5xl font-primary font-bold text-swiss-black dark:text-neutral-200 tracking-tight">
{text} {text}
</h2> </h2>
{/if} {/if}
+1 -1
View File
@@ -69,7 +69,7 @@ let {
const isVertical = $derived(orientation === 'vertical'); const isVertical = $derived(orientation === 'vertical');
const labelClasses = `font-mono text-[0.625rem] tabular-nums shrink-0 const labelClasses = `font-mono text-2xs tabular-nums shrink-0
text-secondary text-secondary
group-hover:text-neutral-700 dark:group-hover:text-neutral-300 group-hover:text-neutral-700 dark:group-hover:text-neutral-300
transition-colors`; transition-colors`;
@@ -72,7 +72,7 @@ $effect(() => {
<div class="flex-1 min-h-0 h-full"> <div class="flex-1 min-h-0 h-full">
<div class="py-2 relative flex flex-col min-h-0 h-full"> <div class="py-2 relative flex flex-col min-h-0 h-full">
<div class="py-2 mx-6 sticky border-b border-subtle"> <div class="py-2 mx-6 sticky border-b border-subtle">
<Label class="font-primary text-neutral-400" bold variant="default" size="sm" uppercase> <Label font="primary" variant="muted" bold size="sm" uppercase>
Typeface Selection Typeface Selection
</Label> </Label>
</div> </div>
@@ -70,19 +70,21 @@ let {
--> -->
<ButtonGroup> <ButtonGroup>
<ToggleButton <ToggleButton
size="sm"
active={comparisonStore.side === 'A'} active={comparisonStore.side === 'A'}
onclick={() => comparisonStore.side = 'A'} onclick={() => comparisonStore.side = 'A'}
class="flex-1 tracking-wide font-bold uppercase text-[0.625rem]" class="flex-1 tracking-wide font-bold uppercase"
> >
<span>Left Font</span> <span>Left Font</span>
</ToggleButton> </ToggleButton>
<ToggleButton <ToggleButton
class="flex-1 tracking-wide font-bold uppercase text-[0.625rem]" size="sm"
class="flex-1 tracking-wide font-bold uppercase"
active={comparisonStore.side === 'B'} active={comparisonStore.side === 'B'}
onclick={() => comparisonStore.side = 'B'} onclick={() => comparisonStore.side = 'B'}
> >
<span class="uppercase">Right Font</span> <span>Right Font</span>
</ToggleButton> </ToggleButton>
</ButtonGroup> </ButtonGroup>
</div> </div>