aboutsummaryrefslogtreecommitdiff
path: root/src/lib/User
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/User')
-rw-r--r--src/lib/User/BadgeWall/Badges.svelte28
-rw-r--r--src/lib/User/BadgeWall/badges.css9
2 files changed, 36 insertions, 1 deletions
diff --git a/src/lib/User/BadgeWall/Badges.svelte b/src/lib/User/BadgeWall/Badges.svelte
index d2c56392..a77aebd6 100644
--- a/src/lib/User/BadgeWall/Badges.svelte
+++ b/src/lib/User/BadgeWall/Badges.svelte
@@ -1,4 +1,6 @@
<script lang="ts">
+import { onDestroy } from "svelte";
+import { browser } from "$app/environment";
import FallbackImage from "$lib/Image/FallbackImage.svelte";
import Spacer from "$lib/Layout/Spacer.svelte";
import LinkedTooltip from "$lib/Tooltip/LinkedTooltip.svelte";
@@ -16,6 +18,30 @@ export let categoryFilter: string | null;
export let editMode: boolean;
export let preferences: Preferences | undefined;
export let selectedBadge: IndexedBadge | undefined = undefined;
+
+const skipObserver =
+ browser && typeof IntersectionObserver !== "undefined"
+ ? new IntersectionObserver(
+ (entries) => {
+ for (const entry of entries)
+ entry.target.classList.toggle(
+ "is-offscreen",
+ !entry.isIntersecting,
+ );
+ },
+ { rootMargin: "600px" },
+ )
+ : null;
+
+const skipWhenOffscreen = (node: HTMLElement) => {
+ skipObserver?.observe(node);
+
+ return {
+ destroy: () => skipObserver?.unobserve(node),
+ };
+};
+
+onDestroy(() => skipObserver?.disconnect());
</script>
{#if ungroupedBadges.length === 0}
@@ -42,7 +68,7 @@ export let selectedBadge: IndexedBadge | undefined = undefined;
<div class="badges">
{#each badges as badge}
- <div id={`badge-${badge.id}`}>
+ <div id={`badge-${badge.id}`} class="is-offscreen" use:skipWhenOffscreen>
{#if editMode}
<LinkedTooltip
content={`${
diff --git a/src/lib/User/BadgeWall/badges.css b/src/lib/User/BadgeWall/badges.css
index 19f8996f..f2e03988 100644
--- a/src/lib/User/BadgeWall/badges.css
+++ b/src/lib/User/BadgeWall/badges.css
@@ -11,6 +11,15 @@
gap: 0.25rem;
}
+/* Off-screen cells skip layout + paint. skipWhenOffscreen toggles this class
+ via IntersectionObserver so the containment — and the clipping it does to
+ the hover tilt, scale, and tooltip — is never active on an on-screen cell,
+ and the auto<->visible flip (which flashes) only ever happens off-screen. */
+.badges > .is-offscreen {
+ content-visibility: auto;
+ contain-intrinsic-size: auto 8rem;
+}
+
.edit-row-2 {
margin-top: -1.25rem;
}