diff options
| -rw-r--r-- | src/lib/components/Giscus.svelte | 119 |
1 files changed, 95 insertions, 24 deletions
diff --git a/src/lib/components/Giscus.svelte b/src/lib/components/Giscus.svelte index 8a924ef..6659b36 100644 --- a/src/lib/components/Giscus.svelte +++ b/src/lib/components/Giscus.svelte @@ -1,27 +1,98 @@ <script lang="ts"> - import { onMount } from "svelte"; - - let container: HTMLDivElement; - - onMount(() => { - const script = document.createElement("script"); - script.src = "https://giscus.app/client.js"; - script.setAttribute("data-repo", "wenekar/giscus"); - script.setAttribute("data-repo-id", "R_kgDOREZgEQ"); - script.setAttribute("data-category", "Announcements"); - script.setAttribute("data-category-id", "DIC_kwDOREZgEc4C1nRY"); - script.setAttribute("data-mapping", "pathname"); - script.setAttribute("data-strict", "0"); - script.setAttribute("data-reactions-enabled", "1"); - script.setAttribute("data-emit-metadata", "0"); - script.setAttribute("data-input-position", "top"); - script.setAttribute("data-theme", "preferred_color_scheme"); - script.setAttribute("data-lang", "en"); - script.setAttribute("data-loading", "lazy"); - script.crossOrigin = "anonymous"; - script.async = true; - container.appendChild(script); - }); + import { onMount } from "svelte"; + + let container: HTMLDivElement | undefined; + let trigger: HTMLDivElement | undefined; + let observer: IntersectionObserver | undefined; + let isLoading = false; + let hasLoaded = false; + + function loadComments() { + if (!container || isLoading || hasLoaded) return; + + isLoading = true; + + const script = document.createElement("script"); + script.src = "https://giscus.app/client.js"; + script.setAttribute("data-repo", "wenekar/giscus"); + script.setAttribute("data-repo-id", "R_kgDOREZgEQ"); + script.setAttribute("data-category", "Announcements"); + script.setAttribute("data-category-id", "DIC_kwDOREZgEc4C1nRY"); + script.setAttribute("data-mapping", "pathname"); + script.setAttribute("data-strict", "0"); + script.setAttribute("data-reactions-enabled", "1"); + script.setAttribute("data-emit-metadata", "0"); + script.setAttribute("data-input-position", "top"); + script.setAttribute("data-theme", "preferred_color_scheme"); + script.setAttribute("data-lang", "en"); + script.setAttribute("data-loading", "lazy"); + script.crossOrigin = "anonymous"; + script.async = true; + + script.addEventListener("load", () => { + isLoading = false; + }); + + script.addEventListener("error", () => { + isLoading = false; + hasLoaded = false; + script.remove(); + }); + + container.appendChild(script); + hasLoaded = true; + observer?.disconnect(); + observer = undefined; + } + + onMount(() => { + if (!trigger || !("IntersectionObserver" in window)) return; + + observer = new IntersectionObserver( + (entries) => { + if (entries.some((entry) => entry.isIntersecting)) { + loadComments(); + } + }, + { rootMargin: "300px 0px" }, + ); + + observer.observe(trigger); + + return () => { + observer?.disconnect(); + }; + }); </script> -<div class="giscus-container" bind:this={container}></div> +<div class="giscus-container"> + {#if !hasLoaded} + <button class="comments-toggle" on:click={loadComments} disabled={isLoading}> + {isLoading ? "Loading comments..." : "Show comments"} + </button> + {/if} + + <div class="giscus-trigger" bind:this={trigger}></div> + <div bind:this={container}></div> +</div> + +<style> + .comments-toggle { + margin-bottom: 1rem; + padding: 0.6rem 0.9rem; + border: 1px solid var(--border); + background: transparent; + color: var(--text); + font: inherit; + cursor: pointer; + } + + .comments-toggle:disabled { + opacity: 0.75; + cursor: default; + } + + .giscus-trigger { + height: 1px; + } +</style> |
