feat(ComparisonWrapper): remove props and add checks for fonts absence
This commit is contained in:
@@ -9,38 +9,26 @@
|
|||||||
- Responsive layout with Tailwind breakpoints for font sizing.
|
- Responsive layout with Tailwind breakpoints for font sizing.
|
||||||
- Performance optimized using offscreen canvas for measurements and transform-based animations.
|
- Performance optimized using offscreen canvas for measurements and transform-based animations.
|
||||||
-->
|
-->
|
||||||
<script lang="ts" generics="T extends { name: string; id: string }">
|
<script lang="ts">
|
||||||
|
import { displayedFontsStore } from '$features/DisplayFont';
|
||||||
import {
|
import {
|
||||||
createCharacterComparison,
|
createCharacterComparison,
|
||||||
createTypographyControl,
|
createTypographyControl,
|
||||||
} from '$shared/lib';
|
} from '$shared/lib';
|
||||||
import type { LineData } from '$shared/lib';
|
import type { LineData } from '$shared/lib';
|
||||||
|
import { cubicOut } from 'svelte/easing';
|
||||||
import { Spring } from 'svelte/motion';
|
import { Spring } from 'svelte/motion';
|
||||||
|
import { fly } from 'svelte/transition';
|
||||||
import CharacterSlot from './components/CharacterSlot.svelte';
|
import CharacterSlot from './components/CharacterSlot.svelte';
|
||||||
import ControlsWrapper from './components/ControlsWrapper.svelte';
|
import ControlsWrapper from './components/ControlsWrapper.svelte';
|
||||||
import Labels from './components/Labels.svelte';
|
import Labels from './components/Labels.svelte';
|
||||||
import SliderLine from './components/SliderLine.svelte';
|
import SliderLine from './components/SliderLine.svelte';
|
||||||
|
|
||||||
interface Props<T extends { name: string; id: string }> {
|
// Displayed text
|
||||||
/**
|
let text = $state('The quick brown fox jumps over the lazy dog...');
|
||||||
* First font definition ({name, id})
|
// Pair of fonts to compare
|
||||||
*/
|
const fontA = $derived(displayedFontsStore.fontA);
|
||||||
fontA: T;
|
const fontB = $derived(displayedFontsStore.fontB);
|
||||||
/**
|
|
||||||
* Second font definition ({name, id})
|
|
||||||
*/
|
|
||||||
fontB: T;
|
|
||||||
/**
|
|
||||||
* Text to display and compare
|
|
||||||
*/
|
|
||||||
text?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
let {
|
|
||||||
fontA,
|
|
||||||
fontB,
|
|
||||||
text = $bindable('The quick brown fox jumps over the lazy dog'),
|
|
||||||
}: Props<T> = $props();
|
|
||||||
|
|
||||||
let container: HTMLElement | undefined = $state();
|
let container: HTMLElement | undefined = $state();
|
||||||
let controlsWrapperElement = $state<HTMLDivElement | null>(null);
|
let controlsWrapperElement = $state<HTMLDivElement | null>(null);
|
||||||
@@ -98,7 +86,6 @@ function handleMove(e: PointerEvent) {
|
|||||||
|
|
||||||
function startDragging(e: PointerEvent) {
|
function startDragging(e: PointerEvent) {
|
||||||
if (e.target === controlsWrapperElement || controlsWrapperElement?.contains(e.target as Node)) {
|
if (e.target === controlsWrapperElement || controlsWrapperElement?.contains(e.target as Node)) {
|
||||||
console.log('Pointer down on controls wrapper');
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -162,82 +149,87 @@ $effect(() => {
|
|||||||
- Font Family switches based on `isPast`
|
- Font Family switches based on `isPast`
|
||||||
- Transitions/Transforms provide the "morph" feel
|
- Transitions/Transforms provide the "morph" feel
|
||||||
-->
|
-->
|
||||||
<CharacterSlot
|
{#if fontA && fontB}
|
||||||
{char}
|
<CharacterSlot
|
||||||
{proximity}
|
{char}
|
||||||
{isPast}
|
{proximity}
|
||||||
weight={weightControl.value}
|
{isPast}
|
||||||
size={sizeControl.value}
|
weight={weightControl.value}
|
||||||
fontAName={fontA.name}
|
size={sizeControl.value}
|
||||||
fontBName={fontB.name}
|
fontAName={fontA.name}
|
||||||
/>
|
fontBName={fontB.name}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
<!-- Hidden canvas used for text measurement by the helper -->
|
{#if fontA && fontB}
|
||||||
<canvas bind:this={measureCanvas} class="hidden" width="1" height="1"></canvas>
|
<!-- Hidden canvas used for text measurement by the helper -->
|
||||||
|
<canvas bind:this={measureCanvas} class="hidden" width="1" height="1"></canvas>
|
||||||
|
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<div
|
|
||||||
bind:this={container}
|
|
||||||
role="slider"
|
|
||||||
tabindex="0"
|
|
||||||
aria-valuenow={Math.round(sliderPos)}
|
|
||||||
aria-label="Font comparison slider"
|
|
||||||
onpointerdown={startDragging}
|
|
||||||
class="
|
|
||||||
group relative w-full py-16 px-6 sm:py-24 sm:px-12 overflow-hidden
|
|
||||||
bg-indigo-50 rounded-[2.5rem] border border-slate-100 shadow-2xl
|
|
||||||
select-none touch-none cursor-ew-resize min-h-100 flex flex-col justify-center
|
|
||||||
"
|
|
||||||
class:box-shadow={'-20px 20px 60px #bebebe, 20px -20px 60px #ffffff;'}
|
|
||||||
>
|
|
||||||
<!-- Background Gradient Accent -->
|
|
||||||
<div
|
<div
|
||||||
|
bind:this={container}
|
||||||
|
role="slider"
|
||||||
|
tabindex="0"
|
||||||
|
aria-valuenow={Math.round(sliderPos)}
|
||||||
|
aria-label="Font comparison slider"
|
||||||
|
onpointerdown={startDragging}
|
||||||
class="
|
class="
|
||||||
absolute inset-0 bg-linear-to-br
|
group relative w-full py-16 px-6 sm:py-24 sm:px-12 overflow-hidden
|
||||||
from-slate-50/50 via-white to-slate-100/50
|
bg-indigo-50 rounded-[2.5rem] border border-slate-100 shadow-2xl
|
||||||
opacity-50 pointer-events-none
|
select-none touch-none cursor-ew-resize min-h-100 flex flex-col justify-center
|
||||||
"
|
"
|
||||||
|
class:box-shadow={'-20px 20px 60px #bebebe, 20px -20px 60px #ffffff;'}
|
||||||
|
in:fly={{ y: 0, x: -50, duration: 300, easing: cubicOut, opacity: 0.2 }}
|
||||||
>
|
>
|
||||||
|
<!-- Background Gradient Accent -->
|
||||||
|
<div
|
||||||
|
class="
|
||||||
|
absolute inset-0 bg-linear-to-br
|
||||||
|
from-slate-50/50 via-white to-slate-100/50
|
||||||
|
opacity-50 pointer-events-none
|
||||||
|
"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Text Rendering Container -->
|
||||||
|
<div
|
||||||
|
class="
|
||||||
|
relative flex flex-col items-center gap-4
|
||||||
|
text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold leading-[1.15]
|
||||||
|
z-10 pointer-events-none text-center
|
||||||
|
"
|
||||||
|
style:perspective="1000px"
|
||||||
|
>
|
||||||
|
{#each charComparison.lines as line, lineIndex}
|
||||||
|
<div
|
||||||
|
class="relative w-full whitespace-nowrap"
|
||||||
|
style:height={`${heightControl.value}em`}
|
||||||
|
style:display="flex"
|
||||||
|
style:align-items="center"
|
||||||
|
style:justify-content="center"
|
||||||
|
>
|
||||||
|
{@render renderLine(line, lineIndex)}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SliderLine {sliderPos} {isDragging} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Text Rendering Container -->
|
<Labels fontA={fontA} fontB={fontB} {sliderPos} />
|
||||||
<div
|
<!-- Since there're slider controls inside we put them outside the main one -->
|
||||||
class="
|
<ControlsWrapper
|
||||||
relative flex flex-col items-center gap-4
|
bind:wrapper={controlsWrapperElement}
|
||||||
text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold leading-[1.15]
|
{sliderPos}
|
||||||
z-10 pointer-events-none text-center
|
{isDragging}
|
||||||
"
|
bind:text={text}
|
||||||
style:perspective="1000px"
|
containerWidth={container?.clientWidth}
|
||||||
>
|
weightControl={weightControl}
|
||||||
{#each charComparison.lines as line, lineIndex}
|
sizeControl={sizeControl}
|
||||||
<div
|
heightControl={heightControl}
|
||||||
class="relative w-full whitespace-nowrap"
|
/>
|
||||||
style:height={`${heightControl.value}em`}
|
|
||||||
style:display="flex"
|
|
||||||
style:align-items="center"
|
|
||||||
style:justify-content="center"
|
|
||||||
>
|
|
||||||
{@render renderLine(line, lineIndex)}
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Visual Components -->
|
|
||||||
<SliderLine {sliderPos} {isDragging} />
|
|
||||||
<Labels {fontA} {fontB} {sliderPos} />
|
|
||||||
</div>
|
</div>
|
||||||
<!-- Since there're slider controls inside we put them outside the main one -->
|
{/if}
|
||||||
<ControlsWrapper
|
|
||||||
bind:wrapper={controlsWrapperElement}
|
|
||||||
{sliderPos}
|
|
||||||
{isDragging}
|
|
||||||
bind:text={text}
|
|
||||||
containerWidth={container?.clientWidth}
|
|
||||||
weightControl={weightControl}
|
|
||||||
sizeControl={sizeControl}
|
|
||||||
heightControl={heightControl}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user