@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/dates.ts
CHANGED
|
@@ -1,185 +1,185 @@
|
|
|
1
|
-
// Days and times as the date and time pickers (DatePicker.tsx, TimePicker.tsx and their scripts) hold them: a day as a
|
|
2
|
-
// form saves it (ISO, 2026-11-02), a month as its first day's year and month (2026-11), and a time of day as hh:mm
|
|
3
|
-
// (24-hour). Written out and read back in a language (`locale`, BCP 47: the site's on the site), with Intl, so the
|
|
4
|
-
// names of the months and the weekdays, the order of day, month and year and the week's first day are the language's
|
|
5
|
-
// (in Danish: 02.11.2026, november, man., the week from Monday). No React and no texts here: the scripts load it at once.
|
|
6
|
-
|
|
7
|
-
const pad = (n: number) => String(n).padStart(2, '0');
|
|
8
|
-
|
|
9
|
-
/** A day (2026-11-02) as a date at noon, so no change of time moves it a day; null when it is not one. */
|
|
10
|
-
export function dateOf(day: string): Date | null {
|
|
11
|
-
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(day);
|
|
12
|
-
if (!m) return null;
|
|
13
|
-
const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]), 12);
|
|
14
|
-
return d.getMonth() === Number(m[2]) - 1 ? d : null;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** A date's day, as a form saves it (2026-11-02). */
|
|
18
|
-
export const dayOf = (d: Date) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
19
|
-
|
|
20
|
-
/** Today, as a day. */
|
|
21
|
-
export const today = () => dayOf(new Date());
|
|
22
|
-
|
|
23
|
-
/** The month a day is in (2026-11). */
|
|
24
|
-
export const monthOfDay = (day: string) => day.slice(0, 7);
|
|
25
|
-
|
|
26
|
-
/** A month (2026-11) moved by a number of months. */
|
|
27
|
-
export function addMonths(month: string, months: number): string {
|
|
28
|
-
const [y, m] = month.split('-').map(Number);
|
|
29
|
-
return dayOf(new Date(y, m - 1 + months, 1, 12)).slice(0, 7);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** A day moved by a number of days. */
|
|
33
|
-
export function addDays(day: string, days: number): string {
|
|
34
|
-
const d = dateOf(day)!;
|
|
35
|
-
d.setDate(d.getDate() + days);
|
|
36
|
-
return dayOf(d);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** A day moved by a number of months, on the same day of the month or, in a shorter month, its last. */
|
|
40
|
-
export function addMonthsToDay(day: string, months: number): string {
|
|
41
|
-
const d = dateOf(day)!;
|
|
42
|
-
const month = addMonths(monthOfDay(day), months);
|
|
43
|
-
const [y, m] = month.split('-').map(Number);
|
|
44
|
-
const last = new Date(y, m, 0).getDate();
|
|
45
|
-
return `${month}-${pad(Math.min(d.getDate(), last))}`;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** A day within the days that can be picked (`min` and `max`, either of them '' for none). */
|
|
49
|
-
export const clampDay = (day: string, min = '', max = '') => (min && day < min ? min : max && day > max ? max : day);
|
|
50
|
-
|
|
51
|
-
/** The day a week starts with in a language (1 Monday … 7 Sunday), where Intl knows it; else Monday. */
|
|
52
|
-
export function weekStart(locale: string): number {
|
|
53
|
-
try {
|
|
54
|
-
const l = new Intl.Locale(locale) as Intl.Locale & { getWeekInfo?: () => { firstDay: number }; weekInfo?: { firstDay: number } };
|
|
55
|
-
return (l.getWeekInfo?.() ?? l.weekInfo)?.firstDay ?? 1;
|
|
56
|
-
} catch {
|
|
57
|
-
return 1;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** A month's weeks, each seven days from the week's first day: a day, or '' for the days of the months before and
|
|
62
|
-
* after. */
|
|
63
|
-
export function weeksOf(month: string, locale: string): string[][] {
|
|
64
|
-
const [y, m] = month.split('-').map(Number);
|
|
65
|
-
const first = new Date(y, m - 1, 1, 12);
|
|
66
|
-
const lead = (first.getDay() - (weekStart(locale) % 7) + 7) % 7;
|
|
67
|
-
const length = new Date(y, m, 0).getDate();
|
|
68
|
-
const cells = [...Array.from({ length: lead }, () => ''), ...Array.from({ length }, (_, i) => `${month}-${pad(i + 1)}`)];
|
|
69
|
-
while (cells.length % 7) cells.push('');
|
|
70
|
-
return Array.from({ length: cells.length / 7 }, (_, i) => cells.slice(i * 7, i * 7 + 7));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** The weekdays from the one the week starts with, each its short and its full name (M and mandag). */
|
|
74
|
-
export function weekdaysOf(locale: string): { short: string; long: string }[] {
|
|
75
|
-
const start = weekStart(locale);
|
|
76
|
-
// 2024-01-01 was a Monday.
|
|
77
|
-
return Array.from({ length: 7 }, (_, i) => {
|
|
78
|
-
const d = new Date(2024, 0, ((start - 1 + i) % 7) + 1, 12);
|
|
79
|
-
return { short: d.toLocaleDateString(locale, { weekday: 'narrow' }), long: d.toLocaleDateString(locale, { weekday: 'long' }) };
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const firstUp = (text: string, locale: string) => text.charAt(0).toLocaleUpperCase(locale) + text.slice(1);
|
|
84
|
-
|
|
85
|
-
/** A month's name and year (November 2026), its name alone (November), or its short name (nov.). */
|
|
86
|
-
export function monthName(month: string, locale: string, style: 'year' | 'long' | 'short' = 'year'): string {
|
|
87
|
-
const d = dateOf(`${month}-01`)!;
|
|
88
|
-
return firstUp(
|
|
89
|
-
style === 'year' ? d.toLocaleDateString(locale, { month: 'long', year: 'numeric' }) : d.toLocaleDateString(locale, { month: style }),
|
|
90
|
-
locale,
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** A day written out in full (mandag 2. november 2026), for screen readers. */
|
|
95
|
-
export const dayName = (day: string, locale: string) =>
|
|
96
|
-
dateOf(day)!.toLocaleDateString(locale, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });
|
|
97
|
-
|
|
98
|
-
/** A day written short (Man. 2. nov.), as a date picker's headline. */
|
|
99
|
-
export const dayHeadline = (day: string, locale: string) =>
|
|
100
|
-
firstUp(dateOf(day)!.toLocaleDateString(locale, { weekday: 'short', day: 'numeric', month: 'short' }), locale);
|
|
101
|
-
|
|
102
|
-
/** A day as it is typed in a field, in the language's order (02.11.2026). */
|
|
103
|
-
export const dayTyped = (day: string, locale: string) =>
|
|
104
|
-
dateOf(day)!.toLocaleDateString(locale, { day: '2-digit', month: '2-digit', year: 'numeric' });
|
|
105
|
-
|
|
106
|
-
/** A day typed in a field, in the language's order of day, month and year (2.11.2026, 02-11-2026), as a day; null
|
|
107
|
-
* when it is not one. */
|
|
108
|
-
export function dayFromTyped(text: string, locale: string): string | null {
|
|
109
|
-
const numbers = text.match(/\d+/g);
|
|
110
|
-
if (!numbers || numbers.length !== 3 || text.replace(/[\d\s./-]/g, '')) return null;
|
|
111
|
-
const order = new Intl.DateTimeFormat(locale, { day: '2-digit', month: '2-digit', year: 'numeric' })
|
|
112
|
-
.formatToParts(new Date(2024, 0, 1, 12))
|
|
113
|
-
.map((p) => p.type)
|
|
114
|
-
.filter((t) => t === 'day' || t === 'month' || t === 'year');
|
|
115
|
-
const value = Object.fromEntries(order.map((t, i) => [t, numbers[i]]));
|
|
116
|
-
if (value.year?.length !== 4) return null;
|
|
117
|
-
const day = `${value.year}-${pad(Number(value.month))}-${pad(Number(value.day))}`;
|
|
118
|
-
return dateOf(day) ? day : null;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/** Days typed in a field, one or two (02.11.2026 – 08.11.2026), each a day or null. */
|
|
122
|
-
export function daysFromTyped(text: string, locale: string): (string | null)[] {
|
|
123
|
-
return text
|
|
124
|
-
.split(/\s[–-]\s|\s*–\s*/)
|
|
125
|
-
.map((part) => part.trim())
|
|
126
|
-
.filter(Boolean)
|
|
127
|
-
.map((part) => dayFromTyped(part, locale));
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/** A time of day (14:05) as hours and minutes; null when it is not one. */
|
|
131
|
-
export function timeOf(time: string): { hour: number; minute: number } | null {
|
|
132
|
-
const m = /^(\d{2}):(\d{2})$/.exec(time);
|
|
133
|
-
if (!m) return null;
|
|
134
|
-
const hour = Number(m[1]);
|
|
135
|
-
const minute = Number(m[2]);
|
|
136
|
-
return hour <= 23 && minute <= 59 ? { hour, minute } : null;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/** Hours and minutes as a form saves them (14:05). */
|
|
140
|
-
export const timeString = (hour: number, minute: number) => `${pad(hour)}:${pad(minute)}`;
|
|
141
|
-
|
|
142
|
-
/** Two digits (05). */
|
|
143
|
-
export const twoDigits = pad;
|
|
144
|
-
|
|
145
|
-
/** A time of day as the language writes it, 24-hour (14.05 in Danish), or on a 12-hour clock (`twelve`: 2.05 PM). */
|
|
146
|
-
export const timeTyped = (time: string, locale: string, twelve = false) => {
|
|
147
|
-
const t = timeOf(time)!;
|
|
148
|
-
return new Date(2024, 0, 1, t.hour, t.minute).toLocaleTimeString(
|
|
149
|
-
locale,
|
|
150
|
-
twelve ? { hour: 'numeric', minute: '2-digit', hourCycle: 'h12' } : { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' },
|
|
151
|
-
);
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
/** What the language calls the morning and the afternoon on a 12-hour clock (AM and PM). */
|
|
155
|
-
export const dayPeriods = (locale: string): [string, string] =>
|
|
156
|
-
[9, 21].map(
|
|
157
|
-
(hour) =>
|
|
158
|
-
new Intl.DateTimeFormat(locale, { hour: 'numeric', hourCycle: 'h12' })
|
|
159
|
-
.formatToParts(new Date(2024, 0, 1, hour))
|
|
160
|
-
.find((p) => p.type === 'dayPeriod')?.value ?? (hour < 12 ? 'AM' : 'PM'),
|
|
161
|
-
) as [string, string];
|
|
162
|
-
|
|
163
|
-
/** What the language writes between the hours and the minutes (. in Danish). */
|
|
164
|
-
export const timeSeparator = (locale: string) =>
|
|
165
|
-
new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' })
|
|
166
|
-
.formatToParts(new Date(2024, 0, 1, 14, 5))
|
|
167
|
-
.find((p) => p.type === 'literal')
|
|
168
|
-
?.value.trim() || ':';
|
|
169
|
-
|
|
170
|
-
/** A time typed in a field (14.05, 14:05, 1405, 9.30; with `periods`, the language's AM and PM, also 2.05 PM or
|
|
171
|
-
* 2:05 pm, the hour 1–12), as a time; null when it is not one. */
|
|
172
|
-
export function timeFromTyped(text: string, periods?: [string, string]): string | null {
|
|
173
|
-
const m = /^\s*(\d{1,2})\s*[.:\s]?\s*(\d{2})\s*(\S*)\s*$/.exec(text);
|
|
174
|
-
if (!m) return null;
|
|
175
|
-
let hour = Number(m[1]);
|
|
176
|
-
const said = m[3].toLowerCase().replace(/\./g, '');
|
|
177
|
-
if (said) {
|
|
178
|
-
const at = (periods ?? ['AM', 'PM']).findIndex((p) => p.toLowerCase().replace(/\./g, '') === said);
|
|
179
|
-
const pm = at >= 0 ? at === 1 : said === 'pm' || said === 'p' ? true : said === 'am' || said === 'a' ? false : null;
|
|
180
|
-
if (pm === null || !periods || hour < 1 || hour > 12) return null;
|
|
181
|
-
hour = (hour % 12) + (pm ? 12 : 0);
|
|
182
|
-
}
|
|
183
|
-
const time = timeString(hour, Number(m[2]));
|
|
184
|
-
return timeOf(time) ? time : null;
|
|
185
|
-
}
|
|
1
|
+
// Days and times as the date and time pickers (DatePicker.tsx, TimePicker.tsx and their scripts) hold them: a day as a
|
|
2
|
+
// form saves it (ISO, 2026-11-02), a month as its first day's year and month (2026-11), and a time of day as hh:mm
|
|
3
|
+
// (24-hour). Written out and read back in a language (`locale`, BCP 47: the site's on the site), with Intl, so the
|
|
4
|
+
// names of the months and the weekdays, the order of day, month and year and the week's first day are the language's
|
|
5
|
+
// (in Danish: 02.11.2026, november, man., the week from Monday). No React and no texts here: the scripts load it at once.
|
|
6
|
+
|
|
7
|
+
const pad = (n: number) => String(n).padStart(2, '0');
|
|
8
|
+
|
|
9
|
+
/** A day (2026-11-02) as a date at noon, so no change of time moves it a day; null when it is not one. */
|
|
10
|
+
export function dateOf(day: string): Date | null {
|
|
11
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(day);
|
|
12
|
+
if (!m) return null;
|
|
13
|
+
const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]), 12);
|
|
14
|
+
return d.getMonth() === Number(m[2]) - 1 ? d : null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** A date's day, as a form saves it (2026-11-02). */
|
|
18
|
+
export const dayOf = (d: Date) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
19
|
+
|
|
20
|
+
/** Today, as a day. */
|
|
21
|
+
export const today = () => dayOf(new Date());
|
|
22
|
+
|
|
23
|
+
/** The month a day is in (2026-11). */
|
|
24
|
+
export const monthOfDay = (day: string) => day.slice(0, 7);
|
|
25
|
+
|
|
26
|
+
/** A month (2026-11) moved by a number of months. */
|
|
27
|
+
export function addMonths(month: string, months: number): string {
|
|
28
|
+
const [y, m] = month.split('-').map(Number);
|
|
29
|
+
return dayOf(new Date(y, m - 1 + months, 1, 12)).slice(0, 7);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A day moved by a number of days. */
|
|
33
|
+
export function addDays(day: string, days: number): string {
|
|
34
|
+
const d = dateOf(day)!;
|
|
35
|
+
d.setDate(d.getDate() + days);
|
|
36
|
+
return dayOf(d);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** A day moved by a number of months, on the same day of the month or, in a shorter month, its last. */
|
|
40
|
+
export function addMonthsToDay(day: string, months: number): string {
|
|
41
|
+
const d = dateOf(day)!;
|
|
42
|
+
const month = addMonths(monthOfDay(day), months);
|
|
43
|
+
const [y, m] = month.split('-').map(Number);
|
|
44
|
+
const last = new Date(y, m, 0).getDate();
|
|
45
|
+
return `${month}-${pad(Math.min(d.getDate(), last))}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** A day within the days that can be picked (`min` and `max`, either of them '' for none). */
|
|
49
|
+
export const clampDay = (day: string, min = '', max = '') => (min && day < min ? min : max && day > max ? max : day);
|
|
50
|
+
|
|
51
|
+
/** The day a week starts with in a language (1 Monday … 7 Sunday), where Intl knows it; else Monday. */
|
|
52
|
+
export function weekStart(locale: string): number {
|
|
53
|
+
try {
|
|
54
|
+
const l = new Intl.Locale(locale) as Intl.Locale & { getWeekInfo?: () => { firstDay: number }; weekInfo?: { firstDay: number } };
|
|
55
|
+
return (l.getWeekInfo?.() ?? l.weekInfo)?.firstDay ?? 1;
|
|
56
|
+
} catch {
|
|
57
|
+
return 1;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** A month's weeks, each seven days from the week's first day: a day, or '' for the days of the months before and
|
|
62
|
+
* after. */
|
|
63
|
+
export function weeksOf(month: string, locale: string): string[][] {
|
|
64
|
+
const [y, m] = month.split('-').map(Number);
|
|
65
|
+
const first = new Date(y, m - 1, 1, 12);
|
|
66
|
+
const lead = (first.getDay() - (weekStart(locale) % 7) + 7) % 7;
|
|
67
|
+
const length = new Date(y, m, 0).getDate();
|
|
68
|
+
const cells = [...Array.from({ length: lead }, () => ''), ...Array.from({ length }, (_, i) => `${month}-${pad(i + 1)}`)];
|
|
69
|
+
while (cells.length % 7) cells.push('');
|
|
70
|
+
return Array.from({ length: cells.length / 7 }, (_, i) => cells.slice(i * 7, i * 7 + 7));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** The weekdays from the one the week starts with, each its short and its full name (M and mandag). */
|
|
74
|
+
export function weekdaysOf(locale: string): { short: string; long: string }[] {
|
|
75
|
+
const start = weekStart(locale);
|
|
76
|
+
// 2024-01-01 was a Monday.
|
|
77
|
+
return Array.from({ length: 7 }, (_, i) => {
|
|
78
|
+
const d = new Date(2024, 0, ((start - 1 + i) % 7) + 1, 12);
|
|
79
|
+
return { short: d.toLocaleDateString(locale, { weekday: 'narrow' }), long: d.toLocaleDateString(locale, { weekday: 'long' }) };
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const firstUp = (text: string, locale: string) => text.charAt(0).toLocaleUpperCase(locale) + text.slice(1);
|
|
84
|
+
|
|
85
|
+
/** A month's name and year (November 2026), its name alone (November), or its short name (nov.). */
|
|
86
|
+
export function monthName(month: string, locale: string, style: 'year' | 'long' | 'short' = 'year'): string {
|
|
87
|
+
const d = dateOf(`${month}-01`)!;
|
|
88
|
+
return firstUp(
|
|
89
|
+
style === 'year' ? d.toLocaleDateString(locale, { month: 'long', year: 'numeric' }) : d.toLocaleDateString(locale, { month: style }),
|
|
90
|
+
locale,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** A day written out in full (mandag 2. november 2026), for screen readers. */
|
|
95
|
+
export const dayName = (day: string, locale: string) =>
|
|
96
|
+
dateOf(day)!.toLocaleDateString(locale, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });
|
|
97
|
+
|
|
98
|
+
/** A day written short (Man. 2. nov.), as a date picker's headline. */
|
|
99
|
+
export const dayHeadline = (day: string, locale: string) =>
|
|
100
|
+
firstUp(dateOf(day)!.toLocaleDateString(locale, { weekday: 'short', day: 'numeric', month: 'short' }), locale);
|
|
101
|
+
|
|
102
|
+
/** A day as it is typed in a field, in the language's order (02.11.2026). */
|
|
103
|
+
export const dayTyped = (day: string, locale: string) =>
|
|
104
|
+
dateOf(day)!.toLocaleDateString(locale, { day: '2-digit', month: '2-digit', year: 'numeric' });
|
|
105
|
+
|
|
106
|
+
/** A day typed in a field, in the language's order of day, month and year (2.11.2026, 02-11-2026), as a day; null
|
|
107
|
+
* when it is not one. */
|
|
108
|
+
export function dayFromTyped(text: string, locale: string): string | null {
|
|
109
|
+
const numbers = text.match(/\d+/g);
|
|
110
|
+
if (!numbers || numbers.length !== 3 || text.replace(/[\d\s./-]/g, '')) return null;
|
|
111
|
+
const order = new Intl.DateTimeFormat(locale, { day: '2-digit', month: '2-digit', year: 'numeric' })
|
|
112
|
+
.formatToParts(new Date(2024, 0, 1, 12))
|
|
113
|
+
.map((p) => p.type)
|
|
114
|
+
.filter((t) => t === 'day' || t === 'month' || t === 'year');
|
|
115
|
+
const value = Object.fromEntries(order.map((t, i) => [t, numbers[i]]));
|
|
116
|
+
if (value.year?.length !== 4) return null;
|
|
117
|
+
const day = `${value.year}-${pad(Number(value.month))}-${pad(Number(value.day))}`;
|
|
118
|
+
return dateOf(day) ? day : null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Days typed in a field, one or two (02.11.2026 – 08.11.2026), each a day or null. */
|
|
122
|
+
export function daysFromTyped(text: string, locale: string): (string | null)[] {
|
|
123
|
+
return text
|
|
124
|
+
.split(/\s[–-]\s|\s*–\s*/)
|
|
125
|
+
.map((part) => part.trim())
|
|
126
|
+
.filter(Boolean)
|
|
127
|
+
.map((part) => dayFromTyped(part, locale));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** A time of day (14:05) as hours and minutes; null when it is not one. */
|
|
131
|
+
export function timeOf(time: string): { hour: number; minute: number } | null {
|
|
132
|
+
const m = /^(\d{2}):(\d{2})$/.exec(time);
|
|
133
|
+
if (!m) return null;
|
|
134
|
+
const hour = Number(m[1]);
|
|
135
|
+
const minute = Number(m[2]);
|
|
136
|
+
return hour <= 23 && minute <= 59 ? { hour, minute } : null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Hours and minutes as a form saves them (14:05). */
|
|
140
|
+
export const timeString = (hour: number, minute: number) => `${pad(hour)}:${pad(minute)}`;
|
|
141
|
+
|
|
142
|
+
/** Two digits (05). */
|
|
143
|
+
export const twoDigits = pad;
|
|
144
|
+
|
|
145
|
+
/** A time of day as the language writes it, 24-hour (14.05 in Danish), or on a 12-hour clock (`twelve`: 2.05 PM). */
|
|
146
|
+
export const timeTyped = (time: string, locale: string, twelve = false) => {
|
|
147
|
+
const t = timeOf(time)!;
|
|
148
|
+
return new Date(2024, 0, 1, t.hour, t.minute).toLocaleTimeString(
|
|
149
|
+
locale,
|
|
150
|
+
twelve ? { hour: 'numeric', minute: '2-digit', hourCycle: 'h12' } : { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' },
|
|
151
|
+
);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/** What the language calls the morning and the afternoon on a 12-hour clock (AM and PM). */
|
|
155
|
+
export const dayPeriods = (locale: string): [string, string] =>
|
|
156
|
+
[9, 21].map(
|
|
157
|
+
(hour) =>
|
|
158
|
+
new Intl.DateTimeFormat(locale, { hour: 'numeric', hourCycle: 'h12' })
|
|
159
|
+
.formatToParts(new Date(2024, 0, 1, hour))
|
|
160
|
+
.find((p) => p.type === 'dayPeriod')?.value ?? (hour < 12 ? 'AM' : 'PM'),
|
|
161
|
+
) as [string, string];
|
|
162
|
+
|
|
163
|
+
/** What the language writes between the hours and the minutes (. in Danish). */
|
|
164
|
+
export const timeSeparator = (locale: string) =>
|
|
165
|
+
new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' })
|
|
166
|
+
.formatToParts(new Date(2024, 0, 1, 14, 5))
|
|
167
|
+
.find((p) => p.type === 'literal')
|
|
168
|
+
?.value.trim() || ':';
|
|
169
|
+
|
|
170
|
+
/** A time typed in a field (14.05, 14:05, 1405, 9.30; with `periods`, the language's AM and PM, also 2.05 PM or
|
|
171
|
+
* 2:05 pm, the hour 1–12), as a time; null when it is not one. */
|
|
172
|
+
export function timeFromTyped(text: string, periods?: [string, string]): string | null {
|
|
173
|
+
const m = /^\s*(\d{1,2})\s*[.:\s]?\s*(\d{2})\s*(\S*)\s*$/.exec(text);
|
|
174
|
+
if (!m) return null;
|
|
175
|
+
let hour = Number(m[1]);
|
|
176
|
+
const said = m[3].toLowerCase().replace(/\./g, '');
|
|
177
|
+
if (said) {
|
|
178
|
+
const at = (periods ?? ['AM', 'PM']).findIndex((p) => p.toLowerCase().replace(/\./g, '') === said);
|
|
179
|
+
const pm = at >= 0 ? at === 1 : said === 'pm' || said === 'p' ? true : said === 'am' || said === 'a' ? false : null;
|
|
180
|
+
if (pm === null || !periods || hour < 1 || hour > 12) return null;
|
|
181
|
+
hour = (hour % 12) + (pm ? 12 : 0);
|
|
182
|
+
}
|
|
183
|
+
const time = timeString(hour, Number(m[2]));
|
|
184
|
+
return timeOf(time) ? time : null;
|
|
185
|
+
}
|
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
// What a modal dialog (Dialog.tsx in its <dialog> with dialogModalClass, or a full-screen one's with
|
|
2
|
-
// dialogFullScreenModalClass) does in a browser, for the script that shows it (a block's or an app's): dialog(el)
|
|
3
|
-
// gives it its open() and close(). Native <dialog>: focus moves into it and back, Escape closes it, and screen readers
|
|
4
|
-
// know it is modal. Motion: it comes up a little as it opens (ui.css) and goes down and fades as it closes; with reduced
|
|
5
|
-
// motion it appears and disappears at once. Its close button (data-dialog-close: a full-screen one's cross, or a
|
|
6
|
-
// button among a basic one's actions) and Escape close it, and a tap on the scrim (outside it) closes a basic one (a
|
|
7
|
-
// full-screen one holds a task that is not done, so only its buttons close it); the page under it does not scroll
|
|
8
|
-
// while it is open. It moves with the site's motion scheme (motionSpring, @morphemecms/cms/lib/motion.ts).
|
|
9
|
-
import { animate } from 'motion';
|
|
10
|
-
import { motionSpring } from '@morphemecms/cms/lib/motion';
|
|
11
|
-
|
|
12
|
-
export type DialogControls = { open: () => void; close: () => Promise<void> };
|
|
13
|
-
|
|
14
|
-
export function dialog(el: HTMLDialogElement): DialogControls {
|
|
15
|
-
const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
16
|
-
const fullScreen = el.classList.contains('dialog-modal-full-screen');
|
|
17
|
-
let closing = false;
|
|
18
|
-
|
|
19
|
-
function open() {
|
|
20
|
-
if (el.open) return;
|
|
21
|
-
el.showModal();
|
|
22
|
-
document.documentElement.style.overflow = 'hidden';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async function close() {
|
|
26
|
-
if (!el.open || closing) return;
|
|
27
|
-
closing = true;
|
|
28
|
-
if (!reduce) await animate(el, { opacity: 0, y: 16 }, motionSpring('spatial', 'fast'));
|
|
29
|
-
el.close();
|
|
30
|
-
el.style.transform = '';
|
|
31
|
-
el.style.opacity = '';
|
|
32
|
-
document.documentElement.style.overflow = '';
|
|
33
|
-
closing = false;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
el.querySelectorAll('[data-dialog-close]').forEach((b) => b.addEventListener('click', close));
|
|
37
|
-
// Escape: animate out instead of the dialog's instant close.
|
|
38
|
-
el.addEventListener('cancel', (e) => {
|
|
39
|
-
e.preventDefault();
|
|
40
|
-
close();
|
|
41
|
-
});
|
|
42
|
-
// A tap on the scrim (outside the box) closes a basic dialog.
|
|
43
|
-
el.addEventListener('click', (e) => {
|
|
44
|
-
if (e.target === el && !fullScreen) close();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
return { open, close };
|
|
48
|
-
}
|
|
1
|
+
// What a modal dialog (Dialog.tsx in its <dialog> with dialogModalClass, or a full-screen one's with
|
|
2
|
+
// dialogFullScreenModalClass) does in a browser, for the script that shows it (a block's or an app's): dialog(el)
|
|
3
|
+
// gives it its open() and close(). Native <dialog>: focus moves into it and back, Escape closes it, and screen readers
|
|
4
|
+
// know it is modal. Motion: it comes up a little as it opens (ui.css) and goes down and fades as it closes; with reduced
|
|
5
|
+
// motion it appears and disappears at once. Its close button (data-dialog-close: a full-screen one's cross, or a
|
|
6
|
+
// button among a basic one's actions) and Escape close it, and a tap on the scrim (outside it) closes a basic one (a
|
|
7
|
+
// full-screen one holds a task that is not done, so only its buttons close it); the page under it does not scroll
|
|
8
|
+
// while it is open. It moves with the site's motion scheme (motionSpring, @morphemecms/cms/lib/motion.ts).
|
|
9
|
+
import { animate } from 'motion';
|
|
10
|
+
import { motionSpring } from '@morphemecms/cms/lib/motion';
|
|
11
|
+
|
|
12
|
+
export type DialogControls = { open: () => void; close: () => Promise<void> };
|
|
13
|
+
|
|
14
|
+
export function dialog(el: HTMLDialogElement): DialogControls {
|
|
15
|
+
const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
16
|
+
const fullScreen = el.classList.contains('dialog-modal-full-screen');
|
|
17
|
+
let closing = false;
|
|
18
|
+
|
|
19
|
+
function open() {
|
|
20
|
+
if (el.open) return;
|
|
21
|
+
el.showModal();
|
|
22
|
+
document.documentElement.style.overflow = 'hidden';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function close() {
|
|
26
|
+
if (!el.open || closing) return;
|
|
27
|
+
closing = true;
|
|
28
|
+
if (!reduce) await animate(el, { opacity: 0, y: 16 }, motionSpring('spatial', 'fast'));
|
|
29
|
+
el.close();
|
|
30
|
+
el.style.transform = '';
|
|
31
|
+
el.style.opacity = '';
|
|
32
|
+
document.documentElement.style.overflow = '';
|
|
33
|
+
closing = false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
el.querySelectorAll('[data-dialog-close]').forEach((b) => b.addEventListener('click', close));
|
|
37
|
+
// Escape: animate out instead of the dialog's instant close.
|
|
38
|
+
el.addEventListener('cancel', (e) => {
|
|
39
|
+
e.preventDefault();
|
|
40
|
+
close();
|
|
41
|
+
});
|
|
42
|
+
// A tap on the scrim (outside the box) closes a basic dialog.
|
|
43
|
+
el.addEventListener('click', (e) => {
|
|
44
|
+
if (e.target === el && !fullScreen) close();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return { open, close };
|
|
48
|
+
}
|