diff --git a/src/widgets/ComparisonSlider/model/stores/comparisonStore.svelte.ts b/src/widgets/ComparisonSlider/model/stores/comparisonStore.svelte.ts index f6ae670..787cca9 100644 --- a/src/widgets/ComparisonSlider/model/stores/comparisonStore.svelte.ts +++ b/src/widgets/ComparisonSlider/model/stores/comparisonStore.svelte.ts @@ -3,6 +3,10 @@ import { fetchFontsByIds, unifiedFontStore, } from '$entities/Font'; +import { + DEFAULT_TYPOGRAPHY_CONTROLS_DATA, + createTypographyControlManager, +} from '$features/SetupFont'; import { createPersistentStore } from '$shared/lib'; /** @@ -30,6 +34,7 @@ class ComparisonStore { #fontB = $state(); #sampleText = $state('The quick brown fox jumps over the lazy dog'); #isRestoring = $state(true); + #typography = createTypographyControlManager(DEFAULT_TYPOGRAPHY_CONTROLS_DATA, 'glyphdiff:comparison:typography'); constructor() { this.restoreFromStorage(); @@ -102,6 +107,9 @@ class ComparisonStore { } // --- Getters & Setters --- + get typography() { + return this.#typography; + } get fontA() { return this.#fontA; @@ -149,6 +157,13 @@ class ComparisonStore { this.restoreFromStorage(); } } + + resetAll() { + this.#fontA = undefined; + this.#fontB = undefined; + storage.clear(); + this.#typography.reset(); + } } export const comparisonStore = new ComparisonStore(); diff --git a/src/widgets/ComparisonSlider/ui/ComparisonSlider/ComparisonSlider.svelte b/src/widgets/ComparisonSlider/ui/ComparisonSlider/ComparisonSlider.svelte index c40cd99..e34157d 100644 --- a/src/widgets/ComparisonSlider/ui/ComparisonSlider/ComparisonSlider.svelte +++ b/src/widgets/ComparisonSlider/ui/ComparisonSlider/ComparisonSlider.svelte @@ -14,14 +14,17 @@ import { createCharacterComparison, createTypographyControl, } from '$shared/lib'; -import type { LineData } from '$shared/lib'; +import type { + LineData, + ResponsiveManager, +} from '$shared/lib'; import { Loader } from '$shared/ui'; import { comparisonStore } from '$widgets/ComparisonSlider/model'; +import { getContext } from 'svelte'; 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'; +import Controls from './components/Controls.svelte'; import SliderLine from './components/SliderLine.svelte'; // Pair of fonts to compare @@ -30,31 +33,13 @@ const fontB = $derived(comparisonStore.fontB); const isLoading = $derived(comparisonStore.isLoading || !comparisonStore.isReady); -let container: HTMLElement | undefined = $state(); -let controlsWrapperElement = $state(null); -let measureCanvas: HTMLCanvasElement | undefined = $state(); +let container = $state(); +let typographyControls = $state(null); +let measureCanvas = $state(); let isDragging = $state(false); +const typography = $derived(comparisonStore.typography); -const weightControl = createTypographyControl({ - min: 100, - max: 700, - step: 100, - value: 400, -}); - -const heightControl = createTypographyControl({ - min: 1, - max: 2, - step: 0.05, - value: 1.2, -}); - -const sizeControl = createTypographyControl({ - min: 1, - max: 112, - step: 1, - value: 64, -}); +const responsive = getContext('responsive'); /** * Encapsulated helper for text splitting, measuring, and character proximity calculations. @@ -64,8 +49,8 @@ const charComparison = createCharacterComparison( () => comparisonStore.text, () => fontA, () => fontB, - () => weightControl.value, - () => sizeControl.value, + () => typography.weight, + () => typography.renderedSize, ); let lineElements = $state<(HTMLElement | undefined)[]>([]); @@ -88,8 +73,8 @@ function handleMove(e: PointerEvent) { function startDragging(e: PointerEvent) { if ( - e.target === controlsWrapperElement - || controlsWrapperElement?.contains(e.target as Node) + e.target === typographyControls + || typographyControls?.contains(e.target as Node) ) { e.stopPropagation(); return; @@ -99,6 +84,30 @@ function startDragging(e: PointerEvent) { handleMove(e); } +/** + * Sets the multiplier for slider font size based on the current responsive state + */ +$effect(() => { + if (!responsive) { + return; + } + + switch (true) { + case responsive.isMobile: + typography.multiplier = 0.5; + break; + case responsive.isTablet: + typography.multiplier = 0.75; + break; + case responsive.isDesktop: + typography.multiplier = 1; + break; + default: + typography.multiplier = 1; + break; + } +}); + $effect(() => { if (isDragging) { window.addEventListener('pointermove', handleMove); @@ -115,9 +124,9 @@ $effect(() => { $effect(() => { // React on text and typography settings changes const _text = comparisonStore.text; - const _weight = weightControl.value; - const _size = sizeControl.value; - const _height = heightControl.value; + const _weight = typography.weight; + const _size = typography.renderedSize; + const _height = typography.height; if (container && measureCanvas && fontA && fontB) { // Using rAF to ensure DOM is ready/stabilized @@ -143,8 +152,8 @@ $effect(() => {
{#each line.text.split('') as char, charIndex} {@const { proximity, isPast } = charComparison.getCharState(charIndex, sliderPos, lineElements[index], container)} @@ -158,8 +167,8 @@ $effect(() => { {char} {proximity} {isPast} - weight={weightControl.value} - size={sizeControl.value} + weight={typography.weight} + size={typography.renderedSize} fontAName={fontA.name} fontBName={fontB.name} /> @@ -182,12 +191,12 @@ $effect(() => { class=" group relative w-full py-8 px-4 sm:py-12 sm:px-8 md:py-16 md:px-12 lg:py-20 lg:px-24 overflow-hidden rounded-xl sm:rounded-2xl md:rounded-[2.5rem] - select-none touch-none cursor-ew-resize min-h-[300px] sm:min-h-[400px] md:min-h-[500px] flex flex-col justify-center - backdrop-blur-lg bg-gradient-to-br from-gray-100/70 via-white/50 to-gray-100/60 + select-none touch-none cursor-ew-resize min-h-72 sm:min-h-96 flex flex-col justify-center + backdrop-blur-lg bg-linear-to-br from-gray-100/70 via-white/50 to-gray-100/60 border border-gray-300/40 shadow-[inset_0_4px_12px_0_rgba(0,0,0,0.12),inset_0_2px_4px_0_rgba(0,0,0,0.08),0_1px_2px_0_rgba(255,255,255,0.8)] - before:absolute before:inset-0 before:rounded-xl sm:before:rounded-2xl md:before:rounded-[2.5rem] before:p-[1px] - before:bg-gradient-to-br before:from-black/5 before:via-black/2 before:to-transparent + before:absolute before:inset-0 before:rounded-xl sm:before:rounded-2xl md:before:rounded-[2.5rem] before:p-px + before:bg-linear-to-br before:from-black/5 before:via-black/2 before:to-transparent before:-z-10 before:blur-sm " > @@ -209,7 +218,7 @@ $effect(() => { {#each charComparison.lines as line, lineIndex}
{ {/if}
- - {#if fontA && fontB && !isLoading} - - - - {/if} + +
diff --git a/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/Controls.svelte b/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/Controls.svelte new file mode 100644 index 0000000..46ced84 --- /dev/null +++ b/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/Controls.svelte @@ -0,0 +1,70 @@ + + +{#if responsive.isMobile} + + {#snippet trigger({ isOpen, onClick })} + + {#snippet icon({ className })} + + {/snippet} + + {/snippet} + + {#snippet content({ isOpen })} +
+ +
+ + {/snippet} +
+{:else} + {#if !isLoading} +
+ +
+ {/if} + + {#if !isLoading} +
+ +
+ {/if} +{/if} diff --git a/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/ControlsWrapper.svelte b/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/ControlsWrapper.svelte deleted file mode 100644 index f446df3..0000000 --- a/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/ControlsWrapper.svelte +++ /dev/null @@ -1,177 +0,0 @@ - - - -
- - {#snippet badge()} -
- -
- {/snippet} - - {#snippet visibleContent()} -
- -
- {/snippet} - - {#snippet hiddenContent()} -
- - - -
- {/snippet} -
-
diff --git a/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/Labels.svelte b/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/SelectComparedFonts.svelte similarity index 66% rename from src/widgets/ComparisonSlider/ui/ComparisonSlider/components/Labels.svelte rename to src/widgets/ComparisonSlider/ui/ComparisonSlider/components/SelectComparedFonts.svelte index a220822..15ea996 100644 --- a/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/Labels.svelte +++ b/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/SelectComparedFonts.svelte @@ -1,13 +1,14 @@ - {#snippet fontSelector( - name: string, - id: string, - url: string, + font: UnifiedFont, fonts: UnifiedFont[], - selectFont: (font: UnifiedFont) => void, + url: string, + onSelect: (f: UnifiedFont) => void, align: 'start' | 'end', )}
- - {name} + + {font.name}
- - {#snippet children({ item: font })} - {@const handleClick = () => selectFont(font)} + + {#snippet children({ item: fontListItem })} + {@const handleClick = () => onSelect(fontListItem)} - - {font.name} + + {fontListItem.name} {/snippet} @@ -110,7 +110,7 @@ function selectFontB(font: UnifiedFont) {
{/snippet} -
+
- {@render fontSelector( - fontB.name, - fontB.id, - fontB.styles.regular!, - fontList, - selectFontB, - 'start', -)} + {#if fontB && fontBUrl} + {@render fontSelector(fontB, fontList, fontBUrl, selectFontB, 'start')} + {/if}
- {@render fontSelector( - fontA.name, - fontA.id, - fontA.styles.regular!, - fontList, - selectFontA, - 'end', -)} + {#if fontA && fontAUrl} + {@render fontSelector(fontA, fontList, fontAUrl, selectFontA, 'end')} + {/if}
diff --git a/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/TypographyControls.svelte b/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/TypographyControls.svelte new file mode 100644 index 0000000..ec2ef5a --- /dev/null +++ b/src/widgets/ComparisonSlider/ui/ComparisonSlider/components/TypographyControls.svelte @@ -0,0 +1,205 @@ + + + +
+ {#if staticPosition} +
+ + {#if typography.weightControl && typography.sizeControl && typography.heightControl} +
+ + + +
+ {/if} +
+ {:else} + + {#snippet badge()} +
+ +
+ {/snippet} + + {#snippet visibleContent()} +
+ + +
+ {/snippet} + + {#snippet hiddenContent()} + {#if typography.weightControl && typography.sizeControl && typography.heightControl} +
+ + + +
+ {/if} + {/snippet} +
+ {/if} +