domma-cms 0.41.1 → 0.43.1
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/CLAUDE.md +38 -2
- package/admin/js/templates/collection-editor.html +1 -1
- package/admin/js/views/action-editor.js +1 -1
- package/admin/js/views/block-editor.js +2 -2
- package/admin/js/views/collection-editor.js +4 -4
- package/admin/js/views/form-editor.js +6 -6
- package/admin/js/views/navigation.js +16 -16
- package/admin/js/views/page-editor.js +41 -41
- package/admin/js/views/view-editor.js +1 -1
- package/package.json +1 -1
- package/public/css/site.css +1 -1
- package/public/js/collection-context.js +2 -2
- package/public/js/collection-export.mjs +3 -0
- package/public/js/collection-query.mjs +1 -0
- package/public/js/collection-sort.mjs +1 -0
- package/public/js/site.js +1 -1
- package/scripts/setup.js +23 -2
- package/server/services/collections.js +12 -11
- package/server/services/markdown.js +116 -79
- package/server/services/menuRender.js +90 -0
- package/server/services/menus.js +46 -0
- package/server/services/renderer.js +33 -5
- package/server/templates/page.html +1 -1
|
@@ -8,7 +8,8 @@ import {fileURLToPath} from 'url';
|
|
|
8
8
|
import {getConfig} from '../config.js';
|
|
9
9
|
import {getInjectionSnippets} from './plugins.js';
|
|
10
10
|
import {applyTransforms} from './hooks.js';
|
|
11
|
-
import {resolveLocation, resolveMenuDecorations} from './menus.js';
|
|
11
|
+
import {resolveLocation, resolveMenuDecorations, resolveOverlaysForPage} from './menus.js';
|
|
12
|
+
import {buildMenuNav} from './menuRender.js';
|
|
12
13
|
import {getProjectForPage} from './projects.js';
|
|
13
14
|
|
|
14
15
|
const VALID_LAYOUT_WIDTHS = new Set(['narrow', 'normal', 'wide', 'full']);
|
|
@@ -53,6 +54,26 @@ function filterHiddenNavItems(nav) {
|
|
|
53
54
|
return {...nav, items};
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Build the overlay menus for a page: every menu bound to the `overlay` slot
|
|
59
|
+
* whose binding matches, each drawn by the same builder the `[menu]` shortcode
|
|
60
|
+
* uses so an overlay and a shortcode of the same menu look identical.
|
|
61
|
+
*
|
|
62
|
+
* Emitted as bare <nav> elements with no wrapper — a wrapping element would
|
|
63
|
+
* risk becoming a containing block for their position:fixed pinning.
|
|
64
|
+
*
|
|
65
|
+
* @param {{urlPath?: string, project?: string|null}} menuCtx
|
|
66
|
+
* @param {object|null} user
|
|
67
|
+
* @returns {Promise<string>} concatenated HTML, '' when nothing applies
|
|
68
|
+
*/
|
|
69
|
+
async function buildOverlayMenus(menuCtx, user) {
|
|
70
|
+
const overlays = await resolveOverlaysForPage(menuCtx, user);
|
|
71
|
+
if (!overlays.length) return '';
|
|
72
|
+
const navs = await Promise.all(overlays.map(async (menu) =>
|
|
73
|
+
buildMenuNav(menu, await resolveMenuDecorations(menu.items))));
|
|
74
|
+
return navs.join('');
|
|
75
|
+
}
|
|
76
|
+
|
|
56
77
|
/**
|
|
57
78
|
* Render a page to a full HTML string.
|
|
58
79
|
*
|
|
@@ -89,10 +110,11 @@ export async function renderPage(page, opts = {}) {
|
|
|
89
110
|
|
|
90
111
|
// Resolve live badge counts (countFrom) before the menus are injected as
|
|
91
112
|
// globals. Static badges/colours/pills pass through unchanged.
|
|
92
|
-
const [navItemsDecorated, footerPrimaryDecorated, footerLegalDecorated] = await Promise.all([
|
|
113
|
+
const [navItemsDecorated, footerPrimaryDecorated, footerLegalDecorated, overlayMenus] = await Promise.all([
|
|
93
114
|
resolveMenuDecorations(navMenu ? navMenu.items : []),
|
|
94
115
|
resolveMenuDecorations(footerPrimary ? footerPrimary.items : []),
|
|
95
|
-
resolveMenuDecorations(footerLegal ? footerLegal.items : [])
|
|
116
|
+
resolveMenuDecorations(footerLegal ? footerLegal.items : []),
|
|
117
|
+
buildOverlayMenus(menuCtx, opts.user || null)
|
|
96
118
|
]);
|
|
97
119
|
|
|
98
120
|
// Compose the navigation object the public site script expects:
|
|
@@ -220,6 +242,10 @@ export async function renderPage(page, opts = {}) {
|
|
|
220
242
|
headInject: [injection.head, navbarFontLink].filter(Boolean).join('\n'),
|
|
221
243
|
headInjectLate: [injection.headLate, customCssTag, navbarStyleTag].filter(Boolean).join('\n'),
|
|
222
244
|
bodyEndInject: [
|
|
245
|
+
// Overlay menus — bound to the `overlay` slot and pinned by their own
|
|
246
|
+
// float config, so they belong at the end of the body, clear of the
|
|
247
|
+
// content flow.
|
|
248
|
+
overlayMenus,
|
|
223
249
|
injection.bodyEnd,
|
|
224
250
|
site.backToTop?.enabled ? '<script src="/public/js/btt.js"></script>' : '',
|
|
225
251
|
site.cookieConsent?.enabled ? '<script src="/public/js/cookie-consent.js"></script>' : '',
|
|
@@ -516,10 +542,11 @@ export async function renderBlogPage(templatePath, data = {}, seoMeta = {}) {
|
|
|
516
542
|
|
|
517
543
|
// Resolve live badge counts (countFrom) before the menus are injected as
|
|
518
544
|
// globals. Static badges/colours/pills pass through unchanged.
|
|
519
|
-
const [navItemsDecorated, footerPrimaryDecorated, footerLegalDecorated] = await Promise.all([
|
|
545
|
+
const [navItemsDecorated, footerPrimaryDecorated, footerLegalDecorated, overlayMenus] = await Promise.all([
|
|
520
546
|
resolveMenuDecorations(navMenu ? navMenu.items : []),
|
|
521
547
|
resolveMenuDecorations(footerPrimary ? footerPrimary.items : []),
|
|
522
|
-
resolveMenuDecorations(footerLegal ? footerLegal.items : [])
|
|
548
|
+
resolveMenuDecorations(footerLegal ? footerLegal.items : []),
|
|
549
|
+
buildOverlayMenus(menuCtx, user)
|
|
523
550
|
]);
|
|
524
551
|
|
|
525
552
|
// Compose the navigation object the public site script expects:
|
|
@@ -623,6 +650,7 @@ export async function renderBlogPage(templatePath, data = {}, seoMeta = {}) {
|
|
|
623
650
|
headInject: [injection.head, navbarFontLink].filter(Boolean).join('\n'),
|
|
624
651
|
headInjectLate: [injection.headLate, customCssTag, navbarStyleTag].filter(Boolean).join('\n'),
|
|
625
652
|
bodyEndInject: [
|
|
653
|
+
overlayMenus,
|
|
626
654
|
injection.bodyEnd,
|
|
627
655
|
(seoMeta.usedComponents || [])
|
|
628
656
|
.map(n => `<script type="module" src="/api/components/${n}.js"></script>`)
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
|
|
118
118
|
<!-- Site initialisation -->
|
|
119
119
|
<script src="/public/js/site.js?v=20260817-menu-bindings" type="module"></script>
|
|
120
|
-
<script src="/public/js/collection-context.js?v=
|
|
120
|
+
<script src="/public/js/collection-context.js?v=20260819-export" type="module"></script>
|
|
121
121
|
|
|
122
122
|
<!-- Interactive Collection Browser (used by [collection] shortcodes with
|
|
123
123
|
searchable / filterable / sortable / paginate attributes) -->
|