From 70ffea0e16857703b4a0d51c861d18cf7ad3cbf7 Mon Sep 17 00:00:00 2001 From: Jarvis Jr Hermes Date: Fri, 2 Oct 2026 10:47:33 +0000 Subject: [PATCH] ui: expand diagrams in same-page fullscreen modal --- docs/contribution/diagrams.md | 2 +- scripts/portal.test.mjs | 3 +++ src/components/ArchifyDiagram/index.tsx | 20 ++++++++++++++++++-- src/css/custom.css | 8 ++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/docs/contribution/diagrams.md b/docs/contribution/diagrams.md index a9c6fd2..32af7fe 100644 --- a/docs/contribution/diagrams.md +++ b/docs/contribution/diagrams.md @@ -37,7 +37,7 @@ import ArchifyDiagram from '@site/src/components/ArchifyDiagram'; ``` -Supply a text alternative below each diagram. The wrapper uses a local, base-path-aware iframe with a descriptive title, scripts and downloads enabled, and no same-origin or parent-navigation permissions. A full-viewer link provides a wider canvas in a new tab; that direct page is not iframe-sandboxed. Only publish reviewed, trusted diagrams, and do not describe iframe isolation as protection for the standalone route. Generated output is ignored by Git and rebuilt in CI. +Supply a text alternative below each diagram. The wrapper uses a local, base-path-aware iframe with a descriptive title, scripts and downloads enabled, and no same-origin or parent-navigation permissions. The Open full viewer button expands the diagram in a full-screen modal on the current page, with the same iframe sandbox. Close it with the Close button or Escape; focus returns to the opener. It does not open a new tab. The separate standalone HTML asset remains directly addressable and is not itself iframe-sandboxed, so publish only reviewed, trusted diagrams. Generated output is ignored by Git and rebuilt in CI. ## Integration boundaries diff --git a/scripts/portal.test.mjs b/scripts/portal.test.mjs index cf4cbe7..91f922c 100644 --- a/scripts/portal.test.mjs +++ b/scripts/portal.test.mjs @@ -55,6 +55,9 @@ test('Archify is pinned, licensed and rebuilt, not a remote embed', () => { assert(wrapper.includes('sandbox="allow-scripts allow-downloads"')); assert(!wrapper.includes('allow-same-origin')); assert(wrapper.includes('useBaseUrl')); + assert(wrapper.includes('showModal()') && wrapper.includes('onClose=')); + assert(!wrapper.includes('target="_blank"')); + assert(wrapper.includes('Close full-screen diagram')); }); test('example is explicitly illustrative and contains valid connected nodes', () => { const spec = JSON.parse(read('diagrams/organization-structure.architecture.json')); diff --git a/src/components/ArchifyDiagram/index.tsx b/src/components/ArchifyDiagram/index.tsx index 5e4c81c..10a67c2 100644 --- a/src/components/ArchifyDiagram/index.tsx +++ b/src/components/ArchifyDiagram/index.tsx @@ -1,12 +1,28 @@ -import React from 'react'; +import React, {useEffect, useId, useRef, useState} from 'react'; import useBaseUrl from '@docusaurus/useBaseUrl'; export default function ArchifyDiagram({name, title}: {name: string; title: string}): React.ReactElement { if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name)) throw new Error('Invalid diagram name'); const source = useBaseUrl(`/diagrams/${name}/`); const json = useBaseUrl(`/diagrams/${name}.json`); + const dialog = useRef(null); + const opener = useRef(null); + const headingId = useId(); + const [expanded, setExpanded] = useState(false); + 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
- +
Interactive diagram
JSON source ↓