@janga/norna 0.7.25 → 0.7.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -10
- package/astro.config.mjs +26 -12
- package/bin/norna-cli.mjs +14 -2
- package/package.json +14 -5
- package/schemas/card-list.schema.json +121 -0
- package/schemas/category.schema.json +4 -4
- package/schemas/config.schema.json +306 -32
- package/schemas/content-frontmatter.schema.json +8 -8
- package/schemas/image-carousel.schema.json +43 -0
- package/schemas/image-stack.schema.json +43 -0
- package/schemas/manifest.json +6 -1
- package/schemas/page-theme.schema.json +26 -26
- package/schemas/sitewide-content.schema.json +18 -18
- package/schemas/theme.schema.json +237 -262
- package/scripts/add-site-node.mjs +1 -1
- package/scripts/dev-local.mjs +24 -2
- package/scripts/generate-schemas.mjs +15 -3
- package/scripts/lib/category-destinations.mjs +48 -0
- package/scripts/lib/code-fence-metadata.mjs +14 -37
- package/scripts/lib/content-tabs.mjs +155 -0
- package/scripts/lib/details-headings.mjs +58 -0
- package/scripts/lib/documentation-links.mjs +33 -2
- package/scripts/lib/documentation-routes.json +222 -0
- package/scripts/lib/docusaurus-migration-audit.mjs +603 -0
- package/scripts/lib/editor-language-service.mjs +238 -116
- package/scripts/lib/locale-registry.mjs +597 -0
- package/scripts/lib/locales/az-Latn.mjs +78 -0
- package/scripts/lib/locales/be.mjs +78 -0
- package/scripts/lib/locales/bg.mjs +78 -0
- package/scripts/lib/locales/bs.mjs +78 -0
- package/scripts/lib/locales/ca.mjs +78 -0
- package/scripts/lib/locales/cnr.mjs +78 -0
- package/scripts/lib/locales/cs.mjs +78 -0
- package/scripts/lib/locales/da.mjs +78 -0
- package/scripts/lib/locales/de.mjs +78 -0
- package/scripts/lib/locales/el.mjs +78 -0
- package/scripts/lib/locales/en.mjs +78 -0
- package/scripts/lib/locales/es.mjs +78 -0
- package/scripts/lib/locales/et.mjs +78 -0
- package/scripts/lib/locales/fi.mjs +78 -0
- package/scripts/lib/locales/fil.mjs +78 -0
- package/scripts/lib/locales/fr.mjs +78 -0
- package/scripts/lib/locales/ga.mjs +78 -0
- package/scripts/lib/locales/ha.mjs +78 -0
- package/scripts/lib/locales/hr.mjs +78 -0
- package/scripts/lib/locales/hu.mjs +78 -0
- package/scripts/lib/locales/id.mjs +78 -0
- package/scripts/lib/locales/is.mjs +78 -0
- package/scripts/lib/locales/it.mjs +78 -0
- package/scripts/lib/locales/jv.mjs +78 -0
- package/scripts/lib/locales/lb.mjs +78 -0
- package/scripts/lib/locales/lt.mjs +78 -0
- package/scripts/lib/locales/lv.mjs +78 -0
- package/scripts/lib/locales/mk.mjs +78 -0
- package/scripts/lib/locales/mt.mjs +78 -0
- package/scripts/lib/locales/nb.mjs +78 -0
- package/scripts/lib/locales/nl.mjs +78 -0
- package/scripts/lib/locales/nn.mjs +78 -0
- package/scripts/lib/locales/pcm.mjs +78 -0
- package/scripts/lib/locales/pl.mjs +78 -0
- package/scripts/lib/locales/pt.mjs +78 -0
- package/scripts/lib/locales/ro.mjs +78 -0
- package/scripts/lib/locales/ru.mjs +78 -0
- package/scripts/lib/locales/sk.mjs +78 -0
- package/scripts/lib/locales/sl.mjs +78 -0
- package/scripts/lib/locales/sq.mjs +78 -0
- package/scripts/lib/locales/sr-Cyrl.mjs +78 -0
- package/scripts/lib/locales/sr-Latn.mjs +78 -0
- package/scripts/lib/locales/sv.mjs +78 -0
- package/scripts/lib/locales/sw.mjs +78 -0
- package/scripts/lib/locales/tr.mjs +78 -0
- package/scripts/lib/locales/uk.mjs +78 -0
- package/scripts/lib/locales/vi.mjs +78 -0
- package/scripts/lib/markdown-links.mjs +4 -25
- package/scripts/lib/markdown-notes-render-plugin.mjs +75 -0
- package/scripts/lib/markdown-notes.mjs +165 -0
- package/scripts/lib/norna-markdown-blocks.mjs +32 -447
- package/scripts/lib/norna-markdown-render-plugin.mjs +4 -0
- package/scripts/lib/page-aliases.mjs +12 -1
- package/scripts/lib/page-markdown.mjs +63 -16
- package/scripts/lib/page-model.mjs +22 -0
- package/scripts/lib/page-move-plan.mjs +22 -5
- package/scripts/lib/pagefind-translations.mjs +620 -0
- package/scripts/lib/presentation-contract.mjs +6 -1
- package/scripts/lib/presentation.mjs +29 -30
- package/scripts/lib/project-config.mjs +2 -173
- package/scripts/lib/schema-definitions.mjs +6 -13
- package/scripts/lib/schema-editor-metadata.mjs +23 -44
- package/scripts/lib/schema-value-definitions.mjs +4 -8
- package/scripts/lib/semantic-callouts.mjs +4 -2
- package/scripts/lib/site-content.mjs +4 -2
- package/scripts/lib/site-link-graph.mjs +16 -6
- package/scripts/lib/site-navigation-tree.mjs +0 -11
- package/scripts/lib/sitemap.mjs +5 -3
- package/scripts/lib/structured-blocks.mjs +108 -0
- package/scripts/lib/table-render-plugin.mjs +46 -3
- package/scripts/lib/table-row-headers.mjs +218 -0
- package/scripts/lib/theme-presets.mjs +3 -10
- package/scripts/lib/yaml-config.mjs +2 -6
- package/scripts/migrate-check.mjs +19 -0
- package/scripts/sync-content-sections.mjs +39 -10
- package/scripts/sync-site-public.mjs +7 -1
- package/src/components/CodeBlockCopyScript.astro +47 -5
- package/src/components/ContentBlocks.astro +39 -0
- package/src/components/ContentTabsScript.astro +60 -0
- package/src/components/DisplaySettings.astro +17 -19
- package/src/components/NavigationPageTree.astro +1 -1
- package/src/components/NoteNavigationScript.astro +4 -0
- package/src/components/PageAliasRedirect.astro +49 -7
- package/src/components/SearchNavigationScript.astro +4 -0
- package/src/components/SearchPage.astro +43 -2
- package/src/components/SectionNavigationScript.astro +43 -11
- package/src/components/SiteBreadcrumbs.astro +1 -1
- package/src/components/SiteNavigation.astro +29 -20
- package/src/components/SitePage.astro +40 -15
- package/src/components/SiteSection.astro +5 -81
- package/src/components/SiteTreeNavigation.astro +2 -2
- package/src/components/TableOverflowScript.astro +386 -58
- package/src/components/TopPageMenu.astro +47 -0
- package/src/components/TreeNavigationScript.astro +10 -3
- package/src/content.config.ts +5 -8
- package/src/layouts/BaseLayout.astro +8 -12
- package/src/lib/navigationFollowing.ts +142 -0
- package/src/lib/noteNavigation.ts +50 -0
- package/src/lib/searchNavigation.ts +107 -0
- package/src/lib/sectionContent.ts +20 -90
- package/src/lib/siteNavigation.ts +0 -5
- package/src/lib/sitePages.ts +17 -20
- package/src/lib/table-sort-tooltip.ts +109 -0
- package/src/pages/[...slug].astro +16 -6
- package/src/styles/content.css +397 -134
- package/src/styles/foundations.css +9 -0
- package/src/styles/media.css +5 -0
- package/src/styles/navigation.css +63 -74
- package/src/styles/page-layout.css +7 -0
- package/src/styles/responsive.css +2 -7
- package/starters/basic/README.md +1 -1
|
@@ -4,16 +4,17 @@ import projectConfig from '../../scripts/lib/project-config.mjs';
|
|
|
4
4
|
import { withBasePath } from '../lib/basePath';
|
|
5
5
|
import type { SectionNavigation } from '../lib/sectionContent';
|
|
6
6
|
import {
|
|
7
|
-
getFirstPageInNavigationNode,
|
|
8
7
|
getListedSiteNavigationTree,
|
|
9
8
|
type SiteNavigationEntry,
|
|
10
9
|
type SiteNavigationNode,
|
|
11
10
|
} from '../lib/siteNavigation';
|
|
12
|
-
import type { SiteNode
|
|
11
|
+
import type { SiteNode } from '../lib/sitePages';
|
|
13
12
|
import DisplaySettings from './DisplaySettings.astro';
|
|
14
13
|
import NavigationPageTree from './NavigationPageTree.astro';
|
|
15
14
|
import NavigationTreeControls from './NavigationTreeControls.astro';
|
|
15
|
+
import TopPageMenu from './TopPageMenu.astro';
|
|
16
16
|
import SectionNavigationScript from './SectionNavigationScript.astro';
|
|
17
|
+
import SearchNavigationScript from './SearchNavigationScript.astro';
|
|
17
18
|
|
|
18
19
|
type FrameColors = {
|
|
19
20
|
backgroundColor: string;
|
|
@@ -26,7 +27,7 @@ interface Props {
|
|
|
26
27
|
alt: string;
|
|
27
28
|
height?: string;
|
|
28
29
|
};
|
|
29
|
-
currentPage?:
|
|
30
|
+
currentPage?: SiteNode;
|
|
30
31
|
navigationEntries: SiteNavigationEntry[];
|
|
31
32
|
navigationMode: 'sections' | 'top' | 'tree';
|
|
32
33
|
showTopNavigationSubmenus: boolean;
|
|
@@ -67,6 +68,12 @@ const navigationStyle = [
|
|
|
67
68
|
...(logo?.height ? [`--site-brand-logo-height: ${logo.height}`] : []),
|
|
68
69
|
].join('; ');
|
|
69
70
|
const siteNavigationTree = getListedSiteNavigationTree(navigationEntries);
|
|
71
|
+
const mobileNavigationTree = navigationMode === 'top'
|
|
72
|
+
? getListedSiteNavigationTree(navigationEntries.map((entry) => ({
|
|
73
|
+
...entry,
|
|
74
|
+
headings: entry.headings.filter((heading) => heading.depth === 2),
|
|
75
|
+
})))
|
|
76
|
+
: siteNavigationTree;
|
|
70
77
|
const topLevelNavigation = siteNavigationTree;
|
|
71
78
|
const showSiteNavigation = topLevelNavigation.some(({ node }) => !node.isHome);
|
|
72
79
|
const homeNode = navigationEntries.find(({ node }) => node.isHome)?.node;
|
|
@@ -75,13 +82,13 @@ if (!homePage) throw new Error('Site navigation requires a homepage.');
|
|
|
75
82
|
const currentPageNavigation = currentPage
|
|
76
83
|
? navigationEntries.find(({ node }) => node.kind === 'page' && node.pathname === currentPage.pathname)
|
|
77
84
|
: undefined;
|
|
78
|
-
const isCurrentPage = (page:
|
|
85
|
+
const isCurrentPage = (page: SiteNode) => currentPage?.pathname === page.pathname;
|
|
79
86
|
const isCurrentBranch = (node: SiteNode) => Boolean(currentPage && (
|
|
80
87
|
currentPage.pageDirectory === node.pageDirectory
|
|
81
88
|
|| currentPage.pageDirectory.startsWith(`${node.pageDirectory}/pages/`)
|
|
82
89
|
));
|
|
83
|
-
const pageHref = (page:
|
|
84
|
-
const getNavigationPage = (node: SiteNavigationNode) =>
|
|
90
|
+
const pageHref = (page: SiteNode) => withBasePath(projectConfig.site.basePath, page.pathname);
|
|
91
|
+
const getNavigationPage = (node: SiteNavigationNode) => node.node;
|
|
85
92
|
const hasSectionMenu = (pageSections: SectionNavigation[]) => pageSections.length > 1;
|
|
86
93
|
const showSinglePageTopLink = !showSiteNavigation;
|
|
87
94
|
const currentPageSectionCount = currentPageNavigation?.sections.length ?? 0;
|
|
@@ -97,6 +104,7 @@ const hasTreePageContents = Boolean(
|
|
|
97
104
|
);
|
|
98
105
|
const showPageNavigation = Boolean(
|
|
99
106
|
navigationMode !== 'tree'
|
|
107
|
+
&& (navigationMode !== 'top' || showSinglePageTopLink)
|
|
100
108
|
&& currentPageNavigation
|
|
101
109
|
&& (showSinglePageTopLink || hasCurrentPageSectionMenu),
|
|
102
110
|
);
|
|
@@ -107,7 +115,7 @@ const showSearch = projectConfig.search.enabled;
|
|
|
107
115
|
const searchHref = withBasePath(projectConfig.site.basePath, '/search/');
|
|
108
116
|
const showDesktopNavigationRow = showSiteNavigation || Boolean(logo) || showReaderControls || showSearch;
|
|
109
117
|
const showNavigationRow = showMobileNavigation || showDesktopNavigationRow;
|
|
110
|
-
const needsNavigationScript =
|
|
118
|
+
const needsNavigationScript = showMobileNavigation || hasCurrentPageSectionMenu || hasTreePageContents;
|
|
111
119
|
---
|
|
112
120
|
|
|
113
121
|
<a class="skip-link" href="#main-content">{projectConfig.locale.labels.skipToContent}</a>
|
|
@@ -138,22 +146,20 @@ const needsNavigationScript = hasCurrentPageSectionMenu || hasTreePageContents |
|
|
|
138
146
|
{topLevelNavigation.map((navigationNode) => {
|
|
139
147
|
const destination = getNavigationPage(navigationNode);
|
|
140
148
|
if (!destination) return null;
|
|
141
|
-
const nodeIsCurrentPage =
|
|
149
|
+
const nodeIsCurrentPage = isCurrentPage(navigationNode.node);
|
|
142
150
|
return (
|
|
143
151
|
<li class:list={['site-nav-item', {
|
|
144
|
-
'site-nav-item-has-submenu': showTopNavigationSubmenus && navigationNode.children.length > 0,
|
|
145
152
|
'site-nav-item-current-branch': !nodeIsCurrentPage && isCurrentBranch(navigationNode.node),
|
|
146
153
|
}]}>
|
|
147
154
|
<a href={pageHref(destination)} aria-current={nodeIsCurrentPage ? 'page' : undefined}>
|
|
148
155
|
{navigationNode.node.title}
|
|
149
156
|
</a>
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
)}
|
|
157
|
+
<TopPageMenu
|
|
158
|
+
node={navigationNode}
|
|
159
|
+
currentPage={currentPage}
|
|
160
|
+
showSections={navigationMode === 'top'}
|
|
161
|
+
showChildren={showTopNavigationSubmenus}
|
|
162
|
+
/>
|
|
157
163
|
</li>
|
|
158
164
|
);
|
|
159
165
|
})}
|
|
@@ -165,6 +171,8 @@ const needsNavigationScript = hasCurrentPageSectionMenu || hasTreePageContents |
|
|
|
165
171
|
<a
|
|
166
172
|
class="site-search-link"
|
|
167
173
|
href={searchHref}
|
|
174
|
+
data-search-base={projectConfig.site.basePath}
|
|
175
|
+
data-search-source-title={currentPage?.title}
|
|
168
176
|
aria-current={searchPage ? 'page' : undefined}
|
|
169
177
|
aria-label={projectConfig.locale.labels.search}
|
|
170
178
|
title={projectConfig.locale.labels.search}
|
|
@@ -211,18 +219,18 @@ const needsNavigationScript = hasCurrentPageSectionMenu || hasTreePageContents |
|
|
|
211
219
|
<h2 tabindex="-1">{projectConfig.locale.labels.siteNavigation}</h2>
|
|
212
220
|
<NavigationTreeControls
|
|
213
221
|
idPrefix="mobile-tree-navigation"
|
|
214
|
-
nodes={
|
|
222
|
+
nodes={mobileNavigationTree}
|
|
215
223
|
/>
|
|
216
224
|
<NavigationPageTree
|
|
217
|
-
nodes={
|
|
225
|
+
nodes={mobileNavigationTree}
|
|
218
226
|
currentPage={currentPage}
|
|
219
227
|
variant="mobile"
|
|
220
|
-
integratePageSections={navigationMode === 'tree'}
|
|
228
|
+
integratePageSections={navigationMode === 'tree' || navigationMode === 'top'}
|
|
221
229
|
/>
|
|
222
230
|
</nav>
|
|
223
231
|
)}
|
|
224
232
|
|
|
225
|
-
{navigationMode
|
|
233
|
+
{(navigationMode === 'sections' || !showSiteNavigation) && hasCurrentPageSectionMenu && currentPageNavigation && currentPage && (
|
|
226
234
|
<nav class="mobile-nav-view" aria-label={projectConfig.locale.labels.pageNavigation}>
|
|
227
235
|
{!showSinglePageTopLink && (
|
|
228
236
|
<h2 tabindex="-1">{projectConfig.locale.labels.pageNavigation}</h2>
|
|
@@ -285,3 +293,4 @@ const needsNavigationScript = hasCurrentPageSectionMenu || hasTreePageContents |
|
|
|
285
293
|
</header>
|
|
286
294
|
|
|
287
295
|
{needsNavigationScript && <SectionNavigationScript />}
|
|
296
|
+
{showSearch && <SearchNavigationScript />}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { getCollection, type CollectionEntry } from 'astro:content';
|
|
3
3
|
import BaseLayout from '../layouts/BaseLayout.astro';
|
|
4
4
|
import CodeBlockCopyScript from './CodeBlockCopyScript.astro';
|
|
5
|
+
import ContentTabsScript from './ContentTabsScript.astro';
|
|
6
|
+
import NoteNavigationScript from './NoteNavigationScript.astro';
|
|
5
7
|
import EditSourceLink from './EditSourceLink.astro';
|
|
6
8
|
import ImageStackEnhancement from './ImageStackEnhancement.astro';
|
|
7
9
|
import SiteBreadcrumbs from './SiteBreadcrumbs.astro';
|
|
@@ -13,7 +15,7 @@ import SiteSection from './SiteSection.astro';
|
|
|
13
15
|
import SiteTreeNavigation from './SiteTreeNavigation.astro';
|
|
14
16
|
import TableOverflowScript from './TableOverflowScript.astro';
|
|
15
17
|
import TreeNavigationScript from './TreeNavigationScript.astro';
|
|
16
|
-
import { getSectionsContent, type ResolvedSection } from '../lib/sectionContent';
|
|
18
|
+
import { flattenContentBlocks, getSectionsContent, type ResolvedSection } from '../lib/sectionContent';
|
|
17
19
|
import { getPageTheme } from '../lib/pageThemes';
|
|
18
20
|
import { getSiteModel, type SitePage } from '../lib/sitePages';
|
|
19
21
|
import {
|
|
@@ -36,15 +38,18 @@ import { mergePageThemeConfig } from '../../scripts/lib/theme-presets.mjs';
|
|
|
36
38
|
type SiteEntry = CollectionEntry<'site'>;
|
|
37
39
|
|
|
38
40
|
interface Props {
|
|
39
|
-
entry
|
|
41
|
+
entry?: SiteEntry;
|
|
42
|
+
categoryPath?: string;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
const { entry } = Astro.props;
|
|
45
|
+
const { entry, categoryPath } = Astro.props;
|
|
43
46
|
const siteDirectory = (process.env.NORNA_SITE_DIR ?? 'site').trim();
|
|
44
47
|
const siteModel = await getSiteModel(await getCollection('site'));
|
|
45
48
|
const { nodes: siteNodes, pages: sitePages } = siteModel;
|
|
46
|
-
const
|
|
47
|
-
|
|
49
|
+
const categoryDestination = categoryPath ? siteModel.categoryDestinations.byPathname.get(categoryPath) : null;
|
|
50
|
+
const currentPage = categoryDestination?.category
|
|
51
|
+
?? sitePages.find((page) => page.entry.id === entry?.id);
|
|
52
|
+
if (!currentPage) throw new Error(`Page entry "${entry?.id ?? categoryPath}" is missing from the site page model.`);
|
|
48
53
|
const [siteTheme] = await getCollection('theme');
|
|
49
54
|
if (!siteTheme) {
|
|
50
55
|
throw new Error('site/theme.yaml is required. Add a root theme before building the site.');
|
|
@@ -93,17 +98,35 @@ const listedNavigationTree = getListedSiteNavigationTree(siteNavigation);
|
|
|
93
98
|
const renderedNavigationEntries = flattenSiteNavigationTree(listedNavigationTree);
|
|
94
99
|
const pageSequence = getSequentialPageNavigation(listedNavigationTree, currentPage.pagePath);
|
|
95
100
|
const childPages = getDirectChildPages(listedNavigationTree, currentPage.pagePath);
|
|
96
|
-
const siteHtml = entry
|
|
97
|
-
const resolvedSections =
|
|
98
|
-
|
|
101
|
+
const siteHtml = entry?.rendered?.html ?? '';
|
|
102
|
+
const resolvedSections: ResolvedSection[] = categoryDestination ? [{
|
|
103
|
+
id: null,
|
|
104
|
+
title: currentPage.title,
|
|
105
|
+
titleHtml: currentPage.title.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>'),
|
|
106
|
+
headingLevel: 1,
|
|
107
|
+
contentBlocks: [{
|
|
108
|
+
type: 'page-list',
|
|
109
|
+
pages: categoryDestination.children.map((node) => ({
|
|
110
|
+
title: node.title,
|
|
111
|
+
pathname: node.pathname,
|
|
112
|
+
description: node.kind === 'page' ? node.entry.data.page?.description : undefined,
|
|
113
|
+
})),
|
|
114
|
+
}],
|
|
115
|
+
}] : await getSectionsContent(siteHtml, currentPage, childPages);
|
|
116
|
+
const allContentBlocks = resolvedSections.flatMap((section) => flattenContentBlocks(section.contentBlocks));
|
|
117
|
+
const hasTabs = allContentBlocks.some((block) => block.type === 'tabs');
|
|
118
|
+
const hasNotes = allContentBlocks.some((block) => (
|
|
119
|
+
block.type === 'html' && /class="[^"]*\bsection-note-ref\b|\bdata-footnote-ref(?:="")?/.test(block.html)
|
|
120
|
+
));
|
|
121
|
+
const hasCodeBlocks = allContentBlocks.some((block) => (
|
|
99
122
|
block.type === 'html' && /<pre\b[^>]*>[\s\S]*?<code\b/i.test(block.html)
|
|
100
|
-
))
|
|
101
|
-
const hasTables =
|
|
123
|
+
));
|
|
124
|
+
const hasTables = allContentBlocks.some((block) => (
|
|
102
125
|
block.type === 'html' && /\bdata-table-frame(?:="")?/i.test(block.html)
|
|
103
|
-
))
|
|
104
|
-
const hasImageStack =
|
|
126
|
+
));
|
|
127
|
+
const hasImageStack = allContentBlocks.some((block) => (
|
|
105
128
|
block.type === 'image-stack'
|
|
106
|
-
))
|
|
129
|
+
));
|
|
107
130
|
const hasPrioritizableImage = (section: ResolvedSection) => section.contentBlocks.some((block) => (
|
|
108
131
|
block.type === 'image-stack'
|
|
109
132
|
|| block.type === 'image-carousel'
|
|
@@ -116,7 +139,7 @@ const renderedSections = resolvedSections.map((section, index) => ({
|
|
|
116
139
|
prioritizeFirstImage: index === firstImageSectionIndex,
|
|
117
140
|
}));
|
|
118
141
|
const hasPageSequence = Boolean(pageSequence.previous || pageSequence.next);
|
|
119
|
-
const editSourceTarget = projectConfig.editLink
|
|
142
|
+
const editSourceTarget = projectConfig.editLink && currentPage.kind === 'page'
|
|
120
143
|
? resolveEditSourceTarget({
|
|
121
144
|
...projectConfig.editLink,
|
|
122
145
|
development: import.meta.env.DEV,
|
|
@@ -184,7 +207,7 @@ const reserveBreadcrumbSpace = showTreeNavigation || showBreadcrumbs;
|
|
|
184
207
|
|
|
185
208
|
<BaseLayout
|
|
186
209
|
title={currentPage.title}
|
|
187
|
-
description={entry
|
|
210
|
+
description={entry?.data.page?.description}
|
|
188
211
|
presentation={pagePresentation}
|
|
189
212
|
visualTheme={visualTheme}
|
|
190
213
|
frameColors={frameColors}
|
|
@@ -259,6 +282,8 @@ const reserveBreadcrumbSpace = showTreeNavigation || showBreadcrumbs;
|
|
|
259
282
|
</div>
|
|
260
283
|
{hasTreeNavigation && <TreeNavigationScript />}
|
|
261
284
|
{hasCodeBlocks && <CodeBlockCopyScript />}
|
|
285
|
+
{hasTabs && <ContentTabsScript />}
|
|
286
|
+
{hasNotes && <NoteNavigationScript />}
|
|
262
287
|
{hasTables && <TableOverflowScript />}
|
|
263
288
|
{hasImageStack && <ImageStackEnhancement />}
|
|
264
289
|
</BaseLayout>
|
|
@@ -6,11 +6,8 @@ import {
|
|
|
6
6
|
getHeadingTypographySizeValue,
|
|
7
7
|
getTypographySizeValue,
|
|
8
8
|
} from '../../scripts/lib/typography.mjs';
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import ImageStack from './ImageStack.astro';
|
|
12
|
-
import PageList from './PageList.astro';
|
|
13
|
-
import type { ResolvedSection } from '../lib/sectionContent';
|
|
9
|
+
import ContentBlocks from './ContentBlocks.astro';
|
|
10
|
+
import { flattenContentBlocks, type ResolvedSection } from '../lib/sectionContent';
|
|
14
11
|
|
|
15
12
|
type ResponsiveValue<T> = { desktop: T; mobile: T };
|
|
16
13
|
type ResponsiveOverride<T> = { desktop?: T; mobile?: T };
|
|
@@ -110,42 +107,11 @@ const bodyWidth = {
|
|
|
110
107
|
desktop: bodyWidthValue,
|
|
111
108
|
mobile: bodyWidthValue,
|
|
112
109
|
};
|
|
113
|
-
const
|
|
114
|
-
block.type === 'image-stack'
|
|
115
|
-
|| block.type === 'image-carousel'
|
|
116
|
-
|| block.type === 'card-list'
|
|
117
|
-
|| block.type === 'page-list'
|
|
118
|
-
);
|
|
119
|
-
const hasMedia = section.contentBlocks.some((block) => (
|
|
110
|
+
const hasMedia = flattenContentBlocks(section.contentBlocks).some((block) => (
|
|
120
111
|
block.type === 'image-stack'
|
|
121
112
|
|| block.type === 'image-carousel'
|
|
122
113
|
|| (block.type === 'card-list' && block.cards.some((card) => card.image))
|
|
123
114
|
));
|
|
124
|
-
const contentGroups: Array<
|
|
125
|
-
| { type: 'reading'; blocks: ResolvedSection['contentBlocks'] }
|
|
126
|
-
| { type: 'structured'; block: Extract<ResolvedSection['contentBlocks'][number], { type: 'image-stack' | 'image-carousel' | 'card-list' | 'page-list' }> }
|
|
127
|
-
> = [];
|
|
128
|
-
let readingBlocks: ResolvedSection['contentBlocks'] = [];
|
|
129
|
-
const flushReadingBlocks = () => {
|
|
130
|
-
if (readingBlocks.length === 0) return;
|
|
131
|
-
contentGroups.push({ type: 'reading', blocks: readingBlocks });
|
|
132
|
-
readingBlocks = [];
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
for (const block of section.contentBlocks) {
|
|
136
|
-
if (isStructuredBlock(block)) {
|
|
137
|
-
flushReadingBlocks();
|
|
138
|
-
contentGroups.push({ type: 'structured', block });
|
|
139
|
-
} else {
|
|
140
|
-
readingBlocks = [...readingBlocks, block];
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
flushReadingBlocks();
|
|
145
|
-
const firstMediaGroupIndex = contentGroups.findIndex((group) => (
|
|
146
|
-
group.type === 'structured'
|
|
147
|
-
&& (group.block.type === 'image-stack' || group.block.type === 'image-carousel')
|
|
148
|
-
));
|
|
149
115
|
const markdownHeadingStyle = (level: 'h3' | 'h4') => {
|
|
150
116
|
const headingConfig = markdownHeadings[level];
|
|
151
117
|
const fontSize = getHeadingTypographySizeValue(level, headingConfig.size);
|
|
@@ -209,55 +175,13 @@ const sectionStyle = [
|
|
|
209
175
|
style={sectionStyle}
|
|
210
176
|
>
|
|
211
177
|
<div class="section-card">
|
|
178
|
+
<slot name="before-heading" />
|
|
212
179
|
<header class="section-header">
|
|
213
180
|
<HeadingTag id={headingId} set:html={section.titleHtml} />
|
|
214
181
|
</header>
|
|
215
182
|
|
|
216
183
|
<div class:list={['section-body', { 'section-body-has-media': hasMedia, 'section-body-text-only': !hasMedia }]}>
|
|
217
|
-
{
|
|
218
|
-
if (group.type === 'reading') {
|
|
219
|
-
return group.blocks.map((block) => block.type === 'html'
|
|
220
|
-
&& block.html
|
|
221
|
-
&& <div class="section-markdown" set:html={block.html} />);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const block = group.block;
|
|
225
|
-
if (block.type === 'image-carousel') {
|
|
226
|
-
return (
|
|
227
|
-
<ImageCarousel
|
|
228
|
-
title={section.title}
|
|
229
|
-
images={block.images}
|
|
230
|
-
maxAvailableWidthPercent={visualTheme.images.maxAvailableWidthPercent}
|
|
231
|
-
maxAvailableHeightPercent={visualTheme.images.maxAvailableHeightPercent}
|
|
232
|
-
priorityFirstImage={prioritizeFirstImage && groupIndex === firstMediaGroupIndex}
|
|
233
|
-
/>
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (block.type === 'card-list') {
|
|
238
|
-
return (
|
|
239
|
-
<CardList
|
|
240
|
-
cards={block.cards}
|
|
241
|
-
layout={block.layout}
|
|
242
|
-
flow={block.flow}
|
|
243
|
-
size={block.size}
|
|
244
|
-
width={block.width ?? pagePresentation.blocks.cardList.width}
|
|
245
|
-
/>
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
if (block.type === 'page-list') {
|
|
249
|
-
return <PageList pages={block.pages} />;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
return (
|
|
253
|
-
<ImageStack
|
|
254
|
-
title={section.title}
|
|
255
|
-
images={block.images}
|
|
256
|
-
maxAvailableWidthPercent={visualTheme.images.maxAvailableWidthPercent}
|
|
257
|
-
priorityFirstImage={prioritizeFirstImage && groupIndex === firstMediaGroupIndex}
|
|
258
|
-
/>
|
|
259
|
-
);
|
|
260
|
-
})}
|
|
184
|
+
<ContentBlocks blocks={section.contentBlocks} title={section.title} images={visualTheme.images} cardWidth={pagePresentation.blocks.cardList.width} prioritizeFirstImage={prioritizeFirstImage} />
|
|
261
185
|
</div>
|
|
262
186
|
</div>
|
|
263
187
|
</section>
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import projectConfig from '../../scripts/lib/project-config.mjs';
|
|
3
3
|
import { withBasePath } from '../lib/basePath';
|
|
4
4
|
import { getListedSiteNavigationTree, type SiteNavigationEntry } from '../lib/siteNavigation';
|
|
5
|
-
import type {
|
|
5
|
+
import type { SiteNode } from '../lib/sitePages';
|
|
6
6
|
import NavigationPageTree from './NavigationPageTree.astro';
|
|
7
7
|
import NavigationTreeControls from './NavigationTreeControls.astro';
|
|
8
8
|
|
|
9
9
|
interface Props {
|
|
10
|
-
currentPage:
|
|
10
|
+
currentPage: SiteNode;
|
|
11
11
|
navigationEntries: SiteNavigationEntry[];
|
|
12
12
|
integratePageSections?: boolean;
|
|
13
13
|
}
|