@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/theme/ui/Chip.tsx
CHANGED
|
@@ -1,101 +1,101 @@
|
|
|
1
|
-
// A chip (m3.material.io/components/chips, .chip in ../styles/ui.css): a short label (`label`), evt. an icon before it
|
|
2
|
-
// (`icon`), or a person's picture (`avatar`: its address, on an input chip) and one after it (`trailingIcon`). Its kind
|
|
3
|
-
// (`kind`) is Material's name; how each looks is the theme's: assist (the default: a link to something related, a post's
|
|
4
|
-
// tag), filter (one of a few that choose what is shown: `selected` is the chosen one, aria-pressed on a button,
|
|
5
|
-
// aria-current="page" on a link; it has a check before its label, which a theme shows on the chosen one or not), input
|
|
6
|
-
// (something entered, evt. selected and with a button after it that removes it, `removeLabel`, its name for screen
|
|
7
|
-
// readers, and what it does in the editor, `onRemove`) and suggestion (evt. selected). Assist, filter and suggestion chips can be `elevated` (with a shadow
|
|
8
|
-
// instead of the edge, on a picture or a colour). Its states: `selected`, `disabled` (it cannot be used: a button
|
|
9
|
-
// disabled, a link only shown) and `dragged` (while it is dragged to another place, with the shadow that lifts it).
|
|
10
|
-
// With `href` it is a link (Link: on the site; in the editor only drawn), with `plain` only shown (a tag without a
|
|
11
|
-
// page), else a <button type="button">; an input chip with `removeLabel` is the chip (a <span>) with its own button and
|
|
12
|
-
// the button that removes it. Other attributes (data-…, aria-…, onClick) go on the button or the link, and `className`
|
|
13
|
-
// after its own classes. The label is a prop, not children, so an Astro component shows it as it is (BlogIndex.astro).
|
|
14
|
-
import type { ReactNode } from 'react';
|
|
15
|
-
import { Glyph, Svg, type IconRef } from '@morphemecms/cms/src/icon';
|
|
16
|
-
import { Link } from '@morphemecms/cms/src/standard/view';
|
|
17
|
-
|
|
18
|
-
export type ChipKind = 'assist' | 'filter' | 'input' | 'suggestion';
|
|
19
|
-
|
|
20
|
-
/** The kinds of a chip, as Material 3 names them. */
|
|
21
|
-
export const chipKinds: ChipKind[] = ['assist', 'filter', 'input', 'suggestion'];
|
|
22
|
-
|
|
23
|
-
/** A chip's classes: its kind's, and evt. elevated (not an input chip), dragged, and with a button that removes it. */
|
|
24
|
-
export const chipClass = (kind: ChipKind = 'assist', { elevated = false, dragged = false, removable = false } = {}) =>
|
|
25
|
-
['chip', `chip-${kind}`, elevated && kind !== 'input' && 'chip-elevated', dragged && 'chip-dragged', removable && 'chip-removable']
|
|
26
|
-
.filter(Boolean)
|
|
27
|
-
.join(' ');
|
|
28
|
-
|
|
29
|
-
export default function Chip({
|
|
30
|
-
label,
|
|
31
|
-
kind = 'assist',
|
|
32
|
-
selected,
|
|
33
|
-
elevated,
|
|
34
|
-
disabled,
|
|
35
|
-
dragged,
|
|
36
|
-
icon,
|
|
37
|
-
avatar,
|
|
38
|
-
trailingIcon,
|
|
39
|
-
removeLabel,
|
|
40
|
-
onRemove,
|
|
41
|
-
href,
|
|
42
|
-
plain,
|
|
43
|
-
className,
|
|
44
|
-
...rest
|
|
45
|
-
}: {
|
|
46
|
-
label: ReactNode;
|
|
47
|
-
kind?: ChipKind;
|
|
48
|
-
selected?: boolean;
|
|
49
|
-
elevated?: boolean;
|
|
50
|
-
disabled?: boolean;
|
|
51
|
-
dragged?: boolean;
|
|
52
|
-
icon?: IconRef;
|
|
53
|
-
avatar?: string;
|
|
54
|
-
trailingIcon?: IconRef;
|
|
55
|
-
removeLabel?: string;
|
|
56
|
-
onRemove?: () => void;
|
|
57
|
-
href?: string;
|
|
58
|
-
plain?: boolean;
|
|
59
|
-
className?: string;
|
|
60
|
-
} & Record<string, unknown>) {
|
|
61
|
-
const removable = kind === 'input' && Boolean(removeLabel);
|
|
62
|
-
const classes = [chipClass(kind, { elevated, dragged, removable }), className].filter(Boolean).join(' ');
|
|
63
|
-
// Chosen: a filter, an input or a suggestion chip that is a button (a filter chip that is a link: the open page).
|
|
64
|
-
const pressed = kind === 'assist' ? undefined : kind === 'filter' ? Boolean(selected) : selected;
|
|
65
|
-
const content = (
|
|
66
|
-
<>
|
|
67
|
-
{kind === 'filter' && <Svg name="check" size={18} className="chip-check" />}
|
|
68
|
-
{avatar ? <img src={avatar} alt="" className="chip-avatar" /> : icon && <Glyph icon={icon} size={18} />}
|
|
69
|
-
{label}
|
|
70
|
-
{trailingIcon && !removable && <Glyph icon={trailingIcon} size={18} className="chip-trailing-icon" />}
|
|
71
|
-
</>
|
|
72
|
-
);
|
|
73
|
-
if (removable)
|
|
74
|
-
return (
|
|
75
|
-
<span className={classes} data-selected={selected ? '' : undefined} aria-disabled={disabled || undefined}>
|
|
76
|
-
<button type="button" className="chip-action" aria-pressed={pressed} disabled={disabled} {...rest}>
|
|
77
|
-
{content}
|
|
78
|
-
</button>
|
|
79
|
-
<button type="button" className="chip-remove" aria-label={removeLabel} disabled={disabled} onClick={onRemove}>
|
|
80
|
-
<Glyph icon={trailingIcon ?? 'x'} size={18} />
|
|
81
|
-
</button>
|
|
82
|
-
</span>
|
|
83
|
-
);
|
|
84
|
-
if (href !== undefined && !disabled)
|
|
85
|
-
return (
|
|
86
|
-
<Link href={href} className={classes} aria-current={selected ? 'page' : undefined} {...rest}>
|
|
87
|
-
{content}
|
|
88
|
-
</Link>
|
|
89
|
-
);
|
|
90
|
-
if (plain || href !== undefined)
|
|
91
|
-
return (
|
|
92
|
-
<span className={classes} aria-disabled={disabled || undefined} {...rest}>
|
|
93
|
-
{content}
|
|
94
|
-
</span>
|
|
95
|
-
);
|
|
96
|
-
return (
|
|
97
|
-
<button type="button" className={classes} aria-pressed={pressed} disabled={disabled} {...rest}>
|
|
98
|
-
{content}
|
|
99
|
-
</button>
|
|
100
|
-
);
|
|
101
|
-
}
|
|
1
|
+
// A chip (m3.material.io/components/chips, .chip in ../styles/ui.css): a short label (`label`), evt. an icon before it
|
|
2
|
+
// (`icon`), or a person's picture (`avatar`: its address, on an input chip) and one after it (`trailingIcon`). Its kind
|
|
3
|
+
// (`kind`) is Material's name; how each looks is the theme's: assist (the default: a link to something related, a post's
|
|
4
|
+
// tag), filter (one of a few that choose what is shown: `selected` is the chosen one, aria-pressed on a button,
|
|
5
|
+
// aria-current="page" on a link; it has a check before its label, which a theme shows on the chosen one or not), input
|
|
6
|
+
// (something entered, evt. selected and with a button after it that removes it, `removeLabel`, its name for screen
|
|
7
|
+
// readers, and what it does in the editor, `onRemove`) and suggestion (evt. selected). Assist, filter and suggestion chips can be `elevated` (with a shadow
|
|
8
|
+
// instead of the edge, on a picture or a colour). Its states: `selected`, `disabled` (it cannot be used: a button
|
|
9
|
+
// disabled, a link only shown) and `dragged` (while it is dragged to another place, with the shadow that lifts it).
|
|
10
|
+
// With `href` it is a link (Link: on the site; in the editor only drawn), with `plain` only shown (a tag without a
|
|
11
|
+
// page), else a <button type="button">; an input chip with `removeLabel` is the chip (a <span>) with its own button and
|
|
12
|
+
// the button that removes it. Other attributes (data-…, aria-…, onClick) go on the button or the link, and `className`
|
|
13
|
+
// after its own classes. The label is a prop, not children, so an Astro component shows it as it is (BlogIndex.astro).
|
|
14
|
+
import type { ReactNode } from 'react';
|
|
15
|
+
import { Glyph, Svg, type IconRef } from '@morphemecms/cms/src/icon';
|
|
16
|
+
import { Link } from '@morphemecms/cms/src/standard/view';
|
|
17
|
+
|
|
18
|
+
export type ChipKind = 'assist' | 'filter' | 'input' | 'suggestion';
|
|
19
|
+
|
|
20
|
+
/** The kinds of a chip, as Material 3 names them. */
|
|
21
|
+
export const chipKinds: ChipKind[] = ['assist', 'filter', 'input', 'suggestion'];
|
|
22
|
+
|
|
23
|
+
/** A chip's classes: its kind's, and evt. elevated (not an input chip), dragged, and with a button that removes it. */
|
|
24
|
+
export const chipClass = (kind: ChipKind = 'assist', { elevated = false, dragged = false, removable = false } = {}) =>
|
|
25
|
+
['chip', `chip-${kind}`, elevated && kind !== 'input' && 'chip-elevated', dragged && 'chip-dragged', removable && 'chip-removable']
|
|
26
|
+
.filter(Boolean)
|
|
27
|
+
.join(' ');
|
|
28
|
+
|
|
29
|
+
export default function Chip({
|
|
30
|
+
label,
|
|
31
|
+
kind = 'assist',
|
|
32
|
+
selected,
|
|
33
|
+
elevated,
|
|
34
|
+
disabled,
|
|
35
|
+
dragged,
|
|
36
|
+
icon,
|
|
37
|
+
avatar,
|
|
38
|
+
trailingIcon,
|
|
39
|
+
removeLabel,
|
|
40
|
+
onRemove,
|
|
41
|
+
href,
|
|
42
|
+
plain,
|
|
43
|
+
className,
|
|
44
|
+
...rest
|
|
45
|
+
}: {
|
|
46
|
+
label: ReactNode;
|
|
47
|
+
kind?: ChipKind;
|
|
48
|
+
selected?: boolean;
|
|
49
|
+
elevated?: boolean;
|
|
50
|
+
disabled?: boolean;
|
|
51
|
+
dragged?: boolean;
|
|
52
|
+
icon?: IconRef;
|
|
53
|
+
avatar?: string;
|
|
54
|
+
trailingIcon?: IconRef;
|
|
55
|
+
removeLabel?: string;
|
|
56
|
+
onRemove?: () => void;
|
|
57
|
+
href?: string;
|
|
58
|
+
plain?: boolean;
|
|
59
|
+
className?: string;
|
|
60
|
+
} & Record<string, unknown>) {
|
|
61
|
+
const removable = kind === 'input' && Boolean(removeLabel);
|
|
62
|
+
const classes = [chipClass(kind, { elevated, dragged, removable }), className].filter(Boolean).join(' ');
|
|
63
|
+
// Chosen: a filter, an input or a suggestion chip that is a button (a filter chip that is a link: the open page).
|
|
64
|
+
const pressed = kind === 'assist' ? undefined : kind === 'filter' ? Boolean(selected) : selected;
|
|
65
|
+
const content = (
|
|
66
|
+
<>
|
|
67
|
+
{kind === 'filter' && <Svg name="check" size={18} className="chip-check" />}
|
|
68
|
+
{avatar ? <img src={avatar} alt="" className="chip-avatar" /> : icon && <Glyph icon={icon} size={18} />}
|
|
69
|
+
{label}
|
|
70
|
+
{trailingIcon && !removable && <Glyph icon={trailingIcon} size={18} className="chip-trailing-icon" />}
|
|
71
|
+
</>
|
|
72
|
+
);
|
|
73
|
+
if (removable)
|
|
74
|
+
return (
|
|
75
|
+
<span className={classes} data-selected={selected ? '' : undefined} aria-disabled={disabled || undefined}>
|
|
76
|
+
<button type="button" className="chip-action" aria-pressed={pressed} disabled={disabled} {...rest}>
|
|
77
|
+
{content}
|
|
78
|
+
</button>
|
|
79
|
+
<button type="button" className="chip-remove" aria-label={removeLabel} disabled={disabled} onClick={onRemove}>
|
|
80
|
+
<Glyph icon={trailingIcon ?? 'x'} size={18} />
|
|
81
|
+
</button>
|
|
82
|
+
</span>
|
|
83
|
+
);
|
|
84
|
+
if (href !== undefined && !disabled)
|
|
85
|
+
return (
|
|
86
|
+
<Link href={href} className={classes} aria-current={selected ? 'page' : undefined} {...rest}>
|
|
87
|
+
{content}
|
|
88
|
+
</Link>
|
|
89
|
+
);
|
|
90
|
+
if (plain || href !== undefined)
|
|
91
|
+
return (
|
|
92
|
+
<span className={classes} aria-disabled={disabled || undefined} {...rest}>
|
|
93
|
+
{content}
|
|
94
|
+
</span>
|
|
95
|
+
);
|
|
96
|
+
return (
|
|
97
|
+
<button type="button" className={classes} aria-pressed={pressed} disabled={disabled} {...rest}>
|
|
98
|
+
{content}
|
|
99
|
+
</button>
|
|
100
|
+
);
|
|
101
|
+
}
|
package/theme/ui/ChipSet.tsx
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
// A chip set (Material's chips side by side, as Material's own web components group them, md-chip-set; .chip-set in
|
|
2
|
-
// ../styles/ui.css): the theme's chips (`children`: Chip) in a group with its name (`label`, read by screen readers).
|
|
3
|
-
// Its layout (`layout`): wrap (the default: on as many lines as they need) or scroll (on one line that scrolls sideways
|
|
4
|
-
// when they are wider than it, as Material's chips do on a phone, without a scrollbar). Other attributes (data-…) go on
|
|
5
|
-
// the group, and `className` after its own classes. An Astro component gives an element the same classes with
|
|
6
|
-
// chipSetClass.
|
|
7
|
-
import type { ReactNode } from 'react';
|
|
8
|
-
|
|
9
|
-
export const chipSetLayouts = ['wrap', 'scroll'] as const;
|
|
10
|
-
export type ChipSetLayout = (typeof chipSetLayouts)[number];
|
|
11
|
-
|
|
12
|
-
/** A chip set's classes: its layout's. */
|
|
13
|
-
export const chipSetClass = (layout: ChipSetLayout = 'wrap') => `chip-set chip-set-${layout}`;
|
|
14
|
-
|
|
15
|
-
export default function ChipSet({
|
|
16
|
-
layout,
|
|
17
|
-
label,
|
|
18
|
-
className,
|
|
19
|
-
children,
|
|
20
|
-
...rest
|
|
21
|
-
}: { layout?: ChipSetLayout; label: string; className?: string; children: ReactNode } & Record<string, unknown>) {
|
|
22
|
-
return (
|
|
23
|
-
<div role="group" aria-label={label} className={[chipSetClass(layout), className].filter(Boolean).join(' ')} {...rest}>
|
|
24
|
-
{children}
|
|
25
|
-
</div>
|
|
26
|
-
);
|
|
27
|
-
}
|
|
1
|
+
// A chip set (Material's chips side by side, as Material's own web components group them, md-chip-set; .chip-set in
|
|
2
|
+
// ../styles/ui.css): the theme's chips (`children`: Chip) in a group with its name (`label`, read by screen readers).
|
|
3
|
+
// Its layout (`layout`): wrap (the default: on as many lines as they need) or scroll (on one line that scrolls sideways
|
|
4
|
+
// when they are wider than it, as Material's chips do on a phone, without a scrollbar). Other attributes (data-…) go on
|
|
5
|
+
// the group, and `className` after its own classes. An Astro component gives an element the same classes with
|
|
6
|
+
// chipSetClass.
|
|
7
|
+
import type { ReactNode } from 'react';
|
|
8
|
+
|
|
9
|
+
export const chipSetLayouts = ['wrap', 'scroll'] as const;
|
|
10
|
+
export type ChipSetLayout = (typeof chipSetLayouts)[number];
|
|
11
|
+
|
|
12
|
+
/** A chip set's classes: its layout's. */
|
|
13
|
+
export const chipSetClass = (layout: ChipSetLayout = 'wrap') => `chip-set chip-set-${layout}`;
|
|
14
|
+
|
|
15
|
+
export default function ChipSet({
|
|
16
|
+
layout,
|
|
17
|
+
label,
|
|
18
|
+
className,
|
|
19
|
+
children,
|
|
20
|
+
...rest
|
|
21
|
+
}: { layout?: ChipSetLayout; label: string; className?: string; children: ReactNode } & Record<string, unknown>) {
|
|
22
|
+
return (
|
|
23
|
+
<div role="group" aria-label={label} className={[chipSetClass(layout), className].filter(Boolean).join(' ')} {...rest}>
|
|
24
|
+
{children}
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
package/theme/ui/DatePicker.tsx
CHANGED
|
@@ -1,149 +1,149 @@
|
|
|
1
|
-
// A date picker (m3.material.io/components/date-pickers, .date-picker in ../styles/ui.css): a text field to type a
|
|
2
|
-
// date in (in the site's language's order, 02.11.2026), with a calendar button that opens the picker
|
|
3
|
-
// (DatePickerContainer.tsx), and what a form sends, the day as ISO (2026-11-02), in a hidden input named `name` (and,
|
|
4
|
-
// with `range`, the last day in one named `endName`). `kind`: docked (the picker opens under the field) or modal (in a
|
|
5
|
-
// dialog in the middle of the screen, also with a keyboard input mode); a range is always modal. `value`, `endValue`:
|
|
6
|
-
// the day(s) it starts with; `min`, `max`: the first and last day that can be picked; `label`, `supporting`, `error`:
|
|
7
|
-
// the field's name, the line under it (else the date's format) and what is wrong with it (the field marked);
|
|
8
|
-
// `required`, `id` and the rest go on the field's input, and `className` on the field. On the site datePicker.script.ts opens it, draws the picker in its <dialog>, writes the
|
|
9
|
-
// day picked into the inputs and closes it; in the editor's previews it is only drawn, and with `onChange` (the editor's
|
|
10
|
-
// own fields) it works the same way, here, and says the day(s) picked (or '' for none). Its fixed texts
|
|
11
|
-
// (datePickerTexts) are the site's own, in @site/texts, unless `texts` gives them (the editor's, in its language).
|
|
12
|
-
import { useEffect, useRef, type ReactNode } from 'react';
|
|
13
|
-
import { siteText, locale } from '@morphemecms/cms/src/i18n';
|
|
14
|
-
import { datePickerField } from '@theme/ui/datePicker.script';
|
|
15
|
-
import IconButton from '@theme/ui/IconButton';
|
|
16
|
-
import TextField from '@theme/ui/TextField';
|
|
17
|
-
import { dateOf, dayTyped } from '@theme/ui/dates';
|
|
18
|
-
import type { DatePickerKind, DatePickerTexts } from '@theme/ui/DatePickerContainer';
|
|
19
|
-
|
|
20
|
-
/** A date picker's fixed texts, in the language its dates are written in. */
|
|
21
|
-
export const datePickerTexts = (): DatePickerTexts => ({
|
|
22
|
-
locale,
|
|
23
|
-
select: siteText('Vælg dato'),
|
|
24
|
-
selectRange: siteText('Vælg datoer'),
|
|
25
|
-
enter: siteText('Skriv dato'),
|
|
26
|
-
enterRange: siteText('Skriv datoer'),
|
|
27
|
-
date: siteText('Dato'),
|
|
28
|
-
start: siteText('Startdato'),
|
|
29
|
-
end: siteText('Slutdato'),
|
|
30
|
-
format: siteText('dd.mm.åååå'),
|
|
31
|
-
wrongFormat: siteText('Skriv datoen som dd.mm.åååå.'),
|
|
32
|
-
notAllowed: siteText('Datoen kan ikke vælges.'),
|
|
33
|
-
endBeforeStart: siteText('Slutdatoen er før startdatoen.'),
|
|
34
|
-
previousMonth: siteText('Forrige måned'),
|
|
35
|
-
nextMonth: siteText('Næste måned'),
|
|
36
|
-
previousYear: siteText('Forrige år'),
|
|
37
|
-
nextYear: siteText('Næste år'),
|
|
38
|
-
chooseMonth: siteText('Vælg måned'),
|
|
39
|
-
chooseYear: siteText('Vælg år'),
|
|
40
|
-
toInput: siteText('Skift til at skrive'),
|
|
41
|
-
toCalendar: siteText('Skift til kalenderen'),
|
|
42
|
-
cancel: siteText('Annuller'),
|
|
43
|
-
ok: siteText('OK'),
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
/** What a date picker's script is told by its field: the fixed texts and what can be picked. */
|
|
47
|
-
export type DatePickerSettings = { texts: DatePickerTexts; kind: DatePickerKind; range: boolean; min: string; max: string };
|
|
48
|
-
|
|
49
|
-
export default function DatePicker({
|
|
50
|
-
label,
|
|
51
|
-
name,
|
|
52
|
-
endName,
|
|
53
|
-
value = '',
|
|
54
|
-
endValue = '',
|
|
55
|
-
kind = 'docked',
|
|
56
|
-
range = false,
|
|
57
|
-
min = '',
|
|
58
|
-
max = '',
|
|
59
|
-
supporting,
|
|
60
|
-
error,
|
|
61
|
-
texts: given,
|
|
62
|
-
onChange,
|
|
63
|
-
className,
|
|
64
|
-
...rest
|
|
65
|
-
}: {
|
|
66
|
-
label: string;
|
|
67
|
-
name: string;
|
|
68
|
-
endName?: string;
|
|
69
|
-
value?: string;
|
|
70
|
-
endValue?: string;
|
|
71
|
-
kind?: DatePickerKind;
|
|
72
|
-
range?: boolean;
|
|
73
|
-
min?: string;
|
|
74
|
-
max?: string;
|
|
75
|
-
supporting?: ReactNode;
|
|
76
|
-
error?: string | boolean;
|
|
77
|
-
texts?: DatePickerTexts;
|
|
78
|
-
onChange?: (value: string, endValue: string) => void;
|
|
79
|
-
className?: string;
|
|
80
|
-
} & Record<string, unknown>) {
|
|
81
|
-
const texts = given ?? datePickerTexts();
|
|
82
|
-
const modal = kind === 'modal' || range;
|
|
83
|
-
const settings: DatePickerSettings = { texts, kind: modal ? 'modal' : 'docked', range, min, max };
|
|
84
|
-
const typed = [value, range ? endValue : '']
|
|
85
|
-
.filter((d) => dateOf(d))
|
|
86
|
-
.map((d) => dayTyped(d, texts.locale))
|
|
87
|
-
.join(' – ');
|
|
88
|
-
const format = range ? `${texts.format} – ${texts.format}` : texts.format;
|
|
89
|
-
const title = range ? texts.selectRange : texts.select;
|
|
90
|
-
const box = useWorking(onChange, [value, endValue], typed);
|
|
91
|
-
return (
|
|
92
|
-
<div ref={box} className={['date-picker-field', className].filter(Boolean).join(' ')} data-date-picker={JSON.stringify(settings)}>
|
|
93
|
-
<TextField
|
|
94
|
-
label={label}
|
|
95
|
-
supporting={supporting ?? format}
|
|
96
|
-
error={error}
|
|
97
|
-
placeholder={format}
|
|
98
|
-
defaultValue={typed}
|
|
99
|
-
inputMode="numeric"
|
|
100
|
-
autoComplete="off"
|
|
101
|
-
data-date-picker-text=""
|
|
102
|
-
{...rest}
|
|
103
|
-
/>
|
|
104
|
-
<IconButton
|
|
105
|
-
icon="calendar-blank"
|
|
106
|
-
label={title}
|
|
107
|
-
className="date-picker-field-button"
|
|
108
|
-
aria-haspopup="dialog"
|
|
109
|
-
aria-expanded="false"
|
|
110
|
-
data-date-picker-open=""
|
|
111
|
-
/>
|
|
112
|
-
<input type="hidden" name={name} defaultValue={dateOf(value) ? value : ''} data-date-picker-value="0" />
|
|
113
|
-
{range && <input type="hidden" name={endName} defaultValue={dateOf(endValue) ? endValue : ''} data-date-picker-value="1" />}
|
|
114
|
-
<dialog
|
|
115
|
-
className={modal ? 'dialog-modal date-picker-dialog' : 'date-picker-popover'}
|
|
116
|
-
aria-label={title}
|
|
117
|
-
data-date-picker-dialog=""
|
|
118
|
-
></dialog>
|
|
119
|
-
</div>
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// A picker the editor changes (`onChange`): made to work here as on the site, telling the editor what is picked, and
|
|
124
|
-
// showing what the editor's value is when it changes from outside (a version restored).
|
|
125
|
-
function useWorking(onChange: ((value: string, endValue: string) => void) | undefined, values: string[], typed: string) {
|
|
126
|
-
const box = useRef<HTMLDivElement>(null);
|
|
127
|
-
const told = useRef(onChange);
|
|
128
|
-
told.current = onChange;
|
|
129
|
-
const working = onChange !== undefined;
|
|
130
|
-
useEffect(() => {
|
|
131
|
-
const field = box.current;
|
|
132
|
-
if (!working || !field) return;
|
|
133
|
-
datePickerField(field);
|
|
134
|
-
const inputs = [...field.querySelectorAll<HTMLInputElement>('[data-date-picker-value]')];
|
|
135
|
-
const changed = () => told.current?.(inputs[0]?.value ?? '', inputs[1]?.value ?? '');
|
|
136
|
-
inputs.forEach((i) => i.addEventListener('change', changed));
|
|
137
|
-
return () => inputs.forEach((i) => i.removeEventListener('change', changed));
|
|
138
|
-
}, [working]);
|
|
139
|
-
useEffect(() => {
|
|
140
|
-
const field = box.current;
|
|
141
|
-
if (!working || !field) return;
|
|
142
|
-
const inputs = [...field.querySelectorAll<HTMLInputElement>('[data-date-picker-value]')];
|
|
143
|
-
if (inputs.every((input, i) => input.value === (dateOf(values[i] ?? '') ? values[i] : ''))) return;
|
|
144
|
-
inputs.forEach((input, i) => (input.value = dateOf(values[i] ?? '') ? values[i]! : ''));
|
|
145
|
-
const text = field.querySelector<HTMLInputElement>('[data-date-picker-text]');
|
|
146
|
-
if (text) text.value = typed;
|
|
147
|
-
}, [working, ...values]);
|
|
148
|
-
return box;
|
|
149
|
-
}
|
|
1
|
+
// A date picker (m3.material.io/components/date-pickers, .date-picker in ../styles/ui.css): a text field to type a
|
|
2
|
+
// date in (in the site's language's order, 02.11.2026), with a calendar button that opens the picker
|
|
3
|
+
// (DatePickerContainer.tsx), and what a form sends, the day as ISO (2026-11-02), in a hidden input named `name` (and,
|
|
4
|
+
// with `range`, the last day in one named `endName`). `kind`: docked (the picker opens under the field) or modal (in a
|
|
5
|
+
// dialog in the middle of the screen, also with a keyboard input mode); a range is always modal. `value`, `endValue`:
|
|
6
|
+
// the day(s) it starts with; `min`, `max`: the first and last day that can be picked; `label`, `supporting`, `error`:
|
|
7
|
+
// the field's name, the line under it (else the date's format) and what is wrong with it (the field marked);
|
|
8
|
+
// `required`, `id` and the rest go on the field's input, and `className` on the field. On the site datePicker.script.ts opens it, draws the picker in its <dialog>, writes the
|
|
9
|
+
// day picked into the inputs and closes it; in the editor's previews it is only drawn, and with `onChange` (the editor's
|
|
10
|
+
// own fields) it works the same way, here, and says the day(s) picked (or '' for none). Its fixed texts
|
|
11
|
+
// (datePickerTexts) are the site's own, in @site/texts, unless `texts` gives them (the editor's, in its language).
|
|
12
|
+
import { useEffect, useRef, type ReactNode } from 'react';
|
|
13
|
+
import { siteText, locale } from '@morphemecms/cms/src/i18n';
|
|
14
|
+
import { datePickerField } from '@theme/ui/datePicker.script';
|
|
15
|
+
import IconButton from '@theme/ui/IconButton';
|
|
16
|
+
import TextField from '@theme/ui/TextField';
|
|
17
|
+
import { dateOf, dayTyped } from '@theme/ui/dates';
|
|
18
|
+
import type { DatePickerKind, DatePickerTexts } from '@theme/ui/DatePickerContainer';
|
|
19
|
+
|
|
20
|
+
/** A date picker's fixed texts, in the language its dates are written in. */
|
|
21
|
+
export const datePickerTexts = (): DatePickerTexts => ({
|
|
22
|
+
locale,
|
|
23
|
+
select: siteText('Vælg dato'),
|
|
24
|
+
selectRange: siteText('Vælg datoer'),
|
|
25
|
+
enter: siteText('Skriv dato'),
|
|
26
|
+
enterRange: siteText('Skriv datoer'),
|
|
27
|
+
date: siteText('Dato'),
|
|
28
|
+
start: siteText('Startdato'),
|
|
29
|
+
end: siteText('Slutdato'),
|
|
30
|
+
format: siteText('dd.mm.åååå'),
|
|
31
|
+
wrongFormat: siteText('Skriv datoen som dd.mm.åååå.'),
|
|
32
|
+
notAllowed: siteText('Datoen kan ikke vælges.'),
|
|
33
|
+
endBeforeStart: siteText('Slutdatoen er før startdatoen.'),
|
|
34
|
+
previousMonth: siteText('Forrige måned'),
|
|
35
|
+
nextMonth: siteText('Næste måned'),
|
|
36
|
+
previousYear: siteText('Forrige år'),
|
|
37
|
+
nextYear: siteText('Næste år'),
|
|
38
|
+
chooseMonth: siteText('Vælg måned'),
|
|
39
|
+
chooseYear: siteText('Vælg år'),
|
|
40
|
+
toInput: siteText('Skift til at skrive'),
|
|
41
|
+
toCalendar: siteText('Skift til kalenderen'),
|
|
42
|
+
cancel: siteText('Annuller'),
|
|
43
|
+
ok: siteText('OK'),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/** What a date picker's script is told by its field: the fixed texts and what can be picked. */
|
|
47
|
+
export type DatePickerSettings = { texts: DatePickerTexts; kind: DatePickerKind; range: boolean; min: string; max: string };
|
|
48
|
+
|
|
49
|
+
export default function DatePicker({
|
|
50
|
+
label,
|
|
51
|
+
name,
|
|
52
|
+
endName,
|
|
53
|
+
value = '',
|
|
54
|
+
endValue = '',
|
|
55
|
+
kind = 'docked',
|
|
56
|
+
range = false,
|
|
57
|
+
min = '',
|
|
58
|
+
max = '',
|
|
59
|
+
supporting,
|
|
60
|
+
error,
|
|
61
|
+
texts: given,
|
|
62
|
+
onChange,
|
|
63
|
+
className,
|
|
64
|
+
...rest
|
|
65
|
+
}: {
|
|
66
|
+
label: string;
|
|
67
|
+
name: string;
|
|
68
|
+
endName?: string;
|
|
69
|
+
value?: string;
|
|
70
|
+
endValue?: string;
|
|
71
|
+
kind?: DatePickerKind;
|
|
72
|
+
range?: boolean;
|
|
73
|
+
min?: string;
|
|
74
|
+
max?: string;
|
|
75
|
+
supporting?: ReactNode;
|
|
76
|
+
error?: string | boolean;
|
|
77
|
+
texts?: DatePickerTexts;
|
|
78
|
+
onChange?: (value: string, endValue: string) => void;
|
|
79
|
+
className?: string;
|
|
80
|
+
} & Record<string, unknown>) {
|
|
81
|
+
const texts = given ?? datePickerTexts();
|
|
82
|
+
const modal = kind === 'modal' || range;
|
|
83
|
+
const settings: DatePickerSettings = { texts, kind: modal ? 'modal' : 'docked', range, min, max };
|
|
84
|
+
const typed = [value, range ? endValue : '']
|
|
85
|
+
.filter((d) => dateOf(d))
|
|
86
|
+
.map((d) => dayTyped(d, texts.locale))
|
|
87
|
+
.join(' – ');
|
|
88
|
+
const format = range ? `${texts.format} – ${texts.format}` : texts.format;
|
|
89
|
+
const title = range ? texts.selectRange : texts.select;
|
|
90
|
+
const box = useWorking(onChange, [value, endValue], typed);
|
|
91
|
+
return (
|
|
92
|
+
<div ref={box} className={['date-picker-field', className].filter(Boolean).join(' ')} data-date-picker={JSON.stringify(settings)}>
|
|
93
|
+
<TextField
|
|
94
|
+
label={label}
|
|
95
|
+
supporting={supporting ?? format}
|
|
96
|
+
error={error}
|
|
97
|
+
placeholder={format}
|
|
98
|
+
defaultValue={typed}
|
|
99
|
+
inputMode="numeric"
|
|
100
|
+
autoComplete="off"
|
|
101
|
+
data-date-picker-text=""
|
|
102
|
+
{...rest}
|
|
103
|
+
/>
|
|
104
|
+
<IconButton
|
|
105
|
+
icon="calendar-blank"
|
|
106
|
+
label={title}
|
|
107
|
+
className="date-picker-field-button"
|
|
108
|
+
aria-haspopup="dialog"
|
|
109
|
+
aria-expanded="false"
|
|
110
|
+
data-date-picker-open=""
|
|
111
|
+
/>
|
|
112
|
+
<input type="hidden" name={name} defaultValue={dateOf(value) ? value : ''} data-date-picker-value="0" />
|
|
113
|
+
{range && <input type="hidden" name={endName} defaultValue={dateOf(endValue) ? endValue : ''} data-date-picker-value="1" />}
|
|
114
|
+
<dialog
|
|
115
|
+
className={modal ? 'dialog-modal date-picker-dialog' : 'date-picker-popover'}
|
|
116
|
+
aria-label={title}
|
|
117
|
+
data-date-picker-dialog=""
|
|
118
|
+
></dialog>
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// A picker the editor changes (`onChange`): made to work here as on the site, telling the editor what is picked, and
|
|
124
|
+
// showing what the editor's value is when it changes from outside (a version restored).
|
|
125
|
+
function useWorking(onChange: ((value: string, endValue: string) => void) | undefined, values: string[], typed: string) {
|
|
126
|
+
const box = useRef<HTMLDivElement>(null);
|
|
127
|
+
const told = useRef(onChange);
|
|
128
|
+
told.current = onChange;
|
|
129
|
+
const working = onChange !== undefined;
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
const field = box.current;
|
|
132
|
+
if (!working || !field) return;
|
|
133
|
+
datePickerField(field);
|
|
134
|
+
const inputs = [...field.querySelectorAll<HTMLInputElement>('[data-date-picker-value]')];
|
|
135
|
+
const changed = () => told.current?.(inputs[0]?.value ?? '', inputs[1]?.value ?? '');
|
|
136
|
+
inputs.forEach((i) => i.addEventListener('change', changed));
|
|
137
|
+
return () => inputs.forEach((i) => i.removeEventListener('change', changed));
|
|
138
|
+
}, [working]);
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
const field = box.current;
|
|
141
|
+
if (!working || !field) return;
|
|
142
|
+
const inputs = [...field.querySelectorAll<HTMLInputElement>('[data-date-picker-value]')];
|
|
143
|
+
if (inputs.every((input, i) => input.value === (dateOf(values[i] ?? '') ? values[i] : ''))) return;
|
|
144
|
+
inputs.forEach((input, i) => (input.value = dateOf(values[i] ?? '') ? values[i]! : ''));
|
|
145
|
+
const text = field.querySelector<HTMLInputElement>('[data-date-picker-text]');
|
|
146
|
+
if (text) text.value = typed;
|
|
147
|
+
}, [working, ...values]);
|
|
148
|
+
return box;
|
|
149
|
+
}
|