@supersoniks/concorde 5.0.5 → 5.1.1

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 (282) hide show
  1. package/.claude/launch.json +15 -0
  2. package/.claude/vite.http.config.mjs +7 -0
  3. package/.taste-skill/after/desktop-fold.jpg +0 -0
  4. package/.taste-skill/after/desktop-page-01.jpg +0 -0
  5. package/.taste-skill/after/desktop-page-02.jpg +0 -0
  6. package/.taste-skill/after/desktop-page-03.jpg +0 -0
  7. package/.taste-skill/after/mobile-fold.jpg +0 -0
  8. package/.taste-skill/after/mobile-page-01.jpg +0 -0
  9. package/.taste-skill/after/report.json +4103 -0
  10. package/.taste-skill/after/tablet-fold.jpg +0 -0
  11. package/.taste-skill/after/tablet-page-01.jpg +0 -0
  12. package/.taste-skill/after/tablet-page-02.jpg +0 -0
  13. package/.taste-skill/before/desktop-fold.jpg +0 -0
  14. package/.taste-skill/before/desktop-page-01.jpg +0 -0
  15. package/.taste-skill/before/desktop-page-02.jpg +0 -0
  16. package/.taste-skill/before/mobile-fold.jpg +0 -0
  17. package/.taste-skill/before/mobile-page-01.jpg +0 -0
  18. package/.taste-skill/before/report.json +2556 -0
  19. package/.taste-skill/before/tablet-fold.jpg +0 -0
  20. package/.taste-skill/before/tablet-page-01.jpg +0 -0
  21. package/.taste-skill/direction.json +510 -0
  22. package/.taste-skill/notes.md +84 -0
  23. package/.taste-skill/prod/desktop-fold.jpg +0 -0
  24. package/.taste-skill/prod/desktop-page-01.jpg +0 -0
  25. package/.taste-skill/prod/desktop-page-02.jpg +0 -0
  26. package/.taste-skill/prod/desktop-page-03.jpg +0 -0
  27. package/.taste-skill/prod/mobile-fold.jpg +0 -0
  28. package/.taste-skill/prod/mobile-page-01.jpg +0 -0
  29. package/.taste-skill/prod/mobile-page-02.jpg +0 -0
  30. package/.taste-skill/prod/report.json +1973 -0
  31. package/.taste-skill/prod/tablet-fold.jpg +0 -0
  32. package/.taste-skill/prod/tablet-page-01.jpg +0 -0
  33. package/.taste-skill/prod/tablet-page-02.jpg +0 -0
  34. package/.tmp-cem/custom-elements.json +13705 -0
  35. package/AUDIT.md +228 -0
  36. package/PLAN-AMELIORATION.md +220 -0
  37. package/build-infos.json +1 -1
  38. package/concorde-core.bundle.js +196 -196
  39. package/concorde-core.es.js +3854 -3572
  40. package/custom-elements-manifest.config.mjs +14 -0
  41. package/dist/concorde-core.bundle.js +196 -196
  42. package/dist/concorde-core.es.js +3854 -3572
  43. package/dist/img/archive/concorde-001-2cv.webp +0 -0
  44. package/dist/img/archive/concorde-red-arrows-2002-poster.jpg +0 -0
  45. package/dist/img/archive/concorde-red-arrows-2002.webm +0 -0
  46. package/dist/img/archive/credits.json +28 -0
  47. package/docs/assets/index-Bb-_LRyY.js +12280 -0
  48. package/docs/index.html +1 -1
  49. package/index.html +27 -63
  50. package/package.json +44 -3
  51. package/public/img/archive/concorde-001-2cv.webp +0 -0
  52. package/public/img/archive/concorde-red-arrows-2002-poster.jpg +0 -0
  53. package/public/img/archive/concorde-red-arrows-2002.webm +0 -0
  54. package/public/img/archive/credits.json +28 -0
  55. package/scripts/generate-sdui-catalog.mjs +250 -0
  56. package/scripts/generate-sdui-catalog.spec.ts +91 -0
  57. package/scripts/pre-build.mjs +15 -0
  58. package/src/core/components/functional/fetch/fetch.md +2 -2
  59. package/src/core/components/functional/sdui/SDUIDescriptorTransformer.ts +5 -5
  60. package/src/core/components/functional/sdui/__fixtures__/descriptors.ts +251 -0
  61. package/src/core/components/functional/sdui/__snapshots__/sdui-action.spec.ts.snap +73 -0
  62. package/src/core/components/functional/sdui/__snapshots__/sdui-incremental.spec.ts.snap +50 -0
  63. package/src/core/components/functional/sdui/__snapshots__/sdui-partial.spec.ts.snap +50 -0
  64. package/src/core/components/functional/sdui/__snapshots__/sdui.regression.spec.ts.snap +461 -0
  65. package/src/core/components/functional/sdui/component-catalog.gaps.json +511 -0
  66. package/src/core/components/functional/sdui/component-catalog.json +3103 -0
  67. package/src/core/components/functional/sdui/component-catalog.spec.ts +23 -0
  68. package/src/core/components/functional/sdui/sdui-action.spec.ts +99 -0
  69. package/src/core/components/functional/sdui/sdui-dom-snapshot.ts +61 -0
  70. package/src/core/components/functional/sdui/sdui-extension-points.md +94 -0
  71. package/src/core/components/functional/sdui/sdui-incremental.spec.ts +137 -0
  72. package/src/core/components/functional/sdui/sdui-partial.spec.ts +83 -0
  73. package/src/core/components/functional/sdui/sdui-partial.ts +19 -0
  74. package/src/core/components/functional/sdui/sdui-safe.spec.ts +188 -0
  75. package/src/core/components/functional/sdui/sdui-safe.ts +100 -0
  76. package/src/core/components/functional/sdui/sdui.md +122 -0
  77. package/src/core/components/functional/sdui/sdui.regression.spec.ts +64 -0
  78. package/src/core/components/functional/sdui/sdui.ts +442 -34
  79. package/src/core/components/functional/sdui/types.ts +49 -0
  80. package/src/core/components/ui/modal/modal.ts +14 -11
  81. package/src/docs/_getting-started/components.md +5 -0
  82. package/src/docs/_getting-started/theming.md +2 -2
  83. package/src/docs/code.ts +88 -75
  84. package/src/docs/components/docs-demo-sources.ts +16 -8
  85. package/src/docs/components/docs-lit-demo.ts +19 -37
  86. package/src/docs/docs.ts +5 -0
  87. package/src/docs/example/docs-boarding-pass-demo.ts +134 -0
  88. package/src/docs/example/docs-provider-keys.ts +12 -0
  89. package/src/docs/header/header.ts +233 -69
  90. package/src/docs/home/catalog.ts +44 -0
  91. package/src/docs/home/home.ts +513 -0
  92. package/src/docs/home/mach-stage.ts +389 -0
  93. package/src/docs/layout.ts +3 -1
  94. package/src/docs/navigation/components-index.ts +56 -0
  95. package/src/docs/navigation/navigation.ts +240 -232
  96. package/src/docs/navigation/pager.ts +67 -0
  97. package/src/docs/navigation/toc.ts +98 -0
  98. package/src/docs/search/docs-search.json +330 -20
  99. package/src/docs/search/markdown-renderer.ts +11 -3
  100. package/src/docs/shiki/index.ts +109 -0
  101. package/src/docs/tailwind/css/base/scrollbar.css +22 -0
  102. package/src/docs/tailwind/css/base/theme.css +96 -0
  103. package/src/docs/tailwind/css/base/typography.css +4 -0
  104. package/src/docs/tailwind/css/docs/boarding-pass.css +65 -0
  105. package/src/docs/tailwind/css/docs/content.css +32 -0
  106. package/src/docs/tailwind/css/docs/page.css +10 -0
  107. package/src/docs/tailwind/css/docs.css +9 -0
  108. package/src/docs/tailwind/css/home/hero.css +210 -0
  109. package/src/docs/tailwind/css/home/motion.css +84 -0
  110. package/src/docs/tailwind/css/home/sections.css +416 -0
  111. package/src/docs/tailwind/css/tailwind.css +7 -185
  112. package/src/tsconfig.json +113 -2
  113. package/src/tsconfig.tsbuildinfo +1 -1
  114. package/tailwind.config.js +8 -4
  115. package/docs/assets/index-wVZpLVYW.js +0 -12122
  116. package/docs/crawl/core/components/functional/date/date.html +0 -190
  117. package/docs/crawl/core/components/functional/fetch/fetch.html +0 -109
  118. package/docs/crawl/core/components/functional/if/if.html +0 -27
  119. package/docs/crawl/core/components/functional/jsonata/jsonata.html +0 -79
  120. package/docs/crawl/core/components/functional/list/list.html +0 -70
  121. package/docs/crawl/core/components/functional/mix/mix.html +0 -45
  122. package/docs/crawl/core/components/functional/queue/queue.html +0 -96
  123. package/docs/crawl/core/components/functional/router/router.html +0 -106
  124. package/docs/crawl/core/components/functional/sdui/sdui.html +0 -269
  125. package/docs/crawl/core/components/functional/states/states.html +0 -66
  126. package/docs/crawl/core/components/functional/submit/submit.html +0 -160
  127. package/docs/crawl/core/components/functional/subscriber/subscriber.html +0 -67
  128. package/docs/crawl/core/components/functional/value/value.html +0 -51
  129. package/docs/crawl/core/components/ui/alert/alert.html +0 -211
  130. package/docs/crawl/core/components/ui/alert-messages/alert-messages.html +0 -131
  131. package/docs/crawl/core/components/ui/badge/badge.html +0 -197
  132. package/docs/crawl/core/components/ui/button/button.html +0 -150
  133. package/docs/crawl/core/components/ui/captcha/captcha.html +0 -112
  134. package/docs/crawl/core/components/ui/card/card.html +0 -253
  135. package/docs/crawl/core/components/ui/divider/divider.html +0 -144
  136. package/docs/crawl/core/components/ui/form/checkbox/checkbox.html +0 -73
  137. package/docs/crawl/core/components/ui/form/fieldset/fieldset.html +0 -266
  138. package/docs/crawl/core/components/ui/form/form-actions/form-actions.html +0 -122
  139. package/docs/crawl/core/components/ui/form/form-layout/form-layout.html +0 -121
  140. package/docs/crawl/core/components/ui/form/input/input.html +0 -109
  141. package/docs/crawl/core/components/ui/form/input-autocomplete/input-autocomplete.html +0 -38
  142. package/docs/crawl/core/components/ui/form/radio/radio.html +0 -56
  143. package/docs/crawl/core/components/ui/form/select/select.html +0 -73
  144. package/docs/crawl/core/components/ui/form/switch/switch.html +0 -56
  145. package/docs/crawl/core/components/ui/form/textarea/textarea.html +0 -59
  146. package/docs/crawl/core/components/ui/group/group.html +0 -104
  147. package/docs/crawl/core/components/ui/icon/icon.html +0 -222
  148. package/docs/crawl/core/components/ui/image/image.html +0 -298
  149. package/docs/crawl/core/components/ui/link/link.html +0 -100
  150. package/docs/crawl/core/components/ui/loader/loader.html +0 -124
  151. package/docs/crawl/core/components/ui/menu/menu.html +0 -394
  152. package/docs/crawl/core/components/ui/modal/modal.html +0 -342
  153. package/docs/crawl/core/components/ui/pop/pop.html +0 -296
  154. package/docs/crawl/core/components/ui/progress/progress.html +0 -131
  155. package/docs/crawl/core/components/ui/table/table.html +0 -545
  156. package/docs/crawl/core/components/ui/theme/theme.html +0 -131
  157. package/docs/crawl/core/components/ui/toast/toast.html +0 -233
  158. package/docs/crawl/core/components/ui/tooltip/tooltip.html +0 -140
  159. package/docs/crawl/docs/_core-concept/dataFlow.html +0 -177
  160. package/docs/crawl/docs/_core-concept/overview.html +0 -66
  161. package/docs/crawl/docs/_core-concept/subscriber.html +0 -75
  162. package/docs/crawl/docs/_decorators/ancestor-attribute.html +0 -117
  163. package/docs/crawl/docs/_decorators/auto-subscribe.html +0 -202
  164. package/docs/crawl/docs/_decorators/bind.html +0 -141
  165. package/docs/crawl/docs/_decorators/get.html +0 -149
  166. package/docs/crawl/docs/_decorators/handle.html +0 -165
  167. package/docs/crawl/docs/_decorators/on-assign.html +0 -355
  168. package/docs/crawl/docs/_decorators/patch.html +0 -78
  169. package/docs/crawl/docs/_decorators/post.html +0 -139
  170. package/docs/crawl/docs/_decorators/publish.html +0 -61
  171. package/docs/crawl/docs/_decorators/put.html +0 -78
  172. package/docs/crawl/docs/_decorators/subscribe.html +0 -109
  173. package/docs/crawl/docs/_decorators/wait-for-ancestors.html +0 -137
  174. package/docs/crawl/docs/_directives/sub.html +0 -93
  175. package/docs/crawl/docs/_getting-started/ai-agents.html +0 -173
  176. package/docs/crawl/docs/_getting-started/concorde-manual-install.html +0 -100
  177. package/docs/crawl/docs/_getting-started/concorde-outside.html +0 -58
  178. package/docs/crawl/docs/_getting-started/create-a-component.html +0 -111
  179. package/docs/crawl/docs/_getting-started/my-first-component.html +0 -189
  180. package/docs/crawl/docs/_getting-started/my-first-subscriber.html +0 -110
  181. package/docs/crawl/docs/_getting-started/pubsub.html +0 -62
  182. package/docs/crawl/docs/_getting-started/start.html +0 -76
  183. package/docs/crawl/docs/_getting-started/theming.html +0 -333
  184. package/docs/crawl/docs/_misc/api-configuration.html +0 -149
  185. package/docs/crawl/docs/_misc/dataProviderKey.html +0 -135
  186. package/docs/crawl/docs/_misc/docs-mock-api.html +0 -158
  187. package/docs/crawl/docs/_misc/dynamic-path.html +0 -180
  188. package/docs/crawl/docs/_misc/endpoint.html +0 -50
  189. package/docs/crawl/docs/_misc/formelement-subscriber-removal.html +0 -138
  190. package/docs/crawl/docs/_misc/html-integration.html +0 -48
  191. package/docs/crawl/hubs/decorators.html +0 -547
  192. package/docs/crawl/hubs/form-components.html +0 -381
  193. package/docs/crawl/hubs/remote-data.html +0 -452
  194. package/docs/crawl/index.html +0 -102
  195. package/docs/llms-full.txt +0 -7008
  196. package/docs/llms.txt +0 -97
  197. package/docs/sitemap.xml +0 -240
  198. package/docs/src/core/components/functional/date/date.md +0 -290
  199. package/docs/src/core/components/functional/fetch/fetch.md +0 -125
  200. package/docs/src/core/components/functional/if/if.md +0 -9
  201. package/docs/src/core/components/functional/jsonata/jsonata.md +0 -56
  202. package/docs/src/core/components/functional/list/list.md +0 -65
  203. package/docs/src/core/components/functional/mix/mix.md +0 -41
  204. package/docs/src/core/components/functional/queue/queue.md +0 -72
  205. package/docs/src/core/components/functional/router/router.md +0 -94
  206. package/docs/src/core/components/functional/sdui/default-library.json +0 -108
  207. package/docs/src/core/components/functional/sdui/example.json +0 -99
  208. package/docs/src/core/components/functional/sdui/sdui.md +0 -356
  209. package/docs/src/core/components/functional/states/states.md +0 -87
  210. package/docs/src/core/components/functional/submit/submit.md +0 -114
  211. package/docs/src/core/components/functional/subscriber/subscriber.md +0 -91
  212. package/docs/src/core/components/functional/value/value.md +0 -35
  213. package/docs/src/core/components/ui/alert/alert.md +0 -196
  214. package/docs/src/core/components/ui/alert-messages/alert-messages.md +0 -85
  215. package/docs/src/core/components/ui/badge/badge.md +0 -188
  216. package/docs/src/core/components/ui/button/button.md +0 -183
  217. package/docs/src/core/components/ui/captcha/captcha.md +0 -71
  218. package/docs/src/core/components/ui/card/card.md +0 -215
  219. package/docs/src/core/components/ui/divider/divider.md +0 -129
  220. package/docs/src/core/components/ui/form/checkbox/checkbox.md +0 -77
  221. package/docs/src/core/components/ui/form/fieldset/fieldset.md +0 -205
  222. package/docs/src/core/components/ui/form/form-actions/form-actions.md +0 -100
  223. package/docs/src/core/components/ui/form/form-layout/form-layout.md +0 -119
  224. package/docs/src/core/components/ui/form/input/input.md +0 -142
  225. package/docs/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +0 -29
  226. package/docs/src/core/components/ui/form/radio/radio.md +0 -57
  227. package/docs/src/core/components/ui/form/select/select.md +0 -71
  228. package/docs/src/core/components/ui/form/switch/switch.md +0 -57
  229. package/docs/src/core/components/ui/form/textarea/textarea.md +0 -65
  230. package/docs/src/core/components/ui/group/group.md +0 -75
  231. package/docs/src/core/components/ui/icon/icon.md +0 -214
  232. package/docs/src/core/components/ui/icon/icons.json +0 -1
  233. package/docs/src/core/components/ui/image/image.md +0 -233
  234. package/docs/src/core/components/ui/link/link.md +0 -81
  235. package/docs/src/core/components/ui/loader/loader.md +0 -112
  236. package/docs/src/core/components/ui/menu/menu.md +0 -370
  237. package/docs/src/core/components/ui/modal/modal.md +0 -235
  238. package/docs/src/core/components/ui/pop/pop.md +0 -294
  239. package/docs/src/core/components/ui/progress/progress.md +0 -109
  240. package/docs/src/core/components/ui/table/table.md +0 -431
  241. package/docs/src/core/components/ui/theme/theme.md +0 -122
  242. package/docs/src/core/components/ui/toast/toast.md +0 -216
  243. package/docs/src/core/components/ui/tooltip/tooltip.md +0 -124
  244. package/docs/src/docs/_core-concept/dataFlow.md +0 -88
  245. package/docs/src/docs/_core-concept/overview.md +0 -57
  246. package/docs/src/docs/_core-concept/subscriber.md +0 -75
  247. package/docs/src/docs/_decorators/ancestor-attribute.md +0 -128
  248. package/docs/src/docs/_decorators/auto-subscribe.md +0 -202
  249. package/docs/src/docs/_decorators/bind.md +0 -167
  250. package/docs/src/docs/_decorators/get.md +0 -162
  251. package/docs/src/docs/_decorators/handle.md +0 -175
  252. package/docs/src/docs/_decorators/on-assign.md +0 -390
  253. package/docs/src/docs/_decorators/patch.md +0 -70
  254. package/docs/src/docs/_decorators/post.md +0 -146
  255. package/docs/src/docs/_decorators/publish.md +0 -55
  256. package/docs/src/docs/_decorators/put.md +0 -70
  257. package/docs/src/docs/_decorators/subscribe.md +0 -100
  258. package/docs/src/docs/_decorators/wait-for-ancestors.md +0 -163
  259. package/docs/src/docs/_directives/sub.md +0 -91
  260. package/docs/src/docs/_getting-started/ai-agents.md +0 -76
  261. package/docs/src/docs/_getting-started/concorde-manual-install.md +0 -133
  262. package/docs/src/docs/_getting-started/concorde-outside.md +0 -33
  263. package/docs/src/docs/_getting-started/create-a-component.md +0 -139
  264. package/docs/src/docs/_getting-started/my-first-component.md +0 -236
  265. package/docs/src/docs/_getting-started/my-first-subscriber.md +0 -120
  266. package/docs/src/docs/_getting-started/pubsub.md +0 -37
  267. package/docs/src/docs/_getting-started/start.md +0 -47
  268. package/docs/src/docs/_getting-started/theming.md +0 -253
  269. package/docs/src/docs/_misc/api-configuration.md +0 -81
  270. package/docs/src/docs/_misc/dataProviderKey.md +0 -168
  271. package/docs/src/docs/_misc/docs-mock-api.md +0 -63
  272. package/docs/src/docs/_misc/dynamic-path.md +0 -71
  273. package/docs/src/docs/_misc/endpoint.md +0 -45
  274. package/docs/src/docs/_misc/formelement-subscriber-removal.md +0 -115
  275. package/docs/src/docs/_misc/html-integration.md +0 -15
  276. package/docs/src/docs/search/docs-search.json +0 -12242
  277. package/docs/src/tag-list.json +0 -1
  278. package/docs/src/tsconfig-model.json +0 -23
  279. package/docs/src/tsconfig.json +0 -1242
  280. package/src/docs/prism/index.ts +0 -6
  281. package/src/docs/prism/prism.css +0 -158
  282. package/src/docs/prism/prism.js +0 -1022
@@ -0,0 +1,513 @@
1
+ import { html, LitElement } from "lit";
2
+ import { customElement, state } from "lit/decorators.js";
3
+ import { unsafeHTML } from "lit/directives/unsafe-html.js";
4
+ import { sectionPages } from "../navigation/components-index";
5
+ import { COMPONENT_NOTES } from "./catalog";
6
+ import "./mach-stage";
7
+
8
+ const GET_STARTED = "#docs/_getting-started/start.md/start";
9
+ const COMPONENTS_PAGE = "#docs/_getting-started/components.md/components";
10
+
11
+ /**
12
+ * Presets for the theming instrument: palette, typeface and radius all come from tokens.
13
+ * `--sc-btn-rounded` is derived once on <sonic-theme>, so it is set explicitly.
14
+ */
15
+ const themes = [
16
+ { name: "Manual", vars: "" },
17
+ {
18
+ name: "Dracula",
19
+ vars: [
20
+ "--sc-base:#282a36;--sc-base-content:#f8f8f2",
21
+ "--sc-base-50:#343746;--sc-base-100:#44475a;--sc-base-200:#6272a4",
22
+ "--sc-primary:#bd93f9;--sc-primary-content:#282a36",
23
+ "--sc-info:#8be9fd;--sc-info-content:#282a36",
24
+ "--sc-success:#50fa7b;--sc-success-content:#282a36",
25
+ "--sc-warning:#ffb86c;--sc-danger:#ff5555",
26
+ "--sc-rounded:1rem;--sc-btn-rounded:9999px",
27
+ ].join(";"),
28
+ },
29
+ {
30
+ name: "Classic",
31
+ vars: [
32
+ "--sc-base:#fbf5e6;--sc-base-content:#3b2f2f",
33
+ "--sc-base-50:#f3e9d2;--sc-base-100:#e9dcbd;--sc-base-200:#d6c49a",
34
+ "--sc-primary:#7f1d1d;--sc-primary-content:#fbf5e6",
35
+ "--sc-info:#1e3a8a;--sc-success:#166534;--sc-warning:#b45309",
36
+ '--sc-font-family-base:Georgia,"Times New Roman",serif',
37
+ '--sc-headings-font-family:Georgia,"Times New Roman",serif',
38
+ "--sc-rounded:0;--sc-btn-rounded:0",
39
+ ].join(";"),
40
+ },
41
+ {
42
+ name: "Terminal",
43
+ vars: [
44
+ "--sc-base:#0b0f0b;--sc-base-content:#b8f7c4",
45
+ "--sc-base-50:#111a12;--sc-base-100:#16231a;--sc-base-200:#1f3a26",
46
+ "--sc-primary:#22c55e;--sc-primary-content:#0b0f0b",
47
+ "--sc-info:#22d3ee;--sc-info-content:#0b0f0b",
48
+ "--sc-success:#4ade80;--sc-success-content:#0b0f0b",
49
+ // the Terminal preset only ever restyles the data-ui fragment
50
+ "--sc-font-family-base:ui-monospace,SFMono-Regular,Menlo,monospace", // taste-skill-ignore
51
+ "--sc-headings-font-family:ui-monospace,SFMono-Regular,Menlo,monospace", // taste-skill-ignore
52
+ "--sc-rounded:2px;--sc-btn-rounded:2px",
53
+ ].join(";"),
54
+ },
55
+ ];
56
+
57
+ /** The same <sonic-button>, dropped in different stacks (strings: formatters leave them alone). */
58
+ const hosts = [
59
+ {
60
+ name: "HTML",
61
+ language: "html",
62
+ code: `<script type="module" src="concorde.js"></script>
63
+
64
+ <sonic-button type="primary">Book</sonic-button>`,
65
+ },
66
+ {
67
+ name: "React",
68
+ language: "javascript",
69
+ code: `import "@supersoniks/concorde/button";
70
+
71
+ export const Book = () => (
72
+ <sonic-button type="primary">Book</sonic-button>
73
+ );`,
74
+ },
75
+ {
76
+ name: "Vue",
77
+ language: "html",
78
+ code: `<script setup>
79
+ import "@supersoniks/concorde/button";
80
+ </script>
81
+ <template><sonic-button type="primary">Book</sonic-button></template>`,
82
+ },
83
+ {
84
+ name: "PHP",
85
+ language: "html",
86
+ code: `<?php foreach ($flights as $f): ?>
87
+ <sonic-button type="primary"><?= $f->label ?></sonic-button>
88
+ <?php endforeach ?>`,
89
+ },
90
+ ];
91
+
92
+ const bindSnippet = `<div formDataProvider="flight">
93
+ <sonic-input name="captain"></sonic-input>
94
+ </div>
95
+ <sonic-value dataProvider="flight" key="captain"></sonic-value>`;
96
+
97
+ /** What the server pushes when the gate changes (rendered by the real <sonic-sdui>). */
98
+ const gateJson = `{
99
+ "nodes": [
100
+ {
101
+ "tagName": "sonic-alert",
102
+ "attributes": {
103
+ "status": "warning",
104
+ "background": "",
105
+ "label": "Gate change: AF 002 now boards at C4"
106
+ }
107
+ }
108
+ ]
109
+ }`;
110
+ const gateChange = JSON.parse(gateJson);
111
+
112
+ const INSTALL = `npx @supersoniks/create-concorde-ts-starter "MyProject"`;
113
+
114
+ const escapeCode = (code: string) =>
115
+ code.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
116
+
117
+ /** A read-only code block built from a string, so whitespace survives formatters. */
118
+ const codeBlock = (code: string, language: string, className = "") =>
119
+ unsafeHTML(
120
+ `<sonic-code language="${language}" noEdit noPreview class="${className}"><template>${escapeCode(code)}</template></sonic-code>`,
121
+ );
122
+
123
+ const INDEX_TABS = [
124
+ { title: "UI components", label: "Interface" },
125
+ { title: "Functional components", label: "Functional" },
126
+ ];
127
+
128
+ const ARCHIVE = "./img/archive/";
129
+
130
+ /** Credit lines for the archive pictures (CC BY / CC BY-SA, from assets.mjs --credits). */
131
+ const CREDITS = `Film: <a href="https://commons.wikimedia.org/wiki/File:Concorde_%26_Red_Arrows_2002.webm">“Concorde &amp; Red Arrows 2002”</a> by Steve Elliott, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a>, via Wikimedia Commons.`;
132
+
133
+ const tagName = "docs-home";
134
+ /**
135
+ * Landing page of the documentation, set like an old technical manual.
136
+ * Light DOM so the global sheet and the docs helpers (sonic-code) apply.
137
+ */
138
+ @customElement(tagName)
139
+ export class DocsHome extends LitElement {
140
+ private observer?: IntersectionObserver;
141
+ private settleObserver?: IntersectionObserver;
142
+
143
+ @state() private theme = 0;
144
+ @state() private host = 0;
145
+ @state() private gate = false;
146
+ @state() private families = new Set([0, 1]);
147
+ @state() private focus = "Button";
148
+
149
+ createRenderRoot() {
150
+ return this;
151
+ }
152
+
153
+ firstUpdated() {
154
+ this.observer = new IntersectionObserver(
155
+ (records) => {
156
+ records.forEach((r) => {
157
+ if (!r.isIntersecting) return;
158
+ r.target.classList.add("is-visible");
159
+ this.observer?.unobserve(r.target);
160
+ });
161
+ },
162
+ { threshold: 0.12 },
163
+ );
164
+ this.querySelectorAll("[data-reveal]").forEach((el) =>
165
+ this.observer?.observe(el),
166
+ );
167
+ // the archive photograph settles from a slight zoom as it comes in (always visible)
168
+ this.settleObserver = new IntersectionObserver(
169
+ (records) => {
170
+ records.forEach((r) => {
171
+ if (!r.isIntersecting) return;
172
+ r.target.classList.add("is-visible");
173
+ this.settleObserver?.unobserve(r.target);
174
+ });
175
+ },
176
+ { rootMargin: "0px 0px 25% 0px" },
177
+ );
178
+ this.querySelectorAll(".settle").forEach((el) =>
179
+ this.settleObserver?.observe(el),
180
+ );
181
+ }
182
+
183
+ disconnectedCallback() {
184
+ this.observer?.disconnect();
185
+ this.settleObserver?.disconnect();
186
+ super.disconnectedCallback();
187
+ }
188
+
189
+ /** The departures shown on the board; the gate switch reroutes the passenger's flight. */
190
+ private get flights() {
191
+ return [
192
+ { time: "10:30", flight: "AF 002", to: "New York", gate: this.gate ? "C4" : "B12", status: this.gate ? "Gate change" : "Boarding", type: this.gate ? "warning" : "success", mine: true },
193
+ { time: "11:15", flight: "BA 001", to: "London", gate: "A7", status: "On time", type: "default", mine: false },
194
+ { time: "13:40", flight: "AF 054", to: "Rio", gate: "D2", status: "Delayed", type: "danger", mine: false },
195
+ ];
196
+ }
197
+
198
+ /** Reads the switch after its own toggle (a label click fires two click events). */
199
+ private syncGate(e: Event) {
200
+ const sw = e.currentTarget as HTMLElement & { checked?: boolean };
201
+ window.setTimeout(() => (this.gate = !!sw.checked));
202
+ }
203
+
204
+
205
+ private renderHero() {
206
+ return html`<section class="hero" aria-labelledby="home-title">
207
+ <div class="hero-copy">
208
+ <h1 id="home-title" class="hero-title hero-in">
209
+ Web components<br />for every stack.
210
+ </h1>
211
+ <div class="hero-actions hero-in" style="--d:180ms">
212
+ <sonic-button size="lg" type="primary" class="signal-button" href=${GET_STARTED}
213
+ >Open the manual</sonic-button
214
+ >
215
+ <sonic-link href=${COMPONENTS_PAGE} class="text-link"
216
+ >Browse the components</sonic-link
217
+ >
218
+ </div>
219
+ <div class="hero-install hero-in" style="--d:270ms">
220
+ ${codeBlock(INSTALL, "bash", "hero-install-code")}
221
+ </div>
222
+ </div>
223
+ <div class="hero-stage">
224
+ <docs-mach-stage class="hero-mach"></docs-mach-stage>
225
+ </div>
226
+ </section>`;
227
+ }
228
+
229
+ private renderManifesto() {
230
+ return html`<section class="manifesto" aria-label="What Concorde is">
231
+ <p class="manifesto-text" data-reveal>
232
+ Concorde is a Lit library of 41 web components. They bind data, call
233
+ APIs and theme themselves from plain HTML, in React, Vue, PHP or a
234
+ static page.
235
+ </p>
236
+ </section>`;
237
+ }
238
+
239
+ /** Families shown in the wall; at least one stays on. */
240
+ private toggleFamily(i: number) {
241
+ const next = new Set(this.families);
242
+ if (next.has(i) && next.size > 1) next.delete(i);
243
+ else next.add(i);
244
+ this.families = next;
245
+ }
246
+
247
+ private renderIndex() {
248
+ const pages = INDEX_TABS.flatMap((t, i) =>
249
+ this.families.has(i) ? sectionPages(t.title) : [],
250
+ );
251
+ const focus = COMPONENT_NOTES[this.focus] ?? COMPONENT_NOTES[pages[0]?.label];
252
+ return html`<section class="index" aria-labelledby="index-title">
253
+ <div class="index-head" data-reveal>
254
+ <h2 id="index-title" class="section-title">41 components,<br />one tag each.</h2>
255
+ <div class="index-filters" role="group" aria-label="Component families" data-ui>
256
+ ${INDEX_TABS.map((t, i) => {
257
+ const on = this.families.has(i);
258
+ return html`<sonic-button
259
+ variant="unstyled"
260
+ size="lg"
261
+ class="index-filter"
262
+ aria-pressed=${on ? "true" : "false"}
263
+ @click=${() => this.toggleFamily(i)}
264
+ >[<span class="index-filter-mark">×</span>] ${t.label}
265
+ (${sectionPages(t.title).length})</sonic-button
266
+ >`;
267
+ })}
268
+ </div>
269
+ </div>
270
+ <p class="index-wall">
271
+ ${pages.map(
272
+ (page) => html`<span class="wall-item"
273
+ ><sonic-link
274
+ href=${page.href}
275
+ class="wall-name ${page.label === this.focus ? "is-focus" : ""}"
276
+ @mouseenter=${() => (this.focus = page.label)}
277
+ @focusin=${() => (this.focus = page.label)}
278
+ >${page.label}</sonic-link
279
+ ></span
280
+ > `,
281
+ )}
282
+ </p>
283
+ <div class="index-caption" aria-live="polite">
284
+ <code class="index-caption-tag">&lt;${focus?.tag ?? ""}&gt;</code>
285
+ <span class="index-caption-note">${focus?.note ?? ""}</span>
286
+ <sonic-link href=${COMPONENTS_PAGE} class="text-link index-caption-all"
287
+ >All components</sonic-link
288
+ >
289
+ </div>
290
+ </section>`;
291
+ }
292
+
293
+ private renderInstruments() {
294
+ return html`<section class="instruments" aria-labelledby="instruments-title">
295
+ <h2 id="instruments-title" class="section-title instr-title" data-reveal>
296
+ Plumbing in attributes.
297
+ </h2>
298
+ <div class="instr-field">
299
+ <div class="instr-output board" data-ui style=${themes[this.theme].vars}>
300
+ <div class="board-head">
301
+ <span class="board-title">Departures</span>
302
+ <span class="board-airport">Paris CDG</span>
303
+ </div>
304
+ <div class="board-passenger">
305
+ <span class="board-label">Captain</span>
306
+ <span class="board-name"
307
+ ><sonic-value dataProvider="homeFlight" key="captain"></sonic-value
308
+ ></span>
309
+ </div>
310
+ <sonic-table class="board-table">
311
+ <sonic-thead>
312
+ <sonic-tr>
313
+ <sonic-th>Time</sonic-th>
314
+ <sonic-th>Flight</sonic-th>
315
+ <sonic-th>To</sonic-th>
316
+ <sonic-th>Gate</sonic-th>
317
+ <sonic-th>Status</sonic-th>
318
+ </sonic-tr>
319
+ </sonic-thead>
320
+ <sonic-tbody>
321
+ ${this.flights.map(
322
+ (f) => html`<sonic-tr class=${f.mine ? "board-mine" : ""}>
323
+ <sonic-td>${f.time}</sonic-td>
324
+ <sonic-td>${f.flight}</sonic-td>
325
+ <sonic-td>${f.to}</sonic-td>
326
+ <sonic-td>${f.gate}</sonic-td>
327
+ <sonic-td
328
+ ><sonic-badge size="sm" type=${f.type}>${f.status}</sonic-badge></sonic-td
329
+ >
330
+ </sonic-tr>`,
331
+ )}
332
+ </sonic-tbody>
333
+ </sonic-table>
334
+ ${this.gate
335
+ ? html`<sonic-sdui dataProvider="homeGate" .props=${gateChange}></sonic-sdui>`
336
+ : ""}
337
+ <div class="board-foot">
338
+ <sonic-button type="primary">
339
+ <sonic-icon slot="prefix" name="airplane" library="iconoir"></sonic-icon>
340
+ Board AF 002
341
+ </sonic-button>
342
+ <span class="board-note">Rendered in ${hosts[this.host].name}</span>
343
+ </div>
344
+ </div>
345
+ </div>
346
+ <div class="instr-blocks">
347
+ <div class="instr-block" data-reveal>
348
+ <p class="instr-claim">Bind state without glue.</p>
349
+ <p class="instr-text">
350
+ The field publishes into a formDataProvider and the panel
351
+ subscribes. No store to set up, no event to wire.
352
+ </p>
353
+ <div formDataProvider="homeFlight">
354
+ <sonic-input name="captain" label="Captain" value="André Turcat"></sonic-input>
355
+ </div>
356
+ ${codeBlock(bindSnippet, "html", "instr-code")}
357
+ </div>
358
+ <div class="instr-block" data-reveal>
359
+ <p class="instr-claim">Restyle with a handful of tokens.</p>
360
+ <p class="instr-text">
361
+ Palette, typeface and radius are CSS custom properties. Swap them
362
+ and every component in the panel follows.
363
+ </p>
364
+ <sonic-group size="sm">
365
+ ${themes.map(
366
+ (t, i) => html`<sonic-button
367
+ type=${i === this.theme ? "primary" : "default"}
368
+ aria-pressed=${i === this.theme ? "true" : "false"}
369
+ @click=${() => (this.theme = i)}
370
+ >${t.name}</sonic-button
371
+ >`,
372
+ )}
373
+ </sonic-group>
374
+ </div>
375
+ <div class="instr-block" data-reveal>
376
+ <p class="instr-claim">Render screens from JSON.</p>
377
+ <p class="instr-text">
378
+ The server sends the JSON below; sonic-sdui draws it with the same components. Flip the switch to push it to the board.
379
+ </p>
380
+ <sonic-switch @click=${this.syncGate}
381
+ >Push a gate change from the server</sonic-switch
382
+ >
383
+ ${codeBlock(gateJson, "json", "instr-code")}
384
+ </div>
385
+ <div class="instr-block" data-reveal>
386
+ <p class="instr-claim">Drop the same tag in any stack.</p>
387
+ <p class="instr-text">
388
+ Standard custom elements: no wrapper per framework, no bundler
389
+ required on a legacy page.
390
+ </p>
391
+ <sonic-group size="sm">
392
+ ${hosts.map(
393
+ (h, i) => html`<sonic-button
394
+ type=${i === this.host ? "primary" : "default"}
395
+ aria-pressed=${i === this.host ? "true" : "false"}
396
+ @click=${() => (this.host = i)}
397
+ >${h.name}</sonic-button
398
+ >`,
399
+ )}
400
+ </sonic-group>
401
+ <div class="host-snippets">
402
+ ${hosts.map(
403
+ (h, i) => html`<div
404
+ class="host-snippet ${i === this.host ? "is-active" : ""}"
405
+ ?inert=${i !== this.host}
406
+ >
407
+ ${codeBlock(h.code, h.language, "instr-code")}
408
+ </div>`,
409
+ )}
410
+ </div>
411
+ </div>
412
+ </div>
413
+ </section>`;
414
+ }
415
+
416
+ private renderStory() {
417
+ return html`<section class="story" aria-labelledby="story-title">
418
+ <div class="letter">
419
+ <h2 id="story-title" class="section-title" data-reveal>Why we built it.</h2>
420
+ <div class="letter-body" data-reveal style="--d:90ms">
421
+ <p>
422
+ In 2022 we needed one ticketing stack for nearly a hundred sites:
423
+ mobile apps, modern front ends, and PHP pages that will never see a
424
+ bundler.
425
+ </p>
426
+ <p>
427
+ Writing the same booking form five times was not an option. We
428
+ wanted components that any of those pages could load and that
429
+ would still share their data with each other.
430
+ </p>
431
+ <p>
432
+ We chose Lit for its reach and web components for their
433
+ longevity, then moved the plumbing into attributes: data
434
+ providers, fetchers, forms and themes.
435
+ </p>
436
+ <p>
437
+ We named it after the aircraft that flew Paris to New York in
438
+ three and a half hours. Concorde is the library we run in
439
+ production every day, now open to you.
440
+ </p>
441
+ <p class="letter-sign">The Supersoniks team</p>
442
+ </div>
443
+ </div>
444
+ <figure class="story-figure settle">
445
+ <img
446
+ src="${ARCHIVE}concorde-001-2cv.webp"
447
+ width="3000"
448
+ height="1934"
449
+ alt="Concorde 001 on the apron, a yellow 2CV parked under its wing, photographers walking past"
450
+ loading="lazy"
451
+ decoding="async"
452
+ />
453
+ </figure>
454
+ </section>`;
455
+ }
456
+
457
+ private renderTakeoff() {
458
+ return html`<section class="takeoff" aria-labelledby="takeoff-title">
459
+ <div class="takeoff-copy">
460
+ <h2 id="takeoff-title" class="takeoff-title" data-reveal>
461
+ Take your project<br />supersonic.
462
+ </h2>
463
+ <p class="takeoff-lead" data-reveal style="--d:60ms">
464
+ One command scaffolds a Vite project with Concorde, Tailwind and
465
+ the agent skills, ready to build.
466
+ </p>
467
+ <div class="takeoff-code" data-reveal style="--d:120ms">
468
+ ${codeBlock(INSTALL, "bash", "takeoff-command")}
469
+ </div>
470
+ </div>
471
+ <figure class="takeoff-figure">
472
+ <video
473
+ src="${ARCHIVE}concorde-red-arrows-2002.webm"
474
+ poster="${ARCHIVE}concorde-red-arrows-2002-poster.jpg"
475
+ width="640"
476
+ height="360"
477
+ autoplay
478
+ muted
479
+ loop
480
+ playsinline
481
+ aria-label="Concorde flying in formation with the Red Arrows, 2002"
482
+ ></video>
483
+ </figure>
484
+ </section>`;
485
+ }
486
+
487
+ private renderFooter() {
488
+ return html`<footer class="home-footer">
489
+ <div class="footer-line">
490
+ <span>Concorde, web components by Supersoniks</span>
491
+ <nav class="footer-links" aria-label="Footer">
492
+ <sonic-link href=${GET_STARTED}>Docs</sonic-link>
493
+ <sonic-link href=${COMPONENTS_PAGE}>Components</sonic-link>
494
+ <sonic-link href="https://www.npmjs.com/package/@supersoniks/concorde" target="_blank"
495
+ >npm</sonic-link
496
+ >
497
+ </nav>
498
+ <span class="footer-end">MIT licence · ${new Date().getFullYear()}</span>
499
+ </div>
500
+ <p class="credits">${unsafeHTML(CREDITS)}</p>
501
+ </footer>`;
502
+ }
503
+
504
+ render() {
505
+ return html`<div class="docs-home">
506
+ ${this.renderHero()} ${this.renderManifesto()} ${this.renderIndex()}
507
+ ${this.renderInstruments()}
508
+ ${this.renderStory()} ${this.renderTakeoff()}
509
+ ${this.renderFooter()}
510
+ </div>`;
511
+ }
512
+ }
513
+