@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// The site's Worker's modules (packages/editor/worker/) for the checks, built as wrangler builds them: with the
|
|
2
2
|
// aliases in wrangler.jsonc (`@site/config`, `@site/worker`), in one bundle, so they share what they keep, as in the
|
|
3
|
-
// Worker. Used by packages/editor/scripts/check-worker.mjs and packages/editor/scripts/check-consent.mjs.
|
|
3
|
+
// Worker (`cloudflare:workers`, which only the runtime has, is an empty stand-in). Used by packages/editor/scripts/check-worker.mjs and packages/editor/scripts/check-consent.mjs.
|
|
4
4
|
import { mkdtempSync } from 'node:fs';
|
|
5
5
|
import { tmpdir } from 'node:os';
|
|
6
6
|
import { join } from 'node:path';
|
|
@@ -27,6 +27,16 @@ export async function workerModules(...names) {
|
|
|
27
27
|
platform: 'node',
|
|
28
28
|
outfile,
|
|
29
29
|
alias: Object.fromEntries(Object.entries(alias).map(([from, to]) => [from, join(ROOT, to)])),
|
|
30
|
+
// `cloudflare:workers` only exists in the Worker's runtime (the app Cookiescanner's Playwright asks for its `env`).
|
|
31
|
+
plugins: [
|
|
32
|
+
{
|
|
33
|
+
name: 'cloudflare-workers-stub',
|
|
34
|
+
setup(b) {
|
|
35
|
+
b.onResolve({ filter: /^cloudflare:workers$/ }, () => ({ path: 'cloudflare:workers', namespace: 'stub' }));
|
|
36
|
+
b.onLoad({ filter: /.*/, namespace: 'stub' }, () => ({ contents: 'export const env = {};', loader: 'js' }));
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
],
|
|
30
40
|
logLevel: 'silent',
|
|
31
41
|
});
|
|
32
42
|
const bundle = await import(pathToFileURL(outfile).href);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** The problems on one line: each a hand-written width or an old breakpoint name (empty when the line is fine).
|
|
2
|
+
* @param {string} line
|
|
3
|
+
* @returns {string[]} */
|
|
4
|
+
export function lineProblems(line: string): string[];
|
|
5
|
+
/** Every line, in the CMS's code (theme, editor, site, lib) and the site's themes and apps, that has a breakpoint of its own. */
|
|
6
|
+
export function breakpointProblems(root?: string): any[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// The site keeps to Material 3's breakpoints (lib/breakpoints.mjs, --breakpoint-* in theme/styles/base.css): a width in a
|
|
2
|
+
// media query (@media, matchMedia, useMedia, sizes), a variant with a width of its own or Tailwind's old breakpoint names is a problem
|
|
3
|
+
// (lineProblems for one line, breakpointProblems for the tree, in check:content), in the CMS's code (also its defaults)
|
|
4
|
+
// and in the site's themes, apps and own files.
|
|
5
|
+
import { readFileSync, readdirSync, existsSync } from 'node:fs';
|
|
6
|
+
import { join, relative } from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const own = fileURLToPath(new URL('..', import.meta.url));
|
|
10
|
+
const CODE = /\.(css|astro|tsx|ts|js|mjs)$/;
|
|
11
|
+
const RULES = [
|
|
12
|
+
[
|
|
13
|
+
/\(\s*(min|max)-width\s*:\s*\d|\(\s*width\s*(>=|<=|>|<)\s*\d|\d[\w.]*\s*(<=|<)\s*width\b/,
|
|
14
|
+
'en bredde i en medieforespørgsel (@media, matchMedia, useMedia, sizes); brug theme(--breakpoint-medium), -expanded, -large eller -extra-large i CSS og atLeast() fra lib/breakpoints.mjs i scripts',
|
|
15
|
+
],
|
|
16
|
+
[
|
|
17
|
+
/(^|[\s"'`{:])(min|max)-\[/,
|
|
18
|
+
'et brudpunkt skrevet som en vilkårlig variant (min eller max med en bredde i klammer); brug medium:, expanded:, large: eller extra-large:',
|
|
19
|
+
],
|
|
20
|
+
[/(^|[\s"'`{])(max-)?(sm|md|lg|xl|2xl):[\w[-]/, 'Tailwinds gamle brudpunkt; brug medium:, expanded:, large: eller extra-large:'],
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
function files(dir) {
|
|
24
|
+
if (!existsSync(dir)) return [];
|
|
25
|
+
return readdirSync(dir, { recursive: true, withFileTypes: true })
|
|
26
|
+
.filter((e) => e.isFile() && CODE.test(e.name) && !e.parentPath.includes('node_modules') && !/\.test\.mjs$/.test(e.name))
|
|
27
|
+
.map((e) => join(e.parentPath, e.name));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** The problems on one line: each a hand-written width or an old breakpoint name (empty when the line is fine).
|
|
31
|
+
* @param {string} line
|
|
32
|
+
* @returns {string[]} */
|
|
33
|
+
export function lineProblems(line) {
|
|
34
|
+
// A container query is about the box it sits in, not the window.
|
|
35
|
+
if (line.includes('@container')) return [];
|
|
36
|
+
return RULES.filter(([re]) => re.test(line)).map(([, what]) => what);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Every line, in the CMS's code (theme, editor, site, lib) and the site's themes and apps, that has a breakpoint of its own. */
|
|
40
|
+
export function breakpointProblems(root = process.cwd()) {
|
|
41
|
+
const dirs = ['theme', 'src', 'site', 'lib', 'pages', 'defaults']
|
|
42
|
+
.map((d) => join(own, d))
|
|
43
|
+
.concat(['src/themes', 'src/apps', 'src/site'].map((d) => join(root, d)));
|
|
44
|
+
const problems = [];
|
|
45
|
+
for (const file of dirs.flatMap(files))
|
|
46
|
+
readFileSync(file, 'utf8')
|
|
47
|
+
.split('\n')
|
|
48
|
+
.forEach((line, i) => {
|
|
49
|
+
for (const what of lineProblems(line)) problems.push(`${relative(root, file)}:${i + 1}: ${what} (Material 3's brudpunkter).`);
|
|
50
|
+
});
|
|
51
|
+
return problems;
|
|
52
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Tests of the breakpoint check (breakpoints.mjs): which hand-written widths lineProblems flags and which lines it lets be.
|
|
2
|
+
import { test } from 'node:test';
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import { lineProblems } from './breakpoints.mjs';
|
|
5
|
+
|
|
6
|
+
const flagged = [
|
|
7
|
+
'@media (min-width: 48rem) {',
|
|
8
|
+
'@media (max-width:640px) and (hover: hover) {',
|
|
9
|
+
"const wide = matchMedia('(min-width: 48rem)').matches;",
|
|
10
|
+
"useMedia('(min-width: 80rem)')",
|
|
11
|
+
'sizes="(min-width: 640px) 50vw, 100vw"',
|
|
12
|
+
"matchMedia('(width >= 48rem)')",
|
|
13
|
+
'@media (width < 600px) {',
|
|
14
|
+
'@media (width <= 40rem) {',
|
|
15
|
+
'@media (width > 40rem) {',
|
|
16
|
+
'@media (40rem <= width) {',
|
|
17
|
+
'<div class="min-[700px]:flex">',
|
|
18
|
+
'<div class="max-[700px]:hidden">',
|
|
19
|
+
'<div class="md:flex">',
|
|
20
|
+
'<div class="max-lg:hidden">',
|
|
21
|
+
];
|
|
22
|
+
const fine = [
|
|
23
|
+
'@container (width >= 34rem) {',
|
|
24
|
+
'@container navigation-bar (min-width: 37.5rem) {',
|
|
25
|
+
'@media (max-height: 30rem) {',
|
|
26
|
+
'@media (prefers-reduced-motion: reduce) {',
|
|
27
|
+
'@media print {',
|
|
28
|
+
'@media (hover: hover) {',
|
|
29
|
+
'sizes={`(min-width: ${BREAKPOINTS.expanded}px) 50vw, 100vw`}',
|
|
30
|
+
"matchMedia(atLeast('medium'))",
|
|
31
|
+
'<div class="min-h-[10rem] min-w-0 medium:flex">',
|
|
32
|
+
'<div class="max-w-[20rem] expanded:grid">',
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
for (const line of flagged) test(`flags ${line}`, () => assert.ok(lineProblems(line).length > 0));
|
|
36
|
+
for (const line of fine) test(`lets ${line} be`, () => assert.deepEqual(lineProblems(line), []));
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Each folder whose files (by their name without the last extension) or folders have the same name but for case:
|
|
2
|
+
* Redirects.tsx beside redirects.ts, View.tsx beside view.ts. Img.astro beside Img.tsx is the same name, so not one. */
|
|
3
|
+
export function casingProblems(paths: any): string[];
|
package/site/casing.mjs
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Names in one folder that differ only in case (`npm run check:content`): Windows and macOS do not tell them apart, so
|
|
2
|
+
// './Redirects' would open redirects.ts there (a .ts is tried before a .tsx) and the check and the build break, though
|
|
3
|
+
// Linux finds the right file. Exposes casingProblems, given the repository's files (git ls-files).
|
|
4
|
+
|
|
5
|
+
/** Each folder whose files (by their name without the last extension) or folders have the same name but for case:
|
|
6
|
+
* Redirects.tsx beside redirects.ts, View.tsx beside view.ts. Img.astro beside Img.tsx is the same name, so not one. */
|
|
7
|
+
export function casingProblems(paths) {
|
|
8
|
+
const names = new Map();
|
|
9
|
+
for (const path of paths) {
|
|
10
|
+
const parts = path.split('/');
|
|
11
|
+
parts.forEach((part, i) => {
|
|
12
|
+
const folder = parts.slice(0, i).join('/');
|
|
13
|
+
const name = i === parts.length - 1 ? part.replace(/(.)\.[^.]+$/, '$1') : part;
|
|
14
|
+
const key = `${folder}/${name.toLowerCase()}`;
|
|
15
|
+
if (!names.has(key)) names.set(key, { folder, spellings: new Map() });
|
|
16
|
+
const spellings = names.get(key).spellings;
|
|
17
|
+
if (!spellings.has(name)) spellings.set(name, i === parts.length - 1 ? part : `${part}/`);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return [...names.values()]
|
|
21
|
+
.filter(({ spellings }) => spellings.size > 1)
|
|
22
|
+
.map(
|
|
23
|
+
({ folder, spellings }) =>
|
|
24
|
+
`${folder || '.'}/: ${[...spellings.values()].join(' og ')} har samme navn, når store og små bogstaver ses som ens (Windows og macOS gør det). Lad komponenten beholde sit navn, og giv filen ved siden af sin rolle i navnet, fx redirectData.ts (se CLAUDE.md).`,
|
|
25
|
+
);
|
|
26
|
+
}
|
package/site/content.config.ts
CHANGED
|
@@ -56,6 +56,8 @@ const pages = defineCollection({
|
|
|
56
56
|
.regex(/^\/.*\/$/, 'path skal starte og slutte med /')
|
|
57
57
|
.optional(),
|
|
58
58
|
description: z.string().optional().default(''),
|
|
59
|
+
// Tags chosen in the editor, not shown on the page.
|
|
60
|
+
categories: z.array(z.string()).optional().default([]),
|
|
59
61
|
order: z.number().optional().default(0),
|
|
60
62
|
...status,
|
|
61
63
|
// Google title and description (the <title> and meta description). Empty: built from the title.
|
package/site/content.ts
CHANGED
|
@@ -4,10 +4,11 @@ import { displayTitle } from './text';
|
|
|
4
4
|
import { isPreview } from './noindex.mjs';
|
|
5
5
|
import { stateOf } from '@morphemecms/cms/lib/status.mjs';
|
|
6
6
|
import { pageH1 } from '@morphemecms/cms/src/sections.mjs';
|
|
7
|
+
import { withoutH1 } from '@morphemecms/cms/lib/without-h1.mjs';
|
|
7
8
|
|
|
8
9
|
// From text.ts, which the editor uses too (it has no content collections).
|
|
9
10
|
export { displayTitle, openingText } from './text';
|
|
10
|
-
export { stateOf };
|
|
11
|
+
export { stateOf, withoutH1 };
|
|
11
12
|
|
|
12
13
|
export type Post = CollectionEntry<'blog'>;
|
|
13
14
|
// Every page has a path: its own, or /<file name>/ for pages created in the editor.
|
|
@@ -89,9 +90,6 @@ export const pageHeading = (page: Page) => pageH1(page.body ?? '').heading ?? di
|
|
|
89
90
|
* for the layout to draw in its place; else undefined, and the layout draws pageHeading. */
|
|
90
91
|
export const pageHeadingHtml = (page: Page): string | undefined => pageH1(page.body ?? '').html;
|
|
91
92
|
|
|
92
|
-
/** A page's text as HTML without its H1 at the top, which the layout draws in its own place (above the picture). */
|
|
93
|
-
export const withoutH1 = (html: string) => html.replace(/^\s*<h1\b[^>]*>[\s\S]*?<\/h1>\s*/, '');
|
|
94
|
-
|
|
95
93
|
/** Anchor for a testimonial on the testimonials page, e.g. "marie-louise-eriksen". */
|
|
96
94
|
export const testimonialId = (t: { name: string }) =>
|
|
97
95
|
t.name
|
package/site/defineSite.d.mts
CHANGED
package/site/defineSite.mjs
CHANGED
|
@@ -125,6 +125,9 @@ const STANDARD = {
|
|
|
125
125
|
/** Which pages are the front page, the blog page and the 404 page: `{ "front": "<its address>", "blog": …, "notFound": … }`
|
|
126
126
|
* ("Indstillinger" › "Udseende" › "Standardsider", defaults/standardPages.ts). */
|
|
127
127
|
standardPages: 'src/data/standard-pages.json',
|
|
128
|
+
/** The folder of the file records, one `<id>.json` per file in Filer that has tags (`{ src, categories, removed }`,
|
|
129
|
+
* src/fileRecords.mjs): what a file is tagged with and which tags were removed from it. */
|
|
130
|
+
fileRecords: 'src/data/files',
|
|
128
131
|
};
|
|
129
132
|
|
|
130
133
|
/** @typedef {SiteOwn & SiteChoices & typeof STANDARD} SiteConfig */
|
package/site/home.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// e.g. a theme's components/home/), with the text above it that is its own (its lead), and the rest of the text
|
|
5
5
|
// as sections of text ("text": a heading and Markdown). The types below are the standard blocks'; an app's block is a
|
|
6
6
|
// section too, by its own type, which the theme that draws it types itself (e.g. its components/home/sections.ts).
|
|
7
|
+
// A section under a coloured heading has its colour as `sectionColor` (src/sections.mjs).
|
|
7
8
|
import setting from '@data/standard-pages.json';
|
|
8
9
|
import { getPages, type Page, type PostChoice } from './content';
|
|
9
10
|
import { isBlogCategory } from './categories';
|
|
@@ -44,7 +45,7 @@ export const allPostsLink = (choice: { show?: string; categories?: string[]; lin
|
|
|
44
45
|
};
|
|
45
46
|
|
|
46
47
|
export type SectionType = keyof Sections;
|
|
47
|
-
export type HomeSection = { [T in SectionType]: { type: T; hidden?: boolean } & Sections[T] }[SectionType];
|
|
48
|
+
export type HomeSection = { [T in SectionType]: { type: T; hidden?: boolean; sectionColor?: string } & Sections[T] }[SectionType];
|
|
48
49
|
|
|
49
50
|
/** The address of the page that is the front page; its own address sends on to / (packages/editor/worker/index.js). */
|
|
50
51
|
export const frontPath = setting.front;
|
|
@@ -56,7 +57,7 @@ export type FrontPage = { page: Page; heading: string; headingHtml?: string; sec
|
|
|
56
57
|
export async function frontPage(): Promise<FrontPage> {
|
|
57
58
|
const page = (await getPages({ previews: false })).find((p) => p.data.path === frontPath);
|
|
58
59
|
if (!page) throw new Error(`src/data/standard-pages.json: forsiden, ${frontPath}, findes ikke, eller den er en kladde.`);
|
|
59
|
-
const sections = sectionsFromParts(partsOfMarkdown(page.body ?? ''), frontLeads) as HomeSection[];
|
|
60
|
+
const sections = sectionsFromParts(partsOfMarkdown(page.body ?? ''), frontLeads, { colors: true }) as HomeSection[];
|
|
60
61
|
const h1 = pageH1(page.body);
|
|
61
62
|
return { page, heading: h1.heading || page.data.title, headingHtml: h1.html, sections: sections.filter((s) => !s.hidden) };
|
|
62
63
|
}
|