@morphemecms/cms 0.5.0 → 0.7.0
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/CHANGELOG.md +16 -0
- package/astro.mjs +3 -0
- package/bin/morpheme.mjs +3 -1
- package/defaults/blockTexts.ts +2 -2
- package/defaults/collections.ts +10 -0
- package/defaults/editor.ts +57 -53
- package/defaults/privacy.ts +4 -1
- package/defaults/rules.ts +36 -38
- package/defaults/standardPages.ts +0 -3
- package/defaults/texts.ts +11 -2
- package/demo/src/content/pages/about.md +2 -0
- package/icons/lucide/browser-fill.svg +1 -0
- package/icons/lucide/buildings-fill.svg +1 -0
- package/icons/lucide/certificate-fill.svg +1 -0
- package/icons/lucide/chart-line-up-fill.svg +1 -0
- package/icons/lucide/chats-fill.svg +1 -0
- package/icons/lucide/envelope-simple-fill.svg +1 -0
- package/icons/lucide/file-text-fill.svg +1 -0
- package/icons/lucide/folder-simple-fill.svg +1 -0
- package/icons/lucide/gauge.svg +1 -1
- package/icons/lucide/gear-six.svg +1 -0
- package/icons/lucide/globe-simple.svg +1 -0
- package/icons/lucide/heart-fill.svg +1 -0
- package/icons/lucide/layout.svg +1 -0
- package/icons/lucide/list-checks-fill.svg +1 -0
- package/icons/lucide/magnifying-glass-fill.svg +1 -0
- package/icons/lucide/megaphone-fill.svg +1 -0
- package/icons/lucide/newspaper-fill.svg +1 -0
- package/icons/lucide/paint-brush-broad-fill.svg +1 -0
- package/icons/lucide/puzzle-piece-fill.svg +1 -0
- package/icons/lucide/shield-check-fill.svg +1 -0
- package/icons/lucide/sidebar-simple.svg +1 -1
- package/icons/lucide/sidebar.svg +1 -0
- package/icons/lucide/square-half-bottom-fill.svg +1 -0
- package/icons/lucide/square-half.svg +1 -0
- package/icons/lucide/squares-four-fill.svg +1 -0
- package/icons/lucide/storefront-fill.svg +1 -0
- package/icons/lucide/tag-fill.svg +1 -0
- package/icons/lucide/toggle-right-fill.svg +1 -0
- package/icons/lucide/trash-fill.svg +1 -0
- package/icons/lucide/user-fill.svg +1 -0
- package/icons/lucide/wrench-fill.svg +1 -0
- package/icons/material-symbols/browser-fill.svg +1 -0
- package/icons/material-symbols/buildings-fill.svg +1 -0
- package/icons/material-symbols/certificate-fill.svg +1 -0
- package/icons/material-symbols/chart-line-up-fill.svg +1 -0
- package/icons/material-symbols/chats-fill.svg +1 -0
- package/icons/material-symbols/envelope-simple-fill.svg +1 -0
- package/icons/material-symbols/file-text-fill.svg +1 -0
- package/icons/material-symbols/folder-simple-fill.svg +1 -0
- package/icons/material-symbols/gauge.svg +1 -1
- package/icons/material-symbols/gear-six.svg +1 -0
- package/icons/material-symbols/globe-simple.svg +1 -0
- package/icons/material-symbols/heart-fill.svg +1 -0
- package/icons/material-symbols/layout.svg +1 -0
- package/icons/material-symbols/list-checks-fill.svg +1 -0
- package/icons/material-symbols/magnifying-glass-fill.svg +1 -0
- package/icons/material-symbols/megaphone-fill.svg +1 -0
- package/icons/material-symbols/newspaper-fill.svg +1 -0
- package/icons/material-symbols/paint-brush-broad-fill.svg +1 -0
- package/icons/material-symbols/puzzle-piece-fill.svg +1 -0
- package/icons/material-symbols/shield-check-fill.svg +1 -0
- package/icons/material-symbols/sidebar-simple.svg +1 -1
- package/icons/material-symbols/sidebar.svg +1 -0
- package/icons/material-symbols/square-half-bottom-fill.svg +1 -0
- package/icons/material-symbols/square-half.svg +1 -0
- package/icons/material-symbols/squares-four-fill.svg +1 -0
- package/icons/material-symbols/storefront-fill.svg +1 -0
- package/icons/material-symbols/tag-fill.svg +1 -0
- package/icons/material-symbols/toggle-right-fill.svg +1 -0
- package/icons/material-symbols/trash-fill.svg +1 -0
- package/icons/material-symbols/user-fill.svg +1 -0
- package/icons/material-symbols/wrench-fill.svg +1 -0
- package/icons/phosphor/browser-fill.svg +1 -0
- package/icons/phosphor/buildings-fill.svg +1 -0
- package/icons/phosphor/certificate-fill.svg +1 -0
- package/icons/phosphor/chart-line-up-fill.svg +1 -0
- package/icons/phosphor/chats-fill.svg +1 -0
- package/icons/phosphor/envelope-simple-fill.svg +1 -0
- package/icons/phosphor/file-text-fill.svg +1 -0
- package/icons/phosphor/folder-simple-fill.svg +1 -0
- package/icons/phosphor/gear-six.svg +1 -0
- package/icons/phosphor/globe-simple.svg +1 -0
- package/icons/phosphor/heart-fill.svg +1 -0
- package/icons/phosphor/layout.svg +1 -0
- package/icons/phosphor/list-checks-fill.svg +1 -0
- package/icons/phosphor/magnifying-glass-fill.svg +1 -0
- package/icons/phosphor/megaphone-fill.svg +1 -0
- package/icons/phosphor/newspaper-fill.svg +1 -0
- package/icons/phosphor/paint-brush-broad-fill.svg +1 -0
- package/icons/phosphor/puzzle-piece-fill.svg +1 -0
- package/icons/phosphor/shield-check-fill.svg +1 -0
- package/icons/phosphor/sidebar.svg +1 -0
- package/icons/phosphor/square-half-bottom-fill.svg +1 -0
- package/icons/phosphor/square-half.svg +1 -0
- package/icons/phosphor/squares-four-fill.svg +1 -0
- package/icons/phosphor/storefront-fill.svg +1 -0
- package/icons/phosphor/tag-fill.svg +1 -0
- package/icons/phosphor/toggle-right-fill.svg +1 -0
- package/icons/phosphor/trash-fill.svg +1 -0
- package/icons/phosphor/user-fill.svg +1 -0
- package/icons/phosphor/wrench-fill.svg +1 -0
- package/lib/breakpoints.d.mts +13 -0
- package/lib/breakpoints.mjs +20 -0
- package/lib/breakpoints.test.mjs +39 -0
- package/lib/build-lane.d.mts +15 -0
- package/lib/build-lane.mjs +23 -0
- package/lib/build-lane.test.mjs +74 -0
- package/lib/build-settings.d.mts +16 -0
- package/lib/build-settings.mjs +39 -0
- package/lib/build-settings.test.mjs +41 -0
- package/lib/contracts.d.mts +3 -2
- package/lib/contracts.mjs +3 -2
- package/lib/drawer-swipe.d.mts +10 -0
- package/lib/drawer-swipe.mjs +17 -0
- package/lib/drawer-swipe.test.mjs +33 -0
- package/lib/drawerKeys.d.mts +9 -0
- package/lib/drawerKeys.mjs +26 -0
- package/lib/drawerKeys.test.mjs +21 -0
- package/lib/eyebrow.d.mts +6 -0
- package/lib/eyebrow.mjs +24 -0
- package/lib/eyebrow.test.mjs +20 -0
- package/lib/front-sections.test.mjs +82 -0
- package/lib/heading-levels.d.mts +7 -0
- package/lib/heading-levels.mjs +16 -0
- package/lib/heading-levels.test.mjs +37 -0
- package/lib/inline.ts +3 -2
- package/lib/markdown.ts +2 -0
- package/lib/materialIcon.d.mts +21 -0
- package/lib/materialIcon.mjs +29 -0
- package/lib/materialIcon.test.mjs +45 -0
- package/lib/menu-layout.d.mts +11 -0
- package/lib/menu-layout.mjs +14 -0
- package/lib/menu-layout.test.mjs +23 -0
- package/lib/menu.d.mts +59 -0
- package/lib/menu.mjs +129 -0
- package/lib/menu.test.mjs +291 -0
- package/lib/rehype-emphasize.d.mts +4 -0
- package/lib/rehype-emphasize.mjs +20 -0
- package/lib/rehype-emphasize.test.mjs +39 -0
- package/lib/section-in-view.d.mts +8 -0
- package/lib/section-in-view.mjs +25 -0
- package/lib/section-in-view.test.mjs +35 -0
- package/lib/section-marker.d.mts +5 -0
- package/lib/section-marker.mjs +18 -0
- package/lib/section-marker.test.mjs +22 -0
- package/lib/section-ranges.d.mts +12 -0
- package/lib/section-ranges.mjs +43 -0
- package/lib/section-ranges.test.mjs +61 -0
- package/lib/sheet-stops.d.mts +68 -0
- package/lib/sheet-stops.mjs +198 -0
- package/lib/sheet-stops.test.mjs +155 -0
- package/lib/still-timer.d.mts +5 -0
- package/lib/still-timer.mjs +17 -0
- package/lib/still-timer.test.mjs +42 -0
- package/lib/text-sections.d.mts +10 -0
- package/lib/text-sections.mjs +45 -0
- package/lib/text-sections.test.mjs +78 -0
- package/lib/video.mjs +2 -1
- package/lib/without-h1.d.mts +1 -0
- package/lib/without-h1.mjs +7 -0
- package/lib/without-h1.test.mjs +26 -0
- package/lib/word-at.d.mts +6 -0
- package/lib/word-at.mjs +20 -0
- package/lib/word-at.test.mjs +19 -0
- package/package.json +3 -1
- package/pages/editor/version.json.js +22 -2
- package/scripts/already-checked.mjs +11 -0
- package/scripts/already-checked.test.mjs +18 -0
- package/scripts/build-settings-problems.mjs +27 -0
- package/scripts/build-settings-problems.test.mjs +35 -0
- package/scripts/check-content.mjs +42 -4
- package/scripts/check-worker.mjs +96 -4
- package/scripts/ci-build.mjs +85 -0
- package/scripts/ci-build.test.mjs +137 -0
- package/scripts/editor-roundtrip.mjs +62 -3
- package/scripts/editor-screens.mjs +21 -7
- package/scripts/git-env.mjs +6 -0
- package/scripts/step-command.mjs +34 -0
- package/scripts/step-command.test.mjs +50 -0
- package/scripts/text-problems.mjs +83 -0
- package/scripts/text-problems.test.mjs +74 -0
- package/scripts/worker-modules.mjs +11 -1
- package/site/breakpoints.d.mts +6 -0
- package/site/breakpoints.mjs +52 -0
- package/site/breakpoints.test.mjs +36 -0
- package/site/casing.d.mts +3 -0
- package/site/casing.mjs +26 -0
- package/site/content.config.ts +2 -0
- package/site/content.ts +2 -4
- package/site/defineSite.d.mts +1 -0
- package/site/defineSite.mjs +3 -0
- package/site/home.ts +3 -2
- package/site/icons.d.mts +116 -4
- package/site/icons.mjs +62 -6
- package/site/images.mjs +1 -1
- package/site/live-diff.d.mts +22 -0
- package/site/live-diff.mjs +98 -0
- package/site/live-diff.test.mjs +235 -0
- package/site/materialSymbols.d.mts +5 -0
- package/site/materialSymbols.mjs +19 -0
- package/site/sections.ts +1 -1
- package/site/theme.d.mts +1 -1
- package/site/theme.mjs +7 -1
- package/src/ActionParts.tsx +1 -1
- package/src/Advanced.tsx +101 -20
- package/src/App.tsx +47 -121
- package/src/AppList.tsx +1 -1
- package/src/BlockParts.tsx +3 -3
- package/src/Colors.tsx +1 -1
- package/src/CommunicationParts.tsx +1 -1
- package/src/ContainmentParts.tsx +80 -28
- package/src/Deleted.tsx +18 -4
- package/src/EditorFooter.tsx +14 -0
- package/src/EntryForm.tsx +75 -39
- package/src/FormFrame.tsx +3 -8
- package/src/Library.tsx +46 -51
- package/src/Licenses.tsx +27 -11
- package/src/MainDrawerParts.tsx +60 -0
- package/src/MainMenu.tsx +136 -0
- package/src/MarkdownEditor.tsx +175 -32
- package/src/Media.tsx +69 -16
- package/src/MediaTags.tsx +91 -0
- package/src/ModalSheetSample.tsx +47 -0
- package/src/NavigationParts.tsx +67 -21
- package/src/NavigationRestParts.tsx +1 -1
- package/src/Parts.tsx +71 -0
- package/src/PartsShown.tsx +1 -1
- package/src/PickerParts.tsx +2 -2
- package/src/Redirects.tsx +3 -2
- package/src/Screen.tsx +93 -90
- package/src/SelectionParts.tsx +22 -6
- package/src/SiteLogoLink.tsx +14 -0
- package/src/StartFab.tsx +22 -0
- package/src/StartStatus.tsx +1 -1
- package/src/autoTags.d.mts +28 -0
- package/src/autoTags.mjs +68 -0
- package/src/autoTags.test.mjs +109 -0
- package/src/buildSettings.test.mjs +20 -0
- package/src/buildSettings.ts +20 -0
- package/src/checkSite.ts +14 -1
- package/src/deploy.ts +7 -9
- package/src/editor.css +150 -17
- package/src/eyebrow.d.mts +5 -0
- package/src/eyebrow.mjs +53 -0
- package/src/eyebrowState.d.mts +21 -0
- package/src/eyebrowState.mjs +62 -0
- package/src/eyebrowState.test.mjs +78 -0
- package/src/fileRecords.d.mts +115 -0
- package/src/fileRecords.mjs +224 -0
- package/src/fileRecords.test.mjs +224 -0
- package/src/fileTagFilter.d.mts +30 -0
- package/src/fileTagFilter.mjs +44 -0
- package/src/fileTagFilter.test.mjs +57 -0
- package/src/fileTags.d.mts +56 -0
- package/src/fileTags.mjs +100 -0
- package/src/fileTags.test.mjs +127 -0
- package/src/firstHeading.d.mts +6 -0
- package/src/firstHeading.mjs +37 -0
- package/src/i18n/da-DK/advanced.ts +27 -12
- package/src/i18n/da-DK/app.ts +9 -7
- package/src/i18n/da-DK/apps.ts +16 -16
- package/src/i18n/da-DK/blockSettings.ts +9 -9
- package/src/i18n/da-DK/blocks.ts +2 -2
- package/src/i18n/da-DK/check.ts +5 -2
- package/src/i18n/da-DK/cms.ts +14 -12
- package/src/i18n/da-DK/colors.ts +5 -5
- package/src/i18n/da-DK/common.ts +2 -2
- package/src/i18n/da-DK/company.ts +3 -3
- package/src/i18n/da-DK/consents.ts +6 -6
- package/src/i18n/da-DK/forms.ts +6 -6
- package/src/i18n/da-DK/history.ts +6 -6
- package/src/i18n/da-DK/keywords.ts +2 -2
- package/src/i18n/da-DK/library.ts +17 -15
- package/src/i18n/da-DK/licenses.ts +4 -4
- package/src/i18n/da-DK/media.ts +10 -4
- package/src/i18n/da-DK/parts.ts +62 -25
- package/src/i18n/da-DK/preview.ts +5 -6
- package/src/i18n/da-DK/redirects.ts +7 -7
- package/src/i18n/da-DK/seo.ts +1 -1
- package/src/i18n/da-DK/text.ts +2 -0
- package/src/i18n/da-DK/theme.ts +5 -5
- package/src/i18n/en-US/advanced.ts +34 -18
- package/src/i18n/en-US/app.ts +7 -5
- package/src/i18n/en-US/apps.ts +9 -9
- package/src/i18n/en-US/blockSettings.ts +4 -4
- package/src/i18n/en-US/blocks.ts +6 -6
- package/src/i18n/en-US/check.ts +6 -3
- package/src/i18n/en-US/cms.ts +15 -14
- package/src/i18n/en-US/colors.ts +18 -18
- package/src/i18n/en-US/common.ts +3 -3
- package/src/i18n/en-US/consents.ts +4 -4
- package/src/i18n/en-US/forms.ts +5 -5
- package/src/i18n/en-US/history.ts +2 -2
- package/src/i18n/en-US/library.ts +21 -15
- package/src/i18n/en-US/licenses.ts +6 -6
- package/src/i18n/en-US/media.ts +7 -1
- package/src/i18n/en-US/parts.ts +60 -21
- package/src/i18n/en-US/preview.ts +5 -6
- package/src/i18n/en-US/redirects.ts +3 -3
- package/src/i18n/en-US/seo.ts +1 -1
- package/src/i18n/en-US/text.ts +3 -0
- package/src/i18n/en-US/theme.ts +6 -6
- package/src/icon.tsx +90 -27
- package/src/licenseData.test.mjs +28 -0
- package/src/licenseData.ts +12 -1
- package/src/markdown.d.mts +2 -0
- package/src/markdown.mjs +73 -5
- package/src/markdown.test.mjs +74 -0
- package/src/materialIcons.ts +8 -0
- package/src/menuChildren.ts +36 -0
- package/src/menuOpen.ts +34 -0
- package/src/pagePreview.tsx +23 -19
- package/src/r2Caching.ts +14 -0
- package/src/sectionFrame.ts +39 -0
- package/src/sectionState.d.mts +19 -0
- package/src/sectionState.mjs +31 -0
- package/src/sectionState.test.mjs +59 -0
- package/src/sections.d.mts +9 -7
- package/src/sections.mjs +74 -27
- package/src/sections.test.mjs +59 -0
- package/src/sidebar.ts +2 -2
- package/src/site.ts +27 -17
- package/src/stillCursor.d.mts +8 -0
- package/src/stillCursor.mjs +19 -0
- package/src/stillCursor.test.mjs +26 -0
- package/src/tagUses.d.mts +47 -0
- package/src/tagUses.mjs +121 -0
- package/src/tagUses.test.mjs +141 -0
- package/src/themeUi.ts +10 -0
- package/src/topBarSlot.tsx +37 -0
- package/src/ui.tsx +654 -150
- package/src/virtual.d.ts +5 -0
- package/starter/README.md +2 -1
- package/starter/package.json +2 -1
- package/starter/wrangler.jsonc +3 -2
- package/theme/blocks/cards/LinkCards.tsx +2 -1
- package/theme/blocks/hero/View.tsx +2 -1
- package/theme/blocks/video/View.tsx +2 -1
- package/theme/components/BlogIndex.astro +2 -2
- package/theme/components/BlogPosts.astro +1 -1
- package/theme/components/BlogPosts.tsx +9 -6
- package/theme/components/Container.astro +1 -1
- package/theme/components/CookieConsent.astro +1 -1
- package/theme/components/EndBlock.astro +1 -1
- package/theme/components/Footer.astro +5 -5
- package/theme/components/Header.astro +3 -3
- package/theme/components/Icon.astro +2 -2
- package/theme/components/MobileMenu.tsx +72 -61
- package/theme/components/MobileNav.astro +2 -2
- package/theme/components/PageHeader.astro +2 -2
- package/theme/components/PageSection.astro +1 -1
- package/theme/components/PopupButton.tsx +2 -2
- package/theme/components/PopupView.tsx +2 -2
- package/theme/components/PostList.tsx +7 -3
- package/theme/components/RichText.astro +22 -7
- package/theme/components/Section.astro +17 -10
- package/theme/components/SectionHeading.tsx +1 -1
- package/theme/components/home/PageBlock.astro +4 -4
- package/theme/components/home/Text.astro +3 -3
- package/theme/layouts/PageLayout.astro +3 -3
- package/theme/layouts/PostLayout.astro +9 -8
- package/theme/styles/base.css +13 -3
- package/theme/styles/blocks.css +97 -10
- package/theme/styles/components.css +9 -9
- package/theme/styles/elevation.test.mjs +168 -0
- package/theme/styles/global.css +65 -59
- package/theme/styles/ui.css +460 -131
- package/theme/templates/Home.astro +1 -1
- package/theme/templates/New.astro +5 -5
- package/theme/templates/NotFound.astro +2 -2
- package/theme/ui/BottomSheet.tsx +118 -21
- package/theme/ui/BottomSheetResizeIcon.tsx +13 -0
- package/theme/ui/Button.tsx +4 -3
- package/theme/ui/Dialog.tsx +1 -1
- package/theme/ui/FabMenu.tsx +13 -12
- package/theme/ui/LoadingIndicator.tsx +1 -1
- package/theme/ui/NavigationDrawer.tsx +116 -15
- package/theme/ui/NavigationRail.tsx +22 -13
- package/theme/ui/Search.tsx +1 -1
- package/theme/ui/SettingRow.tsx +31 -0
- package/theme/ui/Switch.tsx +11 -11
- package/theme/ui/TextField.tsx +17 -6
- package/theme/ui/bottomSheet.script.ts +3 -2
- package/theme/ui/bottomSheetControl.ts +131 -46
- package/theme/ui/fabMenu.script.ts +69 -53
- package/theme/ui/modalSheetSize.ts +214 -0
- package/theme/ui/navigationDrawerControl.ts +35 -0
- package/theme/ui/search.script.ts +4 -2
- package/worker/index.js +3 -0
- package/worker/plan-status.js +46 -0
- package/worker/push.js +7 -5
- package/worker/r2-status.js +2 -1
- package/icons/lucide/desktop.svg +0 -1
- package/icons/material-symbols/desktop.svg +0 -1
- package/icons/phosphor/desktop.svg +0 -1
package/src/virtual.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
declare module 'virtual:material-symbols-ssr' {
|
|
2
|
+
const files: Record<string, string>;
|
|
3
|
+
export default files;
|
|
4
|
+
}
|
|
5
|
+
|
|
1
6
|
// What is in each app's folder (appFoldersPlugin in lib/apps.mjs): its files, by their paths in it, and its csp.json.
|
|
2
7
|
declare module 'virtual:app-folders' {
|
|
3
8
|
const folders: Record<string, { files: string[]; csp?: Partial<Record<string, string[]>> }>;
|
package/starter/README.md
CHANGED
|
@@ -25,4 +25,5 @@ npm run dev
|
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
`npm run check` kører tjekkene (formatering, typer, indholdet efter editorens regler, editoren og Workeren), før hver
|
|
28
|
-
push
|
|
28
|
+
push. Cloudflare bygger med `npx morpheme ci-build`: alle tjekkene, eller kun editorens egne, når kun indhold er ændret
|
|
29
|
+
siden det live site; og `npm run build` bygger sitet i `dist/`.
|
package/starter/package.json
CHANGED
|
@@ -29,9 +29,10 @@
|
|
|
29
29
|
"@astrojs/rss": "^4.0.19",
|
|
30
30
|
"@astrojs/sitemap": "^3.7.4",
|
|
31
31
|
"@fontsource-variable/roboto": "^5.3.0",
|
|
32
|
+
"@material-symbols/svg-400": "0.48.2",
|
|
32
33
|
"@material/material-color-utilities": "^0.3.0",
|
|
33
34
|
"@milkdown/kit": "^7.22.3",
|
|
34
|
-
"@morphemecms/cms": "0.
|
|
35
|
+
"@morphemecms/cms": "0.7.0",
|
|
35
36
|
"@phosphor-icons/core": "^2.1.1",
|
|
36
37
|
"@phosphor-icons/react": "^2.1.10",
|
|
37
38
|
"@tailwindcss/typography": "^0.5.20",
|
package/starter/wrangler.jsonc
CHANGED
|
@@ -22,9 +22,10 @@
|
|
|
22
22
|
"d1_databases": [{ "binding": "CONSENT" }],
|
|
23
23
|
// Builds of other branches than main run `wrangler preview`, which needs this block.
|
|
24
24
|
"previews": {},
|
|
25
|
-
//
|
|
25
|
+
// morpheme ci-build runs the checks first (all of them, or just the editor's when only content changed since the live
|
|
26
|
+
// commit), so a branch that fails them is neither built nor deployed.
|
|
26
27
|
"build": {
|
|
27
|
-
"command": "
|
|
28
|
+
"command": "npx morpheme ci-build",
|
|
28
29
|
},
|
|
29
30
|
// Each hour, the pages and posts that are Planlagt are published once their time has come, and the apps do theirs. Each
|
|
30
31
|
// minute, whether the site has been built with a save, for the notification on the phone.
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
// theme's surface or (`background`) the accent: the standard block "Kort", and a site's own cards (this site's front
|
|
5
5
|
// page).
|
|
6
6
|
// `className`: the site's own classes on the list, e.g. its margin.
|
|
7
|
+
import { BREAKPOINTS } from '@morphemecms/cms/lib/breakpoints.mjs';
|
|
7
8
|
import { Svg } from '@morphemecms/cms/src/icon';
|
|
8
9
|
import type { LinkCard } from '@morphemecms/cms/src/standard/cards/view';
|
|
9
10
|
import Card from '@theme/ui/Card';
|
|
10
11
|
|
|
11
|
-
const sizes =
|
|
12
|
+
const sizes = `(min-width: ${BREAKPOINTS.medium}px) 352px, 100vw`;
|
|
12
13
|
|
|
13
14
|
export default function LinkCards({
|
|
14
15
|
items,
|
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
// screen may show them (data-hero-cta, Base.astro).
|
|
8
8
|
import Buttons from '@theme/blocks/buttons/Buttons';
|
|
9
9
|
import type { HeroView } from '@morphemecms/cms/src/standard/hero/view';
|
|
10
|
+
import { BREAKPOINTS } from '@morphemecms/cms/lib/breakpoints.mjs';
|
|
10
11
|
import { useInText } from '@morphemecms/cms/src/standard/view';
|
|
11
12
|
|
|
12
13
|
export default function Hero({ view }: { view: HeroView }) {
|
|
13
14
|
const { image } = view;
|
|
14
15
|
// The widths the picture is shown in: behind the text the whole block's, beside it a part of it.
|
|
15
|
-
const sizes = view.behind ? (view.full ? '100vw' : '(
|
|
16
|
+
const sizes = view.behind ? (view.full ? '100vw' : 'min(72rem, 100vw)') : `(min-width: ${BREAKPOINTS.expanded}px) 40vw, 100vw`;
|
|
16
17
|
return (
|
|
17
18
|
<div
|
|
18
19
|
className={useInText('block-hero', view.behind && 'block-hero-behind', !image && 'block-hero-plain', view.full && 'block-hero-full')}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// its title; a click puts the video in its place (Base.astro). A new link is a new video, with its own still. In the
|
|
4
4
|
// editor a still the site does not have yet is YouTube's or Vimeo's, else the plain box.
|
|
5
5
|
import { useState } from 'react';
|
|
6
|
+
import { BREAKPOINTS } from '@morphemecms/cms/lib/breakpoints.mjs';
|
|
6
7
|
import { Svg } from '@morphemecms/cms/src/icon';
|
|
7
8
|
import type { VideoView } from '@morphemecms/cms/src/standard/video/view';
|
|
8
9
|
import { InProse, Link, useOnSite } from '@morphemecms/cms/src/standard/view';
|
|
@@ -26,7 +27,7 @@ function Facade({ view }: { view: VideoView }) {
|
|
|
26
27
|
className="video-facade-image"
|
|
27
28
|
src={still.src}
|
|
28
29
|
srcSet={still.srcset}
|
|
29
|
-
sizes={still.srcset &&
|
|
30
|
+
sizes={still.srcset && `(min-width: ${BREAKPOINTS.expanded}px) 720px, 100vw`}
|
|
30
31
|
alt=""
|
|
31
32
|
loading="lazy"
|
|
32
33
|
decoding="async"
|
|
@@ -24,8 +24,8 @@ const categories = await getCategories();
|
|
|
24
24
|
|
|
25
25
|
<Base {...seo} title={title} description={description} crumbs={activeCategory ? [{ name: 'Blog', href: '/blog/' }] : []}>
|
|
26
26
|
<PageHeader title={title} intro={intro}>
|
|
27
|
-
<nav aria-label={siteT.theme.tags} class="-mx-5 mt-8
|
|
28
|
-
<ul class="flex gap-2 overflow-x-auto px-5 pb-2 [scrollbar-width:none]
|
|
27
|
+
<nav aria-label={siteT.theme.tags} class="-mx-5 mt-8 medium:mx-0">
|
|
28
|
+
<ul class="flex gap-2 overflow-x-auto px-5 pb-2 [scrollbar-width:none] medium:flex-wrap medium:overflow-visible medium:px-0">
|
|
29
29
|
<li class="shrink-0">
|
|
30
30
|
<Chip kind="filter" href="/blog/" label={siteT.theme.allPosts} selected={!activeCategory} className="shrink-0" />
|
|
31
31
|
</li>
|
|
@@ -13,6 +13,6 @@ interface Props {
|
|
|
13
13
|
const { posts, class: className } = Astro.props;
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
<Container class={className ?? (posts.length ? 'mt-10
|
|
16
|
+
<Container class={className ?? (posts.length ? 'mt-10 medium:mt-14' : 'mt-10')}>
|
|
17
17
|
<BlogPostsView posts={posts.map(postViewOf)} />
|
|
18
18
|
</Container>
|
|
@@ -6,6 +6,7 @@ import PostList from '@theme/components/PostList';
|
|
|
6
6
|
import PostMeta from '@theme/components/PostMeta';
|
|
7
7
|
import type { PostView } from '@theme/components/posts';
|
|
8
8
|
import { Link } from '@morphemecms/cms/src/standard/view';
|
|
9
|
+
import { BREAKPOINTS } from '@morphemecms/cms/lib/breakpoints.mjs';
|
|
9
10
|
import { siteT } from '@morphemecms/cms/src/i18n';
|
|
10
11
|
|
|
11
12
|
export default function BlogPosts({ posts }: { posts: PostView[] }) {
|
|
@@ -21,25 +22,27 @@ export default function BlogPosts({ posts }: { posts: PostView[] }) {
|
|
|
21
22
|
);
|
|
22
23
|
return (
|
|
23
24
|
<>
|
|
24
|
-
<Link href={featured.href} className="group grid items-center gap-6
|
|
25
|
+
<Link href={featured.href} className="group grid items-center gap-6 medium:gap-12 expanded:grid-cols-12">
|
|
25
26
|
{featured.image && (
|
|
26
|
-
<div className="overflow-hidden rounded-(--theme-picture-radius)
|
|
27
|
+
<div className="overflow-hidden rounded-(--theme-picture-radius) expanded:col-span-7">
|
|
27
28
|
<Img
|
|
28
29
|
image={featured.image}
|
|
29
30
|
alt={featured.imageAlt ?? ''}
|
|
30
31
|
fetchPriority="high"
|
|
31
32
|
className="aspect-[16/10] w-full object-cover [transition:scale_var(--motion-spatial-slow)] group-hover:scale-[1.03]"
|
|
32
|
-
sizes=
|
|
33
|
+
sizes={`(min-width: ${BREAKPOINTS.expanded}px) 55vw, calc(100vw - 40px)`}
|
|
33
34
|
/>
|
|
34
35
|
</div>
|
|
35
36
|
)}
|
|
36
|
-
<div className="
|
|
37
|
+
<div className="expanded:col-span-5">
|
|
37
38
|
<PostMeta post={featured} />
|
|
38
|
-
<h2 className="mt-2 type-headline-medium transition-colors group-hover:text-accent
|
|
39
|
+
<h2 className="mt-2 type-headline-medium transition-colors group-hover:text-accent medium:type-headline-large">
|
|
40
|
+
{featured.title}
|
|
41
|
+
</h2>
|
|
39
42
|
<p className="mt-3 text-muted">{featured.description}</p>
|
|
40
43
|
</div>
|
|
41
44
|
</Link>
|
|
42
|
-
{rest.length > 0 && <PostList posts={rest} className="mt-12
|
|
45
|
+
{rest.length > 0 && <PostList posts={rest} className="mt-12 medium:mt-16" />}
|
|
43
46
|
</>
|
|
44
47
|
);
|
|
45
48
|
}
|
|
@@ -6,6 +6,6 @@ type Props = HTMLAttributes<'section'> & { as?: 'section' | 'div' | 'header' };
|
|
|
6
6
|
const { as: Tag = 'section', class: className, ...rest } = Astro.props;
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
<Tag class:list={['mx-auto max-w-6xl px-5
|
|
9
|
+
<Tag class:list={['mx-auto max-w-6xl px-5 medium:px-8', className]} {...rest}>
|
|
10
10
|
<slot />
|
|
11
11
|
</Tag>
|
|
@@ -34,7 +34,7 @@ const necessary = category('necessary');
|
|
|
34
34
|
hidden
|
|
35
35
|
class:list={[
|
|
36
36
|
dialogClass,
|
|
37
|
-
'fixed inset-x-3 bottom-3 z-[42] max-h-[calc(100dvh-1.5rem)] max-w-md overflow-y-auto p-5
|
|
37
|
+
'fixed inset-x-3 bottom-3 z-[42] max-h-[calc(100dvh-1.5rem)] max-w-md overflow-y-auto p-5 medium:inset-x-auto medium:bottom-6 medium:left-6 medium:p-6',
|
|
38
38
|
]}
|
|
39
39
|
style="margin-bottom: env(safe-area-inset-bottom)"
|
|
40
40
|
>
|
|
@@ -16,6 +16,6 @@ interface Props {
|
|
|
16
16
|
const { type, props = {}, ...rest } = Astro.props;
|
|
17
17
|
---
|
|
18
18
|
|
|
19
|
-
<Container class="block-place mt-20
|
|
19
|
+
<Container class="block-place mt-20 medium:mt-28" data-reveal {...rest}>
|
|
20
20
|
<Block type={type} props={props} />
|
|
21
21
|
</Container>
|
|
@@ -21,13 +21,13 @@ const contactLinks = [
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
23
|
<footer class="md-footer">
|
|
24
|
-
<Container as="div" class="grid gap-10 py-12
|
|
25
|
-
<div class="
|
|
24
|
+
<Container as="div" class="grid gap-10 py-12 expanded:grid-cols-12 medium:py-16">
|
|
25
|
+
<div class="expanded:col-span-5">
|
|
26
26
|
<LogoMark class="block h-12 w-11 bg-accent" />
|
|
27
27
|
<p class="md-footer-name">{site.name}</p>
|
|
28
28
|
<p class="md-footer-text">{footer.text}</p>
|
|
29
29
|
</div>
|
|
30
|
-
<div class="
|
|
30
|
+
<div class="expanded:col-span-4">
|
|
31
31
|
<p class="md-footer-heading">{footer.contactHeading}</p>
|
|
32
32
|
<ul class="md-footer-list">
|
|
33
33
|
{contactLinks.map((c) => (
|
|
@@ -47,7 +47,7 @@ const contactLinks = [
|
|
|
47
47
|
))}
|
|
48
48
|
</ul>
|
|
49
49
|
</div>
|
|
50
|
-
<div class="md-footer-column
|
|
50
|
+
<div class="md-footer-column expanded:col-span-3">
|
|
51
51
|
<slot name="footer-column">
|
|
52
52
|
<p class="md-footer-heading">{footer.linksHeading}</p>
|
|
53
53
|
<ul class="md-footer-list">
|
|
@@ -61,7 +61,7 @@ const contactLinks = [
|
|
|
61
61
|
</ul>
|
|
62
62
|
</slot>
|
|
63
63
|
</div>
|
|
64
|
-
<div class="md-footer-bottom
|
|
64
|
+
<div class="md-footer-bottom expanded:col-span-12">
|
|
65
65
|
<span>
|
|
66
66
|
© {new Date().getFullYear()} {site.name}
|
|
67
67
|
{site.cvr && <> · CVR {site.cvr}</>}
|
|
@@ -26,7 +26,7 @@ const fab = !current.startsWith(site.bookingPath) && current !== '/tak/';
|
|
|
26
26
|
<header data-header class:list={[topAppBarClass, 'group/header sticky top-0 z-[43]']}>
|
|
27
27
|
<Container as="div" data-header-row class="flex h-16 items-center gap-1">
|
|
28
28
|
{navShown && (
|
|
29
|
-
<div class="-ml-2 mr-1
|
|
29
|
+
<div class="-ml-2 mr-1 large:hidden large:group-data-crowded/header:block">
|
|
30
30
|
<MobileMenu
|
|
31
31
|
client:interact
|
|
32
32
|
items={nav}
|
|
@@ -48,12 +48,12 @@ const fab = !current.startsWith(site.bookingPath) && current !== '/tak/';
|
|
|
48
48
|
/>
|
|
49
49
|
</div>
|
|
50
50
|
)}
|
|
51
|
-
<a href="/" class="md-top-app-bar-title mr-auto
|
|
51
|
+
<a href="/" class="md-top-app-bar-title mr-auto large:shrink-0 large:whitespace-nowrap">
|
|
52
52
|
<Logo />
|
|
53
53
|
</a>
|
|
54
54
|
|
|
55
55
|
{navShown && (
|
|
56
|
-
<nav aria-label={siteT.theme.mainMenu} class="hidden shrink-0
|
|
56
|
+
<nav aria-label={siteT.theme.mainMenu} class="hidden shrink-0 large:block large:group-data-crowded/header:hidden">
|
|
57
57
|
<ul class="flex items-center gap-1">
|
|
58
58
|
{nav.map((item, i) => (
|
|
59
59
|
<li class="group relative flex items-center" data-nav-item>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
// An icon by its name, drawn by the same Svg as the blocks and the editor (@morphemecms/cms/src/icon): the theme's own
|
|
3
|
-
// (icons/<name>.svg), else the icon pack in use's, else Phosphor's
|
|
4
|
-
// (MISSING), which check:screens finds on the built pages.
|
|
3
|
+
// (icons/<name>.svg), else the icon pack in use's, else Phosphor's, else Material Symbols' by its Material name (listed by
|
|
4
|
+
// check:screens); one none has as the question mark (MISSING), which check:screens finds on the built pages.
|
|
5
5
|
import { Svg } from '@morphemecms/cms/src/icon';
|
|
6
6
|
|
|
7
7
|
interface Props {
|
|
@@ -9,16 +9,18 @@
|
|
|
9
9
|
import { useEffect, useRef, useState } from 'react';
|
|
10
10
|
import { createPortal } from 'react-dom';
|
|
11
11
|
import { AnimatePresence, motion, useReducedMotion } from 'motion/react';
|
|
12
|
-
import { Svg } from '@morphemecms/cms/src/icon';
|
|
13
12
|
import { motionSpring } from '@morphemecms/cms/lib/motion';
|
|
14
13
|
import IconButton from '@theme/ui/IconButton';
|
|
15
14
|
import { ExtendedFab } from '@theme/ui/Fab';
|
|
16
15
|
import {
|
|
17
16
|
NavigationDrawerItem,
|
|
18
17
|
NavigationDrawerRow,
|
|
18
|
+
NavigationDrawerSection,
|
|
19
19
|
NavigationDrawerSubitem,
|
|
20
20
|
NavigationDrawerToggle,
|
|
21
|
+
focusNavigationDrawerItem,
|
|
21
22
|
navigationDrawerClass,
|
|
23
|
+
navigationDrawerKeys,
|
|
22
24
|
navigationDrawerScrimClass,
|
|
23
25
|
} from '@theme/ui/NavigationDrawer';
|
|
24
26
|
|
|
@@ -54,7 +56,6 @@ export default function MobileMenu({
|
|
|
54
56
|
const [mounted, setMounted] = useState(false);
|
|
55
57
|
const reduce = useReducedMotion();
|
|
56
58
|
const openButton = useRef<HTMLButtonElement>(null);
|
|
57
|
-
const closeButton = useRef<HTMLButtonElement>(null);
|
|
58
59
|
const drawer = useRef<HTMLDivElement>(null);
|
|
59
60
|
// The scheme's springs (only used in the browser, where the menu opens): in at the default spatial spring, out at the
|
|
60
61
|
// fast one, and the scrim with the effects'.
|
|
@@ -65,14 +66,21 @@ export default function MobileMenu({
|
|
|
65
66
|
fadeOut: motionSpring('effects', 'fast'),
|
|
66
67
|
}));
|
|
67
68
|
|
|
68
|
-
|
|
69
|
+
// The edge it comes from is the start edge: it slides in from the left, and from the right in right-to-left languages.
|
|
70
|
+
const [away, setAway] = useState('-100%');
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
setMounted(true);
|
|
73
|
+
setAway(getComputedStyle(document.documentElement).direction === 'rtl' ? '100%' : '-100%');
|
|
74
|
+
}, []);
|
|
69
75
|
|
|
70
76
|
useEffect(() => {
|
|
71
77
|
if (!open) return;
|
|
72
78
|
const root = document.documentElement;
|
|
73
79
|
const prevOverflow = root.style.overflow;
|
|
74
80
|
root.style.overflow = 'hidden';
|
|
75
|
-
|
|
81
|
+
// The focus goes to the first item; the arrow keys, Home and End move between them.
|
|
82
|
+
if (drawer.current) focusNavigationDrawerItem(drawer.current);
|
|
83
|
+
const stopKeys = drawer.current ? navigationDrawerKeys(drawer.current) : undefined;
|
|
76
84
|
|
|
77
85
|
const onKey = (e: KeyboardEvent) => {
|
|
78
86
|
if (e.key === 'Escape') setOpen(false);
|
|
@@ -92,6 +100,7 @@ export default function MobileMenu({
|
|
|
92
100
|
};
|
|
93
101
|
document.addEventListener('keydown', onKey);
|
|
94
102
|
return () => {
|
|
103
|
+
stopKeys?.();
|
|
95
104
|
document.removeEventListener('keydown', onKey);
|
|
96
105
|
// Closed by "Book en tid": the booking sheet (a modal dialog) is open now and keeps the page
|
|
97
106
|
// still and the focus itself.
|
|
@@ -135,10 +144,10 @@ export default function MobileMenu({
|
|
|
135
144
|
role="dialog"
|
|
136
145
|
aria-modal="true"
|
|
137
146
|
aria-label={texts.drawer}
|
|
138
|
-
className={`${navigationDrawerClass} absolute inset-y-0
|
|
139
|
-
initial={reduce ? false : { x:
|
|
147
|
+
className={`${navigationDrawerClass} absolute inset-y-0 start-0`}
|
|
148
|
+
initial={reduce ? false : { x: away }}
|
|
140
149
|
animate={{ x: 0, transition: reduce ? { duration: 0 } : spring.enter }}
|
|
141
|
-
exit={reduce ? undefined : { x:
|
|
150
|
+
exit={reduce ? undefined : { x: away, transition: spring.leave }}
|
|
142
151
|
>
|
|
143
152
|
<div className="md-drawer-head">
|
|
144
153
|
<span aria-hidden="true" className="logo-mark h-10 w-9 shrink-0 bg-accent" />
|
|
@@ -146,7 +155,7 @@ export default function MobileMenu({
|
|
|
146
155
|
<p className="md-drawer-name">{name}</p>
|
|
147
156
|
<p className="md-drawer-role">{role}</p>
|
|
148
157
|
</div>
|
|
149
|
-
<IconButton
|
|
158
|
+
<IconButton icon="x" label={texts.close} onClick={() => setOpen(false)} />
|
|
150
159
|
</div>
|
|
151
160
|
|
|
152
161
|
<ExtendedFab
|
|
@@ -158,61 +167,63 @@ export default function MobileMenu({
|
|
|
158
167
|
onClick={() => setOpen(false)}
|
|
159
168
|
/>
|
|
160
169
|
|
|
161
|
-
<
|
|
162
|
-
<
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
<
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
{item.label}
|
|
172
|
-
</NavigationDrawerItem>
|
|
173
|
-
{item.children && (
|
|
174
|
-
<NavigationDrawerToggle
|
|
175
|
-
label={texts.subpages[i]}
|
|
176
|
-
expanded={expanded === item.href}
|
|
177
|
-
onClick={() => setExpanded(expanded === item.href ? null : item.href)}
|
|
178
|
-
aria-controls={`sub-${item.href}`}
|
|
179
|
-
/>
|
|
180
|
-
)}
|
|
181
|
-
</NavigationDrawerRow>
|
|
182
|
-
<AnimatePresence initial={false}>
|
|
183
|
-
{item.children && expanded === item.href && (
|
|
184
|
-
<motion.ul
|
|
185
|
-
id={`sub-${item.href}`}
|
|
186
|
-
className="overflow-hidden"
|
|
187
|
-
initial={reduce ? false : { height: 0, opacity: 0 }}
|
|
188
|
-
animate={{ height: 'auto', opacity: 1, transition: spring.enter }}
|
|
189
|
-
exit={reduce ? undefined : { height: 0, opacity: 0, transition: spring.leave }}
|
|
170
|
+
<NavigationDrawerSection>
|
|
171
|
+
<nav aria-label={texts.menu}>
|
|
172
|
+
<ul>
|
|
173
|
+
{items.map((item, i) => (
|
|
174
|
+
<li key={item.href}>
|
|
175
|
+
<NavigationDrawerRow data-active={holdsCurrent(item) || undefined}>
|
|
176
|
+
<NavigationDrawerItem
|
|
177
|
+
href={item.href}
|
|
178
|
+
onClick={() => setOpen(false)}
|
|
179
|
+
aria-current={current === item.href ? 'page' : undefined}
|
|
190
180
|
>
|
|
191
|
-
{item.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
181
|
+
{item.label}
|
|
182
|
+
</NavigationDrawerItem>
|
|
183
|
+
{item.children && (
|
|
184
|
+
<NavigationDrawerToggle
|
|
185
|
+
label={texts.subpages[i]}
|
|
186
|
+
expanded={expanded === item.href}
|
|
187
|
+
onClick={() => setExpanded(expanded === item.href ? null : item.href)}
|
|
188
|
+
aria-controls={`sub-${item.href}`}
|
|
189
|
+
/>
|
|
190
|
+
)}
|
|
191
|
+
</NavigationDrawerRow>
|
|
192
|
+
<AnimatePresence initial={false}>
|
|
193
|
+
{item.children && expanded === item.href && (
|
|
194
|
+
<motion.ul
|
|
195
|
+
id={`sub-${item.href}`}
|
|
196
|
+
className="overflow-hidden"
|
|
197
|
+
initial={reduce ? false : { height: 0, opacity: 0 }}
|
|
198
|
+
animate={{ height: 'auto', opacity: 1, transition: spring.enter }}
|
|
199
|
+
exit={reduce ? undefined : { height: 0, opacity: 0, transition: spring.leave }}
|
|
200
|
+
>
|
|
201
|
+
{item.children.map((child) => (
|
|
202
|
+
<li key={child.href}>
|
|
203
|
+
<NavigationDrawerSubitem
|
|
204
|
+
href={child.href}
|
|
205
|
+
active={current === child.href}
|
|
206
|
+
onClick={() => setOpen(false)}
|
|
207
|
+
aria-current={current === child.href ? 'page' : undefined}
|
|
208
|
+
>
|
|
209
|
+
{child.label}
|
|
210
|
+
</NavigationDrawerSubitem>
|
|
211
|
+
</li>
|
|
212
|
+
))}
|
|
213
|
+
</motion.ul>
|
|
214
|
+
)}
|
|
215
|
+
</AnimatePresence>
|
|
216
|
+
</li>
|
|
217
|
+
))}
|
|
218
|
+
</ul>
|
|
219
|
+
</nav>
|
|
220
|
+
</NavigationDrawerSection>
|
|
210
221
|
|
|
211
|
-
<
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
</
|
|
222
|
+
<NavigationDrawerSection>
|
|
223
|
+
<NavigationDrawerItem href={phoneHref} icon="phone">
|
|
224
|
+
{call} {phone}
|
|
225
|
+
</NavigationDrawerItem>
|
|
226
|
+
</NavigationDrawerSection>
|
|
216
227
|
</motion.div>
|
|
217
228
|
</div>
|
|
218
229
|
)}
|
|
@@ -13,8 +13,8 @@ const isActive = (href: string) => current === href || (href !== '/' && current.
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
{mobileNav.length > 0 && (
|
|
16
|
-
<nav aria-label={siteT.theme.mobileMenu} data-mobile-nav class="
|
|
17
|
-
<ul class:list={[tabsClass, 'relative mx-auto max-w-6xl px-1
|
|
16
|
+
<nav aria-label={siteT.theme.mobileMenu} data-mobile-nav class="large:hidden large:group-data-crowded/header:block">
|
|
17
|
+
<ul class:list={[tabsClass, 'relative mx-auto max-w-6xl px-1 medium:px-4']}>
|
|
18
18
|
{mobileNav.map((item) => (
|
|
19
19
|
<li>
|
|
20
20
|
<a href={item.href} class={tabClass} aria-current={isActive(item.href) ? 'page' : undefined}>
|
|
@@ -11,10 +11,10 @@ interface Props {
|
|
|
11
11
|
const { title, intro } = Astro.props;
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
<Container as="header" class="pt-8
|
|
14
|
+
<Container as="header" class="pt-8 medium:pt-14">
|
|
15
15
|
<h1 class="theme-title max-w-[18ch]">{title}</h1>
|
|
16
16
|
{intro && (
|
|
17
|
-
<p class="type-body-large
|
|
17
|
+
<p class="type-body-large medium:type-title-large mt-4 max-w-[52ch] text-muted">
|
|
18
18
|
<Inline text={intro} />
|
|
19
19
|
</p>
|
|
20
20
|
)}
|
|
@@ -14,7 +14,7 @@ const { title, intro, class: className, id } = Astro.props;
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
<Container class={className} id={id} data-reveal>
|
|
17
|
-
{title && <h2 class="type-headline-large
|
|
17
|
+
{title && <h2 class="type-headline-large medium:type-display-small">{title}</h2>}
|
|
18
18
|
{intro && (
|
|
19
19
|
<p class="mt-3 max-w-[52ch] text-muted">
|
|
20
20
|
<Inline text={intro} />
|
|
@@ -13,11 +13,11 @@ export default function PopupButton({ button }: { button?: PopupButtonView }) {
|
|
|
13
13
|
return (
|
|
14
14
|
<div className="block-buttons mt-6">
|
|
15
15
|
{'file' in button ? (
|
|
16
|
-
<Button href={button.file.href} icon="download-simple" download="" className="w-full
|
|
16
|
+
<Button href={button.file.href} icon="download-simple" download="" className="w-full medium:w-auto">
|
|
17
17
|
{button.file.label}
|
|
18
18
|
</Button>
|
|
19
19
|
) : (
|
|
20
|
-
<Buttons buttons={button.buttons} className="w-full
|
|
20
|
+
<Buttons buttons={button.buttons} className="w-full medium:w-auto" />
|
|
21
21
|
)}
|
|
22
22
|
</div>
|
|
23
23
|
);
|
|
@@ -27,12 +27,12 @@ export default function PopupView({ popup, Part, part }: { popup: PopupBoxView;
|
|
|
27
27
|
srcSet={popup.image.srcset}
|
|
28
28
|
width={popup.image.width}
|
|
29
29
|
height={popup.image.height}
|
|
30
|
-
sizes="(
|
|
30
|
+
sizes="min(28rem, calc(100vw - 2rem))"
|
|
31
31
|
alt=""
|
|
32
32
|
className="block aspect-[3/2] w-full bg-tint object-cover"
|
|
33
33
|
/>
|
|
34
34
|
)}
|
|
35
|
-
<div className="p-6
|
|
35
|
+
<div className="p-6 medium:p-8">
|
|
36
36
|
<h2 id={`popup-${popup.slug}`} className={popup.image ? 'type-headline-small' : 'pr-12 type-headline-small'}>
|
|
37
37
|
{popup.heading}
|
|
38
38
|
</h2>
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import Img from '@theme/components/Img';
|
|
5
5
|
import PostMeta from '@theme/components/PostMeta';
|
|
6
6
|
import type { PostView } from '@theme/components/posts';
|
|
7
|
+
import { BREAKPOINTS } from '@morphemecms/cms/lib/breakpoints.mjs';
|
|
7
8
|
import { Link, useOnSite } from '@morphemecms/cms/src/standard/view';
|
|
8
9
|
|
|
9
10
|
// Shows the number in data-random-posts of the posts in the list just before it, picked at random.
|
|
@@ -29,16 +30,19 @@ export default function PostList({
|
|
|
29
30
|
const onSite = useOnSite();
|
|
30
31
|
return (
|
|
31
32
|
<>
|
|
32
|
-
<ul
|
|
33
|
+
<ul
|
|
34
|
+
className={['grid gap-x-12 expanded:grid-cols-2', className].filter(Boolean).join(' ')}
|
|
35
|
+
data-random-posts={random ? count : undefined}
|
|
36
|
+
>
|
|
33
37
|
{posts.map((post, i) => (
|
|
34
38
|
<li key={post.href || post.title} hidden={random && i >= count} className="border-t border-line">
|
|
35
|
-
<Link href={post.href} className="group grid grid-cols-[5.5rem_1fr] gap-4 py-5
|
|
39
|
+
<Link href={post.href} className="group grid grid-cols-[5.5rem_1fr] gap-4 py-5 medium:grid-cols-[8rem_1fr] medium:gap-5">
|
|
36
40
|
{post.image ? (
|
|
37
41
|
<Img
|
|
38
42
|
image={post.image}
|
|
39
43
|
alt=""
|
|
40
44
|
className="theme-post-picture aspect-square w-full object-cover"
|
|
41
|
-
sizes=
|
|
45
|
+
sizes={`(min-width: ${BREAKPOINTS.medium}px) 128px, 88px`}
|
|
42
46
|
/>
|
|
43
47
|
) : (
|
|
44
48
|
<span className="theme-post-picture aspect-square bg-tint" />
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
// is in it, as a video written in the text, packages/editor/lib/video.mjs); a block hidden in the editor is left
|
|
6
6
|
// out (splitBlocks). The HTML comes as `html`, or as the default slot (rendered Markdown). `path`: the
|
|
7
7
|
// page's address, for the testimonials' label. `preview`: a new version of a page (/ny/), whose topics
|
|
8
|
-
// show the opening of the new versions too. Each block gets its type, and its shared texts as `texts` (blockTexts).
|
|
8
|
+
// show the opening of the new versions too. A section with a colour is drawn as <section class="text-section text-section-<color>"> around its parts (lib/text-sections.mjs). Each block gets its type, and its shared texts as `texts` (blockTexts).
|
|
9
9
|
import { splitBlocks } from '@morphemecms/cms/lib/blocks.mjs';
|
|
10
|
+
import { sectionClass, sectionsOf } from '@morphemecms/cms/lib/text-sections.mjs';
|
|
10
11
|
import { blockSites } from '@morphemecms/cms/src/standard/sites';
|
|
11
12
|
import { blockTexts } from '@morphemecms/cms/site/site';
|
|
12
13
|
|
|
@@ -14,15 +15,29 @@ interface Props {
|
|
|
14
15
|
html?: string;
|
|
15
16
|
path?: string;
|
|
16
17
|
preview?: boolean;
|
|
18
|
+
// false: the text only, its blocks left as written (a blog post's text, which draws none).
|
|
19
|
+
blocks?: boolean;
|
|
17
20
|
}
|
|
18
|
-
const { path, preview } = Astro.props;
|
|
21
|
+
const { path, preview, blocks = true } = Astro.props;
|
|
19
22
|
const html = Astro.props.html ?? (await Astro.slots.render('default'));
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
// A section with a colour (lib/text-sections.mjs) is a run of its own, drawn as a panel around its parts (blocks.css).
|
|
25
|
+
let n = 0;
|
|
26
|
+
const runs = sectionsOf(html).map((run) => ({
|
|
27
|
+
color: run.color,
|
|
28
|
+
parts: splitBlocks(run.html, blocks ? Object.keys(blockSites) : []).map((p) => ({ ...p, index: n++ })),
|
|
29
|
+
}));
|
|
22
30
|
---
|
|
23
31
|
|
|
24
|
-
{
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
{runs.map((run) => {
|
|
33
|
+
const Run = run.color ? 'section' : Fragment;
|
|
34
|
+
return (
|
|
35
|
+
<Run {...(run.color ? { class: sectionClass(run.color) } : {})}>
|
|
36
|
+
{run.parts.map((p) => {
|
|
37
|
+
if (p.html !== undefined) return <Fragment set:html={p.html} />;
|
|
38
|
+
const Block = blockSites[p.type];
|
|
39
|
+
return <Block type={p.type} props={p.props} index={p.index} path={path} preview={preview} texts={blockTexts[p.type]} />;
|
|
40
|
+
})}
|
|
41
|
+
</Run>
|
|
42
|
+
);
|
|
28
43
|
})}
|