feat(ComparisonSlider): rewrite slider labels to include selects for compared fonts
This commit is contained in:
@@ -1,37 +1,110 @@
|
|||||||
<script lang="ts">
|
<!--
|
||||||
import type { Snippet } from 'svelte';
|
Component: Labels
|
||||||
|
Displays labels for font selection in the comparison slider.
|
||||||
|
-->
|
||||||
|
<script lang="ts" generics="T extends { name: string; id: string }">
|
||||||
|
import {
|
||||||
|
FontVirtualList,
|
||||||
|
type UnifiedFont,
|
||||||
|
} from '$entities/Font';
|
||||||
|
import FontApplicator from '$entities/Font/ui/FontApplicator/FontApplicator.svelte';
|
||||||
|
import { displayedFontsStore } from '$features/DisplayFont';
|
||||||
|
import { buttonVariants } from '$shared/shadcn/ui/button';
|
||||||
|
import {
|
||||||
|
Content as SelectContent,
|
||||||
|
Item as SelectItem,
|
||||||
|
Root as SelectRoot,
|
||||||
|
Trigger as SelectTrigger,
|
||||||
|
} from '$shared/shadcn/ui/select';
|
||||||
|
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
||||||
|
|
||||||
interface Props {
|
interface Props<T> {
|
||||||
fontA: { name: string; id: string };
|
/**
|
||||||
fontB: { name: string; id: string };
|
* First font to compare
|
||||||
|
*/
|
||||||
|
fontA: T;
|
||||||
|
/**
|
||||||
|
* Second font to compare
|
||||||
|
*/
|
||||||
|
fontB: T;
|
||||||
|
/**
|
||||||
|
* Position of the slider
|
||||||
|
*/
|
||||||
sliderPos: number;
|
sliderPos: number;
|
||||||
}
|
}
|
||||||
let { fontA, fontB, sliderPos }: Props = $props();
|
let { fontA, fontB, sliderPos }: Props<T> = $props();
|
||||||
|
|
||||||
|
const fontList = $derived(
|
||||||
|
displayedFontsStore.fonts.filter(font => font.name !== fontA.name && font.name !== fontB.name),
|
||||||
|
);
|
||||||
|
|
||||||
|
function selectFontA(fontId: string) {
|
||||||
|
const newFontA = displayedFontsStore.getById(fontId);
|
||||||
|
if (!newFontA) return;
|
||||||
|
displayedFontsStore.fontA = newFontA;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectFontB(fontId: string) {
|
||||||
|
const newFontB = displayedFontsStore.getById(fontId);
|
||||||
|
if (!newFontB) return;
|
||||||
|
displayedFontsStore.fontB = newFontB;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Bottom Labels -->
|
{#snippet fontSelector(
|
||||||
<div class="absolute bottom-6 inset-x-8 sm:inset-x-12 flex justify-between items-center pointer-events-none z-20">
|
name: string,
|
||||||
<!-- Left Label (Font A) -->
|
id: string,
|
||||||
|
fonts: UnifiedFont[],
|
||||||
|
handleChange: (value: string) => void,
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
class="flex flex-col gap-1 transition-opacity duration-300"
|
class="z-50 pointer-events-auto **:bg-transparent"
|
||||||
style:opacity={sliderPos < 10 ? 0 : 1}
|
onpointerdown={(e => e.stopPropagation())}
|
||||||
>
|
>
|
||||||
<span class="text-[0.5rem] font-mono uppercase tracking-widest text-indigo-400"
|
<SelectRoot type="single" onValueChange={handleChange}>
|
||||||
>Baseline</span>
|
<SelectTrigger
|
||||||
<span class="text-xs sm:text-sm font-bold text-indigo-600">
|
class={cn(buttonVariants({ variant: 'ghost' }), 'border-none, hover:bg-indigo-100')}
|
||||||
{fontB.name}
|
disabled={!fontList.length}
|
||||||
</span>
|
>
|
||||||
|
<FontApplicator name={name} id={id}>
|
||||||
|
{name}
|
||||||
|
</FontApplicator>
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent
|
||||||
|
class="h-60 bg-transparent **:bg-transparent backdrop-blur-0 data-[state=open]:backdrop-blur-lg transition-[backdrop-filter] duration-200"
|
||||||
|
scrollYThreshold={100}
|
||||||
|
side="top"
|
||||||
|
>
|
||||||
|
<FontVirtualList items={fonts}>
|
||||||
|
{#snippet children({ item: font })}
|
||||||
|
<SelectItem value={font.id} class="data-[highlighted]:bg-indigo-100">
|
||||||
|
<FontApplicator name={font.name} id={font.id}>
|
||||||
|
{font.name}
|
||||||
|
</FontApplicator>
|
||||||
|
</SelectItem>
|
||||||
|
{/snippet}
|
||||||
|
</FontVirtualList>
|
||||||
|
</SelectContent>
|
||||||
|
</SelectRoot>
|
||||||
|
</div>
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
<div class="absolute bottom-6 inset-x-6 sm:inset-x-6 flex justify-between items-end pointer-events-none z-20">
|
||||||
|
<div
|
||||||
|
class="flex flex-col gap-0.5 transition-opacity duration-300 items-start"
|
||||||
|
style:opacity={sliderPos < 15 ? 0 : 1}
|
||||||
|
>
|
||||||
|
<span class="text-[0.5rem] font-mono uppercase tracking-widest text-indigo-400">
|
||||||
|
Baseline</span>
|
||||||
|
{@render fontSelector(fontB.name, fontB.id, fontList, selectFontB)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right Label (Font B) -->
|
|
||||||
<div
|
<div
|
||||||
class="flex flex-col items-end text-right gap-1 transition-opacity duration-300"
|
class="flex flex-col items-end text-right gap-1 transition-opacity duration-300"
|
||||||
style:opacity={sliderPos > 90 ? 0 : 1}
|
style:opacity={sliderPos > 85 ? 0 : 1}
|
||||||
>
|
>
|
||||||
<span class="text-[0.5rem] font-mono uppercase tracking-widest text-slate-400"
|
<span class="text-[0.5rem] font-mono uppercase tracking-widest text-slate-400">
|
||||||
>Comparison</span>
|
Comparison</span>
|
||||||
<span class="text-xs sm:text-sm font-bold text-slate-900">
|
{@render fontSelector(fontA.name, fontA.id, fontList, selectFontA)}
|
||||||
{fontA.name}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user