Skip to content
72 linesCodeBlameRaw
1---
2// A diagram from src/diagrams, by name: drawn as an inline SVG in the g1t
3// tokens, with its caption, a key, and Expand, which opens it at full size
4// in a dialog. See src/diagrams/engine.ts.
5import { DIAGRAMS } from '../diagrams/index.ts';
6import { render } from '../diagrams/engine.ts';
7import LucideIcon from './LucideIcon.astro';
8
9interface Props {
10 name: string;
11}
12
13const { name } = Astro.props;
14const spec = DIAGRAMS[name];
15if (!spec) throw new Error(`No diagram named "${name}". Add it to src/diagrams/index.ts.`);
16// The dialog's copy has its own ids, so its arrowheads and title never
17// point at the page's copy.
18const svg = render(`d-${name}`, spec);
19const large = render(`d-${name}-full`, spec);
20const asyncUsed = spec.kind === 'graph' ? spec.edges.some((e) => e.async) : spec.steps.some((s) => 'from' in s && (s.async || s.reply));
21---
22
23<figure class="g1t-diagram not-content" data-diagram>
24 <div class="g1t-diagram__scroll" tabindex="0" role="group" aria-label={`${spec.caption}. Scrolls sideways on a narrow screen.`}>
25 <Fragment set:html={svg} />
26 </div>
27 <figcaption>
28 <span>{spec.caption}</span>
29 <span class="g1t-diagram__tools">
30 <span class="g1t-diagram__key" aria-hidden="true">
31 <span><svg width="22" height="8"><line x1="1" y1="4" x2="21" y2="4" class="d-key" /></svg>
32 {spec.kind === 'sequence' ? 'call' : 'calls'}</span>
33 {
34 asyncUsed && (
35 <span><svg width="22" height="8"><line x1="1" y1="4" x2="21" y2="4" class="d-key d-async" /></svg>
36 {spec.kind === 'sequence' ? 'answer or event' : 'event, queue or stream'}</span>
37 )
38 }
39 </span>
40 <button type="button" class="g1t-diagram__expand" data-diagram-open aria-haspopup="dialog">
41 <LucideIcon name="maximize-2" size="0.875rem" />
42 Expand
43 </button>
44 </span>
45 </figcaption>
46 <dialog class="g1t-diagram__dialog" aria-label={spec.caption}>
47 <div class="g1t-diagram__dialog-bar">
48 <span>{spec.caption}</span>
49 <button type="button" class="g1t-diagram__expand" data-diagram-close>
50 <LucideIcon name="x" size="0.875rem" />
51 Close
52 </button>
53 </div>
54 <div class="g1t-diagram g1t-diagram__dialog-body">
55 <div class="g1t-diagram__scroll"><Fragment set:html={large} /></div>
56 </div>
57 </dialog>
58</figure>
59
60<script>
61 // Expand opens the figure's dialog; Close, Escape or a click on the
62 // backdrop closes it.
63 for (const figure of document.querySelectorAll<HTMLElement>('[data-diagram]')) {
64 const dialog = figure.querySelector('dialog');
65 if (!dialog) continue;
66 figure.querySelector('[data-diagram-open]')?.addEventListener('click', () => dialog.showModal());
67 dialog.querySelector('[data-diagram-close]')?.addEventListener('click', () => dialog.close());
68 dialog.addEventListener('click', (event) => {
69 if (event.target === dialog) dialog.close();
70 });
71 }
72</script>