@morphemecms/cms 0.1.0 → 0.2.0-next-20261104150211
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 +12 -0
- package/LICENSE +21 -21
- package/README.md +51 -51
- package/astro.mjs +162 -162
- package/bin/morpheme.mjs +38 -38
- package/client.d.ts +10 -10
- package/defaults/blockTexts.ts +33 -33
- package/defaults/collections.ts +774 -774
- package/defaults/colors.ts +125 -125
- package/defaults/company.ts +20 -20
- package/defaults/editor.ts +178 -178
- package/defaults/internalLinks.ts +30 -30
- package/defaults/opens.ts +18 -18
- package/defaults/popup.tsx +93 -93
- package/defaults/privacy.ts +79 -79
- package/defaults/rules.ts +450 -450
- package/defaults/schema.ts +16 -16
- package/defaults/sitedata.ts +129 -129
- package/defaults/standard.ts +106 -106
- package/defaults/standardPages.ts +87 -87
- package/defaults/texts.ts +481 -481
- package/demo/README.md +26 -26
- package/demo/src/content/blog/build-a-page-from-blocks.md +19 -19
- package/demo/src/content/blog/colors-everyone-can-read.md +19 -19
- package/demo/src/content/blog/edit-your-website-from-your-phone.md +21 -21
- package/demo/src/content/blog/every-save-is-a-version.md +21 -21
- package/demo/src/content/blog/schedule-a-post.md +17 -17
- package/demo/src/content/blog/secure-from-day-one.md +17 -17
- package/demo/src/content/blog/seo-without-the-guesswork.md +23 -23
- package/demo/src/content/blog/switch-themes-without-losing-anything.md +23 -23
- package/demo/src/content/blog/the-app-store.md +21 -21
- package/demo/src/content/pages/about.md +22 -22
- package/demo/src/content/pages/app-store.md +30 -30
- package/demo/src/content/pages/blocks.md +98 -98
- package/demo/src/content/pages/blog-page.md +11 -11
- package/demo/src/content/pages/contact.md +16 -16
- package/demo/src/content/pages/get-started.md +20 -20
- package/demo/src/content/pages/home.md +26 -26
- package/demo/src/content/pages/page-not-found.md +11 -11
- package/demo/src/content/pages/privacy-policy.md +24 -24
- package/demo/src/data/blocks.json +25 -25
- package/demo/src/data/booking.json +6 -6
- package/demo/src/data/categories/apps.json +6 -6
- package/demo/src/data/categories/design.json +6 -6
- package/demo/src/data/categories/editing.json +6 -6
- package/demo/src/data/categories/security.json +6 -6
- package/demo/src/data/categories/seo.json +6 -6
- package/demo/src/data/colors.json +75 -75
- package/demo/src/data/contact.json +8 -8
- package/demo/src/data/cookies.json +21 -21
- package/demo/src/data/footer.json +27 -27
- package/demo/src/data/menu.json +35 -35
- package/demo/src/data/mobile-menu.json +25 -25
- package/demo/src/data/popups/booking-bar.json +13 -13
- package/demo/src/data/popups/try-the-editor.json +16 -16
- package/demo/src/data/standard-pages.json +8 -8
- package/demo/src/data/testimonials/sample-bakery.json +10 -10
- package/demo/src/data/testimonials/sample-clinic.json +10 -10
- package/demo/src/data/testimonials/sample-studio.json +10 -10
- package/demo/src/site/colors.ts +11 -11
- package/demo/src/site/config.ts +19 -19
- package/icons/lucide/LICENSE +43 -43
- package/icons/lucide/address-book.svg +1 -1
- package/icons/lucide/app-window.svg +1 -1
- package/icons/lucide/arrow-counter-clockwise.svg +1 -1
- package/icons/lucide/arrow-down.svg +1 -1
- package/icons/lucide/arrow-left.svg +1 -1
- package/icons/lucide/arrow-right.svg +1 -1
- package/icons/lucide/arrow-square-out.svg +1 -1
- package/icons/lucide/arrow-u-up-left.svg +1 -1
- package/icons/lucide/arrow-u-up-right.svg +1 -1
- package/icons/lucide/arrow-up-right.svg +1 -1
- package/icons/lucide/arrow-up.svg +1 -1
- package/icons/lucide/arrows-down-up.svg +1 -1
- package/icons/lucide/arrows-in-line-horizontal.svg +1 -1
- package/icons/lucide/arrows-out-line-horizontal.svg +1 -1
- package/icons/lucide/article.svg +1 -1
- package/icons/lucide/bank.svg +1 -1
- package/icons/lucide/bell.svg +1 -1
- package/icons/lucide/bicycle.svg +1 -1
- package/icons/lucide/binoculars.svg +1 -1
- package/icons/lucide/book-open-text.svg +1 -1
- package/icons/lucide/book-open.svg +1 -1
- package/icons/lucide/browser.svg +1 -1
- package/icons/lucide/buildings.svg +1 -1
- package/icons/lucide/bus.svg +1 -1
- package/icons/lucide/calendar-blank.svg +1 -1
- package/icons/lucide/calendar-check.svg +1 -1
- package/icons/lucide/car.svg +1 -1
- package/icons/lucide/cards.svg +1 -1
- package/icons/lucide/caret-down.svg +1 -1
- package/icons/lucide/caret-left.svg +1 -1
- package/icons/lucide/caret-right.svg +1 -1
- package/icons/lucide/caret-up.svg +1 -1
- package/icons/lucide/certificate.svg +1 -1
- package/icons/lucide/chart-line-up.svg +1 -1
- package/icons/lucide/chats.svg +1 -1
- package/icons/lucide/check-circle.svg +1 -1
- package/icons/lucide/check.svg +1 -1
- package/icons/lucide/circle-half.svg +1 -1
- package/icons/lucide/circle.svg +1 -1
- package/icons/lucide/clock-counter-clockwise.svg +1 -1
- package/icons/lucide/clock.svg +1 -1
- package/icons/lucide/code.svg +1 -1
- package/icons/lucide/coffee.svg +1 -1
- package/icons/lucide/columns.svg +1 -1
- package/icons/lucide/cookie.svg +1 -1
- package/icons/lucide/copy.svg +1 -1
- package/icons/lucide/credit-card.svg +1 -1
- package/icons/lucide/currency-circle-dollar.svg +1 -1
- package/icons/lucide/cursor-click.svg +1 -1
- package/icons/lucide/database.svg +1 -1
- package/icons/lucide/desktop.svg +1 -1
- package/icons/lucide/device-mobile.svg +1 -1
- package/icons/lucide/door-open.svg +1 -1
- package/icons/lucide/download-simple.svg +1 -1
- package/icons/lucide/envelope-simple.svg +1 -1
- package/icons/lucide/eye-slash.svg +1 -1
- package/icons/lucide/eye.svg +1 -1
- package/icons/lucide/file-pdf.svg +1 -1
- package/icons/lucide/file-text.svg +1 -1
- package/icons/lucide/file-video.svg +1 -1
- package/icons/lucide/file-zip.svg +1 -1
- package/icons/lucide/flower-lotus.svg +1 -1
- package/icons/lucide/folder-simple.svg +1 -1
- package/icons/lucide/funnel.svg +1 -1
- package/icons/lucide/gauge.svg +1 -1
- package/icons/lucide/gear.svg +1 -1
- package/icons/lucide/github-logo.svg +1 -1
- package/icons/lucide/globe.svg +1 -1
- package/icons/lucide/google-logo.svg +1 -1
- package/icons/lucide/graduation-cap.svg +1 -1
- package/icons/lucide/hammer.svg +1 -1
- package/icons/lucide/hand-heart.svg +1 -1
- package/icons/lucide/handshake.svg +1 -1
- package/icons/lucide/hard-drives.svg +1 -1
- package/icons/lucide/heart.svg +1 -1
- package/icons/lucide/house.svg +1 -1
- package/icons/lucide/image-square.svg +1 -1
- package/icons/lucide/image.svg +1 -1
- package/icons/lucide/info.svg +1 -1
- package/icons/lucide/keyboard.svg +1 -1
- package/icons/lucide/leaf.svg +1 -1
- package/icons/lucide/lifebuoy.svg +1 -1
- package/icons/lucide/lightbulb.svg +1 -1
- package/icons/lucide/link-break.svg +1 -1
- package/icons/lucide/link-simple.svg +1 -1
- package/icons/lucide/list-bullets.svg +1 -1
- package/icons/lucide/list-checks.svg +1 -1
- package/icons/lucide/list-numbers.svg +1 -1
- package/icons/lucide/list.svg +1 -1
- package/icons/lucide/lock-simple-open.svg +1 -1
- package/icons/lucide/lock-simple.svg +1 -1
- package/icons/lucide/magnifying-glass.svg +1 -1
- package/icons/lucide/map-pin.svg +1 -1
- package/icons/lucide/map-trifold.svg +1 -1
- package/icons/lucide/medal.svg +1 -1
- package/icons/lucide/megaphone.svg +1 -1
- package/icons/lucide/minus.svg +1 -1
- package/icons/lucide/moon.svg +1 -1
- package/icons/lucide/newspaper.svg +1 -1
- package/icons/lucide/pack.json +23 -23
- package/icons/lucide/paint-brush-broad.svg +1 -1
- package/icons/lucide/palette.svg +1 -1
- package/icons/lucide/paper-plane-tilt.svg +1 -1
- package/icons/lucide/pencil-simple.svg +1 -1
- package/icons/lucide/phone.svg +1 -1
- package/icons/lucide/play-fill.svg +1 -1
- package/icons/lucide/plus.svg +1 -1
- package/icons/lucide/prohibit.svg +1 -1
- package/icons/lucide/puzzle-piece.svg +1 -1
- package/icons/lucide/question.svg +1 -1
- package/icons/lucide/quotes.svg +1 -1
- package/icons/lucide/rows.svg +1 -1
- package/icons/lucide/ruler.svg +1 -1
- package/icons/lucide/scan.svg +1 -1
- package/icons/lucide/shapes.svg +1 -1
- package/icons/lucide/share-network.svg +1 -1
- package/icons/lucide/shield-check.svg +1 -1
- package/icons/lucide/sidebar-simple.svg +1 -1
- package/icons/lucide/sign-out.svg +1 -1
- package/icons/lucide/signpost.svg +1 -1
- package/icons/lucide/sliders-horizontal.svg +1 -1
- package/icons/lucide/smiley.svg +1 -1
- package/icons/lucide/sparkle.svg +1 -1
- package/icons/lucide/square-half-bottom.svg +1 -1
- package/icons/lucide/square.svg +1 -1
- package/icons/lucide/squares-four.svg +1 -1
- package/icons/lucide/sticker.svg +1 -1
- package/icons/lucide/storefront.svg +1 -1
- package/icons/lucide/sun.svg +1 -1
- package/icons/lucide/swatches.svg +1 -1
- package/icons/lucide/tag.svg +1 -1
- package/icons/lucide/text-aa.svg +1 -1
- package/icons/lucide/text-align-left.svg +1 -1
- package/icons/lucide/text-b.svg +1 -1
- package/icons/lucide/text-h-one.svg +1 -1
- package/icons/lucide/text-h-three.svg +1 -1
- package/icons/lucide/text-h-two.svg +1 -1
- package/icons/lucide/text-italic.svg +1 -1
- package/icons/lucide/text-t.svg +1 -1
- package/icons/lucide/ticket.svg +1 -1
- package/icons/lucide/toggle-right.svg +1 -1
- package/icons/lucide/train.svg +1 -1
- package/icons/lucide/trash.svg +1 -1
- package/icons/lucide/upload-simple.svg +1 -1
- package/icons/lucide/user-circle.svg +1 -1
- package/icons/lucide/user.svg +1 -1
- package/icons/lucide/users-three.svg +1 -1
- package/icons/lucide/users.svg +1 -1
- package/icons/lucide/video-camera.svg +1 -1
- package/icons/lucide/warning-circle.svg +1 -1
- package/icons/lucide/warning.svg +1 -1
- package/icons/lucide/wave-sine.svg +1 -1
- package/icons/lucide/wheelchair.svg +1 -1
- package/icons/lucide/wrench.svg +1 -1
- package/icons/lucide/x.svg +1 -1
- package/icons/material-symbols/LICENSE +201 -201
- package/icons/material-symbols/address-book.svg +1 -1
- package/icons/material-symbols/app-window.svg +1 -1
- package/icons/material-symbols/arrow-counter-clockwise.svg +1 -1
- package/icons/material-symbols/arrow-down.svg +1 -1
- package/icons/material-symbols/arrow-left.svg +1 -1
- package/icons/material-symbols/arrow-right.svg +1 -1
- package/icons/material-symbols/arrow-square-out.svg +1 -1
- package/icons/material-symbols/arrow-u-up-left.svg +1 -1
- package/icons/material-symbols/arrow-u-up-right.svg +1 -1
- package/icons/material-symbols/arrow-up-right.svg +1 -1
- package/icons/material-symbols/arrow-up.svg +1 -1
- package/icons/material-symbols/arrows-down-up.svg +1 -1
- package/icons/material-symbols/arrows-in-line-horizontal.svg +1 -1
- package/icons/material-symbols/arrows-out-line-horizontal.svg +1 -1
- package/icons/material-symbols/article.svg +1 -1
- package/icons/material-symbols/bank.svg +1 -1
- package/icons/material-symbols/bell.svg +1 -1
- package/icons/material-symbols/bicycle.svg +1 -1
- package/icons/material-symbols/binoculars.svg +1 -1
- package/icons/material-symbols/book-open-text.svg +1 -1
- package/icons/material-symbols/book-open.svg +1 -1
- package/icons/material-symbols/browser.svg +1 -1
- package/icons/material-symbols/buildings.svg +1 -1
- package/icons/material-symbols/bus.svg +1 -1
- package/icons/material-symbols/calendar-blank.svg +1 -1
- package/icons/material-symbols/calendar-check.svg +1 -1
- package/icons/material-symbols/car.svg +1 -1
- package/icons/material-symbols/cards.svg +1 -1
- package/icons/material-symbols/caret-down.svg +1 -1
- package/icons/material-symbols/caret-left.svg +1 -1
- package/icons/material-symbols/caret-right.svg +1 -1
- package/icons/material-symbols/caret-up.svg +1 -1
- package/icons/material-symbols/certificate.svg +1 -1
- package/icons/material-symbols/chart-line-up.svg +1 -1
- package/icons/material-symbols/chats.svg +1 -1
- package/icons/material-symbols/check-circle.svg +1 -1
- package/icons/material-symbols/check.svg +1 -1
- package/icons/material-symbols/circle-half.svg +1 -1
- package/icons/material-symbols/circle.svg +1 -1
- package/icons/material-symbols/clock-counter-clockwise.svg +1 -1
- package/icons/material-symbols/clock.svg +1 -1
- package/icons/material-symbols/code.svg +1 -1
- package/icons/material-symbols/coffee.svg +1 -1
- package/icons/material-symbols/columns.svg +1 -1
- package/icons/material-symbols/cookie.svg +1 -1
- package/icons/material-symbols/copy.svg +1 -1
- package/icons/material-symbols/credit-card.svg +1 -1
- package/icons/material-symbols/currency-circle-dollar.svg +1 -1
- package/icons/material-symbols/cursor-click.svg +1 -1
- package/icons/material-symbols/database.svg +1 -1
- package/icons/material-symbols/desktop.svg +1 -1
- package/icons/material-symbols/device-mobile.svg +1 -1
- package/icons/material-symbols/door-open.svg +1 -1
- package/icons/material-symbols/download-simple.svg +1 -1
- package/icons/material-symbols/envelope-simple.svg +1 -1
- package/icons/material-symbols/eye-slash.svg +1 -1
- package/icons/material-symbols/eye.svg +1 -1
- package/icons/material-symbols/file-pdf.svg +1 -1
- package/icons/material-symbols/file-text.svg +1 -1
- package/icons/material-symbols/file-video.svg +1 -1
- package/icons/material-symbols/file-zip.svg +1 -1
- package/icons/material-symbols/flower-lotus.svg +1 -1
- package/icons/material-symbols/folder-simple.svg +1 -1
- package/icons/material-symbols/funnel.svg +1 -1
- package/icons/material-symbols/gauge.svg +1 -1
- package/icons/material-symbols/gear.svg +1 -1
- package/icons/material-symbols/github-logo.svg +1 -1
- package/icons/material-symbols/globe.svg +1 -1
- package/icons/material-symbols/google-logo.svg +1 -1
- package/icons/material-symbols/graduation-cap.svg +1 -1
- package/icons/material-symbols/hammer.svg +1 -1
- package/icons/material-symbols/hand-heart.svg +1 -1
- package/icons/material-symbols/handshake.svg +1 -1
- package/icons/material-symbols/hard-drives.svg +1 -1
- package/icons/material-symbols/heart.svg +1 -1
- package/icons/material-symbols/house.svg +1 -1
- package/icons/material-symbols/image-square.svg +1 -1
- package/icons/material-symbols/image.svg +1 -1
- package/icons/material-symbols/info.svg +1 -1
- package/icons/material-symbols/keyboard.svg +1 -1
- package/icons/material-symbols/leaf.svg +1 -1
- package/icons/material-symbols/lifebuoy.svg +1 -1
- package/icons/material-symbols/lightbulb.svg +1 -1
- package/icons/material-symbols/link-break.svg +1 -1
- package/icons/material-symbols/link-simple.svg +1 -1
- package/icons/material-symbols/list-bullets.svg +1 -1
- package/icons/material-symbols/list-checks.svg +1 -1
- package/icons/material-symbols/list-numbers.svg +1 -1
- package/icons/material-symbols/list.svg +1 -1
- package/icons/material-symbols/lock-simple-open.svg +1 -1
- package/icons/material-symbols/lock-simple.svg +1 -1
- package/icons/material-symbols/magnifying-glass.svg +1 -1
- package/icons/material-symbols/map-pin.svg +1 -1
- package/icons/material-symbols/map-trifold.svg +1 -1
- package/icons/material-symbols/medal.svg +1 -1
- package/icons/material-symbols/megaphone.svg +1 -1
- package/icons/material-symbols/minus.svg +1 -1
- package/icons/material-symbols/moon.svg +1 -1
- package/icons/material-symbols/newspaper.svg +1 -1
- package/icons/material-symbols/pack.json +29 -29
- package/icons/material-symbols/paint-brush-broad.svg +1 -1
- package/icons/material-symbols/palette.svg +1 -1
- package/icons/material-symbols/paper-plane-tilt.svg +1 -1
- package/icons/material-symbols/pencil-simple.svg +1 -1
- package/icons/material-symbols/phone.svg +1 -1
- package/icons/material-symbols/play-fill.svg +1 -1
- package/icons/material-symbols/plus.svg +1 -1
- package/icons/material-symbols/prohibit.svg +1 -1
- package/icons/material-symbols/puzzle-piece.svg +1 -1
- package/icons/material-symbols/question.svg +1 -1
- package/icons/material-symbols/quotes.svg +1 -1
- package/icons/material-symbols/rows.svg +1 -1
- package/icons/material-symbols/ruler.svg +1 -1
- package/icons/material-symbols/scan.svg +1 -1
- package/icons/material-symbols/shapes.svg +1 -1
- package/icons/material-symbols/share-network.svg +1 -1
- package/icons/material-symbols/shield-check.svg +1 -1
- package/icons/material-symbols/sidebar-simple.svg +1 -1
- package/icons/material-symbols/sign-out.svg +1 -1
- package/icons/material-symbols/signpost.svg +1 -1
- package/icons/material-symbols/sliders-horizontal.svg +1 -1
- package/icons/material-symbols/smiley.svg +1 -1
- package/icons/material-symbols/sparkle.svg +1 -1
- package/icons/material-symbols/square-half-bottom.svg +1 -1
- package/icons/material-symbols/square.svg +1 -1
- package/icons/material-symbols/squares-four.svg +1 -1
- package/icons/material-symbols/sticker.svg +1 -1
- package/icons/material-symbols/storefront.svg +1 -1
- package/icons/material-symbols/sun.svg +1 -1
- package/icons/material-symbols/swatches.svg +1 -1
- package/icons/material-symbols/tag.svg +1 -1
- package/icons/material-symbols/text-aa.svg +1 -1
- package/icons/material-symbols/text-align-left.svg +1 -1
- package/icons/material-symbols/text-b.svg +1 -1
- package/icons/material-symbols/text-h-one.svg +1 -1
- package/icons/material-symbols/text-h-three.svg +1 -1
- package/icons/material-symbols/text-h-two.svg +1 -1
- package/icons/material-symbols/text-italic.svg +1 -1
- package/icons/material-symbols/text-t.svg +1 -1
- package/icons/material-symbols/ticket.svg +1 -1
- package/icons/material-symbols/toggle-right.svg +1 -1
- package/icons/material-symbols/train.svg +1 -1
- package/icons/material-symbols/trash.svg +1 -1
- package/icons/material-symbols/upload-simple.svg +1 -1
- package/icons/material-symbols/user-circle.svg +1 -1
- package/icons/material-symbols/user.svg +1 -1
- package/icons/material-symbols/users-three.svg +1 -1
- package/icons/material-symbols/users.svg +1 -1
- package/icons/material-symbols/video-camera.svg +1 -1
- package/icons/material-symbols/warning-circle.svg +1 -1
- package/icons/material-symbols/warning.svg +1 -1
- package/icons/material-symbols/wave-sine.svg +1 -1
- package/icons/material-symbols/wheelchair.svg +1 -1
- package/icons/material-symbols/wrench.svg +1 -1
- package/icons/material-symbols/x.svg +1 -1
- package/icons/phosphor/pack.json +8 -8
- package/lib/apps.mjs +142 -139
- package/lib/apps.test.d.mts +1 -0
- package/lib/apps.test.mjs +50 -0
- package/lib/blocks.mjs +90 -90
- package/lib/caseCollisions.d.mts +4 -0
- package/lib/caseCollisions.mjs +62 -0
- package/lib/caseCollisions.test.d.mts +1 -0
- package/lib/caseCollisions.test.mjs +74 -0
- package/lib/colors.ts +86 -86
- package/lib/contactBar.ts +18 -18
- package/lib/contracts.d.mts +15 -0
- package/lib/contracts.mjs +17 -0
- package/lib/cookieCategories.mjs +28 -28
- package/lib/crop.mjs +83 -83
- package/lib/csp.mjs +130 -130
- package/lib/cspSources.mjs +60 -60
- package/lib/dynamic-colors.ts +426 -426
- package/lib/git.mjs +64 -64
- package/lib/hooks.ts +51 -51
- package/lib/inline.ts +20 -20
- package/lib/license-texts/Apache-2.0.txt +190 -190
- package/lib/license-texts/BSD-2-Clause.txt +24 -24
- package/lib/license-texts/BSD-3-Clause.txt +28 -28
- package/lib/license-texts/ISC.txt +15 -15
- package/lib/license-texts/MIT.txt +21 -21
- package/lib/licenses.d.mts +1 -1
- package/lib/licenses.mjs +683 -683
- package/lib/markdown.ts +42 -42
- package/lib/motion-schemes.mjs +5 -5
- package/lib/motion.ts +131 -131
- package/lib/notice.mjs +34 -34
- package/lib/scheduled.mjs +37 -37
- package/lib/snackbar.ts +149 -149
- package/lib/status.mjs +18 -18
- package/lib/storeEntries.d.mts +18 -0
- package/lib/storeEntries.mjs +64 -0
- package/lib/storeEntries.test.d.mts +1 -0
- package/lib/storeEntries.test.mjs +71 -0
- package/lib/svg.mjs +231 -231
- package/lib/text-colors.mjs +43 -43
- package/lib/video-id.mjs +72 -72
- package/lib/video.mjs +91 -91
- package/package.json +136 -131
- package/pages/404.astro +10 -10
- package/pages/[...slug].astro +51 -51
- package/pages/_headers.txt +31 -31
- package/pages/blog/index.astro +10 -10
- package/pages/blog/kategori/[category].astro +18 -18
- package/pages/editor/code-images.json.js +25 -25
- package/pages/editor/index.astro +75 -75
- package/pages/editor/manifest.webmanifest.js +23 -23
- package/pages/editor/sw.js +33 -33
- package/pages/editor/sw.js.js +4 -4
- package/pages/editor/thumbnails.json.js +21 -21
- package/pages/editor/version.json.js +22 -22
- package/pages/headers.js +4 -4
- package/pages/index.astro +10 -10
- package/pages/ny.astro +6 -6
- package/pages/robots.txt.js +3 -3
- package/pages/rss.xml.js +20 -20
- package/scripts/app-screenshots.mjs +164 -164
- package/scripts/app-workers.mjs +6 -6
- package/scripts/bin.mjs +12 -12
- package/scripts/built-site.mjs +134 -99
- package/scripts/check-consent.mjs +113 -113
- package/scripts/check-content.mjs +151 -149
- package/scripts/check-demo.mjs +24 -24
- package/scripts/check-store.mjs +160 -0
- package/scripts/check-themes.mjs +45 -45
- package/scripts/check-worker.mjs +569 -569
- package/scripts/compare-html.mjs +81 -81
- package/scripts/declarations.mjs +10 -0
- package/scripts/declarations.test.mjs +32 -0
- package/scripts/demo-site.mjs +42 -42
- package/scripts/editor-icons.mjs +56 -56
- package/scripts/editor-roundtrip.mjs +134 -134
- package/scripts/editor-screens.mjs +101 -101
- package/scripts/git-env.mjs +9 -9
- package/scripts/icon-packs.mjs +151 -151
- package/scripts/link-counts.mjs +22 -22
- package/scripts/page-colors.mjs +42 -42
- package/scripts/releases.mjs +80 -80
- package/scripts/responsive-images.mjs +94 -94
- package/scripts/scheduled-list.mjs +15 -15
- package/scripts/theme-screenshots.mjs +88 -88
- package/scripts/types.mjs +17 -21
- package/scripts/video-thumbnails.mjs +89 -89
- package/scripts/worker-modules.mjs +34 -34
- package/site/appCookies.mjs +74 -74
- package/site/apps.ts +21 -21
- package/site/autolinks.mjs +200 -200
- package/site/blockScripts.ts +31 -31
- package/site/categories.ts +16 -16
- package/site/consent.ts +26 -26
- package/site/content.config.ts +84 -84
- package/site/content.ts +104 -104
- package/site/cookieList.ts +17 -17
- package/site/defineSite.d.mts +2 -14
- package/site/defineSite.mjs +131 -136
- package/site/directives/interact.mjs +31 -31
- package/site/editor-version.mjs +26 -26
- package/site/fill.ts +13 -13
- package/site/format.ts +11 -11
- package/site/home.ts +66 -66
- package/site/iconPacks.mjs +43 -43
- package/site/icons.mjs +605 -605
- package/site/images.mjs +157 -157
- package/site/motion.ts +13 -13
- package/site/noindex.mjs +21 -21
- package/site/pageColors.ts +110 -110
- package/site/popups.ts +98 -98
- package/site/schema.ts +189 -189
- package/site/sections.ts +3 -3
- package/site/seo.ts +28 -28
- package/site/site.ts +76 -76
- package/site/siteConfig.mjs +8 -8
- package/site/siteCsp.mjs +75 -75
- package/site/siteModules.mjs +27 -27
- package/site/standardPages.ts +59 -59
- package/site/storeTheme.d.mts +6 -0
- package/site/storeTheme.mjs +29 -0
- package/site/storeTheme.test.d.mts +1 -0
- package/site/storeTheme.test.mjs +53 -0
- package/site/testimonials.ts +48 -48
- package/site/text.ts +43 -43
- package/site/theme.mjs +483 -472
- package/site/tracking.client.ts +225 -225
- package/site/tracking.ts +9 -9
- package/src/ActionParts.tsx +205 -205
- package/src/Advanced.tsx +152 -152
- package/src/App.tsx +901 -904
- package/src/AppList.tsx +1362 -1345
- package/src/BlockDialog.tsx +360 -360
- package/src/BlockParts.tsx +652 -652
- package/src/BlockSettings.tsx +533 -533
- package/src/BrandForm.tsx +164 -164
- package/src/Colors.tsx +476 -476
- package/src/CommunicationParts.tsx +199 -199
- package/src/CompanyForm.tsx +209 -209
- package/src/Consents.tsx +175 -175
- package/src/ContainmentParts.tsx +185 -185
- package/src/Crop.tsx +152 -152
- package/src/DataForm.tsx +434 -434
- package/src/Deleted.tsx +177 -177
- package/src/EntryForm.tsx +740 -740
- package/src/FileView.tsx +30 -30
- package/src/FormFrame.tsx +237 -237
- package/src/Keywords.tsx +225 -225
- package/src/Library.tsx +1563 -1563
- package/src/Licenses.tsx +336 -336
- package/src/LinkSheet.tsx +138 -138
- package/src/MarkdownEditor.tsx +1075 -1075
- package/src/Media.tsx +677 -677
- package/src/NavigationParts.tsx +350 -350
- package/src/NavigationRestParts.tsx +247 -247
- package/src/Notifications.tsx +59 -59
- package/src/PagePicker.tsx +136 -136
- package/src/Parts.tsx +991 -991
- package/src/PartsShown.tsx +168 -168
- package/src/PickerParts.tsx +183 -183
- package/src/Redirects.tsx +450 -450
- package/src/Screen.tsx +184 -184
- package/src/SectionsField.tsx +65 -65
- package/src/SelectionParts.tsx +134 -134
- package/src/SeoScores.tsx +184 -184
- package/src/Sheet.tsx +35 -35
- package/src/ThemeStore.tsx +376 -376
- package/src/Tokens.tsx +346 -346
- package/src/Versions.tsx +214 -214
- package/src/addresses.ts +75 -75
- package/src/allIcons.ts +7 -7
- package/src/appFiles.ts +29 -29
- package/src/apps.ts +281 -281
- package/src/ask.tsx +123 -123
- package/src/blocks.ts +251 -251
- package/src/brand.ts +153 -153
- package/src/cache.ts +42 -42
- package/src/check.ts +285 -285
- package/src/checkSite.ts +256 -256
- package/src/{consents.ts → consentData.ts} +26 -26
- package/src/cookieList.ts +70 -70
- package/src/countries.ts +59 -59
- package/src/deploy.ts +155 -155
- package/src/editor.css +602 -602
- package/src/examples.ts +85 -85
- package/src/fields.tsx +942 -942
- package/src/frontmatter.mjs +42 -42
- package/src/github.ts +376 -376
- package/src/i18n/da-DK/advanced.ts +28 -28
- package/src/i18n/da-DK/app.ts +71 -71
- package/src/i18n/da-DK/apps.ts +90 -90
- package/src/i18n/da-DK/blockSettings.ts +38 -38
- package/src/i18n/da-DK/blocks.ts +408 -408
- package/src/i18n/da-DK/check.ts +25 -25
- package/src/i18n/da-DK/colors.ts +64 -64
- package/src/i18n/da-DK/common.ts +118 -118
- package/src/i18n/da-DK/company.ts +24 -24
- package/src/i18n/da-DK/consents.ts +23 -23
- package/src/i18n/da-DK/forms.ts +116 -116
- package/src/i18n/da-DK/history.ts +35 -35
- package/src/i18n/da-DK/index.ts +49 -49
- package/src/i18n/da-DK/keywords.ts +19 -19
- package/src/i18n/da-DK/library.ts +135 -135
- package/src/i18n/da-DK/licenses.ts +25 -25
- package/src/i18n/da-DK/media.ts +79 -79
- package/src/i18n/da-DK/parts.ts +696 -696
- package/src/i18n/da-DK/preview.ts +13 -13
- package/src/i18n/da-DK/redirects.ts +51 -51
- package/src/i18n/da-DK/seo.ts +20 -20
- package/src/i18n/da-DK/text.ts +35 -35
- package/src/i18n/da-DK/theme.ts +41 -41
- package/src/i18n/en-US/advanced.ts +32 -32
- package/src/i18n/en-US/app.ts +84 -84
- package/src/i18n/en-US/apps.ts +134 -134
- package/src/i18n/en-US/blockSettings.ts +48 -48
- package/src/i18n/en-US/blocks.ts +441 -441
- package/src/i18n/en-US/check.ts +31 -31
- package/src/i18n/en-US/colors.ts +82 -82
- package/src/i18n/en-US/common.ts +144 -144
- package/src/i18n/en-US/company.ts +25 -25
- package/src/i18n/en-US/consents.ts +25 -25
- package/src/i18n/en-US/forms.ts +145 -145
- package/src/i18n/en-US/history.ts +43 -43
- package/src/i18n/en-US/index.ts +51 -51
- package/src/i18n/en-US/keywords.ts +24 -24
- package/src/i18n/en-US/library.ts +176 -176
- package/src/i18n/en-US/licenses.ts +36 -36
- package/src/i18n/en-US/media.ts +80 -80
- package/src/i18n/en-US/parts.ts +718 -718
- package/src/i18n/en-US/preview.ts +15 -15
- package/src/i18n/en-US/redirects.ts +66 -66
- package/src/i18n/en-US/seo.ts +26 -26
- package/src/i18n/en-US/text.ts +41 -41
- package/src/i18n/en-US/theme.ts +41 -41
- package/src/i18n/index.ts +124 -124
- package/src/icon.tsx +160 -160
- package/src/iconPacks.ts +89 -89
- package/src/images.ts +163 -163
- package/src/{licenses.ts → licenseData.ts} +79 -79
- package/src/markdown.mjs +204 -204
- package/src/nav.ts +68 -68
- package/src/notFound.ts +28 -28
- package/src/{notifications.ts → notificationData.ts} +223 -223
- package/src/pagePreview.tsx +204 -204
- package/src/r2Caching.ts +55 -55
- package/src/{redirects.ts → redirectData.ts} +149 -149
- package/src/registry.tsx +188 -188
- package/src/schema.ts +417 -417
- package/src/sections.mjs +303 -303
- package/src/seo.ts +333 -333
- package/src/shared.ts +44 -44
- package/src/sidebar.ts +31 -31
- package/src/site.ts +317 -317
- package/src/standard/Block.astro +19 -19
- package/src/standard/BlockSite.astro +18 -18
- package/src/standard/accordion/index.tsx +47 -47
- package/src/standard/accordion/load.ts +23 -23
- package/src/standard/accordion/shared.ts +15 -15
- package/src/standard/accordion/view.ts +32 -32
- package/src/standard/buttons/fields.ts +98 -98
- package/src/standard/buttons/index.tsx +23 -23
- package/src/standard/buttons/load.ts +34 -34
- package/src/standard/buttons/shared.ts +12 -12
- package/src/standard/buttons/view.ts +30 -30
- package/src/standard/cards/index.tsx +71 -71
- package/src/standard/cards/load.ts +17 -17
- package/src/standard/cards/shared.ts +27 -27
- package/src/standard/cards/view.ts +29 -29
- package/src/standard/checklist/index.tsx +27 -27
- package/src/standard/checklist/load.ts +5 -5
- package/src/standard/checklist/view.ts +13 -13
- package/src/standard/cookies/index.tsx +17 -17
- package/src/standard/cookies/list.ts +56 -56
- package/src/standard/cookies/load.ts +11 -11
- package/src/standard/cookies/shared.ts +20 -20
- package/src/standard/cookies/view.ts +28 -28
- package/src/standard/faq/index.tsx +29 -29
- package/src/standard/faq/load.ts +14 -14
- package/src/standard/faq/view.ts +21 -21
- package/src/standard/head.ts +23 -23
- package/src/standard/hero/fields.ts +48 -48
- package/src/standard/hero/index.tsx +57 -57
- package/src/standard/hero/load.ts +23 -23
- package/src/standard/hero/view.ts +38 -38
- package/src/standard/links/index.tsx +41 -41
- package/src/standard/links/load.ts +17 -17
- package/src/standard/links/view.ts +25 -25
- package/src/standard/list/index.tsx +50 -50
- package/src/standard/list/load.ts +5 -5
- package/src/standard/list/view.ts +18 -18
- package/src/standard/load.ts +7 -7
- package/src/standard/notice/index.tsx +30 -30
- package/src/standard/notice/load.ts +16 -16
- package/src/standard/notice/view.ts +10 -10
- package/src/standard/points/index.tsx +42 -42
- package/src/standard/points/load.ts +5 -5
- package/src/standard/points/view.ts +12 -12
- package/src/standard/posts/index.tsx +132 -132
- package/src/standard/posts/load.ts +36 -36
- package/src/standard/posts/shared.ts +21 -21
- package/src/standard/posts/view.ts +63 -63
- package/src/standard/pricecards/index.tsx +57 -57
- package/src/standard/pricecards/load.ts +11 -11
- package/src/standard/pricecards/view.ts +50 -50
- package/src/standard/sharedTexts.ts +6 -6
- package/src/standard/site.ts +124 -124
- package/src/standard/siteLooks.ts +19 -19
- package/src/standard/sites.ts +13 -13
- package/src/standard/steps/index.tsx +28 -28
- package/src/standard/steps/load.ts +5 -5
- package/src/standard/steps/view.ts +11 -11
- package/src/standard/testimonials/index.tsx +87 -87
- package/src/standard/testimonials/list.ts +43 -43
- package/src/standard/testimonials/load.ts +58 -58
- package/src/standard/testimonials/shared.ts +13 -13
- package/src/standard/testimonials/view.ts +76 -76
- package/src/standard/themeBlocks.ts +13 -13
- package/src/standard/video/index.tsx +23 -23
- package/src/standard/video/load.ts +10 -10
- package/src/standard/video/view.ts +42 -42
- package/src/standard/view.tsx +105 -105
- package/src/standard/views.ts +37 -37
- package/src/store.ts +479 -499
- package/src/theme.ts +90 -90
- package/src/themeUi.ts +97 -97
- package/src/themes.ts +91 -91
- package/src/ui.tsx +3402 -3402
- package/src/virtual.d.ts +5 -5
- package/src/when.ts +22 -22
- package/starter/.githooks/pre-push +4 -4
- package/starter/.nvmrc +1 -1
- package/starter/.prettierignore +11 -11
- package/starter/.prettierrc.json +7 -7
- package/starter/README.md +27 -26
- package/starter/astro.config.mjs +5 -5
- package/starter/package.json +67 -67
- package/starter/public/_redirects +1 -1
- package/starter/public/favicon.svg +1 -1
- package/starter/public/logo.svg +1 -1
- package/starter/src/content/pages/blog.md +8 -8
- package/starter/src/content/pages/forside.md +9 -9
- package/starter/src/content/pages/kontakt.md +7 -7
- package/starter/src/content/pages/privatlivspolitik.md +9 -9
- package/starter/src/content/pages/siden-findes-ikke.md +7 -7
- package/starter/src/content.config.ts +2 -2
- package/starter/src/data/apps.json +1 -1
- package/starter/src/data/block-settings.json +3 -3
- package/starter/src/data/blocks.json +1 -1
- package/starter/src/data/booking.json +6 -6
- package/starter/src/data/colors.json +70 -70
- package/starter/src/data/contact.json +8 -8
- package/starter/src/data/cookies.json +21 -21
- package/starter/src/data/csp.json +1 -1
- package/starter/src/data/footer.json +15 -15
- package/starter/src/data/internal-links.json +4 -4
- package/starter/src/data/menu.json +4 -4
- package/starter/src/data/mobile-menu.json +4 -4
- package/starter/src/data/old-addresses.json +1 -1
- package/starter/src/data/redirects.json +1 -1
- package/starter/src/data/standard-pages.json +8 -8
- package/starter/src/data/theme.json +1 -1
- package/starter/src/env.d.ts +2 -2
- package/starter/src/site/config.ts +13 -13
- package/starter/src/site/worker.js +14 -14
- package/starter/tsconfig.json +17 -17
- package/starter/worker/apps.js +6 -6
- package/starter/wrangler.jsonc +39 -39
- package/theme/LICENSE +21 -21
- package/theme/blocks/ArrowLink.tsx +14 -14
- package/theme/blocks/BlockHead.tsx +26 -26
- package/theme/blocks/Panel.tsx +32 -32
- package/theme/blocks/Person.tsx +26 -26
- package/theme/blocks/accordion/PageRow.tsx +25 -25
- package/theme/blocks/accordion/View.tsx +17 -17
- package/theme/blocks/buttons/Buttons.tsx +28 -28
- package/theme/blocks/buttons/View.tsx +12 -12
- package/theme/blocks/cards/LinkCards.tsx +72 -72
- package/theme/blocks/cards/View.tsx +20 -20
- package/theme/blocks/checklist/Checks.tsx +15 -15
- package/theme/blocks/checklist/View.tsx +14 -14
- package/theme/blocks/cookies/View.tsx +36 -36
- package/theme/blocks/faq/Accordion.tsx +34 -34
- package/theme/blocks/faq/View.tsx +16 -16
- package/theme/blocks/faq/script.ts +56 -56
- package/theme/blocks/hero/View.tsx +44 -44
- package/theme/blocks/links/LinkGroups.tsx +24 -24
- package/theme/blocks/links/View.tsx +17 -17
- package/theme/blocks/list/Rows.tsx +24 -24
- package/theme/blocks/list/View.tsx +14 -14
- package/theme/blocks/notice/View.tsx +13 -13
- package/theme/blocks/points/PointList.tsx +34 -34
- package/theme/blocks/points/View.tsx +14 -14
- package/theme/blocks/posts/View.tsx +26 -26
- package/theme/blocks/pricecards/View.tsx +40 -40
- package/theme/blocks/steps/StepList.tsx +23 -23
- package/theme/blocks/steps/View.tsx +14 -14
- package/theme/blocks/testimonials/List.tsx +46 -46
- package/theme/blocks/testimonials/Slider.tsx +44 -44
- package/theme/blocks/testimonials/Testimonial.tsx +124 -124
- package/theme/blocks/testimonials/View.tsx +21 -21
- package/theme/blocks/testimonials/script.ts +52 -52
- package/theme/blocks/video/View.tsx +41 -41
- package/theme/components/ActionBar.astro +63 -63
- package/theme/components/AppSlot.astro +21 -21
- package/theme/components/ArrowLink.tsx +21 -21
- package/theme/components/BlogIndex.astro +48 -48
- package/theme/components/BlogPosts.astro +18 -18
- package/theme/components/BlogPosts.tsx +45 -45
- package/theme/components/BookButton.tsx +22 -22
- package/theme/components/Container.astro +11 -11
- package/theme/components/CookieConsent.astro +121 -121
- package/theme/components/EndBlock.astro +21 -21
- package/theme/components/FontPreload.astro +6 -6
- package/theme/components/Footer.astro +85 -85
- package/theme/components/Header.astro +186 -186
- package/theme/components/Icon.astro +16 -16
- package/theme/components/Img.astro +29 -29
- package/theme/components/Img.tsx +33 -33
- package/theme/components/Inline.astro +11 -11
- package/theme/components/Logo.astro +23 -23
- package/theme/components/LogoMark.astro +10 -10
- package/theme/components/Markdown.astro +17 -17
- package/theme/components/MobileMenu.tsx +224 -224
- package/theme/components/MobileNav.astro +33 -33
- package/theme/components/PageHeader.astro +22 -22
- package/theme/components/PageSection.astro +24 -24
- package/theme/components/PhoneButton.tsx +11 -11
- package/theme/components/Popup.astro +145 -145
- package/theme/components/PopupButton.tsx +24 -24
- package/theme/components/PopupView.tsx +48 -48
- package/theme/components/PostList.tsx +58 -58
- package/theme/components/PostMeta.tsx +17 -17
- package/theme/components/RichText.astro +28 -28
- package/theme/components/Section.astro +29 -29
- package/theme/components/SectionHeading.tsx +8 -8
- package/theme/components/TextSection.astro +16 -16
- package/theme/components/home/PageBlock.astro +19 -19
- package/theme/components/home/Text.astro +13 -13
- package/theme/components/loadPopup.ts +22 -22
- package/theme/components/loadPosts.ts +16 -16
- package/theme/components/posts.ts +15 -15
- package/theme/editor/looks.mjs +7 -7
- package/theme/editor/previews.tsx +56 -56
- package/theme/layouts/Base.astro +273 -273
- package/theme/layouts/PageLayout.astro +126 -126
- package/theme/layouts/PostLayout.astro +137 -137
- package/theme/scripts/motion.ts +29 -29
- package/theme/styles/base.css +320 -320
- package/theme/styles/blocks.css +1808 -1808
- package/theme/styles/components.css +206 -206
- package/theme/styles/global.css +1302 -1302
- package/theme/styles/ui.css +6544 -6544
- package/theme/templates/Blog.astro +38 -38
- package/theme/templates/Category.astro +19 -19
- package/theme/templates/Home.astro +36 -36
- package/theme/templates/New.astro +68 -68
- package/theme/templates/NotFound.astro +117 -117
- package/theme/theme.json +28 -28
- package/theme/ui/Badge.tsx +45 -45
- package/theme/ui/BottomSheet.tsx +148 -148
- package/theme/ui/Button.tsx +79 -79
- package/theme/ui/ButtonGroup.tsx +31 -31
- package/theme/ui/Card.tsx +45 -45
- package/theme/ui/Carousel.tsx +124 -124
- package/theme/ui/Checkbox.tsx +59 -59
- package/theme/ui/Chip.tsx +101 -101
- package/theme/ui/ChipSet.tsx +27 -27
- package/theme/ui/DatePicker.tsx +149 -149
- package/theme/ui/DatePickerContainer.tsx +316 -316
- package/theme/ui/Dialog.tsx +100 -100
- package/theme/ui/Divider.tsx +27 -27
- package/theme/ui/ExposedDropdownMenu.tsx +77 -77
- package/theme/ui/Fab.tsx +88 -88
- package/theme/ui/FabMenu.tsx +67 -67
- package/theme/ui/IconButton.tsx +78 -78
- package/theme/ui/List.tsx +287 -287
- package/theme/ui/LoadingIndicator.tsx +29 -29
- package/theme/ui/Menu.tsx +278 -278
- package/theme/ui/NavigationBar.tsx +62 -62
- package/theme/ui/NavigationDrawer.tsx +80 -80
- package/theme/ui/NavigationRail.tsx +154 -154
- package/theme/ui/ProgressIndicator.tsx +162 -162
- package/theme/ui/RadioButton.tsx +50 -50
- package/theme/ui/Search.tsx +129 -129
- package/theme/ui/SegmentedButton.tsx +49 -49
- package/theme/ui/SideSheet.tsx +54 -54
- package/theme/ui/Slider.tsx +155 -155
- package/theme/ui/Snackbar.tsx +67 -67
- package/theme/ui/SplitButton.tsx +67 -67
- package/theme/ui/Switch.tsx +60 -60
- package/theme/ui/Tabs.tsx +114 -114
- package/theme/ui/TextField.tsx +278 -278
- package/theme/ui/TimePicker.tsx +128 -128
- package/theme/ui/TimePickerContainer.tsx +234 -234
- package/theme/ui/Toolbar.tsx +67 -67
- package/theme/ui/Tooltip.tsx +58 -58
- package/theme/ui/TopAppBar.tsx +77 -77
- package/theme/ui/bottomSheet.script.ts +8 -8
- package/theme/ui/{bottomSheet.ts → bottomSheetControl.ts} +211 -211
- package/theme/ui/carousel.script.ts +28 -28
- package/theme/ui/carouselLayout.ts +229 -229
- package/theme/ui/checkbox.script.ts +8 -8
- package/theme/ui/datePicker.script.ts +302 -302
- package/theme/ui/dates.ts +185 -185
- package/theme/ui/{dialog.ts → dialogControl.ts} +48 -48
- package/theme/ui/dropdownMenu.script.ts +166 -166
- package/theme/ui/fabMenu.script.ts +57 -57
- package/theme/ui/navigationRail.script.ts +47 -47
- package/theme/ui/ripple.script.ts +159 -159
- package/theme/ui/search.script.ts +92 -92
- package/theme/ui/{sideSheet.ts → sideSheetControl.ts} +48 -48
- package/theme/ui/slider.script.ts +12 -12
- package/theme/ui/sliderUpdate.ts +52 -52
- package/theme/ui/snackbar.script.ts +16 -16
- package/theme/ui/splitButton.script.ts +63 -63
- package/theme/ui/tabs.script.ts +48 -48
- package/theme/ui/textField.script.ts +17 -17
- package/theme/ui/textFieldUpdate.ts +44 -44
- package/theme/ui/timePicker.script.ts +248 -248
- package/theme/ui/toolbar.script.ts +43 -43
- package/theme/ui/tooltip.script.ts +68 -68
- package/worker/consent.js +141 -141
- package/worker/editor-github.js +167 -167
- package/worker/editor-host.js +74 -74
- package/worker/files.js +401 -401
- package/worker/github.js +36 -36
- package/worker/index.js +188 -184
- package/worker/not-found.js +97 -97
- package/worker/oauth.js +95 -95
- package/worker/publish.js +52 -52
- package/worker/push.js +270 -270
- package/worker/r2-status.js +50 -50
- package/worker/session.js +58 -58
- package/worker/store.js +46 -0
package/site/site.ts
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
// Name, title, phone, email, address and CVR number: contact.json; the texts of "Book en tid": booking.json (the calendar
|
|
2
|
-
// is the app Calendly's, src/apps/calendly/); the menus: menu.json and mobile-menu.json; the shared texts of the other blocks: their shared.ts, with those saved in
|
|
3
|
-
// blocks.json over them (`blockTexts`).
|
|
4
|
-
// The site's owner edits them in the editor (/editor/); what the editor does not edit is the site's config
|
|
5
|
-
// (src/site/config.ts).
|
|
6
|
-
import contact from '@data/contact.json';
|
|
7
|
-
import booking from '@data/booking.json';
|
|
8
|
-
import menu from '@data/menu.json';
|
|
9
|
-
import mobileMenu from '@data/mobile-menu.json';
|
|
10
|
-
import blocks from '@data/blocks.json';
|
|
11
|
-
import standardPages from '@data/standard-pages.json';
|
|
12
|
-
import { config } from '@site/config';
|
|
13
|
-
import { sharedTexts, type SharedTexts } from '@morphemecms/cms/src/shared';
|
|
14
|
-
import { standardShared } from '@morphemecms/cms/src/standard/sharedTexts';
|
|
15
|
-
|
|
16
|
-
// The number with its country code: +45 when it has none (a number in Denmark, saved without it), else
|
|
17
|
-
// its own ("+46 70 12 34 56", picked in the editor).
|
|
18
|
-
const phoneIntl = `${contact.phone.trim().startsWith('+') ? '+' : '+45'}${contact.phone.replace(/\D/g, '')}`;
|
|
19
|
-
// The CVR number, when it is filled in ("Virksomheden" › "Kontakt").
|
|
20
|
-
const { cvr = '' } = contact as typeof contact & { cvr?: string };
|
|
21
|
-
|
|
22
|
-
export const site = {
|
|
23
|
-
name: contact.name,
|
|
24
|
-
role: contact.role,
|
|
25
|
-
/** The site's own address, https://<domain> (config.ts). */
|
|
26
|
-
url: `https://${config.domain}`,
|
|
27
|
-
/** The site's language (config.ts, BCP 47: "da-DK"). */
|
|
28
|
-
locale: config.locale,
|
|
29
|
-
description: config.siteDescription,
|
|
30
|
-
phone: contact.phone,
|
|
31
|
-
phoneHref: `tel:${phoneIntl}`,
|
|
32
|
-
/** For structured data: the country code and the digits. */
|
|
33
|
-
phoneIntl,
|
|
34
|
-
email: contact.email,
|
|
35
|
-
address: { street: contact.street, city: contact.city },
|
|
36
|
-
/** The CVR number, or empty: at the bottom of every page (the theme's Footer.astro) and in the structured data. */
|
|
37
|
-
cvr,
|
|
38
|
-
mapsUrl: `https://www.google.com/maps/search/?api=1&query=${`${contact.street}, ${contact.city}`.replace(/ /g, '+')}`,
|
|
39
|
-
bookingPath: config.booking.path,
|
|
40
|
-
/** The pages a booking or an order ends on (config.ts): no action bar there. */
|
|
41
|
-
thanks: config.booking.thanks,
|
|
42
|
-
/** The page about the owner, or '' (config.ts). */
|
|
43
|
-
aboutPath: config.aboutPath,
|
|
44
|
-
/** The block after every blog post, by its type, or '' (config.ts). */
|
|
45
|
-
postEnd: config.postEnd,
|
|
46
|
-
/** The page chosen as the contact page ("Indstillinger" › "Udseende" › "Standardsider", standard-pages.json). */
|
|
47
|
-
contactPath: standardPages.contact,
|
|
48
|
-
/** The shared texts of "Book en tid" (an app's booking block). */
|
|
49
|
-
booking: { heading: booking.heading, text: booking.text },
|
|
50
|
-
/** The labels of the buttons "Book en tid" and "Ring" (the number comes after). */
|
|
51
|
-
labels: { book: booking.book, call: booking.call },
|
|
52
|
-
/** The owner's picture (config.ts), or '' when the site has none. */
|
|
53
|
-
portrait: config.picture?.src ?? '',
|
|
54
|
-
portraitAlt: config.picture?.alt ?? '',
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// Primary navigation (menu.json, "Hovedmenu"). Labels, URLs and sub-items started out as the old site's menu.
|
|
58
|
-
export type NavItem = { label: string; href: string; children?: { label: string; href: string }[] };
|
|
59
|
-
export const nav: NavItem[] = menu.items;
|
|
60
|
-
/** Whether the header has the menu and its button ("Aktiveret" under "Hovedmenu"). */
|
|
61
|
-
export const navShown = menu.enabled !== false;
|
|
62
|
-
/** The links in the bar under the header on a phone (mobile-menu.json, "Mobilmenu"); none when it is turned off. */
|
|
63
|
-
export const mobileNav: { label: string; href: string }[] = mobileMenu.enabled ? mobileMenu.items : [];
|
|
64
|
-
// Sub-items in alphabetical order (Danish: æ, ø, å last), in both the desktop and the mobile menu.
|
|
65
|
-
for (const item of nav) item.children?.sort((a, b) => a.label.localeCompare(b.label, 'da'));
|
|
66
|
-
|
|
67
|
-
/** The texts every copy of a block has ("Blokke" in the editor), with {…} for what differs, by
|
|
68
|
-
* the block's type: those written in its shared.ts, with the saved ones (blocks.json) over them. The
|
|
69
|
-
* standard blocks' first, so an app's block (src/apps/<app>/blocks/) by the same name has its own. */
|
|
70
|
-
export const blockTexts = sharedTexts(
|
|
71
|
-
{
|
|
72
|
-
...standardShared,
|
|
73
|
-
...import.meta.glob<SharedTexts>('/src/apps/*/blocks/*/shared.ts', { eager: true, import: 'default' }),
|
|
74
|
-
},
|
|
75
|
-
blocks,
|
|
76
|
-
);
|
|
1
|
+
// Name, title, phone, email, address and CVR number: contact.json; the texts of "Book en tid": booking.json (the calendar
|
|
2
|
+
// is the app Calendly's, src/apps/calendly/); the menus: menu.json and mobile-menu.json; the shared texts of the other blocks: their shared.ts, with those saved in
|
|
3
|
+
// blocks.json over them (`blockTexts`).
|
|
4
|
+
// The site's owner edits them in the editor (/editor/); what the editor does not edit is the site's config
|
|
5
|
+
// (src/site/config.ts).
|
|
6
|
+
import contact from '@data/contact.json';
|
|
7
|
+
import booking from '@data/booking.json';
|
|
8
|
+
import menu from '@data/menu.json';
|
|
9
|
+
import mobileMenu from '@data/mobile-menu.json';
|
|
10
|
+
import blocks from '@data/blocks.json';
|
|
11
|
+
import standardPages from '@data/standard-pages.json';
|
|
12
|
+
import { config } from '@site/config';
|
|
13
|
+
import { sharedTexts, type SharedTexts } from '@morphemecms/cms/src/shared';
|
|
14
|
+
import { standardShared } from '@morphemecms/cms/src/standard/sharedTexts';
|
|
15
|
+
|
|
16
|
+
// The number with its country code: +45 when it has none (a number in Denmark, saved without it), else
|
|
17
|
+
// its own ("+46 70 12 34 56", picked in the editor).
|
|
18
|
+
const phoneIntl = `${contact.phone.trim().startsWith('+') ? '+' : '+45'}${contact.phone.replace(/\D/g, '')}`;
|
|
19
|
+
// The CVR number, when it is filled in ("Virksomheden" › "Kontakt").
|
|
20
|
+
const { cvr = '' } = contact as typeof contact & { cvr?: string };
|
|
21
|
+
|
|
22
|
+
export const site = {
|
|
23
|
+
name: contact.name,
|
|
24
|
+
role: contact.role,
|
|
25
|
+
/** The site's own address, https://<domain> (config.ts). */
|
|
26
|
+
url: `https://${config.domain}`,
|
|
27
|
+
/** The site's language (config.ts, BCP 47: "da-DK"). */
|
|
28
|
+
locale: config.locale,
|
|
29
|
+
description: config.siteDescription,
|
|
30
|
+
phone: contact.phone,
|
|
31
|
+
phoneHref: `tel:${phoneIntl}`,
|
|
32
|
+
/** For structured data: the country code and the digits. */
|
|
33
|
+
phoneIntl,
|
|
34
|
+
email: contact.email,
|
|
35
|
+
address: { street: contact.street, city: contact.city },
|
|
36
|
+
/** The CVR number, or empty: at the bottom of every page (the theme's Footer.astro) and in the structured data. */
|
|
37
|
+
cvr,
|
|
38
|
+
mapsUrl: `https://www.google.com/maps/search/?api=1&query=${`${contact.street}, ${contact.city}`.replace(/ /g, '+')}`,
|
|
39
|
+
bookingPath: config.booking.path,
|
|
40
|
+
/** The pages a booking or an order ends on (config.ts): no action bar there. */
|
|
41
|
+
thanks: config.booking.thanks,
|
|
42
|
+
/** The page about the owner, or '' (config.ts). */
|
|
43
|
+
aboutPath: config.aboutPath,
|
|
44
|
+
/** The block after every blog post, by its type, or '' (config.ts). */
|
|
45
|
+
postEnd: config.postEnd,
|
|
46
|
+
/** The page chosen as the contact page ("Indstillinger" › "Udseende" › "Standardsider", standard-pages.json). */
|
|
47
|
+
contactPath: standardPages.contact,
|
|
48
|
+
/** The shared texts of "Book en tid" (an app's booking block). */
|
|
49
|
+
booking: { heading: booking.heading, text: booking.text },
|
|
50
|
+
/** The labels of the buttons "Book en tid" and "Ring" (the number comes after). */
|
|
51
|
+
labels: { book: booking.book, call: booking.call },
|
|
52
|
+
/** The owner's picture (config.ts), or '' when the site has none. */
|
|
53
|
+
portrait: config.picture?.src ?? '',
|
|
54
|
+
portraitAlt: config.picture?.alt ?? '',
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Primary navigation (menu.json, "Hovedmenu"). Labels, URLs and sub-items started out as the old site's menu.
|
|
58
|
+
export type NavItem = { label: string; href: string; children?: { label: string; href: string }[] };
|
|
59
|
+
export const nav: NavItem[] = menu.items;
|
|
60
|
+
/** Whether the header has the menu and its button ("Aktiveret" under "Hovedmenu"). */
|
|
61
|
+
export const navShown = menu.enabled !== false;
|
|
62
|
+
/** The links in the bar under the header on a phone (mobile-menu.json, "Mobilmenu"); none when it is turned off. */
|
|
63
|
+
export const mobileNav: { label: string; href: string }[] = mobileMenu.enabled ? mobileMenu.items : [];
|
|
64
|
+
// Sub-items in alphabetical order (Danish: æ, ø, å last), in both the desktop and the mobile menu.
|
|
65
|
+
for (const item of nav) item.children?.sort((a, b) => a.label.localeCompare(b.label, 'da'));
|
|
66
|
+
|
|
67
|
+
/** The texts every copy of a block has ("Blokke" in the editor), with {…} for what differs, by
|
|
68
|
+
* the block's type: those written in its shared.ts, with the saved ones (blocks.json) over them. The
|
|
69
|
+
* standard blocks' first, so an app's block (src/apps/<app>/blocks/) by the same name has its own. */
|
|
70
|
+
export const blockTexts = sharedTexts(
|
|
71
|
+
{
|
|
72
|
+
...standardShared,
|
|
73
|
+
...import.meta.glob<SharedTexts>('/src/apps/*/blocks/*/shared.ts', { eager: true, import: 'default' }),
|
|
74
|
+
},
|
|
75
|
+
blocks,
|
|
76
|
+
);
|
package/site/siteConfig.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// The site's settings (src/site/config.ts, `@site/config`) for this package's modules that also run outside Vite, where
|
|
2
|
-
// @site is no alias (astro.mjs and the scripts): loaded from the site's root, the working directory, as Node loads
|
|
3
|
-
// TypeScript. Its imports must be ones Node can follow (defineSite.mjs, not @site).
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
import { pathToFileURL } from 'node:url';
|
|
6
|
-
|
|
7
|
-
/** @type {{ config: import('./defineSite.mjs').SiteConfig }} */
|
|
8
|
-
export const { config } = await import(/* @vite-ignore */ pathToFileURL(join(process.cwd(), 'src/site/config.ts')).href);
|
|
1
|
+
// The site's settings (src/site/config.ts, `@site/config`) for this package's modules that also run outside Vite, where
|
|
2
|
+
// @site is no alias (astro.mjs and the scripts): loaded from the site's root, the working directory, as Node loads
|
|
3
|
+
// TypeScript. Its imports must be ones Node can follow (defineSite.mjs, not @site).
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
6
|
+
|
|
7
|
+
/** @type {{ config: import('./defineSite.mjs').SiteConfig }} */
|
|
8
|
+
export const { config } = await import(/* @vite-ignore */ pathToFileURL(join(process.cwd(), 'src/site/config.ts')).href);
|
package/site/siteCsp.mjs
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
// What this site's pages may load from elsewhere, besides what the editor's package allows on every site (the
|
|
2
|
-
// videos, packages/editor/lib/csp.mjs, which writes the policy into the pages): what each installed app needs
|
|
3
|
-
// (src/apps/<app>/csp.json, src/data/apps.json), Google Analytics, Google Ads and Google Tag Manager too, which load
|
|
4
|
-
// Google's tag once the visitor has said yes (src/scripts/tracking.ts), and the addresses allowed in the editor after
|
|
5
|
-
// the policy stopped them (src/data/csp.json, config.csp: the app "Cookiescanner"'s "Blokeret adresse").
|
|
6
|
-
// Read by the build (packages/editor/astro.mjs) and by npm run check:content (appCspProblems), so no TypeScript here.
|
|
7
|
-
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
8
|
-
import { pathToFileURL } from 'node:url';
|
|
9
|
-
import { allows, sourcesProblems } from '../lib/csp.mjs';
|
|
10
|
-
|
|
11
|
-
// The site's src/, from its root (the working directory).
|
|
12
|
-
const SRC = pathToFileURL(`${process.cwd()}/src/`);
|
|
13
|
-
|
|
14
|
-
const json = (file) => JSON.parse(readFileSync(new URL(file, SRC), 'utf8'));
|
|
15
|
-
|
|
16
|
-
const appSources = (app) => {
|
|
17
|
-
const file = new URL(`apps/${app}/csp.json`, SRC);
|
|
18
|
-
return existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) : {};
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// The addresses allowed in the editor (config.csp), as an app's csp.json.
|
|
22
|
-
const ALLOWED = new URL('data/csp.json', SRC);
|
|
23
|
-
const allowedSources = () => (existsSync(ALLOWED) ? JSON.parse(readFileSync(ALLOWED, 'utf8')) : {});
|
|
24
|
-
|
|
25
|
-
/** What the site's installed apps load from elsewhere, and the addresses allowed in the editor.
|
|
26
|
-
* @returns {import('../lib/csp.mjs').Sources[]} */
|
|
27
|
-
export function siteSources() {
|
|
28
|
-
return [...(json('data/apps.json').installed ?? []).map(appSources), allowedSources()];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** What is wrong with the addresses allowed in the editor (src/data/csp.json): not JSON, or not written as an app's
|
|
32
|
-
* csp.json must be (npm run check:content). */
|
|
33
|
-
export function allowedCspProblems() {
|
|
34
|
-
try {
|
|
35
|
-
return sourcesProblems(allowedSources(), 'src/data/csp.json');
|
|
36
|
-
} catch {
|
|
37
|
-
return ['src/data/csp.json: er ikke JSON.'];
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// A line of code that loads from an address (not a link to it): a script's or a frame's src, fetch, import …
|
|
42
|
-
const LOADS = /\bsrc\b|\bsrcset\b|\bfetch\(|\bimport\(|\bsendBeacon\(|\bEventSource\(|\bWebSocket\(|\bXMLHttpRequest\b/;
|
|
43
|
-
const ADDRESS = /https:\/\/[a-z0-9-]+(?:\.[a-z0-9-]+)+/gi;
|
|
44
|
-
// An app's files that do not run in a browser on the site: its part of the Worker and its step after the build
|
|
45
|
-
// (packages/editor/lib/apps.mjs).
|
|
46
|
-
const OFF_SITE = new Set(['worker.js', 'build.mjs']);
|
|
47
|
-
|
|
48
|
-
/** What is wrong with what the apps (all of them, installed or not) say they load from elsewhere: a csp.json not
|
|
49
|
-
* written as it must be, or an address the app's code on the site loads from that its csp.json does not have (npm run
|
|
50
|
-
* check:content). */
|
|
51
|
-
export function appCspProblems() {
|
|
52
|
-
const apps = new URL('apps/', SRC);
|
|
53
|
-
if (!existsSync(apps)) return [];
|
|
54
|
-
return readdirSync(apps, { withFileTypes: true })
|
|
55
|
-
.filter((d) => d.isDirectory())
|
|
56
|
-
.flatMap(({ name: app }) => {
|
|
57
|
-
const dir = `src/apps/${app}`;
|
|
58
|
-
let sources;
|
|
59
|
-
try {
|
|
60
|
-
sources = appSources(app);
|
|
61
|
-
} catch {
|
|
62
|
-
return [`${dir}/csp.json: er ikke JSON.`];
|
|
63
|
-
}
|
|
64
|
-
const problems = sourcesProblems(sources, `${dir}/csp.json`);
|
|
65
|
-
if (problems.length) return problems;
|
|
66
|
-
const missing = new Set();
|
|
67
|
-
for (const file of readdirSync(new URL(`${app}/`, apps), { recursive: true, encoding: 'utf8' }))
|
|
68
|
-
if (/\.(tsx?|mjs|js|astro)$/.test(file) && !OFF_SITE.has(file))
|
|
69
|
-
for (const line of readFileSync(new URL(`${app}/${file}`, apps), 'utf8').split('\n'))
|
|
70
|
-
if (LOADS.test(line)) for (const [url] of line.matchAll(ADDRESS)) if (!allows(sources, url)) missing.add(new URL(url).origin);
|
|
71
|
-
return [...missing].map(
|
|
72
|
-
(origin) => `${dir}: henter fra ${origin}, men csp.json har det ikke, så sidernes Content-Security-Policy stopper det.`,
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
}
|
|
1
|
+
// What this site's pages may load from elsewhere, besides what the editor's package allows on every site (the
|
|
2
|
+
// videos, packages/editor/lib/csp.mjs, which writes the policy into the pages): what each installed app needs
|
|
3
|
+
// (src/apps/<app>/csp.json, src/data/apps.json), Google Analytics, Google Ads and Google Tag Manager too, which load
|
|
4
|
+
// Google's tag once the visitor has said yes (src/scripts/tracking.ts), and the addresses allowed in the editor after
|
|
5
|
+
// the policy stopped them (src/data/csp.json, config.csp: the app "Cookiescanner"'s "Blokeret adresse").
|
|
6
|
+
// Read by the build (packages/editor/astro.mjs) and by npm run check:content (appCspProblems), so no TypeScript here.
|
|
7
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
8
|
+
import { pathToFileURL } from 'node:url';
|
|
9
|
+
import { allows, sourcesProblems } from '../lib/csp.mjs';
|
|
10
|
+
|
|
11
|
+
// The site's src/, from its root (the working directory).
|
|
12
|
+
const SRC = pathToFileURL(`${process.cwd()}/src/`);
|
|
13
|
+
|
|
14
|
+
const json = (file) => JSON.parse(readFileSync(new URL(file, SRC), 'utf8'));
|
|
15
|
+
|
|
16
|
+
const appSources = (app) => {
|
|
17
|
+
const file = new URL(`apps/${app}/csp.json`, SRC);
|
|
18
|
+
return existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) : {};
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// The addresses allowed in the editor (config.csp), as an app's csp.json.
|
|
22
|
+
const ALLOWED = new URL('data/csp.json', SRC);
|
|
23
|
+
const allowedSources = () => (existsSync(ALLOWED) ? JSON.parse(readFileSync(ALLOWED, 'utf8')) : {});
|
|
24
|
+
|
|
25
|
+
/** What the site's installed apps load from elsewhere, and the addresses allowed in the editor.
|
|
26
|
+
* @returns {import('../lib/csp.mjs').Sources[]} */
|
|
27
|
+
export function siteSources() {
|
|
28
|
+
return [...(json('data/apps.json').installed ?? []).map(appSources), allowedSources()];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** What is wrong with the addresses allowed in the editor (src/data/csp.json): not JSON, or not written as an app's
|
|
32
|
+
* csp.json must be (npm run check:content). */
|
|
33
|
+
export function allowedCspProblems() {
|
|
34
|
+
try {
|
|
35
|
+
return sourcesProblems(allowedSources(), 'src/data/csp.json');
|
|
36
|
+
} catch {
|
|
37
|
+
return ['src/data/csp.json: er ikke JSON.'];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// A line of code that loads from an address (not a link to it): a script's or a frame's src, fetch, import …
|
|
42
|
+
const LOADS = /\bsrc\b|\bsrcset\b|\bfetch\(|\bimport\(|\bsendBeacon\(|\bEventSource\(|\bWebSocket\(|\bXMLHttpRequest\b/;
|
|
43
|
+
const ADDRESS = /https:\/\/[a-z0-9-]+(?:\.[a-z0-9-]+)+/gi;
|
|
44
|
+
// An app's files that do not run in a browser on the site: its part of the Worker and its step after the build
|
|
45
|
+
// (packages/editor/lib/apps.mjs).
|
|
46
|
+
const OFF_SITE = new Set(['worker.js', 'build.mjs']);
|
|
47
|
+
|
|
48
|
+
/** What is wrong with what the apps (all of them, installed or not) say they load from elsewhere: a csp.json not
|
|
49
|
+
* written as it must be, or an address the app's code on the site loads from that its csp.json does not have (npm run
|
|
50
|
+
* check:content). */
|
|
51
|
+
export function appCspProblems() {
|
|
52
|
+
const apps = new URL('apps/', SRC);
|
|
53
|
+
if (!existsSync(apps)) return [];
|
|
54
|
+
return readdirSync(apps, { withFileTypes: true })
|
|
55
|
+
.filter((d) => d.isDirectory())
|
|
56
|
+
.flatMap(({ name: app }) => {
|
|
57
|
+
const dir = `src/apps/${app}`;
|
|
58
|
+
let sources;
|
|
59
|
+
try {
|
|
60
|
+
sources = appSources(app);
|
|
61
|
+
} catch {
|
|
62
|
+
return [`${dir}/csp.json: er ikke JSON.`];
|
|
63
|
+
}
|
|
64
|
+
const problems = sourcesProblems(sources, `${dir}/csp.json`);
|
|
65
|
+
if (problems.length) return problems;
|
|
66
|
+
const missing = new Set();
|
|
67
|
+
for (const file of readdirSync(new URL(`${app}/`, apps), { recursive: true, encoding: 'utf8' }))
|
|
68
|
+
if (/\.(tsx?|mjs|js|astro)$/.test(file) && !OFF_SITE.has(file))
|
|
69
|
+
for (const line of readFileSync(new URL(`${app}/${file}`, apps), 'utf8').split('\n'))
|
|
70
|
+
if (LOADS.test(line)) for (const [url] of line.matchAll(ADDRESS)) if (!allows(sources, url)) missing.add(new URL(url).origin);
|
|
71
|
+
return [...missing].map(
|
|
72
|
+
(origin) => `${dir}: henter fra ${origin}, men csp.json har det ikke, så sidernes Content-Security-Policy stopper det.`,
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
}
|
package/site/siteModules.mjs
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
// The site's TypeScript loaded with Vite, as the build has it (its @site, @theme and apps), for the scripts that run
|
|
2
|
-
// outside the build: Node itself loads no TypeScript from a package in node_modules, and follows no @site.
|
|
3
|
-
import { createServer } from 'vite';
|
|
4
|
-
import { appFoldersPlugin } from '../lib/apps.mjs';
|
|
5
|
-
import { aliases, themePlugin } from './theme.mjs';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Runs `use` with a loader of the site's modules (`@site/collections`, `/src/apps/<id>/index.ts`), then closes it.
|
|
9
|
-
* @template T
|
|
10
|
-
* @param {(load: (path: string) => Promise<any>) => Promise<T>} use
|
|
11
|
-
* @returns {Promise<T>}
|
|
12
|
-
*/
|
|
13
|
-
export async function withSiteModules(use) {
|
|
14
|
-
const server = await createServer({
|
|
15
|
-
configFile: false,
|
|
16
|
-
logLevel: 'error',
|
|
17
|
-
appType: 'custom',
|
|
18
|
-
plugins: [themePlugin(), appFoldersPlugin(`${process.cwd()}/`)],
|
|
19
|
-
resolve: { alias: aliases() },
|
|
20
|
-
server: { middlewareMode: true, hmr: false, ws: false },
|
|
21
|
-
});
|
|
22
|
-
try {
|
|
23
|
-
return await use((path) => server.ssrLoadModule(path));
|
|
24
|
-
} finally {
|
|
25
|
-
await server.close();
|
|
26
|
-
}
|
|
27
|
-
}
|
|
1
|
+
// The site's TypeScript loaded with Vite, as the build has it (its @site, @theme and apps), for the scripts that run
|
|
2
|
+
// outside the build: Node itself loads no TypeScript from a package in node_modules, and follows no @site.
|
|
3
|
+
import { createServer } from 'vite';
|
|
4
|
+
import { appFoldersPlugin } from '../lib/apps.mjs';
|
|
5
|
+
import { aliases, themePlugin } from './theme.mjs';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Runs `use` with a loader of the site's modules (`@site/collections`, `/src/apps/<id>/index.ts`), then closes it.
|
|
9
|
+
* @template T
|
|
10
|
+
* @param {(load: (path: string) => Promise<any>) => Promise<T>} use
|
|
11
|
+
* @returns {Promise<T>}
|
|
12
|
+
*/
|
|
13
|
+
export async function withSiteModules(use) {
|
|
14
|
+
const server = await createServer({
|
|
15
|
+
configFile: false,
|
|
16
|
+
logLevel: 'error',
|
|
17
|
+
appType: 'custom',
|
|
18
|
+
plugins: [themePlugin(), appFoldersPlugin(`${process.cwd()}/`)],
|
|
19
|
+
resolve: { alias: aliases() },
|
|
20
|
+
server: { middlewareMode: true, hmr: false, ws: false },
|
|
21
|
+
});
|
|
22
|
+
try {
|
|
23
|
+
return await use((path) => server.ssrLoadModule(path));
|
|
24
|
+
} finally {
|
|
25
|
+
await server.close();
|
|
26
|
+
}
|
|
27
|
+
}
|
package/site/standardPages.ts
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
// The blog page, the 404 page and the cookie policy: the pages chosen under "Indstillinger" › "Udseende" › "Standardsider"
|
|
2
|
-
// (src/data/standard-pages.json, packages/editor/defaults/standardPages.ts), read for the theme's templates/Blog.astro (at /blog/) and
|
|
3
|
-
// templates/NotFound.astro (the page for an address that does not exist): the page, its heading (the H1 at the top of
|
|
4
|
-
// its text, else its title), its introduction (the first paragraph of the text before its first heading or block) and the
|
|
5
|
-
// rest, shown, as sections: text ("text": a heading and Markdown) and each block by its type, with its fields; and where
|
|
6
|
-
// the cookie banner's "Læs mere" goes (cookiesHref).
|
|
7
|
-
import { slug } from 'github-slugger';
|
|
8
|
-
import paths from '@data/standard-pages.json';
|
|
9
|
-
import { getPages, type Page } from './content';
|
|
10
|
-
import { pageH1, partsOfMarkdown, sectionsFromParts } from '@morphemecms/cms/src/sections.mjs';
|
|
11
|
-
|
|
12
|
-
/** The addresses of the pages that are the front page, the blog page, the 404 page, the contact page, the privacy policy
|
|
13
|
-
* and the cookie policy (their own addresses: the front page is shown at /, the blog page at /blog/, the 404 page at none,
|
|
14
|
-
* the others at their own). */
|
|
15
|
-
export const standardPaths: {
|
|
16
|
-
front: string;
|
|
17
|
-
blog: string;
|
|
18
|
-
notFound: string;
|
|
19
|
-
contact: string;
|
|
20
|
-
privacy: string;
|
|
21
|
-
cookies: string;
|
|
22
|
-
} = paths;
|
|
23
|
-
|
|
24
|
-
export type PageSection = { type: string; hidden?: boolean; heading?: string; body?: string } & Record<string, any>;
|
|
25
|
-
export type StandardPageView = { page: Page; heading: string; intro?: string; sections: PageSection[] };
|
|
26
|
-
|
|
27
|
-
async function read(key: 'blog' | 'notFound'): Promise<StandardPageView> {
|
|
28
|
-
const page = (await getPages({ previews: false })).find((p) => p.data.path === standardPaths[key]);
|
|
29
|
-
if (!page) throw new Error(`src/data/standard-pages.json: siden ${standardPaths[key]} findes ikke, eller den er en kladde.`);
|
|
30
|
-
const sections = (sectionsFromParts(partsOfMarkdown(page.body ?? '')) as PageSection[]).filter((s) => !s.hidden);
|
|
31
|
-
// The introduction: the first paragraph of a text without a heading at the top; the rest of that text stays a section.
|
|
32
|
-
let intro: string | undefined;
|
|
33
|
-
const first = sections[0];
|
|
34
|
-
if (first?.type === 'text' && !first.heading && first.body) {
|
|
35
|
-
const [paragraph, ...rest] = first.body.trim().split(/\n\s*\n/);
|
|
36
|
-
intro = paragraph.trim();
|
|
37
|
-
if (rest.length) first.body = rest.join('\n\n');
|
|
38
|
-
else sections.shift();
|
|
39
|
-
}
|
|
40
|
-
return { page, heading: pageH1(page.body).heading || page.data.title, intro, sections };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** The blog page, shown at /blog/. */
|
|
44
|
-
export const blogPage = () => read('blog');
|
|
45
|
-
/** The 404 page, shown for an address that does not exist. */
|
|
46
|
-
export const notFoundPage = () => read('notFound');
|
|
47
|
-
|
|
48
|
-
/** The addresses the standard pages are shown at, by their own: the front page's at /, the blog page's at /blog/. */
|
|
49
|
-
export const shownAt = (path: string) => (path === standardPaths.front ? '/' : path === standardPaths.blog ? '/blog/' : path);
|
|
50
|
-
|
|
51
|
-
/** Where the cookie banner's "Læs mere" goes: the cookie policy, and when it is the privacy policy, its first heading about
|
|
52
|
-
* cookies (its id, as Astro gives it: github-slugger), if it has one. */
|
|
53
|
-
export async function cookiesHref(): Promise<string> {
|
|
54
|
-
const path = standardPaths.cookies;
|
|
55
|
-
if (path !== standardPaths.privacy) return path;
|
|
56
|
-
const page = (await getPages({ previews: false })).find((p) => p.data.path === path);
|
|
57
|
-
const heading = (page?.body ?? '').match(/^#{2,6}\s+(.*cookie.*?)\s*#*\s*$/im)?.[1];
|
|
58
|
-
return heading ? `${path}#${slug(heading)}` : path;
|
|
59
|
-
}
|
|
1
|
+
// The blog page, the 404 page and the cookie policy: the pages chosen under "Indstillinger" › "Udseende" › "Standardsider"
|
|
2
|
+
// (src/data/standard-pages.json, packages/editor/defaults/standardPages.ts), read for the theme's templates/Blog.astro (at /blog/) and
|
|
3
|
+
// templates/NotFound.astro (the page for an address that does not exist): the page, its heading (the H1 at the top of
|
|
4
|
+
// its text, else its title), its introduction (the first paragraph of the text before its first heading or block) and the
|
|
5
|
+
// rest, shown, as sections: text ("text": a heading and Markdown) and each block by its type, with its fields; and where
|
|
6
|
+
// the cookie banner's "Læs mere" goes (cookiesHref).
|
|
7
|
+
import { slug } from 'github-slugger';
|
|
8
|
+
import paths from '@data/standard-pages.json';
|
|
9
|
+
import { getPages, type Page } from './content';
|
|
10
|
+
import { pageH1, partsOfMarkdown, sectionsFromParts } from '@morphemecms/cms/src/sections.mjs';
|
|
11
|
+
|
|
12
|
+
/** The addresses of the pages that are the front page, the blog page, the 404 page, the contact page, the privacy policy
|
|
13
|
+
* and the cookie policy (their own addresses: the front page is shown at /, the blog page at /blog/, the 404 page at none,
|
|
14
|
+
* the others at their own). */
|
|
15
|
+
export const standardPaths: {
|
|
16
|
+
front: string;
|
|
17
|
+
blog: string;
|
|
18
|
+
notFound: string;
|
|
19
|
+
contact: string;
|
|
20
|
+
privacy: string;
|
|
21
|
+
cookies: string;
|
|
22
|
+
} = paths;
|
|
23
|
+
|
|
24
|
+
export type PageSection = { type: string; hidden?: boolean; heading?: string; body?: string } & Record<string, any>;
|
|
25
|
+
export type StandardPageView = { page: Page; heading: string; intro?: string; sections: PageSection[] };
|
|
26
|
+
|
|
27
|
+
async function read(key: 'blog' | 'notFound'): Promise<StandardPageView> {
|
|
28
|
+
const page = (await getPages({ previews: false })).find((p) => p.data.path === standardPaths[key]);
|
|
29
|
+
if (!page) throw new Error(`src/data/standard-pages.json: siden ${standardPaths[key]} findes ikke, eller den er en kladde.`);
|
|
30
|
+
const sections = (sectionsFromParts(partsOfMarkdown(page.body ?? '')) as PageSection[]).filter((s) => !s.hidden);
|
|
31
|
+
// The introduction: the first paragraph of a text without a heading at the top; the rest of that text stays a section.
|
|
32
|
+
let intro: string | undefined;
|
|
33
|
+
const first = sections[0];
|
|
34
|
+
if (first?.type === 'text' && !first.heading && first.body) {
|
|
35
|
+
const [paragraph, ...rest] = first.body.trim().split(/\n\s*\n/);
|
|
36
|
+
intro = paragraph.trim();
|
|
37
|
+
if (rest.length) first.body = rest.join('\n\n');
|
|
38
|
+
else sections.shift();
|
|
39
|
+
}
|
|
40
|
+
return { page, heading: pageH1(page.body).heading || page.data.title, intro, sections };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** The blog page, shown at /blog/. */
|
|
44
|
+
export const blogPage = () => read('blog');
|
|
45
|
+
/** The 404 page, shown for an address that does not exist. */
|
|
46
|
+
export const notFoundPage = () => read('notFound');
|
|
47
|
+
|
|
48
|
+
/** The addresses the standard pages are shown at, by their own: the front page's at /, the blog page's at /blog/. */
|
|
49
|
+
export const shownAt = (path: string) => (path === standardPaths.front ? '/' : path === standardPaths.blog ? '/blog/' : path);
|
|
50
|
+
|
|
51
|
+
/** Where the cookie banner's "Læs mere" goes: the cookie policy, and when it is the privacy policy, its first heading about
|
|
52
|
+
* cookies (its id, as Astro gives it: github-slugger), if it has one. */
|
|
53
|
+
export async function cookiesHref(): Promise<string> {
|
|
54
|
+
const path = standardPaths.cookies;
|
|
55
|
+
if (path !== standardPaths.privacy) return path;
|
|
56
|
+
const page = (await getPages({ previews: false })).find((p) => p.data.path === path);
|
|
57
|
+
const heading = (page?.body ?? '').match(/^#{2,6}\s+(.*cookie.*?)\s*#*\s*$/im)?.[1];
|
|
58
|
+
return heading ? `${path}#${slug(heading)}` : path;
|
|
59
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** What is wrong with the imports in a store theme's CSS file.
|
|
2
|
+
* @param {string} css the file's text
|
|
3
|
+
* @param {string} file its path in the theme, e.g. 'styles/global.css'
|
|
4
|
+
* @returns {string[]}
|
|
5
|
+
*/
|
|
6
|
+
export function storeImportProblems(css: string, file: string): string[];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Keeps a store theme's CSS to imports from the CMS and its own files, which is all that is there on a site that
|
|
2
|
+
// installs it. Exposes storeImportProblems, the problems in one CSS file's imports. Depends on node:path only.
|
|
3
|
+
import { posix } from 'node:path';
|
|
4
|
+
|
|
5
|
+
/** What is wrong with the imports in a store theme's CSS file.
|
|
6
|
+
* @param {string} css the file's text
|
|
7
|
+
* @param {string} file its path in the theme, e.g. 'styles/global.css'
|
|
8
|
+
* @returns {string[]}
|
|
9
|
+
*/
|
|
10
|
+
export function storeImportProblems(css, file) {
|
|
11
|
+
const text = css.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
12
|
+
// One pass over both forms, so the targets come in the order they appear in the text.
|
|
13
|
+
const targets = [];
|
|
14
|
+
const targetRe = /@import\s+(['"])(.*?)\1|url\(\s*(['"]?)(.*?)\3\s*\)/g;
|
|
15
|
+
let match;
|
|
16
|
+
while ((match = targetRe.exec(text))) targets.push(match[2] !== undefined ? match[2] : match[4].trim());
|
|
17
|
+
|
|
18
|
+
return targets
|
|
19
|
+
.filter((target) => {
|
|
20
|
+
if (target.startsWith('data:')) return false;
|
|
21
|
+
if (target.startsWith('@morphemecms/cms/')) return false;
|
|
22
|
+
if (target.startsWith('./') || target.startsWith('../')) {
|
|
23
|
+
const joined = posix.normalize(posix.join(posix.dirname(file), target));
|
|
24
|
+
if (joined !== '..' && !joined.startsWith('../')) return false;
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
})
|
|
28
|
+
.map((target) => `${file}: et tema i butikken må kun importere fra @morphemecms/cms og sine egne filer, ikke "${target}".`);
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// What is wrong with a store theme's CSS imports: only the CMS and its own files are allowed.
|
|
2
|
+
// Run with `node --test packages/editor/site/*.test.mjs` (part of npm run check).
|
|
3
|
+
import { strict as assert } from 'node:assert';
|
|
4
|
+
import { test } from 'node:test';
|
|
5
|
+
import { storeImportProblems } from './storeTheme.mjs';
|
|
6
|
+
|
|
7
|
+
const F = 'styles/global.css';
|
|
8
|
+
const expected = (target) => `${F}: et tema i butikken må kun importere fra @morphemecms/cms og sine egne filer, ikke "${target}".`;
|
|
9
|
+
|
|
10
|
+
test('an import of the CMS is allowed', () => {
|
|
11
|
+
const css = `@import '@morphemecms/cms/theme/styles/base.css';`;
|
|
12
|
+
assert.deepEqual(storeImportProblems(css, F), []);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('an npm package is not there', () => {
|
|
16
|
+
const css = `@import '@fontsource-variable/outfit';`;
|
|
17
|
+
assert.deepEqual(storeImportProblems(css, F), [expected('@fontsource-variable/outfit')]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('a font in the theme is allowed', () => {
|
|
21
|
+
const css = `@font-face { src: url('../fonts/a.woff2') format('woff2'); }`;
|
|
22
|
+
assert.deepEqual(storeImportProblems(css, F), []);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('a path that leaves the theme is not there', () => {
|
|
26
|
+
const css = `@font-face { src: url('../../x.woff2'); }`;
|
|
27
|
+
assert.deepEqual(storeImportProblems(css, F), [expected('../../x.woff2')]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('a font from another host is not there', () => {
|
|
31
|
+
const css = `@font-face { src: url(https://fonts.example/a.woff2); }`;
|
|
32
|
+
assert.deepEqual(storeImportProblems(css, F), [expected('https://fonts.example/a.woff2')]);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('a data URI is allowed', () => {
|
|
36
|
+
const css = `@font-face { src: url(data:font/woff2;base64,AA); }`;
|
|
37
|
+
assert.deepEqual(storeImportProblems(css, F), []);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('two targets outside the theme are two problems', () => {
|
|
41
|
+
const css = `@import 'https://a.example/x.css';\n@import url("other-package/x.css");`;
|
|
42
|
+
assert.deepEqual(storeImportProblems(css, F), [expected('https://a.example/x.css'), expected('other-package/x.css')]);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('the problems come in the order of the text', () => {
|
|
46
|
+
const css = `@font-face { src: url(https://a.example/x); }\n@import 'b';`;
|
|
47
|
+
assert.deepEqual(storeImportProblems(css, F), [expected('https://a.example/x'), expected('b')]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('an import in a comment is not there', () => {
|
|
51
|
+
const css = `/* @import 'left-out'; */ @import './ui.css';`;
|
|
52
|
+
assert.deepEqual(storeImportProblems(css, F), []);
|
|
53
|
+
});
|