feat(ComparisonSlider): integrate loader and add animations for appearance/disappearance

This commit is contained in:
Ilia Mashkov
2026-02-06 12:04:32 +03:00
parent 3ed63562b7
commit b304e841de
3 changed files with 43 additions and 27 deletions

View File

@@ -15,8 +15,10 @@ import {
createTypographyControl,
} from '$shared/lib';
import type { LineData } from '$shared/lib';
import { Loader } from '$shared/ui';
import { comparisonStore } from '$widgets/ComparisonSlider/model';
import { Spring } from 'svelte/motion';
import { fade } from 'svelte/transition';
import CharacterSlot from './components/CharacterSlot.svelte';
import ControlsWrapper from './components/ControlsWrapper.svelte';
import Labels from './components/Labels.svelte';
@@ -26,6 +28,8 @@ import SliderLine from './components/SliderLine.svelte';
const fontA = $derived(comparisonStore.fontA);
const fontB = $derived(comparisonStore.fontB);
const isLoading = $derived(comparisonStore.isLoading || !comparisonStore.isReady);
let container: HTMLElement | undefined = $state();
let controlsWrapperElement = $state<HTMLDivElement | null>(null);
let measureCanvas: HTMLCanvasElement | undefined = $state();
@@ -164,11 +168,10 @@ $effect(() => {
</div>
{/snippet}
{#if fontA && fontB}
<!-- Hidden canvas used for text measurement by the helper -->
<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"
@@ -189,6 +192,9 @@ $effect(() => {
"
>
<!-- Text Rendering Container -->
{#if isLoading}
<Loader size={24} />
{:else}
<div
class="
relative flex flex-col items-center gap-4
@@ -197,6 +203,8 @@ $effect(() => {
drop-shadow-[0_3px_6px_rgba(255,255,255,0.9)]
"
style:perspective="1000px"
in:fade={{ duration: 300, delay: 300 }}
out:fade={{ duration: 300 }}
>
{#each charComparison.lines as line, lineIndex}
<div
@@ -212,8 +220,10 @@ $effect(() => {
</div>
<SliderLine {sliderPos} {isDragging} />
{/if}
</div>
{#if fontA && fontB && !isLoading}
<Labels {fontA} {fontB} {sliderPos} weight={weightControl.value} />
<!-- Since there're slider controls inside we put them outside the main one -->
<ControlsWrapper
@@ -226,5 +236,5 @@ $effect(() => {
{sizeControl}
{heightControl}
/>
</div>
{/if}
{/if}
</div>

View File

@@ -12,6 +12,7 @@ import { ComboControlV2 } from '$shared/ui';
import { ExpandableWrapper } from '$shared/ui';
import AArrowUP from '@lucide/svelte/icons/a-arrow-up';
import { Spring } from 'svelte/motion';
import { fade } from 'svelte/transition';
interface Props {
/**
@@ -121,6 +122,8 @@ $effect(() => {
translateX({xSpring.current}px)
rotateZ({rotateSpring.current}deg)
"
in:fade={{ duration: 300, delay: 300 }}
out:fade={{ duration: 300, delay: 300 }}
>
<ExpandableWrapper
bind:element={wrapper}

View File

@@ -17,6 +17,7 @@ import {
} from '$shared/shadcn/ui/select';
import { cn } from '$shared/shadcn/utils/shadcn-utils';
import { comparisonStore } from '$widgets/ComparisonSlider/model';
import { fade } from 'svelte/transition';
interface Props<T> {
/**
@@ -60,6 +61,8 @@ function selectFontB(font: UnifiedFont) {
<div
class="z-50 pointer-events-auto"
onpointerdown={(e => e.stopPropagation())}
in:fade={{ duration: 300, delay: 300 }}
out:fade={{ duration: 300, delay: 300 }}
>
<SelectRoot type="single" disabled={!fontList.length}>
<SelectTrigger