2026-01-18 15:55:07 +03:00
|
|
|
<!--
|
|
|
|
|
Component: SuggestedFonts
|
|
|
|
|
Renders a list of suggested fonts in a virtualized list to improve performance.
|
2026-01-30 19:21:47 +03:00
|
|
|
Includes pagination with auto-loading when scrolling near the bottom.
|
2026-01-18 15:55:07 +03:00
|
|
|
-->
|
2026-01-18 14:56:25 +03:00
|
|
|
<script lang="ts">
|
|
|
|
|
import {
|
|
|
|
|
FontListItem,
|
|
|
|
|
FontVirtualList,
|
2026-01-29 14:43:07 +03:00
|
|
|
unifiedFontStore,
|
2026-01-18 14:56:25 +03:00
|
|
|
} from '$entities/Font';
|
2026-01-30 19:21:47 +03:00
|
|
|
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Load more fonts by moving to the next page
|
|
|
|
|
*/
|
|
|
|
|
function loadMore() {
|
|
|
|
|
if (!unifiedFontStore.pagination.hasMore || unifiedFontStore.isFetching) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
unifiedFontStore.nextPage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle scroll near bottom - auto-load next page
|
|
|
|
|
*
|
|
|
|
|
* Triggered when the user scrolls within 5 items of the end of the list.
|
|
|
|
|
* Only fetches if there are more pages available and not already fetching.
|
|
|
|
|
*/
|
|
|
|
|
function handleNearBottom(lastVisibleIndex: number) {
|
|
|
|
|
const { hasMore, total } = unifiedFontStore.pagination;
|
|
|
|
|
const itemsRemaining = total - lastVisibleIndex;
|
|
|
|
|
|
|
|
|
|
// Only trigger if within 5 items of the end, more data exists, and not already fetching
|
|
|
|
|
if (itemsRemaining <= 5 && hasMore && !unifiedFontStore.isFetching) {
|
|
|
|
|
loadMore();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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`;
|
|
|
|
|
});
|
2026-01-18 14:56:25 +03:00
|
|
|
</script>
|
|
|
|
|
|
2026-01-30 19:21:47 +03:00
|
|
|
{#if unifiedFontStore.pagination.total > 0 && !unifiedFontStore.isLoading}
|
|
|
|
|
<div class="text-sm text-muted-foreground px-2 py-2">
|
|
|
|
|
{displayRange}
|
|
|
|
|
{#if unifiedFontStore.isFetching}
|
|
|
|
|
<span class="ml-2 text-xs text-muted-foreground/70">(Loading...)</span>
|
|
|
|
|
{/if}
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
<FontVirtualList
|
|
|
|
|
items={unifiedFontStore.fonts}
|
|
|
|
|
total={unifiedFontStore.pagination.total}
|
|
|
|
|
onNearBottom={handleNearBottom}
|
|
|
|
|
>
|
2026-01-22 15:40:17 +03:00
|
|
|
{#snippet children({ item: font, isVisible, proximity })}
|
|
|
|
|
<FontListItem {font} {isVisible} {proximity} />
|
2026-01-18 14:56:25 +03:00
|
|
|
{/snippet}
|
|
|
|
|
</FontVirtualList>
|