feature/comparison-slider #19
@@ -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,6 +149,7 @@ $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
|
||||||
-->
|
-->
|
||||||
|
{#if fontA && fontB}
|
||||||
<CharacterSlot
|
<CharacterSlot
|
||||||
{char}
|
{char}
|
||||||
{proximity}
|
{proximity}
|
||||||
@@ -171,10 +159,12 @@ $effect(() => {
|
|||||||
fontAName={fontA.name}
|
fontAName={fontA.name}
|
||||||
fontBName={fontB.name}
|
fontBName={fontB.name}
|
||||||
/>
|
/>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
|
{#if fontA && fontB}
|
||||||
<!-- Hidden canvas used for text measurement by the helper -->
|
<!-- Hidden canvas used for text measurement by the helper -->
|
||||||
<canvas bind:this={measureCanvas} class="hidden" width="1" height="1"></canvas>
|
<canvas bind:this={measureCanvas} class="hidden" width="1" height="1"></canvas>
|
||||||
|
|
||||||
@@ -192,6 +182,7 @@ $effect(() => {
|
|||||||
select-none touch-none cursor-ew-resize min-h-100 flex flex-col justify-center
|
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;'}
|
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 -->
|
<!-- Background Gradient Accent -->
|
||||||
<div
|
<div
|
||||||
@@ -225,10 +216,10 @@ $effect(() => {
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Visual Components -->
|
|
||||||
<SliderLine {sliderPos} {isDragging} />
|
<SliderLine {sliderPos} {isDragging} />
|
||||||
<Labels {fontA} {fontB} {sliderPos} />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Labels fontA={fontA} fontB={fontB} {sliderPos} />
|
||||||
<!-- Since there're slider controls inside we put them outside the main one -->
|
<!-- Since there're slider controls inside we put them outside the main one -->
|
||||||
<ControlsWrapper
|
<ControlsWrapper
|
||||||
bind:wrapper={controlsWrapperElement}
|
bind:wrapper={controlsWrapperElement}
|
||||||
@@ -241,3 +232,4 @@ $effect(() => {
|
|||||||
heightControl={heightControl}
|
heightControl={heightControl}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
|||||||
Reference in New Issue
Block a user