@janga/norna 0.7.16 → 0.7.17
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 +6 -6
- package/astro.config.mjs +35 -3
- package/docs/README.md +10 -10
- package/docs/commands.md +2 -2
- package/docs/content.md +82 -102
- package/docs/design/navigation-and-theme-plan.md +115 -0
- package/docs/design/norna-diagram-design.md +9 -9
- package/docs/design/site-examples-structure.md +9 -9
- package/docs/engine-development.md +9 -9
- package/docs/getting-started.md +20 -15
- package/docs/images-and-metadata.md +10 -9
- package/docs/pages.md +134 -0
- package/docs/public-files.md +49 -36
- package/docs/publishing.md +19 -3
- package/docs/site-files.md +29 -28
- package/docs/sitewide-content.md +20 -36
- package/docs/theme.md +20 -20
- package/docs/typography.md +10 -10
- package/examples/README.md +2 -2
- package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/site.schema.json +17 -41
- package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/sitewide.schema.json +26 -67
- package/examples/complete-sites/dog-shelter-multi-page/.astro/collections/theme.schema.json +185 -88
- package/examples/complete-sites/dog-shelter-multi-page/.astro/data-store.json +1 -1
- package/examples/complete-sites/dog-shelter-multi-page/.astro/dev-local.json +4 -4
- package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.json +5 -5
- package/examples/complete-sites/dog-shelter-multi-page/.astro/dev.log +33 -23
- package/examples/complete-sites/dog-shelter-multi-page/README.md +1 -1
- package/examples/complete-sites/dog-shelter-multi-page/node_modules/.vite/deps/_metadata.json +8 -8
- package/examples/complete-sites/dog-shelter-multi-page/site/.norna/generated-images.json +20 -20
- package/examples/complete-sites/dog-shelter-multi-page/site/content.md +3 -4
- package/examples/complete-sites/dog-shelter-multi-page/site/{routes → pages}/010-dogs/content.md +3 -4
- package/examples/complete-sites/dog-shelter-multi-page/site/{routes → pages}/020-adopt/content.md +3 -4
- package/examples/complete-sites/dog-shelter-multi-page/site/sitewide-content.yaml +2 -4
- package/examples/complete-sites/dog-shelter-single-page/.astro/collections/site.schema.json +17 -41
- package/examples/complete-sites/dog-shelter-single-page/.astro/collections/sitewide.schema.json +26 -67
- package/examples/complete-sites/dog-shelter-single-page/.astro/collections/theme.schema.json +185 -88
- package/examples/complete-sites/dog-shelter-single-page/.astro/data-store.json +1 -1
- package/examples/complete-sites/dog-shelter-single-page/.astro/dev-local.json +8 -0
- package/examples/complete-sites/dog-shelter-single-page/.astro/dev.json +5 -5
- package/examples/complete-sites/dog-shelter-single-page/.astro/dev.log +16 -12
- package/examples/complete-sites/dog-shelter-single-page/README.md +1 -1
- package/examples/complete-sites/dog-shelter-single-page/node_modules/.vite/deps/_metadata.json +8 -8
- package/examples/complete-sites/dog-shelter-single-page/site/.norna/generated-images.json +12 -12
- package/examples/complete-sites/dog-shelter-single-page/site/content.md +5 -2
- package/examples/complete-sites/dog-shelter-single-page/site/sitewide-content.yaml +2 -4
- package/examples/feature-demos/media-and-surfaces/.astro/collections/site.schema.json +17 -41
- package/examples/feature-demos/media-and-surfaces/.astro/collections/sitewide.schema.json +26 -67
- package/examples/feature-demos/media-and-surfaces/.astro/collections/theme.schema.json +185 -88
- package/examples/feature-demos/media-and-surfaces/.astro/data-store.json +1 -1
- package/examples/feature-demos/media-and-surfaces/.astro/dev.log +4 -14
- package/examples/feature-demos/media-and-surfaces/README.md +2 -2
- package/examples/feature-demos/media-and-surfaces/node_modules/.vite/deps/_metadata.json +9 -9
- package/examples/feature-demos/media-and-surfaces/site/.norna/generated-images.json +16 -16
- package/examples/feature-demos/media-and-surfaces/site/content.md +4 -7
- package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/010-media/content.md +6 -5
- package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/020-surfaces/content.md +7 -6
- package/examples/feature-demos/media-and-surfaces/site/sitewide-content.yaml +0 -2
- package/examples/feature-demos/sitewide-content/README.md +3 -3
- package/examples/feature-demos/sitewide-content/site/content.md +8 -7
- package/examples/feature-demos/sitewide-content/site/pages/010-logo-and-navigation/content.md +17 -0
- package/examples/feature-demos/sitewide-content/site/{routes → pages}/020-notices/content.md +7 -6
- package/examples/feature-demos/sitewide-content/site/{routes → pages}/030-footer/content.md +6 -5
- package/examples/feature-demos/sitewide-content/site/sitewide-content.yaml +4 -13
- package/examples/feature-demos/theme-presets/README.md +1 -1
- package/examples/feature-demos/theme-presets/site/.norna/generated-images.json +60 -60
- package/examples/feature-demos/theme-presets/site/content.md +4 -7
- package/examples/feature-demos/theme-presets/site/{routes → pages}/010-portfolio/content.md +4 -7
- package/examples/feature-demos/theme-presets/site/{routes → pages}/020-documentation/content.md +4 -7
- package/examples/feature-demos/theme-presets/site/{routes → pages}/030-project/content.md +4 -7
- package/examples/feature-demos/theme-presets/site/{routes → pages}/040-statement/content.md +4 -7
- package/examples/feature-demos/theme-presets/site/sitewide-content.yaml +1 -10
- package/fixtures/basic/site/content.md +5 -6
- package/fixtures/basic/site/sitewide-content.yaml +1 -8
- package/fixtures/content-model-v2/site/content.md +11 -13
- package/fixtures/content-model-v2/site/pages/010-guide/content.md +18 -0
- package/fixtures/nested-pages/site/.norna/generated-images.json +10 -0
- package/fixtures/nested-pages/site/config.yaml +1 -0
- package/fixtures/nested-pages/site/content.md +15 -0
- package/fixtures/nested-pages/site/pages/010-guides/content.md +15 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/content.md +21 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/images/diagram.svg +21 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/010-installation/pages/010-macos/content.md +14 -0
- package/fixtures/nested-pages/site/pages/010-guides/pages/020-workflows/content.md +11 -0
- package/fixtures/nested-pages/site/pages/010-guides/theme.yaml +3 -0
- package/fixtures/nested-pages/site/pages/020-reference/content.md +10 -0
- package/fixtures/nested-pages/site/pages/020-reference/pages/010-installation/content.md +11 -0
- package/fixtures/nested-pages/site/theme.yaml +3 -0
- package/package.json +7 -4
- package/schemas/config.schema.json +5 -5
- package/schemas/content-frontmatter.schema.json +28 -63
- package/schemas/manifest.json +1 -0
- package/schemas/sitewide-content.schema.json +58 -132
- package/schemas/theme.schema.json +396 -86
- package/scripts/check-config.mjs +6 -5
- package/scripts/deploy-site.mjs +6 -8
- package/scripts/doctor.mjs +2 -2
- package/scripts/generate-images.mjs +11 -18
- package/scripts/generate-schemas.mjs +3 -217
- package/scripts/lib/base-path-redirect.mjs +9 -0
- package/scripts/lib/editor-language-service.mjs +126 -66
- package/scripts/lib/heading-ids.mjs +161 -0
- package/scripts/lib/navigation-model.mjs +51 -0
- package/scripts/lib/norna-markdown-blocks.mjs +3 -4
- package/scripts/lib/page-model.mjs +83 -0
- package/scripts/lib/project-config.mjs +28 -0
- package/scripts/lib/schema-definitions.mjs +41 -46
- package/scripts/lib/schema-editor-metadata.mjs +475 -0
- package/scripts/lib/schema-value-definitions.mjs +6 -6
- package/scripts/lib/site-content.mjs +124 -87
- package/scripts/lib/site-paths.mjs +2 -2
- package/scripts/lib/theme-config.mjs +9 -16
- package/scripts/lib/theme-presets.mjs +9 -1
- package/scripts/release.mjs +1 -1
- package/scripts/show-typography.mjs +26 -20
- package/scripts/sync-content-sections.mjs +106 -65
- package/scripts/{test-temporary-visibility.mjs → test-banner-visibility.mjs} +7 -24
- package/scripts/test-client-javascript.mjs +39 -42
- package/scripts/test-content-check.mjs +138 -54
- package/scripts/test-content-model-v2.mjs +445 -228
- package/scripts/test-documentation.mjs +6 -1
- package/scripts/test-editor-language-service.mjs +168 -24
- package/scripts/test-engine-commands.mjs +2 -1
- package/scripts/test-heading-ids.mjs +68 -0
- package/scripts/test-navigation-model.mjs +63 -0
- package/scripts/test-nested-pages.mjs +110 -0
- package/scripts/test-package-check.mjs +31 -40
- package/scripts/test-page-model.mjs +80 -0
- package/scripts/test-project-config.mjs +25 -1
- package/scripts/test-schemas.mjs +66 -14
- package/scripts/test-theme-presets.mjs +33 -24
- package/src/components/NavigationPageTree.astro +68 -0
- package/src/components/SectionNavigationScript.astro +110 -5
- package/src/components/SiteBreadcrumbs.astro +29 -0
- package/src/components/SiteNavigation.astro +65 -69
- package/src/components/SitePage.astro +70 -46
- package/src/components/SiteSection.astro +27 -20
- package/src/content.config.ts +9 -5
- package/src/layouts/BaseLayout.astro +11 -20
- package/src/lib/pageThemes.ts +42 -0
- package/src/lib/sectionContent.ts +109 -106
- package/src/lib/siteNavigation.ts +48 -0
- package/src/lib/sitePages.ts +85 -38
- package/src/pages/{[slug].astro → [...slug].astro} +2 -2
- package/src/styles/global.css +373 -55
- package/starters/basic/README.md +5 -7
- package/starters/basic/site/content.md +7 -4
- package/starters/basic/site/sitewide-content.yaml +1 -10
- package/starters/project/README.md +8 -8
- package/starters/project/site/content.md +5 -4
- package/starters/project/site/{routes → pages}/010-guide/content.md +5 -4
- package/starters/project/site/sitewide-content.yaml +1 -10
- package/docs/routes.md +0 -121
- package/examples/feature-demos/sitewide-content/site/routes/010-identity/content.md +0 -20
- package/fixtures/content-model-v2/site/routes/010-guide/content.md +0 -17
- package/scripts/lib/route-model.mjs +0 -17
- package/scripts/test-route-model.mjs +0 -32
- package/src/lib/routeThemes.ts +0 -41
- /package/examples/complete-sites/dog-shelter-multi-page/site/images/{intro/shelter-dog.jpg → shelter-dog.jpg} +0 -0
- /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/010-dogs/images/dogs → pages/010-dogs/images}/rex.jpg +0 -0
- /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/010-dogs/images/dogs → pages/010-dogs/images}/rover.jpg +0 -0
- /package/examples/complete-sites/dog-shelter-multi-page/site/{routes/020-adopt/images/adopt → pages/020-adopt/images}/adoption-dog.jpg +0 -0
- /package/examples/complete-sites/dog-shelter-single-page/site/images/{you-can-help/foster-dog.jpg → foster-dog.jpg} +0 -0
- /package/examples/complete-sites/dog-shelter-single-page/site/images/{what-we-do/rescue-dog.jpg → rescue-dog.jpg} +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-carousel.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-stack.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/cards → pages/010-media/images}/card-surfaces.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-one.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-three.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/carousel → pages/010-media/images}/carousel-two.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/stack → pages/010-media/images}/stack-one.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes/010-media/images/stack → pages/010-media/images}/stack-two.svg +0 -0
- /package/examples/feature-demos/media-and-surfaces/site/{routes → pages}/020-surfaces/theme.yaml +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes/010-portfolio/images/portfolio → pages/010-portfolio/images}/puppy-portrait.jpg +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes/010-portfolio/images/portfolio → pages/010-portfolio/images}/shepherd-portrait.jpg +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes/010-portfolio/images/portfolio → pages/010-portfolio/images}/white-puppy.jpg +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes → pages}/010-portfolio/theme.yaml +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes/020-documentation/images/documentation → pages/020-documentation/images}/black-schnauzer.jpg +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes/020-documentation/images/documentation → pages/020-documentation/images}/retriever-portrait.jpg +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes/020-documentation/images/documentation → pages/020-documentation/images}/schnauzer-portrait.jpg +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes → pages}/020-documentation/theme.yaml +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes/030-project/images/project → pages/030-project/images}/boxer-portrait.jpg +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes/030-project/images/project → pages/030-project/images}/grass-puppy.jpg +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes/030-project/images/project → pages/030-project/images}/grey-street-dog.jpg +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes → pages}/030-project/theme.yaml +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes/040-statement/images/statement → pages/040-statement/images}/black-pedigree.jpg +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes/040-statement/images/statement → pages/040-statement/images}/sheepdog-grass.jpg +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes/040-statement/images/statement → pages/040-statement/images}/sheepdog-wide.jpg +0 -0
- /package/examples/feature-demos/theme-presets/site/{routes → pages}/040-statement/theme.yaml +0 -0
- /package/fixtures/basic/site/images/{work/.gitkeep → .gitkeep} +0 -0
- /package/fixtures/content-model-v2/site/images/{card-section/adopt.svg → adopt.svg} +0 -0
- /package/fixtures/content-model-v2/site/images/{intro/detail.jpg → detail.jpg} +0 -0
- /package/fixtures/content-model-v2/site/images/{intro/duplicate.jpg → duplicate.jpg} +0 -0
- /package/fixtures/content-model-v2/site/images/{card-section/foster.svg → foster.svg} +0 -0
- /package/fixtures/content-model-v2/site/images/{intro/hero.jpg → hero.jpg} +0 -0
- /package/fixtures/content-model-v2/site/images/{plain/image.jpg → image.jpg} +0 -0
- /package/fixtures/content-model-v2/site/images/{timed/slide-one.jpg → slide-one.jpg} +0 -0
- /package/fixtures/content-model-v2/site/images/{timed/slide-three.jpg → slide-three.jpg} +0 -0
- /package/fixtures/content-model-v2/site/images/{timed/slide-two.jpg → slide-two.jpg} +0 -0
- /package/fixtures/content-model-v2/site/{routes/010-guide/images/intro → pages/010-guide/images}/duplicate.jpg +0 -0
- /package/starters/basic/site/images/{work/.gitkeep → .gitkeep} +0 -0
package/src/lib/sitePages.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CollectionEntry } from 'astro:content';
|
|
2
|
-
import {
|
|
2
|
+
import { decodePageDirectoryPath, parsePageDirectoryPath } from '../../scripts/lib/page-model.mjs';
|
|
3
3
|
|
|
4
4
|
type SiteEntry = CollectionEntry<'site'>;
|
|
5
5
|
|
|
@@ -7,64 +7,109 @@ export type SitePage = {
|
|
|
7
7
|
entry: SiteEntry;
|
|
8
8
|
isHome: boolean;
|
|
9
9
|
navigation: {
|
|
10
|
-
|
|
11
|
-
label: string;
|
|
10
|
+
listed: boolean;
|
|
12
11
|
order: number;
|
|
13
12
|
};
|
|
13
|
+
depth: number;
|
|
14
|
+
pageDirectories: string[];
|
|
14
15
|
pathSegment: string;
|
|
15
16
|
pathname: string;
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
pageDirectory: string | null;
|
|
18
|
+
pageId: string;
|
|
19
|
+
pageIds: string[];
|
|
20
|
+
pageOrders: number[];
|
|
21
|
+
pagePath: string;
|
|
22
|
+
parentPagePath: string | null;
|
|
18
23
|
title: string;
|
|
19
24
|
};
|
|
20
25
|
|
|
21
|
-
const
|
|
26
|
+
const pageIdMarker = '-page-';
|
|
22
27
|
|
|
23
|
-
const
|
|
24
|
-
const markerIndex = id.
|
|
25
|
-
|
|
28
|
+
const stripPageIdPrefix = (id: string) => {
|
|
29
|
+
const markerIndex = id.lastIndexOf(pageIdMarker);
|
|
30
|
+
if (markerIndex === -1) return null;
|
|
31
|
+
|
|
32
|
+
const candidate = id.slice(markerIndex + pageIdMarker.length);
|
|
33
|
+
try {
|
|
34
|
+
return parsePageDirectoryPath(decodePageDirectoryPath(candidate)).pageDirectory;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
26
38
|
};
|
|
27
39
|
|
|
28
|
-
export const isHomePageEntry = (entry: SiteEntry) =>
|
|
40
|
+
export const isHomePageEntry = (entry: SiteEntry) => stripPageIdPrefix(entry.id) === null;
|
|
29
41
|
|
|
30
|
-
const
|
|
42
|
+
const getPageDirectory = (entry: SiteEntry) => isHomePageEntry(entry) ? null : stripPageIdPrefix(entry.id);
|
|
31
43
|
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
return
|
|
44
|
+
const getPageMetadata = (entry: SiteEntry) => {
|
|
45
|
+
const pageDirectory = getPageDirectory(entry);
|
|
46
|
+
return pageDirectory ? parsePageDirectoryPath(pageDirectory, `page directory ${pageDirectory}`) : null;
|
|
35
47
|
};
|
|
36
48
|
|
|
37
49
|
const getPagePathname = (pathSegment: string) => pathSegment ? `/${pathSegment}/` : '/';
|
|
38
50
|
|
|
51
|
+
const compareNumberPaths = (left: number[], right: number[]) => {
|
|
52
|
+
const sharedLength = Math.min(left.length, right.length);
|
|
53
|
+
for (let index = 0; index < sharedLength; index += 1) {
|
|
54
|
+
const difference = left[index] - right[index];
|
|
55
|
+
if (difference !== 0) return difference;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return left.length - right.length;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const decodeHtmlEntities = (value: string) => value
|
|
62
|
+
.replace(/&/g, '&')
|
|
63
|
+
.replace(/</g, '<')
|
|
64
|
+
.replace(/>/g, '>')
|
|
65
|
+
.replace(/"/g, '"')
|
|
66
|
+
.replace(/'/g, "'");
|
|
67
|
+
|
|
68
|
+
const getPageTitle = (entry: SiteEntry) => {
|
|
69
|
+
const html = entry.rendered?.html ?? '';
|
|
70
|
+
const headings = Array.from(html.matchAll(/<h1\b[^>]*>([\s\S]*?)<\/h1>/gi));
|
|
71
|
+
if (headings.length !== 1) {
|
|
72
|
+
throw new Error(`Page entry "${entry.id}" must contain exactly one Markdown H1 page title.`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return decodeHtmlEntities((headings[0]?.[1] ?? '').replace(/<[^>]*>/g, '')).trim();
|
|
76
|
+
};
|
|
77
|
+
|
|
39
78
|
export const getSitePage = (entry: SiteEntry): SitePage => {
|
|
40
79
|
const isHome = isHomePageEntry(entry);
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const
|
|
80
|
+
const pageMetadata = getPageMetadata(entry);
|
|
81
|
+
const pageDirectory = pageMetadata?.pageDirectory ?? null;
|
|
82
|
+
const pageId = pageMetadata?.pageId ?? '';
|
|
83
|
+
const pagePath = pageMetadata?.pagePath ?? '';
|
|
84
|
+
const pathSegment = isHome ? '' : pagePath;
|
|
45
85
|
const navigation = entry.data.navigation ?? {};
|
|
46
86
|
|
|
47
87
|
return {
|
|
48
88
|
entry,
|
|
49
89
|
isHome,
|
|
90
|
+
depth: pageMetadata?.depth ?? 0,
|
|
50
91
|
navigation: {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
order: isHome ? 0 : routeMetadata?.routeOrder ?? 100,
|
|
92
|
+
listed: navigation.listed ?? true,
|
|
93
|
+
order: isHome ? 0 : pageMetadata?.pageOrder ?? 100,
|
|
54
94
|
},
|
|
55
95
|
pathSegment,
|
|
56
96
|
pathname: getPagePathname(pathSegment),
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
97
|
+
pageDirectory,
|
|
98
|
+
pageDirectories: pageMetadata?.pageDirectories ?? [],
|
|
99
|
+
pageId,
|
|
100
|
+
pageIds: pageMetadata?.pageIds ?? [],
|
|
101
|
+
pageOrders: pageMetadata?.pageOrders ?? [],
|
|
102
|
+
pagePath,
|
|
103
|
+
parentPagePath: pageMetadata?.parentPagePath ?? null,
|
|
104
|
+
title: getPageTitle(entry),
|
|
60
105
|
};
|
|
61
106
|
};
|
|
62
107
|
|
|
63
108
|
export const getSitePages = (entries: SiteEntry[]) => {
|
|
64
109
|
const pages = entries.map(getSitePage);
|
|
65
110
|
const pathnames = new Map<string, SitePage>();
|
|
66
|
-
const
|
|
67
|
-
const
|
|
111
|
+
const siblingPageIds = new Map<string, SitePage>();
|
|
112
|
+
const siblingPageOrders = new Map<string, SitePage>();
|
|
68
113
|
|
|
69
114
|
for (const page of pages) {
|
|
70
115
|
const existing = pathnames.get(page.pathname);
|
|
@@ -76,26 +121,28 @@ export const getSitePages = (entries: SiteEntry[]) => {
|
|
|
76
121
|
|
|
77
122
|
if (page.isHome) continue;
|
|
78
123
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
124
|
+
const siblingScope = page.parentPagePath ?? '';
|
|
125
|
+
const pageIdKey = `${siblingScope}\0${page.pageId}`;
|
|
126
|
+
const existingPageId = siblingPageIds.get(pageIdKey);
|
|
127
|
+
if (existingPageId) {
|
|
128
|
+
throw new Error(`Duplicate sibling page id "${page.pageId}" below "${page.parentPagePath ?? '/'}" from "${existingPageId.entry.id}" and "${page.entry.id}".`);
|
|
82
129
|
}
|
|
83
130
|
|
|
84
|
-
|
|
131
|
+
siblingPageIds.set(pageIdKey, page);
|
|
85
132
|
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
133
|
+
const pageOrderKey = `${siblingScope}\0${page.navigation.order}`;
|
|
134
|
+
const existingPageOrder = siblingPageOrders.get(pageOrderKey);
|
|
135
|
+
if (existingPageOrder) {
|
|
136
|
+
throw new Error(`Duplicate sibling page order "${String(page.navigation.order).padStart(3, '0')}" below "${page.parentPagePath ?? '/'}" from "${existingPageOrder.entry.id}" and "${page.entry.id}".`);
|
|
89
137
|
}
|
|
90
138
|
|
|
91
|
-
|
|
139
|
+
siblingPageOrders.set(pageOrderKey, page);
|
|
92
140
|
}
|
|
93
141
|
|
|
94
142
|
return pages.sort((left, right) => (
|
|
95
|
-
left.
|
|
96
|
-
left.
|
|
143
|
+
left.isHome ? -1 : right.isHome ? 1 :
|
|
144
|
+
compareNumberPaths(left.pageOrders, right.pageOrders) ||
|
|
145
|
+
left.title.localeCompare(right.title, 'sv') ||
|
|
97
146
|
left.pathname.localeCompare(right.pathname, 'sv')
|
|
98
147
|
));
|
|
99
148
|
};
|
|
100
|
-
|
|
101
|
-
export const getNavigationPages = (pages: SitePage[]) => pages.filter((page) => page.navigation.include);
|
|
@@ -18,13 +18,13 @@ export async function getStaticPaths() {
|
|
|
18
18
|
const { entry } = Astro.props;
|
|
19
19
|
|
|
20
20
|
if (!entry || isHomePageEntry(entry)) {
|
|
21
|
-
throw new Error('
|
|
21
|
+
throw new Error('Page entry is missing.');
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
const currentPage = getSitePage(entry);
|
|
25
25
|
|
|
26
26
|
if (!currentPage.pathSegment) {
|
|
27
|
-
throw new Error(`
|
|
27
|
+
throw new Error(`Page "${entry.id}" needs a page id.`);
|
|
28
28
|
}
|
|
29
29
|
---
|
|
30
30
|
|