@janga/norna 0.7.17 → 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 +15 -6
- package/bin/norna-cli.mjs +1 -1
- package/docs/README.md +11 -9
- package/docs/configuration.md +25 -2
- package/docs/content.md +21 -12
- package/docs/design/navigation-and-theme-plan.md +90 -19
- package/docs/design/site-examples-structure.md +7 -3
- package/docs/engine-development.md +19 -22
- package/docs/getting-started.md +3 -3
- package/docs/images-and-metadata.md +6 -4
- package/docs/pages.md +120 -64
- package/docs/public-files.md +1 -1
- package/docs/site-files.md +36 -29
- package/docs/sitewide-content.md +1 -1
- package/docs/theme.md +107 -141
- package/docs/typography.md +15 -27
- package/examples/README.md +8 -2
- package/examples/complete-sites/dog-shelter-multi-page/site/.norna/generated-images.json +5 -5
- package/examples/complete-sites/dog-shelter-single-page/site/.norna/generated-images.json +10 -10
- package/examples/feature-demos/media-and-surfaces/.astro/collections/theme.schema.json +35 -43
- package/examples/feature-demos/media-and-surfaces/.astro/data-store.json +1 -1
- package/examples/feature-demos/media-and-surfaces/site/pages/020-surfaces/content.md +2 -1
- package/examples/feature-demos/media-and-surfaces/site/pages/020-surfaces/theme.yaml +2 -3
- 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/pages/020-documentation → theme-preset-documentation/site/pages/000-home}/content.md +1 -1
- 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/pages/010-portfolio → theme-preset-portfolio/site/pages/000-home}/content.md +1 -1
- 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/pages/030-project → theme-preset-project/site/pages/000-home}/content.md +1 -1
- 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/pages/040-statement → theme-preset-statement/site/pages/000-home}/content.md +1 -1
- 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/theme.yaml +1 -8
- 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/config.yaml +2 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/pages/010-macos/content.md +4 -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/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 -3
- package/fixtures/nested-pages/site/theme.yaml +1 -3
- package/package.json +2 -1
- package/schemas/config.schema.json +45 -4
- package/schemas/content-frontmatter.schema.json +5 -5
- package/schemas/manifest.json +3 -2
- package/schemas/page-theme.schema.json +192 -0
- package/schemas/sitewide-content.schema.json +17 -17
- package/schemas/theme.schema.json +188 -216
- package/scripts/check-config.mjs +2 -1
- package/scripts/deploy-site.mjs +1 -1
- package/scripts/generate-images.mjs +7 -14
- package/scripts/generate-schemas.mjs +4 -1
- package/scripts/lib/editor-language-service.mjs +0 -14
- package/scripts/lib/example-sites.mjs +15 -3
- package/scripts/lib/page-model.mjs +26 -7
- package/scripts/lib/presentation.mjs +25 -17
- package/scripts/lib/project-config.mjs +26 -16
- package/scripts/lib/schema-definitions.mjs +42 -14
- package/scripts/lib/schema-editor-metadata.mjs +70 -26
- package/scripts/lib/schema-value-definitions.mjs +14 -0
- package/scripts/lib/site-content.mjs +50 -25
- package/scripts/lib/site-conventions.mjs +1 -0
- package/scripts/lib/site-paths.mjs +9 -3
- package/scripts/lib/theme-config.mjs +3 -2
- package/scripts/lib/theme-presets.mjs +54 -21
- package/scripts/show-typography.mjs +1 -33
- package/scripts/sync-content-sections.mjs +1 -3
- package/scripts/test-banner-visibility.mjs +2 -2
- package/scripts/test-client-javascript.mjs +11 -4
- package/scripts/test-content-check.mjs +25 -25
- package/scripts/test-content-model-v2.mjs +165 -101
- package/scripts/test-documentation.mjs +4 -2
- package/scripts/test-editor-language-service.mjs +11 -8
- package/scripts/test-engine-commands.mjs +5 -5
- package/scripts/test-examples.mjs +30 -1
- package/scripts/test-heading-ids.mjs +2 -2
- package/scripts/test-navigation.mjs +11 -2
- package/scripts/test-nested-pages.mjs +25 -10
- package/scripts/test-package-check.mjs +29 -60
- package/scripts/test-page-model.mjs +30 -2
- package/scripts/test-project-config.mjs +5 -10
- package/scripts/test-schemas.mjs +18 -3
- package/scripts/test-theme-presets.mjs +33 -27
- package/src/components/NavigationPageTree.astro +114 -25
- package/src/components/PageContentsLinks.astro +40 -0
- package/src/components/SectionNavigationScript.astro +12 -5
- package/src/components/SiteBreadcrumbs.astro +17 -14
- package/src/components/SiteNavigation.astro +45 -12
- package/src/components/SitePage.astro +37 -23
- package/src/components/SiteSection.astro +2 -7
- package/src/components/SiteTreeNavigation.astro +35 -0
- package/src/components/TreeNavigationScript.astro +83 -0
- package/src/content.config.ts +2 -8
- package/src/layouts/BaseLayout.astro +10 -0
- package/src/lib/pageThemes.ts +11 -9
- package/src/lib/sectionContent.ts +1 -5
- package/src/lib/siteNavigation.ts +2 -1
- package/src/lib/sitePages.ts +25 -14
- package/src/pages/index.astro +2 -1
- package/src/styles/global.css +411 -43
- package/starters/basic/README.md +7 -7
- package/starters/basic/site/theme.yaml +1 -105
- package/starters/project/README.md +8 -8
- package/starters/project/site/theme.yaml +1 -31
- 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 -14
- package/examples/feature-demos/theme-presets/site/theme.yaml +0 -1
- /package/examples/complete-sites/dog-shelter-multi-page/site/{content.md → pages/000-home/content.md} +0 -0
- /package/examples/complete-sites/dog-shelter-multi-page/site/{images → pages/000-home/images}/shelter-dog.jpg +0 -0
- /package/examples/complete-sites/dog-shelter-single-page/site/{content.md → pages/000-home/content.md} +0 -0
- /package/examples/complete-sites/dog-shelter-single-page/site/{images → pages/000-home/images}/foster-dog.jpg +0 -0
- /package/examples/complete-sites/dog-shelter-single-page/site/{images → pages/000-home/images}/rescue-dog.jpg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{content.md → pages/000-home/content.md} +0 -0
- /package/examples/feature-demos/sitewide-content/site/{content.md → pages/000-home/content.md} +0 -0
- /package/examples/feature-demos/{theme-presets → theme-preset-documentation}/site/config.yaml +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/020-documentation → theme-preset-documentation/site/pages/000-home}/images/black-schnauzer.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/020-documentation → theme-preset-documentation/site/pages/000-home}/images/retriever-portrait.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/020-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 → theme-preset-documentation}/site/sitewide-content.yaml +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/020-documentation → theme-preset-documentation/site}/theme.yaml +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/010-portfolio → theme-preset-portfolio/site/pages/000-home}/images/puppy-portrait.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/010-portfolio → theme-preset-portfolio/site/pages/000-home}/images/shepherd-portrait.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/010-portfolio → theme-preset-portfolio/site/pages/000-home}/images/white-puppy.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/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/pages/030-project → theme-preset-project/site/pages/000-home}/images/boxer-portrait.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/030-project → theme-preset-project/site/pages/000-home}/images/grass-puppy.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/030-project → theme-preset-project/site/pages/000-home}/images/grey-street-dog.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/030-project → theme-preset-project/site}/theme.yaml +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/040-statement → theme-preset-statement/site/pages/000-home}/images/black-pedigree.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/040-statement → theme-preset-statement/site/pages/000-home}/images/sheepdog-grass.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/040-statement → theme-preset-statement/site/pages/000-home}/images/sheepdog-wide.jpg +0 -0
- /package/examples/feature-demos/{theme-presets/site/pages/040-statement → theme-preset-statement/site}/theme.yaml +0 -0
- /package/fixtures/basic/site/{content.md → pages/000-home/content.md} +0 -0
- /package/fixtures/basic/site/{images → pages/000-home/images}/.gitkeep +0 -0
- /package/fixtures/content-model-v2/site/{content.md → pages/000-home/content.md} +0 -0
- /package/fixtures/content-model-v2/site/{images → pages/000-home/images}/adopt.svg +0 -0
- /package/fixtures/content-model-v2/site/{images → pages/000-home/images}/detail.jpg +0 -0
- /package/fixtures/content-model-v2/site/{images → pages/000-home/images}/duplicate.jpg +0 -0
- /package/fixtures/content-model-v2/site/{images → pages/000-home/images}/foster.svg +0 -0
- /package/fixtures/content-model-v2/site/{images → pages/000-home/images}/hero.jpg +0 -0
- /package/fixtures/content-model-v2/site/{images → pages/000-home/images}/image.jpg +0 -0
- /package/fixtures/content-model-v2/site/{images → pages/000-home/images}/slide-one.jpg +0 -0
- /package/fixtures/content-model-v2/site/{images → pages/000-home/images}/slide-three.jpg +0 -0
- /package/fixtures/content-model-v2/site/{images → pages/000-home/images}/slide-two.jpg +0 -0
- /package/fixtures/nested-pages/site/{content.md → pages/000-home/content.md} +0 -0
- /package/starters/basic/site/{content.md → pages/000-home/content.md} +0 -0
- /package/starters/basic/site/{images → pages/000-home/images}/.gitkeep +0 -0
- /package/starters/project/site/{content.md → pages/000-home/content.md} +0 -0
|
@@ -9,6 +9,8 @@ const cliPath = path.join(repoRoot, 'bin', 'norna.mjs');
|
|
|
9
9
|
const tutorialPath = path.join(repoRoot, 'docs', 'getting-started.md');
|
|
10
10
|
const scratchRoot = path.join(repoRoot, 'todos');
|
|
11
11
|
const obsoleteSourceReferences = [
|
|
12
|
+
'site/content.md',
|
|
13
|
+
'site/images/',
|
|
12
14
|
'site/config.md',
|
|
13
15
|
'site/theme.md',
|
|
14
16
|
'site/sitewide-content.md',
|
|
@@ -149,8 +151,8 @@ try {
|
|
|
149
151
|
|
|
150
152
|
await Promise.all([
|
|
151
153
|
writeFile(
|
|
152
|
-
path.join(tutorialSiteRoot, 'site', 'content.md'),
|
|
153
|
-
extractTutorialFile(tutorial, 'Replace `site/content.md` with:', 'md'),
|
|
154
|
+
path.join(tutorialSiteRoot, 'site', 'pages', '000-home', 'content.md'),
|
|
155
|
+
extractTutorialFile(tutorial, 'Replace `site/pages/000-home/content.md` with:', 'md'),
|
|
154
156
|
),
|
|
155
157
|
writeFile(
|
|
156
158
|
path.join(tutorialSiteRoot, 'site', 'sitewide-content.yaml'),
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
|
|
19
19
|
const root = await mkdtemp(path.join(os.tmpdir(), 'norna-editor-language-'));
|
|
20
20
|
const siteRoot = path.join(root, 'site');
|
|
21
|
-
const homeContentPath = path.join(siteRoot, 'content.md');
|
|
21
|
+
const homeContentPath = path.join(siteRoot, 'pages', '000-home', 'content.md');
|
|
22
22
|
const pageContentPath = path.join(siteRoot, 'pages', '010-about', 'content.md');
|
|
23
23
|
const pageThemePath = path.join(siteRoot, 'pages', '010-about', 'theme.yaml');
|
|
24
24
|
const nestedPageContentPath = path.join(siteRoot, 'pages', '010-about', 'pages', '020-team', 'content.md');
|
|
@@ -63,7 +63,7 @@ Page content.
|
|
|
63
63
|
|
|
64
64
|
try {
|
|
65
65
|
await mkdir(path.join(installedNornaRoot, 'schemas'), { recursive: true });
|
|
66
|
-
await mkdir(path.join(siteRoot, 'images'), { recursive: true });
|
|
66
|
+
await mkdir(path.join(siteRoot, 'pages', '000-home', 'images'), { recursive: true });
|
|
67
67
|
await mkdir(path.join(siteRoot, 'pages', '010-about', 'images'), { recursive: true });
|
|
68
68
|
await mkdir(path.dirname(nestedPageContentPath), { recursive: true });
|
|
69
69
|
await mkdir(path.join(siteRoot, 'public'), { recursive: true });
|
|
@@ -74,6 +74,7 @@ try {
|
|
|
74
74
|
files: {
|
|
75
75
|
config: 'config.schema.json',
|
|
76
76
|
contentFrontmatter: 'content-frontmatter.schema.json',
|
|
77
|
+
pageTheme: 'page-theme.schema.json',
|
|
77
78
|
sitewideContent: 'sitewide-content.schema.json',
|
|
78
79
|
theme: 'theme.schema.json',
|
|
79
80
|
},
|
|
@@ -84,7 +85,7 @@ try {
|
|
|
84
85
|
await writeFile(path.join(siteRoot, 'sitewide-content.yaml'), `logo:
|
|
85
86
|
height: 2rem
|
|
86
87
|
`);
|
|
87
|
-
await writeFile(path.join(siteRoot, 'images', 'local.jpg'), 'local');
|
|
88
|
+
await writeFile(path.join(siteRoot, 'pages', '000-home', 'images', 'local.jpg'), 'local');
|
|
88
89
|
await writeFile(path.join(siteRoot, 'pages', '010-about', 'images', 'portrait.jpg'), 'portrait');
|
|
89
90
|
await writeFile(path.join(siteRoot, 'public', 'logo.svg'), '<svg/>');
|
|
90
91
|
await writeFile(path.join(siteRoot, 'public', 'logo.png'), 'logo');
|
|
@@ -94,21 +95,22 @@ try {
|
|
|
94
95
|
await writeFile(path.join(siteRoot, 'public', 'favicon-32x32.png'), 'unrecognized');
|
|
95
96
|
await writeFile(homeContentPath, homeSource);
|
|
96
97
|
await writeFile(pageContentPath, pageSource);
|
|
97
|
-
await writeFile(pageThemePath, '
|
|
98
|
+
await writeFile(pageThemePath, 'layout:\n textWidth: wide\n');
|
|
98
99
|
await writeFile(nestedPageContentPath, pageSource.replace('# About', '# Team'));
|
|
99
|
-
await writeFile(nestedPageThemePath, '
|
|
100
|
+
await writeFile(nestedPageThemePath, 'layout:\n contentSpacing: compact\n');
|
|
100
101
|
|
|
101
102
|
assert.equal(await findNornaSiteRoot(homeContentPath), siteRoot);
|
|
102
103
|
assert.equal(getNornaDocumentContext(homeContentPath).schemaKind, 'contentFrontmatter');
|
|
104
|
+
assert.equal(getNornaDocumentContext(homeContentPath).pageDirectory, '000-home');
|
|
103
105
|
assert.equal(getNornaDocumentContext(homeContentPath).nornaPackage.root, installedNornaRoot);
|
|
104
106
|
assert.equal(getNornaDocumentContext(path.join(siteRoot, 'config.yaml')).schemaKind, 'config');
|
|
105
107
|
assert.equal(getNornaDocumentContext(path.join(siteRoot, 'theme.yaml')).schemaKind, 'theme');
|
|
106
108
|
assert.equal(getNornaDocumentContext(path.join(siteRoot, 'sitewide-content.yaml')).schemaKind, 'sitewideContent');
|
|
107
109
|
assert.equal(getNornaDocumentContext(pageContentPath).pageDirectory, '010-about');
|
|
108
|
-
assert.equal(getNornaDocumentContext(pageThemePath).schemaKind, '
|
|
110
|
+
assert.equal(getNornaDocumentContext(pageThemePath).schemaKind, 'pageTheme');
|
|
109
111
|
assert.equal(getNornaDocumentContext(nestedPageContentPath).pageDirectory, '010-about/pages/020-team');
|
|
110
112
|
assert.equal(getNornaDocumentContext(nestedPageContentPath).schemaKind, 'contentFrontmatter');
|
|
111
|
-
assert.equal(getNornaDocumentContext(nestedPageThemePath).schemaKind, '
|
|
113
|
+
assert.equal(getNornaDocumentContext(nestedPageThemePath).schemaKind, 'pageTheme');
|
|
112
114
|
assert.equal(getNornaProjectContext(path.join(siteRoot, 'public', 'logo.svg')).siteRoot, siteRoot);
|
|
113
115
|
assert.equal(getNornaDocumentContext(path.join(siteRoot, 'public', 'logo.svg')), null);
|
|
114
116
|
assert.equal(getNornaDocumentContext(path.join(root, 'README.md')), null);
|
|
@@ -116,6 +118,7 @@ try {
|
|
|
116
118
|
await mkdir(path.join(siteRoot, 'pages', 'about'), { recursive: true });
|
|
117
119
|
await writeFile(path.join(siteRoot, 'pages', 'about', 'content.md'), pageSource);
|
|
118
120
|
assert.equal(getNornaDocumentContext(path.join(siteRoot, 'pages', 'about', 'content.md')), null);
|
|
121
|
+
assert.equal(getNornaDocumentContext(path.join(siteRoot, 'pages', '000-home', 'pages', '010-news', 'content.md')), null);
|
|
119
122
|
await mkdir(path.join(siteRoot, 'pages', '010-about', 'nested'), { recursive: true });
|
|
120
123
|
await writeFile(path.join(siteRoot, 'pages', '010-about', 'nested', 'content.md'), pageSource);
|
|
121
124
|
assert.equal(getNornaDocumentContext(path.join(siteRoot, 'pages', '010-about', 'nested', 'content.md')), null);
|
|
@@ -244,7 +247,7 @@ try {
|
|
|
244
247
|
line: localDefinitionLine,
|
|
245
248
|
source: homeSource,
|
|
246
249
|
});
|
|
247
|
-
assert.deepEqual(localDefinition.files, [path.join(siteRoot, 'images', 'local.jpg')]);
|
|
250
|
+
assert.deepEqual(localDefinition.files, [path.join(siteRoot, 'pages', '000-home', 'images', 'local.jpg')]);
|
|
248
251
|
|
|
249
252
|
const diagnostics = await getMarkdownDiagnostics({ documentPath: homeContentPath, source: homeSource });
|
|
250
253
|
assert.ok(diagnostics.some(({ code, message }) => code === 'image-needs-sync' && message.includes('Run "norna content:sync"')));
|
|
@@ -39,9 +39,9 @@ try {
|
|
|
39
39
|
assert.match(deployWatchHelpResult.stdout, /Default: deploy\.yml/);
|
|
40
40
|
|
|
41
41
|
const directSiteRoot = path.join(tempRoot, 'current-directory-site');
|
|
42
|
-
await mkdir(directSiteRoot, { recursive: true });
|
|
42
|
+
await mkdir(path.join(directSiteRoot, 'pages', '000-home'), { recursive: true });
|
|
43
43
|
await writeFile(path.join(directSiteRoot, 'config.yaml'), 'url: https://example.com/\n');
|
|
44
|
-
await writeFile(path.join(directSiteRoot, 'content.md'), '# Direct Site\n\n## Intro {#intro}\n\nText.\n');
|
|
44
|
+
await writeFile(path.join(directSiteRoot, 'pages', '000-home', 'content.md'), '# Direct Site\n\n## Intro {#intro}\n\nText.\n');
|
|
45
45
|
const directSiteProjectRoot = await realpath(tempRoot);
|
|
46
46
|
const directSiteDoctorResult = runCli(['doctor'], {
|
|
47
47
|
cwd: directSiteRoot,
|
|
@@ -99,7 +99,7 @@ try {
|
|
|
99
99
|
assert.match(showResult.stdout, /theme:/);
|
|
100
100
|
assert.match(showResult.stdout, /pages:/);
|
|
101
101
|
assert.match(showResult.stdout, /\s+\/:/);
|
|
102
|
-
assert.match(showResult.stdout, /value:
|
|
102
|
+
assert.match(showResult.stdout, /value: reading/);
|
|
103
103
|
assert.match(showResult.stdout, /source: "site\/theme\.yaml"/);
|
|
104
104
|
assert.match(showResult.stdout, /intro:/);
|
|
105
105
|
|
|
@@ -116,7 +116,7 @@ try {
|
|
|
116
116
|
assert.equal(customStandalonePackageJson.scripts['norna:dev'], 'norna --site-dir presentation dev:local');
|
|
117
117
|
assert.equal(customStandalonePackageJson.scripts['norna:check'], 'norna --site-dir presentation check');
|
|
118
118
|
assert.equal(customStandalonePackageJson.scripts['norna:build'], 'norna --site-dir presentation build');
|
|
119
|
-
await readFile(path.join(customStandaloneSiteRoot, 'presentation', 'content.md'));
|
|
119
|
+
await readFile(path.join(customStandaloneSiteRoot, 'presentation', 'pages', '000-home', 'content.md'));
|
|
120
120
|
await readFile(path.join(customStandaloneSiteRoot, 'presentation', 'config.yaml'));
|
|
121
121
|
await readFile(path.join(customStandaloneSiteRoot, 'presentation', 'theme.yaml'));
|
|
122
122
|
|
|
@@ -143,7 +143,7 @@ try {
|
|
|
143
143
|
assert.equal(mixedPackageJson.scripts['norna:check'], 'norna --site-dir presentation check');
|
|
144
144
|
assert.equal(mixedPackageJson.scripts['norna:engine:update'], 'norna --site-dir presentation engine:update');
|
|
145
145
|
assert.equal(mixedPackageJson.scripts['norna:engine:version'], 'norna --site-dir presentation engine:version');
|
|
146
|
-
await readFile(path.join(mixedProjectRoot, 'presentation', 'content.md'));
|
|
146
|
+
await readFile(path.join(mixedProjectRoot, 'presentation', 'pages', '000-home', 'content.md'));
|
|
147
147
|
await readFile(path.join(mixedProjectRoot, 'presentation', 'config.yaml'));
|
|
148
148
|
await readFile(path.join(mixedProjectRoot, 'presentation', 'theme.yaml'));
|
|
149
149
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
1
2
|
import { existsSync } from 'node:fs';
|
|
2
|
-
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
3
5
|
import path from 'node:path';
|
|
4
6
|
import { fileURLToPath } from 'node:url';
|
|
5
7
|
import { getExampleSites } from './lib/example-sites.mjs';
|
|
@@ -9,6 +11,33 @@ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
|
9
11
|
const cliPath = path.join(root, 'bin', 'norna.mjs');
|
|
10
12
|
const examples = await getExampleSites(root);
|
|
11
13
|
|
|
14
|
+
const discoveryRoot = await mkdtemp(path.join(tmpdir(), 'norna-example-discovery-'));
|
|
15
|
+
try {
|
|
16
|
+
for (const category of ['complete-sites', 'feature-demos']) {
|
|
17
|
+
await mkdir(path.join(discoveryRoot, 'examples', category), { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
const validSite = path.join(discoveryRoot, 'examples', 'complete-sites', 'valid', 'site');
|
|
20
|
+
await mkdir(path.join(validSite, 'pages', '000-home'), { recursive: true });
|
|
21
|
+
await writeFile(path.join(validSite, 'config.yaml'), 'url: https://example.com/\n');
|
|
22
|
+
await writeFile(path.join(validSite, 'pages', '000-home', 'content.md'), '# Example\n');
|
|
23
|
+
await mkdir(path.join(
|
|
24
|
+
discoveryRoot,
|
|
25
|
+
'examples',
|
|
26
|
+
'feature-demos',
|
|
27
|
+
'removed-example',
|
|
28
|
+
'site',
|
|
29
|
+
'.norna',
|
|
30
|
+
'public',
|
|
31
|
+
'images',
|
|
32
|
+
'generated',
|
|
33
|
+
), { recursive: true });
|
|
34
|
+
|
|
35
|
+
const discovered = await getExampleSites(discoveryRoot);
|
|
36
|
+
assert.deepEqual(discovered.map(({ name }) => name), ['valid']);
|
|
37
|
+
} finally {
|
|
38
|
+
await rm(discoveryRoot, { recursive: true, force: true });
|
|
39
|
+
}
|
|
40
|
+
|
|
12
41
|
for (const example of examples) {
|
|
13
42
|
console.log(`\nBuilding ${example.siteLabel}`);
|
|
14
43
|
await runInherit(process.execPath, [cliPath, '--site-dir', example.siteLabel, 'build'], { cwd: root });
|
|
@@ -43,9 +43,9 @@ const collision = await getMarkdownHeadings(`# Page
|
|
|
43
43
|
`);
|
|
44
44
|
assert.equal(getHeadingIdentifierIssues(collision.headings)[0]?.code, 'duplicate-heading-id');
|
|
45
45
|
assert.equal(
|
|
46
|
-
formatHeadingIdentifierIssue(getHeadingIdentifierIssues(collision.headings)[0], 'site/content.md'),
|
|
46
|
+
formatHeadingIdentifierIssue(getHeadingIdentifierIssues(collision.headings)[0], 'site/pages/000-home/content.md'),
|
|
47
47
|
[
|
|
48
|
-
'site/content.md: Two headings resolve to id "forsta".',
|
|
48
|
+
'site/pages/000-home/content.md: Two headings resolve to id "forsta".',
|
|
49
49
|
'- line 3: "Förstå"',
|
|
50
50
|
'- line 5: "Forsta"',
|
|
51
51
|
'Add a unique explicit id to at least one heading, for example {#forsta-details}.',
|
|
@@ -5,10 +5,19 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
|
|
6
6
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
7
7
|
const cliPath = path.join(root, 'bin', 'norna.mjs');
|
|
8
|
-
const navigationDemoSiteDir = path.join(root, 'examples', 'feature-demos', 'media-and-surfaces', 'site');
|
|
9
8
|
const host = '127.0.0.1';
|
|
10
9
|
const npmBin = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
11
|
-
const
|
|
10
|
+
const cliArguments = process.argv.slice(2);
|
|
11
|
+
const siteDirOptionIndex = cliArguments.indexOf('--site-dir');
|
|
12
|
+
const configuredSiteDir = siteDirOptionIndex === -1
|
|
13
|
+
? path.join('examples', 'feature-demos', 'media-and-surfaces', 'site')
|
|
14
|
+
: cliArguments[siteDirOptionIndex + 1];
|
|
15
|
+
if (!configuredSiteDir || configuredSiteDir.startsWith('--')) {
|
|
16
|
+
throw new Error('Use --site-dir <path> to select a navigation test site.');
|
|
17
|
+
}
|
|
18
|
+
if (siteDirOptionIndex !== -1) cliArguments.splice(siteDirOptionIndex, 2);
|
|
19
|
+
const navigationDemoSiteDir = path.resolve(root, configuredSiteDir);
|
|
20
|
+
const testTargets = cliArguments;
|
|
12
21
|
const playwrightTargets = testTargets.length > 0 ? testTargets : ['tests/navigation.spec.ts'];
|
|
13
22
|
|
|
14
23
|
const sleep = (milliseconds) => new Promise((resolve) => {
|
|
@@ -46,6 +46,7 @@ try {
|
|
|
46
46
|
'guides/installation/index.html',
|
|
47
47
|
'guides/installation/macos/index.html',
|
|
48
48
|
'guides/workflows/index.html',
|
|
49
|
+
'guides/release-notes/index.html',
|
|
49
50
|
'reference/index.html',
|
|
50
51
|
'reference/installation/index.html',
|
|
51
52
|
];
|
|
@@ -57,20 +58,34 @@ try {
|
|
|
57
58
|
const guidesHtml = await readFile(path.join(distDir, 'guides', 'index.html'), 'utf8');
|
|
58
59
|
const installationHtml = await readFile(path.join(distDir, 'guides', 'installation', 'index.html'), 'utf8');
|
|
59
60
|
const macosHtml = await readFile(path.join(distDir, 'guides', 'installation', 'macos', 'index.html'), 'utf8');
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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,/);
|
|
64
74
|
assert.match(installationHtml, /Three nested page levels connected in sequence/);
|
|
65
75
|
assert.match(installationHtml, /\/original\/pages\/010-guides\/pages\/010-installation\/images\/diagram-[a-f0-9]+\.svg/);
|
|
66
|
-
assert.match(macosHtml, /
|
|
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"/);
|
|
67
79
|
assert.match(macosHtml, /href="\/guides\/installation\/macos\/" aria-current="page"/);
|
|
68
|
-
assert.match(macosHtml, /<
|
|
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>/);
|
|
69
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>/);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
assert.
|
|
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"/);
|
|
74
89
|
assert.ok(
|
|
75
90
|
macosHtml.indexOf('href="/guides/installation/"') < macosHtml.indexOf('href="/guides/workflows/"'),
|
|
76
91
|
'Nested sibling navigation should follow page directory order.',
|
|
@@ -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', 'images', '.gitkeep')),
|
|
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(
|
|
@@ -204,7 +204,7 @@ try {
|
|
|
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'), `---
|
|
207
|
+
await writeFile(path.join(siteProjectRoot, 'site', 'pages', '000-home', 'content.md'), `---
|
|
208
208
|
page:
|
|
209
209
|
description: Site used by package checks.
|
|
210
210
|
---
|
|
@@ -248,12 +248,14 @@ This page verifies that packaged norna sites can build additional pages.
|
|
|
248
248
|
assertFileExists(path.join(initializedSiteRoot, 'package.json')),
|
|
249
249
|
assertFileExists(path.join(initializedSiteRoot, 'site', 'config.yaml')),
|
|
250
250
|
assertFileExists(path.join(initializedSiteRoot, 'site', 'theme.yaml')),
|
|
251
|
+
assertFileExists(path.join(initializedSiteRoot, 'site', 'pages', '000-home', 'content.md')),
|
|
251
252
|
assertFileMissing(path.join(initializedSiteRoot, '.DS_Store')),
|
|
252
253
|
assertFileMissing(path.join(initializedSiteRoot, 'site', '.DS_Store')),
|
|
253
254
|
]);
|
|
254
|
-
|
|
255
|
-
await runInherit(npxBin, ['norna', '
|
|
256
|
-
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 });
|
|
257
259
|
await runInherit(npxBin, ['norna', 'content:check'], { cwd: siteProjectRoot, env: npmEnv });
|
|
258
260
|
await runInherit(npxBin, ['norna', 'check'], { cwd: siteProjectRoot, env: npmEnv });
|
|
259
261
|
await runInherit(npxBin, ['norna', 'build'], { cwd: siteProjectRoot, env: npmEnv });
|
|
@@ -275,19 +277,19 @@ This page verifies that packaged norna sites can build additional pages.
|
|
|
275
277
|
);
|
|
276
278
|
await assertFileIncludes(
|
|
277
279
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
278
|
-
'--section-heading-font-weight:
|
|
280
|
+
'--section-heading-font-weight: 500',
|
|
279
281
|
);
|
|
280
282
|
await assertFileIncludes(
|
|
281
283
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
282
|
-
'--section-heading-spacing-after: 0.
|
|
284
|
+
'--section-heading-spacing-after: 0.45em',
|
|
283
285
|
);
|
|
284
286
|
await assertFileIncludes(
|
|
285
287
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
286
|
-
'--section-markdown-h3-spacing-before: 1.
|
|
288
|
+
'--section-markdown-h3-spacing-before: 1.2em',
|
|
287
289
|
);
|
|
288
290
|
await assertFileIncludes(
|
|
289
291
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
290
|
-
"--font-sans:
|
|
292
|
+
"--font-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
291
293
|
);
|
|
292
294
|
await assertFileIncludes(
|
|
293
295
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
@@ -323,7 +325,7 @@ This page verifies that packaged norna sites can build additional pages.
|
|
|
323
325
|
);
|
|
324
326
|
await assertFileIncludes(
|
|
325
327
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
326
|
-
'<nav class="page-nav" aria-label="
|
|
328
|
+
'<nav class="page-nav" aria-label="Page contents">',
|
|
327
329
|
);
|
|
328
330
|
await assertFileIncludes(
|
|
329
331
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
@@ -335,7 +337,7 @@ This page verifies that packaged norna sites can build additional pages.
|
|
|
335
337
|
);
|
|
336
338
|
await assertFileIncludes(
|
|
337
339
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
338
|
-
'--section-body-line-height: 1.
|
|
340
|
+
'--section-body-line-height: 1.62',
|
|
339
341
|
);
|
|
340
342
|
await assertFileIncludes(
|
|
341
343
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
@@ -347,15 +349,15 @@ This page verifies that packaged norna sites can build additional pages.
|
|
|
347
349
|
);
|
|
348
350
|
await assertFileIncludes(
|
|
349
351
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
350
|
-
'--section-body-paragraph-spacing: 0.
|
|
352
|
+
'--section-body-paragraph-spacing: 0.65em',
|
|
351
353
|
);
|
|
352
354
|
await assertFileIncludes(
|
|
353
355
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
354
|
-
'--section-caption-line-height: 1.
|
|
356
|
+
'--section-caption-line-height: 1.4',
|
|
355
357
|
);
|
|
356
358
|
await assertFileIncludes(
|
|
357
359
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
358
|
-
'--section-caption-spacing-before: 0.
|
|
360
|
+
'--section-caption-spacing-before: 0.35em',
|
|
359
361
|
);
|
|
360
362
|
await assertFileIncludes(
|
|
361
363
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
@@ -375,35 +377,31 @@ This page verifies that packaged norna sites can build additional pages.
|
|
|
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
|
-
'--
|
|
388
|
+
'--site-top-background-color: #ffffff',
|
|
387
389
|
);
|
|
388
390
|
await assertFileIncludes(
|
|
389
391
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
390
|
-
'--site-top-
|
|
392
|
+
'--site-top-text-color: #17201d',
|
|
391
393
|
);
|
|
392
394
|
await assertFileIncludes(
|
|
393
395
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
394
|
-
'--site-
|
|
396
|
+
'--site-footer-background-color: #ffffff',
|
|
395
397
|
);
|
|
396
398
|
await assertFileIncludes(
|
|
397
399
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
398
|
-
'--site-footer-
|
|
400
|
+
'--site-footer-text-color: #17201d',
|
|
399
401
|
);
|
|
400
402
|
await assertFileIncludes(
|
|
401
403
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
402
|
-
'--
|
|
403
|
-
);
|
|
404
|
-
await assertFileIncludes(
|
|
405
|
-
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
406
|
-
'--section-text-color: #f2eee6',
|
|
404
|
+
'--section-text-color: #17201d',
|
|
407
405
|
);
|
|
408
406
|
await writeFile(path.join(siteProjectRoot, 'site', 'public', 'favicon.ico'), 'fake icon');
|
|
409
407
|
await runInherit(npxBin, ['norna', 'build'], { cwd: siteProjectRoot, env: npmEnv });
|
|
@@ -416,47 +414,24 @@ This page verifies that packaged norna sites can build additional pages.
|
|
|
416
414
|
path.join(siteProjectRoot, 'dist', 'index.html'),
|
|
417
415
|
'href="/favicon.svg"',
|
|
418
416
|
);
|
|
419
|
-
const siteContentPath = path.join(siteProjectRoot, 'site', 'content.md');
|
|
417
|
+
const siteContentPath = path.join(siteProjectRoot, 'site', 'pages', '000-home', 'content.md');
|
|
420
418
|
const siteContent = await readFile(siteContentPath, 'utf8');
|
|
421
419
|
const siteThemePath = path.join(siteProjectRoot, 'site', 'theme.yaml');
|
|
422
420
|
const siteTheme = await readFile(siteThemePath, 'utf8');
|
|
423
|
-
await writeFile(siteThemePath, siteTheme.
|
|
421
|
+
await writeFile(siteThemePath, `${siteTheme.trim()}\ntypography:\n profile: noisy\n`);
|
|
424
422
|
await runExpectFailure(
|
|
425
423
|
npxBin,
|
|
426
424
|
['norna', 'build'],
|
|
427
425
|
{ cwd: siteProjectRoot, env: npmEnv },
|
|
428
|
-
'
|
|
429
|
-
);
|
|
430
|
-
await writeFile(
|
|
431
|
-
siteThemePath,
|
|
432
|
-
siteTheme.replace('\npalette: dark', '\npalette: neon'),
|
|
426
|
+
'typography.profile',
|
|
433
427
|
);
|
|
428
|
+
await writeFile(siteThemePath, `${siteTheme.trim()}\npalette: neon\n`);
|
|
434
429
|
await runExpectFailure(
|
|
435
430
|
npxBin,
|
|
436
431
|
['norna', 'build'],
|
|
437
432
|
{ cwd: siteProjectRoot, env: npmEnv },
|
|
438
433
|
'palette',
|
|
439
434
|
);
|
|
440
|
-
await writeFile(
|
|
441
|
-
siteThemePath,
|
|
442
|
-
siteTheme.replace('\nsectionSurfaces: [base, soft, emphasis]', '\nsectionSurfaces: [base, glowing]'),
|
|
443
|
-
);
|
|
444
|
-
await runExpectFailure(
|
|
445
|
-
npxBin,
|
|
446
|
-
['norna', 'build'],
|
|
447
|
-
{ cwd: siteProjectRoot, env: npmEnv },
|
|
448
|
-
'Unknown section surface "glowing"',
|
|
449
|
-
);
|
|
450
|
-
await writeFile(
|
|
451
|
-
siteThemePath,
|
|
452
|
-
siteTheme.replace('\nsectionSurfaces: [base, soft, emphasis]', '\nsectionSurfaces: [base, base]'),
|
|
453
|
-
);
|
|
454
|
-
await runExpectFailure(
|
|
455
|
-
npxBin,
|
|
456
|
-
['norna', 'build'],
|
|
457
|
-
{ cwd: siteProjectRoot, env: npmEnv },
|
|
458
|
-
'Each section surface may appear only once',
|
|
459
|
-
);
|
|
460
435
|
await writeFile(siteThemePath, siteTheme);
|
|
461
436
|
await writeFile(
|
|
462
437
|
siteContentPath,
|
|
@@ -498,13 +473,7 @@ This page verifies that packaged norna sites can build additional pages.
|
|
|
498
473
|
{ cwd: siteProjectRoot, env: npmEnv },
|
|
499
474
|
'defines "sections" at the top level, but it is not a valid top-level content field',
|
|
500
475
|
);
|
|
501
|
-
await writeFile(
|
|
502
|
-
siteThemePath,
|
|
503
|
-
siteTheme.replace(
|
|
504
|
-
'fontFamily: "Arial, \'Helvetica Neue\', Helvetica, sans-serif"',
|
|
505
|
-
'fontFamily: "Arial; color: red"',
|
|
506
|
-
),
|
|
507
|
-
);
|
|
476
|
+
await writeFile(siteThemePath, `${siteTheme.trim()}\ntypography:\n fontFamily: "Arial; color: red"\n`);
|
|
508
477
|
await runExpectFailure(
|
|
509
478
|
npxBin,
|
|
510
479
|
['norna', 'config:check'],
|
|
@@ -19,6 +19,29 @@ assert.deepEqual(parsePageDirectory('120-api-reference'), {
|
|
|
19
19
|
pageId: 'api-reference',
|
|
20
20
|
});
|
|
21
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
|
+
|
|
22
45
|
assert.deepEqual(parsePageDirectoryPath('010-guides/pages/020-installation'), {
|
|
23
46
|
pageDirectory: '010-guides/pages/020-installation',
|
|
24
47
|
pageDirectories: ['010-guides', '020-installation'],
|
|
@@ -62,7 +85,7 @@ for (const pageDirectoryPath of [
|
|
|
62
85
|
}
|
|
63
86
|
|
|
64
87
|
for (const pageDirectory of [
|
|
65
|
-
'000-
|
|
88
|
+
'000-about',
|
|
66
89
|
'10-about',
|
|
67
90
|
'010_About',
|
|
68
91
|
'010-About',
|
|
@@ -72,9 +95,14 @@ for (const pageDirectory of [
|
|
|
72
95
|
]) {
|
|
73
96
|
assert.throws(
|
|
74
97
|
() => parsePageDirectory(pageDirectory),
|
|
75
|
-
/Page directories must use the form NNN-page-id/,
|
|
98
|
+
/(Page directories must use the form NNN-page-id|000 prefix is reserved)/,
|
|
76
99
|
`${pageDirectory} should be rejected`,
|
|
77
100
|
);
|
|
78
101
|
}
|
|
79
102
|
|
|
103
|
+
assert.throws(
|
|
104
|
+
() => parsePageDirectoryPath('010-guides/pages/000-home'),
|
|
105
|
+
/000-home is allowed only as a top-level page/,
|
|
106
|
+
);
|
|
107
|
+
|
|
80
108
|
console.log('Page model test passed.');
|
|
@@ -24,9 +24,9 @@ const importScript = `
|
|
|
24
24
|
const createSite = async (name, config) => {
|
|
25
25
|
const projectRoot = path.join(tempRoot, name);
|
|
26
26
|
const siteDir = path.join(projectRoot, 'site');
|
|
27
|
-
await mkdir(siteDir, { recursive: true });
|
|
27
|
+
await mkdir(path.join(siteDir, 'pages', '000-home'), { recursive: true });
|
|
28
28
|
await writeFile(path.join(siteDir, 'config.yaml'), config);
|
|
29
|
-
await writeFile(path.join(siteDir, 'content.md'), '# Config test\n\n## Intro {#intro}\n\nText.\n');
|
|
29
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), '# Config test\n\n## Intro {#intro}\n\nText.\n');
|
|
30
30
|
await writeFile(path.join(siteDir, 'theme.yaml'), 'preset: documentation\n');
|
|
31
31
|
return { projectRoot, siteDir };
|
|
32
32
|
};
|
|
@@ -69,11 +69,10 @@ try {
|
|
|
69
69
|
dismissBanner: 'Dismiss notice',
|
|
70
70
|
built: 'Built',
|
|
71
71
|
images: 'Images',
|
|
72
|
-
|
|
72
|
+
navigationChildren: 'Child pages',
|
|
73
73
|
navigationMenu: 'Menu',
|
|
74
|
-
navigationOverview: 'Overview',
|
|
75
74
|
note: 'Note',
|
|
76
|
-
pageNavigation: '
|
|
75
|
+
pageNavigation: 'Page contents',
|
|
77
76
|
siteBanners: 'Site notices',
|
|
78
77
|
siteNavigation: 'Pages',
|
|
79
78
|
skipToContent: 'Skip to content',
|
|
@@ -92,11 +91,7 @@ try {
|
|
|
92
91
|
assert.equal(localizedConfig.labels.skipToContent, 'Hoppa till innehållet');
|
|
93
92
|
assert.equal(localizedConfig.scrollBehavior, 'smooth');
|
|
94
93
|
|
|
95
|
-
const treeNavigationSite = await createSite('tree-navigation', 'url: https://example.com/\n');
|
|
96
|
-
await writeFile(path.join(treeNavigationSite.siteDir, 'theme.yaml'), `preset: documentation
|
|
97
|
-
navigation:
|
|
98
|
-
mode: tree
|
|
99
|
-
`);
|
|
94
|
+
const treeNavigationSite = await createSite('tree-navigation', 'url: https://example.com/\nnavigation:\n mode: tree\n');
|
|
100
95
|
const treeNavigationResult = loadConfig(treeNavigationSite);
|
|
101
96
|
assert.equal(treeNavigationResult.status, 0, treeNavigationResult.stderr);
|
|
102
97
|
assert.equal(JSON.parse(treeNavigationResult.stdout).navigationMode, 'tree');
|
package/scripts/test-schemas.mjs
CHANGED
|
@@ -10,18 +10,21 @@ const expectedDocumentationRef = `v${packageJson.version}`;
|
|
|
10
10
|
const filenames = [
|
|
11
11
|
'config.schema.json',
|
|
12
12
|
'theme.schema.json',
|
|
13
|
+
'page-theme.schema.json',
|
|
13
14
|
'sitewide-content.schema.json',
|
|
14
15
|
'content-frontmatter.schema.json',
|
|
15
16
|
];
|
|
16
17
|
const requiredRichHelp = {
|
|
17
|
-
'config.schema.json': ['url', 'language', 'scrollBehavior'],
|
|
18
|
-
'theme.schema.json': ['preset', '
|
|
18
|
+
'config.schema.json': ['url', 'language', 'navigation', 'scrollBehavior'],
|
|
19
|
+
'theme.schema.json': ['preset', 'shape', 'layout', 'images', 'typography', 'palette', 'sections'],
|
|
20
|
+
'page-theme.schema.json': ['layout', 'images', 'sections'],
|
|
19
21
|
'sitewide-content.schema.json': ['logo', 'banners', 'footer'],
|
|
20
22
|
'content-frontmatter.schema.json': ['page', 'navigation'],
|
|
21
23
|
};
|
|
22
24
|
const manifest = JSON.parse(await readFile(path.join(root, 'schemas', 'manifest.json'), 'utf8'));
|
|
23
25
|
assert.equal(manifest.editorApiVersion, 1);
|
|
24
|
-
assert.equal(manifest.schemaVersion,
|
|
26
|
+
assert.equal(manifest.schemaVersion, 2);
|
|
27
|
+
assert.equal(manifest.files.pageTheme, 'page-theme.schema.json');
|
|
25
28
|
|
|
26
29
|
const githubHeadingAnchor = (heading) => heading
|
|
27
30
|
.toLowerCase()
|
|
@@ -143,6 +146,18 @@ assert.equal(
|
|
|
143
146
|
theme.properties.images.properties.maxAvailableWidthPercent.defaultSnippets[0].label,
|
|
144
147
|
'Responsive image limit',
|
|
145
148
|
);
|
|
149
|
+
assert.equal(theme.properties.navigation, undefined);
|
|
150
|
+
assert.equal(theme.properties.layout.properties.density, undefined);
|
|
151
|
+
assert.ok(theme.properties.layout.properties.contentSpacing);
|
|
152
|
+
assert.ok(theme.properties.layout.properties.textWidth);
|
|
153
|
+
assert.ok(theme.properties.sections.properties.backgroundPattern);
|
|
154
|
+
|
|
155
|
+
const pageTheme = JSON.parse(await readFile(path.join(root, 'schemas', 'page-theme.schema.json'), 'utf8'));
|
|
156
|
+
assert.deepEqual(Object.keys(pageTheme.properties), ['layout', 'images', 'sections']);
|
|
157
|
+
assert.deepEqual(Object.keys(pageTheme.properties.layout.properties), ['contentSpacing', 'textWidth']);
|
|
158
|
+
assert.equal(pageTheme.properties.preset, undefined);
|
|
159
|
+
assert.equal(pageTheme.properties.palette, undefined);
|
|
160
|
+
assert.equal(pageTheme.properties.typography, undefined);
|
|
146
161
|
|
|
147
162
|
const content = JSON.parse(await readFile(path.join(root, 'schemas', 'content-frontmatter.schema.json'), 'utf8'));
|
|
148
163
|
assert.deepEqual(Object.keys(content.properties), ['page', 'navigation']);
|