@janga/norna 0.7.10 → 0.7.12
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/README.md +120 -106
- package/bin/norna-cli.mjs +4 -1
- package/docs/README.md +107 -74
- package/docs/assets/norna-dog-shelter.jpg +0 -0
- package/docs/commands.md +13 -4
- package/docs/configuration.md +86 -184
- package/docs/content.md +14 -14
- package/docs/design/command-organization.md +1 -1
- package/docs/design/norna-diagram-design.md +2 -1
- package/docs/design/site-examples-structure.md +38 -24
- package/docs/engine-development.md +28 -15
- package/docs/getting-started.md +141 -124
- package/docs/how-to/embedded-site.md +35 -0
- package/docs/publishing.md +47 -46
- package/docs/requirements.md +54 -0
- package/docs/routes.md +3 -2
- package/docs/site-structure.md +12 -9
- package/docs/sitewide-content.md +2 -1
- package/docs/theme.md +104 -34
- package/docs/typography.md +32 -17
- package/examples/README.md +43 -0
- package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/collections/sitewide.schema.json +24 -0
- package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/collections/theme.schema.json +9 -24
- package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/.astro/content.d.ts +9 -1
- package/examples/complete-sites/dog-shelter-multi-page/.astro/data-store.json +1 -0
- package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/dev-local.json +2 -2
- package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.json +13 -0
- package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.log +26 -0
- package/examples/complete-sites/dog-shelter-multi-page/.astro/settings.json +5 -0
- package/examples/complete-sites/dog-shelter-multi-page/README.md +16 -0
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/_metadata.json +74 -0
- package/examples/{typography-presets/node_modules/.vite/deps/astro-D_GIpJIE.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro-B3JHJyiv.js} +4 -4
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro-B3JHJyiv.js.map +1 -0
- package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_aria-query.js +151 -151
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
- package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_axobject-query.js +131 -131
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
- package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_html-escaper.js +1 -1
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
- package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +10 -10
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
- package/examples/{typography-presets/node_modules/.vite/deps/audit-DM9Hkl5B.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/audit-C3SVr7dT.js} +10 -10
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/audit-C3SVr7dT.js.map +1 -0
- package/examples/{typography-presets/node_modules/.vite/deps/highlight-DnZ1ULOL.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/highlight-BLtvqtzO.js} +1 -1
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +1 -0
- package/examples/{typography-presets/node_modules/.vite/deps/icons-RyebKi45.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/icons-C92i61-2.js} +1 -1
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/icons-C92i61-2.js.map +1 -0
- package/examples/{typography-presets/node_modules/.vite/deps/settings-DaU-gNnK.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/settings-v5GgKks_.js} +2 -2
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/settings-v5GgKks_.js.map +1 -0
- package/examples/{typography-presets/node_modules/.vite/deps/toolbar-63PA619H.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/toolbar-BFvJVp26.js} +2 -2
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +1 -0
- package/examples/{typography-presets/node_modules/.vite/deps/ui-library--bkcNSYz.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js} +10 -10
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +1 -0
- package/examples/{typography-presets/node_modules/.vite/deps/window-jPkpKVcy.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/window-vo3A6TMn.js} +1 -1
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/window-vo3A6TMn.js.map +1 -0
- package/examples/{typography-presets/node_modules/.vite/deps/xray-BXCHpEJP.js → complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/xray-DwhzGckb.js} +3 -3
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/xray-DwhzGckb.js.map +1 -0
- package/examples/complete-sites/dog-shelter-multi-page/site/.norna/generated-images.json +98 -0
- package/examples/complete-sites/dog-shelter-multi-page/site/config.md +3 -0
- package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-multi-page}/site/content.md +12 -0
- package/examples/complete-sites/dog-shelter-multi-page/site/public/logo.svg +9 -0
- package/examples/complete-sites/dog-shelter-multi-page/site/routes/010-dogs/route-content.md +22 -0
- package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-multi-page}/site/routes/020-adopt/route-content.md +11 -0
- package/examples/complete-sites/dog-shelter-multi-page/site/sitewide-content.md +16 -0
- package/examples/complete-sites/dog-shelter-multi-page/site/theme.md +3 -0
- package/examples/complete-sites/dog-shelter-single-page/.astro/collections/site.schema.json +59 -0
- package/examples/complete-sites/dog-shelter-single-page/.astro/collections/sitewide.schema.json +138 -0
- package/examples/{dog-gallery → complete-sites/dog-shelter-single-page}/.astro/collections/theme.schema.json +151 -68
- package/examples/complete-sites/dog-shelter-single-page/.astro/content.d.ts +183 -0
- package/examples/complete-sites/dog-shelter-single-page/.astro/data-store.json +1 -0
- package/examples/complete-sites/dog-shelter-single-page/.astro/dev.json +13 -0
- package/examples/complete-sites/dog-shelter-single-page/.astro/dev.log +14 -0
- package/examples/complete-sites/dog-shelter-single-page/.astro/settings.json +5 -0
- package/examples/complete-sites/dog-shelter-single-page/README.md +16 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/_metadata.json +74 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro-B3JHJyiv.js +434 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro-B3JHJyiv.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/audit-C3SVr7dT.js +1534 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/audit-C3SVr7dT.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/highlight-BLtvqtzO.js +48 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/icons-C92i61-2.js +42 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/icons-C92i61-2.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/settings-v5GgKks_.js +190 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/settings-v5GgKks_.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/toolbar-BFvJVp26.js +458 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js +1016 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/window-vo3A6TMn.js +32 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/window-vo3A6TMn.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/xray-DwhzGckb.js +111 -0
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/xray-DwhzGckb.js.map +1 -0
- package/examples/complete-sites/dog-shelter-single-page/site/.norna/generated-images.json +50 -0
- package/examples/complete-sites/dog-shelter-single-page/site/config.md +3 -0
- package/examples/complete-sites/dog-shelter-single-page/site/content.md +34 -0
- package/examples/complete-sites/dog-shelter-single-page/site/public/logo.svg +9 -0
- package/examples/complete-sites/dog-shelter-single-page/site/sitewide-content.md +16 -0
- package/examples/complete-sites/dog-shelter-single-page/site/theme.md +3 -0
- package/examples/feature-demos/media-and-surfaces/.astro/collections/site.schema.json +59 -0
- package/examples/feature-demos/media-and-surfaces/.astro/collections/sitewide.schema.json +138 -0
- package/examples/feature-demos/media-and-surfaces/.astro/collections/theme.schema.json +755 -0
- package/examples/feature-demos/media-and-surfaces/.astro/content-assets.mjs +4 -0
- package/examples/feature-demos/media-and-surfaces/.astro/content-modules.mjs +1 -0
- package/examples/feature-demos/media-and-surfaces/.astro/content.d.ts +183 -0
- package/examples/feature-demos/media-and-surfaces/.astro/data-store.json +1 -0
- package/examples/feature-demos/media-and-surfaces/.astro/dev.log +24 -0
- package/examples/feature-demos/media-and-surfaces/.astro/settings.json +5 -0
- package/examples/feature-demos/media-and-surfaces/.astro/types.d.ts +2 -0
- package/examples/feature-demos/media-and-surfaces/README.md +21 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/_metadata.json +80 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro-B3JHJyiv.js +434 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro-B3JHJyiv.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/audit-C3SVr7dT.js +1534 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/audit-C3SVr7dT.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/embla-carousel.js +1389 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/embla-carousel.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/highlight-BLtvqtzO.js +48 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/icons-C92i61-2.js +42 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/icons-C92i61-2.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/package.json +3 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/settings-v5GgKks_.js +190 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/settings-v5GgKks_.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/toolbar-BFvJVp26.js +458 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/ui-library-Cd35oAvo.js +1016 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/window-vo3A6TMn.js +32 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/window-vo3A6TMn.js.map +1 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/xray-DwhzGckb.js +111 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/xray-DwhzGckb.js.map +1 -0
- package/examples/{presentation → feature-demos/media-and-surfaces}/site/.norna/generated-images.json +16 -16
- package/examples/feature-demos/media-and-surfaces/site/config.md +4 -0
- package/examples/feature-demos/media-and-surfaces/site/content.md +18 -0
- package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/route-content.md +17 -24
- package/examples/{presentation/site/routes/030-surfaces → feature-demos/media-and-surfaces/site/routes/020-surfaces}/route-content.md +1 -1
- package/examples/{presentation/site/routes/030-surfaces → feature-demos/media-and-surfaces/site/routes/020-surfaces}/theme.md +1 -0
- package/examples/feature-demos/media-and-surfaces/site/sitewide-content.md +6 -0
- package/examples/feature-demos/media-and-surfaces/site/theme.md +3 -0
- package/examples/feature-demos/sitewide-content/.astro/collections/site.schema.json +59 -0
- package/examples/feature-demos/sitewide-content/.astro/collections/sitewide.schema.json +138 -0
- package/examples/feature-demos/sitewide-content/.astro/collections/theme.schema.json +755 -0
- package/examples/feature-demos/sitewide-content/.astro/content-assets.mjs +1 -0
- package/examples/feature-demos/sitewide-content/.astro/content-modules.mjs +1 -0
- package/examples/feature-demos/sitewide-content/.astro/content.d.ts +183 -0
- package/examples/feature-demos/sitewide-content/.astro/data-store.json +1 -0
- package/examples/feature-demos/sitewide-content/.astro/dev.json +13 -0
- package/examples/feature-demos/sitewide-content/.astro/dev.log +18 -0
- package/examples/feature-demos/sitewide-content/.astro/settings.json +5 -0
- package/examples/feature-demos/sitewide-content/.astro/types.d.ts +2 -0
- package/examples/feature-demos/sitewide-content/README.md +18 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/_metadata.json +74 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro-B3JHJyiv.js +434 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro-B3JHJyiv.js.map +1 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/audit-C3SVr7dT.js +1534 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/audit-C3SVr7dT.js.map +1 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/highlight-BLtvqtzO.js +48 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/highlight-BLtvqtzO.js.map +1 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/icons-C92i61-2.js +42 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/icons-C92i61-2.js.map +1 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/package.json +3 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/settings-v5GgKks_.js +190 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/settings-v5GgKks_.js.map +1 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/toolbar-BFvJVp26.js +458 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/toolbar-BFvJVp26.js.map +1 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/ui-library-Cd35oAvo.js +1016 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/ui-library-Cd35oAvo.js.map +1 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/window-vo3A6TMn.js +32 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/window-vo3A6TMn.js.map +1 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/xray-DwhzGckb.js +111 -0
- package/examples/feature-demos/sitewide-content/node_modules/.vite/deps/xray-DwhzGckb.js.map +1 -0
- package/examples/feature-demos/sitewide-content/site/.norna/generated-images.json +1 -0
- package/examples/feature-demos/sitewide-content/site/config.md +3 -0
- package/examples/feature-demos/sitewide-content/site/content.md +16 -0
- package/examples/feature-demos/sitewide-content/site/public/logo.svg +6 -0
- package/examples/feature-demos/sitewide-content/site/routes/010-identity/route-content.md +20 -0
- package/examples/feature-demos/sitewide-content/site/routes/020-notices/route-content.md +22 -0
- package/examples/feature-demos/sitewide-content/site/routes/030-footer/route-content.md +17 -0
- package/examples/feature-demos/sitewide-content/site/sitewide-content.md +33 -0
- package/examples/feature-demos/sitewide-content/site/theme.md +3 -0
- package/examples/feature-demos/theme-presets/.astro/collections/site.schema.json +59 -0
- package/examples/feature-demos/theme-presets/.astro/collections/sitewide.schema.json +138 -0
- package/examples/feature-demos/theme-presets/.astro/collections/theme.schema.json +755 -0
- package/examples/feature-demos/theme-presets/.astro/content-assets.mjs +4 -0
- package/examples/feature-demos/theme-presets/.astro/content-modules.mjs +1 -0
- package/examples/{typography-presets → feature-demos/theme-presets}/.astro/data-store.json +1 -1
- package/examples/feature-demos/theme-presets/.astro/dev-local.json +8 -0
- package/examples/{typography-presets → feature-demos/theme-presets}/.astro/dev.json +2 -2
- package/examples/feature-demos/theme-presets/.astro/dev.log +164 -0
- package/examples/feature-demos/theme-presets/.astro/types.d.ts +2 -0
- package/examples/feature-demos/theme-presets/README.md +18 -0
- package/examples/feature-demos/theme-presets/node_modules/.vite/deps/package.json +3 -0
- package/examples/feature-demos/theme-presets/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
- package/examples/{typography-presets → feature-demos/theme-presets}/site/.norna/generated-images.json +45 -45
- package/examples/feature-demos/theme-presets/site/config.md +3 -0
- package/examples/feature-demos/theme-presets/site/content.md +17 -0
- package/examples/feature-demos/theme-presets/site/routes/010-portfolio/images/portfolio/shepherd-portrait.jpg +0 -0
- package/examples/feature-demos/theme-presets/site/routes/010-portfolio/images/portfolio/white-puppy.jpg +0 -0
- package/examples/{typography-presets/site/routes/010-quiet-gallery → feature-demos/theme-presets/site/routes/010-portfolio}/route-content.md +8 -8
- package/examples/feature-demos/theme-presets/site/routes/010-portfolio/theme.md +3 -0
- package/examples/feature-demos/theme-presets/site/routes/020-documentation/images/documentation/retriever-portrait.jpg +0 -0
- package/examples/{typography-presets/site/routes/020-compact-gallery → feature-demos/theme-presets/site/routes/020-documentation}/route-content.md +8 -8
- package/examples/feature-demos/theme-presets/site/routes/020-documentation/theme.md +3 -0
- package/examples/feature-demos/theme-presets/site/routes/030-project/images/project/boxer-portrait.jpg +0 -0
- package/examples/feature-demos/theme-presets/site/routes/030-project/images/project/grass-puppy.jpg +0 -0
- package/examples/{typography-presets/site/routes/030-text-forward → feature-demos/theme-presets/site/routes/030-project}/route-content.md +8 -8
- package/examples/feature-demos/theme-presets/site/routes/030-project/theme.md +3 -0
- package/examples/feature-demos/theme-presets/site/routes/040-statement/images/statement/sheepdog-grass.jpg +0 -0
- package/examples/{typography-presets → feature-demos/theme-presets}/site/routes/040-statement/route-content.md +3 -3
- package/examples/feature-demos/theme-presets/site/routes/040-statement/theme.md +3 -0
- package/examples/{typography-presets → feature-demos/theme-presets}/site/sitewide-content.md +1 -1
- package/examples/feature-demos/theme-presets/site/theme.md +3 -0
- package/fixtures/basic/site/config.md +3 -0
- package/fixtures/content-model-v2/site/config.md +3 -0
- package/package.json +17 -8
- package/scripts/build-pages.mjs +69 -0
- package/scripts/check-config.mjs +3 -11
- package/scripts/deploy-site.mjs +12 -8
- package/scripts/export-theme-preset.mjs +31 -0
- package/scripts/init-site.mjs +1 -0
- package/scripts/lib/example-sites.mjs +37 -0
- package/scripts/lib/github-repository.mjs +44 -0
- package/scripts/lib/norna-markdown-blocks.mjs +97 -10
- package/scripts/lib/presentation.mjs +6 -5
- package/scripts/lib/project-config.mjs +114 -124
- package/scripts/lib/site-content.mjs +9 -2
- package/scripts/lib/site-paths.mjs +6 -2
- package/scripts/lib/theme-config.mjs +3 -0
- package/scripts/lib/theme-presets.mjs +209 -0
- package/scripts/show-typography.mjs +6 -5
- package/scripts/test-client-javascript.mjs +236 -0
- package/scripts/test-content-check.mjs +103 -0
- package/scripts/test-content-model-v2.mjs +9 -13
- package/scripts/test-documentation.mjs +116 -0
- package/scripts/test-engine-commands.mjs +13 -3
- package/scripts/test-examples.mjs +24 -0
- package/scripts/test-navigation.mjs +73 -45
- package/scripts/test-package-check.mjs +17 -9
- package/scripts/test-project-config.mjs +130 -0
- package/scripts/test-temporary-visibility.mjs +3 -10
- package/scripts/test-theme-presets.mjs +146 -0
- package/scripts/watch-pages-deploy.mjs +15 -11
- package/src/components/GalleryGrid.astro +30 -230
- package/src/components/ImageCarousel.astro +184 -0
- package/src/components/MobileSectionNavigationScript.astro +14 -0
- package/src/components/NornaSmoothScrollScript.astro +250 -0
- package/src/components/SiteNavigation.astro +58 -341
- package/src/components/SiteNotesScript.astro +43 -0
- package/src/components/SitePage.astro +6 -3
- package/src/components/SiteSection.astro +4 -47
- package/src/content.config.ts +2 -0
- package/src/layouts/BaseLayout.astro +1 -1
- package/src/lib/galleryImages.ts +53 -0
- package/src/styles/global.css +83 -1
- package/starters/basic/.github/workflows/deploy.yml +1 -2
- package/starters/basic/README.md +10 -8
- package/starters/basic/package.json +1 -0
- package/starters/basic/site/config.md +3 -0
- package/starters/project/.github/workflows/deploy.yml +1 -2
- package/starters/project/README.md +3 -4
- package/starters/project/package.json +1 -0
- package/starters/project/site/config.md +3 -0
- package/examples/001-dog-shelter-single-page/README.md +0 -9
- package/examples/001-dog-shelter-single-page/site/config.mjs +0 -27
- package/examples/001-dog-shelter-single-page/site/content.md +0 -38
- package/examples/001-dog-shelter-single-page/site/images/what-we-do/dog-house.svg +0 -25
- package/examples/001-dog-shelter-single-page/site/images/you-can-help/heart.svg +0 -13
- package/examples/001-dog-shelter-single-page/site/sitewide-content.md +0 -6
- package/examples/001-dog-shelter-single-page/site/theme.md +0 -25
- package/examples/002-dog-shelter-multi-page/README.md +0 -9
- package/examples/002-dog-shelter-multi-page/site/config.mjs +0 -27
- package/examples/002-dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rex.svg +0 -19
- package/examples/002-dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rover.svg +0 -19
- package/examples/002-dog-shelter-multi-page/site/routes/010-dogs/route-content.md +0 -30
- package/examples/002-dog-shelter-multi-page/site/sitewide-content.md +0 -6
- package/examples/002-dog-shelter-multi-page/site/theme.md +0 -25
- package/examples/dog-gallery/.astro/collections/site.schema.json +0 -776
- package/examples/dog-gallery/.astro/data-store.json +0 -1
- package/examples/dog-gallery/.astro/dev-local.json +0 -8
- package/examples/dog-gallery/.astro/dev.json +0 -13
- package/examples/dog-gallery/.astro/dev.log +0 -95
- package/examples/dog-gallery/.astro/settings.json +0 -5
- package/examples/dog-gallery/dist/_astro/GalleryGrid.astro_astro_type_script_index_0_lang.B0kxDyGz.js +0 -1
- package/examples/dog-gallery/dist/_astro/SitePage.DicGh_5N.css +0 -1
- package/examples/dog-gallery/dist/dog-care/index.html +0 -15
- package/examples/dog-gallery/dist/dog-shelter-logo.svg +0 -14
- package/examples/dog-gallery/dist/favicon.svg +0 -7
- package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1440.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1536.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-960.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1440.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1920.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-3939.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1440.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1920.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-2400.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1440.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1600.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1440.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1920.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-2576.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-1277.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-768.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1080.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1440.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1536.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-480.webp +0 -0
- package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-768.webp +0 -0
- package/examples/dog-gallery/dist/index.html +0 -45
- package/examples/dog-gallery/node_modules/.vite/deps/_metadata.json +0 -74
- package/examples/dog-gallery/site/.norna/generated-images.json +0 -226
- package/examples/dog-gallery/site/config.mjs +0 -47
- package/examples/dog-gallery/site/content.md +0 -127
- package/examples/dog-gallery/site/images/black-dogs/black-puppy-meadow.png +0 -0
- package/examples/dog-gallery/site/images/black-dogs/photo-of-a-black-dog.jpg +0 -0
- package/examples/dog-gallery/site/images/brown-dogs/brown-dog.jpg +0 -0
- package/examples/dog-gallery/site/images/brown-dogs/dog-accompanies-master.jpg +0 -0
- package/examples/dog-gallery/site/images/golden-dogs/golden-retriever.jpg +0 -0
- package/examples/dog-gallery/site/images/golden-dogs/toller-puppy.jpg +0 -0
- package/examples/dog-gallery/site/images/white-dogs/white-cute-dog.jpg +0 -0
- package/examples/dog-gallery/site/images/white-dogs/white-puppy-garden.png +0 -0
- package/examples/dog-gallery/site/public/favicon.svg +0 -7
- package/examples/dog-gallery/site/public/logo.svg +0 -14
- package/examples/dog-gallery/site/routes/010-dog-care/route-content.md +0 -38
- package/examples/dog-gallery/site/sitewide-content.md +0 -16
- package/examples/dog-gallery/site/theme.md +0 -101
- package/examples/presentation/README.md +0 -15
- package/examples/presentation/site/config.mjs +0 -29
- package/examples/presentation/site/content.md +0 -67
- package/examples/presentation/site/public/robots.txt +0 -2
- package/examples/presentation/site/routes/010-presets/route-content.md +0 -63
- package/examples/presentation/site/routes/010-presets/theme.md +0 -4
- package/examples/presentation/site/routes/020-media/theme.md +0 -4
- package/examples/presentation/site/sitewide-content.md +0 -6
- package/examples/presentation/site/theme.md +0 -43
- package/examples/typography-presets/.astro/dev.log +0 -45
- package/examples/typography-presets/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -1
- package/examples/typography-presets/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -1
- package/examples/typography-presets/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -1
- package/examples/typography-presets/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -1
- package/examples/typography-presets/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -1
- package/examples/typography-presets/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -1
- package/examples/typography-presets/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -1
- package/examples/typography-presets/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -1
- package/examples/typography-presets/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -1
- package/examples/typography-presets/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -1
- package/examples/typography-presets/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -1
- package/examples/typography-presets/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -1
- package/examples/typography-presets/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -1
- package/examples/typography-presets/site/config.mjs +0 -29
- package/examples/typography-presets/site/content.md +0 -16
- package/examples/typography-presets/site/routes/010-quiet-gallery/theme.md +0 -4
- package/examples/typography-presets/site/routes/020-compact-gallery/theme.md +0 -4
- package/examples/typography-presets/site/routes/030-text-forward/theme.md +0 -4
- package/examples/typography-presets/site/routes/040-statement/theme.md +0 -4
- package/examples/typography-presets/site/theme.md +0 -43
- package/fixtures/basic/site/config.mjs +0 -27
- package/fixtures/content-model-v2/site/config.mjs +0 -11
- package/starters/basic/site/config.mjs +0 -27
- package/starters/project/site/config.mjs +0 -30
- /package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/collections/site.schema.json +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/.astro/content-assets.mjs +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/.astro/content-modules.mjs +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/.astro/types.d.ts +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/package.json +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -0
- /package/examples/{typography-presets/site/routes/020-compact-gallery/images/compact-gallery/retriever-portrait.jpg → complete-sites/dog-shelter-multi-page/site/images/intro/shelter-dog.jpg} +0 -0
- /package/examples/{001-dog-shelter-single-page → complete-sites/dog-shelter-multi-page}/site/public/favicon.svg +0 -0
- /package/examples/{001-dog-shelter-single-page → complete-sites/dog-shelter-multi-page}/site/public/robots.txt +0 -0
- /package/examples/{typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery/white-puppy.jpg → complete-sites/dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rex.jpg} +0 -0
- /package/examples/{typography-presets/site/routes/030-text-forward/images/text-forward/boxer-portrait.jpg → complete-sites/dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rover.jpg} +0 -0
- /package/examples/{typography-presets/site/routes/040-statement/images/statement/sheepdog-grass.jpg → complete-sites/dog-shelter-multi-page/site/routes/020-adopt/images/adopt/adoption-dog.jpg} +0 -0
- /package/examples/{typography-presets → complete-sites/dog-shelter-single-page}/.astro/content-assets.mjs +0 -0
- /package/examples/{typography-presets → complete-sites/dog-shelter-single-page}/.astro/content-modules.mjs +0 -0
- /package/examples/{typography-presets → complete-sites/dog-shelter-single-page}/.astro/types.d.ts +0 -0
- /package/examples/{typography-presets → complete-sites/dog-shelter-single-page}/node_modules/.vite/deps/package.json +0 -0
- /package/examples/{typography-presets → complete-sites/dog-shelter-single-page}/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -0
- /package/examples/{typography-presets/site/routes/030-text-forward/images/text-forward/grass-puppy.jpg → complete-sites/dog-shelter-single-page/site/images/what-we-do/rescue-dog.jpg} +0 -0
- /package/examples/{typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery/shepherd-portrait.jpg → complete-sites/dog-shelter-single-page/site/images/you-can-help/foster-dog.jpg} +0 -0
- /package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-single-page}/site/public/favicon.svg +0 -0
- /package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-single-page}/site/public/robots.txt +0 -0
- /package/examples/{dog-gallery/dist → feature-demos/media-and-surfaces/site/public}/robots.txt +0 -0
- /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/cards/card-carousel.svg +0 -0
- /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/cards/card-stack.svg +0 -0
- /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/cards/card-surfaces.svg +0 -0
- /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/carousel/carousel-one.svg +0 -0
- /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/carousel/carousel-three.svg +0 -0
- /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/carousel/carousel-two.svg +0 -0
- /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/stack/stack-one.svg +0 -0
- /package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/images/stack/stack-two.svg +0 -0
- /package/examples/{dog-gallery → feature-demos/sitewide-content}/site/public/robots.txt +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/.astro/collections/routeTheme.schema.json +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/.astro/content.d.ts +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/.astro/settings.json +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/_metadata.json +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro-D_GIpJIE.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_aria-query.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_axobject-query.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_html-escaper.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/audit-DM9Hkl5B.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/embla-carousel.js +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/embla-carousel.js.map +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/highlight-DnZ1ULOL.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/icons-RyebKi45.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/settings-DaU-gNnK.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/toolbar-63PA619H.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/ui-library--bkcNSYz.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/window-jPkpKVcy.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/xray-BXCHpEJP.js +0 -0
- /package/examples/{dog-gallery → feature-demos/theme-presets}/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/site/public/robots.txt +0 -0
- /package/examples/{typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery → feature-demos/theme-presets/site/routes/010-portfolio/images/portfolio}/puppy-portrait.jpg +0 -0
- /package/examples/{typography-presets/site/routes/020-compact-gallery/images/compact-gallery → feature-demos/theme-presets/site/routes/020-documentation/images/documentation}/black-schnauzer.jpg +0 -0
- /package/examples/{typography-presets/site/routes/020-compact-gallery/images/compact-gallery → feature-demos/theme-presets/site/routes/020-documentation/images/documentation}/schnauzer-portrait.jpg +0 -0
- /package/examples/{typography-presets/site/routes/030-text-forward/images/text-forward → feature-demos/theme-presets/site/routes/030-project/images/project}/grey-street-dog.jpg +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/site/routes/040-statement/images/statement/black-pedigree.jpg +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/site/routes/040-statement/images/statement/sheepdog-wide.jpg +0 -0
package/scripts/deploy-site.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
extractNornaMarkdownBlocks,
|
|
13
13
|
getNornaBlockImageReferences,
|
|
14
14
|
} from './lib/norna-markdown-blocks.mjs';
|
|
15
|
-
import {
|
|
15
|
+
import { getGitHubRepositoryContext, githubPagesWorkflow } from './lib/github-repository.mjs';
|
|
16
16
|
import {
|
|
17
17
|
engineRoot,
|
|
18
18
|
generatedImagesManifestLabel,
|
|
@@ -28,9 +28,9 @@ import {
|
|
|
28
28
|
const execFileAsync = promisify(execFile);
|
|
29
29
|
|
|
30
30
|
const root = siteProjectRoot;
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const pagesWorkflow = githubPagesWorkflow;
|
|
32
|
+
let branch;
|
|
33
|
+
let repo;
|
|
34
34
|
const args = process.argv.slice(2);
|
|
35
35
|
const mode = args[0] === 'commit' ? 'commit' : 'deploy';
|
|
36
36
|
const modeArgs = mode === 'commit' ? args.slice(1) : args;
|
|
@@ -53,9 +53,9 @@ const failedConclusions = new Set(['action_required', 'cancelled', 'failure', 's
|
|
|
53
53
|
const deployUsage = [
|
|
54
54
|
'Usage: norna deploy',
|
|
55
55
|
'',
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
'Publishes an already committed default branch: builds, verifies a clean worktree,',
|
|
57
|
+
'pushes it when local HEAD is ahead of origin, and checks GitHub Pages.',
|
|
58
|
+
'If local HEAD already matches origin, it skips push and checks Pages.',
|
|
59
59
|
'',
|
|
60
60
|
'For the old build-and-commit convenience flow, use:',
|
|
61
61
|
'norna deploy:commit "Commit message"',
|
|
@@ -63,7 +63,7 @@ const deployUsage = [
|
|
|
63
63
|
const deployCommitUsage = [
|
|
64
64
|
'Usage: norna deploy:commit "Commit message"',
|
|
65
65
|
'',
|
|
66
|
-
|
|
66
|
+
'Builds, stages only allowed site changes, commits, pushes the default branch,',
|
|
67
67
|
'and checks GitHub Pages.',
|
|
68
68
|
].join('\n');
|
|
69
69
|
|
|
@@ -385,6 +385,10 @@ if (modeArgs.includes('--help') || modeArgs.includes('-h')) {
|
|
|
385
385
|
}
|
|
386
386
|
|
|
387
387
|
try {
|
|
388
|
+
const githubRepository = await getGitHubRepositoryContext({ cwd: root });
|
|
389
|
+
branch = githubRepository.branch;
|
|
390
|
+
repo = githubRepository.repo;
|
|
391
|
+
|
|
388
392
|
if (mode === 'commit') {
|
|
389
393
|
await deployWithCommit();
|
|
390
394
|
} else {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {
|
|
4
|
+
renderThemePresetReference,
|
|
5
|
+
themePresetNames,
|
|
6
|
+
} from './lib/theme-presets.mjs';
|
|
7
|
+
import { siteDir, siteThemeLabel } from './lib/site-paths.mjs';
|
|
8
|
+
|
|
9
|
+
const [presetName, ...extraArgs] = process.argv.slice(2);
|
|
10
|
+
|
|
11
|
+
if (!presetName || extraArgs.length > 0) {
|
|
12
|
+
throw new Error(`Usage: norna theme:export <preset>\nAvailable presets: ${themePresetNames.join(', ')}`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const filename = `orig-${presetName}-theme.md`;
|
|
16
|
+
const outputPath = path.join(siteDir, filename);
|
|
17
|
+
const outputLabel = path.posix.join(path.posix.dirname(siteThemeLabel), filename);
|
|
18
|
+
const source = renderThemePresetReference(presetName, siteThemeLabel);
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
await writeFile(outputPath, source, { encoding: 'utf8', flag: 'wx' });
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (error?.code === 'EEXIST') {
|
|
24
|
+
throw new Error(`${outputLabel} already exists. Norna will not overwrite it.`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log(`Exported the ${presetName} theme preset to ${outputLabel}.`);
|
|
31
|
+
console.log(`Norna still reads ${siteThemeLabel}; use the exported file as an override reference.`);
|
package/scripts/init-site.mjs
CHANGED
|
@@ -133,6 +133,7 @@ const galleryScripts = {
|
|
|
133
133
|
'norna:config:check': cliCommand('config:check'),
|
|
134
134
|
'norna:content:check': cliCommand('content:check'),
|
|
135
135
|
'norna:sync': cliCommand('content:sync'),
|
|
136
|
+
'norna:theme:export': cliCommand('theme:export'),
|
|
136
137
|
'norna:typography:presets': cliCommand('typography presets'),
|
|
137
138
|
'norna:typography:show': cliCommand('typography show'),
|
|
138
139
|
'norna:public': cliCommand('site:public'),
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { readdir } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
export const exampleCategories = ['complete-sites', 'feature-demos'];
|
|
6
|
+
|
|
7
|
+
export const getExampleSites = async (root) => {
|
|
8
|
+
const examples = [];
|
|
9
|
+
|
|
10
|
+
for (const category of exampleCategories) {
|
|
11
|
+
const categoryDirectory = path.join(root, 'examples', category);
|
|
12
|
+
const entries = await readdir(categoryDirectory, { withFileTypes: true });
|
|
13
|
+
|
|
14
|
+
for (const entry of entries.filter((candidate) => candidate.isDirectory()).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
15
|
+
const siteDirectory = path.join(categoryDirectory, entry.name, 'site');
|
|
16
|
+
if (!existsSync(path.join(siteDirectory, 'config.md'))) {
|
|
17
|
+
throw new Error(`Example ${path.relative(root, siteDirectory)} is missing config.md.`);
|
|
18
|
+
}
|
|
19
|
+
if (!existsSync(path.join(siteDirectory, 'content.md'))) {
|
|
20
|
+
throw new Error(`Example ${path.relative(root, siteDirectory)} is missing content.md.`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
examples.push({
|
|
24
|
+
category,
|
|
25
|
+
name: entry.name,
|
|
26
|
+
siteDirectory,
|
|
27
|
+
siteLabel: path.relative(root, siteDirectory),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (examples.length === 0) {
|
|
33
|
+
throw new Error('No example sites were found.');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return examples;
|
|
37
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
|
|
6
|
+
export const githubPagesWorkflow = 'deploy.yml';
|
|
7
|
+
|
|
8
|
+
export const getGitHubRepositoryContext = async ({ cwd, repo } = {}) => {
|
|
9
|
+
const args = [
|
|
10
|
+
'repo',
|
|
11
|
+
'view',
|
|
12
|
+
...(repo ? [repo] : []),
|
|
13
|
+
'--json',
|
|
14
|
+
'nameWithOwner,defaultBranchRef',
|
|
15
|
+
];
|
|
16
|
+
let stdout;
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
({ stdout } = await execFileAsync('gh', args, {
|
|
20
|
+
cwd,
|
|
21
|
+
maxBuffer: 1024 * 1024,
|
|
22
|
+
}));
|
|
23
|
+
} catch (error) {
|
|
24
|
+
throw new Error([
|
|
25
|
+
'Could not discover the GitHub repository and its default branch.',
|
|
26
|
+
'Run this command in a Git repository with a GitHub remote and an authenticated gh CLI, or pass explicit deploy:watch options.',
|
|
27
|
+
error.stderr?.trim(),
|
|
28
|
+
error.message,
|
|
29
|
+
].filter(Boolean).join('\n'));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const result = JSON.parse(stdout || '{}');
|
|
33
|
+
const defaultBranch = result.defaultBranchRef?.name;
|
|
34
|
+
const nameWithOwner = result.nameWithOwner;
|
|
35
|
+
|
|
36
|
+
if (!nameWithOwner || !defaultBranch) {
|
|
37
|
+
throw new Error('GitHub did not report a repository name and default branch.');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return Object.freeze({
|
|
41
|
+
branch: defaultBranch,
|
|
42
|
+
repo: nameWithOwner,
|
|
43
|
+
});
|
|
44
|
+
};
|
|
@@ -589,7 +589,8 @@ export const splitNornaMarkdownBlockMarkers = (html, options = {}) => {
|
|
|
589
589
|
const normalizeBlockSource = (source) => source.replace(/\r\n?/g, '\n').trim();
|
|
590
590
|
|
|
591
591
|
const inlineNoteReferenceRegex = /\{note-ref\}/g;
|
|
592
|
-
const
|
|
592
|
+
const inlineNoteDeclarationOpeningRegex = /^\s*\{note:\s*(.*)$/;
|
|
593
|
+
const inlineNoteDeclarationClosingRegex = /^(.*?)\}\s*$/;
|
|
593
594
|
const inlineNoteDeclarationStartRegex = /\{note(?:\s*:|\s*\})/;
|
|
594
595
|
|
|
595
596
|
const maskInlineCodeAndComments = (source) => source.replace(
|
|
@@ -605,7 +606,82 @@ const formatInlineNoteError = (message, options, line) => ({
|
|
|
605
606
|
message: failMessage(message, { ...options, line }),
|
|
606
607
|
});
|
|
607
608
|
|
|
608
|
-
const getInlineNoteErrorMessage = () => 'Write the note on its own line as "{note:
|
|
609
|
+
const getInlineNoteErrorMessage = () => 'Write the note on its own line as "{note: Short text.}", or end a multiline note with "}".';
|
|
610
|
+
|
|
611
|
+
const findUnescapedInlineNoteConstruct = (source) => {
|
|
612
|
+
const constructRegex = /\{note(?:-ref\}|\s*:|\s*\})/g;
|
|
613
|
+
|
|
614
|
+
for (const match of source.matchAll(constructRegex)) {
|
|
615
|
+
const index = match.index ?? 0;
|
|
616
|
+
let precedingBackslashes = 0;
|
|
617
|
+
for (let cursor = index - 1; cursor >= 0 && source[cursor] === '\\'; cursor -= 1) {
|
|
618
|
+
precedingBackslashes += 1;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if (precedingBackslashes % 2 === 0) {
|
|
622
|
+
return match[0].startsWith('{note-ref') ? 'reference' : 'note';
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
return null;
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
const collectInlineNoteDeclaration = (lines, maskedLines, startIndex) => {
|
|
630
|
+
const openingMatch = (lines[startIndex] ?? '').match(inlineNoteDeclarationOpeningRegex);
|
|
631
|
+
if (!openingMatch) return null;
|
|
632
|
+
const maskedOpeningMatch = (maskedLines[startIndex] ?? '').match(inlineNoteDeclarationOpeningRegex);
|
|
633
|
+
|
|
634
|
+
const textLines = [];
|
|
635
|
+
let currentLine = openingMatch[1] ?? '';
|
|
636
|
+
let currentMaskedLine = maskedOpeningMatch?.[1] ?? '';
|
|
637
|
+
|
|
638
|
+
for (let index = startIndex; index < lines.length; index += 1) {
|
|
639
|
+
const conflictType = findUnescapedInlineNoteConstruct(currentMaskedLine);
|
|
640
|
+
if (conflictType) {
|
|
641
|
+
return {
|
|
642
|
+
closed: false,
|
|
643
|
+
conflictIndex: index,
|
|
644
|
+
conflictType,
|
|
645
|
+
endIndex: index,
|
|
646
|
+
text: textLines.map((line) => line.trim()).filter(Boolean).join(' '),
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
const closingMatch = currentLine.match(inlineNoteDeclarationClosingRegex);
|
|
651
|
+
if (closingMatch) {
|
|
652
|
+
textLines.push(closingMatch[1]);
|
|
653
|
+
return {
|
|
654
|
+
closed: true,
|
|
655
|
+
endIndex: index,
|
|
656
|
+
text: textLines.map((line) => line.trim()).filter(Boolean).join(' '),
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
textLines.push(currentLine);
|
|
661
|
+
currentLine = lines[index + 1] ?? '';
|
|
662
|
+
currentMaskedLine = maskedLines[index + 1] ?? '';
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
return {
|
|
666
|
+
closed: false,
|
|
667
|
+
endIndex: lines.length - 1,
|
|
668
|
+
text: textLines.map((line) => line.trim()).filter(Boolean).join(' '),
|
|
669
|
+
};
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
const getUnclosedInlineNoteMessage = (noteDeclaration, startLine, lineOffset = 0) => {
|
|
673
|
+
if (noteDeclaration.conflictType === 'note') {
|
|
674
|
+
const conflictLine = lineOffset + noteDeclaration.conflictIndex + 1;
|
|
675
|
+
return `The note starting on line ${startLine} is not closed before another note starts on line ${conflictLine}. Close the first note with "}".`;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
if (noteDeclaration.conflictType === 'reference') {
|
|
679
|
+
const conflictLine = lineOffset + noteDeclaration.conflictIndex + 1;
|
|
680
|
+
return `The note starting on line ${startLine} contains "{note-ref}" on line ${conflictLine}. Close the note before adding a note reference.`;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
return `The note starting on line ${startLine} is not closed. End it with "}" on its own line or at the end of the note text.`;
|
|
684
|
+
};
|
|
609
685
|
|
|
610
686
|
/**
|
|
611
687
|
* Finds the deliberately small inline-note syntax while ignoring fenced and
|
|
@@ -640,8 +716,7 @@ export const extractInlineNoteDiagnostics = (markdown, options = {}) => {
|
|
|
640
716
|
pendingParagraph = null;
|
|
641
717
|
};
|
|
642
718
|
|
|
643
|
-
const attachNote = (
|
|
644
|
-
const text = noteMatch[1].trim();
|
|
719
|
+
const attachNote = (text, lineNumber) => {
|
|
645
720
|
if (!text) {
|
|
646
721
|
addError(`The note on line ${lineNumber} is empty. ${getInlineNoteErrorMessage()}`, lineNumber);
|
|
647
722
|
pendingParagraph = null;
|
|
@@ -686,7 +761,10 @@ export const extractInlineNoteDiagnostics = (markdown, options = {}) => {
|
|
|
686
761
|
|
|
687
762
|
const trimmed = line.trim();
|
|
688
763
|
const maskedTrimmed = maskedLine.trim();
|
|
689
|
-
const
|
|
764
|
+
const startsNoteDeclaration = inlineNoteDeclarationOpeningRegex.test(maskedLine);
|
|
765
|
+
const noteDeclaration = startsNoteDeclaration
|
|
766
|
+
? collectInlineNoteDeclaration(lines, maskedLines, index)
|
|
767
|
+
: null;
|
|
690
768
|
const looksLikeNoteDeclaration = inlineNoteDeclarationStartRegex.test(maskedTrimmed);
|
|
691
769
|
const referenceCount = countInlineNoteReferences(maskedLine);
|
|
692
770
|
const isHeading = /^#{1,6}(?:\s|$)/.test(trimmed);
|
|
@@ -698,8 +776,14 @@ export const extractInlineNoteDiagnostics = (markdown, options = {}) => {
|
|
|
698
776
|
}
|
|
699
777
|
|
|
700
778
|
if (pendingParagraph) {
|
|
701
|
-
if (
|
|
702
|
-
|
|
779
|
+
if (noteDeclaration) {
|
|
780
|
+
if (!noteDeclaration.closed) {
|
|
781
|
+
addError(getUnclosedInlineNoteMessage(noteDeclaration, lineNumber, options.lineOffset), lineNumber);
|
|
782
|
+
pendingParagraph = null;
|
|
783
|
+
} else {
|
|
784
|
+
attachNote(noteDeclaration.text, lineNumber);
|
|
785
|
+
}
|
|
786
|
+
index = noteDeclaration.endIndex;
|
|
703
787
|
continue;
|
|
704
788
|
}
|
|
705
789
|
|
|
@@ -716,13 +800,16 @@ export const extractInlineNoteDiagnostics = (markdown, options = {}) => {
|
|
|
716
800
|
noteJustSeen = false;
|
|
717
801
|
}
|
|
718
802
|
|
|
719
|
-
if (
|
|
803
|
+
if (noteDeclaration || looksLikeNoteDeclaration) {
|
|
720
804
|
addError(
|
|
721
|
-
|
|
722
|
-
?
|
|
805
|
+
noteDeclaration
|
|
806
|
+
? noteDeclaration.closed
|
|
807
|
+
? `A "{note: ...}" requires a preceding paragraph containing "{note-ref}".`
|
|
808
|
+
: getUnclosedInlineNoteMessage(noteDeclaration, lineNumber, options.lineOffset)
|
|
723
809
|
: `Invalid note syntax on line ${lineNumber}. ${getInlineNoteErrorMessage()}`,
|
|
724
810
|
lineNumber,
|
|
725
811
|
);
|
|
812
|
+
if (noteDeclaration) index = noteDeclaration.endIndex;
|
|
726
813
|
continue;
|
|
727
814
|
}
|
|
728
815
|
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
defaultTypography,
|
|
3
3
|
resolveTypographyConfig,
|
|
4
4
|
} from './typography.mjs';
|
|
5
|
+
import { resolveThemeConfig } from './theme-presets.mjs';
|
|
5
6
|
|
|
6
7
|
export const presentationPaletteNames = ['dark', 'light', 'paper'];
|
|
7
8
|
|
|
@@ -92,8 +93,8 @@ export const getPresentationCssVariables = (presentation) => {
|
|
|
92
93
|
};
|
|
93
94
|
};
|
|
94
95
|
|
|
95
|
-
export const resolveThemePresentation = (theme) => {
|
|
96
|
-
const normalizedTheme = theme
|
|
96
|
+
export const resolveThemePresentation = (theme, sourceLabel = 'theme.md') => {
|
|
97
|
+
const normalizedTheme = resolveThemeConfig(theme, sourceLabel);
|
|
97
98
|
const normalizedThemePresentation = normalizePresentation(normalizedTheme.presentation);
|
|
98
99
|
const paletteName = normalizedThemePresentation.palette ?? 'dark';
|
|
99
100
|
const palette = getPresentationPalette(paletteName);
|
|
@@ -109,8 +110,8 @@ export const resolveThemePresentation = (theme) => {
|
|
|
109
110
|
};
|
|
110
111
|
};
|
|
111
112
|
|
|
112
|
-
export const resolvePagePresentation = (theme) => {
|
|
113
|
-
const resolvedThemePresentation = resolveThemePresentation(theme);
|
|
113
|
+
export const resolvePagePresentation = (theme, sourceLabel) => {
|
|
114
|
+
const resolvedThemePresentation = resolveThemePresentation(theme, sourceLabel);
|
|
114
115
|
|
|
115
116
|
return resolvedThemePresentation;
|
|
116
117
|
};
|
|
@@ -126,4 +127,4 @@ export const resolveSectionSurface = (pagePresentation, sectionIndex) => {
|
|
|
126
127
|
};
|
|
127
128
|
};
|
|
128
129
|
|
|
129
|
-
export const resolveFrameColors = ({ theme }) => resolveThemePresentation(theme).palette.frame;
|
|
130
|
+
export const resolveFrameColors = ({ theme, sourceLabel }) => resolveThemePresentation(theme, sourceLabel).palette.frame;
|
|
@@ -1,8 +1,55 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { access, readFile } from 'node:fs/promises';
|
|
2
|
+
import { parseYamlMapping } from './frontmatter-yaml.mjs';
|
|
3
|
+
import {
|
|
4
|
+
splitSiteFile,
|
|
5
|
+
validateConfigFrontmatterStructure,
|
|
6
|
+
validateFrontmatterIndentation,
|
|
7
|
+
} from './site-content.mjs';
|
|
8
|
+
import {
|
|
9
|
+
legacySiteConfigPath,
|
|
10
|
+
siteConfigLabel,
|
|
11
|
+
siteConfigPath,
|
|
12
|
+
siteThemeLabel,
|
|
13
|
+
} from './site-paths.mjs';
|
|
3
14
|
import { readThemeConfig } from './theme-config.mjs';
|
|
15
|
+
import { resolveThemeConfig } from './theme-presets.mjs';
|
|
4
16
|
|
|
5
|
-
const
|
|
17
|
+
const fileExists = (filePath) => access(filePath).then(() => true, () => false);
|
|
18
|
+
const readSiteConfig = async () => {
|
|
19
|
+
const source = await readFile(siteConfigPath, 'utf8').catch(async (error) => {
|
|
20
|
+
if (error?.code === 'ENOENT' && await fileExists(legacySiteConfigPath)) {
|
|
21
|
+
throw new Error(`${siteConfigLabel} is required. Replace the obsolete config.mjs with a frontmatter-only config.md file.`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (error?.code === 'ENOENT') {
|
|
25
|
+
throw new Error(`${siteConfigLabel} is required. Create it before running Norna.`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
throw error;
|
|
29
|
+
});
|
|
30
|
+
const { body, frontmatter, frontmatterBody } = splitSiteFile(source, siteConfigLabel);
|
|
31
|
+
const issues = [];
|
|
32
|
+
|
|
33
|
+
validateFrontmatterIndentation(frontmatter, (issue) => issues.push(issue));
|
|
34
|
+
validateConfigFrontmatterStructure(frontmatter, (issue) => issues.push(issue));
|
|
35
|
+
|
|
36
|
+
if (body.trim()) {
|
|
37
|
+
issues.push({
|
|
38
|
+
message: `${siteConfigLabel} may contain YAML frontmatter only. Remove the Markdown body.`,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (issues.length > 0) {
|
|
43
|
+
throw new Error([
|
|
44
|
+
`${siteConfigLabel} has invalid frontmatter.`,
|
|
45
|
+
...issues.map((issue) => `- ${issue.message}`),
|
|
46
|
+
].join('\n'));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return parseYamlMapping(frontmatterBody);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const siteConfig = await readSiteConfig();
|
|
6
53
|
const themeConfig = await readThemeConfig();
|
|
7
54
|
|
|
8
55
|
const cssLengthPattern = String.raw`(?:\d+|\d*\.\d+)(?:px|rem|em|vw|vh|vmin|vmax|ch|%)`;
|
|
@@ -27,16 +74,6 @@ const readEnum = (object, key, path, allowedValues, fallback, sourceLabel = site
|
|
|
27
74
|
return value;
|
|
28
75
|
};
|
|
29
76
|
|
|
30
|
-
const readString = (object, key, path, sourceLabel = siteConfigLabel) => {
|
|
31
|
-
const value = object[key];
|
|
32
|
-
|
|
33
|
-
if (typeof value !== 'string' || value.trim() === '') {
|
|
34
|
-
throw new Error(`${path}.${key} must be a non-empty string in ${sourceLabel}.`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return value.trim();
|
|
38
|
-
};
|
|
39
|
-
|
|
40
77
|
const readFontFamily = (object, key, path, fallback, sourceLabel = siteConfigLabel) => {
|
|
41
78
|
const value = object[key] ?? fallback;
|
|
42
79
|
|
|
@@ -137,123 +174,82 @@ const readResponsivePercent = (object, key, path, fallback, sourceLabel = siteCo
|
|
|
137
174
|
});
|
|
138
175
|
};
|
|
139
176
|
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
if (typeof value !== 'boolean') {
|
|
144
|
-
throw new Error(`${path}.${key} must be a boolean in ${siteConfigLabel}.`);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return value;
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const readPositiveInteger = (object, key, path, fallback) => {
|
|
151
|
-
const value = object[key] ?? fallback;
|
|
177
|
+
const readSiteUrl = (config) => {
|
|
178
|
+
const configuredValue = process.env.NORNA_SITE_URL ?? config.url;
|
|
152
179
|
|
|
153
|
-
if (
|
|
154
|
-
throw new Error(
|
|
180
|
+
if (typeof configuredValue !== 'string' || configuredValue.trim() === '') {
|
|
181
|
+
throw new Error(`url must be a non-empty absolute URL in ${siteConfigLabel}.`);
|
|
155
182
|
}
|
|
156
183
|
|
|
157
|
-
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const readPositiveNumber = (object, key, path, fallback) => {
|
|
161
|
-
const value = object[key] ?? fallback;
|
|
162
|
-
|
|
163
|
-
if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) {
|
|
164
|
-
throw new Error(`${path}.${key} must be a positive number in ${siteConfigLabel}.`);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return value;
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const readUrl = (object, key, path) => {
|
|
171
|
-
const value = readString(object, key, path);
|
|
172
|
-
|
|
184
|
+
let url;
|
|
173
185
|
try {
|
|
174
|
-
|
|
186
|
+
url = new URL(configuredValue.trim());
|
|
175
187
|
} catch {
|
|
176
|
-
throw new Error(
|
|
188
|
+
throw new Error(`url must be an absolute URL such as "https://example.com/" in ${siteConfigLabel}.`);
|
|
177
189
|
}
|
|
178
|
-
};
|
|
179
190
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (typeof value !== 'string' || value.trim() === '') {
|
|
184
|
-
throw new Error(`${path}.${key} must be a non-empty URL path in ${siteConfigLabel}.`);
|
|
191
|
+
if (!['http:', 'https:'].includes(url.protocol)) {
|
|
192
|
+
throw new Error(`url must use http or https in ${siteConfigLabel}.`);
|
|
185
193
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
) {
|
|
195
|
-
throw new Error(`${path}.${key} must start and end with "/" and must not contain whitespace, "?", "#", or "//" in ${siteConfigLabel}.`);
|
|
194
|
+
if (url.search || url.hash) {
|
|
195
|
+
throw new Error(`url must not contain a query string or fragment in ${siteConfigLabel}.`);
|
|
196
|
+
}
|
|
197
|
+
if (!url.pathname.endsWith('/')) {
|
|
198
|
+
url.pathname = `${url.pathname}/`;
|
|
199
|
+
}
|
|
200
|
+
if (url.pathname.includes('//')) {
|
|
201
|
+
throw new Error(`url must not contain repeated slashes in its path in ${siteConfigLabel}.`);
|
|
196
202
|
}
|
|
197
203
|
|
|
198
|
-
return
|
|
204
|
+
return url;
|
|
199
205
|
};
|
|
200
206
|
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
207
|
+
const localeLabels = Object.freeze({
|
|
208
|
+
en: Object.freeze({
|
|
209
|
+
dismissBanner: 'Dismiss notice',
|
|
210
|
+
gallery: 'Images',
|
|
211
|
+
note: 'Note',
|
|
212
|
+
pageNavigation: 'On this page',
|
|
213
|
+
siteBanners: 'Site notices',
|
|
214
|
+
siteNavigation: 'Pages',
|
|
215
|
+
skipToContent: 'Skip to content',
|
|
216
|
+
}),
|
|
217
|
+
sv: Object.freeze({
|
|
218
|
+
dismissBanner: 'Stäng meddelande',
|
|
219
|
+
gallery: 'Bilder',
|
|
220
|
+
note: 'Not',
|
|
221
|
+
pageNavigation: 'På den här sidan',
|
|
222
|
+
siteBanners: 'Meddelanden',
|
|
223
|
+
siteNavigation: 'Sidor',
|
|
224
|
+
skipToContent: 'Hoppa till innehållet',
|
|
225
|
+
}),
|
|
226
|
+
});
|
|
205
227
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
228
|
+
const readLocale = (config) => {
|
|
229
|
+
const lang = config.language ?? 'en';
|
|
209
230
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
maximumDurationMs,
|
|
214
|
-
minimumDurationMs,
|
|
215
|
-
});
|
|
216
|
-
};
|
|
231
|
+
if (typeof lang !== 'string' || !/^[a-zA-Z]{2,3}(?:-[a-zA-Z0-9]+)*$/.test(lang.trim())) {
|
|
232
|
+
throw new Error(`language must be a valid language tag such as "en" or "sv" in ${siteConfigLabel}.`);
|
|
233
|
+
}
|
|
217
234
|
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
const labels =
|
|
221
|
-
const lang = locale.lang ?? 'en';
|
|
235
|
+
const normalizedLang = lang.trim();
|
|
236
|
+
const languageKey = normalizedLang.toLowerCase().split('-')[0];
|
|
237
|
+
const labels = localeLabels[languageKey];
|
|
222
238
|
|
|
223
|
-
if (
|
|
224
|
-
throw new Error(`
|
|
239
|
+
if (!labels) {
|
|
240
|
+
throw new Error(`language "${normalizedLang}" has no built-in Norna UI text. Supported languages: ${Object.keys(localeLabels).join(', ')}.`);
|
|
225
241
|
}
|
|
226
242
|
|
|
227
243
|
return Object.freeze({
|
|
228
|
-
lang:
|
|
229
|
-
labels
|
|
230
|
-
closeMenu: readString({ closeMenu: labels.closeMenu ?? 'Close menu' }, 'closeMenu', 'locale.labels'),
|
|
231
|
-
dismissBanner: readString({ dismissBanner: labels.dismissBanner ?? 'Dismiss notice' }, 'dismissBanner', 'locale.labels'),
|
|
232
|
-
skipToContent: readString({ skipToContent: labels.skipToContent ?? 'Skip to content' }, 'skipToContent', 'locale.labels'),
|
|
233
|
-
sectionNavigation: readString({ sectionNavigation: labels.sectionNavigation ?? 'Sections' }, 'sectionNavigation', 'locale.labels'),
|
|
234
|
-
gallery: readString({ gallery: labels.gallery ?? 'Images' }, 'gallery', 'locale.labels'),
|
|
235
|
-
note: readString({ note: labels.note ?? 'Note' }, 'note', 'locale.labels'),
|
|
236
|
-
menu: readString({ menu: labels.menu ?? 'Menu' }, 'menu', 'locale.labels'),
|
|
237
|
-
pageNavigation: readString({ pageNavigation: labels.pageNavigation ?? 'On this page' }, 'pageNavigation', 'locale.labels'),
|
|
238
|
-
siteNavigation: readString({ siteNavigation: labels.siteNavigation ?? 'Pages' }, 'siteNavigation', 'locale.labels'),
|
|
239
|
-
siteBanners: readString({ siteBanners: labels.siteBanners ?? 'Site notices' }, 'siteBanners', 'locale.labels'),
|
|
240
|
-
}),
|
|
244
|
+
lang: normalizedLang,
|
|
245
|
+
labels,
|
|
241
246
|
});
|
|
242
247
|
};
|
|
243
248
|
|
|
244
|
-
const rawConfig = assertObject(siteConfig, '
|
|
245
|
-
const misplacedThemeKeys = ['layout', 'gallery', 'typography'].filter((key) => key in rawConfig);
|
|
246
|
-
if (misplacedThemeKeys.length > 0) {
|
|
247
|
-
throw new Error(`${misplacedThemeKeys.join(', ')} belong in ${siteThemeLabel}, not ${siteConfigLabel}.`);
|
|
248
|
-
}
|
|
249
|
-
|
|
249
|
+
const rawConfig = assertObject(siteConfig, 'config frontmatter');
|
|
250
250
|
const rawTheme = assertObject(themeConfig, 'theme frontmatter', siteThemeLabel);
|
|
251
|
-
const
|
|
252
|
-
const
|
|
253
|
-
const rawLocale = rawConfig.locale ?? {};
|
|
254
|
-
const rawGithub = assertObject(rawConfig.github, 'github');
|
|
255
|
-
const rawDeploy = assertObject(rawConfig.deploy ?? {}, 'deploy');
|
|
256
|
-
const rawDeployWatch = assertObject(rawDeploy.watch ?? {}, 'deploy.watch');
|
|
251
|
+
const siteUrl = readSiteUrl(rawConfig);
|
|
252
|
+
const scrollBehaviorNames = ['instant', 'browser-smooth', 'norna-smooth'];
|
|
257
253
|
|
|
258
254
|
const defaultFontFamily = "Arial, 'Helvetica Neue', Helvetica, sans-serif";
|
|
259
255
|
const layoutDensityNames = ['compact', 'normal', 'airy'];
|
|
@@ -338,7 +334,7 @@ const layoutDensityProfiles = Object.freeze({
|
|
|
338
334
|
}),
|
|
339
335
|
});
|
|
340
336
|
export const resolveThemeVisualConfig = (theme, sourceLabel = siteThemeLabel) => {
|
|
341
|
-
const rawThemeConfig = assertObject(theme
|
|
337
|
+
const rawThemeConfig = assertObject(resolveThemeConfig(theme, sourceLabel), 'theme frontmatter', sourceLabel);
|
|
342
338
|
const rawLayoutConfig = assertObject(rawThemeConfig.layout ?? {}, 'layout', sourceLabel);
|
|
343
339
|
const rawLayoutSpacingConfig = assertObject(rawLayoutConfig.spacing ?? {}, 'layout.spacing', sourceLabel);
|
|
344
340
|
const rawGalleryConfig = assertObject(rawThemeConfig.gallery ?? {}, 'gallery', sourceLabel);
|
|
@@ -382,26 +378,20 @@ export const resolveThemeVisualConfig = (theme, sourceLabel = siteThemeLabel) =>
|
|
|
382
378
|
|
|
383
379
|
export const projectConfig = Object.freeze({
|
|
384
380
|
site: Object.freeze({
|
|
385
|
-
basePath:
|
|
386
|
-
url:
|
|
381
|
+
basePath: siteUrl.pathname,
|
|
382
|
+
url: siteUrl.href,
|
|
387
383
|
}),
|
|
388
384
|
...resolveThemeVisualConfig(rawTheme, siteThemeLabel),
|
|
389
385
|
navigation: Object.freeze({
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}),
|
|
398
|
-
deploy: Object.freeze({
|
|
399
|
-
watch: Object.freeze({
|
|
400
|
-
intervalMs: readPositiveInteger(rawDeployWatch, 'intervalMs', 'deploy.watch', 10_000),
|
|
401
|
-
timeoutMs: readPositiveInteger(rawDeployWatch, 'timeoutMs', 'deploy.watch', 15 * 60_000),
|
|
402
|
-
runLimit: readPositiveInteger(rawDeployWatch, 'runLimit', 'deploy.watch', 10),
|
|
403
|
-
}),
|
|
386
|
+
scrollBehavior: readEnum(
|
|
387
|
+
rawConfig,
|
|
388
|
+
'scrollBehavior',
|
|
389
|
+
'config frontmatter',
|
|
390
|
+
scrollBehaviorNames,
|
|
391
|
+
'instant',
|
|
392
|
+
),
|
|
404
393
|
}),
|
|
394
|
+
locale: readLocale(rawConfig),
|
|
405
395
|
});
|
|
406
396
|
|
|
407
397
|
export default projectConfig;
|