@janga/norna 0.7.16 → 0.7.18
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 +18 -9
- package/astro.config.mjs +35 -3
- package/bin/norna-cli.mjs +1 -1
- package/docs/README.md +16 -14
- package/docs/commands.md +2 -2
- package/docs/configuration.md +25 -2
- package/docs/content.md +92 -103
- package/docs/design/navigation-and-theme-plan.md +186 -0
- package/docs/design/norna-diagram-design.md +9 -9
- package/docs/design/site-examples-structure.md +15 -11
- package/docs/engine-development.md +19 -22
- package/docs/getting-started.md +21 -16
- package/docs/images-and-metadata.md +12 -9
- package/docs/pages.md +190 -0
- package/docs/public-files.md +49 -36
- package/docs/publishing.md +19 -3
- package/docs/site-files.md +46 -38
- package/docs/sitewide-content.md +20 -36
- package/docs/theme.md +109 -143
- package/docs/typography.md +19 -31
- package/examples/README.md +10 -4
- package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/site.schema.json +17 -41
- package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/sitewide.schema.json +26 -67
- package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/theme.schema.json +185 -88
- package/examples/complete-sites/dog-shelter-multi-page/.astro/data-store.json +1 -1
- package/examples/complete-sites/dog-shelter-multi-page/.astro/dev-local.json +4 -4
- package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.json +5 -5
- package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.log +33 -23
- package/examples/complete-sites/dog-shelter-multi-page/README.md +1 -1
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/_metadata.json +8 -8
- package/examples/complete-sites/dog-shelter-multi-page/site/.norna/generated-images.json +20 -20
- package/examples/complete-sites/dog-shelter-multi-page/site/{content.md → pages/000-home/content.md} +3 -4
- package/examples/complete-sites/dog-shelter-multi-page/site/{routes → pages}/010-dogs/content.md +3 -4
- package/examples/complete-sites/dog-shelter-multi-page/site/{routes → pages}/020-adopt/content.md +3 -4
- package/examples/complete-sites/dog-shelter-multi-page/site/sitewide-content.yaml +2 -4
- package/examples/complete-sites/dog-shelter-single-page/.astro/collections/site.schema.json +17 -41
- package/examples/complete-sites/dog-shelter-single-page/.astro/collections/sitewide.schema.json +26 -67
- package/examples/complete-sites/dog-shelter-single-page/.astro/collections/theme.schema.json +185 -88
- package/examples/complete-sites/dog-shelter-single-page/.astro/data-store.json +1 -1
- package/examples/complete-sites/dog-shelter-single-page/.astro/dev-local.json +8 -0
- package/examples/complete-sites/dog-shelter-single-page/.astro/dev.json +5 -5
- package/examples/complete-sites/dog-shelter-single-page/.astro/dev.log +16 -12
- package/examples/complete-sites/dog-shelter-single-page/README.md +1 -1
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/_metadata.json +8 -8
- package/examples/complete-sites/dog-shelter-single-page/site/.norna/generated-images.json +12 -12
- package/examples/complete-sites/dog-shelter-single-page/site/{content.md → pages/000-home/content.md} +5 -2
- package/examples/complete-sites/dog-shelter-single-page/site/sitewide-content.yaml +2 -4
- package/examples/feature-demos/media-and-surfaces/.astro/collections/site.schema.json +17 -41
- package/examples/feature-demos/media-and-surfaces/.astro/collections/sitewide.schema.json +26 -67
- package/examples/feature-demos/media-and-surfaces/.astro/collections/theme.schema.json +180 -91
- package/examples/feature-demos/media-and-surfaces/.astro/data-store.json +1 -1
- package/examples/feature-demos/media-and-surfaces/.astro/dev.log +4 -14
- package/examples/feature-demos/media-and-surfaces/README.md +2 -2
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/_metadata.json +9 -9
- package/examples/feature-demos/media-and-surfaces/site/.norna/generated-images.json +16 -16
- package/examples/feature-demos/media-and-surfaces/site/{content.md → pages/000-home/content.md} +4 -7
- package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/010-media/content.md +6 -5
- package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/020-surfaces/content.md +9 -7
- package/examples/feature-demos/media-and-surfaces/site/pages/020-surfaces/theme.yaml +2 -0
- package/examples/feature-demos/media-and-surfaces/site/sitewide-content.yaml +0 -2
- package/examples/feature-demos/sitewide-content/README.md +3 -3
- package/examples/feature-demos/sitewide-content/site/pages/000-home/content.md +17 -0
- package/examples/feature-demos/sitewide-content/site/pages/010-logo-and-navigation/content.md +17 -0
- package/examples/feature-demos/sitewide-content/site/{routes → pages}/020-notices/content.md +7 -6
- package/examples/feature-demos/sitewide-content/site/{routes → pages}/030-footer/content.md +6 -5
- package/examples/feature-demos/sitewide-content/site/sitewide-content.yaml +4 -13
- package/examples/feature-demos/theme-preset-documentation/README.md +16 -0
- package/examples/feature-demos/theme-preset-documentation/site/.norna/generated-images.json +74 -0
- package/examples/feature-demos/{theme-presets/site/routes/020-documentation → theme-preset-documentation/site/pages/000-home}/content.md +4 -7
- package/examples/feature-demos/theme-preset-documentation/site/sitewide-content.yaml +3 -0
- package/examples/feature-demos/theme-preset-portfolio/README.md +16 -0
- package/examples/feature-demos/theme-preset-portfolio/site/.norna/generated-images.json +74 -0
- package/examples/feature-demos/theme-preset-portfolio/site/config.yaml +1 -0
- package/examples/feature-demos/{theme-presets/site/routes/010-portfolio → theme-preset-portfolio/site/pages/000-home}/content.md +4 -7
- package/examples/feature-demos/theme-preset-portfolio/site/public/robots.txt +2 -0
- package/examples/feature-demos/theme-preset-portfolio/site/sitewide-content.yaml +3 -0
- package/examples/feature-demos/theme-preset-project/README.md +16 -0
- package/examples/feature-demos/theme-preset-project/site/.norna/generated-images.json +74 -0
- package/examples/feature-demos/theme-preset-project/site/config.yaml +1 -0
- package/examples/feature-demos/{theme-presets/site/routes/030-project → theme-preset-project/site/pages/000-home}/content.md +4 -7
- package/examples/feature-demos/theme-preset-project/site/public/robots.txt +2 -0
- package/examples/feature-demos/theme-preset-project/site/sitewide-content.yaml +3 -0
- package/examples/feature-demos/theme-preset-statement/README.md +16 -0
- package/examples/feature-demos/theme-preset-statement/site/.norna/generated-images.json +74 -0
- package/examples/feature-demos/theme-preset-statement/site/config.yaml +1 -0
- package/examples/feature-demos/{theme-presets/site/routes/040-statement → theme-preset-statement/site/pages/000-home}/content.md +4 -7
- package/examples/feature-demos/theme-preset-statement/site/public/robots.txt +2 -0
- package/examples/feature-demos/theme-preset-statement/site/sitewide-content.yaml +3 -0
- package/fixtures/basic/site/{content.md → pages/000-home/content.md} +5 -6
- package/fixtures/basic/site/sitewide-content.yaml +1 -8
- package/fixtures/basic/site/theme.yaml +1 -8
- package/fixtures/content-model-v2/site/{content.md → pages/000-home/content.md} +11 -13
- package/fixtures/content-model-v2/site/pages/010-guide/content.md +18 -0
- package/fixtures/nested-pages/.astro/collections/site.schema.json +35 -0
- package/fixtures/nested-pages/.astro/collections/sitewide.schema.json +97 -0
- package/fixtures/nested-pages/.astro/collections/theme.schema.json +844 -0
- package/fixtures/nested-pages/.astro/content-assets.mjs +4 -0
- package/fixtures/nested-pages/.astro/content-modules.mjs +1 -0
- package/fixtures/nested-pages/.astro/content.d.ts +183 -0
- package/fixtures/nested-pages/.astro/data-store.json +1 -0
- package/fixtures/nested-pages/.astro/dev-local.json +8 -0
- package/fixtures/nested-pages/.astro/dev.log +1128 -0
- package/fixtures/nested-pages/.astro/settings.json +5 -0
- package/fixtures/nested-pages/.astro/types.d.ts +2 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/_metadata.json +74 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/astro-D_GIpJIE.js +434 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/astro-D_GIpJIE.js.map +1 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/audit-DM9Hkl5B.js +1534 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +1 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/highlight-DnZ1ULOL.js +48 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +1 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/icons-RyebKi45.js +42 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/icons-RyebKi45.js.map +1 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/package.json +3 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/settings-DaU-gNnK.js +190 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/settings-DaU-gNnK.js.map +1 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/toolbar-63PA619H.js +458 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/toolbar-63PA619H.js.map +1 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/ui-library--bkcNSYz.js +1016 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +1 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/window-jPkpKVcy.js +32 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/window-jPkpKVcy.js.map +1 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/xray-BXCHpEJP.js +111 -0
- package/fixtures/nested-pages/node_modules/.vite/deps/xray-BXCHpEJP.js.map +1 -0
- package/fixtures/nested-pages/site/.norna/generated-images.json +10 -0
- package/fixtures/nested-pages/site/config.yaml +3 -0
- package/fixtures/nested-pages/site/pages/000-home/content.md +15 -0
- package/fixtures/nested-pages/site/pages/010-guides/content.md +15 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/content.md +21 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/images/diagram.svg +21 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/pages/010-macos/content.md +18 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/theme.yaml +2 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/020-workflows/content.md +11 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/030-release-notes/content.md +9 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/040-configuration/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/050-content/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/060-themes/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/070-images/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/080-cards/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/090-notes/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/100-validation/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/110-synchronization/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/120-building/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/130-publishing/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/140-troubleshooting/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/150-migration/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/160-accessibility/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/170-performance/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/180-security/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/190-localization/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/200-upgrading/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/210-faq/content.md +3 -0
- package/fixtures/nested-pages/site/pages/010-guides/theme.yaml +7 -0
- package/fixtures/nested-pages/site/pages/020-reference/content.md +10 -0
- package/fixtures/nested-pages/site/pages/020-reference/pages/010-installation/content.md +11 -0
- package/fixtures/nested-pages/site/theme.yaml +1 -0
- package/package.json +8 -4
- package/schemas/config.schema.json +46 -5
- package/schemas/content-frontmatter.schema.json +28 -63
- package/schemas/manifest.json +4 -2
- package/schemas/page-theme.schema.json +192 -0
- package/schemas/sitewide-content.schema.json +58 -132
- package/schemas/theme.schema.json +434 -152
- package/scripts/check-config.mjs +8 -6
- package/scripts/deploy-site.mjs +6 -8
- package/scripts/doctor.mjs +2 -2
- package/scripts/generate-images.mjs +15 -29
- package/scripts/generate-schemas.mjs +7 -218
- package/scripts/lib/base-path-redirect.mjs +9 -0
- package/scripts/lib/editor-language-service.mjs +125 -79
- package/scripts/lib/example-sites.mjs +15 -3
- package/scripts/lib/heading-ids.mjs +161 -0
- package/scripts/lib/navigation-model.mjs +51 -0
- package/scripts/lib/norna-markdown-blocks.mjs +3 -4
- package/scripts/lib/page-model.mjs +102 -0
- package/scripts/lib/presentation.mjs +25 -17
- package/scripts/lib/project-config.mjs +46 -8
- package/scripts/lib/schema-definitions.mjs +78 -55
- package/scripts/lib/schema-editor-metadata.mjs +519 -0
- package/scripts/lib/schema-value-definitions.mjs +20 -6
- package/scripts/lib/site-content.mjs +159 -97
- package/scripts/lib/site-conventions.mjs +1 -0
- package/scripts/lib/site-paths.mjs +11 -5
- package/scripts/lib/theme-config.mjs +12 -18
- package/scripts/lib/theme-presets.mjs +55 -14
- package/scripts/release.mjs +1 -1
- package/scripts/show-typography.mjs +4 -30
- package/scripts/sync-content-sections.mjs +107 -68
- package/scripts/{test-temporary-visibility.mjs → test-banner-visibility.mjs} +8 -25
- package/scripts/test-client-javascript.mjs +50 -46
- package/scripts/test-content-check.mjs +153 -69
- package/scripts/test-content-model-v2.mjs +566 -285
- package/scripts/test-documentation.mjs +10 -3
- package/scripts/test-editor-language-service.mjs +172 -25
- package/scripts/test-engine-commands.mjs +6 -5
- package/scripts/test-examples.mjs +30 -1
- package/scripts/test-heading-ids.mjs +68 -0
- package/scripts/test-navigation-model.mjs +63 -0
- package/scripts/test-navigation.mjs +11 -2
- package/scripts/test-nested-pages.mjs +125 -0
- package/scripts/test-package-check.mjs +55 -95
- package/scripts/test-page-model.mjs +108 -0
- package/scripts/test-project-config.mjs +22 -3
- package/scripts/test-schemas.mjs +82 -15
- package/scripts/test-theme-presets.mjs +57 -42
- package/src/components/NavigationPageTree.astro +157 -0
- package/src/components/PageContentsLinks.astro +40 -0
- package/src/components/SectionNavigationScript.astro +117 -5
- package/src/components/SiteBreadcrumbs.astro +32 -0
- package/src/components/SiteNavigation.astro +97 -68
- package/src/components/SitePage.astro +93 -55
- package/src/components/SiteSection.astro +29 -27
- package/src/components/SiteTreeNavigation.astro +35 -0
- package/src/components/TreeNavigationScript.astro +83 -0
- package/src/content.config.ts +8 -10
- package/src/layouts/BaseLayout.astro +21 -20
- package/src/lib/pageThemes.ts +44 -0
- package/src/lib/sectionContent.ts +106 -107
- package/src/lib/siteNavigation.ts +49 -0
- package/src/lib/sitePages.ts +96 -38
- package/src/pages/{[slug].astro → [...slug].astro} +2 -2
- package/src/pages/index.astro +2 -1
- package/src/styles/global.css +743 -57
- package/starters/basic/README.md +9 -11
- package/starters/basic/site/{content.md → pages/000-home/content.md} +7 -4
- package/starters/basic/site/sitewide-content.yaml +1 -10
- package/starters/basic/site/theme.yaml +1 -105
- package/starters/project/README.md +14 -14
- package/starters/project/site/{content.md → pages/000-home/content.md} +5 -4
- package/starters/project/site/{routes → pages}/010-guide/content.md +5 -4
- package/starters/project/site/sitewide-content.yaml +1 -10
- package/starters/project/site/theme.yaml +1 -31
- package/docs/routes.md +0 -121
- package/examples/feature-demos/media-and-surfaces/site/routes/020-surfaces/theme.yaml +0 -3
- package/examples/feature-demos/sitewide-content/site/content.md +0 -16
- package/examples/feature-demos/sitewide-content/site/routes/010-identity/content.md +0 -20
- package/examples/feature-demos/theme-presets/README.md +0 -18
- package/examples/feature-demos/theme-presets/site/.norna/generated-images.json +0 -290
- package/examples/feature-demos/theme-presets/site/content.md +0 -17
- package/examples/feature-demos/theme-presets/site/sitewide-content.yaml +0 -12
- package/examples/feature-demos/theme-presets/site/theme.yaml +0 -1
- package/fixtures/content-model-v2/site/routes/010-guide/content.md +0 -17
- package/scripts/lib/route-model.mjs +0 -17
- package/scripts/test-route-model.mjs +0 -32
- package/src/lib/routeThemes.ts +0 -41
- /package/examples/complete-sites/dog-shelter-multi-page/site/{images/intro → pages/000-home/images}/shelter-dog.jpg +0 -0
- /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/010-dogs/images/dogs → pages/010-dogs/images}/rex.jpg +0 -0
- /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/010-dogs/images/dogs → pages/010-dogs/images}/rover.jpg +0 -0
- /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/020-adopt/images/adopt → pages/020-adopt/images}/adoption-dog.jpg +0 -0
- /package/examples/complete-sites/dog-shelter-single-page/site/{images/you-can-help → pages/000-home/images}/foster-dog.jpg +0 -0
- /package/examples/complete-sites/dog-shelter-single-page/site/{images/what-we-do → pages/000-home/images}/rescue-dog.jpg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-carousel.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-stack.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-surfaces.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-one.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-three.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-two.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/stack → pages/010-media/images}/stack-one.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/stack → pages/010-media/images}/stack-two.svg +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-documentation}/site/config.yaml +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/020-documentation/images/documentation → theme-preset-documentation/site/pages/000-home/images}/black-schnauzer.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/020-documentation/images/documentation → theme-preset-documentation/site/pages/000-home/images}/retriever-portrait.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/020-documentation/images/documentation → theme-preset-documentation/site/pages/000-home/images}/schnauzer-portrait.jpg +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-documentation}/site/public/robots.txt +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/020-documentation → theme-preset-documentation/site}/theme.yaml +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/010-portfolio/images/portfolio → theme-preset-portfolio/site/pages/000-home/images}/puppy-portrait.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/010-portfolio/images/portfolio → theme-preset-portfolio/site/pages/000-home/images}/shepherd-portrait.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/010-portfolio/images/portfolio → theme-preset-portfolio/site/pages/000-home/images}/white-puppy.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/010-portfolio → theme-preset-portfolio/site}/theme.yaml +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/collections/routeTheme.schema.json +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/collections/site.schema.json +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/collections/sitewide.schema.json +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/collections/theme.schema.json +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/content-assets.mjs +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/content-modules.mjs +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/content.d.ts +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/data-store.json +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/dev-local.json +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/dev.json +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/dev.log +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/settings.json +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/.astro/types.d.ts +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/_metadata.json +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro-D_GIpJIE.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro-D_GIpJIE.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_n_aria-query.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_n_aria-query.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_n_axobject-query.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_n_axobject-query.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_n_html-escaper.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_n_html-escaper.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/audit-DM9Hkl5B.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/embla-carousel.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/embla-carousel.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/highlight-DnZ1ULOL.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/icons-RyebKi45.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/icons-RyebKi45.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/package.json +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/settings-DaU-gNnK.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/settings-DaU-gNnK.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/toolbar-63PA619H.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/toolbar-63PA619H.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/ui-library--bkcNSYz.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/window-jPkpKVcy.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/window-jPkpKVcy.js.map +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/xray-BXCHpEJP.js +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-project}/node_modules/.vite/deps/xray-BXCHpEJP.js.map +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/030-project/images/project → theme-preset-project/site/pages/000-home/images}/boxer-portrait.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/030-project/images/project → theme-preset-project/site/pages/000-home/images}/grass-puppy.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/030-project/images/project → theme-preset-project/site/pages/000-home/images}/grey-street-dog.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/030-project → theme-preset-project/site}/theme.yaml +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/040-statement/images/statement → theme-preset-statement/site/pages/000-home/images}/black-pedigree.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/040-statement/images/statement → theme-preset-statement/site/pages/000-home/images}/sheepdog-grass.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/040-statement/images/statement → theme-preset-statement/site/pages/000-home/images}/sheepdog-wide.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/routes/040-statement → theme-preset-statement/site}/theme.yaml +0 -0
- /package/fixtures/basic/site/{images/work → pages/000-home/images}/.gitkeep +0 -0
- /package/fixtures/content-model-v2/site/{images/card-section → pages/000-home/images}/adopt.svg +0 -0
- /package/fixtures/content-model-v2/site/{images/intro → pages/000-home/images}/detail.jpg +0 -0
- /package/fixtures/content-model-v2/site/{images/intro → pages/000-home/images}/duplicate.jpg +0 -0
- /package/fixtures/content-model-v2/site/{images/card-section → pages/000-home/images}/foster.svg +0 -0
- /package/fixtures/content-model-v2/site/{images/intro → pages/000-home/images}/hero.jpg +0 -0
- /package/fixtures/content-model-v2/site/{images/plain → pages/000-home/images}/image.jpg +0 -0
- /package/fixtures/content-model-v2/site/{images/timed → pages/000-home/images}/slide-one.jpg +0 -0
- /package/fixtures/content-model-v2/site/{images/timed → pages/000-home/images}/slide-three.jpg +0 -0
- /package/fixtures/content-model-v2/site/{images/timed → pages/000-home/images}/slide-two.jpg +0 -0
- /package/fixtures/content-model-v2/site/{routes/010-guide/images/intro → pages/010-guide/images}/duplicate.jpg +0 -0
- /package/starters/basic/site/{images/work → pages/000-home/images}/.gitkeep +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
3
|
+
import { access, cp, mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
|
|
7
|
+
const execFileAsync = promisify(execFile);
|
|
8
|
+
const repoRoot = path.resolve(import.meta.dirname, '..');
|
|
9
|
+
const fixtureRoot = path.join(repoRoot, 'fixtures', 'nested-pages');
|
|
10
|
+
const tempParent = path.join(repoRoot, 'node_modules', '.cache');
|
|
11
|
+
await mkdir(tempParent, { recursive: true });
|
|
12
|
+
const tempRoot = await mkdtemp(path.join(tempParent, 'norna-nested-pages-'));
|
|
13
|
+
const fixtureCopyRoot = path.join(tempRoot, 'nested-pages');
|
|
14
|
+
const nornaBin = path.join(repoRoot, 'bin', 'norna.mjs');
|
|
15
|
+
const runNorna = (siteDir, ...args) => execFileAsync(process.execPath, [
|
|
16
|
+
nornaBin,
|
|
17
|
+
'--site-dir',
|
|
18
|
+
siteDir,
|
|
19
|
+
...args,
|
|
20
|
+
], {
|
|
21
|
+
cwd: repoRoot,
|
|
22
|
+
maxBuffer: 1024 * 1024 * 10,
|
|
23
|
+
});
|
|
24
|
+
const runGit = (args) => execFileAsync('git', args, {
|
|
25
|
+
cwd: fixtureCopyRoot,
|
|
26
|
+
env: {
|
|
27
|
+
...process.env,
|
|
28
|
+
GIT_AUTHOR_NAME: 'Norna Test',
|
|
29
|
+
GIT_AUTHOR_EMAIL: 'norna@example.test',
|
|
30
|
+
GIT_COMMITTER_NAME: 'Norna Test',
|
|
31
|
+
GIT_COMMITTER_EMAIL: 'norna@example.test',
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
const fileExists = (filePath) => access(filePath).then(() => true, () => false);
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
await cp(fixtureRoot, fixtureCopyRoot, { recursive: true });
|
|
38
|
+
const siteDir = path.join(fixtureCopyRoot, 'site');
|
|
39
|
+
await runNorna(siteDir, 'content:check');
|
|
40
|
+
await runNorna(siteDir, 'build');
|
|
41
|
+
|
|
42
|
+
const distDir = path.join(fixtureCopyRoot, 'dist');
|
|
43
|
+
const expectedPages = [
|
|
44
|
+
'index.html',
|
|
45
|
+
'guides/index.html',
|
|
46
|
+
'guides/installation/index.html',
|
|
47
|
+
'guides/installation/macos/index.html',
|
|
48
|
+
'guides/workflows/index.html',
|
|
49
|
+
'guides/release-notes/index.html',
|
|
50
|
+
'reference/index.html',
|
|
51
|
+
'reference/installation/index.html',
|
|
52
|
+
];
|
|
53
|
+
for (const pagePath of expectedPages) {
|
|
54
|
+
assert.match(await readFile(path.join(distDir, pagePath), 'utf8'), /<main\b[^>]*id="main-content"/);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const rootHtml = await readFile(path.join(distDir, 'index.html'), 'utf8');
|
|
58
|
+
const guidesHtml = await readFile(path.join(distDir, 'guides', 'index.html'), 'utf8');
|
|
59
|
+
const installationHtml = await readFile(path.join(distDir, 'guides', 'installation', 'index.html'), 'utf8');
|
|
60
|
+
const macosHtml = await readFile(path.join(distDir, 'guides', 'installation', 'macos', 'index.html'), 'utf8');
|
|
61
|
+
for (const html of [rootHtml, guidesHtml, installationHtml, macosHtml]) {
|
|
62
|
+
assert.match(html, /--color-page: #f8f5ee/);
|
|
63
|
+
assert.match(html, /--font-sans: Georgia, 'Times New Roman', serif/);
|
|
64
|
+
}
|
|
65
|
+
assert.match(rootHtml, /--image-width: 920px/);
|
|
66
|
+
assert.match(rootHtml, /--space-section-to-section-desktop: clamp\(1\.2rem, 2\.4vw, 2\.25rem\)/);
|
|
67
|
+
assert.match(guidesHtml, /--image-width: 760px/);
|
|
68
|
+
assert.match(guidesHtml, /--space-section-to-section-desktop: clamp\(2\.25rem, 5vw, 4\.5rem\)/);
|
|
69
|
+
assert.match(guidesHtml, /--section-body-width-desktop: min\(72ch,/);
|
|
70
|
+
assert.match(installationHtml, /--image-width: 760px/);
|
|
71
|
+
assert.match(installationHtml, /--space-section-to-section-desktop: clamp\(2\.25rem, 5vw, 4\.5rem\)/);
|
|
72
|
+
assert.match(installationHtml, /--section-body-width-desktop: min\(60ch,/);
|
|
73
|
+
assert.match(macosHtml, /--section-body-width-desktop: min\(60ch,/);
|
|
74
|
+
assert.match(installationHtml, /Three nested page levels connected in sequence/);
|
|
75
|
+
assert.match(installationHtml, /\/original\/pages\/010-guides\/pages\/010-installation\/images\/diagram-[a-f0-9]+\.svg/);
|
|
76
|
+
assert.match(macosHtml, /data-navigation-mode="tree"/);
|
|
77
|
+
assert.match(macosHtml, /class="site-nav-item site-nav-item-current-branch"/);
|
|
78
|
+
assert.doesNotMatch(macosHtml, /class="site-nav-submenu"/);
|
|
79
|
+
assert.match(macosHtml, /href="\/guides\/installation\/macos\/" aria-current="page"/);
|
|
80
|
+
assert.match(macosHtml, /<aside class="tree-local-navigation" data-navigation-root="\/guides\/">/);
|
|
81
|
+
assert.match(macosHtml, /<ul class="navigation-page-tree navigation-page-tree-sidebar">/);
|
|
82
|
+
assert.match(macosHtml, /<details class="navigation-page-branch navigation-page-disclosure navigation-page-disclosure-sidebar" data-page-path="guides" data-current-branch="true"/);
|
|
83
|
+
assert.match(macosHtml, /<summary class="navigation-page-summary"[^>]*><span class="navigation-page-summary-title">Guides<\/span>/);
|
|
84
|
+
assert.match(macosHtml, /<nav class="site-breadcrumbs" aria-label="Breadcrumb"><ol><li><a href="\/guides\/">Guides<\/a><\/li><li><a href="\/guides\/installation\/">Installation<\/a><\/li><li><span aria-current="page">macOS<\/span>/);
|
|
85
|
+
assert.match(macosHtml, /<nav class="navigation-page-sections" aria-label="Page contents: macOS">/);
|
|
86
|
+
assert.doesNotMatch(macosHtml, /class="tree-page-contents"/);
|
|
87
|
+
assert.match(macosHtml, /href="#install">Install<\/a><ol><li><a href="#prerequisites">Prerequisites<\/a>/);
|
|
88
|
+
assert.doesNotMatch(macosHtml, /<nav class="page-nav"/);
|
|
89
|
+
assert.ok(
|
|
90
|
+
macosHtml.indexOf('href="/guides/installation/"') < macosHtml.indexOf('href="/guides/workflows/"'),
|
|
91
|
+
'Nested sibling navigation should follow page directory order.',
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
await runGit(['init']);
|
|
95
|
+
await runGit(['add', '.']);
|
|
96
|
+
await runGit(['commit', '-m', 'Initial nested fixture']);
|
|
97
|
+
const installationContentPath = path.join(
|
|
98
|
+
siteDir,
|
|
99
|
+
'pages',
|
|
100
|
+
'010-guides',
|
|
101
|
+
'pages',
|
|
102
|
+
'010-installation',
|
|
103
|
+
'content.md',
|
|
104
|
+
);
|
|
105
|
+
const workflowsContentPath = path.join(siteDir, 'pages', '010-guides', 'pages', '020-workflows', 'content.md');
|
|
106
|
+
const imageBlockPattern = /\n```norna-image-stack\n[\s\S]*?\n```\n/;
|
|
107
|
+
const installationContent = await readFile(installationContentPath, 'utf8');
|
|
108
|
+
const imageBlock = installationContent.match(imageBlockPattern)?.[0];
|
|
109
|
+
assert.ok(imageBlock, 'The nested fixture needs a managed image block to exercise content:sync.');
|
|
110
|
+
await writeFile(installationContentPath, installationContent.replace(imageBlockPattern, '\n'));
|
|
111
|
+
await writeFile(workflowsContentPath, `${await readFile(workflowsContentPath, 'utf8')}${imageBlock}`);
|
|
112
|
+
await runGit(['add', '.']);
|
|
113
|
+
await runGit(['commit', '-m', 'Move nested image reference']);
|
|
114
|
+
await runNorna(siteDir, 'content:sync', '--yes');
|
|
115
|
+
|
|
116
|
+
const previousImagePath = path.join(siteDir, 'pages', '010-guides', 'pages', '010-installation', 'images', 'diagram.svg');
|
|
117
|
+
const nextImagePath = path.join(siteDir, 'pages', '010-guides', 'pages', '020-workflows', 'images', 'diagram.svg');
|
|
118
|
+
assert.equal(await fileExists(previousImagePath), false);
|
|
119
|
+
assert.equal(await fileExists(nextImagePath), true);
|
|
120
|
+
await runNorna(siteDir, 'content:check');
|
|
121
|
+
|
|
122
|
+
console.log('Nested pages fixture check passed.');
|
|
123
|
+
} finally {
|
|
124
|
+
await rm(tempRoot, { recursive: true, force: true });
|
|
125
|
+
}
|
|
@@ -167,8 +167,8 @@ try {
|
|
|
167
167
|
assertFileExists(path.join(packagedStarterRoot, 'site', 'config.yaml')),
|
|
168
168
|
assertFileExists(path.join(packagedStarterRoot, 'site', 'theme.yaml')),
|
|
169
169
|
assertFileExists(path.join(packagedStarterRoot, 'site', 'sitewide-content.yaml')),
|
|
170
|
-
assertFileExists(path.join(packagedStarterRoot, 'site', 'content.md')),
|
|
171
|
-
assertFileExists(path.join(packagedStarterRoot, 'site', '
|
|
170
|
+
assertFileExists(path.join(packagedStarterRoot, 'site', 'pages', '000-home', 'content.md')),
|
|
171
|
+
assertFileExists(path.join(packagedStarterRoot, 'site', 'pages', '000-home', 'images', '.gitkeep')),
|
|
172
172
|
assertFileExists(path.join(packagedStarterRoot, 'site', 'public', 'robots.txt')),
|
|
173
173
|
]);
|
|
174
174
|
await assertFileIncludes(
|
|
@@ -198,21 +198,19 @@ try {
|
|
|
198
198
|
const packageCheckSitewide = await readFile(packageCheckSitewidePath, 'utf8');
|
|
199
199
|
await writeFile(
|
|
200
200
|
packageCheckSitewidePath,
|
|
201
|
-
|
|
201
|
+
`logo:\n height: 2.6rem\n${packageCheckSitewide}`,
|
|
202
202
|
);
|
|
203
203
|
await writeFile(
|
|
204
204
|
path.join(siteProjectRoot, 'site', 'public', 'logo.svg'),
|
|
205
205
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" fill="black"/></svg>\n',
|
|
206
206
|
);
|
|
207
|
-
await writeFile(path.join(siteProjectRoot, 'site', 'content.md'), `---
|
|
208
|
-
|
|
209
|
-
description: Site used by package checks.
|
|
210
|
-
sections:
|
|
211
|
-
intro: {}
|
|
212
|
-
warning: {}
|
|
213
|
-
work: {}
|
|
207
|
+
await writeFile(path.join(siteProjectRoot, 'site', 'pages', '000-home', 'content.md'), `---
|
|
208
|
+
page:
|
|
209
|
+
description: Site used by package checks.
|
|
214
210
|
---
|
|
215
211
|
|
|
212
|
+
# Package Check Site
|
|
213
|
+
|
|
216
214
|
## Intro {#intro}
|
|
217
215
|
|
|
218
216
|
This page verifies that **packaged norna sites** can build with the current content model.
|
|
@@ -230,19 +228,17 @@ This section verifies styled section headings.
|
|
|
230
228
|
|
|
231
229
|
This section keeps the package check independent from user-facing starter copy.
|
|
232
230
|
`);
|
|
233
|
-
await mkdir(path.join(siteProjectRoot, 'site', '
|
|
234
|
-
await writeFile(path.join(siteProjectRoot, 'site', '
|
|
235
|
-
|
|
236
|
-
description:
|
|
237
|
-
navigation:
|
|
238
|
-
label: About
|
|
239
|
-
sections:
|
|
240
|
-
about: {}
|
|
231
|
+
await mkdir(path.join(siteProjectRoot, 'site', 'pages', '010-about'), { recursive: true });
|
|
232
|
+
await writeFile(path.join(siteProjectRoot, 'site', 'pages', '010-about', 'content.md'), `---
|
|
233
|
+
page:
|
|
234
|
+
description: Page used by package checks.
|
|
241
235
|
---
|
|
242
236
|
|
|
237
|
+
# About the site
|
|
238
|
+
|
|
243
239
|
## About {#about}
|
|
244
240
|
|
|
245
|
-
This
|
|
241
|
+
This page verifies that packaged norna sites can build additional pages.
|
|
246
242
|
`);
|
|
247
243
|
|
|
248
244
|
await runInherit(npmBin, ['install', '--no-audit', '--no-fund', '--prefer-offline', '--fetch-retries=0'], { cwd: siteProjectRoot, env: npmEnv });
|
|
@@ -252,12 +248,14 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
252
248
|
assertFileExists(path.join(initializedSiteRoot, 'package.json')),
|
|
253
249
|
assertFileExists(path.join(initializedSiteRoot, 'site', 'config.yaml')),
|
|
254
250
|
assertFileExists(path.join(initializedSiteRoot, 'site', 'theme.yaml')),
|
|
251
|
+
assertFileExists(path.join(initializedSiteRoot, 'site', 'pages', '000-home', 'content.md')),
|
|
255
252
|
assertFileMissing(path.join(initializedSiteRoot, '.DS_Store')),
|
|
256
253
|
assertFileMissing(path.join(initializedSiteRoot, 'site', '.DS_Store')),
|
|
257
254
|
]);
|
|
258
|
-
|
|
259
|
-
await runInherit(npxBin, ['norna', '
|
|
260
|
-
await runInherit(npxBin, ['norna', '
|
|
255
|
+
const homeImagesDir = path.join(siteProjectRoot, 'site', 'pages', '000-home', 'images');
|
|
256
|
+
await runInherit(npxBin, ['norna', 'engine:version'], { cwd: homeImagesDir, env: npmEnv });
|
|
257
|
+
await runInherit(npxBin, ['norna', 'doctor'], { cwd: homeImagesDir, env: npmEnv });
|
|
258
|
+
await runInherit(npxBin, ['norna', 'config:check'], { cwd: homeImagesDir, env: npmEnv });
|
|
261
259
|
await runInherit(npxBin, ['norna', 'content:check'], { cwd: siteProjectRoot, env: npmEnv });
|
|
262
260
|
await runInherit(npxBin, ['norna', 'check'], { cwd: siteProjectRoot, env: npmEnv });
|
|
263
261
|
await runInherit(npxBin, ['norna', 'build'], { cwd: siteProjectRoot, env: npmEnv });
|
|
@@ -279,19 +277,19 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
279
277
|
);
|
|
280
278
|
await assertFileIncludes(
|
|
281
279
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
282
|
-
'--section-heading-font-weight:
|
|
280
|
+
'--section-heading-font-weight: 500',
|
|
283
281
|
);
|
|
284
282
|
await assertFileIncludes(
|
|
285
283
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
286
|
-
'--section-heading-spacing-after: 0.
|
|
284
|
+
'--section-heading-spacing-after: 0.45em',
|
|
287
285
|
);
|
|
288
286
|
await assertFileIncludes(
|
|
289
287
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
290
|
-
'--section-markdown-h3-spacing-before: 1.
|
|
288
|
+
'--section-markdown-h3-spacing-before: 1.2em',
|
|
291
289
|
);
|
|
292
290
|
await assertFileIncludes(
|
|
293
291
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
294
|
-
"--font-sans:
|
|
292
|
+
"--font-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
295
293
|
);
|
|
296
294
|
await assertFileIncludes(
|
|
297
295
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
@@ -315,15 +313,23 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
315
313
|
);
|
|
316
314
|
await assertFileIncludes(
|
|
317
315
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
318
|
-
'<a class="site-brand" href="/site/"><img class="site-brand-logo" src="/site/logo.svg" alt="Package Check
|
|
316
|
+
'<a class="site-brand" href="/site/"><img class="site-brand-logo" src="/site/logo.svg" alt="Package Check Site">',
|
|
319
317
|
);
|
|
320
|
-
await
|
|
318
|
+
await assertFileExcludes(
|
|
321
319
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
322
320
|
'<div class="site-nav-submenu">',
|
|
323
321
|
);
|
|
324
322
|
await assertFileIncludes(
|
|
325
323
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
326
|
-
'href="/site
|
|
324
|
+
'href="/site/about/">About the site</a>',
|
|
325
|
+
);
|
|
326
|
+
await assertFileIncludes(
|
|
327
|
+
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
328
|
+
'<nav class="page-nav" aria-label="Page contents">',
|
|
329
|
+
);
|
|
330
|
+
await assertFileIncludes(
|
|
331
|
+
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
332
|
+
'href="#intro">Intro</a>',
|
|
327
333
|
);
|
|
328
334
|
await assertFileIncludes(
|
|
329
335
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
@@ -331,7 +337,7 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
331
337
|
);
|
|
332
338
|
await assertFileIncludes(
|
|
333
339
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
334
|
-
'--section-body-line-height: 1.
|
|
340
|
+
'--section-body-line-height: 1.62',
|
|
335
341
|
);
|
|
336
342
|
await assertFileIncludes(
|
|
337
343
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
@@ -343,15 +349,15 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
343
349
|
);
|
|
344
350
|
await assertFileIncludes(
|
|
345
351
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
346
|
-
'--section-body-paragraph-spacing: 0.
|
|
352
|
+
'--section-body-paragraph-spacing: 0.65em',
|
|
347
353
|
);
|
|
348
354
|
await assertFileIncludes(
|
|
349
355
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
350
|
-
'--section-caption-line-height: 1.
|
|
356
|
+
'--section-caption-line-height: 1.4',
|
|
351
357
|
);
|
|
352
358
|
await assertFileIncludes(
|
|
353
359
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
354
|
-
'--section-caption-spacing-before: 0.
|
|
360
|
+
'--section-caption-spacing-before: 0.35em',
|
|
355
361
|
);
|
|
356
362
|
await assertFileIncludes(
|
|
357
363
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
@@ -367,39 +373,35 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
367
373
|
);
|
|
368
374
|
await assertFileIncludes(
|
|
369
375
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
370
|
-
'href="
|
|
371
|
-
);
|
|
372
|
-
await assertFileIncludes(
|
|
373
|
-
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
374
|
-
'--section-background-color: #000000',
|
|
376
|
+
'href="#warning">Warning</a>',
|
|
375
377
|
);
|
|
376
378
|
await assertFileIncludes(
|
|
377
379
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
378
|
-
'--section-background-color: #
|
|
380
|
+
'--section-background-color: #ffffff',
|
|
379
381
|
);
|
|
380
382
|
await assertFileIncludes(
|
|
381
383
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
382
|
-
'--section-background-color: #
|
|
384
|
+
'--section-background-color: #f1f4f2',
|
|
383
385
|
);
|
|
384
386
|
await assertFileIncludes(
|
|
385
387
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
386
|
-
'--site-top-background-color: #
|
|
388
|
+
'--site-top-background-color: #ffffff',
|
|
387
389
|
);
|
|
388
390
|
await assertFileIncludes(
|
|
389
391
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
390
|
-
'--site-top-text-color: #
|
|
392
|
+
'--site-top-text-color: #17201d',
|
|
391
393
|
);
|
|
392
394
|
await assertFileIncludes(
|
|
393
395
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
394
|
-
'--site-footer-background-color: #
|
|
396
|
+
'--site-footer-background-color: #ffffff',
|
|
395
397
|
);
|
|
396
398
|
await assertFileIncludes(
|
|
397
399
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
398
|
-
'--site-footer-text-color: #
|
|
400
|
+
'--site-footer-text-color: #17201d',
|
|
399
401
|
);
|
|
400
402
|
await assertFileIncludes(
|
|
401
403
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
402
|
-
'--section-text-color: #
|
|
404
|
+
'--section-text-color: #17201d',
|
|
403
405
|
);
|
|
404
406
|
await writeFile(path.join(siteProjectRoot, 'site', 'public', 'favicon.ico'), 'fake icon');
|
|
405
407
|
await runInherit(npxBin, ['norna', 'build'], { cwd: siteProjectRoot, env: npmEnv });
|
|
@@ -412,47 +414,24 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
412
414
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
413
415
|
'href="/favicon.svg"',
|
|
414
416
|
);
|
|
415
|
-
const siteContentPath = path.join(siteProjectRoot, 'site', 'content.md');
|
|
417
|
+
const siteContentPath = path.join(siteProjectRoot, 'site', 'pages', '000-home', 'content.md');
|
|
416
418
|
const siteContent = await readFile(siteContentPath, 'utf8');
|
|
417
419
|
const siteThemePath = path.join(siteProjectRoot, 'site', 'theme.yaml');
|
|
418
420
|
const siteTheme = await readFile(siteThemePath, 'utf8');
|
|
419
|
-
await writeFile(siteThemePath, siteTheme.
|
|
421
|
+
await writeFile(siteThemePath, `${siteTheme.trim()}\ntypography:\n profile: noisy\n`);
|
|
420
422
|
await runExpectFailure(
|
|
421
423
|
npxBin,
|
|
422
424
|
['norna', 'build'],
|
|
423
425
|
{ cwd: siteProjectRoot, env: npmEnv },
|
|
424
|
-
'
|
|
425
|
-
);
|
|
426
|
-
await writeFile(
|
|
427
|
-
siteThemePath,
|
|
428
|
-
siteTheme.replace('\npalette: dark', '\npalette: neon'),
|
|
426
|
+
'typography.profile',
|
|
429
427
|
);
|
|
428
|
+
await writeFile(siteThemePath, `${siteTheme.trim()}\npalette: neon\n`);
|
|
430
429
|
await runExpectFailure(
|
|
431
430
|
npxBin,
|
|
432
431
|
['norna', 'build'],
|
|
433
432
|
{ cwd: siteProjectRoot, env: npmEnv },
|
|
434
433
|
'palette',
|
|
435
434
|
);
|
|
436
|
-
await writeFile(
|
|
437
|
-
siteThemePath,
|
|
438
|
-
siteTheme.replace('\nsectionSurfaces: [base, soft, emphasis]', '\nsectionSurfaces: [base, glowing]'),
|
|
439
|
-
);
|
|
440
|
-
await runExpectFailure(
|
|
441
|
-
npxBin,
|
|
442
|
-
['norna', 'build'],
|
|
443
|
-
{ cwd: siteProjectRoot, env: npmEnv },
|
|
444
|
-
'Unknown section surface "glowing"',
|
|
445
|
-
);
|
|
446
|
-
await writeFile(
|
|
447
|
-
siteThemePath,
|
|
448
|
-
siteTheme.replace('\nsectionSurfaces: [base, soft, emphasis]', '\nsectionSurfaces: [base, base]'),
|
|
449
|
-
);
|
|
450
|
-
await runExpectFailure(
|
|
451
|
-
npxBin,
|
|
452
|
-
['norna', 'build'],
|
|
453
|
-
{ cwd: siteProjectRoot, env: npmEnv },
|
|
454
|
-
'Each section surface may appear only once',
|
|
455
|
-
);
|
|
456
435
|
await writeFile(siteThemePath, siteTheme);
|
|
457
436
|
await writeFile(
|
|
458
437
|
siteContentPath,
|
|
@@ -484,36 +463,17 @@ This route verifies that packaged norna sites can build route pages.
|
|
|
484
463
|
await writeFile(
|
|
485
464
|
siteContentPath,
|
|
486
465
|
siteContent.replace(
|
|
487
|
-
'
|
|
488
|
-
' intro
|
|
489
|
-
),
|
|
490
|
-
);
|
|
491
|
-
await runExpectFailure(
|
|
492
|
-
npxBin,
|
|
493
|
-
['norna', 'build'],
|
|
494
|
-
{ cwd: siteProjectRoot, env: npmEnv },
|
|
495
|
-
'sections.intro: Unrecognized key: "typography"',
|
|
496
|
-
);
|
|
497
|
-
await writeFile(
|
|
498
|
-
siteContentPath,
|
|
499
|
-
siteContent.replace(
|
|
500
|
-
' intro: {}',
|
|
501
|
-
' intro:\n palette: dark',
|
|
466
|
+
'description: Site used by package checks.',
|
|
467
|
+
'description: Site used by package checks.\nsections:\n intro: {}',
|
|
502
468
|
),
|
|
503
469
|
);
|
|
504
470
|
await runExpectFailure(
|
|
505
471
|
npxBin,
|
|
506
472
|
['norna', 'build'],
|
|
507
473
|
{ cwd: siteProjectRoot, env: npmEnv },
|
|
508
|
-
'sections
|
|
509
|
-
);
|
|
510
|
-
await writeFile(
|
|
511
|
-
siteThemePath,
|
|
512
|
-
siteTheme.replace(
|
|
513
|
-
'fontFamily: "Arial, \'Helvetica Neue\', Helvetica, sans-serif"',
|
|
514
|
-
'fontFamily: "Arial; color: red"',
|
|
515
|
-
),
|
|
474
|
+
'defines "sections" at the top level, but it is not a valid top-level content field',
|
|
516
475
|
);
|
|
476
|
+
await writeFile(siteThemePath, `${siteTheme.trim()}\ntypography:\n fontFamily: "Arial; color: red"\n`);
|
|
517
477
|
await runExpectFailure(
|
|
518
478
|
npxBin,
|
|
519
479
|
['norna', 'config:check'],
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import {
|
|
3
|
+
decodePageDirectoryPath,
|
|
4
|
+
encodePageDirectoryPath,
|
|
5
|
+
getPageDirectoryAncestors,
|
|
6
|
+
parsePageDirectory,
|
|
7
|
+
parsePageDirectoryPath,
|
|
8
|
+
} from './lib/page-model.mjs';
|
|
9
|
+
|
|
10
|
+
assert.deepEqual(parsePageDirectory('010-getting-started'), {
|
|
11
|
+
pageDirectory: '010-getting-started',
|
|
12
|
+
pageOrder: 10,
|
|
13
|
+
pageId: 'getting-started',
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
assert.deepEqual(parsePageDirectory('120-api-reference'), {
|
|
17
|
+
pageDirectory: '120-api-reference',
|
|
18
|
+
pageOrder: 120,
|
|
19
|
+
pageId: 'api-reference',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
assert.deepEqual(parsePageDirectory('000-home'), {
|
|
23
|
+
pageDirectory: '000-home',
|
|
24
|
+
pageOrder: 0,
|
|
25
|
+
pageId: 'home',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
assert.deepEqual(parsePageDirectoryPath('000-home'), {
|
|
29
|
+
pageDirectory: '000-home',
|
|
30
|
+
pageDirectories: ['000-home'],
|
|
31
|
+
pageId: 'home',
|
|
32
|
+
pageIds: [],
|
|
33
|
+
pageOrder: 0,
|
|
34
|
+
pageOrders: [],
|
|
35
|
+
pagePath: '',
|
|
36
|
+
parentPagePath: null,
|
|
37
|
+
depth: 1,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
assert.throws(
|
|
41
|
+
() => parsePageDirectoryPath('000-home/pages/010-about'),
|
|
42
|
+
/000-home is the homepage and cannot contain child pages.*beside it under site\/pages\/.*below another non-home page/,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
assert.deepEqual(parsePageDirectoryPath('010-guides/pages/020-installation'), {
|
|
46
|
+
pageDirectory: '010-guides/pages/020-installation',
|
|
47
|
+
pageDirectories: ['010-guides', '020-installation'],
|
|
48
|
+
pageId: 'installation',
|
|
49
|
+
pageIds: ['guides', 'installation'],
|
|
50
|
+
pageOrder: 20,
|
|
51
|
+
pageOrders: [10, 20],
|
|
52
|
+
pagePath: 'guides/installation',
|
|
53
|
+
parentPagePath: 'guides',
|
|
54
|
+
depth: 2,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
assert.equal(
|
|
58
|
+
encodePageDirectoryPath('010-guides/pages/020-installation'),
|
|
59
|
+
'010-guides--020-installation',
|
|
60
|
+
);
|
|
61
|
+
assert.equal(
|
|
62
|
+
decodePageDirectoryPath('010-guides--020-installation'),
|
|
63
|
+
'010-guides/pages/020-installation',
|
|
64
|
+
);
|
|
65
|
+
assert.deepEqual(
|
|
66
|
+
getPageDirectoryAncestors('010-guides/pages/020-installation/pages/030-macos'),
|
|
67
|
+
[
|
|
68
|
+
'010-guides',
|
|
69
|
+
'010-guides/pages/020-installation',
|
|
70
|
+
'010-guides/pages/020-installation/pages/030-macos',
|
|
71
|
+
],
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
for (const pageDirectoryPath of [
|
|
75
|
+
'010-guides/020-installation',
|
|
76
|
+
'010-guides/children/020-installation',
|
|
77
|
+
'pages/010-guides',
|
|
78
|
+
'010-guides/pages',
|
|
79
|
+
]) {
|
|
80
|
+
assert.throws(
|
|
81
|
+
() => parsePageDirectoryPath(pageDirectoryPath),
|
|
82
|
+
/(Nested pages must use|Use a pages directory)/,
|
|
83
|
+
`${pageDirectoryPath} should be rejected`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for (const pageDirectory of [
|
|
88
|
+
'000-about',
|
|
89
|
+
'10-about',
|
|
90
|
+
'010_About',
|
|
91
|
+
'010-About',
|
|
92
|
+
'010-about-',
|
|
93
|
+
'010-about--team',
|
|
94
|
+
'010-om-oss!',
|
|
95
|
+
]) {
|
|
96
|
+
assert.throws(
|
|
97
|
+
() => parsePageDirectory(pageDirectory),
|
|
98
|
+
/(Page directories must use the form NNN-page-id|000 prefix is reserved)/,
|
|
99
|
+
`${pageDirectory} should be rejected`,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
assert.throws(
|
|
104
|
+
() => parsePageDirectoryPath('010-guides/pages/000-home'),
|
|
105
|
+
/000-home is allowed only as a top-level page/,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
console.log('Page model test passed.');
|
|
@@ -4,6 +4,7 @@ import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { pathToFileURL } from 'node:url';
|
|
7
|
+
import { getBasePathRedirectLocation } from './lib/base-path-redirect.mjs';
|
|
7
8
|
|
|
8
9
|
const repoRoot = path.resolve(import.meta.dirname, '..');
|
|
9
10
|
const projectConfigUrl = pathToFileURL(path.join(repoRoot, 'scripts', 'lib', 'project-config.mjs')).href;
|
|
@@ -14,6 +15,7 @@ const importScript = `
|
|
|
14
15
|
basePath: projectConfig.site.basePath,
|
|
15
16
|
language: projectConfig.locale.lang,
|
|
16
17
|
labels: projectConfig.locale.labels,
|
|
18
|
+
navigationMode: projectConfig.navigation.mode,
|
|
17
19
|
scrollBehavior: projectConfig.navigation.scrollBehavior,
|
|
18
20
|
url: projectConfig.site.url,
|
|
19
21
|
}));
|
|
@@ -22,9 +24,9 @@ const importScript = `
|
|
|
22
24
|
const createSite = async (name, config) => {
|
|
23
25
|
const projectRoot = path.join(tempRoot, name);
|
|
24
26
|
const siteDir = path.join(projectRoot, 'site');
|
|
25
|
-
await mkdir(siteDir, { recursive: true });
|
|
27
|
+
await mkdir(path.join(siteDir, 'pages', '000-home'), { recursive: true });
|
|
26
28
|
await writeFile(path.join(siteDir, 'config.yaml'), config);
|
|
27
|
-
await writeFile(path.join(siteDir, 'content.md'), '
|
|
29
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), '# Config test\n\n## Intro {#intro}\n\nText.\n');
|
|
28
30
|
await writeFile(path.join(siteDir, 'theme.yaml'), 'preset: documentation\n');
|
|
29
31
|
return { projectRoot, siteDir };
|
|
30
32
|
};
|
|
@@ -50,6 +52,12 @@ const assertFailure = (result, expectedPattern) => {
|
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
try {
|
|
55
|
+
assert.equal(getBasePathRedirectLocation('/norna/', '/norna'), '/norna/');
|
|
56
|
+
assert.equal(getBasePathRedirectLocation('/norna/', '/norna?source=test'), '/norna/?source=test');
|
|
57
|
+
assert.equal(getBasePathRedirectLocation('/norna/', '/norna/'), undefined);
|
|
58
|
+
assert.equal(getBasePathRedirectLocation('/norna/', '/norna/concepts/'), undefined);
|
|
59
|
+
assert.equal(getBasePathRedirectLocation('/', '/'), undefined);
|
|
60
|
+
|
|
53
61
|
const minimalSite = await createSite('minimal', 'url: https://example.com/docs\n');
|
|
54
62
|
const minimalResult = loadConfig(minimalSite);
|
|
55
63
|
assert.equal(minimalResult.status, 0, minimalResult.stderr);
|
|
@@ -57,14 +65,19 @@ try {
|
|
|
57
65
|
basePath: '/docs/',
|
|
58
66
|
language: 'en',
|
|
59
67
|
labels: {
|
|
68
|
+
breadcrumb: 'Breadcrumb',
|
|
60
69
|
dismissBanner: 'Dismiss notice',
|
|
70
|
+
built: 'Built',
|
|
61
71
|
images: 'Images',
|
|
72
|
+
navigationChildren: 'Child pages',
|
|
73
|
+
navigationMenu: 'Menu',
|
|
62
74
|
note: 'Note',
|
|
63
|
-
pageNavigation: '
|
|
75
|
+
pageNavigation: 'Page contents',
|
|
64
76
|
siteBanners: 'Site notices',
|
|
65
77
|
siteNavigation: 'Pages',
|
|
66
78
|
skipToContent: 'Skip to content',
|
|
67
79
|
},
|
|
80
|
+
navigationMode: 'automatic',
|
|
68
81
|
scrollBehavior: 'instant',
|
|
69
82
|
url: 'https://example.com/docs/',
|
|
70
83
|
});
|
|
@@ -74,9 +87,15 @@ try {
|
|
|
74
87
|
assert.equal(localizedResult.status, 0, localizedResult.stderr);
|
|
75
88
|
const localizedConfig = JSON.parse(localizedResult.stdout);
|
|
76
89
|
assert.equal(localizedConfig.language, 'sv-SE');
|
|
90
|
+
assert.equal(localizedConfig.labels.built, 'Byggd');
|
|
77
91
|
assert.equal(localizedConfig.labels.skipToContent, 'Hoppa till innehållet');
|
|
78
92
|
assert.equal(localizedConfig.scrollBehavior, 'smooth');
|
|
79
93
|
|
|
94
|
+
const treeNavigationSite = await createSite('tree-navigation', 'url: https://example.com/\nnavigation:\n mode: tree\n');
|
|
95
|
+
const treeNavigationResult = loadConfig(treeNavigationSite);
|
|
96
|
+
assert.equal(treeNavigationResult.status, 0, treeNavigationResult.stderr);
|
|
97
|
+
assert.equal(JSON.parse(treeNavigationResult.stdout).navigationMode, 'tree');
|
|
98
|
+
|
|
80
99
|
const overrideResult = loadConfig(minimalSite, {
|
|
81
100
|
NORNA_SITE_URL: 'http://127.0.0.1:4567/preview',
|
|
82
101
|
});
|