feat(FontApplicator): remove IntersectionObserver to ease the product, font applying logic is entirely in the VirtualList
This commit is contained in:
@@ -2,11 +2,10 @@
|
|||||||
Component: FontApplicator
|
Component: FontApplicator
|
||||||
Loads fonts from fontshare with link tag
|
Loads fonts from fontshare with link tag
|
||||||
- Loads font only if it's not already applied
|
- Loads font only if it's not already applied
|
||||||
- Uses IntersectionObserver to detect when font is visible
|
- Reacts to font load status to show/hide content
|
||||||
- Adds smooth transition when font appears
|
- Adds smooth transition when font appears
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getFontUrl } from '$entities/Font/lib';
|
|
||||||
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
||||||
import type { Snippet } from 'svelte';
|
import type { Snippet } from 'svelte';
|
||||||
import { prefersReducedMotion } from 'svelte/motion';
|
import { prefersReducedMotion } from 'svelte/motion';
|
||||||
@@ -34,47 +33,27 @@ interface Props {
|
|||||||
children?: Snippet;
|
children?: Snippet;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { font, weight = 400, className, children }: Props = $props();
|
let {
|
||||||
let element: Element;
|
font,
|
||||||
|
weight = 400,
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
}: Props = $props();
|
||||||
|
|
||||||
// Track if the user has actually scrolled this into view
|
const status = $derived(
|
||||||
let hasEnteredViewport = $state(false);
|
appliedFontsManager.getFontStatus(
|
||||||
const status = $derived(appliedFontsManager.getFontStatus(font.id, weight, font.features.isVariable));
|
font.id,
|
||||||
|
|
||||||
$effect(() => {
|
|
||||||
if (status === 'loaded' || status === 'error') {
|
|
||||||
hasEnteredViewport = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const observer = new IntersectionObserver(entries => {
|
|
||||||
if (entries[0].isIntersecting) {
|
|
||||||
hasEnteredViewport = true;
|
|
||||||
const url = getFontUrl(font, weight);
|
|
||||||
// Touch ensures it's in the queue.
|
|
||||||
// It's safe to call this even if VirtualList called it
|
|
||||||
// (Manager dedupes based on key)
|
|
||||||
if (url) {
|
|
||||||
appliedFontsManager.touch([{
|
|
||||||
id: font.id,
|
|
||||||
weight,
|
weight,
|
||||||
name: font.name,
|
font.features.isVariable,
|
||||||
url,
|
),
|
||||||
isVariable: font.features.isVariable,
|
);
|
||||||
}]);
|
|
||||||
}
|
|
||||||
|
|
||||||
observer.unobserve(element);
|
// The "Show" condition: Font is loaded OR it errored out OR it's a noTouch preview (like in search)
|
||||||
}
|
const shouldReveal = $derived.by(() => {
|
||||||
});
|
if (noTouch) return true;
|
||||||
|
return status === 'loaded' || status === 'error';
|
||||||
if (element) observer.observe(element);
|
|
||||||
return () => observer.disconnect();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// The "Show" condition: Element is in view AND (Font is ready OR it errored out)
|
|
||||||
const shouldReveal = $derived(hasEnteredViewport && (status === 'loaded'));
|
|
||||||
|
|
||||||
const transitionClasses = $derived(
|
const transitionClasses = $derived(
|
||||||
prefersReducedMotion.current
|
prefersReducedMotion.current
|
||||||
? 'transition-none' // Disable CSS transitions if motion is reduced
|
? 'transition-none' // Disable CSS transitions if motion is reduced
|
||||||
@@ -83,12 +62,14 @@ const transitionClasses = $derived(
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
bind:this={element}
|
style:font-family={shouldReveal
|
||||||
style:font-family={shouldReveal ? `'${font.name}'` : 'system-ui, -apple-system, sans-serif'}
|
? `'${font.name}'`
|
||||||
|
: 'system-ui, -apple-system, sans-serif'}
|
||||||
class={cn(
|
class={cn(
|
||||||
transitionClasses,
|
transitionClasses,
|
||||||
// If reduced motion is on, we skip the transform/blur entirely
|
// If reduced motion is on, we skip the transform/blur entirely
|
||||||
!shouldReveal && !prefersReducedMotion.current
|
!shouldReveal
|
||||||
|
&& !prefersReducedMotion.current
|
||||||
&& 'opacity-50 scale-[0.95] blur-sm',
|
&& 'opacity-50 scale-[0.95] blur-sm',
|
||||||
!shouldReveal && prefersReducedMotion.current && 'opacity-0', // Still hide until font is ready, but no movement
|
!shouldReveal && prefersReducedMotion.current && 'opacity-0', // Still hide until font is ready, but no movement
|
||||||
shouldReveal && 'opacity-100 scale-100 blur-0',
|
shouldReveal && 'opacity-100 scale-100 blur-0',
|
||||||
|
|||||||
Reference in New Issue
Block a user