Lib: Implement (slightly broken) lazy loading of cards
Issues arise when the viewport size changes
This commit is contained in:
@ -43,6 +43,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LazyCard
|
<LazyCard
|
||||||
|
group="DriverCard"
|
||||||
imgsrc={driver?.headshot_url ?? headshot_template}
|
imgsrc={driver?.headshot_url ?? headshot_template}
|
||||||
imgwidth={DRIVER_HEADSHOT_WIDTH}
|
imgwidth={DRIVER_HEADSHOT_WIDTH}
|
||||||
imgheight={DRIVER_HEADSHOT_HEIGHT}
|
imgheight={DRIVER_HEADSHOT_HEIGHT}
|
||||||
|
|||||||
@ -1,3 +1,12 @@
|
|||||||
|
<script lang="ts" module>
|
||||||
|
// The first element of a group of cards (e.g. driver cards or team cards)
|
||||||
|
// will register its height here, once its fully loaded.
|
||||||
|
// This height is then used as the height of following components.
|
||||||
|
// This is necessary, because for lazy loading depending on viewport intersection,
|
||||||
|
// the elements must have their actual height from the beginning.
|
||||||
|
let group_heights: { [key: string]: number } = {};
|
||||||
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Snippet } from "svelte";
|
import type { Snippet } from "svelte";
|
||||||
import LazyImage from "./LazyImage.svelte";
|
import LazyImage from "./LazyImage.svelte";
|
||||||
@ -23,6 +32,9 @@
|
|||||||
|
|
||||||
/** Enable to give the card the "w-full" class. */
|
/** Enable to give the card the "w-full" class. */
|
||||||
fullwidth?: boolean;
|
fullwidth?: boolean;
|
||||||
|
|
||||||
|
/** The group this card belongs to (e.g. "driver" or "race"). All cards that have the same contents (more specifically, height) may be assigned to the same group. */
|
||||||
|
group: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@ -33,6 +45,7 @@
|
|||||||
imgheight,
|
imgheight,
|
||||||
imghidden = false,
|
imghidden = false,
|
||||||
fullwidth = false,
|
fullwidth = false,
|
||||||
|
group,
|
||||||
...restProps
|
...restProps
|
||||||
}: CardProps = $props();
|
}: CardProps = $props();
|
||||||
|
|
||||||
@ -41,11 +54,50 @@
|
|||||||
const lazy_visible_handler = () => {
|
const lazy_visible_handler = () => {
|
||||||
load = true;
|
load = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const set_group_height = (node: HTMLElement) => {
|
||||||
|
if (group_heights[group]) return;
|
||||||
|
|
||||||
|
group_heights[group] = node.getBoundingClientRect().height;
|
||||||
|
// console.log(`Set card group hight: ${group}: ${group_heights[group]}px`);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div use:lazyload onLazyVisible={lazy_visible_handler}>
|
<!-- TODO: This component needs to know its own height, otherwise the intersection observer doesn't work -->
|
||||||
|
<!-- (all elements are visible at once, so no lazy loading...) -->
|
||||||
|
<div use:lazyload onLazyVisible={lazy_visible_handler} style="width: 100%;">
|
||||||
|
{#if group_heights[group]}
|
||||||
|
<!-- A card has already loaded and determined the height for cards of this group -->
|
||||||
|
<div
|
||||||
|
class="card overflow-hidden bg-white shadow {fullwidth ? 'w-full' : 'w-auto'}"
|
||||||
|
style="height: {group_heights[group]}px;"
|
||||||
|
>
|
||||||
|
<!-- Allow empty strings for images that only appear after user action -->
|
||||||
|
{#if imgsrc !== undefined}
|
||||||
|
<LazyImage
|
||||||
|
id={imgid}
|
||||||
|
src={imgsrc}
|
||||||
|
{imgwidth}
|
||||||
|
{imgheight}
|
||||||
|
alt="Card header"
|
||||||
|
draggable="false"
|
||||||
|
class="select-none shadow"
|
||||||
|
hidden={imghidden}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
<!-- Only lazyload children, as the image is already lazy (also the image fade would break) -->
|
||||||
{#if load}
|
{#if load}
|
||||||
<div class="card overflow-hidden bg-white shadow {fullwidth ? 'w-full' : 'w-auto'}">
|
<div class="p-2" {...restProps}>
|
||||||
|
{@render children()}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<!-- This card is the first one to load in the group, so it is not lazy-loaded to determine the height -->
|
||||||
|
<div
|
||||||
|
class="card overflow-hidden bg-white shadow {fullwidth ? 'w-full' : 'w-auto'}"
|
||||||
|
use:set_group_height
|
||||||
|
>
|
||||||
<!-- Allow empty strings for images that only appear after user action -->
|
<!-- Allow empty strings for images that only appear after user action -->
|
||||||
{#if imgsrc !== undefined}
|
{#if imgsrc !== undefined}
|
||||||
<LazyImage
|
<LazyImage
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const img_opacity_handler = (node: HTMLElement) => {
|
const img_opacity_handler = (node: HTMLElement) => {
|
||||||
setTimeout(() => (node.style.opacity = "1"), 10);
|
setTimeout(() => (node.style.opacity = "1"), 20);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -40,7 +40,7 @@
|
|||||||
src={data}
|
src={data}
|
||||||
use:img_opacity_handler
|
use:img_opacity_handler
|
||||||
class="bg-surface-100 transition-opacity"
|
class="bg-surface-100 transition-opacity"
|
||||||
style="width: 100%; opacity: 0; transition-duration: 250ms;"
|
style="width: 100%; opacity: 0; transition-duration: 500ms;"
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
{/await}
|
{/await}
|
||||||
|
|||||||
@ -56,6 +56,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LazyCard
|
<LazyCard
|
||||||
|
group="RaceCard"
|
||||||
imgsrc={race?.pictogram_url ?? pictogram_template}
|
imgsrc={race?.pictogram_url ?? pictogram_template}
|
||||||
imgwidth={RACE_PICTOGRAM_WIDTH}
|
imgwidth={RACE_PICTOGRAM_WIDTH}
|
||||||
imgheight={RACE_PICTOGRAM_HEIGHT}
|
imgheight={RACE_PICTOGRAM_HEIGHT}
|
||||||
|
|||||||
@ -77,6 +77,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LazyCard
|
<LazyCard
|
||||||
|
group="SubstitutionCard"
|
||||||
imgsrc={get_by_value(drivers, "id", substitution?.substitute ?? "")?.headshot_url ??
|
imgsrc={get_by_value(drivers, "id", substitution?.substitute ?? "")?.headshot_url ??
|
||||||
headshot_template}
|
headshot_template}
|
||||||
imgwidth={DRIVER_HEADSHOT_WIDTH}
|
imgwidth={DRIVER_HEADSHOT_WIDTH}
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LazyCard
|
<LazyCard
|
||||||
|
group="TeamCard"
|
||||||
imgsrc={team?.logo_url ?? logo_template}
|
imgsrc={team?.logo_url ?? logo_template}
|
||||||
imgwidth={TEAM_LOGO_WIDTH}
|
imgwidth={TEAM_LOGO_WIDTH}
|
||||||
imgheight={TEAM_LOGO_HEIGHT}
|
imgheight={TEAM_LOGO_HEIGHT}
|
||||||
|
|||||||
Reference in New Issue
Block a user