2026-02-01 11:55:46 +03:00
|
|
|
<!--
|
|
|
|
|
Component: SampleList
|
|
|
|
|
Renders a list of fonts in a virtualized list to improve performance.
|
2026-02-07 18:39:52 +03:00
|
|
|
- Includes pagination with auto-loading when scrolling near the bottom.
|
|
|
|
|
- Provides a typography menu for font setup.
|
2026-02-01 11:55:46 +03:00
|
|
|
-->
|
|
|
|
|
<script lang="ts">
|
2026-02-27 19:07:53 +03:00
|
|
|
import { FontVirtualList } from '$entities/Font';
|
2026-02-01 11:55:46 +03:00
|
|
|
import { FontSampler } from '$features/DisplayFont';
|
2026-02-07 18:39:52 +03:00
|
|
|
import {
|
|
|
|
|
TypographyMenu,
|
|
|
|
|
controlManager,
|
|
|
|
|
} from '$features/SetupFont';
|
2026-02-12 11:11:22 +03:00
|
|
|
import { throttle } from '$shared/lib/utils';
|
2026-02-16 14:15:47 +03:00
|
|
|
import { Skeleton } from '$shared/ui';
|
2026-02-27 19:07:53 +03:00
|
|
|
import { layoutManager } from '../../model';
|
2026-02-01 11:55:46 +03:00
|
|
|
|
|
|
|
|
let text = $state('The quick brown fox jumps over the lazy dog...');
|
2026-02-07 18:39:52 +03:00
|
|
|
let wrapper = $state<HTMLDivElement | null>(null);
|
|
|
|
|
// Binds to the actual window height
|
|
|
|
|
let innerHeight = $state(0);
|
|
|
|
|
// Is the component above the middle of the viewport?
|
|
|
|
|
let isAboveMiddle = $state(false);
|
|
|
|
|
|
2026-02-12 11:11:22 +03:00
|
|
|
const checkPosition = throttle(() => {
|
2026-02-07 18:39:52 +03:00
|
|
|
if (!wrapper) return;
|
|
|
|
|
|
|
|
|
|
const rect = wrapper.getBoundingClientRect();
|
|
|
|
|
const viewportMiddle = innerHeight / 2;
|
|
|
|
|
|
|
|
|
|
isAboveMiddle = rect.top < viewportMiddle;
|
2026-02-12 11:11:22 +03:00
|
|
|
}, 100);
|
2026-02-06 12:05:29 +03:00
|
|
|
</script>
|
2026-02-01 11:55:46 +03:00
|
|
|
|
2026-02-16 14:15:47 +03:00
|
|
|
{#snippet skeleton()}
|
|
|
|
|
<div class="flex flex-col gap-3 sm:gap-4 p-3 sm:p-4">
|
|
|
|
|
{#each Array(5) as _, i}
|
|
|
|
|
<div class="flex flex-col gap-1.5 sm:gap-2 p-3 sm:p-4 border rounded-lg sm:rounded-xl border-border-subtle bg-background-40">
|
|
|
|
|
<div class="flex items-center justify-between mb-3 sm:mb-4">
|
|
|
|
|
<Skeleton class="h-6 sm:h-8 w-1/3" />
|
|
|
|
|
<Skeleton class="h-6 sm:h-8 w-6 sm:w-8 rounded-full" />
|
|
|
|
|
</div>
|
|
|
|
|
<Skeleton class="h-24 sm:h-32 w-full" />
|
|
|
|
|
</div>
|
|
|
|
|
{/each}
|
|
|
|
|
</div>
|
|
|
|
|
{/snippet}
|
|
|
|
|
|
2026-02-07 18:39:52 +03:00
|
|
|
<svelte:window
|
|
|
|
|
bind:innerHeight
|
|
|
|
|
onscroll={checkPosition}
|
|
|
|
|
onresize={checkPosition}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<div bind:this={wrapper}>
|
|
|
|
|
<FontVirtualList
|
|
|
|
|
itemHeight={220}
|
|
|
|
|
useWindowScroll={true}
|
|
|
|
|
weight={controlManager.weight}
|
2026-02-27 19:07:53 +03:00
|
|
|
columns={layoutManager.columns}
|
|
|
|
|
gap={layoutManager.gap}
|
2026-02-16 14:15:47 +03:00
|
|
|
{skeleton}
|
2026-02-07 18:39:52 +03:00
|
|
|
>
|
2026-02-27 19:07:53 +03:00
|
|
|
{#snippet children({ item: font, index })}
|
|
|
|
|
<FontSampler bind:text {font} {index} />
|
2026-02-07 18:39:52 +03:00
|
|
|
{/snippet}
|
|
|
|
|
</FontVirtualList>
|
|
|
|
|
|
2026-02-09 16:49:56 +03:00
|
|
|
<TypographyMenu
|
2026-02-27 19:07:53 +03:00
|
|
|
class="fixed bottom-4 sm:bottom-5 right-4 sm:left-1/2 sm:right-[unset] sm:-translate-x-1/2 z-50"
|
2026-02-09 16:49:56 +03:00
|
|
|
hidden={!isAboveMiddle}
|
|
|
|
|
/>
|
2026-02-07 18:39:52 +03:00
|
|
|
</div>
|