Files
documentation/src/components/ArchifyDiagram/index.tsx
T
jarvis-at-skic 2a4e058684
Build and publish Eldorado documentation / build (pull_request) Successful in 54s
fix: [verified] simplify Roadmap adoption timeline
2026-10-06 07:25:53 +00:00

81 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<HTMLDialogElement>(null);
const opener = useRef<HTMLButtonElement>(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<HTMLIFrameElement>(null);
const mobile = useRef<HTMLIFrameElement>(null);
const fullscreen = useRef<HTMLIFrameElement>(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<HTMLElement>(':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 <section className={`archify-panel${compact ? ' archify-panel--compact' : ''}${story ? ' archify-panel--story' : ''}`} data-diagram={name} aria-label={title}>
<div className="archify-toolbar"><button ref={opener} type="button" className="archify-expand" aria-label={`Expand ${title}`} title="Expand diagram" onClick={() => setExpanded(true)}><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true"><path d="M8 3H3v5M16 3h5v5M21 16v5h-5M8 21H3v-5" /></svg></button></div>
{story ? <>
<iframe className="story-desktop" ref={desktop} onLoad={() => syncTheme(desktop.current)} src={`${source}?embed=1&theme=${initialTheme.current}`} title={title} sandbox="allow-scripts allow-downloads" loading="lazy" referrerPolicy="no-referrer" />
<iframe className="story-mobile" ref={mobile} onLoad={() => syncTheme(mobile.current)} src={`${mobileSource}?embed=1&theme=${initialTheme.current}`} title={`${title} — narrow layout`} sandbox="allow-scripts allow-downloads" loading="lazy" referrerPolicy="no-referrer" />
</> : <iframe ref={desktop} onLoad={() => syncTheme(desktop.current)} src={`${source}?theme=${initialTheme.current}`} title={title} sandbox="allow-scripts allow-downloads" loading="lazy" referrerPolicy="no-referrer" />}
<dialog ref={dialog} className="archify-modal" aria-labelledby={headingId} onClose={() => {setExpanded(false); opener.current?.focus();}}>
<div className="archify-modal-toolbar"><strong id={headingId}>{title}</strong><button type="button" onClick={close} autoFocus aria-label="Close full-screen diagram"><span aria-hidden="true">×</span></button></div>
{expanded && <iframe ref={fullscreen} onLoad={() => syncTheme(fullscreen.current)} src={`${narrowRoadmap ? mobileSource : source}?${name === 'strategy-roadmap' ? 'embed=1&' : ''}theme=${initialTheme.current}`} title={`${title} — expanded`} sandbox="allow-scripts allow-downloads" referrerPolicy="no-referrer" />}
</dialog>
</section>;
}