@morphemecms/cms 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/astro.mjs +3 -0
- package/bin/morpheme.mjs +3 -1
- package/defaults/blockTexts.ts +2 -2
- package/defaults/collections.ts +10 -0
- package/defaults/editor.ts +57 -53
- package/defaults/privacy.ts +4 -1
- package/defaults/rules.ts +36 -38
- package/defaults/standardPages.ts +0 -3
- package/defaults/texts.ts +11 -2
- package/demo/src/content/pages/about.md +2 -0
- package/icons/lucide/browser-fill.svg +1 -0
- package/icons/lucide/buildings-fill.svg +1 -0
- package/icons/lucide/certificate-fill.svg +1 -0
- package/icons/lucide/chart-line-up-fill.svg +1 -0
- package/icons/lucide/chats-fill.svg +1 -0
- package/icons/lucide/envelope-simple-fill.svg +1 -0
- package/icons/lucide/file-text-fill.svg +1 -0
- package/icons/lucide/folder-simple-fill.svg +1 -0
- package/icons/lucide/gauge.svg +1 -1
- package/icons/lucide/gear-six.svg +1 -0
- package/icons/lucide/globe-simple.svg +1 -0
- package/icons/lucide/heart-fill.svg +1 -0
- package/icons/lucide/layout.svg +1 -0
- package/icons/lucide/list-checks-fill.svg +1 -0
- package/icons/lucide/magnifying-glass-fill.svg +1 -0
- package/icons/lucide/megaphone-fill.svg +1 -0
- package/icons/lucide/newspaper-fill.svg +1 -0
- package/icons/lucide/paint-brush-broad-fill.svg +1 -0
- package/icons/lucide/puzzle-piece-fill.svg +1 -0
- package/icons/lucide/shield-check-fill.svg +1 -0
- package/icons/lucide/sidebar-simple.svg +1 -1
- package/icons/lucide/sidebar.svg +1 -0
- package/icons/lucide/square-half-bottom-fill.svg +1 -0
- package/icons/lucide/square-half.svg +1 -0
- package/icons/lucide/squares-four-fill.svg +1 -0
- package/icons/lucide/storefront-fill.svg +1 -0
- package/icons/lucide/tag-fill.svg +1 -0
- package/icons/lucide/toggle-right-fill.svg +1 -0
- package/icons/lucide/trash-fill.svg +1 -0
- package/icons/lucide/user-fill.svg +1 -0
- package/icons/lucide/wrench-fill.svg +1 -0
- package/icons/material-symbols/browser-fill.svg +1 -0
- package/icons/material-symbols/buildings-fill.svg +1 -0
- package/icons/material-symbols/certificate-fill.svg +1 -0
- package/icons/material-symbols/chart-line-up-fill.svg +1 -0
- package/icons/material-symbols/chats-fill.svg +1 -0
- package/icons/material-symbols/envelope-simple-fill.svg +1 -0
- package/icons/material-symbols/file-text-fill.svg +1 -0
- package/icons/material-symbols/folder-simple-fill.svg +1 -0
- package/icons/material-symbols/gauge.svg +1 -1
- package/icons/material-symbols/gear-six.svg +1 -0
- package/icons/material-symbols/globe-simple.svg +1 -0
- package/icons/material-symbols/heart-fill.svg +1 -0
- package/icons/material-symbols/layout.svg +1 -0
- package/icons/material-symbols/list-checks-fill.svg +1 -0
- package/icons/material-symbols/magnifying-glass-fill.svg +1 -0
- package/icons/material-symbols/megaphone-fill.svg +1 -0
- package/icons/material-symbols/newspaper-fill.svg +1 -0
- package/icons/material-symbols/paint-brush-broad-fill.svg +1 -0
- package/icons/material-symbols/puzzle-piece-fill.svg +1 -0
- package/icons/material-symbols/shield-check-fill.svg +1 -0
- package/icons/material-symbols/sidebar-simple.svg +1 -1
- package/icons/material-symbols/sidebar.svg +1 -0
- package/icons/material-symbols/square-half-bottom-fill.svg +1 -0
- package/icons/material-symbols/square-half.svg +1 -0
- package/icons/material-symbols/squares-four-fill.svg +1 -0
- package/icons/material-symbols/storefront-fill.svg +1 -0
- package/icons/material-symbols/tag-fill.svg +1 -0
- package/icons/material-symbols/toggle-right-fill.svg +1 -0
- package/icons/material-symbols/trash-fill.svg +1 -0
- package/icons/material-symbols/user-fill.svg +1 -0
- package/icons/material-symbols/wrench-fill.svg +1 -0
- package/icons/phosphor/browser-fill.svg +1 -0
- package/icons/phosphor/buildings-fill.svg +1 -0
- package/icons/phosphor/certificate-fill.svg +1 -0
- package/icons/phosphor/chart-line-up-fill.svg +1 -0
- package/icons/phosphor/chats-fill.svg +1 -0
- package/icons/phosphor/envelope-simple-fill.svg +1 -0
- package/icons/phosphor/file-text-fill.svg +1 -0
- package/icons/phosphor/folder-simple-fill.svg +1 -0
- package/icons/phosphor/gear-six.svg +1 -0
- package/icons/phosphor/globe-simple.svg +1 -0
- package/icons/phosphor/heart-fill.svg +1 -0
- package/icons/phosphor/layout.svg +1 -0
- package/icons/phosphor/list-checks-fill.svg +1 -0
- package/icons/phosphor/magnifying-glass-fill.svg +1 -0
- package/icons/phosphor/megaphone-fill.svg +1 -0
- package/icons/phosphor/newspaper-fill.svg +1 -0
- package/icons/phosphor/paint-brush-broad-fill.svg +1 -0
- package/icons/phosphor/puzzle-piece-fill.svg +1 -0
- package/icons/phosphor/shield-check-fill.svg +1 -0
- package/icons/phosphor/sidebar.svg +1 -0
- package/icons/phosphor/square-half-bottom-fill.svg +1 -0
- package/icons/phosphor/square-half.svg +1 -0
- package/icons/phosphor/squares-four-fill.svg +1 -0
- package/icons/phosphor/storefront-fill.svg +1 -0
- package/icons/phosphor/tag-fill.svg +1 -0
- package/icons/phosphor/toggle-right-fill.svg +1 -0
- package/icons/phosphor/trash-fill.svg +1 -0
- package/icons/phosphor/user-fill.svg +1 -0
- package/icons/phosphor/wrench-fill.svg +1 -0
- package/lib/breakpoints.d.mts +13 -0
- package/lib/breakpoints.mjs +20 -0
- package/lib/breakpoints.test.mjs +39 -0
- package/lib/build-lane.d.mts +15 -0
- package/lib/build-lane.mjs +23 -0
- package/lib/build-lane.test.mjs +74 -0
- package/lib/build-settings.d.mts +16 -0
- package/lib/build-settings.mjs +39 -0
- package/lib/build-settings.test.mjs +41 -0
- package/lib/contracts.d.mts +3 -2
- package/lib/contracts.mjs +3 -2
- package/lib/drawer-swipe.d.mts +10 -0
- package/lib/drawer-swipe.mjs +17 -0
- package/lib/drawer-swipe.test.mjs +33 -0
- package/lib/drawerKeys.d.mts +9 -0
- package/lib/drawerKeys.mjs +26 -0
- package/lib/drawerKeys.test.mjs +21 -0
- package/lib/eyebrow.d.mts +6 -0
- package/lib/eyebrow.mjs +24 -0
- package/lib/eyebrow.test.mjs +20 -0
- package/lib/front-sections.test.mjs +82 -0
- package/lib/heading-levels.d.mts +7 -0
- package/lib/heading-levels.mjs +16 -0
- package/lib/heading-levels.test.mjs +37 -0
- package/lib/inline.ts +3 -2
- package/lib/markdown.ts +2 -0
- package/lib/materialIcon.d.mts +21 -0
- package/lib/materialIcon.mjs +29 -0
- package/lib/materialIcon.test.mjs +45 -0
- package/lib/menu-layout.d.mts +11 -0
- package/lib/menu-layout.mjs +14 -0
- package/lib/menu-layout.test.mjs +23 -0
- package/lib/menu.d.mts +59 -0
- package/lib/menu.mjs +129 -0
- package/lib/menu.test.mjs +291 -0
- package/lib/rehype-emphasize.d.mts +4 -0
- package/lib/rehype-emphasize.mjs +20 -0
- package/lib/rehype-emphasize.test.mjs +39 -0
- package/lib/section-in-view.d.mts +8 -0
- package/lib/section-in-view.mjs +25 -0
- package/lib/section-in-view.test.mjs +35 -0
- package/lib/section-marker.d.mts +5 -0
- package/lib/section-marker.mjs +18 -0
- package/lib/section-marker.test.mjs +22 -0
- package/lib/section-ranges.d.mts +12 -0
- package/lib/section-ranges.mjs +43 -0
- package/lib/section-ranges.test.mjs +61 -0
- package/lib/sheet-stops.d.mts +68 -0
- package/lib/sheet-stops.mjs +198 -0
- package/lib/sheet-stops.test.mjs +155 -0
- package/lib/still-timer.d.mts +5 -0
- package/lib/still-timer.mjs +17 -0
- package/lib/still-timer.test.mjs +42 -0
- package/lib/text-sections.d.mts +10 -0
- package/lib/text-sections.mjs +45 -0
- package/lib/text-sections.test.mjs +78 -0
- package/lib/video.mjs +2 -1
- package/lib/without-h1.d.mts +1 -0
- package/lib/without-h1.mjs +7 -0
- package/lib/without-h1.test.mjs +26 -0
- package/lib/word-at.d.mts +6 -0
- package/lib/word-at.mjs +20 -0
- package/lib/word-at.test.mjs +19 -0
- package/package.json +3 -1
- package/pages/editor/version.json.js +22 -2
- package/scripts/already-checked.mjs +11 -0
- package/scripts/already-checked.test.mjs +18 -0
- package/scripts/build-settings-problems.mjs +27 -0
- package/scripts/build-settings-problems.test.mjs +35 -0
- package/scripts/check-content.mjs +42 -4
- package/scripts/check-worker.mjs +96 -4
- package/scripts/ci-build.mjs +85 -0
- package/scripts/ci-build.test.mjs +137 -0
- package/scripts/editor-roundtrip.mjs +62 -3
- package/scripts/editor-screens.mjs +21 -7
- package/scripts/git-env.mjs +6 -0
- package/scripts/step-command.mjs +34 -0
- package/scripts/step-command.test.mjs +50 -0
- package/scripts/text-problems.mjs +83 -0
- package/scripts/text-problems.test.mjs +74 -0
- package/scripts/worker-modules.mjs +11 -1
- package/site/breakpoints.d.mts +6 -0
- package/site/breakpoints.mjs +52 -0
- package/site/breakpoints.test.mjs +36 -0
- package/site/casing.d.mts +3 -0
- package/site/casing.mjs +26 -0
- package/site/content.config.ts +2 -0
- package/site/content.ts +2 -4
- package/site/defineSite.d.mts +1 -0
- package/site/defineSite.mjs +3 -0
- package/site/home.ts +3 -2
- package/site/icons.d.mts +116 -4
- package/site/icons.mjs +62 -6
- package/site/images.mjs +1 -1
- package/site/live-diff.d.mts +22 -0
- package/site/live-diff.mjs +98 -0
- package/site/live-diff.test.mjs +235 -0
- package/site/materialSymbols.d.mts +5 -0
- package/site/materialSymbols.mjs +19 -0
- package/site/sections.ts +1 -1
- package/site/theme.d.mts +1 -1
- package/site/theme.mjs +7 -1
- package/src/ActionParts.tsx +1 -1
- package/src/Advanced.tsx +101 -20
- package/src/App.tsx +47 -121
- package/src/AppList.tsx +1 -1
- package/src/BlockParts.tsx +3 -3
- package/src/Colors.tsx +1 -1
- package/src/CommunicationParts.tsx +1 -1
- package/src/ContainmentParts.tsx +80 -28
- package/src/Deleted.tsx +18 -4
- package/src/EditorFooter.tsx +14 -0
- package/src/EntryForm.tsx +75 -39
- package/src/FormFrame.tsx +3 -8
- package/src/Library.tsx +46 -51
- package/src/Licenses.tsx +27 -11
- package/src/MainDrawerParts.tsx +60 -0
- package/src/MainMenu.tsx +136 -0
- package/src/MarkdownEditor.tsx +175 -32
- package/src/Media.tsx +69 -16
- package/src/MediaTags.tsx +91 -0
- package/src/ModalSheetSample.tsx +47 -0
- package/src/NavigationParts.tsx +67 -21
- package/src/NavigationRestParts.tsx +1 -1
- package/src/Parts.tsx +71 -0
- package/src/PartsShown.tsx +1 -1
- package/src/PickerParts.tsx +2 -2
- package/src/Redirects.tsx +3 -2
- package/src/Screen.tsx +93 -90
- package/src/SelectionParts.tsx +22 -6
- package/src/SiteLogoLink.tsx +14 -0
- package/src/StartFab.tsx +22 -0
- package/src/StartStatus.tsx +1 -1
- package/src/autoTags.d.mts +28 -0
- package/src/autoTags.mjs +68 -0
- package/src/autoTags.test.mjs +109 -0
- package/src/buildSettings.test.mjs +20 -0
- package/src/buildSettings.ts +20 -0
- package/src/checkSite.ts +14 -1
- package/src/deploy.ts +7 -9
- package/src/editor.css +150 -17
- package/src/eyebrow.d.mts +5 -0
- package/src/eyebrow.mjs +53 -0
- package/src/eyebrowState.d.mts +21 -0
- package/src/eyebrowState.mjs +62 -0
- package/src/eyebrowState.test.mjs +78 -0
- package/src/fileRecords.d.mts +115 -0
- package/src/fileRecords.mjs +224 -0
- package/src/fileRecords.test.mjs +224 -0
- package/src/fileTagFilter.d.mts +30 -0
- package/src/fileTagFilter.mjs +44 -0
- package/src/fileTagFilter.test.mjs +57 -0
- package/src/fileTags.d.mts +56 -0
- package/src/fileTags.mjs +100 -0
- package/src/fileTags.test.mjs +127 -0
- package/src/firstHeading.d.mts +6 -0
- package/src/firstHeading.mjs +37 -0
- package/src/i18n/da-DK/advanced.ts +27 -12
- package/src/i18n/da-DK/app.ts +9 -7
- package/src/i18n/da-DK/apps.ts +16 -16
- package/src/i18n/da-DK/blockSettings.ts +9 -9
- package/src/i18n/da-DK/blocks.ts +2 -2
- package/src/i18n/da-DK/check.ts +5 -2
- package/src/i18n/da-DK/cms.ts +14 -12
- package/src/i18n/da-DK/colors.ts +5 -5
- package/src/i18n/da-DK/common.ts +2 -2
- package/src/i18n/da-DK/company.ts +3 -3
- package/src/i18n/da-DK/consents.ts +6 -6
- package/src/i18n/da-DK/forms.ts +6 -6
- package/src/i18n/da-DK/history.ts +6 -6
- package/src/i18n/da-DK/keywords.ts +2 -2
- package/src/i18n/da-DK/library.ts +17 -15
- package/src/i18n/da-DK/licenses.ts +4 -4
- package/src/i18n/da-DK/media.ts +10 -4
- package/src/i18n/da-DK/parts.ts +62 -25
- package/src/i18n/da-DK/preview.ts +5 -6
- package/src/i18n/da-DK/redirects.ts +7 -7
- package/src/i18n/da-DK/seo.ts +1 -1
- package/src/i18n/da-DK/text.ts +2 -0
- package/src/i18n/da-DK/theme.ts +5 -5
- package/src/i18n/en-US/advanced.ts +34 -18
- package/src/i18n/en-US/app.ts +7 -5
- package/src/i18n/en-US/apps.ts +9 -9
- package/src/i18n/en-US/blockSettings.ts +4 -4
- package/src/i18n/en-US/blocks.ts +6 -6
- package/src/i18n/en-US/check.ts +6 -3
- package/src/i18n/en-US/cms.ts +15 -14
- package/src/i18n/en-US/colors.ts +18 -18
- package/src/i18n/en-US/common.ts +3 -3
- package/src/i18n/en-US/consents.ts +4 -4
- package/src/i18n/en-US/forms.ts +5 -5
- package/src/i18n/en-US/history.ts +2 -2
- package/src/i18n/en-US/library.ts +21 -15
- package/src/i18n/en-US/licenses.ts +6 -6
- package/src/i18n/en-US/media.ts +7 -1
- package/src/i18n/en-US/parts.ts +60 -21
- package/src/i18n/en-US/preview.ts +5 -6
- package/src/i18n/en-US/redirects.ts +3 -3
- package/src/i18n/en-US/seo.ts +1 -1
- package/src/i18n/en-US/text.ts +3 -0
- package/src/i18n/en-US/theme.ts +6 -6
- package/src/icon.tsx +90 -27
- package/src/licenseData.test.mjs +28 -0
- package/src/licenseData.ts +12 -1
- package/src/markdown.d.mts +2 -0
- package/src/markdown.mjs +73 -5
- package/src/markdown.test.mjs +74 -0
- package/src/materialIcons.ts +8 -0
- package/src/menuChildren.ts +36 -0
- package/src/menuOpen.ts +34 -0
- package/src/pagePreview.tsx +23 -19
- package/src/r2Caching.ts +14 -0
- package/src/sectionFrame.ts +39 -0
- package/src/sectionState.d.mts +19 -0
- package/src/sectionState.mjs +31 -0
- package/src/sectionState.test.mjs +59 -0
- package/src/sections.d.mts +9 -7
- package/src/sections.mjs +74 -27
- package/src/sections.test.mjs +59 -0
- package/src/sidebar.ts +2 -2
- package/src/site.ts +27 -17
- package/src/stillCursor.d.mts +8 -0
- package/src/stillCursor.mjs +19 -0
- package/src/stillCursor.test.mjs +26 -0
- package/src/tagUses.d.mts +47 -0
- package/src/tagUses.mjs +121 -0
- package/src/tagUses.test.mjs +141 -0
- package/src/themeUi.ts +10 -0
- package/src/topBarSlot.tsx +37 -0
- package/src/ui.tsx +654 -150
- package/src/virtual.d.ts +5 -0
- package/starter/README.md +2 -1
- package/starter/package.json +2 -1
- package/starter/wrangler.jsonc +3 -2
- package/theme/blocks/cards/LinkCards.tsx +2 -1
- package/theme/blocks/hero/View.tsx +2 -1
- package/theme/blocks/video/View.tsx +2 -1
- package/theme/components/BlogIndex.astro +2 -2
- package/theme/components/BlogPosts.astro +1 -1
- package/theme/components/BlogPosts.tsx +9 -6
- package/theme/components/Container.astro +1 -1
- package/theme/components/CookieConsent.astro +1 -1
- package/theme/components/EndBlock.astro +1 -1
- package/theme/components/Footer.astro +5 -5
- package/theme/components/Header.astro +3 -3
- package/theme/components/Icon.astro +2 -2
- package/theme/components/MobileMenu.tsx +72 -61
- package/theme/components/MobileNav.astro +2 -2
- package/theme/components/PageHeader.astro +2 -2
- package/theme/components/PageSection.astro +1 -1
- package/theme/components/PopupButton.tsx +2 -2
- package/theme/components/PopupView.tsx +2 -2
- package/theme/components/PostList.tsx +7 -3
- package/theme/components/RichText.astro +22 -7
- package/theme/components/Section.astro +17 -10
- package/theme/components/SectionHeading.tsx +1 -1
- package/theme/components/home/PageBlock.astro +4 -4
- package/theme/components/home/Text.astro +3 -3
- package/theme/layouts/PageLayout.astro +3 -3
- package/theme/layouts/PostLayout.astro +9 -8
- package/theme/styles/base.css +13 -3
- package/theme/styles/blocks.css +97 -10
- package/theme/styles/components.css +9 -9
- package/theme/styles/elevation.test.mjs +168 -0
- package/theme/styles/global.css +65 -59
- package/theme/styles/ui.css +460 -131
- package/theme/templates/Home.astro +1 -1
- package/theme/templates/New.astro +5 -5
- package/theme/templates/NotFound.astro +2 -2
- package/theme/ui/BottomSheet.tsx +118 -21
- package/theme/ui/BottomSheetResizeIcon.tsx +13 -0
- package/theme/ui/Button.tsx +4 -3
- package/theme/ui/Dialog.tsx +1 -1
- package/theme/ui/FabMenu.tsx +13 -12
- package/theme/ui/LoadingIndicator.tsx +1 -1
- package/theme/ui/NavigationDrawer.tsx +116 -15
- package/theme/ui/NavigationRail.tsx +22 -13
- package/theme/ui/Search.tsx +1 -1
- package/theme/ui/SettingRow.tsx +31 -0
- package/theme/ui/Switch.tsx +11 -11
- package/theme/ui/TextField.tsx +17 -6
- package/theme/ui/bottomSheet.script.ts +3 -2
- package/theme/ui/bottomSheetControl.ts +131 -46
- package/theme/ui/fabMenu.script.ts +69 -53
- package/theme/ui/modalSheetSize.ts +214 -0
- package/theme/ui/navigationDrawerControl.ts +35 -0
- package/theme/ui/search.script.ts +4 -2
- package/worker/index.js +3 -0
- package/worker/plan-status.js +46 -0
- package/worker/push.js +7 -5
- package/worker/r2-status.js +2 -1
- package/icons/lucide/desktop.svg +0 -1
- package/icons/material-symbols/desktop.svg +0 -1
- package/icons/phosphor/desktop.svg +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
// A front-page section: container, spacing above, reveal on scroll and an optional heading + intro
|
|
2
|
+
// A front-page section: container, spacing above, reveal on scroll and an optional heading + intro; with a `color`
|
|
3
|
+
// the content sits in a panel (.text-section-<color>, blocks.css) inside the container, none without one.
|
|
3
4
|
import Container from '@theme/components/Container.astro';
|
|
4
5
|
import SectionHeading from '@theme/components/SectionHeading';
|
|
5
6
|
import Inline from '@theme/components/Inline.astro';
|
|
@@ -10,20 +11,26 @@ interface Props {
|
|
|
10
11
|
class?: string;
|
|
11
12
|
/** Id for the heading; the section is then labelled by it (aria-labelledby). */
|
|
12
13
|
id?: string;
|
|
14
|
+
/** The colour of the panel behind the section (`sectionColor` from the front page's heading, as in a page's text-section). */
|
|
15
|
+
color?: string;
|
|
13
16
|
}
|
|
14
|
-
const { title, intro, class: className, id } = Astro.props;
|
|
17
|
+
const { title, intro, class: className, id, color } = Astro.props;
|
|
18
|
+
const Panel = color ? 'div' : Fragment;
|
|
19
|
+
const panel = color ? { class: `text-section text-section-${color} my-0` } : {};
|
|
15
20
|
---
|
|
16
21
|
|
|
17
22
|
<Container
|
|
18
|
-
class:list={['pt-(--theme-section-space)
|
|
23
|
+
class:list={['pt-(--theme-section-space) medium:pt-(--theme-section-space-large)', className]}
|
|
19
24
|
aria-labelledby={title && id ? id : undefined}
|
|
20
25
|
data-reveal
|
|
21
26
|
>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
<Panel {...panel}>
|
|
28
|
+
{title && <SectionHeading id={id} text={title} />}
|
|
29
|
+
{intro && (
|
|
30
|
+
<p class="type-body-large mt-3 max-w-[52ch] text-muted">
|
|
31
|
+
<Inline text={intro} />
|
|
32
|
+
</p>
|
|
33
|
+
)}
|
|
34
|
+
<slot />
|
|
35
|
+
</Panel>
|
|
29
36
|
</Container>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// The h2 used for every front-page section. `text`: its text.
|
|
2
2
|
export default function SectionHeading({ text, id, className }: { text: string; id?: string; className?: string }) {
|
|
3
3
|
return (
|
|
4
|
-
<h2 id={id} className={['type-headline-large
|
|
4
|
+
<h2 id={id} className={['type-headline-large medium:type-display-medium', className].filter(Boolean).join(' ')}>
|
|
5
5
|
{text}
|
|
6
6
|
</h2>
|
|
7
7
|
);
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
// A block a page can have, as a section of the front page (`pageBlocks` in packages/editor/defaults/collections.ts): the standard
|
|
3
|
-
// one's or the app's (Block.astro, by its type), in the front page's width and space, with its shared texts.
|
|
3
|
+
// one's or the app's (Block.astro, by its type), in the front page's width and space, with its shared texts; a colour under its heading (`sectionColor`) goes to Section, not to the block.
|
|
4
4
|
import Block from '@morphemecms/cms/src/standard/Block.astro';
|
|
5
5
|
import Section from '@theme/components/Section.astro';
|
|
6
6
|
import { blockTexts } from '@morphemecms/cms/site/site';
|
|
7
7
|
|
|
8
8
|
interface Props {
|
|
9
|
-
section: { type: string; hidden?: boolean } & Record<string, unknown>;
|
|
9
|
+
section: { type: string; hidden?: boolean; sectionColor?: string } & Record<string, unknown>;
|
|
10
10
|
class?: string;
|
|
11
11
|
}
|
|
12
|
-
const { type, hidden, ...props } = Astro.props.section;
|
|
12
|
+
const { type, hidden, sectionColor, ...props } = Astro.props.section;
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
<Section class={Astro.props.class}>
|
|
15
|
+
<Section class={Astro.props.class} color={sectionColor}>
|
|
16
16
|
<div class="block-place">
|
|
17
17
|
<Block type={type} props={props} texts={blockTexts[type]} />
|
|
18
18
|
</div>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
|
-
// A text the site's owner writes: an optional heading and Markdown.
|
|
2
|
+
// A text the site's owner writes: an optional heading and Markdown, in a panel when its heading has a colour (`sectionColor`).
|
|
3
3
|
import Section from '@theme/components/Section.astro';
|
|
4
4
|
import Markdown from '@theme/components/Markdown.astro';
|
|
5
5
|
import type { HomeSection } from '@morphemecms/cms/site/home';
|
|
6
6
|
|
|
7
7
|
type Props = Extract<HomeSection, { type: 'text' }> & { class?: string };
|
|
8
|
-
const { heading, body, class: className } = Astro.props;
|
|
8
|
+
const { heading, body, sectionColor, class: className } = Astro.props;
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
<Section title={heading} class={className}>
|
|
11
|
+
<Section title={heading} class={className} color={sectionColor}>
|
|
12
12
|
<Markdown body={body} class={heading && 'mt-6'} />
|
|
13
13
|
</Section>
|
|
@@ -90,7 +90,7 @@ const side =
|
|
|
90
90
|
questions={questions}
|
|
91
91
|
>
|
|
92
92
|
<article>
|
|
93
|
-
<Container as="header" class="pt-8
|
|
93
|
+
<Container as="header" class="pt-8 medium:pt-14">
|
|
94
94
|
{parent && (
|
|
95
95
|
<a href={parent.href} class="inline-flex items-center gap-1.5 type-body-medium text-muted hover:text-accent">
|
|
96
96
|
<Icon name="arrow-left" size={16} />
|
|
@@ -102,14 +102,14 @@ const side =
|
|
|
102
102
|
</h1>
|
|
103
103
|
</Container>
|
|
104
104
|
|
|
105
|
-
<Container as="div" class:list={[wide ? 'mt-4' : 'mt-8
|
|
105
|
+
<Container as="div" class:list={[wide ? 'mt-4' : 'mt-8 medium:mt-12']}>
|
|
106
106
|
<div {...(side ? { class: 'page-with-side' } : {})}>
|
|
107
107
|
<div
|
|
108
108
|
data-editor="text"
|
|
109
109
|
class:list={[
|
|
110
110
|
'prose',
|
|
111
111
|
wide
|
|
112
|
-
? 'max-w-none [&>:not(.not-prose)]:max-w-[66ch] [&>p:first-child]:max-w-[52ch] [&>p:first-child]:type-body-large [&>p:first-child]:text-muted
|
|
112
|
+
? 'max-w-none [&>:not(.not-prose)]:max-w-[66ch] [&>p:first-child]:max-w-[52ch] [&>p:first-child]:type-body-large [&>p:first-child]:text-muted medium:[&>p:first-child]:type-title-large'
|
|
113
113
|
: 'max-w-[66ch]',
|
|
114
114
|
]}
|
|
115
115
|
>
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
// Blog post template. A narrow reading column, the site's owner as author; related posts in the footer.
|
|
3
3
|
// data-editor marks what the editor's preview fills in with what is in its form ("Forhåndsvis",
|
|
4
|
-
// packages/editor/src/pagePreview.tsx): the heading, the picture and the text.
|
|
4
|
+
// packages/editor/src/pagePreview.tsx): the heading, the picture and the text. The text goes through RichText (blocks={false}: a post draws no blocks, but its coloured sections are panels).
|
|
5
5
|
import { firstImage, heroImage, picturesOf } from '@morphemecms/cms/site/images.mjs';
|
|
6
6
|
import Base from '@theme/layouts/Base.astro';
|
|
7
7
|
import Icon from '@theme/components/Icon.astro';
|
|
8
8
|
import Img from '@theme/components/Img.astro';
|
|
9
9
|
import EndBlock from '@theme/components/EndBlock.astro';
|
|
10
|
+
import RichText from '@theme/components/RichText.astro';
|
|
10
11
|
import { categoryName, getPosts, postPath, stateOf, type Post } from '@morphemecms/cms/site/content';
|
|
11
12
|
import PostMeta from '@theme/components/PostMeta';
|
|
12
13
|
import Chip from '@theme/ui/Chip';
|
|
@@ -68,7 +69,7 @@ const related = (await getPosts())
|
|
|
68
69
|
]}
|
|
69
70
|
>
|
|
70
71
|
<article>
|
|
71
|
-
<header class="mx-auto max-w-3xl px-5 pt-8
|
|
72
|
+
<header class="mx-auto max-w-3xl px-5 pt-8 medium:px-8 medium:pt-14">
|
|
72
73
|
<a href="/blog/" class="inline-flex items-center gap-1.5 type-body-medium text-muted hover:text-accent">
|
|
73
74
|
<Icon name="arrow-left" size={16} /> {siteT.theme.blog}
|
|
74
75
|
</a>
|
|
@@ -87,22 +88,22 @@ const related = (await getPosts())
|
|
|
87
88
|
</header>
|
|
88
89
|
|
|
89
90
|
{image && (
|
|
90
|
-
<div data-editor="image" class="mx-auto mt-8 max-w-5xl px-5
|
|
91
|
+
<div data-editor="image" class="mx-auto mt-8 max-w-5xl px-5 medium:mt-12 medium:px-8">
|
|
91
92
|
<Img
|
|
92
93
|
src={image}
|
|
93
94
|
alt={imageAlt ?? ''}
|
|
94
95
|
fetchpriority="high"
|
|
95
|
-
class="aspect-[16/10] w-full rounded-(--theme-picture-radius) object-cover
|
|
96
|
-
sizes="(
|
|
96
|
+
class="aspect-[16/10] w-full rounded-(--theme-picture-radius) object-cover medium:aspect-[16/9]"
|
|
97
|
+
sizes="min(60rem, calc(100vw - 2.5rem))"
|
|
97
98
|
/>
|
|
98
99
|
</div>
|
|
99
100
|
)}
|
|
100
101
|
|
|
101
|
-
<div data-editor="text" class="prose mx-auto mt-10 max-w-3xl px-5
|
|
102
|
-
<
|
|
102
|
+
<div data-editor="text" class="prose mx-auto mt-10 max-w-3xl px-5 medium:mt-14 medium:px-8">
|
|
103
|
+
<RichText html={await Astro.slots.render('default')} blocks={false} />
|
|
103
104
|
</div>
|
|
104
105
|
|
|
105
|
-
<footer class="mx-auto mt-12 max-w-3xl px-5
|
|
106
|
+
<footer class="mx-auto mt-12 max-w-3xl px-5 medium:px-8">
|
|
106
107
|
{onBlog.length > 0 && (
|
|
107
108
|
<ul class="flex flex-wrap gap-2" aria-label="Tags">
|
|
108
109
|
{onBlog.map((c) => (
|
package/theme/styles/base.css
CHANGED
|
@@ -93,6 +93,16 @@
|
|
|
93
93
|
--ease-soft: var(--ease);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/* Material 3's breakpoints (m3.material.io/foundations/layout/breakpoints): Tailwind's medium:, expanded:, large: and
|
|
97
|
+
extra-large: (and max-…:), and theme(--breakpoint-…) in a @media; the same as lib/breakpoints.mjs for scripts. */
|
|
98
|
+
@theme {
|
|
99
|
+
--breakpoint-*: initial;
|
|
100
|
+
--breakpoint-medium: 37.5rem;
|
|
101
|
+
--breakpoint-expanded: 52.5rem;
|
|
102
|
+
--breakpoint-large: 75rem;
|
|
103
|
+
--breakpoint-extra-large: 100rem;
|
|
104
|
+
}
|
|
105
|
+
|
|
96
106
|
/* z-index scale (documented, no ad-hoc values): action bar 30, header 40, cookie banner 42 (under the
|
|
97
107
|
open menu, which must stay usable), menu 45, skip link 50 */
|
|
98
108
|
|
|
@@ -276,7 +286,7 @@
|
|
|
276
286
|
font-weight: var(--type-headline-large-weight);
|
|
277
287
|
letter-spacing: var(--type-headline-large-tracking);
|
|
278
288
|
}
|
|
279
|
-
@media (
|
|
289
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
280
290
|
.block-place > h2,
|
|
281
291
|
.block-place > .block-head > h2 {
|
|
282
292
|
font-size: var(--type-display-medium-size);
|
|
@@ -287,7 +297,7 @@
|
|
|
287
297
|
}
|
|
288
298
|
/* Cards placed in the page's full width (a front-page section, PageBlock.astro): three in a row on a computer, as
|
|
289
299
|
there is room for (in the text, two). */
|
|
290
|
-
@media (
|
|
300
|
+
@media (width >= theme(--breakpoint-expanded)) {
|
|
291
301
|
.block-place .block-cards {
|
|
292
302
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
293
303
|
}
|
|
@@ -313,7 +323,7 @@
|
|
|
313
323
|
font-weight: var(--type-headline-small-weight);
|
|
314
324
|
letter-spacing: var(--type-headline-small-tracking);
|
|
315
325
|
}
|
|
316
|
-
@media (
|
|
326
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
317
327
|
.block-panels > .block-panel {
|
|
318
328
|
--card-padding: 2rem;
|
|
319
329
|
}
|
package/theme/styles/blocks.css
CHANGED
|
@@ -23,6 +23,9 @@
|
|
|
23
23
|
square, a step on a time line)
|
|
24
24
|
--block-control-radius the corners of a button and a tag (a pill when large)
|
|
25
25
|
--block-shadow the shadow of a raised panel
|
|
26
|
+
--block-section-padding, --block-section-margin the space inside, and above and below, a coloured section of a text
|
|
27
|
+
(.text-section: a panel the width of the text column, on --block-surface, --block-tint or --block-accent; on the accent
|
|
28
|
+
the blocks in it get inverted variables: text, accent and line on-accent, surface and tint a veil of it)
|
|
26
29
|
--block-ease the easing of motion (else the motion scheme's, --motion-ease)
|
|
27
30
|
--block-ease-quick the easing of a quick change of state (a colour, an arrow that turns or moves; else the motion
|
|
28
31
|
scheme's, --motion-ease-quick)
|
|
@@ -31,7 +34,7 @@
|
|
|
31
34
|
--block-page-width, --block-gutter the page's container (its width, gutters included, and its gutter at the
|
|
32
35
|
side), whose left edge the text starts at: how far a banner across the whole width reaches out
|
|
33
36
|
of the text to the window's edges, and where its content starts again (the standard theme's
|
|
34
|
-
Container.astro: 72rem, 1.25rem and 2rem from
|
|
37
|
+
Container.astro: 72rem, 1.25rem and 2rem from the medium width)
|
|
35
38
|
|
|
36
39
|
How things move is the site's motion scheme (Material 3's, chosen under "Udseende" › "Bevægelse"; lib/motion.ts), which
|
|
37
40
|
Base.astro writes into the <head> as springs, each its duration and curve, for `transition` and `animation`:
|
|
@@ -81,8 +84,10 @@
|
|
|
81
84
|
--block-ease-quick: var(--motion-ease-quick, cubic-bezier(0.2, 0, 0, 1));
|
|
82
85
|
--block-page-width: 72rem;
|
|
83
86
|
--block-gutter: 1.25rem;
|
|
87
|
+
--block-section-padding: 1.5rem;
|
|
88
|
+
--block-section-margin: 2rem;
|
|
84
89
|
}
|
|
85
|
-
@media (
|
|
90
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
86
91
|
:where(:root) {
|
|
87
92
|
--block-gutter: 2rem;
|
|
88
93
|
}
|
|
@@ -95,6 +100,62 @@
|
|
|
95
100
|
margin-block: 2rem;
|
|
96
101
|
}
|
|
97
102
|
|
|
103
|
+
/* A coloured section of a page's or post's text (lib/text-sections.mjs, RichText.astro): a panel the width of the text
|
|
104
|
+
column, from its heading to the next (its first and last parts' margins: at the end of the file). */
|
|
105
|
+
.text-section {
|
|
106
|
+
margin-block: var(--block-section-margin);
|
|
107
|
+
border-radius: var(--block-radius);
|
|
108
|
+
padding: var(--block-section-padding);
|
|
109
|
+
}
|
|
110
|
+
.text-section-surface {
|
|
111
|
+
background: var(--block-surface);
|
|
112
|
+
box-shadow: var(--block-shadow);
|
|
113
|
+
}
|
|
114
|
+
.text-section-tint {
|
|
115
|
+
background: var(--block-tint);
|
|
116
|
+
}
|
|
117
|
+
/* On the accent everything in the text is the text-on-accent colour (the prose colours are variables, .prose in base.css),
|
|
118
|
+
links too: they are underlined by the prose style. The section's real colours are kept in private variables first
|
|
119
|
+
(--section-…): the blocks in it get the variables swapped (below), and a variable cannot swap with another on the
|
|
120
|
+
same element. */
|
|
121
|
+
.text-section-accent {
|
|
122
|
+
--section-accent: var(--block-accent);
|
|
123
|
+
--section-on-accent: var(--block-on-accent);
|
|
124
|
+
--section-text: var(--block-text);
|
|
125
|
+
--section-surface: var(--block-surface);
|
|
126
|
+
background: var(--section-accent);
|
|
127
|
+
color: var(--section-on-accent);
|
|
128
|
+
--tw-prose-body: var(--section-on-accent);
|
|
129
|
+
--tw-prose-headings: var(--section-on-accent);
|
|
130
|
+
--tw-prose-lead: var(--section-on-accent);
|
|
131
|
+
--tw-prose-links: var(--section-on-accent);
|
|
132
|
+
--tw-prose-bold: var(--section-on-accent);
|
|
133
|
+
--tw-prose-counters: var(--section-on-accent);
|
|
134
|
+
--tw-prose-bullets: var(--section-on-accent);
|
|
135
|
+
--tw-prose-hr: var(--section-on-accent);
|
|
136
|
+
--tw-prose-quotes: var(--section-on-accent);
|
|
137
|
+
--tw-prose-quote-borders: var(--section-on-accent);
|
|
138
|
+
--tw-prose-captions: var(--section-on-accent);
|
|
139
|
+
--tw-prose-code: var(--section-on-accent);
|
|
140
|
+
}
|
|
141
|
+
/* The blocks in it read as an inverted theme on the accent: text, lines and the accent itself are the text-on-accent
|
|
142
|
+
colour, a surface is a veil of it, and what was text-on-accent (a filled button's label, a step number) is the
|
|
143
|
+
accent. Dark mode follows, as the variables do. */
|
|
144
|
+
.text-section-accent > * {
|
|
145
|
+
--block-text: var(--section-on-accent);
|
|
146
|
+
--block-muted: color-mix(in srgb, var(--section-on-accent) 80%, transparent);
|
|
147
|
+
--block-accent: var(--section-on-accent);
|
|
148
|
+
--block-accent-hover: color-mix(in srgb, var(--section-on-accent) 88%, var(--section-accent));
|
|
149
|
+
--block-on-accent: var(--section-accent);
|
|
150
|
+
--block-surface: color-mix(in srgb, var(--section-on-accent) 14%, transparent);
|
|
151
|
+
--block-tint: color-mix(in srgb, var(--section-on-accent) 14%, transparent);
|
|
152
|
+
--block-line: color-mix(in srgb, var(--section-on-accent) 35%, transparent);
|
|
153
|
+
--block-shadow: none;
|
|
154
|
+
/* A hero with its picture behind the text is darkened with the section's own text colour, in its own surface. */
|
|
155
|
+
--block-hero-shade: var(--section-text);
|
|
156
|
+
--block-hero-on-shade: var(--section-surface);
|
|
157
|
+
}
|
|
158
|
+
|
|
98
159
|
/* "Besked": a short notice in a box with the accent along its left edge (notice/). */
|
|
99
160
|
.block-notice {
|
|
100
161
|
border-left: 4px solid var(--block-accent);
|
|
@@ -393,7 +454,7 @@
|
|
|
393
454
|
body:has(.block-hero-full.block-in-text) {
|
|
394
455
|
overflow-x: clip;
|
|
395
456
|
}
|
|
396
|
-
@media (
|
|
457
|
+
@media (width >= theme(--breakpoint-expanded)) {
|
|
397
458
|
.block-hero {
|
|
398
459
|
grid-template-columns: 7fr 5fr;
|
|
399
460
|
gap: 3rem;
|
|
@@ -964,7 +1025,7 @@
|
|
|
964
1025
|
font-weight: var(--type-title-large-weight);
|
|
965
1026
|
letter-spacing: var(--type-title-large-tracking);
|
|
966
1027
|
}
|
|
967
|
-
@media (width >=
|
|
1028
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
968
1029
|
.block-timeline {
|
|
969
1030
|
grid-auto-columns: 1fr;
|
|
970
1031
|
grid-auto-flow: column;
|
|
@@ -1000,7 +1061,7 @@
|
|
|
1000
1061
|
padding-top: 1.25rem;
|
|
1001
1062
|
}
|
|
1002
1063
|
/* Only on phones and tablets (a block a site shows beside the text on a computer). */
|
|
1003
|
-
@media (width >=
|
|
1064
|
+
@media (width >= theme(--breakpoint-expanded)) {
|
|
1004
1065
|
.block-small-screens {
|
|
1005
1066
|
display: none;
|
|
1006
1067
|
}
|
|
@@ -1405,7 +1466,7 @@
|
|
|
1405
1466
|
scale: 1.03;
|
|
1406
1467
|
}
|
|
1407
1468
|
}
|
|
1408
|
-
@media (width >=
|
|
1469
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
1409
1470
|
.block-buttons {
|
|
1410
1471
|
flex-direction: row;
|
|
1411
1472
|
flex-wrap: wrap;
|
|
@@ -1420,7 +1481,7 @@
|
|
|
1420
1481
|
text-align: right;
|
|
1421
1482
|
}
|
|
1422
1483
|
}
|
|
1423
|
-
@media (width >=
|
|
1484
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
1424
1485
|
.block-testimonial {
|
|
1425
1486
|
--card-padding: 1.75rem;
|
|
1426
1487
|
}
|
|
@@ -1737,7 +1798,7 @@
|
|
|
1737
1798
|
color: #fff;
|
|
1738
1799
|
text-shadow: 0 1px 3px rgb(0 0 0 / 0.8);
|
|
1739
1800
|
}
|
|
1740
|
-
@media (
|
|
1801
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
1741
1802
|
.prose .video-facade-still svg {
|
|
1742
1803
|
width: 4.5rem;
|
|
1743
1804
|
height: 4.5rem;
|
|
@@ -1754,7 +1815,7 @@
|
|
|
1754
1815
|
heading is the text's own <h2>, without this): the label in small capitals, spaced out, in the accent; the
|
|
1755
1816
|
subheading larger and quiet. Mostly in the text's style (.prose), so outside the layers, like the video above, whose
|
|
1756
1817
|
margins it sets in place of the text's; a theme that places a block outside the text sets its own (.block-place in
|
|
1757
|
-
the standard theme). A theme gives it its own look outside the layers too (the standard theme: in the middle). */
|
|
1818
|
+
the standard theme). A label above a heading in a text has the same look. A theme gives it its own look outside the layers too (the standard theme: in the middle). */
|
|
1758
1819
|
.block-head {
|
|
1759
1820
|
margin-block: 2.5em 1.25em;
|
|
1760
1821
|
}
|
|
@@ -1773,7 +1834,8 @@
|
|
|
1773
1834
|
.block-head > .block-eyebrow + h2 {
|
|
1774
1835
|
margin-top: 0.5rem;
|
|
1775
1836
|
}
|
|
1776
|
-
.block-head > .block-eyebrow
|
|
1837
|
+
.block-head > .block-eyebrow,
|
|
1838
|
+
.prose .block-eyebrow {
|
|
1777
1839
|
font-size: var(--type-label-medium-size);
|
|
1778
1840
|
line-height: var(--type-label-medium-line-height);
|
|
1779
1841
|
font-weight: var(--type-label-medium-weight);
|
|
@@ -1789,6 +1851,15 @@
|
|
|
1789
1851
|
color: var(--block-muted);
|
|
1790
1852
|
}
|
|
1791
1853
|
|
|
1854
|
+
/* A label above a heading in a text (packages/editor/lib/eyebrow.mjs): a block's label, with the heading's space above
|
|
1855
|
+
it and close to its heading. */
|
|
1856
|
+
.prose .block-eyebrow {
|
|
1857
|
+
margin-block: 2em 0;
|
|
1858
|
+
}
|
|
1859
|
+
.prose .block-eyebrow + :is(h1, h2, h3) {
|
|
1860
|
+
margin-top: 0.5rem;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1792
1863
|
/* A word or more in one of the site's colours, in a text (packages/editor/lib/text-colors.mjs, the colour button in the
|
|
1793
1864
|
editor): the accent, or the quiet text's, both readable on the background, the surfaces and the tint (the site's
|
|
1794
1865
|
pairs of colours, checked under "Farver"). Bold, italic and a link in it have its colour. Outside the layers, as it
|
|
@@ -1806,3 +1877,19 @@
|
|
|
1806
1877
|
.block-hero-behind :is(.color-accent, .color-muted) :is(strong, em, a) {
|
|
1807
1878
|
color: inherit;
|
|
1808
1879
|
}
|
|
1880
|
+
|
|
1881
|
+
/* A word in the accent's or the quiet text's colour (above) on a section with the accent as its background would not
|
|
1882
|
+
be read: there it has the section's text colour. */
|
|
1883
|
+
.text-section-accent :is(.color-accent, .color-muted),
|
|
1884
|
+
.text-section-accent :is(.color-accent, .color-muted) :is(strong, em, a) {
|
|
1885
|
+
color: inherit;
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
/* The first and last parts of a coloured section lose the prose margins that would add to the panel's padding. Outside
|
|
1889
|
+
the layers, as the prose style (Tailwind's typography) is in the utilities layer, which wins over components. */
|
|
1890
|
+
.text-section > :first-child {
|
|
1891
|
+
margin-top: 0;
|
|
1892
|
+
}
|
|
1893
|
+
.text-section > :last-child {
|
|
1894
|
+
margin-bottom: 0;
|
|
1895
|
+
}
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
--theme-title-leading: var(--type-display-small-line-height);
|
|
44
44
|
--theme-title-size-large: var(--type-display-medium-size);
|
|
45
45
|
}
|
|
46
|
-
@media (
|
|
46
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
47
47
|
:root {
|
|
48
48
|
--theme-title-leading: var(--type-display-medium-line-height);
|
|
49
49
|
}
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
.theme-logo-role {
|
|
88
88
|
display: var(--theme-logo-role-display);
|
|
89
89
|
}
|
|
90
|
-
@media (
|
|
90
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
91
91
|
.theme-logo-role {
|
|
92
92
|
display: var(--theme-logo-role-display-large);
|
|
93
93
|
}
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
/* The bar at the bottom of a phone's screen (a promotion: ActionBar.astro), a docked toolbar
|
|
110
110
|
(.toolbar-docked, ui.css) fixed there: the page gets room under its footer, and only the first bar on a page is
|
|
111
111
|
shown. data-hidden: moved down out of sight (while the buttons at the top of the front page are on screen, the script
|
|
112
|
-
in Base.astro). Not from
|
|
112
|
+
in Base.astro). Not from the medium width (a tablet in portrait, a computer). */
|
|
113
113
|
.theme-action-bar {
|
|
114
114
|
position: fixed;
|
|
115
115
|
inset: auto 0 0;
|
|
@@ -122,12 +122,12 @@
|
|
|
122
122
|
.theme-action-bar ~ .theme-action-bar {
|
|
123
123
|
display: none;
|
|
124
124
|
}
|
|
125
|
-
@media (width <
|
|
125
|
+
@media (width < theme(--breakpoint-medium)) {
|
|
126
126
|
body:has(.theme-action-bar) {
|
|
127
127
|
padding-bottom: 6rem;
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
-
@media (width >=
|
|
130
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
131
131
|
.theme-action-bar {
|
|
132
132
|
display: none;
|
|
133
133
|
}
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
|
|
166
166
|
@layer components {
|
|
167
167
|
/* With the bar of "Mobilmenu" under the header (MobileNav.astro), a link to a part of a page stops below both. */
|
|
168
|
-
@media (width <
|
|
168
|
+
@media (width < theme(--breakpoint-large)) {
|
|
169
169
|
html:has([data-mobile-nav]) {
|
|
170
170
|
scroll-padding-top: 9.25rem;
|
|
171
171
|
}
|
|
@@ -193,12 +193,12 @@
|
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
/* A page with a block beside its text (PageLayout.astro): the text, then the column (on a phone below the text); from
|
|
196
|
+
/* A page with a block beside its text (PageLayout.astro): the text, then the column (on a phone below the text); from medium
|
|
197
197
|
two columns, the second one staying in view while the text is read. */
|
|
198
198
|
.page-with-side > .page-side {
|
|
199
199
|
margin-top: 3rem;
|
|
200
200
|
}
|
|
201
|
-
@media (
|
|
201
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
202
202
|
.page-with-side {
|
|
203
203
|
display: grid;
|
|
204
204
|
grid-template-columns: minmax(0, 1fr) var(--theme-side-width);
|
|
@@ -220,7 +220,7 @@
|
|
|
220
220
|
font-weight: var(--type-display-small-weight);
|
|
221
221
|
letter-spacing: var(--type-display-small-tracking);
|
|
222
222
|
}
|
|
223
|
-
@media (
|
|
223
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
224
224
|
.theme-title {
|
|
225
225
|
font-size: var(--theme-title-size-large);
|
|
226
226
|
font-weight: var(--type-display-medium-weight);
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// Checks the tonal elevation tokens and rules of the base theme (spec: tonal elevation, Material 3).
|
|
2
|
+
// Reads theme/styles/ui.css (and later global.css) as text; no browser, no build.
|
|
3
|
+
import { test } from 'node:test';
|
|
4
|
+
import assert from 'node:assert/strict';
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
|
|
7
|
+
const read = (name) => readFileSync(new URL(name, import.meta.url), 'utf8');
|
|
8
|
+
const uiCss = read('./ui.css');
|
|
9
|
+
|
|
10
|
+
const count = (text, part) => text.split(part).length - 1;
|
|
11
|
+
|
|
12
|
+
// The level tokens: the exact default declaration of each, once in ui.css.
|
|
13
|
+
const tokens = {
|
|
14
|
+
'--elevation-0-surface': 'var(--bg)',
|
|
15
|
+
'--elevation-1-surface': 'var(--surface-container-low, var(--block-surface))',
|
|
16
|
+
'--elevation-2-surface': 'var(--surface-container, var(--block-surface))',
|
|
17
|
+
'--elevation-3-surface': 'var(--surface-container-high, var(--block-surface))',
|
|
18
|
+
'--elevation-4-surface': 'var(--surface-container-highest, var(--block-surface))',
|
|
19
|
+
'--elevation-5-surface': 'var(--surface-container-highest, var(--block-surface))',
|
|
20
|
+
'--elevation-1-rest-shadow': 'var(--elevation-1)',
|
|
21
|
+
'--elevation-2-rest-shadow': 'var(--elevation-2)',
|
|
22
|
+
'--elevation-3-rest-shadow': 'var(--elevation-3)',
|
|
23
|
+
'--elevation-4-rest-shadow': 'var(--elevation-4)',
|
|
24
|
+
'--elevation-5-rest-shadow': 'var(--elevation-5)',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
for (const [name, value] of Object.entries(tokens)) {
|
|
28
|
+
test(`ui.css declares ${name}`, () => {
|
|
29
|
+
assert.equal(count(uiCss, ` ${name}: ${value};\n`), 1);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Neutral parts: the resting surface reads the part's own variable, then its level's colour.
|
|
34
|
+
const surfaces = [
|
|
35
|
+
['elevated button', 'background: var(--button-elevated-surface, var(--elevation-1-surface));', 1],
|
|
36
|
+
['elevated chip', 'background: var(--chip-elevated-surface, var(--elevation-1-surface));', 1],
|
|
37
|
+
['elevated card', 'background: var(--card-elevated-surface, var(--elevation-1-surface));', 1],
|
|
38
|
+
['outlined card', 'background: var(--card-outlined-surface, var(--elevation-0-surface));', 1],
|
|
39
|
+
['dialog (also date and time picker)', 'background: var(--dialog-surface, var(--elevation-3-surface));', 1],
|
|
40
|
+
['date picker input label notch', '--text-field-label-surface: var(--dialog-surface, var(--elevation-3-surface));', 1],
|
|
41
|
+
['bottom sheet (container and cover)', 'background: var(--bottom-sheet-surface, var(--elevation-1-surface));', 2],
|
|
42
|
+
['standard side sheet', 'background: var(--side-sheet-surface, var(--elevation-0-surface));', 2],
|
|
43
|
+
['modal side sheet', 'background: var(--side-sheet-modal-surface, var(--side-sheet-surface, var(--elevation-1-surface)));', 2],
|
|
44
|
+
['scrolled top app bar', 'background: var(--top-app-bar-stuck-surface, var(--elevation-2-surface));', 1],
|
|
45
|
+
['menu, menu group and select list', 'background: var(--menu-surface, var(--elevation-2-surface));', 3],
|
|
46
|
+
['navigation drawer', 'background: var(--navigation-drawer-surface, var(--elevation-1-surface));', 1],
|
|
47
|
+
['rich tooltip', 'background: var(--tooltip-rich-surface, var(--elevation-2-surface));', 1],
|
|
48
|
+
['standard navigation rail', 'background: var(--navigation-rail-surface, var(--elevation-0-surface));', 1],
|
|
49
|
+
['modal navigation rail', 'background: var(--navigation-rail-modal-surface, var(--elevation-2-surface));', 1],
|
|
50
|
+
['search view', 'background: var(--search-view-surface, var(--elevation-3-surface));', 1],
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
for (const [part, line, times] of surfaces) {
|
|
54
|
+
test(`${part} reads its level's surface`, () => {
|
|
55
|
+
assert.equal(count(uiCss, line), times);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Parts that keep their surface: the top app bar at rest, and the role parts.
|
|
60
|
+
const unchanged = [
|
|
61
|
+
'background: var(--top-app-bar-surface, color-mix(in oklab, var(--bg) 85%, transparent));',
|
|
62
|
+
'background: var(--search-bar-surface, var(--block-surface));',
|
|
63
|
+
'background: var(--navigation-bar-surface, var(--block-surface));',
|
|
64
|
+
'background: var(--card-filled-surface, var(--block-tint));',
|
|
65
|
+
'background: var(--switch-handle-surface, var(--block-surface));',
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
for (const line of unchanged) {
|
|
69
|
+
test(`ui.css keeps ${line}`, () => {
|
|
70
|
+
assert.equal(count(uiCss, line), 1);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
test('no part reads the old surface fallbacks', () => {
|
|
75
|
+
assert.equal(count(uiCss, 'var(--menu-surface, var(--block-surface))'), 0);
|
|
76
|
+
assert.equal(count(uiCss, 'var(--dialog-surface, var(--block-surface))'), 0);
|
|
77
|
+
assert.equal(count(uiCss, 'var(--navigation-drawer-surface, var(--surface-container-low, var(--bg)))'), 0);
|
|
78
|
+
assert.equal(count(uiCss, 'var(--navigation-rail-surface, var(--block-surface))'), 0);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Resting shadows: the part's own variable first, then its level's rest-shadow token.
|
|
82
|
+
const restShadows = [
|
|
83
|
+
['elevated button', 'box-shadow: var(--button-elevated-shadow, var(--elevation-1-rest-shadow));', 2],
|
|
84
|
+
['elevated chip', 'box-shadow: var(--chip-elevated-shadow, var(--elevation-1-rest-shadow));', 2],
|
|
85
|
+
['elevated card', '--card-shadow: var(--card-elevated-shadow, var(--elevation-1-rest-shadow));', 1],
|
|
86
|
+
['modal side sheet (container and wide layout)', 'box-shadow: var(--side-sheet-shadow, var(--elevation-1-rest-shadow));', 2],
|
|
87
|
+
['bottom sheet', 'box-shadow: var(--bottom-sheet-shadow, var(--elevation-1-rest-shadow));', 1],
|
|
88
|
+
['bottom sheet as a dialog', 'box-shadow: var(--bottom-sheet-shadow-large, var(--elevation-3-rest-shadow));', 1],
|
|
89
|
+
['dialog (also date and time picker)', 'var(--dialog-shadow, var(--elevation-3-rest-shadow));', 1],
|
|
90
|
+
['docked date picker', 'var(--date-picker-docked-shadow, var(--dialog-shadow, var(--elevation-3-rest-shadow)));', 1],
|
|
91
|
+
['scrolled top app bar', 'box-shadow: var(--top-app-bar-stuck-shadow, var(--elevation-2-rest-shadow));', 1],
|
|
92
|
+
['modal navigation rail', 'box-shadow: var(--navigation-rail-modal-shadow, var(--elevation-2-rest-shadow));', 1],
|
|
93
|
+
['navigation drawer', 'box-shadow: var(--navigation-drawer-shadow, var(--elevation-1-rest-shadow));', 1],
|
|
94
|
+
['menu, menu group and select list', 'var(--menu-shadow, var(--elevation-2-rest-shadow));', 3],
|
|
95
|
+
['rich tooltip', 'var(--tooltip-rich-shadow, var(--elevation-2-rest-shadow));', 1],
|
|
96
|
+
['search view', 'var(--search-view-shadow, var(--elevation-3-rest-shadow));', 1],
|
|
97
|
+
['floating toolbar', 'var(--toolbar-floating-shadow, var(--elevation-3-rest-shadow));', 1],
|
|
98
|
+
['FAB and FAB menu', 'box-shadow: var(--fab-shadow, var(--elevation-3-rest-shadow));', 2],
|
|
99
|
+
['snackbar', 'box-shadow: var(--snackbar-shadow, var(--elevation-3-rest-shadow));', 1],
|
|
100
|
+
['switch handle', 'box-shadow: var(--switch-handle-shadow, var(--elevation-1-rest-shadow));', 1],
|
|
101
|
+
['slider handle (both directions)', 'box-shadow: var(--slider-handle-shadow, var(--elevation-1-rest-shadow));', 2],
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
for (const [part, line, times] of restShadows) {
|
|
105
|
+
test(`${part} reads its level's rest shadow`, () => {
|
|
106
|
+
assert.equal(count(uiCss, line), times);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// The lift stays on --elevation-N.
|
|
111
|
+
test('elevated card hover still reads --elevation-2', () => {
|
|
112
|
+
assert.equal(count(uiCss, '--card-shadow: var(--card-elevated-hover-shadow, var(--card-elevated-shadow, var(--elevation-2)));'), 1);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test('outlined card keeps --elevation-0', () => {
|
|
116
|
+
assert.equal(count(uiCss, '--card-shadow: var(--card-outlined-shadow, var(--elevation-0));'), 1);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// The Material theme (global.css): colour at rest, a shadow only for the FAB and the lift.
|
|
120
|
+
const globalCss = read('./global.css');
|
|
121
|
+
|
|
122
|
+
for (let level = 1; level <= 5; level++) {
|
|
123
|
+
test(`global.css sets --elevation-${level}-rest-shadow to no shadow`, () => {
|
|
124
|
+
assert.equal(count(globalCss, ` --elevation-${level}-rest-shadow: var(--elevation-0);\n`), 1);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const addedLines = [
|
|
129
|
+
['--fab-shadow: var(--elevation-3);', 1],
|
|
130
|
+
['--fab-hover-shadow: var(--elevation-4);', 1],
|
|
131
|
+
['--block-shadow: var(--elevation-1-rest-shadow);', 1],
|
|
132
|
+
// Light mode once, then the dark-mode media block and the dark theme attribute.
|
|
133
|
+
['--shadow: var(--elevation-1-rest-shadow);', 3],
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
for (const [line, times] of addedLines) {
|
|
137
|
+
test(`global.css has ${line} ${times} time(s)`, () => {
|
|
138
|
+
assert.equal(count(globalCss, line), times);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const removedDeclarations = [
|
|
143
|
+
'--button-elevated-surface',
|
|
144
|
+
'--card-elevated-surface',
|
|
145
|
+
'--side-sheet-surface',
|
|
146
|
+
'--side-sheet-modal-surface',
|
|
147
|
+
'--bottom-sheet-surface',
|
|
148
|
+
'--dialog-surface',
|
|
149
|
+
'--top-app-bar-stuck-surface',
|
|
150
|
+
'--top-app-bar-stuck-shadow',
|
|
151
|
+
'--navigation-rail-surface',
|
|
152
|
+
'--navigation-drawer-surface',
|
|
153
|
+
'--menu-surface',
|
|
154
|
+
'--tooltip-rich-surface',
|
|
155
|
+
'--search-view-surface',
|
|
156
|
+
'--switch-handle-shadow',
|
|
157
|
+
'--slider-handle-shadow',
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
for (const name of removedDeclarations) {
|
|
161
|
+
test(`global.css no longer declares ${name}`, () => {
|
|
162
|
+
assert.equal(count(globalCss, `${name}:`), 0);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
test('global.css keeps the extended FAB lines in the navigation drawer', () => {
|
|
167
|
+
assert.equal(count(globalCss, ' --fab-shadow: var(--elevation-1);\n --fab-hover-shadow: var(--elevation-2);\n'), 1);
|
|
168
|
+
});
|