Files
frontend-svelte/src/widgets/SampleList/ui/SampleList/SampleList.svelte

97 lines
2.7 KiB
Svelte
Raw Normal View History

<!--
Component: SampleList
Renders a list of fonts in a virtualized list to improve performance.
- Includes pagination with auto-loading when scrolling near the bottom.
- Provides a typography menu for font setup.
-->
<script lang="ts">
import {
FontListItem,
FontVirtualList,
unifiedFontStore,
} from '$entities/Font';
import { FontSampler } from '$features/DisplayFont';
import {
TypographyMenu,
controlManager,
} from '$features/SetupFont';
import { throttle } from '$shared/lib/utils';
2026-02-16 14:15:47 +03:00
import { Skeleton } from '$shared/ui';
let text = $state('The quick brown fox jumps over the lazy dog...');
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);
/**
* Calculate display range for pagination info
*/
const displayRange = $derived.by(() => {
const { offset, limit, total } = unifiedFontStore.pagination;
const loadedCount = Math.min(offset + limit, total);
return `Showing ${loadedCount} of ${total} fonts`;
});
const checkPosition = throttle(() => {
if (!wrapper) return;
const rect = wrapper.getBoundingClientRect();
const viewportMiddle = innerHeight / 2;
isAboveMiddle = rect.top < viewportMiddle;
}, 100);
</script>
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}
<svelte:window
bind:innerHeight
onscroll={checkPosition}
onresize={checkPosition}
/>
<div bind:this={wrapper}>
<FontVirtualList
itemHeight={220}
useWindowScroll={true}
weight={controlManager.weight}
2026-02-16 14:15:47 +03:00
{skeleton}
>
{#snippet children({
item: font,
isFullyVisible,
isPartiallyVisible,
proximity,
index,
})}
<FontListItem
{font}
{isFullyVisible}
{isPartiallyVisible}
{proximity}
>
<FontSampler {font} bind:text {index} />
</FontListItem>
{/snippet}
</FontVirtualList>
<TypographyMenu
class="fixed bottom-4 sm:bottom-5 right-4 sm:left-1/2 sm:right-[unset] sm:-translate-x-1/2"
hidden={!isAboveMiddle}
/>
</div>