@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.
- package/.claude/launch.json +15 -0
- package/.claude/vite.http.config.mjs +7 -0
- package/.taste-skill/after/desktop-fold.jpg +0 -0
- package/.taste-skill/after/desktop-page-01.jpg +0 -0
- package/.taste-skill/after/desktop-page-02.jpg +0 -0
- package/.taste-skill/after/desktop-page-03.jpg +0 -0
- package/.taste-skill/after/mobile-fold.jpg +0 -0
- package/.taste-skill/after/mobile-page-01.jpg +0 -0
- package/.taste-skill/after/report.json +4103 -0
- package/.taste-skill/after/tablet-fold.jpg +0 -0
- package/.taste-skill/after/tablet-page-01.jpg +0 -0
- package/.taste-skill/after/tablet-page-02.jpg +0 -0
- package/.taste-skill/before/desktop-fold.jpg +0 -0
- package/.taste-skill/before/desktop-page-01.jpg +0 -0
- package/.taste-skill/before/desktop-page-02.jpg +0 -0
- package/.taste-skill/before/mobile-fold.jpg +0 -0
- package/.taste-skill/before/mobile-page-01.jpg +0 -0
- package/.taste-skill/before/report.json +2556 -0
- package/.taste-skill/before/tablet-fold.jpg +0 -0
- package/.taste-skill/before/tablet-page-01.jpg +0 -0
- package/.taste-skill/direction.json +510 -0
- package/.taste-skill/notes.md +84 -0
- package/.taste-skill/prod/desktop-fold.jpg +0 -0
- package/.taste-skill/prod/desktop-page-01.jpg +0 -0
- package/.taste-skill/prod/desktop-page-02.jpg +0 -0
- package/.taste-skill/prod/desktop-page-03.jpg +0 -0
- package/.taste-skill/prod/mobile-fold.jpg +0 -0
- package/.taste-skill/prod/mobile-page-01.jpg +0 -0
- package/.taste-skill/prod/mobile-page-02.jpg +0 -0
- package/.taste-skill/prod/report.json +1973 -0
- package/.taste-skill/prod/tablet-fold.jpg +0 -0
- package/.taste-skill/prod/tablet-page-01.jpg +0 -0
- package/.taste-skill/prod/tablet-page-02.jpg +0 -0
- package/.tmp-cem/custom-elements.json +13705 -0
- package/AUDIT.md +228 -0
- package/PLAN-AMELIORATION.md +220 -0
- package/build-infos.json +1 -1
- package/concorde-core.bundle.js +196 -196
- package/concorde-core.es.js +3854 -3572
- package/custom-elements-manifest.config.mjs +14 -0
- package/dist/concorde-core.bundle.js +196 -196
- package/dist/concorde-core.es.js +3854 -3572
- package/dist/img/archive/concorde-001-2cv.webp +0 -0
- package/dist/img/archive/concorde-red-arrows-2002-poster.jpg +0 -0
- package/dist/img/archive/concorde-red-arrows-2002.webm +0 -0
- package/dist/img/archive/credits.json +28 -0
- package/docs/assets/index-Bb-_LRyY.js +12280 -0
- package/docs/index.html +1 -1
- package/index.html +27 -63
- package/package.json +44 -3
- package/public/img/archive/concorde-001-2cv.webp +0 -0
- package/public/img/archive/concorde-red-arrows-2002-poster.jpg +0 -0
- package/public/img/archive/concorde-red-arrows-2002.webm +0 -0
- package/public/img/archive/credits.json +28 -0
- package/scripts/generate-sdui-catalog.mjs +250 -0
- package/scripts/generate-sdui-catalog.spec.ts +91 -0
- package/scripts/pre-build.mjs +15 -0
- package/src/core/components/functional/fetch/fetch.md +2 -2
- package/src/core/components/functional/sdui/SDUIDescriptorTransformer.ts +5 -5
- package/src/core/components/functional/sdui/__fixtures__/descriptors.ts +251 -0
- package/src/core/components/functional/sdui/__snapshots__/sdui-action.spec.ts.snap +73 -0
- package/src/core/components/functional/sdui/__snapshots__/sdui-incremental.spec.ts.snap +50 -0
- package/src/core/components/functional/sdui/__snapshots__/sdui-partial.spec.ts.snap +50 -0
- package/src/core/components/functional/sdui/__snapshots__/sdui.regression.spec.ts.snap +461 -0
- package/src/core/components/functional/sdui/component-catalog.gaps.json +511 -0
- package/src/core/components/functional/sdui/component-catalog.json +3103 -0
- package/src/core/components/functional/sdui/component-catalog.spec.ts +23 -0
- package/src/core/components/functional/sdui/sdui-action.spec.ts +99 -0
- package/src/core/components/functional/sdui/sdui-dom-snapshot.ts +61 -0
- package/src/core/components/functional/sdui/sdui-extension-points.md +94 -0
- package/src/core/components/functional/sdui/sdui-incremental.spec.ts +137 -0
- package/src/core/components/functional/sdui/sdui-partial.spec.ts +83 -0
- package/src/core/components/functional/sdui/sdui-partial.ts +19 -0
- package/src/core/components/functional/sdui/sdui-safe.spec.ts +188 -0
- package/src/core/components/functional/sdui/sdui-safe.ts +100 -0
- package/src/core/components/functional/sdui/sdui.md +122 -0
- package/src/core/components/functional/sdui/sdui.regression.spec.ts +64 -0
- package/src/core/components/functional/sdui/sdui.ts +442 -34
- package/src/core/components/functional/sdui/types.ts +49 -0
- package/src/core/components/ui/modal/modal.ts +14 -11
- package/src/docs/_getting-started/components.md +5 -0
- package/src/docs/_getting-started/theming.md +2 -2
- package/src/docs/code.ts +88 -75
- package/src/docs/components/docs-demo-sources.ts +16 -8
- package/src/docs/components/docs-lit-demo.ts +19 -37
- package/src/docs/docs.ts +5 -0
- package/src/docs/example/docs-boarding-pass-demo.ts +134 -0
- package/src/docs/example/docs-provider-keys.ts +12 -0
- package/src/docs/header/header.ts +233 -69
- package/src/docs/home/catalog.ts +44 -0
- package/src/docs/home/home.ts +513 -0
- package/src/docs/home/mach-stage.ts +389 -0
- package/src/docs/layout.ts +3 -1
- package/src/docs/navigation/components-index.ts +56 -0
- package/src/docs/navigation/navigation.ts +240 -232
- package/src/docs/navigation/pager.ts +67 -0
- package/src/docs/navigation/toc.ts +98 -0
- package/src/docs/search/docs-search.json +330 -20
- package/src/docs/search/markdown-renderer.ts +11 -3
- package/src/docs/shiki/index.ts +109 -0
- package/src/docs/tailwind/css/base/scrollbar.css +22 -0
- package/src/docs/tailwind/css/base/theme.css +96 -0
- package/src/docs/tailwind/css/base/typography.css +4 -0
- package/src/docs/tailwind/css/docs/boarding-pass.css +65 -0
- package/src/docs/tailwind/css/docs/content.css +32 -0
- package/src/docs/tailwind/css/docs/page.css +10 -0
- package/src/docs/tailwind/css/docs.css +9 -0
- package/src/docs/tailwind/css/home/hero.css +210 -0
- package/src/docs/tailwind/css/home/motion.css +84 -0
- package/src/docs/tailwind/css/home/sections.css +416 -0
- package/src/docs/tailwind/css/tailwind.css +7 -185
- package/src/tsconfig.json +113 -2
- package/src/tsconfig.tsbuildinfo +1 -1
- package/tailwind.config.js +8 -4
- package/docs/assets/index-wVZpLVYW.js +0 -12122
- package/docs/crawl/core/components/functional/date/date.html +0 -190
- package/docs/crawl/core/components/functional/fetch/fetch.html +0 -109
- package/docs/crawl/core/components/functional/if/if.html +0 -27
- package/docs/crawl/core/components/functional/jsonata/jsonata.html +0 -79
- package/docs/crawl/core/components/functional/list/list.html +0 -70
- package/docs/crawl/core/components/functional/mix/mix.html +0 -45
- package/docs/crawl/core/components/functional/queue/queue.html +0 -96
- package/docs/crawl/core/components/functional/router/router.html +0 -106
- package/docs/crawl/core/components/functional/sdui/sdui.html +0 -269
- package/docs/crawl/core/components/functional/states/states.html +0 -66
- package/docs/crawl/core/components/functional/submit/submit.html +0 -160
- package/docs/crawl/core/components/functional/subscriber/subscriber.html +0 -67
- package/docs/crawl/core/components/functional/value/value.html +0 -51
- package/docs/crawl/core/components/ui/alert/alert.html +0 -211
- package/docs/crawl/core/components/ui/alert-messages/alert-messages.html +0 -131
- package/docs/crawl/core/components/ui/badge/badge.html +0 -197
- package/docs/crawl/core/components/ui/button/button.html +0 -150
- package/docs/crawl/core/components/ui/captcha/captcha.html +0 -112
- package/docs/crawl/core/components/ui/card/card.html +0 -253
- package/docs/crawl/core/components/ui/divider/divider.html +0 -144
- package/docs/crawl/core/components/ui/form/checkbox/checkbox.html +0 -73
- package/docs/crawl/core/components/ui/form/fieldset/fieldset.html +0 -266
- package/docs/crawl/core/components/ui/form/form-actions/form-actions.html +0 -122
- package/docs/crawl/core/components/ui/form/form-layout/form-layout.html +0 -121
- package/docs/crawl/core/components/ui/form/input/input.html +0 -109
- package/docs/crawl/core/components/ui/form/input-autocomplete/input-autocomplete.html +0 -38
- package/docs/crawl/core/components/ui/form/radio/radio.html +0 -56
- package/docs/crawl/core/components/ui/form/select/select.html +0 -73
- package/docs/crawl/core/components/ui/form/switch/switch.html +0 -56
- package/docs/crawl/core/components/ui/form/textarea/textarea.html +0 -59
- package/docs/crawl/core/components/ui/group/group.html +0 -104
- package/docs/crawl/core/components/ui/icon/icon.html +0 -222
- package/docs/crawl/core/components/ui/image/image.html +0 -298
- package/docs/crawl/core/components/ui/link/link.html +0 -100
- package/docs/crawl/core/components/ui/loader/loader.html +0 -124
- package/docs/crawl/core/components/ui/menu/menu.html +0 -394
- package/docs/crawl/core/components/ui/modal/modal.html +0 -342
- package/docs/crawl/core/components/ui/pop/pop.html +0 -296
- package/docs/crawl/core/components/ui/progress/progress.html +0 -131
- package/docs/crawl/core/components/ui/table/table.html +0 -545
- package/docs/crawl/core/components/ui/theme/theme.html +0 -131
- package/docs/crawl/core/components/ui/toast/toast.html +0 -233
- package/docs/crawl/core/components/ui/tooltip/tooltip.html +0 -140
- package/docs/crawl/docs/_core-concept/dataFlow.html +0 -177
- package/docs/crawl/docs/_core-concept/overview.html +0 -66
- package/docs/crawl/docs/_core-concept/subscriber.html +0 -75
- package/docs/crawl/docs/_decorators/ancestor-attribute.html +0 -117
- package/docs/crawl/docs/_decorators/auto-subscribe.html +0 -202
- package/docs/crawl/docs/_decorators/bind.html +0 -141
- package/docs/crawl/docs/_decorators/get.html +0 -149
- package/docs/crawl/docs/_decorators/handle.html +0 -165
- package/docs/crawl/docs/_decorators/on-assign.html +0 -355
- package/docs/crawl/docs/_decorators/patch.html +0 -78
- package/docs/crawl/docs/_decorators/post.html +0 -139
- package/docs/crawl/docs/_decorators/publish.html +0 -61
- package/docs/crawl/docs/_decorators/put.html +0 -78
- package/docs/crawl/docs/_decorators/subscribe.html +0 -109
- package/docs/crawl/docs/_decorators/wait-for-ancestors.html +0 -137
- package/docs/crawl/docs/_directives/sub.html +0 -93
- package/docs/crawl/docs/_getting-started/ai-agents.html +0 -173
- package/docs/crawl/docs/_getting-started/concorde-manual-install.html +0 -100
- package/docs/crawl/docs/_getting-started/concorde-outside.html +0 -58
- package/docs/crawl/docs/_getting-started/create-a-component.html +0 -111
- package/docs/crawl/docs/_getting-started/my-first-component.html +0 -189
- package/docs/crawl/docs/_getting-started/my-first-subscriber.html +0 -110
- package/docs/crawl/docs/_getting-started/pubsub.html +0 -62
- package/docs/crawl/docs/_getting-started/start.html +0 -76
- package/docs/crawl/docs/_getting-started/theming.html +0 -333
- package/docs/crawl/docs/_misc/api-configuration.html +0 -149
- package/docs/crawl/docs/_misc/dataProviderKey.html +0 -135
- package/docs/crawl/docs/_misc/docs-mock-api.html +0 -158
- package/docs/crawl/docs/_misc/dynamic-path.html +0 -180
- package/docs/crawl/docs/_misc/endpoint.html +0 -50
- package/docs/crawl/docs/_misc/formelement-subscriber-removal.html +0 -138
- package/docs/crawl/docs/_misc/html-integration.html +0 -48
- package/docs/crawl/hubs/decorators.html +0 -547
- package/docs/crawl/hubs/form-components.html +0 -381
- package/docs/crawl/hubs/remote-data.html +0 -452
- package/docs/crawl/index.html +0 -102
- package/docs/llms-full.txt +0 -7008
- package/docs/llms.txt +0 -97
- package/docs/sitemap.xml +0 -240
- package/docs/src/core/components/functional/date/date.md +0 -290
- package/docs/src/core/components/functional/fetch/fetch.md +0 -125
- package/docs/src/core/components/functional/if/if.md +0 -9
- package/docs/src/core/components/functional/jsonata/jsonata.md +0 -56
- package/docs/src/core/components/functional/list/list.md +0 -65
- package/docs/src/core/components/functional/mix/mix.md +0 -41
- package/docs/src/core/components/functional/queue/queue.md +0 -72
- package/docs/src/core/components/functional/router/router.md +0 -94
- package/docs/src/core/components/functional/sdui/default-library.json +0 -108
- package/docs/src/core/components/functional/sdui/example.json +0 -99
- package/docs/src/core/components/functional/sdui/sdui.md +0 -356
- package/docs/src/core/components/functional/states/states.md +0 -87
- package/docs/src/core/components/functional/submit/submit.md +0 -114
- package/docs/src/core/components/functional/subscriber/subscriber.md +0 -91
- package/docs/src/core/components/functional/value/value.md +0 -35
- package/docs/src/core/components/ui/alert/alert.md +0 -196
- package/docs/src/core/components/ui/alert-messages/alert-messages.md +0 -85
- package/docs/src/core/components/ui/badge/badge.md +0 -188
- package/docs/src/core/components/ui/button/button.md +0 -183
- package/docs/src/core/components/ui/captcha/captcha.md +0 -71
- package/docs/src/core/components/ui/card/card.md +0 -215
- package/docs/src/core/components/ui/divider/divider.md +0 -129
- package/docs/src/core/components/ui/form/checkbox/checkbox.md +0 -77
- package/docs/src/core/components/ui/form/fieldset/fieldset.md +0 -205
- package/docs/src/core/components/ui/form/form-actions/form-actions.md +0 -100
- package/docs/src/core/components/ui/form/form-layout/form-layout.md +0 -119
- package/docs/src/core/components/ui/form/input/input.md +0 -142
- package/docs/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +0 -29
- package/docs/src/core/components/ui/form/radio/radio.md +0 -57
- package/docs/src/core/components/ui/form/select/select.md +0 -71
- package/docs/src/core/components/ui/form/switch/switch.md +0 -57
- package/docs/src/core/components/ui/form/textarea/textarea.md +0 -65
- package/docs/src/core/components/ui/group/group.md +0 -75
- package/docs/src/core/components/ui/icon/icon.md +0 -214
- package/docs/src/core/components/ui/icon/icons.json +0 -1
- package/docs/src/core/components/ui/image/image.md +0 -233
- package/docs/src/core/components/ui/link/link.md +0 -81
- package/docs/src/core/components/ui/loader/loader.md +0 -112
- package/docs/src/core/components/ui/menu/menu.md +0 -370
- package/docs/src/core/components/ui/modal/modal.md +0 -235
- package/docs/src/core/components/ui/pop/pop.md +0 -294
- package/docs/src/core/components/ui/progress/progress.md +0 -109
- package/docs/src/core/components/ui/table/table.md +0 -431
- package/docs/src/core/components/ui/theme/theme.md +0 -122
- package/docs/src/core/components/ui/toast/toast.md +0 -216
- package/docs/src/core/components/ui/tooltip/tooltip.md +0 -124
- package/docs/src/docs/_core-concept/dataFlow.md +0 -88
- package/docs/src/docs/_core-concept/overview.md +0 -57
- package/docs/src/docs/_core-concept/subscriber.md +0 -75
- package/docs/src/docs/_decorators/ancestor-attribute.md +0 -128
- package/docs/src/docs/_decorators/auto-subscribe.md +0 -202
- package/docs/src/docs/_decorators/bind.md +0 -167
- package/docs/src/docs/_decorators/get.md +0 -162
- package/docs/src/docs/_decorators/handle.md +0 -175
- package/docs/src/docs/_decorators/on-assign.md +0 -390
- package/docs/src/docs/_decorators/patch.md +0 -70
- package/docs/src/docs/_decorators/post.md +0 -146
- package/docs/src/docs/_decorators/publish.md +0 -55
- package/docs/src/docs/_decorators/put.md +0 -70
- package/docs/src/docs/_decorators/subscribe.md +0 -100
- package/docs/src/docs/_decorators/wait-for-ancestors.md +0 -163
- package/docs/src/docs/_directives/sub.md +0 -91
- package/docs/src/docs/_getting-started/ai-agents.md +0 -76
- package/docs/src/docs/_getting-started/concorde-manual-install.md +0 -133
- package/docs/src/docs/_getting-started/concorde-outside.md +0 -33
- package/docs/src/docs/_getting-started/create-a-component.md +0 -139
- package/docs/src/docs/_getting-started/my-first-component.md +0 -236
- package/docs/src/docs/_getting-started/my-first-subscriber.md +0 -120
- package/docs/src/docs/_getting-started/pubsub.md +0 -37
- package/docs/src/docs/_getting-started/start.md +0 -47
- package/docs/src/docs/_getting-started/theming.md +0 -253
- package/docs/src/docs/_misc/api-configuration.md +0 -81
- package/docs/src/docs/_misc/dataProviderKey.md +0 -168
- package/docs/src/docs/_misc/docs-mock-api.md +0 -63
- package/docs/src/docs/_misc/dynamic-path.md +0 -71
- package/docs/src/docs/_misc/endpoint.md +0 -45
- package/docs/src/docs/_misc/formelement-subscriber-removal.md +0 -115
- package/docs/src/docs/_misc/html-integration.md +0 -15
- package/docs/src/docs/search/docs-search.json +0 -12242
- package/docs/src/tag-list.json +0 -1
- package/docs/src/tsconfig-model.json +0 -23
- package/docs/src/tsconfig.json +0 -1242
- package/src/docs/prism/index.ts +0 -6
- package/src/docs/prism/prism.css +0 -158
- package/src/docs/prism/prism.js +0 -1022
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { LitElement, html } from "lit";
|
|
2
|
+
import { customElement } from "lit/decorators.js";
|
|
3
|
+
|
|
4
|
+
/** The Concorde silhouette from the brand icon, nose up, in a 66 × 66 box centred on (33, 33). */
|
|
5
|
+
const PLANE =
|
|
6
|
+
"M33.2499 62.03C33.8799 59.24 34.26 56.17 34.39 53.08C34.57 52.78 34.9099 52.6 35.2599 52.64H35.39C35.48 52.64 35.5799 52.64 35.6899 52.64H35.7599C35.7599 52.64 35.7999 52.64 35.8299 52.64C36.2499 52.62 36.6799 52.58 36.9099 52.56C36.9399 52.56 36.9599 52.56 36.9799 52.56C37.0099 52.56 37.0299 52.56 37.0499 52.56H37.0899L37.2099 51.93H37.4799L37.5799 52.4L37.6899 52.49H39.2699L39.39 52.38L39.5099 51.93H39.7899L39.8399 52.21L39.9999 52.29L45.2099 51.86L46.2799 51.29C46.2799 51.29 46.2799 50.85 46.2399 50.25V50.18C46.2399 50.18 46.2399 50.13 46.2399 50.11C46.2099 49.62 46.1399 49.13 46.0399 48.65C45.7899 47.45 45.29 46 42.2 41.58C39.11 37.16 38.04 35.52 35.89 27.63C35.85 27.48 35.8199 27.35 35.7899 27.2C35.1399 24.53 34.6899 22.95 34.5199 22.38V10.89C34.4999 9.60996 34.3999 8.33996 34.2099 7.07996C34.0499 5.97996 33.6099 4.89996 33.3499 3.95996H32.6299C32.3599 4.89996 31.9299 5.97996 31.7699 7.06996C31.5799 8.33996 31.4799 9.60996 31.4599 10.89V22.38C31.2899 22.95 30.8299 24.52 30.1899 27.2C30.1599 27.35 30.1199 27.49 30.0899 27.63C27.9499 35.52 26.8699 37.16 23.7799 41.58C20.6899 46 20.1899 47.45 19.9399 48.65C19.8399 49.13 19.7799 49.62 19.7399 50.11C19.7399 50.13 19.7399 50.16 19.7399 50.18V50.25C19.6999 50.85 19.7 51.29 19.7 51.29L20.7699 51.86L25.9799 52.29L26.14 52.21L26.1899 51.93H26.4799L26.5999 52.38L26.7299 52.49H28.2999L28.4099 52.4L28.5099 51.93H28.7699L28.89 52.56H28.9399C28.9399 52.56 28.9799 52.56 29.0099 52.56C29.0299 52.56 29.0499 52.56 29.0799 52.56C29.3099 52.58 29.7499 52.63 30.1599 52.64C30.1799 52.64 30.2099 52.64 30.2299 52.64H30.2999C30.4099 52.64 30.5099 52.64 30.5999 52.64H30.7299C31.0799 52.6 31.4299 52.77 31.6099 53.08C31.7299 56.17 32.1099 59.24 32.7399 62.03H33.2499Z";
|
|
7
|
+
|
|
8
|
+
/** Speed of sound on the stage, in stage widths per second. */
|
|
9
|
+
const SOUND = 0.19;
|
|
10
|
+
/** Cruise: Concorde flew at Mach 2.02, 18 000 m up. */
|
|
11
|
+
const CRUISE = 2.02;
|
|
12
|
+
/** Grid cells across the field; every fourth line is heavier. */
|
|
13
|
+
const GRID = 24;
|
|
14
|
+
const WAVE_EVERY = 0.05;
|
|
15
|
+
const WAVE_LIFE = 2.6;
|
|
16
|
+
|
|
17
|
+
const clamp = (v: number, lo: number, hi: number) =>
|
|
18
|
+
Math.min(hi, Math.max(lo, v));
|
|
19
|
+
const smooth = (a: number, b: number, v: number) => {
|
|
20
|
+
const t = clamp((v - a) / (b - a), 0, 1);
|
|
21
|
+
return t * t * (3 - 2 * t);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type Wave = { x: number; y: number; t: number };
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The hero's orange field as a Mach diagram: the aircraft drops a sound wave as it flies and,
|
|
28
|
+
* once it outruns them, the waves pile into the shock cone. On autopilot it accelerates through
|
|
29
|
+
* the barrier on every pass; a moving pointer steers it and moving fast
|
|
30
|
+
* enough breaks the barrier by hand. Reduced motion gets one still frame at cruise.
|
|
31
|
+
*/
|
|
32
|
+
@customElement("docs-mach-stage")
|
|
33
|
+
export class DocsMachStage extends LitElement {
|
|
34
|
+
private canvas?: HTMLCanvasElement;
|
|
35
|
+
private ints: HTMLElement[] = [];
|
|
36
|
+
private decs: HTMLElement[] = [];
|
|
37
|
+
private plane = new Path2D(PLANE);
|
|
38
|
+
private waves: Wave[] = [];
|
|
39
|
+
private x = -0.3;
|
|
40
|
+
private y = 0.55;
|
|
41
|
+
private vx = 0.75 * SOUND;
|
|
42
|
+
private vy = 0;
|
|
43
|
+
private mach = 0;
|
|
44
|
+
private time = 0;
|
|
45
|
+
private lastWave = 0;
|
|
46
|
+
private pointer: { x: number; y: number; t: number } | null = null;
|
|
47
|
+
private boom = -10;
|
|
48
|
+
private frame = 0;
|
|
49
|
+
private last = 0;
|
|
50
|
+
private resize?: ResizeObserver;
|
|
51
|
+
private visible = true;
|
|
52
|
+
private io?: IntersectionObserver;
|
|
53
|
+
|
|
54
|
+
createRenderRoot() {
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
render() {
|
|
59
|
+
return html`<canvas class="mach-canvas" aria-hidden="true"></canvas>
|
|
60
|
+
<p class="mach-readout" aria-label="Concorde cruise speed: Mach 2.02">
|
|
61
|
+
<span class="mach-label">mach</span>
|
|
62
|
+
<span class="mach-value">
|
|
63
|
+
${[
|
|
64
|
+
"mach-layer",
|
|
65
|
+
"mach-layer mach-ghost-a",
|
|
66
|
+
"mach-layer mach-ghost-b",
|
|
67
|
+
].map(
|
|
68
|
+
(layer, i) =>
|
|
69
|
+
html`<span class=${layer} aria-hidden=${i ? "true" : "false"}
|
|
70
|
+
><span class="mach-int">0</span><span class="mach-dot">.</span
|
|
71
|
+
><span class="mach-dec">00</span></span
|
|
72
|
+
>`,
|
|
73
|
+
)}
|
|
74
|
+
</span>
|
|
75
|
+
</p>
|
|
76
|
+
<p class="mach-note">
|
|
77
|
+
cruise mach 2.02 · 18 000 m · paris – new york in 3 h 30
|
|
78
|
+
</p>`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
firstUpdated() {
|
|
82
|
+
this.canvas = this.querySelector("canvas")!;
|
|
83
|
+
this.ints = [...this.querySelectorAll<HTMLElement>(".mach-int")];
|
|
84
|
+
this.decs = [...this.querySelectorAll<HTMLElement>(".mach-dec")];
|
|
85
|
+
this.resize = new ResizeObserver(() => this.fit());
|
|
86
|
+
this.resize.observe(this);
|
|
87
|
+
this.io = new IntersectionObserver(
|
|
88
|
+
([e]) => (this.visible = e.isIntersecting),
|
|
89
|
+
);
|
|
90
|
+
this.io.observe(this);
|
|
91
|
+
this.addEventListener("pointermove", this.onPointer);
|
|
92
|
+
this.addEventListener("pointerdown", this.onPointer);
|
|
93
|
+
this.addEventListener("pointerleave", this.onLeave);
|
|
94
|
+
this.fit();
|
|
95
|
+
if (matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
96
|
+
this.still();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this.frame = requestAnimationFrame(this.tick);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
disconnectedCallback() {
|
|
103
|
+
super.disconnectedCallback();
|
|
104
|
+
cancelAnimationFrame(this.frame);
|
|
105
|
+
this.resize?.disconnect();
|
|
106
|
+
this.io?.disconnect();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private onPointer = (e: PointerEvent) => {
|
|
110
|
+
const r = this.getBoundingClientRect();
|
|
111
|
+
this.pointer = {
|
|
112
|
+
x: (e.clientX - r.left) / r.width,
|
|
113
|
+
y: (e.clientY - r.top) / r.width,
|
|
114
|
+
t: this.time,
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
private onLeave = () => {
|
|
119
|
+
this.pointer = null;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
private fit() {
|
|
123
|
+
const c = this.canvas!;
|
|
124
|
+
const dpr = Math.min(devicePixelRatio || 1, 2);
|
|
125
|
+
c.width = Math.round(this.clientWidth * dpr);
|
|
126
|
+
c.height = Math.round(this.clientHeight * dpr);
|
|
127
|
+
// publish the grid cell so the field's bevel can be cut along the grid
|
|
128
|
+
this.parentElement?.style.setProperty(
|
|
129
|
+
"--mach-cell",
|
|
130
|
+
`${this.clientWidth / GRID}px`,
|
|
131
|
+
);
|
|
132
|
+
if (matchMedia("(prefers-reduced-motion: reduce)").matches) this.still();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Height of the field in stage widths (positions are kept in widths so speed is uniform). */
|
|
136
|
+
private get aspect() {
|
|
137
|
+
return this.clientHeight / Math.max(1, this.clientWidth);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private tick = (now: number) => {
|
|
141
|
+
this.frame = requestAnimationFrame(this.tick);
|
|
142
|
+
const dt = Math.min(0.05, (now - (this.last || now)) / 1000);
|
|
143
|
+
this.last = now;
|
|
144
|
+
if (!this.visible || !dt) return;
|
|
145
|
+
this.time += dt;
|
|
146
|
+
this.fly(dt);
|
|
147
|
+
if (this.time - this.lastWave > WAVE_EVERY) {
|
|
148
|
+
this.lastWave = this.time;
|
|
149
|
+
this.waves.push({ x: this.x, y: this.y, t: this.time });
|
|
150
|
+
}
|
|
151
|
+
this.waves = this.waves.filter((w) => this.time - w.t < WAVE_LIFE);
|
|
152
|
+
this.draw();
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
private fly(dt: number) {
|
|
156
|
+
const h = this.aspect;
|
|
157
|
+
const before = this.mach;
|
|
158
|
+
// flown by heading and speed, never by position, so it always carries on along an arc
|
|
159
|
+
let speed = Math.hypot(this.vx, this.vy);
|
|
160
|
+
let heading = Math.atan2(this.vy, this.vx);
|
|
161
|
+
let wantSpeed: number;
|
|
162
|
+
let wantHeading: number;
|
|
163
|
+
let turn: number;
|
|
164
|
+
let throttle: number;
|
|
165
|
+
const steering = this.pointer && this.time - this.pointer.t < 0.4;
|
|
166
|
+
if (steering) {
|
|
167
|
+
// head for a moving pointer; the further ahead it runs, the faster the aircraft goes
|
|
168
|
+
const dx = this.pointer!.x - this.x;
|
|
169
|
+
const dy = this.pointer!.y - this.y;
|
|
170
|
+
wantHeading = Math.atan2(dy, dx);
|
|
171
|
+
wantSpeed = clamp(Math.hypot(dx, dy) * 2.5, 0.6 * SOUND, 2.4 * SOUND);
|
|
172
|
+
turn = 5;
|
|
173
|
+
throttle = 4;
|
|
174
|
+
} else {
|
|
175
|
+
// autopilot: endless passes, speeding up to cruise across the field and easing off
|
|
176
|
+
// while out of sight, so each pass hands over to the next without a cut
|
|
177
|
+
const up = smooth(-0.1, 0.65, this.x);
|
|
178
|
+
const down = smooth(1.0, 1.2, this.x);
|
|
179
|
+
wantSpeed = (0.6 + (CRUISE - 0.6) * up * (1 - down)) * SOUND;
|
|
180
|
+
const cy = h * 0.55 + Math.sin(this.time * 0.6) * h * 0.06;
|
|
181
|
+
wantHeading = Math.atan2(cy - this.y, 0.6);
|
|
182
|
+
turn = 2;
|
|
183
|
+
throttle = 2;
|
|
184
|
+
}
|
|
185
|
+
let delta = wantHeading - heading;
|
|
186
|
+
delta = Math.atan2(Math.sin(delta), Math.cos(delta));
|
|
187
|
+
heading += delta * Math.min(1, dt * turn);
|
|
188
|
+
speed += (wantSpeed - speed) * Math.min(1, dt * throttle);
|
|
189
|
+
this.vx = Math.cos(heading) * speed;
|
|
190
|
+
this.vy = Math.sin(heading) * speed;
|
|
191
|
+
this.x += this.vx * dt;
|
|
192
|
+
this.y += this.vy * dt;
|
|
193
|
+
// out of sight on the right, back in on the left; the old waves fade where they were left
|
|
194
|
+
if (!steering && this.x > 1.3) this.x -= 1.6;
|
|
195
|
+
this.mach = speed / SOUND;
|
|
196
|
+
if (before < 1 && this.mach >= 1) this.boom = this.time;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private colours() {
|
|
200
|
+
const s = getComputedStyle(this);
|
|
201
|
+
return { ink: s.color, field: s.backgroundColor };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
private draw() {
|
|
205
|
+
const c = this.canvas!;
|
|
206
|
+
const g = c.getContext("2d")!;
|
|
207
|
+
const W = c.width;
|
|
208
|
+
const u = W; // one stage width in device pixels
|
|
209
|
+
const { ink } = this.colours();
|
|
210
|
+
g.clearRect(0, 0, c.width, c.height);
|
|
211
|
+
g.strokeStyle = ink;
|
|
212
|
+
g.fillStyle = ink;
|
|
213
|
+
const px = this.x * u;
|
|
214
|
+
const py = this.y * u;
|
|
215
|
+
|
|
216
|
+
// graph paper under the diagram: a fine square grid, every fourth line heavier
|
|
217
|
+
const cell = u / GRID;
|
|
218
|
+
g.lineWidth = Math.max(1, u * 0.0008);
|
|
219
|
+
for (let i = 0, x = 0; x <= c.width; i++, x += cell) {
|
|
220
|
+
g.globalAlpha = i % 4 ? 0.1 : 0.22;
|
|
221
|
+
g.beginPath();
|
|
222
|
+
g.moveTo(Math.round(x) + 0.5, 0);
|
|
223
|
+
g.lineTo(Math.round(x) + 0.5, c.height);
|
|
224
|
+
g.stroke();
|
|
225
|
+
}
|
|
226
|
+
for (let i = 0, y = 0; y <= c.height; i++, y += cell) {
|
|
227
|
+
g.globalAlpha = i % 4 ? 0.1 : 0.22;
|
|
228
|
+
g.beginPath();
|
|
229
|
+
g.moveTo(0, Math.round(y) + 0.5);
|
|
230
|
+
g.lineTo(c.width, Math.round(y) + 0.5);
|
|
231
|
+
g.stroke();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// the shock cone, filled, once supersonic
|
|
235
|
+
if (this.mach > 1.02) {
|
|
236
|
+
const mu = Math.asin(1 / this.mach);
|
|
237
|
+
const dir = Math.atan2(this.vy, this.vx);
|
|
238
|
+
const len = u * 2;
|
|
239
|
+
g.globalAlpha = Math.min(0.22, (this.mach - 1) * 0.35);
|
|
240
|
+
g.beginPath();
|
|
241
|
+
g.moveTo(px, py);
|
|
242
|
+
g.lineTo(px - Math.cos(dir - mu) * len, py - Math.sin(dir - mu) * len);
|
|
243
|
+
g.lineTo(px - Math.cos(dir + mu) * len, py - Math.sin(dir + mu) * len);
|
|
244
|
+
g.closePath();
|
|
245
|
+
g.fill();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// the waves: each one a circle growing at the speed of sound from where it was dropped
|
|
249
|
+
g.lineWidth = Math.max(2, u * 0.003);
|
|
250
|
+
for (const w of this.waves) {
|
|
251
|
+
const age = this.time - w.t;
|
|
252
|
+
const r = age * SOUND * u;
|
|
253
|
+
g.globalAlpha = Math.max(0, 1 - age / WAVE_LIFE) * 0.9;
|
|
254
|
+
g.beginPath();
|
|
255
|
+
g.arc(w.x * u, w.y * u, r, 0, Math.PI * 2);
|
|
256
|
+
g.stroke();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
this.construct(g, u, px, py);
|
|
260
|
+
|
|
261
|
+
// the boom: one heavy ring when the barrier goes
|
|
262
|
+
const since = this.time - this.boom;
|
|
263
|
+
if (since >= 0 && since < 1.4) {
|
|
264
|
+
g.globalAlpha = 1 - since / 1.4;
|
|
265
|
+
g.lineWidth = u * 0.018 * (1 - since / 1.4) + 2;
|
|
266
|
+
g.beginPath();
|
|
267
|
+
g.arc(px, py, since * SOUND * u * 3.2, 0, Math.PI * 2);
|
|
268
|
+
g.stroke();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// the aircraft, pointing where it flies
|
|
272
|
+
g.globalAlpha = 1;
|
|
273
|
+
const size = u * 0.15;
|
|
274
|
+
g.save();
|
|
275
|
+
g.translate(px, py);
|
|
276
|
+
g.rotate(Math.atan2(this.vy, this.vx) + Math.PI / 2);
|
|
277
|
+
g.scale(size / 66, size / 66);
|
|
278
|
+
g.translate(-33, -33);
|
|
279
|
+
g.fill(this.plane);
|
|
280
|
+
g.restore();
|
|
281
|
+
|
|
282
|
+
const [int, dec] = this.mach.toFixed(2).split(".");
|
|
283
|
+
for (const el of this.ints) el.textContent = int;
|
|
284
|
+
for (const el of this.decs) el.textContent = dec;
|
|
285
|
+
// the readout splits and shakes for a moment as the barrier goes
|
|
286
|
+
this.toggleAttribute("data-boom", since >= 0 && since < 0.9);
|
|
287
|
+
this.toggleAttribute("data-supersonic", this.mach >= 1);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Construction lines, as on a textbook figure: the flight path, the Mach lines run out to the
|
|
292
|
+
* edges, a few radii dropped square onto them from the centres that made them, and the angle.
|
|
293
|
+
*/
|
|
294
|
+
private construct(
|
|
295
|
+
g: CanvasRenderingContext2D,
|
|
296
|
+
u: number,
|
|
297
|
+
px: number,
|
|
298
|
+
py: number,
|
|
299
|
+
) {
|
|
300
|
+
const c = this.canvas!;
|
|
301
|
+
const dir = Math.atan2(this.vy, this.vx);
|
|
302
|
+
const reach = Math.hypot(c.width, c.height) * 2;
|
|
303
|
+
const line = (x1: number, y1: number, x2: number, y2: number) => {
|
|
304
|
+
g.beginPath();
|
|
305
|
+
g.moveTo(x1, y1);
|
|
306
|
+
g.lineTo(x2, y2);
|
|
307
|
+
g.stroke();
|
|
308
|
+
};
|
|
309
|
+
g.lineWidth = Math.max(1, u * 0.0012);
|
|
310
|
+
|
|
311
|
+
// flight path, dashed, through the whole field
|
|
312
|
+
g.globalAlpha = 0.45;
|
|
313
|
+
g.setLineDash([u * 0.012, u * 0.008]);
|
|
314
|
+
line(
|
|
315
|
+
px - Math.cos(dir) * reach,
|
|
316
|
+
py - Math.sin(dir) * reach,
|
|
317
|
+
px + Math.cos(dir) * reach,
|
|
318
|
+
py + Math.sin(dir) * reach,
|
|
319
|
+
);
|
|
320
|
+
g.setLineDash([]);
|
|
321
|
+
|
|
322
|
+
// centre marks where the waves were dropped
|
|
323
|
+
const mark = u * 0.006;
|
|
324
|
+
g.globalAlpha = 0.5;
|
|
325
|
+
this.waves.forEach((w, i) => {
|
|
326
|
+
if (i % 6) return;
|
|
327
|
+
line(w.x * u - mark, w.y * u, w.x * u + mark, w.y * u);
|
|
328
|
+
line(w.x * u, w.y * u - mark, w.x * u, w.y * u + mark);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
if (this.mach <= 1.02) return;
|
|
332
|
+
const mu = Math.asin(1 / this.mach);
|
|
333
|
+
for (const side of [-1, 1]) {
|
|
334
|
+
const ex = Math.cos(dir + Math.PI + side * mu);
|
|
335
|
+
const ey = Math.sin(dir + Math.PI + side * mu);
|
|
336
|
+
// the Mach line, run out past the cone to the edge
|
|
337
|
+
g.globalAlpha = 0.6;
|
|
338
|
+
line(px, py, px + ex * reach, py + ey * reach);
|
|
339
|
+
// radii, square to the Mach line, from a few of the centres
|
|
340
|
+
g.globalAlpha = 0.45;
|
|
341
|
+
this.waves.forEach((w, i) => {
|
|
342
|
+
if (i % 12 || this.time - w.t < 0.5) return;
|
|
343
|
+
const cx = w.x * u;
|
|
344
|
+
const cy = w.y * u;
|
|
345
|
+
const along = (cx - px) * ex + (cy - py) * ey;
|
|
346
|
+
if (along <= 0) return;
|
|
347
|
+
line(cx, cy, px + ex * along, py + ey * along);
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// the angle, marked at the apex, its value set just outside the cone where no wave reaches
|
|
352
|
+
const r = u * 0.12;
|
|
353
|
+
g.globalAlpha = 1;
|
|
354
|
+
g.lineWidth = Math.max(2, u * 0.003);
|
|
355
|
+
g.beginPath();
|
|
356
|
+
g.arc(px, py, r, dir + Math.PI - mu, dir + Math.PI + mu);
|
|
357
|
+
g.stroke();
|
|
358
|
+
const edge = dir + Math.PI + mu;
|
|
359
|
+
const out = edge + Math.PI / 2;
|
|
360
|
+
const gap = u * 0.03;
|
|
361
|
+
g.font = `600 ${Math.round(u * 0.024)}px ${getComputedStyle(this).fontFamily}`;
|
|
362
|
+
g.textAlign = "center";
|
|
363
|
+
g.textBaseline = "middle";
|
|
364
|
+
const deg = ((mu * 180) / Math.PI).toFixed(1);
|
|
365
|
+
g.fillText(
|
|
366
|
+
`μ ${deg}°`,
|
|
367
|
+
px + Math.cos(edge) * r * 1.1 + Math.cos(out) * gap,
|
|
368
|
+
py + Math.sin(edge) * r * 1.1 + Math.sin(out) * gap,
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Reduced motion: the field at cruise, waves laid out as they would be, nothing moving. */
|
|
373
|
+
private still() {
|
|
374
|
+
if (!this.canvas) return;
|
|
375
|
+
const h = this.aspect;
|
|
376
|
+
this.x = 0.68;
|
|
377
|
+
this.y = h * 0.55;
|
|
378
|
+
this.vx = CRUISE * SOUND;
|
|
379
|
+
this.vy = 0;
|
|
380
|
+
this.mach = CRUISE;
|
|
381
|
+
this.time = WAVE_LIFE;
|
|
382
|
+
this.boom = -10;
|
|
383
|
+
this.waves = [];
|
|
384
|
+
for (let t = 0; t < WAVE_LIFE; t += WAVE_EVERY * 2) {
|
|
385
|
+
this.waves.push({ x: this.x - this.vx * (WAVE_LIFE - t), y: this.y, t });
|
|
386
|
+
}
|
|
387
|
+
this.draw();
|
|
388
|
+
}
|
|
389
|
+
}
|
package/src/docs/layout.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const onLocationChange = (location: Location) => {
|
|
2
|
-
|
|
2
|
+
// Docs pages all live in the hash: no hash means the home, whatever the path
|
|
3
|
+
// (served at /, /index.html or from a sub-folder).
|
|
4
|
+
if (location.hash === "") {
|
|
3
5
|
document.documentElement.setAttribute("data-home", "");
|
|
4
6
|
} else {
|
|
5
7
|
document.documentElement.removeAttribute("data-home");
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { html, LitElement } from "lit";
|
|
2
|
+
import { customElement } from "lit/decorators.js";
|
|
3
|
+
import { docsNavigation } from "./navigation";
|
|
4
|
+
|
|
5
|
+
export type Page = { label: string; href: string };
|
|
6
|
+
|
|
7
|
+
/** Sidebar sections listed on the Components page, in display order. */
|
|
8
|
+
const SECTIONS = [
|
|
9
|
+
{ title: "UI components", id: "ui-components" },
|
|
10
|
+
{ title: "Functional components", id: "functional-components" },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
/** Pages of a sidebar section: the items between its title and the next one. */
|
|
14
|
+
export function sectionPages(title: string): Page[] {
|
|
15
|
+
const start = docsNavigation.indexOf(title);
|
|
16
|
+
if (start < 0) return [];
|
|
17
|
+
const pages: Page[] = [];
|
|
18
|
+
for (const item of docsNavigation.slice(start + 1)) {
|
|
19
|
+
if (typeof item === "string") break;
|
|
20
|
+
pages.push(item);
|
|
21
|
+
}
|
|
22
|
+
return pages;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const tagName = "docs-components-index";
|
|
26
|
+
/**
|
|
27
|
+
* Plain index of every component, grouped like the sidebar.
|
|
28
|
+
* Light DOM so the page headings feed the "On this page" navigation.
|
|
29
|
+
*/
|
|
30
|
+
@customElement(tagName)
|
|
31
|
+
export class DocsComponentsIndex extends LitElement {
|
|
32
|
+
createRenderRoot() {
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
render() {
|
|
37
|
+
return SECTIONS.map(
|
|
38
|
+
(section) => html`
|
|
39
|
+
<h2 id=${section.id}>${section.title}</h2>
|
|
40
|
+
<div
|
|
41
|
+
class="not-prose grid grid-cols-2 sm:grid-cols-3 gap-x-8 gap-y-3 mt-6 mb-12"
|
|
42
|
+
>
|
|
43
|
+
${sectionPages(section.title).map(
|
|
44
|
+
(page) =>
|
|
45
|
+
html`<sonic-link
|
|
46
|
+
href=${page.href}
|
|
47
|
+
pushState
|
|
48
|
+
class="hover:underline underline-offset-4"
|
|
49
|
+
>${page.label}</sonic-link
|
|
50
|
+
>`,
|
|
51
|
+
)}
|
|
52
|
+
</div>
|
|
53
|
+
`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|