import React, {useEffect, useId, useRef, useState} from 'react'; import useBaseUrl from '@docusaurus/useBaseUrl'; import {useLocation} from '@docusaurus/router'; import {useColorMode} from '@docusaurus/theme-common'; export default function ArchifyDiagram({name, title, compact = false, story = false}: {name: string; title: string; compact?: boolean; story?: boolean}): React.ReactElement { if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name)) throw new Error('Invalid diagram name'); const source = useBaseUrl(`/diagrams/${name}/`); const mobileSource = useBaseUrl(`/diagrams/${name}-mobile/`); const dialog = useRef(null); const opener = useRef(null); const headingId = useId(); const [expanded, setExpanded] = useState(false); const [narrowRoadmap, setNarrowRoadmap] = useState(false); useEffect(() => { if (name !== 'strategy-roadmap') return; const media = window.matchMedia('(max-width: 999px)'); const update = () => setNarrowRoadmap(media.matches); update(); media.addEventListener('change', update); return () => media.removeEventListener('change', update); }, [name]); const {colorMode, setColorMode} = useColorMode(); const initialTheme = useRef(colorMode); const desktop = useRef(null); const mobile = useRef(null); const fullscreen = useRef(null); const syncTheme = (frame: HTMLIFrameElement | null) => frame?.contentWindow?.postMessage({type: 'eldorado:set-theme', theme: colorMode}, '*'); useEffect(() => { for (const frame of [desktop, mobile, fullscreen]) syncTheme(frame.current); const receiveTheme = (event: MessageEvent) => { if (!event.source || ![desktop, mobile, fullscreen].some(frame => frame.current?.contentWindow === event.source)) return; if (event.data?.type !== 'eldorado:theme' || !['light', 'dark'].includes(event.data.theme)) return; if (event.data.theme !== colorMode) setColorMode(event.data.theme); }; window.addEventListener('message', receiveTheme); return () => window.removeEventListener('message', receiveTheme); }, [colorMode, setColorMode, expanded]); const {pathname, hash} = useLocation(); useEffect(() => { if (!story || !hash) return; let id: string; try {id = decodeURIComponent(hash.slice(1));} catch {return;} const frame = requestAnimationFrame(() => { const target = document.getElementById(id); if (!target?.closest('.strategy-content')) return; let detail = target.closest('details'); if (!detail) return; while (detail) { if (detail.dataset.collapsed === 'true') { detail.querySelector(':scope > summary')?.click(); } else if (!detail.hasAttribute('data-collapsed')) { detail.open = true; } detail = detail.parentElement?.closest('details') ?? null; } target.scrollIntoView(); }); return () => cancelAnimationFrame(frame); }, [story, pathname, hash]); useEffect(() => { if (!expanded) return; dialog.current?.showModal(); const previousOverflow = document.body.style.overflow; document.body.style.overflow = 'hidden'; return () => {document.body.style.overflow = previousOverflow;}; }, [expanded]); const close = () => {dialog.current?.close();}; return
{story ? <>