Skip to main content
Glama
Southclaws

Storyden

by Southclaws
useFragmentScroll.ts2.07 kB
"use client"; import { useEffect, useState } from "react"; function decodeHash() { const raw = window.location.hash; if (!raw || raw.length < 2) return ""; try { return decodeURIComponent(raw.slice(1)); } catch { return raw.slice(1); } } export function useFragmentScroll(elementId: string) { const [isTargeted, setIsTargeted] = useState(false); useEffect(() => { let clearTimer: number | undefined; let obs: MutationObserver | undefined; const run = () => { const hash = decodeHash(); if (hash !== elementId) return; const el = document.getElementById(elementId); if (!el) return; // Get scroll offset - only apply on desktop (md breakpoint and up) // cannot use tokens for this, so hardcoding the value from design system. // spacing.20 = 5rem, convert to pixels (5rem * 16px = 80px) const scrollOffset = window.matchMedia("(min-width: 768px)").matches ? 80 : 0; const elementPosition = el.getBoundingClientRect().top; const offsetPosition = elementPosition + window.scrollY - scrollOffset; window.scrollTo({ top: offsetPosition, behavior: "auto", }); setIsTargeted(false); requestAnimationFrame(() => setIsTargeted(true)); window.clearTimeout(clearTimer); clearTimer = window.setTimeout(() => setIsTargeted(false), 1200); obs?.disconnect(); obs = undefined; }; // try now, otherwise wait until it appears (streaming/suspense bs) if (!document.getElementById(elementId) && decodeHash() === elementId) { obs = new MutationObserver(run); obs.observe(document.body, { childList: true, subtree: true }); window.setTimeout(() => { obs?.disconnect(); obs = undefined; }, 3000); } run(); window.addEventListener("hashchange", run); return () => { window.removeEventListener("hashchange", run); obs?.disconnect(); window.clearTimeout(clearTimer); }; }, [elementId]); return isTargeted; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Southclaws/storyden'

If you have feedback or need assistance with the MCP directory API, please join our Discord server