@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
|
@@ -1,134 +1,134 @@
|
|
|
1
|
-
// Checks that the editor (/editor/) can save every page and blog post without changing the site:
|
|
2
|
-
// each body is loaded into Milkdown and written back, and both versions are rendered with Astro's
|
|
3
|
-
// Markdown pipeline. The HTML must be the same. The front matter, written back without changes, must
|
|
4
|
-
// be the same text. The fixed pages (src/data/*.json with sections) are loaded as their text with the
|
|
5
|
-
// sections as blocks (packages/editor/src/sections.mjs) and read back: the sections must be the same, a section
|
|
6
|
-
// of text with the same heading and the same HTML. Every page is also read into sections as the front page (as the
|
|
7
|
-
// site reads the page that is the front page without the editor, partsOfMarkdown in sections.mjs, packages/editor/site/home.ts):
|
|
8
|
-
// they must be those the editor reads. Run: npm run check:editor [files...]
|
|
9
|
-
// Milkdown needs a DOM; jsdom stands in for the browser.
|
|
10
|
-
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
11
|
-
import { join } from 'node:path';
|
|
12
|
-
import { JSDOM } from 'jsdom';
|
|
13
|
-
|
|
14
|
-
const dom = new JSDOM('<!doctype html><html><body></body></html>', { pretendToBeVisual: true });
|
|
15
|
-
globalThis.window = dom.window;
|
|
16
|
-
for (const key of [
|
|
17
|
-
'document',
|
|
18
|
-
'Node',
|
|
19
|
-
'Element',
|
|
20
|
-
'HTMLElement',
|
|
21
|
-
'MutationObserver',
|
|
22
|
-
'getComputedStyle',
|
|
23
|
-
'requestAnimationFrame',
|
|
24
|
-
'DOMParser',
|
|
25
|
-
'Event',
|
|
26
|
-
'CustomEvent',
|
|
27
|
-
])
|
|
28
|
-
globalThis[key] = dom.window[key];
|
|
29
|
-
for (const key of ['addEventListener', 'removeEventListener', 'dispatchEvent']) globalThis[key] = dom.window[key].bind(dom.window);
|
|
30
|
-
|
|
31
|
-
const { editorViewCtx } = await import('@milkdown/kit/core');
|
|
32
|
-
const { createMarkdownProcessor } = await import('@astrojs/markdown-remark');
|
|
33
|
-
const { makeEditor, markdownOf, partsOf, spacing } = await import('@morphemecms/cms/src/markdown.mjs');
|
|
34
|
-
const { introOf, partsOfMarkdown, sectionsFromParts, sectionsToMarkdown } = await import('@morphemecms/cms/src/sections.mjs');
|
|
35
|
-
const { withSiteModules } = await import('../site/siteModules.mjs');
|
|
36
|
-
// The field of the sections of each fixed page (@site/collections): the sections whose text is written
|
|
37
|
-
// above their card (their lead), and the page's introduction above them (intro).
|
|
38
|
-
const [{ frontLeads }, { collections }] = await withSiteModules((load) =>
|
|
39
|
-
Promise.all([load('@site/standardPages'), load('@site/collections')]),
|
|
40
|
-
);
|
|
41
|
-
const { leadsOfField } = await import('@morphemecms/cms/src/sections.mjs');
|
|
42
|
-
const textOf = Object.fromEntries(
|
|
43
|
-
collections
|
|
44
|
-
.filter((c) => c.kind === 'files')
|
|
45
|
-
.flatMap((c) => c.files)
|
|
46
|
-
.map((f) => [f.file, f.fields.find((x) => x.type === 'blocks')]),
|
|
47
|
-
);
|
|
48
|
-
const { splitFrontmatter, writeFields } = await import('@morphemecms/cms/src/frontmatter.mjs');
|
|
49
|
-
|
|
50
|
-
const walk = (dir) =>
|
|
51
|
-
(existsSync(dir) ? readdirSync(dir, { withFileTypes: true }) : []).flatMap((e) =>
|
|
52
|
-
e.isDirectory() ? walk(join(dir, e.name)) : e.name.endsWith('.md') ? [join(dir, e.name)] : [],
|
|
53
|
-
);
|
|
54
|
-
const fixed = readdirSync('src/data')
|
|
55
|
-
.filter((f) => f.endsWith('.json') && JSON.parse(readFileSync(join('src/data', f), 'utf8')).sections)
|
|
56
|
-
.map((f) => join('src/data', f));
|
|
57
|
-
const files = process.argv.length > 2 ? process.argv.slice(2) : [...walk('src/content/blog'), ...walk('src/content/pages'), ...fixed];
|
|
58
|
-
|
|
59
|
-
const processor = await createMarkdownProcessor();
|
|
60
|
-
const render = async (md) => (await processor.render(md)).code.replace(/\s+/g, ' ').trim();
|
|
61
|
-
|
|
62
|
-
let failed = 0;
|
|
63
|
-
// A fixed page's introduction and sections, as the editor reads them back.
|
|
64
|
-
async function sectionsBack(sections, intro, field) {
|
|
65
|
-
const leads = leadsOfField(field);
|
|
66
|
-
const editor = await makeEditor(
|
|
67
|
-
document.createElement('div'),
|
|
68
|
-
sectionsToMarkdown(sections, leads, field?.intro ? intro : undefined),
|
|
69
|
-
).create();
|
|
70
|
-
let parts = editor.action(partsOf);
|
|
71
|
-
let back = '';
|
|
72
|
-
if (field?.intro) [back, parts] = introOf(parts);
|
|
73
|
-
await editor.destroy();
|
|
74
|
-
return [back, sectionsFromParts(parts, leads)];
|
|
75
|
-
}
|
|
76
|
-
// The text of a section of text, and of the front page's top, as HTML.
|
|
77
|
-
const comparable = async (intro, sections) =>
|
|
78
|
-
JSON.stringify([
|
|
79
|
-
intro ?? '',
|
|
80
|
-
...(await Promise.all(
|
|
81
|
-
sections.map(async (s) =>
|
|
82
|
-
s.type === 'text' ? { ...s, body: await render(s.body) } : s.type === 'hero' ? { ...s, text: await render(s.text) } : s,
|
|
83
|
-
),
|
|
84
|
-
)),
|
|
85
|
-
]);
|
|
86
|
-
|
|
87
|
-
for (const file of files) {
|
|
88
|
-
if (file.endsWith('.json')) {
|
|
89
|
-
const { sections, intro } = JSON.parse(readFileSync(file, 'utf8'));
|
|
90
|
-
const field = textOf[file];
|
|
91
|
-
const [before, after] = [
|
|
92
|
-
await comparable(field?.intro ? intro : '', sections),
|
|
93
|
-
await comparable(...(await sectionsBack(sections, intro, field))),
|
|
94
|
-
];
|
|
95
|
-
if (before === after) continue;
|
|
96
|
-
failed++;
|
|
97
|
-
console.log(`\n✗ ${file}\n før: ${before.slice(0, 300)}\n efter: ${after.slice(0, 300)}`);
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
const { yaml, body } = splitFrontmatter(readFileSync(file, 'utf8'));
|
|
101
|
-
if (writeFields(yaml, {}) !== yaml) {
|
|
102
|
-
failed++;
|
|
103
|
-
console.log(`\n✗ ${file}\n front matter skrives ikke tilbage uændret`);
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
const root = document.createElement('div');
|
|
107
|
-
// As in the editor: with the free lines between the blocks, written without them.
|
|
108
|
-
const editor = await makeEditor(root, body).use(spacing).create();
|
|
109
|
-
editor.action((ctx) => ctx.get(editorViewCtx).dispatch(ctx.get(editorViewCtx).state.tr));
|
|
110
|
-
const saved = editor.action(markdownOf);
|
|
111
|
-
const parts = editor.action(partsOf);
|
|
112
|
-
await editor.destroy();
|
|
113
|
-
if (file.includes('src/content/pages/')) {
|
|
114
|
-
const [editors, site] = [
|
|
115
|
-
await comparable('', sectionsFromParts(parts, frontLeads)),
|
|
116
|
-
await comparable('', sectionsFromParts(partsOfMarkdown(body), frontLeads)),
|
|
117
|
-
];
|
|
118
|
-
if (editors !== site) {
|
|
119
|
-
failed++;
|
|
120
|
-
console.log(`\n✗ ${file} som forside\n editoren: ${editors.slice(0, 300)}\n sitet: ${site.slice(0, 300)}`);
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
const [before, after] = [await render(body), await render(saved)];
|
|
125
|
-
if (before === after) continue;
|
|
126
|
-
failed++;
|
|
127
|
-
let i = 0;
|
|
128
|
-
while (before[i] === after[i]) i++;
|
|
129
|
-
console.log(
|
|
130
|
-
`\n✗ ${file}\n før: …${before.slice(Math.max(0, i - 80), i + 120)}\n efter: …${after.slice(Math.max(0, i - 80), i + 120)}`,
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
console.log(`\n${files.length - failed} af ${files.length} filer giver samme side efter en gem i editoren.`);
|
|
134
|
-
process.exit(failed ? 1 : 0);
|
|
1
|
+
// Checks that the editor (/editor/) can save every page and blog post without changing the site:
|
|
2
|
+
// each body is loaded into Milkdown and written back, and both versions are rendered with Astro's
|
|
3
|
+
// Markdown pipeline. The HTML must be the same. The front matter, written back without changes, must
|
|
4
|
+
// be the same text. The fixed pages (src/data/*.json with sections) are loaded as their text with the
|
|
5
|
+
// sections as blocks (packages/editor/src/sections.mjs) and read back: the sections must be the same, a section
|
|
6
|
+
// of text with the same heading and the same HTML. Every page is also read into sections as the front page (as the
|
|
7
|
+
// site reads the page that is the front page without the editor, partsOfMarkdown in sections.mjs, packages/editor/site/home.ts):
|
|
8
|
+
// they must be those the editor reads. Run: npm run check:editor [files...]
|
|
9
|
+
// Milkdown needs a DOM; jsdom stands in for the browser.
|
|
10
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { JSDOM } from 'jsdom';
|
|
13
|
+
|
|
14
|
+
const dom = new JSDOM('<!doctype html><html><body></body></html>', { pretendToBeVisual: true });
|
|
15
|
+
globalThis.window = dom.window;
|
|
16
|
+
for (const key of [
|
|
17
|
+
'document',
|
|
18
|
+
'Node',
|
|
19
|
+
'Element',
|
|
20
|
+
'HTMLElement',
|
|
21
|
+
'MutationObserver',
|
|
22
|
+
'getComputedStyle',
|
|
23
|
+
'requestAnimationFrame',
|
|
24
|
+
'DOMParser',
|
|
25
|
+
'Event',
|
|
26
|
+
'CustomEvent',
|
|
27
|
+
])
|
|
28
|
+
globalThis[key] = dom.window[key];
|
|
29
|
+
for (const key of ['addEventListener', 'removeEventListener', 'dispatchEvent']) globalThis[key] = dom.window[key].bind(dom.window);
|
|
30
|
+
|
|
31
|
+
const { editorViewCtx } = await import('@milkdown/kit/core');
|
|
32
|
+
const { createMarkdownProcessor } = await import('@astrojs/markdown-remark');
|
|
33
|
+
const { makeEditor, markdownOf, partsOf, spacing } = await import('@morphemecms/cms/src/markdown.mjs');
|
|
34
|
+
const { introOf, partsOfMarkdown, sectionsFromParts, sectionsToMarkdown } = await import('@morphemecms/cms/src/sections.mjs');
|
|
35
|
+
const { withSiteModules } = await import('../site/siteModules.mjs');
|
|
36
|
+
// The field of the sections of each fixed page (@site/collections): the sections whose text is written
|
|
37
|
+
// above their card (their lead), and the page's introduction above them (intro).
|
|
38
|
+
const [{ frontLeads }, { collections }] = await withSiteModules((load) =>
|
|
39
|
+
Promise.all([load('@site/standardPages'), load('@site/collections')]),
|
|
40
|
+
);
|
|
41
|
+
const { leadsOfField } = await import('@morphemecms/cms/src/sections.mjs');
|
|
42
|
+
const textOf = Object.fromEntries(
|
|
43
|
+
collections
|
|
44
|
+
.filter((c) => c.kind === 'files')
|
|
45
|
+
.flatMap((c) => c.files)
|
|
46
|
+
.map((f) => [f.file, f.fields.find((x) => x.type === 'blocks')]),
|
|
47
|
+
);
|
|
48
|
+
const { splitFrontmatter, writeFields } = await import('@morphemecms/cms/src/frontmatter.mjs');
|
|
49
|
+
|
|
50
|
+
const walk = (dir) =>
|
|
51
|
+
(existsSync(dir) ? readdirSync(dir, { withFileTypes: true }) : []).flatMap((e) =>
|
|
52
|
+
e.isDirectory() ? walk(join(dir, e.name)) : e.name.endsWith('.md') ? [join(dir, e.name)] : [],
|
|
53
|
+
);
|
|
54
|
+
const fixed = readdirSync('src/data')
|
|
55
|
+
.filter((f) => f.endsWith('.json') && JSON.parse(readFileSync(join('src/data', f), 'utf8')).sections)
|
|
56
|
+
.map((f) => join('src/data', f));
|
|
57
|
+
const files = process.argv.length > 2 ? process.argv.slice(2) : [...walk('src/content/blog'), ...walk('src/content/pages'), ...fixed];
|
|
58
|
+
|
|
59
|
+
const processor = await createMarkdownProcessor();
|
|
60
|
+
const render = async (md) => (await processor.render(md)).code.replace(/\s+/g, ' ').trim();
|
|
61
|
+
|
|
62
|
+
let failed = 0;
|
|
63
|
+
// A fixed page's introduction and sections, as the editor reads them back.
|
|
64
|
+
async function sectionsBack(sections, intro, field) {
|
|
65
|
+
const leads = leadsOfField(field);
|
|
66
|
+
const editor = await makeEditor(
|
|
67
|
+
document.createElement('div'),
|
|
68
|
+
sectionsToMarkdown(sections, leads, field?.intro ? intro : undefined),
|
|
69
|
+
).create();
|
|
70
|
+
let parts = editor.action(partsOf);
|
|
71
|
+
let back = '';
|
|
72
|
+
if (field?.intro) [back, parts] = introOf(parts);
|
|
73
|
+
await editor.destroy();
|
|
74
|
+
return [back, sectionsFromParts(parts, leads)];
|
|
75
|
+
}
|
|
76
|
+
// The text of a section of text, and of the front page's top, as HTML.
|
|
77
|
+
const comparable = async (intro, sections) =>
|
|
78
|
+
JSON.stringify([
|
|
79
|
+
intro ?? '',
|
|
80
|
+
...(await Promise.all(
|
|
81
|
+
sections.map(async (s) =>
|
|
82
|
+
s.type === 'text' ? { ...s, body: await render(s.body) } : s.type === 'hero' ? { ...s, text: await render(s.text) } : s,
|
|
83
|
+
),
|
|
84
|
+
)),
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
for (const file of files) {
|
|
88
|
+
if (file.endsWith('.json')) {
|
|
89
|
+
const { sections, intro } = JSON.parse(readFileSync(file, 'utf8'));
|
|
90
|
+
const field = textOf[file];
|
|
91
|
+
const [before, after] = [
|
|
92
|
+
await comparable(field?.intro ? intro : '', sections),
|
|
93
|
+
await comparable(...(await sectionsBack(sections, intro, field))),
|
|
94
|
+
];
|
|
95
|
+
if (before === after) continue;
|
|
96
|
+
failed++;
|
|
97
|
+
console.log(`\n✗ ${file}\n før: ${before.slice(0, 300)}\n efter: ${after.slice(0, 300)}`);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const { yaml, body } = splitFrontmatter(readFileSync(file, 'utf8'));
|
|
101
|
+
if (writeFields(yaml, {}) !== yaml) {
|
|
102
|
+
failed++;
|
|
103
|
+
console.log(`\n✗ ${file}\n front matter skrives ikke tilbage uændret`);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const root = document.createElement('div');
|
|
107
|
+
// As in the editor: with the free lines between the blocks, written without them.
|
|
108
|
+
const editor = await makeEditor(root, body).use(spacing).create();
|
|
109
|
+
editor.action((ctx) => ctx.get(editorViewCtx).dispatch(ctx.get(editorViewCtx).state.tr));
|
|
110
|
+
const saved = editor.action(markdownOf);
|
|
111
|
+
const parts = editor.action(partsOf);
|
|
112
|
+
await editor.destroy();
|
|
113
|
+
if (file.includes('src/content/pages/')) {
|
|
114
|
+
const [editors, site] = [
|
|
115
|
+
await comparable('', sectionsFromParts(parts, frontLeads)),
|
|
116
|
+
await comparable('', sectionsFromParts(partsOfMarkdown(body), frontLeads)),
|
|
117
|
+
];
|
|
118
|
+
if (editors !== site) {
|
|
119
|
+
failed++;
|
|
120
|
+
console.log(`\n✗ ${file} som forside\n editoren: ${editors.slice(0, 300)}\n sitet: ${site.slice(0, 300)}`);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const [before, after] = [await render(body), await render(saved)];
|
|
125
|
+
if (before === after) continue;
|
|
126
|
+
failed++;
|
|
127
|
+
let i = 0;
|
|
128
|
+
while (before[i] === after[i]) i++;
|
|
129
|
+
console.log(
|
|
130
|
+
`\n✗ ${file}\n før: …${before.slice(Math.max(0, i - 80), i + 120)}\n efter: …${after.slice(Math.max(0, i - 80), i + 120)}`,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
console.log(`\n${files.length - failed} af ${files.length} filer giver samme side efter en gem i editoren.`);
|
|
134
|
+
process.exit(failed ? 1 : 0);
|
|
@@ -1,101 +1,101 @@
|
|
|
1
|
-
// Opens every screen of the editor (/editor/) in a browser, on a phone and on a computer, and fails
|
|
2
|
-
// when one breaks: an error on the page, something its Content-Security-Policy stopped, an empty app, or a link to an
|
|
3
|
-
// address with nothing on it, or an icon that is not found (drawn as the question mark, data-icon-missing: Svg in
|
|
4
|
-
// packages/editor/src/icon.tsx), there or on one of the built site's pages.
|
|
5
|
-
// The screens are found as the editor's own links: from the start screen (and "Indstillinger", #indstillinger, "Dele", #udseende/dele, "Temaer",
|
|
6
|
-
// #udseende/temaer, "Søgemaskineoptimering", #seo, and "Appstore", #indstillinger/appstore), and
|
|
7
|
-
// from each screen it opens, two steps down. GitHub is answered from the files in this repository, so it needs no login
|
|
8
|
-
// and changes nothing. It runs on the built site: npm run build && npm run check:screens (or on another
|
|
9
|
-
// folder with a built site, its path after the command: packages/editor/scripts/check-themes.mjs).
|
|
10
|
-
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
11
|
-
import { join, relative, resolve } from 'node:path';
|
|
12
|
-
import { chromium } from 'playwright';
|
|
13
|
-
import { openEditor, serveBuilt } from './built-site.mjs';
|
|
14
|
-
|
|
15
|
-
const ROOT = `${process.cwd()}/`;
|
|
16
|
-
const DIST = resolve(ROOT, process.argv[2] ?? 'dist');
|
|
17
|
-
if (!existsSync(join(DIST, 'editor/index.html'))) {
|
|
18
|
-
console.error(`Der er intet bygget site i ${DIST}. Kør npm run build først.`);
|
|
19
|
-
process.exit(1);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const missingIcon = (name) =>
|
|
23
|
-
name
|
|
24
|
-
? `ikonet "${name}" findes ikke (et spørgsmålstegn i stedet): skriv det i packages/editor/src/icon.tsx`
|
|
25
|
-
: 'et ikon er ikke en SVG-fil (et spørgsmålstegn i stedet)';
|
|
26
|
-
|
|
27
|
-
// The icons not found on the built site's pages: each one once, with the pages it is on.
|
|
28
|
-
const problems = [];
|
|
29
|
-
const missingOn = new Map();
|
|
30
|
-
for (const entry of readdirSync(DIST, { recursive: true, withFileTypes: true })) {
|
|
31
|
-
if (!entry.isFile() || !entry.name.endsWith('.html')) continue;
|
|
32
|
-
const file = join(entry.parentPath, entry.name);
|
|
33
|
-
for (const [, name] of readFileSync(file, 'utf8').matchAll(/data-icon-missing="([^"]*)"/g))
|
|
34
|
-
missingOn.set(name, new Set([...(missingOn.get(name) ?? []), `/${relative(DIST, file)}`]));
|
|
35
|
-
}
|
|
36
|
-
for (const [name, pages] of missingOn) {
|
|
37
|
-
const shown = [...pages].slice(0, 3).join(', ');
|
|
38
|
-
problems.push(`${shown}${pages.size > 3 ? ` og ${pages.size - 3} sider til` : ''}: ${missingIcon(name)}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const { server, site } = await serveBuilt(DIST);
|
|
42
|
-
|
|
43
|
-
// CHROMIUM_PATH: another Chromium than Playwright's own (one installed for another version of Playwright).
|
|
44
|
-
const browser = await chromium.launch({ executablePath: process.env.CHROMIUM_PATH || undefined });
|
|
45
|
-
// The screens opened (each on both).
|
|
46
|
-
const opened = new Set();
|
|
47
|
-
|
|
48
|
-
for (const [width, height] of [
|
|
49
|
-
[390, 844],
|
|
50
|
-
[1280, 900],
|
|
51
|
-
]) {
|
|
52
|
-
const page = await browser.newPage({ viewport: { width, height }, locale: 'da-DK' });
|
|
53
|
-
let route = '';
|
|
54
|
-
page.on('pageerror', (e) => problems.push(`${width}px #${route}: ${e.message}`));
|
|
55
|
-
// Something the page's Content-Security-Policy stopped (packages/editor/lib/csp.mjs).
|
|
56
|
-
page.on('console', (m) => {
|
|
57
|
-
if (m.type() === 'error' && /Content Security Policy/i.test(m.text())) problems.push(`${width}px #${route}: ${m.text()}`);
|
|
58
|
-
});
|
|
59
|
-
await openEditor(page, site);
|
|
60
|
-
|
|
61
|
-
// From the start screen, and from "Indstillinger" (the gear in the top bar), "Dele", "Temaer",
|
|
62
|
-
// "Søgemaskineoptimering" and "Appstore" (the apps' pages and their developers'), whose screens are a step further
|
|
63
|
-
// down than the others.
|
|
64
|
-
const starts = ['', 'indstillinger', 'udseende/dele', 'udseende/temaer', 'seo', 'indstillinger/appstore'];
|
|
65
|
-
const seen = new Set(starts);
|
|
66
|
-
let next = starts;
|
|
67
|
-
for (let depth = 0; depth <= 2 && next.length; depth++) {
|
|
68
|
-
const found = [];
|
|
69
|
-
for (const hash of next) {
|
|
70
|
-
route = hash;
|
|
71
|
-
await page.evaluate((h) => (location.hash = h), hash);
|
|
72
|
-
await page.waitForTimeout(150);
|
|
73
|
-
opened.add(hash);
|
|
74
|
-
const state = await page.evaluate(() => ({
|
|
75
|
-
empty: !document.querySelector('astro-island')?.textContent?.trim(),
|
|
76
|
-
text: document.body.innerText,
|
|
77
|
-
links: [...document.querySelectorAll('a[href^="#"]')].map((a) => a.getAttribute('href').slice(1)),
|
|
78
|
-
missing: [...document.querySelectorAll('[data-icon-missing]')].map((e) => e.getAttribute('data-icon-missing')),
|
|
79
|
-
}));
|
|
80
|
-
for (const name of new Set(state.missing)) problems.push(`${width}px #${hash}: ${missingIcon(name)}`);
|
|
81
|
-
if (state.empty) problems.push(`${width}px #${hash}: skærmen er tom`);
|
|
82
|
-
if (state.text.includes(`Der er ikke noget på adressen ${hash}.`))
|
|
83
|
-
problems.push(`${width}px #${hash}: der er ikke noget på adressen`);
|
|
84
|
-
for (const link of state.links) {
|
|
85
|
-
if (seen.has(link)) continue;
|
|
86
|
-
seen.add(link);
|
|
87
|
-
found.push(link);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
next = found;
|
|
91
|
-
}
|
|
92
|
-
await page.close();
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
await browser.close();
|
|
96
|
-
server.close();
|
|
97
|
-
if (problems.length) {
|
|
98
|
-
console.error(`${problems.length} fejl i editoren eller på sitet:\n${[...new Set(problems)].join('\n')}`);
|
|
99
|
-
process.exit(1);
|
|
100
|
-
}
|
|
101
|
-
console.log(`${opened.size} skærme i editoren åbner uden fejl, på en telefon og på en computer, og alle ikoner findes.`);
|
|
1
|
+
// Opens every screen of the editor (/editor/) in a browser, on a phone and on a computer, and fails
|
|
2
|
+
// when one breaks: an error on the page, something its Content-Security-Policy stopped, an empty app, or a link to an
|
|
3
|
+
// address with nothing on it, or an icon that is not found (drawn as the question mark, data-icon-missing: Svg in
|
|
4
|
+
// packages/editor/src/icon.tsx), there or on one of the built site's pages.
|
|
5
|
+
// The screens are found as the editor's own links: from the start screen (and "Indstillinger", #indstillinger, "Dele", #udseende/dele, "Temaer",
|
|
6
|
+
// #udseende/temaer, "Søgemaskineoptimering", #seo, and "Appstore", #indstillinger/appstore), and
|
|
7
|
+
// from each screen it opens, two steps down. GitHub is answered from the files in this repository, so it needs no login
|
|
8
|
+
// and changes nothing. It runs on the built site: npm run build && npm run check:screens (or on another
|
|
9
|
+
// folder with a built site, its path after the command: packages/editor/scripts/check-themes.mjs).
|
|
10
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
11
|
+
import { join, relative, resolve } from 'node:path';
|
|
12
|
+
import { chromium } from 'playwright';
|
|
13
|
+
import { openEditor, serveBuilt } from './built-site.mjs';
|
|
14
|
+
|
|
15
|
+
const ROOT = `${process.cwd()}/`;
|
|
16
|
+
const DIST = resolve(ROOT, process.argv[2] ?? 'dist');
|
|
17
|
+
if (!existsSync(join(DIST, 'editor/index.html'))) {
|
|
18
|
+
console.error(`Der er intet bygget site i ${DIST}. Kør npm run build først.`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const missingIcon = (name) =>
|
|
23
|
+
name
|
|
24
|
+
? `ikonet "${name}" findes ikke (et spørgsmålstegn i stedet): skriv det i packages/editor/src/icon.tsx`
|
|
25
|
+
: 'et ikon er ikke en SVG-fil (et spørgsmålstegn i stedet)';
|
|
26
|
+
|
|
27
|
+
// The icons not found on the built site's pages: each one once, with the pages it is on.
|
|
28
|
+
const problems = [];
|
|
29
|
+
const missingOn = new Map();
|
|
30
|
+
for (const entry of readdirSync(DIST, { recursive: true, withFileTypes: true })) {
|
|
31
|
+
if (!entry.isFile() || !entry.name.endsWith('.html')) continue;
|
|
32
|
+
const file = join(entry.parentPath, entry.name);
|
|
33
|
+
for (const [, name] of readFileSync(file, 'utf8').matchAll(/data-icon-missing="([^"]*)"/g))
|
|
34
|
+
missingOn.set(name, new Set([...(missingOn.get(name) ?? []), `/${relative(DIST, file)}`]));
|
|
35
|
+
}
|
|
36
|
+
for (const [name, pages] of missingOn) {
|
|
37
|
+
const shown = [...pages].slice(0, 3).join(', ');
|
|
38
|
+
problems.push(`${shown}${pages.size > 3 ? ` og ${pages.size - 3} sider til` : ''}: ${missingIcon(name)}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const { server, site } = await serveBuilt(DIST);
|
|
42
|
+
|
|
43
|
+
// CHROMIUM_PATH: another Chromium than Playwright's own (one installed for another version of Playwright).
|
|
44
|
+
const browser = await chromium.launch({ executablePath: process.env.CHROMIUM_PATH || undefined });
|
|
45
|
+
// The screens opened (each on both).
|
|
46
|
+
const opened = new Set();
|
|
47
|
+
|
|
48
|
+
for (const [width, height] of [
|
|
49
|
+
[390, 844],
|
|
50
|
+
[1280, 900],
|
|
51
|
+
]) {
|
|
52
|
+
const page = await browser.newPage({ viewport: { width, height }, locale: 'da-DK' });
|
|
53
|
+
let route = '';
|
|
54
|
+
page.on('pageerror', (e) => problems.push(`${width}px #${route}: ${e.message}`));
|
|
55
|
+
// Something the page's Content-Security-Policy stopped (packages/editor/lib/csp.mjs).
|
|
56
|
+
page.on('console', (m) => {
|
|
57
|
+
if (m.type() === 'error' && /Content Security Policy/i.test(m.text())) problems.push(`${width}px #${route}: ${m.text()}`);
|
|
58
|
+
});
|
|
59
|
+
await openEditor(page, site);
|
|
60
|
+
|
|
61
|
+
// From the start screen, and from "Indstillinger" (the gear in the top bar), "Dele", "Temaer",
|
|
62
|
+
// "Søgemaskineoptimering" and "Appstore" (the apps' pages and their developers'), whose screens are a step further
|
|
63
|
+
// down than the others.
|
|
64
|
+
const starts = ['', 'indstillinger', 'udseende/dele', 'udseende/temaer', 'seo', 'indstillinger/appstore'];
|
|
65
|
+
const seen = new Set(starts);
|
|
66
|
+
let next = starts;
|
|
67
|
+
for (let depth = 0; depth <= 2 && next.length; depth++) {
|
|
68
|
+
const found = [];
|
|
69
|
+
for (const hash of next) {
|
|
70
|
+
route = hash;
|
|
71
|
+
await page.evaluate((h) => (location.hash = h), hash);
|
|
72
|
+
await page.waitForTimeout(150);
|
|
73
|
+
opened.add(hash);
|
|
74
|
+
const state = await page.evaluate(() => ({
|
|
75
|
+
empty: !document.querySelector('astro-island')?.textContent?.trim(),
|
|
76
|
+
text: document.body.innerText,
|
|
77
|
+
links: [...document.querySelectorAll('a[href^="#"]')].map((a) => a.getAttribute('href').slice(1)),
|
|
78
|
+
missing: [...document.querySelectorAll('[data-icon-missing]')].map((e) => e.getAttribute('data-icon-missing')),
|
|
79
|
+
}));
|
|
80
|
+
for (const name of new Set(state.missing)) problems.push(`${width}px #${hash}: ${missingIcon(name)}`);
|
|
81
|
+
if (state.empty) problems.push(`${width}px #${hash}: skærmen er tom`);
|
|
82
|
+
if (state.text.includes(`Der er ikke noget på adressen ${hash}.`))
|
|
83
|
+
problems.push(`${width}px #${hash}: der er ikke noget på adressen`);
|
|
84
|
+
for (const link of state.links) {
|
|
85
|
+
if (seen.has(link)) continue;
|
|
86
|
+
seen.add(link);
|
|
87
|
+
found.push(link);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
next = found;
|
|
91
|
+
}
|
|
92
|
+
await page.close();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
await browser.close();
|
|
96
|
+
server.close();
|
|
97
|
+
if (problems.length) {
|
|
98
|
+
console.error(`${problems.length} fejl i editoren eller på sitet:\n${[...new Set(problems)].join('\n')}`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
console.log(`${opened.size} skærme i editoren åbner uden fejl, på en telefon og på en computer, og alle ikoner findes.`);
|
package/scripts/git-env.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// The environment for git in a repository a script makes for itself. Git gives its hooks the variables that point a
|
|
2
|
-
// command at a repository (GIT_DIR, GIT_INDEX_FILE, GIT_WORK_TREE …; in a worktree always), so a check run from the
|
|
3
|
-
// pre-push hook would otherwise init, add and commit in the repository being pushed instead of its own.
|
|
4
|
-
import { execFileSync } from 'node:child_process';
|
|
5
|
-
|
|
6
|
-
// The variables, as this git names them.
|
|
7
|
-
const local = execFileSync('git', ['rev-parse', '--local-env-vars'], { encoding: 'utf8' }).split('\n').filter(Boolean);
|
|
8
|
-
|
|
9
|
-
export const ownRepoEnv = (env = process.env) => Object.fromEntries(Object.entries(env).filter(([name]) => !local.includes(name)));
|
|
1
|
+
// The environment for git in a repository a script makes for itself. Git gives its hooks the variables that point a
|
|
2
|
+
// command at a repository (GIT_DIR, GIT_INDEX_FILE, GIT_WORK_TREE …; in a worktree always), so a check run from the
|
|
3
|
+
// pre-push hook would otherwise init, add and commit in the repository being pushed instead of its own.
|
|
4
|
+
import { execFileSync } from 'node:child_process';
|
|
5
|
+
|
|
6
|
+
// The variables, as this git names them.
|
|
7
|
+
const local = execFileSync('git', ['rev-parse', '--local-env-vars'], { encoding: 'utf8' }).split('\n').filter(Boolean);
|
|
8
|
+
|
|
9
|
+
export const ownRepoEnv = (env = process.env) => Object.fromEntries(Object.entries(env).filter(([name]) => !local.includes(name)));
|