@janga/norna 0.7.10 → 0.7.11
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 +4 -2
- package/bin/norna-cli.mjs +3 -0
- package/docs/README.md +3 -2
- package/docs/commands.md +6 -0
- package/docs/configuration.md +1 -0
- package/docs/content.md +14 -14
- package/docs/design/site-examples-structure.md +35 -24
- package/docs/engine-development.md +13 -7
- package/docs/getting-started.md +44 -9
- package/docs/routes.md +2 -1
- package/docs/site-structure.md +8 -5
- package/docs/theme.md +86 -34
- package/docs/typography.md +32 -17
- package/examples/README.md +41 -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/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/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/dev.json +2 -2
- package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.log +53 -0
- package/examples/complete-sites/dog-shelter-multi-page/.astro/settings.json +5 -0
- package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-multi-page}/README.md +1 -1
- package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/_metadata.json +13 -7
- package/examples/complete-sites/dog-shelter-multi-page/site/.norna/generated-images.json +18 -0
- package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-multi-page}/site/config.mjs +5 -2
- package/examples/{001-dog-shelter-single-page → complete-sites/dog-shelter-single-page}/README.md +1 -1
- package/examples/complete-sites/dog-shelter-single-page/site/.norna/generated-images.json +18 -0
- package/examples/{001-dog-shelter-single-page → complete-sites/dog-shelter-single-page}/site/config.mjs +5 -2
- 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/{dog-gallery → feature-demos/media-and-surfaces}/.astro/collections/theme.schema.json +151 -68
- 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 +11 -0
- package/examples/feature-demos/media-and-surfaces/.astro/settings.json +5 -0
- package/examples/feature-demos/media-and-surfaces/README.md +15 -0
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/_metadata.json +74 -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/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/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/{presentation → feature-demos/media-and-surfaces}/site/config.mjs +4 -3
- package/examples/{presentation → feature-demos/media-and-surfaces}/site/content.md +12 -15
- package/examples/{presentation/site/routes/020-media → feature-demos/media-and-surfaces/site/routes/010-media}/route-content.md +11 -3
- package/examples/feature-demos/media-and-surfaces/site/routes/010-media/theme.md +3 -0
- 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/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-modules.mjs +1 -0
- package/examples/{dog-gallery → feature-demos/theme-presets}/.astro/content.d.ts +8 -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/feature-demos/theme-presets/.astro/dev.json +15 -0
- package/examples/feature-demos/theme-presets/.astro/dev.log +127 -0
- package/examples/feature-demos/theme-presets/.astro/types.d.ts +2 -0
- package/examples/feature-demos/theme-presets/README.md +14 -0
- package/examples/feature-demos/theme-presets/node_modules/.vite/deps/embla-carousel.js +1389 -0
- package/examples/feature-demos/theme-presets/node_modules/.vite/deps/embla-carousel.js.map +1 -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/{typography-presets → feature-demos/theme-presets}/site/config.mjs +4 -3
- package/examples/feature-demos/theme-presets/site/content.md +17 -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/{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/{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/{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/package.json +7 -3
- package/scripts/build-pages.mjs +71 -0
- package/scripts/check-config.mjs +2 -1
- package/scripts/export-theme-preset.mjs +31 -0
- package/scripts/init-site.mjs +1 -0
- package/scripts/lib/example-sites.mjs +34 -0
- package/scripts/lib/presentation.mjs +6 -5
- package/scripts/lib/project-config.mjs +2 -1
- package/scripts/lib/site-content.mjs +2 -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-engine-commands.mjs +1 -0
- package/scripts/test-examples.mjs +15 -0
- package/scripts/test-navigation.mjs +73 -45
- package/scripts/test-theme-presets.mjs +151 -0
- package/src/components/SitePage.astro +2 -2
- package/src/content.config.ts +2 -0
- package/src/styles/global.css +2 -0
- package/starters/basic/package.json +1 -0
- package/starters/project/package.json +1 -0
- 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/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/public/robots.txt +0 -2
- 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/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/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/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/collections/site.schema.json +0 -0
- /package/examples/{dog-gallery/.astro/content-modules.mjs → complete-sites/dog-shelter-multi-page/.astro/content-assets.mjs} +0 -0
- /package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/content-modules.mjs +0 -0
- /package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/.astro/content.d.ts +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/astro-D_GIpJIE.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_aria-query.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_axobject-query.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_html-escaper.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/audit-DM9Hkl5B.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -0
- /package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/embla-carousel.js +0 -0
- /package/examples/{typography-presets → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/embla-carousel.js.map +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/highlight-DnZ1ULOL.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/icons-RyebKi45.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/icons-RyebKi45.js.map +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/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/settings-DaU-gNnK.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/toolbar-63PA619H.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/ui-library--bkcNSYz.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/window-jPkpKVcy.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/xray-BXCHpEJP.js +0 -0
- /package/examples/{dog-gallery → complete-sites/dog-shelter-multi-page}/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -0
- /package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-multi-page}/site/content.md +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/{002-dog-shelter-multi-page → complete-sites/dog-shelter-multi-page}/site/routes/010-dogs/images/dogs/rex.svg +0 -0
- /package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-multi-page}/site/routes/010-dogs/images/dogs/rover.svg +0 -0
- /package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-multi-page}/site/routes/010-dogs/route-content.md +0 -0
- /package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-multi-page}/site/routes/020-adopt/route-content.md +0 -0
- /package/examples/{001-dog-shelter-single-page → complete-sites/dog-shelter-multi-page}/site/sitewide-content.md +0 -0
- /package/examples/{001-dog-shelter-single-page → complete-sites/dog-shelter-multi-page}/site/theme.md +0 -0
- /package/examples/{001-dog-shelter-single-page → complete-sites/dog-shelter-single-page}/site/content.md +0 -0
- /package/examples/{001-dog-shelter-single-page → complete-sites/dog-shelter-single-page}/site/images/what-we-do/dog-house.svg +0 -0
- /package/examples/{001-dog-shelter-single-page → complete-sites/dog-shelter-single-page}/site/images/you-can-help/heart.svg +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/{002-dog-shelter-multi-page → complete-sites/dog-shelter-single-page}/site/sitewide-content.md +0 -0
- /package/examples/{002-dog-shelter-multi-page → complete-sites/dog-shelter-single-page}/site/theme.md +0 -0
- /package/examples/{dog-gallery → feature-demos/media-and-surfaces}/.astro/content-assets.mjs +0 -0
- /package/examples/{typography-presets → feature-demos/media-and-surfaces}/.astro/types.d.ts +0 -0
- /package/examples/{typography-presets → feature-demos/media-and-surfaces}/node_modules/.vite/deps/package.json +0 -0
- /package/examples/{typography-presets → feature-demos/media-and-surfaces}/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +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/{presentation/site/routes/030-surfaces → feature-demos/media-and-surfaces/site/routes/020-surfaces}/route-content.md +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-assets.mjs +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/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro-D_GIpJIE.js +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_aria-query.js +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_axobject-query.js +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_html-escaper.js +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/audit-DM9Hkl5B.js +0 -0
- /package/examples/{typography-presets → 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/highlight-DnZ1ULOL.js +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/icons-RyebKi45.js +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/settings-DaU-gNnK.js +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/toolbar-63PA619H.js +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/ui-library--bkcNSYz.js +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/window-jPkpKVcy.js +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/node_modules/.vite/deps/xray-BXCHpEJP.js +0 -0
- /package/examples/{typography-presets → 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/010-quiet-gallery/images/quiet-gallery → feature-demos/theme-presets/site/routes/010-portfolio/images/portfolio}/shepherd-portrait.jpg +0 -0
- /package/examples/{typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery → feature-demos/theme-presets/site/routes/010-portfolio/images/portfolio}/white-puppy.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}/retriever-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}/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}/boxer-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}/grass-puppy.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-grass.jpg +0 -0
- /package/examples/{typography-presets → feature-demos/theme-presets}/site/routes/040-statement/images/statement/sheepdog-wide.jpg +0 -0
|
@@ -7,9 +7,9 @@ navigation:
|
|
|
7
7
|
|
|
8
8
|
## Statement {#statement}
|
|
9
9
|
|
|
10
|
-
This route uses the `statement` preset. Its
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
This route uses the complete `statement` preset without overrides. Its airy
|
|
11
|
+
layout, stronger typography and alternating surfaces suit short, declarative
|
|
12
|
+
content with a more editorial voice.
|
|
13
13
|
|
|
14
14
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec id elit non mi
|
|
15
15
|
porta gravida at eget metus. Integer posuere erat a ante venenatis dapibus
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@janga/norna",
|
|
3
3
|
"description": "A command-line publishing workflow for simple static sites.",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.7.
|
|
5
|
+
"version": "0.7.11",
|
|
6
6
|
"license": "GPL-3.0-only",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -51,22 +51,26 @@
|
|
|
51
51
|
"config:check": "node bin/norna.mjs config:check",
|
|
52
52
|
"content:check": "node bin/norna.mjs content:check",
|
|
53
53
|
"content:sync": "node bin/norna.mjs content:sync",
|
|
54
|
+
"theme:export": "node bin/norna.mjs theme:export",
|
|
54
55
|
"typography:presets": "node bin/norna.mjs typography presets",
|
|
55
56
|
"typography:show": "node bin/norna.mjs typography show",
|
|
56
57
|
"site:public": "node bin/norna.mjs site:public",
|
|
57
58
|
"images": "node bin/norna.mjs images",
|
|
58
59
|
"build": "node bin/norna.mjs build",
|
|
60
|
+
"build:pages": "node scripts/build-pages.mjs",
|
|
59
61
|
"build:local": "node bin/norna.mjs build:local",
|
|
60
62
|
"deploy": "node bin/norna.mjs deploy",
|
|
61
63
|
"deploy:commit": "node bin/norna.mjs deploy:commit",
|
|
62
64
|
"deploy:watch": "node bin/norna.mjs deploy:watch",
|
|
63
65
|
"doctor": "node bin/norna.mjs doctor",
|
|
64
|
-
"demo:build": "node bin/norna.mjs --site-dir examples/
|
|
65
|
-
"test": "npm run test:route-model && npm run test:content-check && npm run test:content-model-v2 && npm run test:site-public && npm run test:cli-discovery && npm run test:engine-commands && npm run test:ci-lockfile && npm run test:temporary-visibility && npm run test:fixture:build && npm run package:check",
|
|
66
|
+
"demo:build": "node bin/norna.mjs --site-dir examples/feature-demos/media-and-surfaces/site build",
|
|
67
|
+
"test": "npm run test:route-model && npm run test:content-check && npm run test:content-model-v2 && npm run test:theme-presets && npm run test:site-public && npm run test:cli-discovery && npm run test:engine-commands && npm run test:ci-lockfile && npm run test:temporary-visibility && npm run test:fixture:build && npm run test:examples && npm run package:check",
|
|
66
68
|
"test:fixture:build": "node bin/norna.mjs --site-dir fixtures/basic/site build",
|
|
69
|
+
"test:examples": "node scripts/test-examples.mjs",
|
|
67
70
|
"test:route-model": "node scripts/test-route-model.mjs",
|
|
68
71
|
"test:content-check": "node scripts/test-content-check.mjs",
|
|
69
72
|
"test:content-model-v2": "node scripts/test-content-model-v2.mjs",
|
|
73
|
+
"test:theme-presets": "node scripts/test-theme-presets.mjs",
|
|
70
74
|
"test:site-public": "node scripts/test-site-public.mjs",
|
|
71
75
|
"test:cli-discovery": "node scripts/test-cli-discovery.mjs",
|
|
72
76
|
"test:engine-commands": "node scripts/test-engine-commands.mjs",
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { cp, mkdir, mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import documentationConfig from '../site/config.mjs';
|
|
6
|
+
import { getExampleSites } from './lib/example-sites.mjs';
|
|
7
|
+
import { runInherit } from './lib/run-command.mjs';
|
|
8
|
+
|
|
9
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
10
|
+
const cliPath = path.join(root, 'bin', 'norna.mjs');
|
|
11
|
+
const distDirectory = path.join(root, 'dist');
|
|
12
|
+
const temporaryDirectory = await mkdtemp(path.join(tmpdir(), 'norna-pages-'));
|
|
13
|
+
const artifactDirectory = path.join(temporaryDirectory, 'artifact');
|
|
14
|
+
const documentationUrl = new URL(documentationConfig.site.url);
|
|
15
|
+
const documentationBasePath = documentationConfig.site.basePath;
|
|
16
|
+
const examples = await getExampleSites(root);
|
|
17
|
+
let artifactStarted = false;
|
|
18
|
+
|
|
19
|
+
const buildSite = (siteLabel, env = process.env) => runInherit(
|
|
20
|
+
process.execPath,
|
|
21
|
+
[cliPath, ...(siteLabel ? ['--site-dir', siteLabel] : []), 'build'],
|
|
22
|
+
{ cwd: root, env },
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
console.log('Building documentation site');
|
|
27
|
+
await buildSite();
|
|
28
|
+
await cp(distDirectory, artifactDirectory, { recursive: true });
|
|
29
|
+
artifactStarted = true;
|
|
30
|
+
|
|
31
|
+
for (const example of examples) {
|
|
32
|
+
const relativePublicPath = `examples/${example.category}/${example.name}/`;
|
|
33
|
+
const basePath = `${documentationBasePath.replace(/\/$/, '')}/${relativePublicPath}`;
|
|
34
|
+
const siteUrl = new URL(relativePublicPath, documentationUrl).href;
|
|
35
|
+
|
|
36
|
+
console.log(`\nBuilding ${example.siteLabel} for ${siteUrl}`);
|
|
37
|
+
await buildSite(example.siteLabel, {
|
|
38
|
+
...process.env,
|
|
39
|
+
NORNA_EXAMPLE_BASE_PATH: basePath,
|
|
40
|
+
NORNA_EXAMPLE_SITE_URL: siteUrl,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const destination = path.join(artifactDirectory, relativePublicPath);
|
|
44
|
+
await mkdir(path.dirname(destination), { recursive: true });
|
|
45
|
+
await cp(distDirectory, destination, { recursive: true });
|
|
46
|
+
}
|
|
47
|
+
} finally {
|
|
48
|
+
if (artifactStarted) {
|
|
49
|
+
await rm(distDirectory, { recursive: true, force: true });
|
|
50
|
+
await cp(artifactDirectory, distDirectory, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
await rm(temporaryDirectory, { recursive: true, force: true });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const documentationExamplesHtml = await readFile(path.join(distDirectory, 'examples', 'index.html'), 'utf8');
|
|
56
|
+
|
|
57
|
+
for (const example of examples) {
|
|
58
|
+
const relativePublicPath = `examples/${example.category}/${example.name}/`;
|
|
59
|
+
const basePath = `${documentationBasePath.replace(/\/$/, '')}/${relativePublicPath}`;
|
|
60
|
+
const siteUrl = new URL(relativePublicPath, documentationUrl).href;
|
|
61
|
+
const exampleHtml = await readFile(path.join(distDirectory, relativePublicPath, 'index.html'), 'utf8');
|
|
62
|
+
|
|
63
|
+
if (!documentationExamplesHtml.includes(`href="${siteUrl}"`)) {
|
|
64
|
+
throw new Error(`Documentation is missing the rendered example link ${siteUrl}.`);
|
|
65
|
+
}
|
|
66
|
+
if (!exampleHtml.includes(`href="${basePath}`) && !exampleHtml.includes(`src="${basePath}`)) {
|
|
67
|
+
throw new Error(`Rendered example ${relativePublicPath} does not use its deployment base path ${basePath}.`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(`\nok - assembled documentation and ${examples.length} rendered examples in dist/`);
|
package/scripts/check-config.mjs
CHANGED
|
@@ -20,7 +20,7 @@ const formatErrorMessage = (error) => {
|
|
|
20
20
|
|
|
21
21
|
try {
|
|
22
22
|
const { projectConfig } = await import('./lib/project-config.mjs');
|
|
23
|
-
await readThemeConfig();
|
|
23
|
+
const themeConfig = await readThemeConfig();
|
|
24
24
|
const sitewideConfig = await readSitewideConfig();
|
|
25
25
|
await validateRouteThemeFiles();
|
|
26
26
|
const logoAssets = getLogoAssets();
|
|
@@ -42,6 +42,7 @@ try {
|
|
|
42
42
|
console.log('Config check passed.');
|
|
43
43
|
console.log(`Site URL: ${projectConfig.site.url}`);
|
|
44
44
|
console.log(`Base path: ${projectConfig.site.basePath}`);
|
|
45
|
+
console.log(`Theme preset: ${themeConfig.preset ?? '(none)'}`);
|
|
45
46
|
console.log(`Page width: ${projectConfig.layout.pageWidth}`);
|
|
46
47
|
console.log(`Gutter: desktop ${projectConfig.layout.gutter.desktop}, mobile ${projectConfig.layout.gutter.mobile}`);
|
|
47
48
|
console.log(`Layout density: ${projectConfig.layout.density}`);
|
|
@@ -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,34 @@
|
|
|
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, 'content.md'))) {
|
|
17
|
+
throw new Error(`Example ${path.relative(root, siteDirectory)} is missing content.md.`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
examples.push({
|
|
21
|
+
category,
|
|
22
|
+
name: entry.name,
|
|
23
|
+
siteDirectory,
|
|
24
|
+
siteLabel: path.relative(root, siteDirectory),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (examples.length === 0) {
|
|
30
|
+
throw new Error('No example sites were found.');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return examples;
|
|
34
|
+
};
|
|
@@ -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,6 +1,7 @@
|
|
|
1
1
|
import { pathToFileURL } from 'node:url';
|
|
2
2
|
import { siteConfigLabel, siteConfigPath, siteThemeLabel } from './site-paths.mjs';
|
|
3
3
|
import { readThemeConfig } from './theme-config.mjs';
|
|
4
|
+
import { resolveThemeConfig } from './theme-presets.mjs';
|
|
4
5
|
|
|
5
6
|
const { default: siteConfig } = await import(/* @vite-ignore */ pathToFileURL(siteConfigPath).href);
|
|
6
7
|
const themeConfig = await readThemeConfig();
|
|
@@ -338,7 +339,7 @@ const layoutDensityProfiles = Object.freeze({
|
|
|
338
339
|
}),
|
|
339
340
|
});
|
|
340
341
|
export const resolveThemeVisualConfig = (theme, sourceLabel = siteThemeLabel) => {
|
|
341
|
-
const rawThemeConfig = assertObject(theme
|
|
342
|
+
const rawThemeConfig = assertObject(resolveThemeConfig(theme, sourceLabel), 'theme frontmatter', sourceLabel);
|
|
342
343
|
const rawLayoutConfig = assertObject(rawThemeConfig.layout ?? {}, 'layout', sourceLabel);
|
|
343
344
|
const rawLayoutSpacingConfig = assertObject(rawLayoutConfig.spacing ?? {}, 'layout.spacing', sourceLabel);
|
|
344
345
|
const rawGalleryConfig = assertObject(rawThemeConfig.gallery ?? {}, 'gallery', sourceLabel);
|
|
@@ -21,8 +21,8 @@ const explicitHeadingIdRegex = /\s*\{#([a-z0-9-]+)\}\s*$/;
|
|
|
21
21
|
const deprecatedInlineStyleReferenceRegex = /\[[^\]\n]+\]\{\.([a-z][a-z0-9-]*)\}/g;
|
|
22
22
|
const frontmatterDelimiterRegex = /^---\s*$/;
|
|
23
23
|
const knownContentTopLevelFrontmatterKeys = new Set(['title', 'description', 'navigation', 'sections']);
|
|
24
|
-
const knownThemeTopLevelFrontmatterKeys = new Set(['navigation', 'layout', 'gallery', 'typography', 'presentation']);
|
|
25
|
-
const knownRouteThemeTopLevelFrontmatterKeys = new Set(['navigation', 'layout', 'gallery', 'typography', 'presentation']);
|
|
24
|
+
const knownThemeTopLevelFrontmatterKeys = new Set(['navigation', 'preset', 'layout', 'gallery', 'typography', 'presentation']);
|
|
25
|
+
const knownRouteThemeTopLevelFrontmatterKeys = new Set(['navigation', 'preset', 'layout', 'gallery', 'typography', 'presentation']);
|
|
26
26
|
const knownSitewideTopLevelFrontmatterKeys = new Set(['navigation', 'banners', 'footer']);
|
|
27
27
|
const knownNestedFrontmatterKeys = new Set([
|
|
28
28
|
'align',
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
siteThemePath,
|
|
15
15
|
sitewideContentLabel,
|
|
16
16
|
} from './site-paths.mjs';
|
|
17
|
+
import { resolveThemeConfig } from './theme-presets.mjs';
|
|
17
18
|
|
|
18
19
|
export const readThemeConfig = async () => {
|
|
19
20
|
const themeFile = await readFile(siteThemePath, 'utf8').catch((error) => {
|
|
@@ -40,6 +41,7 @@ export const readThemeConfig = async () => {
|
|
|
40
41
|
if (Object.hasOwn(config, 'navigation')) {
|
|
41
42
|
throw new Error(`${siteThemeLabel} may not define navigation. Brand and logo belong in ${sitewideContentLabel}.`);
|
|
42
43
|
}
|
|
44
|
+
resolveThemeConfig(config, siteThemeLabel);
|
|
43
45
|
|
|
44
46
|
return config;
|
|
45
47
|
};
|
|
@@ -92,6 +94,7 @@ export const validateRouteThemeFiles = async () => {
|
|
|
92
94
|
if (Object.hasOwn(config, 'navigation')) {
|
|
93
95
|
throw new Error(`${file.label} may not define navigation. Brand and logo belong in ${sitewideContentLabel}.`);
|
|
94
96
|
}
|
|
97
|
+
resolveThemeConfig(config, file.label);
|
|
95
98
|
|
|
96
99
|
configs.push({ ...file, config });
|
|
97
100
|
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { mergeDeep } from './typography.mjs';
|
|
2
|
+
|
|
3
|
+
export const themePresetNames = [
|
|
4
|
+
'portfolio',
|
|
5
|
+
'documentation',
|
|
6
|
+
'project',
|
|
7
|
+
'statement',
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
export const themePresets = Object.freeze({
|
|
11
|
+
portfolio: Object.freeze({
|
|
12
|
+
layout: {
|
|
13
|
+
density: 'normal',
|
|
14
|
+
pageWidth: '1240px',
|
|
15
|
+
gutter: {
|
|
16
|
+
desktop: 'clamp(1.25rem, 4vw, 3rem)',
|
|
17
|
+
mobile: '1rem',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
gallery: {
|
|
21
|
+
width: '1000px',
|
|
22
|
+
maxAvailableWidthPercent: { desktop: 100, mobile: 100 },
|
|
23
|
+
maxAvailableHeightPercent: { desktop: 78, mobile: 68 },
|
|
24
|
+
},
|
|
25
|
+
typography: {
|
|
26
|
+
fontFamily: "'Helvetica Neue', Arial, sans-serif",
|
|
27
|
+
preset: 'quiet-gallery',
|
|
28
|
+
rhythm: 'normal',
|
|
29
|
+
},
|
|
30
|
+
presentation: {
|
|
31
|
+
palette: 'dark',
|
|
32
|
+
sectionSurfaces: {
|
|
33
|
+
mode: 'none',
|
|
34
|
+
sequence: ['base', 'soft', 'emphasis'],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
documentation: Object.freeze({
|
|
39
|
+
layout: {
|
|
40
|
+
density: 'compact',
|
|
41
|
+
pageWidth: '1240px',
|
|
42
|
+
gutter: {
|
|
43
|
+
desktop: 'clamp(1.25rem, 4vw, 3rem)',
|
|
44
|
+
mobile: '1rem',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
gallery: {
|
|
48
|
+
width: '920px',
|
|
49
|
+
maxAvailableWidthPercent: { desktop: 100, mobile: 100 },
|
|
50
|
+
maxAvailableHeightPercent: { desktop: 74, mobile: 68 },
|
|
51
|
+
},
|
|
52
|
+
typography: {
|
|
53
|
+
fontFamily: "Georgia, 'Times New Roman', serif",
|
|
54
|
+
preset: 'text-forward',
|
|
55
|
+
rhythm: 'compact',
|
|
56
|
+
},
|
|
57
|
+
presentation: {
|
|
58
|
+
palette: 'paper',
|
|
59
|
+
sectionSurfaces: {
|
|
60
|
+
mode: 'cycle',
|
|
61
|
+
sequence: ['base', 'soft'],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
}),
|
|
65
|
+
project: Object.freeze({
|
|
66
|
+
layout: {
|
|
67
|
+
density: 'compact',
|
|
68
|
+
pageWidth: '1120px',
|
|
69
|
+
gutter: {
|
|
70
|
+
desktop: 'clamp(1.25rem, 4vw, 3rem)',
|
|
71
|
+
mobile: '1rem',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
gallery: {
|
|
75
|
+
width: '840px',
|
|
76
|
+
maxAvailableWidthPercent: { desktop: 100, mobile: 100 },
|
|
77
|
+
maxAvailableHeightPercent: { desktop: 70, mobile: 62 },
|
|
78
|
+
},
|
|
79
|
+
typography: {
|
|
80
|
+
fontFamily: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
81
|
+
preset: 'text-forward',
|
|
82
|
+
rhythm: 'compact',
|
|
83
|
+
},
|
|
84
|
+
presentation: {
|
|
85
|
+
palette: 'light',
|
|
86
|
+
sectionSurfaces: {
|
|
87
|
+
mode: 'cycle',
|
|
88
|
+
sequence: ['base', 'soft'],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
}),
|
|
92
|
+
statement: Object.freeze({
|
|
93
|
+
layout: {
|
|
94
|
+
density: 'airy',
|
|
95
|
+
pageWidth: '1280px',
|
|
96
|
+
gutter: {
|
|
97
|
+
desktop: 'clamp(1.5rem, 5vw, 4rem)',
|
|
98
|
+
mobile: '1rem',
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
gallery: {
|
|
102
|
+
width: '1080px',
|
|
103
|
+
maxAvailableWidthPercent: { desktop: 100, mobile: 100 },
|
|
104
|
+
maxAvailableHeightPercent: { desktop: 80, mobile: 70 },
|
|
105
|
+
},
|
|
106
|
+
typography: {
|
|
107
|
+
fontFamily: "'Trebuchet MS', 'Helvetica Neue', Arial, sans-serif",
|
|
108
|
+
preset: 'statement',
|
|
109
|
+
rhythm: 'airy',
|
|
110
|
+
},
|
|
111
|
+
presentation: {
|
|
112
|
+
palette: 'paper',
|
|
113
|
+
sectionSurfaces: {
|
|
114
|
+
mode: 'cycle',
|
|
115
|
+
sequence: ['base', 'emphasis'],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
}),
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
export const getThemePreset = (presetName, sourceLabel = 'theme.md') => {
|
|
122
|
+
const preset = themePresets[presetName];
|
|
123
|
+
|
|
124
|
+
if (!preset) {
|
|
125
|
+
throw new Error(`Unknown theme preset "${presetName}" in ${sourceLabel}. Use one of: ${themePresetNames.join(', ')}.`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return structuredClone(preset);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const resolveThemeConfig = (theme = {}, sourceLabel = 'theme.md') => {
|
|
132
|
+
const presetName = theme?.preset;
|
|
133
|
+
if (presetName === undefined) return structuredClone(theme ?? {});
|
|
134
|
+
|
|
135
|
+
const overrides = structuredClone(theme ?? {});
|
|
136
|
+
delete overrides.preset;
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
preset: presetName,
|
|
140
|
+
...mergeDeep(getThemePreset(presetName, sourceLabel), overrides),
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const quote = (value) => JSON.stringify(value);
|
|
145
|
+
const responsiveValueLines = (label, value, indent = 2) => {
|
|
146
|
+
const prefix = ' '.repeat(indent);
|
|
147
|
+
return [
|
|
148
|
+
`${prefix}${label}:`,
|
|
149
|
+
`${prefix} desktop: ${value.desktop}`,
|
|
150
|
+
`${prefix} mobile: ${value.mobile}`,
|
|
151
|
+
];
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export const renderThemePresetReference = (presetName, sourceLabel = 'theme.md') => {
|
|
155
|
+
const preset = getThemePreset(presetName, sourceLabel);
|
|
156
|
+
const { layout, gallery, typography, presentation } = preset;
|
|
157
|
+
|
|
158
|
+
return [
|
|
159
|
+
'---',
|
|
160
|
+
`# Original values for Norna's "${presetName}" theme preset.`,
|
|
161
|
+
'# This is a reference file. Norna only loads theme.md.',
|
|
162
|
+
'# Keep the preset in theme.md and copy only the values you want to override.',
|
|
163
|
+
`# Available theme presets: ${themePresetNames.join(', ')}.`,
|
|
164
|
+
`preset: ${presetName}`,
|
|
165
|
+
'',
|
|
166
|
+
'layout:',
|
|
167
|
+
' # Alternatives: compact, normal, airy.',
|
|
168
|
+
` density: ${layout.density}`,
|
|
169
|
+
' # Any positive CSS length, including px, rem, em, %, or clamp(...).',
|
|
170
|
+
` pageWidth: ${layout.pageWidth}`,
|
|
171
|
+
' gutter:',
|
|
172
|
+
` desktop: ${layout.gutter.desktop}`,
|
|
173
|
+
` mobile: ${layout.gutter.mobile}`,
|
|
174
|
+
' # Optional spacing overrides use blockGap, finalSectionBottom,',
|
|
175
|
+
' # firstSectionTop, headingToBlock, imageGap, and sectionGap.',
|
|
176
|
+
'',
|
|
177
|
+
'gallery:',
|
|
178
|
+
' # width accepts a positive CSS length.',
|
|
179
|
+
` width: ${gallery.width}`,
|
|
180
|
+
' # Percent values must be greater than 0 and at most 100.',
|
|
181
|
+
...responsiveValueLines('maxAvailableWidthPercent', gallery.maxAvailableWidthPercent),
|
|
182
|
+
...responsiveValueLines('maxAvailableHeightPercent', gallery.maxAvailableHeightPercent),
|
|
183
|
+
'',
|
|
184
|
+
'typography:',
|
|
185
|
+
' # Any valid CSS font-family stack without semicolons.',
|
|
186
|
+
` fontFamily: ${quote(typography.fontFamily)}`,
|
|
187
|
+
' # Alternatives: quiet-gallery, compact-gallery, text-forward, statement.',
|
|
188
|
+
` preset: ${typography.preset}`,
|
|
189
|
+
' # Alternatives: compact, normal, airy.',
|
|
190
|
+
` rhythm: ${typography.rhythm}`,
|
|
191
|
+
' # Fine-grained overrides can target headings.h1-h4, body, and caption.',
|
|
192
|
+
' # Example:',
|
|
193
|
+
' # overrides:',
|
|
194
|
+
' # headings:',
|
|
195
|
+
' # h2:',
|
|
196
|
+
' # size: large # small, medium, large, or xlarge',
|
|
197
|
+
'',
|
|
198
|
+
'presentation:',
|
|
199
|
+
' # Alternatives: dark, light, paper.',
|
|
200
|
+
` palette: ${presentation.palette}`,
|
|
201
|
+
' sectionSurfaces:',
|
|
202
|
+
' # Alternatives: none, cycle.',
|
|
203
|
+
` mode: ${presentation.sectionSurfaces.mode}`,
|
|
204
|
+
' # Use one to three unique values from: base, soft, emphasis.',
|
|
205
|
+
` sequence: [${presentation.sectionSurfaces.sequence.join(', ')}]`,
|
|
206
|
+
'---',
|
|
207
|
+
'',
|
|
208
|
+
].join('\n');
|
|
209
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { parseYamlMapping } from './lib/frontmatter-yaml.mjs';
|
|
4
4
|
import {
|
|
5
5
|
defaultTypography,
|
|
6
6
|
resolveTypographyConfig,
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
siteThemeLabel,
|
|
26
26
|
siteThemePath,
|
|
27
27
|
} from './lib/site-paths.mjs';
|
|
28
|
+
import { resolveThemeConfig } from './lib/theme-presets.mjs';
|
|
28
29
|
|
|
29
30
|
const mode = process.argv[2] ?? 'show';
|
|
30
31
|
|
|
@@ -204,8 +205,8 @@ const readThemeTypography = async () => {
|
|
|
204
205
|
].join('\n'));
|
|
205
206
|
}
|
|
206
207
|
|
|
207
|
-
const
|
|
208
|
-
const themeTypographyConfig =
|
|
208
|
+
const themeConfig = resolveThemeConfig(parseYamlMapping(themeFrontmatterBody), siteThemeLabel);
|
|
209
|
+
const themeTypographyConfig = themeConfig.typography;
|
|
209
210
|
return resolveAnnotatedTypographyConfig(themeTypographyConfig ?? defaultTypography, siteThemeLabel);
|
|
210
211
|
};
|
|
211
212
|
|
|
@@ -231,8 +232,8 @@ const readRouteThemeTypography = async (contentFile, themeTypography) => {
|
|
|
231
232
|
].join('\n'));
|
|
232
233
|
}
|
|
233
234
|
|
|
234
|
-
const
|
|
235
|
-
const typographyConfig =
|
|
235
|
+
const routeThemeConfig = resolveThemeConfig(parseYamlMapping(frontmatterBody), routeThemeLabel);
|
|
236
|
+
const typographyConfig = routeThemeConfig.typography;
|
|
236
237
|
return resolveAnnotatedTypographyConfig(typographyConfig ?? defaultTypography, routeThemeLabel);
|
|
237
238
|
};
|
|
238
239
|
|
|
@@ -45,6 +45,7 @@ try {
|
|
|
45
45
|
assert.equal(initializedPackageJson.dependencies['@janga/norna'], packageJson.version);
|
|
46
46
|
assert.equal(initializedPackageJson.scripts['norna:engine:update'], 'norna engine:update');
|
|
47
47
|
assert.equal(initializedPackageJson.scripts['norna:engine:version'], 'norna engine:version');
|
|
48
|
+
assert.equal(initializedPackageJson.scripts['norna:theme:export'], 'norna theme:export');
|
|
48
49
|
assert.equal(initializedPackageJson.scripts['engine:update'], undefined);
|
|
49
50
|
assert.equal(initializedPackageJson.scripts['engine:version'], undefined);
|
|
50
51
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { getExampleSites } from './lib/example-sites.mjs';
|
|
4
|
+
import { runInherit } from './lib/run-command.mjs';
|
|
5
|
+
|
|
6
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
7
|
+
const cliPath = path.join(root, 'bin', 'norna.mjs');
|
|
8
|
+
const examples = await getExampleSites(root);
|
|
9
|
+
|
|
10
|
+
for (const example of examples) {
|
|
11
|
+
console.log(`\nBuilding ${example.siteLabel}`);
|
|
12
|
+
await runInherit(process.execPath, [cliPath, '--site-dir', example.siteLabel, 'build'], { cwd: root });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log(`\nok - built ${examples.length} example sites`);
|