@conduction/docusaurus-preset 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/MISSING_COMPONENTS.md +109 -0
  2. package/README.md +171 -0
  3. package/package.json +59 -0
  4. package/src/components/AgentTrace/AgentTrace.jsx +128 -0
  5. package/src/components/AgentTrace/AgentTrace.module.css +115 -0
  6. package/src/components/AppMock/AppMock.jsx +86 -0
  7. package/src/components/AppMock/AppMock.module.css +629 -0
  8. package/src/components/AppMock/variants/DeciDeskMock.jsx +71 -0
  9. package/src/components/AppMock/variants/DocuDeskMock.jsx +69 -0
  10. package/src/components/AppMock/variants/LarpingAppMock.jsx +59 -0
  11. package/src/components/AppMock/variants/MyDashBiMock.jsx +135 -0
  12. package/src/components/AppMock/variants/MyDashMock.jsx +96 -0
  13. package/src/components/AppMock/variants/MyDashTilesMock.jsx +103 -0
  14. package/src/components/AppMock/variants/MyDashWidgetsMock.jsx +123 -0
  15. package/src/components/AppMock/variants/NLDesignMock.jsx +70 -0
  16. package/src/components/AppMock/variants/OpenCatalogiMock.jsx +61 -0
  17. package/src/components/AppMock/variants/OpenConnectorMock.jsx +83 -0
  18. package/src/components/AppMock/variants/OpenRegisterMock.jsx +100 -0
  19. package/src/components/AppMock/variants/OpenWooMock.jsx +61 -0
  20. package/src/components/AppMock/variants/PipelinQMock.jsx +88 -0
  21. package/src/components/AppMock/variants/ProcestMock.jsx +87 -0
  22. package/src/components/AppMock/variants/SoftwareCatalogMock.jsx +71 -0
  23. package/src/components/AppMock/variants/ZaakAfhandelAppMock.jsx +71 -0
  24. package/src/components/AppsGrid/AppsGrid.jsx +84 -0
  25. package/src/components/AppsGrid/AppsGrid.module.css +46 -0
  26. package/src/components/AppsPreview/AppsPreview.jsx +85 -0
  27. package/src/components/AppsPreview/AppsPreview.module.css +128 -0
  28. package/src/components/Clients/Clients.jsx +205 -0
  29. package/src/components/Clients/Clients.module.css +166 -0
  30. package/src/components/ComposeBlock/ComposeBlock.jsx +70 -0
  31. package/src/components/ComposeBlock/ComposeBlock.module.css +74 -0
  32. package/src/components/ConductionBg/ConductionBg.jsx +150 -0
  33. package/src/components/ConductionBg/ConductionBg.module.css +41 -0
  34. package/src/components/ContentCard/ContentCard.jsx +126 -0
  35. package/src/components/ContentCard/ContentCard.module.css +84 -0
  36. package/src/components/ContentDetailHero/ContentDetailHero.jsx +136 -0
  37. package/src/components/ContentDetailHero/ContentDetailHero.module.css +96 -0
  38. package/src/components/ContentTypeFilter/ContentTypeFilter.jsx +103 -0
  39. package/src/components/ContentTypeFilter/ContentTypeFilter.module.css +60 -0
  40. package/src/components/ContentTypeFilter/contentTypes.js +58 -0
  41. package/src/components/CookieCli/CookieCli.jsx +223 -0
  42. package/src/components/CookieCli/CookieCli.module.css +166 -0
  43. package/src/components/CtaBanner/CtaBanner.jsx +61 -0
  44. package/src/components/CtaBanner/CtaBanner.module.css +65 -0
  45. package/src/components/DetailHero/DetailHero.jsx +143 -0
  46. package/src/components/DetailHero/DetailHero.module.css +154 -0
  47. package/src/components/Diagrams/Diagrams.jsx +148 -0
  48. package/src/components/EmployeeCard/EmployeeCard.jsx +127 -0
  49. package/src/components/EmployeeCard/EmployeeCard.module.css +144 -0
  50. package/src/components/ExternalAppShelf/ExternalAppShelf.jsx +61 -0
  51. package/src/components/ExternalAppShelf/ExternalAppShelf.module.css +90 -0
  52. package/src/components/FAQ/FAQ.jsx +42 -0
  53. package/src/components/FAQ/FAQ.module.css +74 -0
  54. package/src/components/FacetedFilters/FacetedFilters.jsx +125 -0
  55. package/src/components/FacetedFilters/FacetedFilters.module.css +133 -0
  56. package/src/components/FeatureGrid/FeatureGrid.jsx +94 -0
  57. package/src/components/FeatureGrid/FeatureGrid.module.css +114 -0
  58. package/src/components/FeatureList/FeatureList.jsx +54 -0
  59. package/src/components/FeatureList/FeatureList.module.css +52 -0
  60. package/src/components/FeaturedCard/FeaturedCard.jsx +101 -0
  61. package/src/components/FeaturedCard/FeaturedCard.module.css +98 -0
  62. package/src/components/GameModal/GameModal.jsx +197 -0
  63. package/src/components/GameModal/GameModal.module.css +184 -0
  64. package/src/components/Hero/Hero.jsx +101 -0
  65. package/src/components/Hero/Hero.module.css +95 -0
  66. package/src/components/HexBackground/HexBackground.jsx +56 -0
  67. package/src/components/HexBackground/HexBackground.module.css +73 -0
  68. package/src/components/HexNetwork/HexNetwork.jsx +141 -0
  69. package/src/components/HexNetwork/HexNetwork.module.css +187 -0
  70. package/src/components/HexRain/HexRain.jsx +81 -0
  71. package/src/components/HowSteps/HowSteps.jsx +57 -0
  72. package/src/components/HowSteps/HowSteps.module.css +52 -0
  73. package/src/components/ManagedCommonGround/ManagedCommonGround.jsx +78 -0
  74. package/src/components/ManagedCommonGround/ManagedCommonGround.module.css +16 -0
  75. package/src/components/NewsletterCta/NewsletterCta.jsx +83 -0
  76. package/src/components/NewsletterCta/NewsletterCta.module.css +103 -0
  77. package/src/components/PairCard/PairCard.jsx +58 -0
  78. package/src/components/PairCard/PairCard.module.css +54 -0
  79. package/src/components/PartnerCard/PartnerCard.jsx +130 -0
  80. package/src/components/PartnerCard/PartnerCard.module.css +198 -0
  81. package/src/components/PartnerDirectory/PartnerDirectory.jsx +122 -0
  82. package/src/components/PartnerDirectory/PartnerDirectory.module.css +25 -0
  83. package/src/components/PartnerSidecard/PartnerSidecard.jsx +116 -0
  84. package/src/components/PartnerSidecard/PartnerSidecard.module.css +185 -0
  85. package/src/components/Pipeline/Pipeline.jsx +198 -0
  86. package/src/components/Pipeline/Pipeline.module.css +206 -0
  87. package/src/components/PlatformDiagram/PlatformDiagram.jsx +110 -0
  88. package/src/components/PlatformOverview/PlatformOverview.jsx +68 -0
  89. package/src/components/PlatformOverview/PlatformOverview.module.css +71 -0
  90. package/src/components/ReferenceCard/ReferenceCard.jsx +44 -0
  91. package/src/components/ReferenceCard/ReferenceCard.module.css +57 -0
  92. package/src/components/RelatedPosts/RelatedPosts.jsx +58 -0
  93. package/src/components/RelatedPosts/RelatedPosts.module.css +51 -0
  94. package/src/components/RotatingCards/RotatingCards.jsx +98 -0
  95. package/src/components/RotatingCards/RotatingCards.module.css +153 -0
  96. package/src/components/Showcase/Showcase.jsx +129 -0
  97. package/src/components/Showcase/Showcase.module.css +168 -0
  98. package/src/components/SolutionCard/SolutionCard.jsx +83 -0
  99. package/src/components/SolutionCard/SolutionCard.module.css +99 -0
  100. package/src/components/StatsStrip/StatsStrip.jsx +38 -0
  101. package/src/components/StatsStrip/StatsStrip.module.css +53 -0
  102. package/src/components/WidgetShelf/WidgetShelf.jsx +67 -0
  103. package/src/components/WidgetShelf/WidgetShelf.module.css +73 -0
  104. package/src/components/index.js +96 -0
  105. package/src/components/primitives/AuthorByline.jsx +85 -0
  106. package/src/components/primitives/AuthorByline.module.css +57 -0
  107. package/src/components/primitives/BrandCitation.jsx +71 -0
  108. package/src/components/primitives/Button.jsx +46 -0
  109. package/src/components/primitives/Button.module.css +88 -0
  110. package/src/components/primitives/Card.jsx +42 -0
  111. package/src/components/primitives/Card.module.css +42 -0
  112. package/src/components/primitives/Eyebrow.jsx +37 -0
  113. package/src/components/primitives/Eyebrow.module.css +19 -0
  114. package/src/components/primitives/HexBullet.jsx +37 -0
  115. package/src/components/primitives/HexBullet.module.css +16 -0
  116. package/src/components/primitives/HexThumbnail.jsx +70 -0
  117. package/src/components/primitives/HexThumbnail.module.css +45 -0
  118. package/src/components/primitives/Pill.jsx +42 -0
  119. package/src/components/primitives/Pill.module.css +30 -0
  120. package/src/components/primitives/Section.jsx +51 -0
  121. package/src/components/primitives/Section.module.css +31 -0
  122. package/src/components/primitives/SectionHead.jsx +36 -0
  123. package/src/components/primitives/SectionHead.module.css +43 -0
  124. package/src/components/primitives/index.js +22 -0
  125. package/src/css/brand.css +158 -0
  126. package/src/css/tokens.css +12 -0
  127. package/src/data/app-downloads.js +42 -0
  128. package/src/diagrams/README.md +74 -0
  129. package/src/diagrams/cn-domain-tree.js +105 -0
  130. package/src/diagrams/cn-hex-prism.js +163 -0
  131. package/src/diagrams/cn-hex.js +181 -0
  132. package/src/diagrams/cn-honeycomb-bg.js +135 -0
  133. package/src/diagrams/cn-pipeline.js +150 -0
  134. package/src/diagrams/cn-platform.js +156 -0
  135. package/src/diagrams/cn-side-box.js +104 -0
  136. package/src/diagrams/index.js +28 -0
  137. package/src/index.js +183 -0
  138. package/src/theme/Footer/index.jsx +516 -0
  139. package/src/theme/MDXPage/index.jsx +134 -0
  140. package/src/theme/Navbar/index.jsx +120 -0
  141. package/src/theme/Navbar/styles.module.css +114 -0
  142. package/src/theme/brand.jsx +63 -0
  143. package/src/theme.js +45 -0
  144. package/src/utils/lazyScript.js +37 -0
  145. package/static/img/favicon.svg +14 -0
  146. package/static/img/honeycomb-scatter.svg +23 -0
  147. package/static/img/honeycomb-watermark.svg +108 -0
  148. package/static/img/logo-dark.svg +11 -0
  149. package/static/img/logo.svg +14 -0
  150. package/static/img/nextcloud-logo.svg +5 -0
  151. package/static/lib/canal-footer.css +418 -0
  152. package/static/lib/canal-footer.js +499 -0
  153. package/static/lib/clients-flow.js +317 -0
  154. package/static/lib/conduction-bg.css +50 -0
  155. package/static/lib/conduction-bg.js +122 -0
  156. package/static/lib/hex-rain.css +128 -0
  157. package/static/lib/hex-rain.js +284 -0
  158. package/static/lib/kade-cyclist.css +264 -0
  159. package/static/lib/kade-cyclist.js +420 -0
  160. package/static/lib/logo-memory.css +219 -0
  161. package/static/lib/logo-memory.js +540 -0
  162. package/static/lib/platform-diagram.css +458 -0
  163. package/static/lib/platform-diagram.js +414 -0
@@ -0,0 +1,414 @@
1
+ /*
2
+ * <platform-diagram> — declarative workspace + corner-hexes + lists + flows.
3
+ *
4
+ * Authoring shape:
5
+ * <platform-diagram>
6
+ * <pd-workspace logo="..." role="Workspace" alt="Nextcloud"></pd-workspace>
7
+ * <pd-list position="top" family="nextcloud">
8
+ * <pd-item name="Files" desc="Sync, share, and version any file.">
9
+ * <svg viewBox="0 0 24 24"><path d="..."/></svg>
10
+ * </pd-item>
11
+ * ...
12
+ * </pd-list>
13
+ * <pd-list position="top-left" family="core" label="Technical Core">
14
+ * <pd-item name="OpenRegister" meta="Data" desc="..."> <svg .../></pd-item>
15
+ * ...
16
+ * </pd-list>
17
+ * <pd-list position="bottom-center" family="builder" label="App Builder" badge="COMING SOON">
18
+ * ...
19
+ * </pd-list>
20
+ * <pd-list position="bottom-right" family="integrate" label="Integrated Apps" columns="2">
21
+ * ... <!-- columns≥2 splits items into N side-by-side columns -->
22
+ * </pd-list>
23
+ * <pd-flow from="top-left:left" to="bottom-left:left" shape="c-bracket-left"></pd-flow>
24
+ * <pd-flow from="bottom-center:left" to="bottom-left:bottom" shape="l-h"></pd-flow>
25
+ * </platform-diagram>
26
+ *
27
+ * Positions: top, top-left, top-right, bottom-left, bottom-right, bottom-center.
28
+ * "top" renders only a list (no hex tag) — used for the Nextcloud-workspace
29
+ * functions list. The other five render a hex tag plus the list.
30
+ *
31
+ * Flow shapes (orthogonal segments only):
32
+ * straight direct line — use only when from/to share an axis.
33
+ * l-h L-bend, horizontal first then vertical.
34
+ * l-v L-bend, vertical first then horizontal.
35
+ * c-bracket-left out left, parallel, back in right (use when both anchors
36
+ * are on the same vertical column, going around).
37
+ * c-bracket-right out right.
38
+ * c-bracket-top out top.
39
+ * c-bracket-bottom out bottom.
40
+ *
41
+ * Anchor format on `from`/`to`: "<position>:<side>" where side is one of
42
+ * left | right | top | bottom (the four hex side midpoints / peaks).
43
+ *
44
+ * The whole component is light-DOM by design — it renders into its own
45
+ * children, which means CSS scopes via `platform-diagram` selectors and the
46
+ * structure ports directly to React/Docusaurus by capitalising tag names.
47
+ */
48
+ (function () {
49
+ const NS = 'http://www.w3.org/2000/svg';
50
+
51
+ // Maps the public position name to the legacy class used by the CSS layout.
52
+ // Keeping these stable means the diagram-overview page can opt to use the
53
+ // legacy class names if it ever wants to bypass the component.
54
+ const POSITION_CLASS = {
55
+ 'top': 'nextcloud-workspace',
56
+ 'top-left': 'tech-core',
57
+ 'top-right': 'solutions',
58
+ 'bottom-left': 'workspace',
59
+ 'bottom-right': 'integrated',
60
+ 'bottom-center': 'app-builder',
61
+ };
62
+
63
+ // Hex centres in workspace-relative coords (px).
64
+ // Derived from the layout in platform-diagram.css — keep in sync if the
65
+ // hex placement ever changes.
66
+ const HEX_CENTRES = {
67
+ 'top-left': { cx: -204, cy: -104 },
68
+ 'top-right': { cx: 204, cy: -104 },
69
+ 'bottom-left': { cx: -204, cy: 104 },
70
+ 'bottom-right': { cx: 204, cy: 104 },
71
+ 'bottom-center': { cx: 0, cy: 232 },
72
+ };
73
+
74
+ // Hex side midpoints / peaks (160×185 pointy-top hex).
75
+ const HEX_SIDES = {
76
+ left: { dx: -80, dy: 0 },
77
+ right: { dx: 80, dy: 0 },
78
+ top: { dx: 0, dy: -92.5 },
79
+ bottom: { dx: 0, dy: 92.5 },
80
+ };
81
+
82
+ function anchor(spec) {
83
+ if (!spec || !spec.includes(':')) return null;
84
+ const [position, side] = spec.split(':');
85
+ const c = HEX_CENTRES[position];
86
+ const s = HEX_SIDES[side];
87
+ if (!c || !s) {
88
+ console.warn('[platform-diagram] unknown anchor:', spec);
89
+ return null;
90
+ }
91
+ return { x: c.cx + s.dx, y: c.cy + s.dy };
92
+ }
93
+
94
+ function pathFor(shape, a, b, clearance) {
95
+ /* `clearance` is how far past the further endpoint the bracket runs
96
+ (in workspace-relative px). Defaults to 36 — enough to clear an
97
+ adjacent hex's own outline. Bump it (e.g. 150) when routing around
98
+ a hex that sits between the two anchors. */
99
+ const c = (typeof clearance === 'number' && clearance > 0) ? clearance : 36;
100
+ switch (shape) {
101
+ case 'l-h':
102
+ case 'l-bend':
103
+ case 'l-bend-h':
104
+ return `M ${a.x} ${a.y} L ${b.x} ${a.y} L ${b.x} ${b.y}`;
105
+ case 'l-v':
106
+ case 'l-bend-v':
107
+ return `M ${a.x} ${a.y} L ${a.x} ${b.y} L ${b.x} ${b.y}`;
108
+ case 'c-bracket-left': {
109
+ const x = Math.min(a.x, b.x) - c;
110
+ return `M ${a.x} ${a.y} L ${x} ${a.y} L ${x} ${b.y} L ${b.x} ${b.y}`;
111
+ }
112
+ case 'c-bracket-right': {
113
+ const x = Math.max(a.x, b.x) + c;
114
+ return `M ${a.x} ${a.y} L ${x} ${a.y} L ${x} ${b.y} L ${b.x} ${b.y}`;
115
+ }
116
+ case 'c-bracket-top': {
117
+ const y = Math.min(a.y, b.y) - c;
118
+ return `M ${a.x} ${a.y} L ${a.x} ${y} L ${b.x} ${y} L ${b.x} ${b.y}`;
119
+ }
120
+ case 'c-bracket-bottom': {
121
+ const y = Math.max(a.y, b.y) + c;
122
+ return `M ${a.x} ${a.y} L ${a.x} ${y} L ${b.x} ${y} L ${b.x} ${b.y}`;
123
+ }
124
+ case 'straight':
125
+ default:
126
+ return `M ${a.x} ${a.y} L ${b.x} ${b.y}`;
127
+ }
128
+ }
129
+
130
+ // Parses a <pd-list> (or any source element) into a config object. Reads
131
+ // its <pd-item> children eagerly so we can blow the source tree away after.
132
+ function parseList(el) {
133
+ const items = [];
134
+ for (const itemEl of el.querySelectorAll(':scope > pd-item')) {
135
+ // The item's icon is the first <svg> child. We snapshot a clone now so
136
+ // the original is safe to remove when we replace the host's innerHTML.
137
+ const svg = itemEl.querySelector(':scope > svg');
138
+ items.push({
139
+ name: itemEl.getAttribute('name') || '',
140
+ meta: itemEl.getAttribute('meta') || '',
141
+ desc: itemEl.getAttribute('desc') || '',
142
+ brand: itemEl.hasAttribute('brand') || itemEl.hasAttribute('brand-color'),
143
+ brandColor: itemEl.getAttribute('brand-color') || '',
144
+ glyph: svg ? svg.cloneNode(true) : null,
145
+ });
146
+ }
147
+ const cols = parseInt(el.getAttribute('columns') || '1', 10);
148
+ return {
149
+ position: el.getAttribute('position'),
150
+ family: el.getAttribute('family') || '',
151
+ label: el.getAttribute('label') || '',
152
+ badge: el.getAttribute('badge') || '',
153
+ columns: Number.isFinite(cols) && cols > 1 ? cols : 1,
154
+ items,
155
+ };
156
+ }
157
+
158
+ function renderList(list) {
159
+ const wrap = document.createElement('div');
160
+ const positionClass = POSITION_CLASS[list.position] || list.position;
161
+ const familyClass = list.family ? `fam-${list.family}` : '';
162
+ const colsClass = list.columns > 1 ? `cols-${list.columns}` : '';
163
+ wrap.className = `box-wrap ${positionClass} ${familyClass} ${colsClass}`.trim();
164
+
165
+ if (list.badge) {
166
+ const badge = document.createElement('span');
167
+ badge.className = 'badge';
168
+ badge.textContent = list.badge;
169
+ wrap.appendChild(badge);
170
+ }
171
+
172
+ const box = document.createElement('div');
173
+ box.className = 'box' + (list.columns > 1 ? ` cols-${list.columns}` : '');
174
+
175
+ function makeRow(item) {
176
+ const row = document.createElement('div');
177
+ row.className = 'row';
178
+
179
+ const glyph = document.createElement('span');
180
+ glyph.className = 'glyph' + (item.brand ? ' brand' : '');
181
+ if (item.brandColor) glyph.style.color = item.brandColor;
182
+ if (item.glyph) glyph.appendChild(item.glyph);
183
+ row.appendChild(glyph);
184
+
185
+ const name = document.createElement('span');
186
+ name.className = 'name';
187
+ name.textContent = item.name;
188
+ row.appendChild(name);
189
+
190
+ if (item.meta) {
191
+ const meta = document.createElement('span');
192
+ meta.className = 'meta';
193
+ meta.textContent = item.meta;
194
+ row.appendChild(meta);
195
+ }
196
+
197
+ if (item.desc) {
198
+ const desc = document.createElement('div');
199
+ desc.className = 'desc';
200
+ desc.textContent = item.desc;
201
+ row.appendChild(desc);
202
+ }
203
+
204
+ return row;
205
+ }
206
+
207
+ if (list.columns > 1) {
208
+ // Split items across N columns, filling top-to-bottom (col 1 first).
209
+ // Each column wraps its rows so .row + .row borders only apply within
210
+ // a single column.
211
+ const perCol = Math.ceil(list.items.length / list.columns);
212
+ for (let c = 0; c < list.columns; c++) {
213
+ const col = document.createElement('div');
214
+ col.className = 'col';
215
+ const start = c * perCol;
216
+ for (const item of list.items.slice(start, start + perCol)) {
217
+ col.appendChild(makeRow(item));
218
+ }
219
+ if (col.childElementCount > 0) box.appendChild(col);
220
+ }
221
+ } else {
222
+ for (const item of list.items) box.appendChild(makeRow(item));
223
+ }
224
+
225
+ wrap.appendChild(box);
226
+ return wrap;
227
+ }
228
+
229
+ function renderHex(list) {
230
+ if (!list.label || list.position === 'top') return null;
231
+ const positionClass = POSITION_CLASS[list.position] || list.position;
232
+ const familyClass = list.family ? `fam-${list.family}` : '';
233
+ const hex = document.createElement('div');
234
+ hex.className = `workspace-corner-hex ${positionClass} ${familyClass}`.trim();
235
+ // Allow newline in label to render a <br>; otherwise straight text.
236
+ if (list.label.includes('\n')) {
237
+ list.label.split('\n').forEach((line, i) => {
238
+ if (i) hex.appendChild(document.createElement('br'));
239
+ hex.appendChild(document.createTextNode(line));
240
+ });
241
+ } else {
242
+ hex.textContent = list.label;
243
+ }
244
+ return hex;
245
+ }
246
+
247
+ function renderFlows(flows) {
248
+ if (!flows.length) return null;
249
+ const svg = document.createElementNS(NS, 'svg');
250
+ svg.setAttribute('class', 'flow-overlay');
251
+ // Symmetric viewBox: x∈[-340,+340], y∈[-325,+325]. The SVG element is
252
+ // centred in the workspace's grid cell, so SVG (0,0) lands exactly on the
253
+ // workspace centre and path coords match the workspace-relative arithmetic.
254
+ svg.setAttribute('viewBox', '-340 -325 680 650');
255
+ svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
256
+ svg.setAttribute('aria-hidden', 'true');
257
+ for (const f of flows) {
258
+ const path = document.createElementNS(NS, 'path');
259
+ path.setAttribute('class', 'flow-line');
260
+ if (f.path) {
261
+ // Custom raw path overrides shape-based routing.
262
+ path.setAttribute('d', f.path);
263
+ } else {
264
+ const a = anchor(f.from);
265
+ const b = anchor(f.to);
266
+ if (!a || !b) continue;
267
+ path.setAttribute('d', pathFor(f.shape, a, b, f.clearance));
268
+ }
269
+ if (f.color) path.setAttribute('stroke', f.color);
270
+ svg.appendChild(path);
271
+ }
272
+ return svg;
273
+ }
274
+
275
+ class PlatformDiagram extends HTMLElement {
276
+ connectedCallback() {
277
+ if (this._rendered) return;
278
+ this._rendered = true;
279
+ this._build();
280
+ this._setupScrollProgress();
281
+ }
282
+
283
+ disconnectedCallback() {
284
+ if (this._teardownScroll) this._teardownScroll();
285
+ }
286
+
287
+ /* Scroll-linked entrance: writes --pd-hex-progress / --pd-list-progress /
288
+ --pd-flow-progress on `this` based on where the diagram sits in the
289
+ viewport. Scrolling up reverses the entrance because the same mapping
290
+ runs in reverse. rAF-throttled so we coalesce wheel/touch bursts. */
291
+ _setupScrollProgress() {
292
+ const reduced = window.matchMedia &&
293
+ window.matchMedia('(prefers-reduced-motion: reduce)').matches;
294
+ if (reduced) return; /* CSS defaults to 1 — diagram stays settled */
295
+
296
+ let raf = null;
297
+ const tick = () => { raf = null; this._updateProgress(); };
298
+ const onScroll = () => { if (!raf) raf = requestAnimationFrame(tick); };
299
+
300
+ window.addEventListener('scroll', onScroll, { passive: true });
301
+ window.addEventListener('resize', onScroll, { passive: true });
302
+ this._teardownScroll = () => {
303
+ window.removeEventListener('scroll', onScroll);
304
+ window.removeEventListener('resize', onScroll);
305
+ if (raf) cancelAnimationFrame(raf);
306
+ };
307
+ this._updateProgress();
308
+ }
309
+
310
+ _updateProgress() {
311
+ /* Anchor on the workspace hex's centre — that's the user's "the diagram
312
+ is here" point. Anchoring on `this` is wrong because the host has
313
+ 240px of top-padding before any visible content, so its rect.top
314
+ crosses the viewport long before the workspace appears. */
315
+ const target = this.querySelector('.workspace') || this;
316
+ const rect = target.getBoundingClientRect();
317
+ const vh = window.innerHeight || document.documentElement.clientHeight;
318
+ const centre = rect.top + rect.height / 2;
319
+
320
+ /* Trigger window: progress runs 0 → 1 as the workspace centre moves from
321
+ the viewport bottom (vh) up to the viewport centre (vh * 0.5).
322
+ Beyond the centre, progress stays at 1; below the viewport, 0.
323
+ Scrolling back up reverses the mapping. */
324
+ const start = vh;
325
+ const end = vh * 0.5;
326
+ const p = Math.max(0, Math.min(1, (start - centre) / (start - end)));
327
+
328
+ /* Stage progress (each stage clamped 0..1).
329
+ hex covers 0.00 → 0.40 (move + fade in)
330
+ list covers 0.30 → 0.75 (slide + fade in after hexes)
331
+ flow covers 0.75 → 1.00 (fade in last) */
332
+ const hex = Math.max(0, Math.min(1, (p - 0.00) / 0.40));
333
+ const list = Math.max(0, Math.min(1, (p - 0.30) / 0.45));
334
+ const flow = Math.max(0, Math.min(1, (p - 0.75) / 0.25));
335
+
336
+ this.style.setProperty('--pd-hex-progress', String(hex));
337
+ this.style.setProperty('--pd-list-progress', String(list));
338
+ this.style.setProperty('--pd-flow-progress', String(flow));
339
+ }
340
+
341
+ _build() {
342
+ // 1. Read declarative config from the light-DOM children.
343
+ let workspace = null;
344
+ const lists = [];
345
+ const flows = [];
346
+
347
+ for (const child of [...this.children]) {
348
+ const tag = child.tagName.toLowerCase();
349
+ if (tag === 'pd-workspace') {
350
+ workspace = {
351
+ logo: child.getAttribute('logo') || '',
352
+ role: child.getAttribute('role') || '',
353
+ alt: child.getAttribute('alt') || '',
354
+ };
355
+ } else if (tag === 'pd-list') {
356
+ lists.push(parseList(child));
357
+ } else if (tag === 'pd-flow') {
358
+ const cl = parseFloat(child.getAttribute('clearance'));
359
+ flows.push({
360
+ from: child.getAttribute('from'),
361
+ to: child.getAttribute('to'),
362
+ shape: child.getAttribute('shape') || 'l-h',
363
+ color: child.getAttribute('color') || '',
364
+ clearance: Number.isFinite(cl) ? cl : 0,
365
+ // Raw SVG `d` string for custom multi-bend routes that don't
366
+ // fit any built-in shape. Coords are workspace-relative (origin
367
+ // at workspace centre, same system as anchor(...)). When
368
+ // present, it overrides shape/from/to.
369
+ path: child.getAttribute('path') || '',
370
+ });
371
+ }
372
+ }
373
+
374
+ // 2. Replace the source tree with the rendered diagram.
375
+ this.innerHTML = '';
376
+ const grid = document.createElement('div');
377
+ grid.className = 'diagram-grid';
378
+
379
+ if (workspace) {
380
+ const k = document.createElement('div');
381
+ k.className = 'workspace';
382
+ const img = document.createElement('img');
383
+ img.className = 'workspace-logo';
384
+ if (workspace.logo) img.src = workspace.logo;
385
+ img.alt = workspace.alt;
386
+ k.appendChild(img);
387
+ if (workspace.role) {
388
+ const r = document.createElement('div');
389
+ r.className = 'role';
390
+ r.textContent = workspace.role;
391
+ k.appendChild(r);
392
+ }
393
+ grid.appendChild(k);
394
+ }
395
+
396
+ // Lists first, then their corresponding hex tags (so DOM order matches
397
+ // the original platform-overview layout: hex tags appear after lists).
398
+ for (const list of lists) grid.appendChild(renderList(list));
399
+ for (const list of lists) {
400
+ const hex = renderHex(list);
401
+ if (hex) grid.appendChild(hex);
402
+ }
403
+
404
+ const flowSvg = renderFlows(flows);
405
+ if (flowSvg) grid.appendChild(flowSvg);
406
+
407
+ this.appendChild(grid);
408
+ }
409
+ }
410
+
411
+ if (!customElements.get('platform-diagram')) {
412
+ customElements.define('platform-diagram', PlatformDiagram);
413
+ }
414
+ })();