@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
|
@@ -50,7 +50,7 @@ const createTempSite = async ({ underRepoCache = false } = {}) => {
|
|
|
50
50
|
await mkdir(tempParent, { recursive: true });
|
|
51
51
|
const root = await mkdtemp(path.join(tempParent, 'norna-content-model-v2-'));
|
|
52
52
|
const siteDir = path.join(root, 'site');
|
|
53
|
-
await mkdir(siteDir, { recursive: true });
|
|
53
|
+
await mkdir(path.join(siteDir, 'pages', '000-home'), { recursive: true });
|
|
54
54
|
await writeFile(path.join(siteDir, 'config.yaml'), 'url: https://example.com/\n');
|
|
55
55
|
await writeFile(path.join(siteDir, 'theme.yaml'), `typography:
|
|
56
56
|
profile: reading
|
|
@@ -109,7 +109,7 @@ test('content model v2 fixture checks and builds', async () => {
|
|
|
109
109
|
await runNorna(['--site-dir', siteDir, 'build']);
|
|
110
110
|
|
|
111
111
|
const manifest = JSON.parse(await readFile(path.join(siteDir, '.norna', 'generated-images.json'), 'utf8'));
|
|
112
|
-
assert.ok(manifest['images/duplicate.jpg']);
|
|
112
|
+
assert.ok(manifest['pages/000-home/images/duplicate.jpg']);
|
|
113
113
|
assert.ok(manifest['pages/010-guide/images/duplicate.jpg']);
|
|
114
114
|
|
|
115
115
|
const homepageHtml = await readFile(path.join(path.dirname(siteDir), 'dist', 'index.html'), 'utf8');
|
|
@@ -121,11 +121,31 @@ test('content model v2 fixture checks and builds', async () => {
|
|
|
121
121
|
}
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
-
test('the removed
|
|
124
|
+
test('the removed root page structure is rejected with a migration hint', async () => {
|
|
125
125
|
const { root, siteDir } = await createTempSite();
|
|
126
126
|
try {
|
|
127
127
|
await writeFile(path.join(siteDir, 'content.md'), `# Home
|
|
128
128
|
Home content.
|
|
129
|
+
`);
|
|
130
|
+
|
|
131
|
+
await assert.rejects(
|
|
132
|
+
runNorna(['--site-dir', siteDir, 'content:check']),
|
|
133
|
+
(error) => {
|
|
134
|
+
assert.match(error.output, /The old root-page structure is no longer supported: site\/content\.md\./);
|
|
135
|
+
assert.match(error.output, /Move the homepage content to site\/pages\/000-home\/content\.md/);
|
|
136
|
+
return true;
|
|
137
|
+
},
|
|
138
|
+
);
|
|
139
|
+
} finally {
|
|
140
|
+
await rm(root, { recursive: true, force: true });
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('the removed routes directory is rejected with a page migration hint', async () => {
|
|
145
|
+
const { root, siteDir } = await createTempSite();
|
|
146
|
+
try {
|
|
147
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `# Home
|
|
148
|
+
Home content.
|
|
129
149
|
`);
|
|
130
150
|
await mkdir(path.join(siteDir, 'routes', '010-guide'), { recursive: true });
|
|
131
151
|
await writeFile(path.join(siteDir, 'routes', '010-guide', 'content.md'), 'Old page content.\n');
|
|
@@ -142,14 +162,41 @@ Home content.
|
|
|
142
162
|
}
|
|
143
163
|
});
|
|
144
164
|
|
|
145
|
-
test('
|
|
165
|
+
test('the required home page cannot own child pages', async () => {
|
|
166
|
+
const { root, siteDir } = await createTempSite();
|
|
167
|
+
try {
|
|
168
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `# Home
|
|
169
|
+
|
|
170
|
+
## Welcome {#welcome}
|
|
171
|
+
|
|
172
|
+
Home content.
|
|
173
|
+
`);
|
|
174
|
+
const homeChildDir = path.join(siteDir, 'pages', '000-home', 'pages', '010-news');
|
|
175
|
+
await mkdir(homeChildDir, { recursive: true });
|
|
176
|
+
await writeFile(path.join(homeChildDir, 'content.md'), '# News\n\nNews content.\n');
|
|
177
|
+
|
|
178
|
+
await assert.rejects(
|
|
179
|
+
runNorna(['--site-dir', siteDir, 'content:check']),
|
|
180
|
+
(error) => {
|
|
181
|
+
assert.match(error.output, /site\/pages\/000-home is the homepage and cannot contain child pages\./);
|
|
182
|
+
assert.match(error.output, /Move these page directories beside 000-home under site\/pages\//);
|
|
183
|
+
assert.match(error.output, /site\/pages\/000-home\/pages\/010-news/);
|
|
184
|
+
return true;
|
|
185
|
+
},
|
|
186
|
+
);
|
|
187
|
+
} finally {
|
|
188
|
+
await rm(root, { recursive: true, force: true });
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test('page theme changes page presentation while preserving site visual identity', async () => {
|
|
146
193
|
const { root, siteDir } = await createTempSite({ underRepoCache: true });
|
|
147
194
|
try {
|
|
148
|
-
await writeFile(path.join(siteDir, 'theme.yaml'), `
|
|
149
|
-
|
|
195
|
+
await writeFile(path.join(siteDir, 'theme.yaml'), `preset: documentation
|
|
196
|
+
palette: dark
|
|
150
197
|
`);
|
|
151
198
|
await mkdir(path.join(siteDir, 'pages', '010-guide'), { recursive: true });
|
|
152
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
199
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
153
200
|
page:
|
|
154
201
|
description: Root page
|
|
155
202
|
---
|
|
@@ -168,16 +215,33 @@ page:
|
|
|
168
215
|
# Guide
|
|
169
216
|
Page content.
|
|
170
217
|
`);
|
|
171
|
-
await
|
|
172
|
-
|
|
173
|
-
|
|
218
|
+
await mkdir(path.join(siteDir, 'pages', '010-guide', 'pages', '010-detail'), { recursive: true });
|
|
219
|
+
await writeFile(path.join(siteDir, 'pages', '010-guide', 'pages', '010-detail', 'content.md'), `# Detail
|
|
220
|
+
|
|
221
|
+
Inherited page content.
|
|
222
|
+
`);
|
|
223
|
+
await writeFile(path.join(siteDir, 'pages', '010-guide', 'theme.yaml'), `layout:
|
|
224
|
+
contentSpacing: spacious
|
|
225
|
+
textWidth: wide
|
|
226
|
+
sections:
|
|
227
|
+
backgroundPattern: cycling
|
|
228
|
+
`);
|
|
229
|
+
await writeFile(path.join(siteDir, 'pages', '010-guide', 'pages', '010-detail', 'theme.yaml'), `layout:
|
|
230
|
+
textWidth: narrow
|
|
174
231
|
`);
|
|
175
232
|
|
|
176
233
|
await runNorna(['--site-dir', siteDir, 'build']);
|
|
177
234
|
const rootHtml = await readFile(path.join(path.dirname(siteDir), 'dist', 'index.html'), 'utf8');
|
|
178
235
|
const pageHtml = await readFile(path.join(path.dirname(siteDir), 'dist', 'guide', 'index.html'), 'utf8');
|
|
236
|
+
const detailHtml = await readFile(path.join(path.dirname(siteDir), 'dist', 'guide', 'detail', 'index.html'), 'utf8');
|
|
179
237
|
assert.match(rootHtml, /--color-page: #000000/);
|
|
180
|
-
assert.match(pageHtml, /--color-page: #
|
|
238
|
+
assert.match(pageHtml, /--color-page: #000000/);
|
|
239
|
+
assert.match(rootHtml, /--font-sans: Georgia, 'Times New Roman', serif/);
|
|
240
|
+
assert.match(pageHtml, /--font-sans: Georgia, 'Times New Roman', serif/);
|
|
241
|
+
assert.match(pageHtml, /--space-section-to-section-desktop: clamp\(2\.25rem, 5vw, 4\.5rem\)/);
|
|
242
|
+
assert.match(pageHtml, /--section-body-width-desktop: min\(72ch,/);
|
|
243
|
+
assert.match(detailHtml, /--space-section-to-section-desktop: clamp\(2\.25rem, 5vw, 4\.5rem\)/);
|
|
244
|
+
assert.match(detailHtml, /--section-body-width-desktop: min\(60ch,/);
|
|
181
245
|
assert.match(pageHtml, /<a href="\/">\s*Root\s*<\/a>/);
|
|
182
246
|
} finally {
|
|
183
247
|
await rm(root, { recursive: true, force: true });
|
|
@@ -192,7 +256,7 @@ test('page metadata, navigation logo, and page listing have separate roles', asy
|
|
|
192
256
|
await writeFile(path.join(siteDir, 'sitewide-content.yaml'), `logo:
|
|
193
257
|
height: 2rem
|
|
194
258
|
`);
|
|
195
|
-
await writeFile(path.join(siteDir, 'content.md'), `# Welcome
|
|
259
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `# Welcome
|
|
196
260
|
|
|
197
261
|
## Intro {#intro}
|
|
198
262
|
|
|
@@ -243,7 +307,7 @@ test('footer build information uses the site language and fixed formatting', asy
|
|
|
243
307
|
await writeFile(path.join(siteDir, 'sitewide-content.yaml'), `footer:
|
|
244
308
|
buildInfo: true
|
|
245
309
|
`);
|
|
246
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
310
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
247
311
|
page:
|
|
248
312
|
description: Footer build information.
|
|
249
313
|
---
|
|
@@ -267,7 +331,7 @@ test('page theme cannot define navigation logo settings', async () => {
|
|
|
267
331
|
const { root, siteDir } = await createTempSite({ underRepoCache: true });
|
|
268
332
|
try {
|
|
269
333
|
await mkdir(path.join(siteDir, 'pages', '010-guide'), { recursive: true });
|
|
270
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
334
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
271
335
|
page:
|
|
272
336
|
description: Root page
|
|
273
337
|
---
|
|
@@ -346,7 +410,7 @@ test('multiple conventional navigation logo files stop config validation', async
|
|
|
346
410
|
test('content:check warns for local Markdown images but not external Markdown images', async () => {
|
|
347
411
|
const { root, siteDir } = await createTempSite();
|
|
348
412
|
try {
|
|
349
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
413
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
350
414
|
page:
|
|
351
415
|
description: Fixture
|
|
352
416
|
---
|
|
@@ -374,7 +438,7 @@ page:
|
|
|
374
438
|
test('managed SVG images are copied as static image output', async () => {
|
|
375
439
|
const { root, siteDir } = await createTempSite();
|
|
376
440
|
try {
|
|
377
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
441
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
378
442
|
page:
|
|
379
443
|
description: Fixture
|
|
380
444
|
---
|
|
@@ -388,18 +452,18 @@ page:
|
|
|
388
452
|
alt: Diagram
|
|
389
453
|
\`\`\`
|
|
390
454
|
`);
|
|
391
|
-
await mkdir(path.join(siteDir, 'images'), { recursive: true });
|
|
392
|
-
await writeFile(path.join(siteDir, 'images', 'diagram.svg'), '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 620"><rect width="900" height="620"/></svg>\n');
|
|
455
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images'), { recursive: true });
|
|
456
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'images', 'diagram.svg'), '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 620"><rect width="900" height="620"/></svg>\n');
|
|
393
457
|
|
|
394
458
|
await runContentScript(siteDir, ['--check']);
|
|
395
459
|
await runNorna(['--site-dir', siteDir, 'images']);
|
|
396
460
|
|
|
397
461
|
const manifest = JSON.parse(await readFile(path.join(siteDir, '.norna', 'generated-images.json'), 'utf8'));
|
|
398
|
-
const entry = manifest['images/diagram.svg'];
|
|
462
|
+
const entry = manifest['pages/000-home/images/diagram.svg'];
|
|
399
463
|
assert.equal(entry.kind, 'static');
|
|
400
464
|
assert.equal(entry.width, 900);
|
|
401
465
|
assert.equal(entry.height, 620);
|
|
402
|
-
assert.match(entry.src, /^\/images\/original\/images\/diagram-[a-f0-9]{8}\.svg$/);
|
|
466
|
+
assert.match(entry.src, /^\/images\/original\/pages\/000-home\/images\/diagram-[a-f0-9]{8}\.svg$/);
|
|
403
467
|
assert.equal(entry.variants, undefined);
|
|
404
468
|
assert.equal(await fileExists(path.join(siteDir, '.norna', 'public', entry.src.replace(/^\//, ''))), true);
|
|
405
469
|
} finally {
|
|
@@ -410,7 +474,7 @@ page:
|
|
|
410
474
|
test('inline notes render as linked numbered margin notes', async () => {
|
|
411
475
|
const { root, siteDir } = await createTempSite({ underRepoCache: true });
|
|
412
476
|
try {
|
|
413
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
477
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
414
478
|
page:
|
|
415
479
|
description: Fixture
|
|
416
480
|
---
|
|
@@ -450,7 +514,7 @@ The second paragraph has its own explanation.{note-ref}
|
|
|
450
514
|
test('updated managed SVG images get updated static output', async () => {
|
|
451
515
|
const { root, siteDir } = await createTempSite();
|
|
452
516
|
try {
|
|
453
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
517
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
454
518
|
page:
|
|
455
519
|
description: Fixture
|
|
456
520
|
---
|
|
@@ -464,22 +528,22 @@ page:
|
|
|
464
528
|
alt: Diagram
|
|
465
529
|
\`\`\`
|
|
466
530
|
`);
|
|
467
|
-
await mkdir(path.join(siteDir, 'images'), { recursive: true });
|
|
468
|
-
const sourcePath = path.join(siteDir, 'images', 'diagram.svg');
|
|
531
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images'), { recursive: true });
|
|
532
|
+
const sourcePath = path.join(siteDir, 'pages', '000-home', 'images', 'diagram.svg');
|
|
469
533
|
await writeFile(sourcePath, '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 620"><rect width="900" height="620" fill="red"/></svg>\n');
|
|
470
534
|
|
|
471
535
|
await runContentScript(siteDir, ['--check']);
|
|
472
536
|
await runNorna(['--site-dir', siteDir, 'images']);
|
|
473
537
|
|
|
474
538
|
const firstManifest = JSON.parse(await readFile(path.join(siteDir, '.norna', 'generated-images.json'), 'utf8'));
|
|
475
|
-
const firstEntry = firstManifest['images/diagram.svg'];
|
|
539
|
+
const firstEntry = firstManifest['pages/000-home/images/diagram.svg'];
|
|
476
540
|
const firstOutputPath = path.join(siteDir, '.norna', 'public', firstEntry.src.replace(/^\//, ''));
|
|
477
541
|
|
|
478
542
|
await writeFile(sourcePath, '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 620"><rect width="900" height="620" fill="blue"/></svg>\n');
|
|
479
543
|
await runNorna(['--site-dir', siteDir, 'images']);
|
|
480
544
|
|
|
481
545
|
const secondManifest = JSON.parse(await readFile(path.join(siteDir, '.norna', 'generated-images.json'), 'utf8'));
|
|
482
|
-
const secondEntry = secondManifest['images/diagram.svg'];
|
|
546
|
+
const secondEntry = secondManifest['pages/000-home/images/diagram.svg'];
|
|
483
547
|
const secondOutputPath = path.join(siteDir, '.norna', 'public', secondEntry.src.replace(/^\//, ''));
|
|
484
548
|
|
|
485
549
|
assert.notEqual(secondEntry.sourceHash, firstEntry.sourceHash);
|
|
@@ -494,7 +558,7 @@ page:
|
|
|
494
558
|
test('content:check warns when carousel SVG images have no intrinsic aspect ratio', async () => {
|
|
495
559
|
const { root, siteDir } = await createTempSite();
|
|
496
560
|
try {
|
|
497
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
561
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
498
562
|
page:
|
|
499
563
|
description: Fixture
|
|
500
564
|
---
|
|
@@ -510,9 +574,9 @@ page:
|
|
|
510
574
|
alt: Second
|
|
511
575
|
\`\`\`
|
|
512
576
|
`);
|
|
513
|
-
await mkdir(path.join(siteDir, 'images'), { recursive: true });
|
|
514
|
-
await writeFile(path.join(siteDir, 'images', 'first.svg'), '<svg xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100"/></svg>\n');
|
|
515
|
-
await writeFile(path.join(siteDir, 'images', 'second.svg'), '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect width="100" height="100"/></svg>\n');
|
|
577
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images'), { recursive: true });
|
|
578
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'images', 'first.svg'), '<svg xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100"/></svg>\n');
|
|
579
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'images', 'second.svg'), '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect width="100" height="100"/></svg>\n');
|
|
516
580
|
|
|
517
581
|
const { stdout } = await runContentScript(siteDir, ['--check']);
|
|
518
582
|
assert.match(stdout, /Content check completed with warnings\./);
|
|
@@ -525,7 +589,7 @@ page:
|
|
|
525
589
|
test('norna-card-list images are managed image references', async () => {
|
|
526
590
|
const { root, siteDir } = await createTempSite({ underRepoCache: true });
|
|
527
591
|
try {
|
|
528
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
592
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
529
593
|
page:
|
|
530
594
|
description: Fixture
|
|
531
595
|
---
|
|
@@ -549,15 +613,15 @@ width: narrow
|
|
|
549
613
|
text: Support the shelter.
|
|
550
614
|
\`\`\`
|
|
551
615
|
`);
|
|
552
|
-
await mkdir(path.join(siteDir, 'images'), { recursive: true });
|
|
553
|
-
await writeFile(path.join(siteDir, 'images', 'adopt.svg'), '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100"><rect width="160" height="100"/></svg>\n');
|
|
616
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images'), { recursive: true });
|
|
617
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'images', 'adopt.svg'), '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100"><rect width="160" height="100"/></svg>\n');
|
|
554
618
|
|
|
555
619
|
const { stdout } = await runContentScript(siteDir, ['--check']);
|
|
556
620
|
assert.match(stdout, /Content check passed\./);
|
|
557
621
|
|
|
558
622
|
await runNorna(['--site-dir', siteDir, 'images']);
|
|
559
623
|
const manifest = JSON.parse(await readFile(path.join(siteDir, '.norna', 'generated-images.json'), 'utf8'));
|
|
560
|
-
assert.equal(manifest['images/adopt.svg'].kind, 'static');
|
|
624
|
+
assert.equal(manifest['pages/000-home/images/adopt.svg'].kind, 'static');
|
|
561
625
|
|
|
562
626
|
await runNorna(['--site-dir', siteDir, 'build']);
|
|
563
627
|
const html = await readFile(path.join(root, 'dist', 'index.html'), 'utf8');
|
|
@@ -569,7 +633,7 @@ width: narrow
|
|
|
569
633
|
assert.match(html, /class="card-list-badge">Recommended<\/p>/);
|
|
570
634
|
assert.match(html, /Give a dog a new home\./);
|
|
571
635
|
assert.match(html, /href="\/adopt\/"/);
|
|
572
|
-
assert.match(html, /src="\/images\/original\/images\/adopt-[a-f0-9]{8}\.svg"/);
|
|
636
|
+
assert.match(html, /src="\/images\/original\/pages\/000-home\/images\/adopt-[a-f0-9]{8}\.svg"/);
|
|
573
637
|
} finally {
|
|
574
638
|
await rm(root, { recursive: true, force: true });
|
|
575
639
|
}
|
|
@@ -578,7 +642,7 @@ width: narrow
|
|
|
578
642
|
test('content:check fails when a norna-card-list image file is missing', async () => {
|
|
579
643
|
const { root, siteDir } = await createTempSite();
|
|
580
644
|
try {
|
|
581
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
645
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
582
646
|
page:
|
|
583
647
|
description: Fixture
|
|
584
648
|
---
|
|
@@ -596,7 +660,7 @@ page:
|
|
|
596
660
|
await assert.rejects(
|
|
597
661
|
() => runContentScript(siteDir, ['--check']),
|
|
598
662
|
(error) => {
|
|
599
|
-
assert.match(error.output, /Image "missing\.svg" does not exist at .*site\/images\/missing\.svg or anywhere under any page image root\./);
|
|
663
|
+
assert.match(error.output, /Image "missing\.svg" does not exist at .*site\/pages\/000-home\/images\/missing\.svg or anywhere under any page image root\./);
|
|
600
664
|
return true;
|
|
601
665
|
},
|
|
602
666
|
);
|
|
@@ -608,7 +672,7 @@ page:
|
|
|
608
672
|
test('content:check fails for malformed norna-card-list blocks', async () => {
|
|
609
673
|
const { root, siteDir } = await createTempSite();
|
|
610
674
|
try {
|
|
611
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
675
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
612
676
|
page:
|
|
613
677
|
description: Fixture
|
|
614
678
|
---
|
|
@@ -637,7 +701,7 @@ page:
|
|
|
637
701
|
test('content:check fails for invalid norna-card-list options', async () => {
|
|
638
702
|
const { root, siteDir } = await createTempSite();
|
|
639
703
|
try {
|
|
640
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
704
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
641
705
|
page:
|
|
642
706
|
description: Fixture
|
|
643
707
|
---
|
|
@@ -672,7 +736,7 @@ width: full
|
|
|
672
736
|
test('content:check fails for invalid norna-card-list width', async () => {
|
|
673
737
|
const { root, siteDir } = await createTempSite();
|
|
674
738
|
try {
|
|
675
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
739
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
676
740
|
page:
|
|
677
741
|
description: Fixture
|
|
678
742
|
---
|
|
@@ -704,7 +768,7 @@ width: full
|
|
|
704
768
|
test('content:check fails for invalid norna-card-list size', async () => {
|
|
705
769
|
const { root, siteDir } = await createTempSite();
|
|
706
770
|
try {
|
|
707
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
771
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
708
772
|
page:
|
|
709
773
|
description: Fixture
|
|
710
774
|
---
|
|
@@ -736,7 +800,7 @@ size: huge
|
|
|
736
800
|
test('content:sync moves Norna-managed images inside the same page image root', async () => {
|
|
737
801
|
const { root, siteDir } = await createTempSite();
|
|
738
802
|
try {
|
|
739
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
803
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
740
804
|
page:
|
|
741
805
|
description: Fixture
|
|
742
806
|
---
|
|
@@ -750,12 +814,12 @@ page:
|
|
|
750
814
|
alt: Moved image
|
|
751
815
|
\`\`\`
|
|
752
816
|
`);
|
|
753
|
-
await mkdir(path.join(siteDir, 'images', 'old'), { recursive: true });
|
|
754
|
-
await writeFile(path.join(siteDir, 'images', 'old', 'moved.jpg'), 'fixture image');
|
|
817
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images', 'old'), { recursive: true });
|
|
818
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'images', 'old', 'moved.jpg'), 'fixture image');
|
|
755
819
|
|
|
756
820
|
await runContentScript(siteDir, ['--write', '--yes']);
|
|
757
821
|
|
|
758
|
-
const moved = await readFile(path.join(siteDir, 'images', 'moved.jpg'), 'utf8');
|
|
822
|
+
const moved = await readFile(path.join(siteDir, 'pages', '000-home', 'images', 'moved.jpg'), 'utf8');
|
|
759
823
|
assert.equal(moved, 'fixture image');
|
|
760
824
|
} finally {
|
|
761
825
|
await rm(root, { recursive: true, force: true });
|
|
@@ -765,7 +829,7 @@ page:
|
|
|
765
829
|
test('content:sync moves managed SVG images inside the same page image root', async () => {
|
|
766
830
|
const { root, siteDir } = await createTempSite();
|
|
767
831
|
try {
|
|
768
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
832
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
769
833
|
page:
|
|
770
834
|
description: Fixture
|
|
771
835
|
---
|
|
@@ -779,12 +843,12 @@ page:
|
|
|
779
843
|
alt: Moved diagram
|
|
780
844
|
\`\`\`
|
|
781
845
|
`);
|
|
782
|
-
await mkdir(path.join(siteDir, 'images', 'old'), { recursive: true });
|
|
783
|
-
await writeFile(path.join(siteDir, 'images', 'old', 'moved.svg'), '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"></svg>\n');
|
|
846
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images', 'old'), { recursive: true });
|
|
847
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'images', 'old', 'moved.svg'), '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"></svg>\n');
|
|
784
848
|
|
|
785
849
|
await runContentScript(siteDir, ['--write', '--yes']);
|
|
786
850
|
|
|
787
|
-
const moved = await readFile(path.join(siteDir, 'images', 'moved.svg'), 'utf8');
|
|
851
|
+
const moved = await readFile(path.join(siteDir, 'pages', '000-home', 'images', 'moved.svg'), 'utf8');
|
|
788
852
|
assert.match(moved, /viewBox="0 0 10 10"/);
|
|
789
853
|
} finally {
|
|
790
854
|
await rm(root, { recursive: true, force: true });
|
|
@@ -798,7 +862,7 @@ test('content:sync moves Norna-managed images across page image roots when git i
|
|
|
798
862
|
const targetPageDir = path.join(siteDir, 'pages', '020-target');
|
|
799
863
|
await mkdir(path.join(sourcePageDir, 'images'), { recursive: true });
|
|
800
864
|
await mkdir(targetPageDir, { recursive: true });
|
|
801
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
865
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
802
866
|
page:
|
|
803
867
|
description: Fixture
|
|
804
868
|
---
|
|
@@ -852,7 +916,7 @@ test('content:sync refuses cross-page image moves when git status is dirty', asy
|
|
|
852
916
|
const targetPageDir = path.join(siteDir, 'pages', '020-target');
|
|
853
917
|
await mkdir(path.join(sourcePageDir, 'images'), { recursive: true });
|
|
854
918
|
await mkdir(targetPageDir, { recursive: true });
|
|
855
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
919
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
856
920
|
page:
|
|
857
921
|
description: Fixture
|
|
858
922
|
---
|
|
@@ -914,7 +978,7 @@ test('content:check reports cross-page image moves without requiring clean git s
|
|
|
914
978
|
const targetPageDir = path.join(siteDir, 'pages', '020-target');
|
|
915
979
|
await mkdir(path.join(sourcePageDir, 'images'), { recursive: true });
|
|
916
980
|
await mkdir(targetPageDir, { recursive: true });
|
|
917
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
981
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
918
982
|
page:
|
|
919
983
|
description: Fixture
|
|
920
984
|
---
|
|
@@ -973,7 +1037,7 @@ test('content:sync refuses to move a cross-page image still referenced by its cu
|
|
|
973
1037
|
const targetPageDir = path.join(siteDir, 'pages', '020-target');
|
|
974
1038
|
await mkdir(path.join(sourcePageDir, 'images'), { recursive: true });
|
|
975
1039
|
await mkdir(targetPageDir, { recursive: true });
|
|
976
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1040
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
977
1041
|
page:
|
|
978
1042
|
description: Fixture
|
|
979
1043
|
---
|
|
@@ -1031,7 +1095,7 @@ page:
|
|
|
1031
1095
|
test('CLI content:sync refreshes generated images after moving a carousel image', async () => {
|
|
1032
1096
|
const { root, siteDir } = await createTempSite();
|
|
1033
1097
|
try {
|
|
1034
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1098
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1035
1099
|
page:
|
|
1036
1100
|
description: Fixture
|
|
1037
1101
|
---
|
|
@@ -1047,16 +1111,16 @@ page:
|
|
|
1047
1111
|
alt: Slide two
|
|
1048
1112
|
\`\`\`
|
|
1049
1113
|
`);
|
|
1050
|
-
await mkdir(path.join(siteDir, 'images', 'old'), { recursive: true });
|
|
1051
|
-
await cp(path.join(fixtureSiteDir, 'images', 'hero.jpg'), path.join(siteDir, 'images', 'old', 'slide-one.jpg'));
|
|
1052
|
-
await cp(path.join(fixtureSiteDir, 'images', 'detail.jpg'), path.join(siteDir, 'images', 'slide-two.jpg'), { force: true });
|
|
1114
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images', 'old'), { recursive: true });
|
|
1115
|
+
await cp(path.join(fixtureSiteDir, 'pages', '000-home', 'images', 'hero.jpg'), path.join(siteDir, 'pages', '000-home', 'images', 'old', 'slide-one.jpg'));
|
|
1116
|
+
await cp(path.join(fixtureSiteDir, 'pages', '000-home', 'images', 'detail.jpg'), path.join(siteDir, 'pages', '000-home', 'images', 'slide-two.jpg'), { force: true });
|
|
1053
1117
|
|
|
1054
1118
|
await runNorna(['--site-dir', siteDir, 'content:sync', '--yes']);
|
|
1055
1119
|
|
|
1056
1120
|
const manifest = JSON.parse(await readFile(path.join(siteDir, '.norna', 'generated-images.json'), 'utf8'));
|
|
1057
|
-
assert.equal(await fileExists(path.join(siteDir, 'images', 'slide-one.jpg')), true);
|
|
1058
|
-
assert.ok(manifest['images/slide-one.jpg']);
|
|
1059
|
-
assert.ok(manifest['images/slide-two.jpg']);
|
|
1121
|
+
assert.equal(await fileExists(path.join(siteDir, 'pages', '000-home', 'images', 'slide-one.jpg')), true);
|
|
1122
|
+
assert.ok(manifest['pages/000-home/images/slide-one.jpg']);
|
|
1123
|
+
assert.ok(manifest['pages/000-home/images/slide-two.jpg']);
|
|
1060
1124
|
} finally {
|
|
1061
1125
|
await rm(root, { recursive: true, force: true });
|
|
1062
1126
|
}
|
|
@@ -1065,7 +1129,7 @@ page:
|
|
|
1065
1129
|
test('automatic H2 and H3 ids render while explicit ids remain stable', async () => {
|
|
1066
1130
|
const { root, siteDir } = await createTempSite({ underRepoCache: true });
|
|
1067
1131
|
try {
|
|
1068
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1132
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1069
1133
|
page:
|
|
1070
1134
|
description: Fixture
|
|
1071
1135
|
---
|
|
@@ -1098,7 +1162,7 @@ Explicit identifier.
|
|
|
1098
1162
|
test('content:check fails for malformed Norna image blocks', async () => {
|
|
1099
1163
|
const { root, siteDir } = await createTempSite();
|
|
1100
1164
|
try {
|
|
1101
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1165
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1102
1166
|
page:
|
|
1103
1167
|
description: Fixture
|
|
1104
1168
|
---
|
|
@@ -1128,9 +1192,9 @@ image hero.jpg
|
|
|
1128
1192
|
test('content:check fails for unknown Norna block names', async () => {
|
|
1129
1193
|
const { root, siteDir } = await createTempSite();
|
|
1130
1194
|
try {
|
|
1131
|
-
await mkdir(path.join(siteDir, 'images', 'plain'), { recursive: true });
|
|
1132
|
-
await writeFile(path.join(siteDir, 'images', 'plain', 'image.jpg'), 'fixture image');
|
|
1133
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1195
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images', 'plain'), { recursive: true });
|
|
1196
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'images', 'plain', 'image.jpg'), 'fixture image');
|
|
1197
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1134
1198
|
page:
|
|
1135
1199
|
description: Fixture
|
|
1136
1200
|
---
|
|
@@ -1161,7 +1225,7 @@ page:
|
|
|
1161
1225
|
test('content:check rejects the removed norna-note block', async () => {
|
|
1162
1226
|
const { root, siteDir } = await createTempSite();
|
|
1163
1227
|
try {
|
|
1164
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1228
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1165
1229
|
page:
|
|
1166
1230
|
description: Fixture
|
|
1167
1231
|
---
|
|
@@ -1190,9 +1254,9 @@ This block is no longer supported.
|
|
|
1190
1254
|
test('content:check supports tilde fenced Norna blocks', async () => {
|
|
1191
1255
|
const { root, siteDir } = await createTempSite();
|
|
1192
1256
|
try {
|
|
1193
|
-
await mkdir(path.join(siteDir, 'images'), { recursive: true });
|
|
1194
|
-
await writeFile(path.join(siteDir, 'images', 'hero.jpg'), 'fixture image');
|
|
1195
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1257
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images'), { recursive: true });
|
|
1258
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'images', 'hero.jpg'), 'fixture image');
|
|
1259
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1196
1260
|
page:
|
|
1197
1261
|
description: Fixture
|
|
1198
1262
|
---
|
|
@@ -1216,7 +1280,7 @@ page:
|
|
|
1216
1280
|
test('content:check ignores Norna blocks shown inside longer code fences', async () => {
|
|
1217
1281
|
const { root, siteDir } = await createTempSite();
|
|
1218
1282
|
try {
|
|
1219
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1283
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1220
1284
|
page:
|
|
1221
1285
|
description: Fixture
|
|
1222
1286
|
---
|
|
@@ -1242,7 +1306,7 @@ page:
|
|
|
1242
1306
|
test('content:check fails for likely Norna block names outside fences', async () => {
|
|
1243
1307
|
const { root, siteDir } = await createTempSite();
|
|
1244
1308
|
try {
|
|
1245
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1309
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1246
1310
|
page:
|
|
1247
1311
|
description: Fixture
|
|
1248
1312
|
---
|
|
@@ -1271,7 +1335,7 @@ norna-image-stack
|
|
|
1271
1335
|
test('content:check fails for short Norna block fences', async () => {
|
|
1272
1336
|
const { root, siteDir } = await createTempSite();
|
|
1273
1337
|
try {
|
|
1274
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1338
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1275
1339
|
page:
|
|
1276
1340
|
description: Fixture
|
|
1277
1341
|
---
|
|
@@ -1301,7 +1365,7 @@ page:
|
|
|
1301
1365
|
test('content:check fails for unclosed Norna blocks', async () => {
|
|
1302
1366
|
const { root, siteDir } = await createTempSite();
|
|
1303
1367
|
try {
|
|
1304
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1368
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1305
1369
|
page:
|
|
1306
1370
|
description: Fixture
|
|
1307
1371
|
---
|
|
@@ -1331,7 +1395,7 @@ page:
|
|
|
1331
1395
|
test('content:check continues after malformed Norna blocks', async () => {
|
|
1332
1396
|
const { root, siteDir } = await createTempSite();
|
|
1333
1397
|
try {
|
|
1334
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1398
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1335
1399
|
page:
|
|
1336
1400
|
description: Fixture
|
|
1337
1401
|
---
|
|
@@ -1362,8 +1426,8 @@ image broken.jpg
|
|
|
1362
1426
|
() => runContentScript(siteDir, ['--check']),
|
|
1363
1427
|
(error) => {
|
|
1364
1428
|
assert.match(error.output, /Invalid norna-image-stack entry "image broken\.jpg"\. Start each image with "- image: filename\.jpg"\./);
|
|
1365
|
-
assert.match(error.output, /Image "missing-intro\.jpg" does not exist at .*site\/images\/missing-intro\.jpg or anywhere under any page image root\./);
|
|
1366
|
-
assert.match(error.output, /Image "missing-more\.jpg" does not exist at .*site\/images\/missing-more\.jpg or anywhere under any page image root\./);
|
|
1429
|
+
assert.match(error.output, /Image "missing-intro\.jpg" does not exist at .*site\/pages\/000-home\/images\/missing-intro\.jpg or anywhere under any page image root\./);
|
|
1430
|
+
assert.match(error.output, /Image "missing-more\.jpg" does not exist at .*site\/pages\/000-home\/images\/missing-more\.jpg or anywhere under any page image root\./);
|
|
1367
1431
|
return true;
|
|
1368
1432
|
},
|
|
1369
1433
|
);
|
|
@@ -1375,9 +1439,9 @@ image broken.jpg
|
|
|
1375
1439
|
test('content:check allows Norna images without alt text', async () => {
|
|
1376
1440
|
const { root, siteDir } = await createTempSite();
|
|
1377
1441
|
try {
|
|
1378
|
-
await mkdir(path.join(siteDir, 'images'), { recursive: true });
|
|
1379
|
-
await writeFile(path.join(siteDir, 'images', 'hero.jpg'), 'fixture image');
|
|
1380
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1442
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images'), { recursive: true });
|
|
1443
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'images', 'hero.jpg'), 'fixture image');
|
|
1444
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1381
1445
|
page:
|
|
1382
1446
|
description: Fixture
|
|
1383
1447
|
---
|
|
@@ -1401,7 +1465,7 @@ page:
|
|
|
1401
1465
|
test('content:check reports single-image carousel and missing file together', async () => {
|
|
1402
1466
|
const { root, siteDir } = await createTempSite();
|
|
1403
1467
|
try {
|
|
1404
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1468
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1405
1469
|
page:
|
|
1406
1470
|
description: Fixture
|
|
1407
1471
|
---
|
|
@@ -1419,7 +1483,7 @@ page:
|
|
|
1419
1483
|
() => runContentScript(siteDir, ['--check']),
|
|
1420
1484
|
(error) => {
|
|
1421
1485
|
assert.match(error.output, /norna-image-carousel on line \d+ contains 1 image\. A carousel needs at least two images\./);
|
|
1422
|
-
assert.match(error.output, /Image "foo\.jpg" does not exist at .*site\/images\/foo\.jpg or anywhere under any page image root\./);
|
|
1486
|
+
assert.match(error.output, /Image "foo\.jpg" does not exist at .*site\/pages\/000-home\/images\/foo\.jpg or anywhere under any page image root\./);
|
|
1423
1487
|
return true;
|
|
1424
1488
|
},
|
|
1425
1489
|
);
|
|
@@ -1431,7 +1495,7 @@ page:
|
|
|
1431
1495
|
test('content:check fails when a Norna-managed image file is missing', async () => {
|
|
1432
1496
|
const { root, siteDir } = await createTempSite();
|
|
1433
1497
|
try {
|
|
1434
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1498
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1435
1499
|
page:
|
|
1436
1500
|
description: Fixture
|
|
1437
1501
|
---
|
|
@@ -1449,7 +1513,7 @@ page:
|
|
|
1449
1513
|
await assert.rejects(
|
|
1450
1514
|
() => runContentScript(siteDir, ['--check']),
|
|
1451
1515
|
(error) => {
|
|
1452
|
-
assert.match(error.output, /Image "missing\.jpg" does not exist at .*site\/images\/missing\.jpg or anywhere under any page image root\./);
|
|
1516
|
+
assert.match(error.output, /Image "missing\.jpg" does not exist at .*site\/pages\/000-home\/images\/missing\.jpg or anywhere under any page image root\./);
|
|
1453
1517
|
return true;
|
|
1454
1518
|
},
|
|
1455
1519
|
);
|
|
@@ -1461,7 +1525,7 @@ page:
|
|
|
1461
1525
|
test('content:check fails when a page repeats a section id', async () => {
|
|
1462
1526
|
const { root, siteDir } = await createTempSite();
|
|
1463
1527
|
try {
|
|
1464
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1528
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1465
1529
|
page:
|
|
1466
1530
|
description: Fixture
|
|
1467
1531
|
---
|
|
@@ -1492,7 +1556,7 @@ Second.
|
|
|
1492
1556
|
test('content:check reports collisions between automatic H2 and H3 ids', async () => {
|
|
1493
1557
|
const { root, siteDir } = await createTempSite();
|
|
1494
1558
|
try {
|
|
1495
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1559
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1496
1560
|
page:
|
|
1497
1561
|
description: Fixture
|
|
1498
1562
|
---
|
|
@@ -1525,7 +1589,7 @@ Topic text.
|
|
|
1525
1589
|
test('content:check rejects removed sections frontmatter', async () => {
|
|
1526
1590
|
const { root, siteDir } = await createTempSite();
|
|
1527
1591
|
try {
|
|
1528
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1592
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1529
1593
|
page:
|
|
1530
1594
|
description: Fixture
|
|
1531
1595
|
sections:
|
|
@@ -1554,7 +1618,7 @@ Text.
|
|
|
1554
1618
|
test('content:sync refuses ambiguous image relocation', async () => {
|
|
1555
1619
|
const { root, siteDir } = await createTempSite();
|
|
1556
1620
|
try {
|
|
1557
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1621
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1558
1622
|
page:
|
|
1559
1623
|
description: Fixture
|
|
1560
1624
|
---
|
|
@@ -1568,24 +1632,24 @@ page:
|
|
|
1568
1632
|
alt: Shared
|
|
1569
1633
|
\`\`\`
|
|
1570
1634
|
`);
|
|
1571
|
-
await mkdir(path.join(siteDir, 'images', 'old-a'), { recursive: true });
|
|
1572
|
-
await mkdir(path.join(siteDir, 'images', 'old-b'), { recursive: true });
|
|
1573
|
-
await writeFile(path.join(siteDir, 'images', 'old-a', 'shared.jpg'), 'a');
|
|
1574
|
-
await writeFile(path.join(siteDir, 'images', 'old-b', 'shared.jpg'), 'b');
|
|
1635
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images', 'old-a'), { recursive: true });
|
|
1636
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images', 'old-b'), { recursive: true });
|
|
1637
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'images', 'old-a', 'shared.jpg'), 'a');
|
|
1638
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'images', 'old-b', 'shared.jpg'), 'b');
|
|
1575
1639
|
|
|
1576
1640
|
await assert.rejects(
|
|
1577
1641
|
() => runContentScript(siteDir, ['--write', '--yes']),
|
|
1578
1642
|
(error) => {
|
|
1579
1643
|
assert.match(error.output, /Cannot relocate "shared\.jpg"\. Multiple files with this filename were found:/);
|
|
1580
|
-
assert.match(error.output, /site\/images\/old-a\/shared\.jpg/);
|
|
1581
|
-
assert.match(error.output, /site\/images\/old-b\/shared\.jpg/);
|
|
1644
|
+
assert.match(error.output, /site\/pages\/000-home\/images\/old-a\/shared\.jpg/);
|
|
1645
|
+
assert.match(error.output, /site\/pages\/000-home\/images\/old-b\/shared\.jpg/);
|
|
1582
1646
|
return true;
|
|
1583
1647
|
},
|
|
1584
1648
|
);
|
|
1585
1649
|
|
|
1586
|
-
assert.equal(await fileExists(path.join(siteDir, 'images', 'shared.jpg')), false);
|
|
1587
|
-
assert.equal(await fileExists(path.join(siteDir, 'images', 'old-a', 'shared.jpg')), true);
|
|
1588
|
-
assert.equal(await fileExists(path.join(siteDir, 'images', 'old-b', 'shared.jpg')), true);
|
|
1650
|
+
assert.equal(await fileExists(path.join(siteDir, 'pages', '000-home', 'images', 'shared.jpg')), false);
|
|
1651
|
+
assert.equal(await fileExists(path.join(siteDir, 'pages', '000-home', 'images', 'old-a', 'shared.jpg')), true);
|
|
1652
|
+
assert.equal(await fileExists(path.join(siteDir, 'pages', '000-home', 'images', 'old-b', 'shared.jpg')), true);
|
|
1589
1653
|
} finally {
|
|
1590
1654
|
await rm(root, { recursive: true, force: true });
|
|
1591
1655
|
}
|
|
@@ -1594,7 +1658,7 @@ page:
|
|
|
1594
1658
|
test('content:sync moves one page-local image once when multiple sections reference it', async () => {
|
|
1595
1659
|
const { root, siteDir } = await createTempSite();
|
|
1596
1660
|
try {
|
|
1597
|
-
await writeFile(path.join(siteDir, 'content.md'), `---
|
|
1661
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'content.md'), `---
|
|
1598
1662
|
page:
|
|
1599
1663
|
description: Fixture
|
|
1600
1664
|
---
|
|
@@ -1615,13 +1679,13 @@ page:
|
|
|
1615
1679
|
alt: Shared copy
|
|
1616
1680
|
\`\`\`
|
|
1617
1681
|
`);
|
|
1618
|
-
await mkdir(path.join(siteDir, 'images', 'intro'), { recursive: true });
|
|
1619
|
-
await writeFile(path.join(siteDir, 'images', 'intro', 'shared.jpg'), 'shared image');
|
|
1682
|
+
await mkdir(path.join(siteDir, 'pages', '000-home', 'images', 'intro'), { recursive: true });
|
|
1683
|
+
await writeFile(path.join(siteDir, 'pages', '000-home', 'images', 'intro', 'shared.jpg'), 'shared image');
|
|
1620
1684
|
|
|
1621
1685
|
await runContentScript(siteDir, ['--write', '--yes']);
|
|
1622
1686
|
|
|
1623
|
-
assert.equal(await fileExists(path.join(siteDir, 'images', 'intro', 'shared.jpg')), false);
|
|
1624
|
-
assert.equal(await fileExists(path.join(siteDir, 'images', 'shared.jpg')), true);
|
|
1687
|
+
assert.equal(await fileExists(path.join(siteDir, 'pages', '000-home', 'images', 'intro', 'shared.jpg')), false);
|
|
1688
|
+
assert.equal(await fileExists(path.join(siteDir, 'pages', '000-home', 'images', 'shared.jpg')), true);
|
|
1625
1689
|
await runContentScript(siteDir, ['--check']);
|
|
1626
1690
|
} finally {
|
|
1627
1691
|
await rm(root, { recursive: true, force: true });
|