@morphemecms/cms 0.7.0 → 0.8.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 +18 -0
- package/defaults/collections.ts +56 -0
- package/defaults/company.ts +13 -4
- package/defaults/texts.ts +17 -0
- package/icons/lucide/LICENSE-phosphor +21 -0
- package/icons/lucide/facebook-logo.svg +1 -0
- package/icons/lucide/linkedin-logo.svg +1 -0
- package/icons/lucide/pack.json +16 -1
- package/icons/lucide/pinterest-logo.svg +1 -0
- package/icons/lucide/x-logo.svg +1 -0
- package/icons/material-symbols/LICENSE-phosphor +21 -0
- package/icons/material-symbols/facebook-logo.svg +1 -0
- package/icons/material-symbols/linkedin-logo.svg +1 -0
- package/icons/material-symbols/pack.json +15 -0
- package/icons/material-symbols/pinterest-logo.svg +1 -0
- package/icons/material-symbols/x-logo.svg +1 -0
- package/icons/phosphor/facebook-logo.svg +1 -0
- package/icons/phosphor/linkedin-logo.svg +1 -0
- package/icons/phosphor/pinterest-logo.svg +1 -0
- package/icons/phosphor/x-logo.svg +1 -0
- package/lib/lead.d.mts +5 -0
- package/lib/lead.mjs +10 -0
- package/lib/lead.test.mjs +65 -0
- package/lib/licenses.mjs +1 -1
- package/package.json +2 -1
- package/scripts/icon-packs.mjs +51 -13
- package/scripts/material-fallback.test.mjs +49 -0
- package/site/icons.d.mts +13 -0
- package/site/icons.mjs +25 -3
- package/site/materialSymbols.d.mts +8 -2
- package/site/materialSymbols.mjs +27 -11
- package/site/materialSymbols.test.mjs +44 -0
- package/site/schema.ts +2 -0
- package/site/site.ts +9 -2
- package/site/social.d.mts +37 -0
- package/site/social.mjs +92 -0
- package/site/social.test.mjs +80 -0
- package/site/theme.d.mts +2 -0
- package/site/theme.mjs +28 -11
- package/site/themeImport.test.mjs +40 -0
- package/src/EntryForm.tsx +21 -58
- package/src/FormFrame.tsx +5 -5
- package/src/Parts.tsx +8 -30
- package/src/Screen.tsx +12 -5
- package/src/editor.css +70 -5
- package/src/i18n/da-DK/parts.ts +1 -1
- package/src/i18n/da-DK/theme.ts +4 -0
- package/src/i18n/en-US/parts.ts +1 -1
- package/src/i18n/en-US/theme.ts +4 -0
- package/src/icon.tsx +1 -1
- package/src/materialIcons.ts +5 -7
- package/src/pagePreview.tsx +21 -1
- package/src/postLead.d.mts +7 -0
- package/src/postLead.mjs +9 -0
- package/src/postLead.test.mjs +28 -0
- package/src/ui.tsx +41 -96
- package/src/virtual.d.ts +5 -0
- package/starter/package.json +1 -1
- package/starter/src/data/social.json +14 -0
- package/theme/components/PostAuthor.astro +20 -0
- package/theme/components/PostCard.tsx +26 -0
- package/theme/components/PostHeader.astro +36 -0
- package/theme/components/PostMeta.tsx +27 -2
- package/theme/components/RelatedPosts.astro +29 -0
- package/theme/components/ShareRow.astro +48 -0
- package/theme/layouts/PostLayout.astro +28 -54
- package/theme/styles/base.css +164 -127
- package/theme/styles/blocks.css +160 -155
- package/theme/styles/components.css +43 -34
- package/theme/styles/global.css +316 -303
- package/theme/styles/ui.css +43 -34
- package/theme/ui/copyLink.script.ts +17 -0
package/theme/styles/base.css
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
@import 'tailwindcss';
|
|
2
2
|
@plugin '@tailwindcss/typography';
|
|
3
|
+
/* Material's rules sit in the last layer, fallback: a theme's own unlayered rules beat them, whatever their specificity. */
|
|
4
|
+
@layer theme, base, components, utilities, fallback;
|
|
3
5
|
/* The theme's UI components, as Material 3 names them (buttons, icon buttons), and the standard blocks of the editor,
|
|
4
6
|
in this site's design (their variables below). */
|
|
5
7
|
@import './ui.css';
|
|
@@ -8,6 +10,9 @@
|
|
|
8
10
|
@import './components.css';
|
|
9
11
|
|
|
10
12
|
/*
|
|
13
|
+
Material is every theme's fallback: its rules that set more than custom properties sit in @layer fallback (declared last in
|
|
14
|
+
base.css), so a theme's own unlayered rules win over them, whatever the specificity. Custom properties stay unlayered.
|
|
15
|
+
|
|
11
16
|
The standard theme's base: what every theme builds on, plain and neutral. The system's own font, a small radius on
|
|
12
17
|
panels, a light shadow, full pills on controls; the classes the standard theme's components use (.link, .prose,
|
|
13
18
|
the motion …) besides the UI components (ui.css: buttons, icon buttons, chips, snackbars). The standard theme's own look is over it, in global.css; a theme with a look of its
|
|
@@ -31,7 +36,6 @@
|
|
|
31
36
|
--shadow: 0 1px 2px rgb(0 0 0 / 0.06), 0 8px 24px -12px rgb(0 0 0 / 0.18);
|
|
32
37
|
/* The motion scheme's curve (blocks.css, lib/motion.ts). */
|
|
33
38
|
--ease: var(--motion-ease, cubic-bezier(0.2, 0, 0, 1));
|
|
34
|
-
color-scheme: light;
|
|
35
39
|
|
|
36
40
|
/* The standard blocks (blocks.css) in this design; in dark mode too, as they
|
|
37
41
|
follow the tokens above. */
|
|
@@ -53,17 +57,34 @@
|
|
|
53
57
|
/* The same for a chip set that scrolls (ui.css). */
|
|
54
58
|
--chip-set-bleed: 1.25rem;
|
|
55
59
|
}
|
|
60
|
+
@layer fallback {
|
|
61
|
+
:root {
|
|
62
|
+
color-scheme: light;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
56
65
|
|
|
57
66
|
@media (prefers-color-scheme: dark) {
|
|
58
67
|
:root:not([data-theme='light']) {
|
|
59
68
|
--shadow: 0 1px 2px rgb(0 0 0 / 0.3), 0 20px 40px -24px rgb(0 0 0 / 0.7);
|
|
60
|
-
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@layer fallback {
|
|
73
|
+
@media (prefers-color-scheme: dark) {
|
|
74
|
+
:root:not([data-theme='light']) {
|
|
75
|
+
color-scheme: dark;
|
|
76
|
+
}
|
|
61
77
|
}
|
|
62
78
|
}
|
|
63
79
|
|
|
64
80
|
:root[data-theme='dark'] {
|
|
65
81
|
--shadow: 0 1px 2px rgb(0 0 0 / 0.3), 0 20px 40px -24px rgb(0 0 0 / 0.7);
|
|
66
|
-
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@layer fallback {
|
|
85
|
+
:root[data-theme='dark'] {
|
|
86
|
+
color-scheme: dark;
|
|
87
|
+
}
|
|
67
88
|
}
|
|
68
89
|
|
|
69
90
|
@theme inline {
|
|
@@ -176,152 +197,168 @@
|
|
|
176
197
|
--tw-prose-th-borders: var(--line);
|
|
177
198
|
--tw-prose-td-borders: var(--line);
|
|
178
199
|
--tw-prose-code: var(--ink);
|
|
179
|
-
font-size: var(--type-body-large-size);
|
|
180
|
-
line-height: var(--type-body-large-line-height);
|
|
181
|
-
font-weight: var(--type-body-large-weight);
|
|
182
|
-
letter-spacing: var(--type-body-large-tracking);
|
|
183
|
-
}
|
|
184
|
-
/* The text's headings: a headline, a title under it and a smaller title under that (the type scale, ui.css). */
|
|
185
|
-
.prose :where(h2) {
|
|
186
|
-
font-size: var(--type-headline-medium-size);
|
|
187
|
-
line-height: var(--type-headline-medium-line-height);
|
|
188
|
-
font-weight: var(--type-headline-medium-weight);
|
|
189
|
-
letter-spacing: var(--type-headline-medium-tracking);
|
|
190
|
-
}
|
|
191
|
-
.prose :where(h3) {
|
|
192
|
-
font-size: var(--type-title-large-size);
|
|
193
|
-
line-height: var(--type-title-large-line-height);
|
|
194
|
-
font-weight: var(--type-title-large-weight);
|
|
195
|
-
letter-spacing: var(--type-title-large-tracking);
|
|
196
|
-
}
|
|
197
|
-
.prose :where(h4) {
|
|
198
|
-
font-size: var(--type-title-medium-size);
|
|
199
|
-
line-height: var(--type-title-medium-line-height);
|
|
200
|
-
font-weight: var(--type-title-medium-weight);
|
|
201
|
-
letter-spacing: var(--type-title-medium-tracking);
|
|
202
|
-
}
|
|
203
|
-
/* Code in a line (cookie names in the privacy policy): on a tint, without the plugin's backticks. */
|
|
204
|
-
.prose :where(:not(pre) > code):not(:where(.not-prose code)) {
|
|
205
|
-
background: var(--tint);
|
|
206
|
-
border-radius: 0.3em;
|
|
207
|
-
padding: 0.1em 0.35em;
|
|
208
|
-
font-weight: 500;
|
|
209
200
|
}
|
|
210
|
-
|
|
211
|
-
.prose
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
text-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
201
|
+
@layer fallback {
|
|
202
|
+
.prose {
|
|
203
|
+
font-size: var(--type-body-large-size);
|
|
204
|
+
line-height: var(--type-body-large-line-height);
|
|
205
|
+
font-weight: var(--type-body-large-weight);
|
|
206
|
+
letter-spacing: var(--type-body-large-tracking);
|
|
207
|
+
}
|
|
208
|
+
/* A blog post's lead: its first paragraph, one step larger than the text (the title-large size, with the body weight). */
|
|
209
|
+
.prose.post-lead {
|
|
210
|
+
font-size: var(--type-title-large-size);
|
|
211
|
+
line-height: var(--type-title-large-line-height);
|
|
212
|
+
font-weight: var(--type-body-large-weight);
|
|
213
|
+
letter-spacing: var(--type-title-large-tracking);
|
|
214
|
+
}
|
|
215
|
+
/* The text right after the lead (no picture between): the space the prose puts between paragraphs (1.25em), not the
|
|
216
|
+
larger space of a text under a picture. Unlayered on purpose: it must beat the mt-10 / medium:mt-14 utilities (a layer). */
|
|
217
|
+
.prose.post-lead + .prose {
|
|
218
|
+
margin-top: 1.25em;
|
|
219
|
+
}
|
|
220
|
+
/* The text's headings: a headline, a title under it and a smaller title under that (the type scale, ui.css). */
|
|
221
|
+
.prose :where(h2) {
|
|
222
|
+
font-size: var(--type-headline-medium-size);
|
|
223
|
+
line-height: var(--type-headline-medium-line-height);
|
|
224
|
+
font-weight: var(--type-headline-medium-weight);
|
|
225
|
+
letter-spacing: var(--type-headline-medium-tracking);
|
|
226
|
+
}
|
|
227
|
+
.prose :where(h3) {
|
|
228
|
+
font-size: var(--type-title-large-size);
|
|
229
|
+
line-height: var(--type-title-large-line-height);
|
|
230
|
+
font-weight: var(--type-title-large-weight);
|
|
231
|
+
letter-spacing: var(--type-title-large-tracking);
|
|
232
|
+
}
|
|
233
|
+
.prose :where(h4) {
|
|
234
|
+
font-size: var(--type-title-medium-size);
|
|
235
|
+
line-height: var(--type-title-medium-line-height);
|
|
236
|
+
font-weight: var(--type-title-medium-weight);
|
|
237
|
+
letter-spacing: var(--type-title-medium-tracking);
|
|
238
|
+
}
|
|
239
|
+
/* Code in a line (cookie names in the privacy policy): on a tint, without the plugin's backticks. */
|
|
240
|
+
.prose :where(:not(pre) > code):not(:where(.not-prose code)) {
|
|
241
|
+
background: var(--tint);
|
|
242
|
+
border-radius: 0.3em;
|
|
243
|
+
padding: 0.1em 0.35em;
|
|
244
|
+
font-weight: 500;
|
|
245
|
+
}
|
|
246
|
+
.prose :where(:not(pre) > code):not(:where(.not-prose code))::before,
|
|
247
|
+
.prose :where(:not(pre) > code):not(:where(.not-prose code))::after {
|
|
248
|
+
content: none;
|
|
249
|
+
}
|
|
250
|
+
/* Not the links of a block in the text (not-prose): their look is the block's. */
|
|
251
|
+
.prose :where(a):not(:where(.not-prose a)) {
|
|
252
|
+
font-weight: 500;
|
|
253
|
+
text-decoration-thickness: 1px;
|
|
254
|
+
text-underline-offset: 0.2em;
|
|
255
|
+
}
|
|
256
|
+
/* Pictures in the text; not those in a block of the site in it (not-prose, RichText.astro). */
|
|
257
|
+
.prose :where(img):not(:where(.not-prose img)) {
|
|
258
|
+
border-radius: var(--radius);
|
|
259
|
+
width: 100%;
|
|
260
|
+
height: auto;
|
|
261
|
+
}
|
|
262
|
+
/* A picture in the text cut to a format in the editor (packages/editor/lib/crop.mjs): the box is the format, the
|
|
227
263
|
picture in it as large and as far moved as the part chosen. */
|
|
228
|
-
.picture-crop {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
.picture-crop > img {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
/* Video embeds (an embed that needs another size, an app's calendar, sets its own). */
|
|
244
|
-
.prose :where(iframe) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
264
|
+
.picture-crop {
|
|
265
|
+
display: block;
|
|
266
|
+
position: relative;
|
|
267
|
+
overflow: hidden;
|
|
268
|
+
border-radius: var(--radius);
|
|
269
|
+
margin-block: 2em;
|
|
270
|
+
}
|
|
271
|
+
.picture-crop > img {
|
|
272
|
+
position: absolute;
|
|
273
|
+
inset: 0 auto auto 0;
|
|
274
|
+
max-width: none;
|
|
275
|
+
height: auto;
|
|
276
|
+
margin: 0;
|
|
277
|
+
border-radius: 0;
|
|
278
|
+
}
|
|
279
|
+
/* Video embeds (an embed that needs another size, an app's calendar, sets its own). */
|
|
280
|
+
.prose :where(iframe) {
|
|
281
|
+
width: 100%;
|
|
282
|
+
aspect-ratio: 16 / 9;
|
|
283
|
+
height: auto;
|
|
284
|
+
border: 0;
|
|
285
|
+
border-radius: var(--radius);
|
|
286
|
+
margin-block: 2em;
|
|
287
|
+
}
|
|
252
288
|
|
|
253
|
-
/* Motion.
|
|
289
|
+
/* Motion.
|
|
254
290
|
[data-reveal]: sections fade up once when scrolled into view (packages/editor/theme/scripts/motion.ts).
|
|
255
291
|
The top of a page stands still from the first paint; from another page of the site it fades in (components.css).
|
|
256
292
|
Off for visitors who prefer reduced motion, and with the calm motion scheme ("Bevægelse", data-motion-scheme). */
|
|
257
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
258
|
-
|
|
259
|
-
|
|
293
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
294
|
+
.js:not([data-motion-scheme='calm']) [data-reveal] {
|
|
295
|
+
opacity: 0;
|
|
296
|
+
}
|
|
260
297
|
}
|
|
261
|
-
}
|
|
262
298
|
|
|
263
|
-
/* The site's logo (public/logo.svg), colored by background-color via a mask. */
|
|
264
|
-
.logo-mark {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
299
|
+
/* The site's logo (public/logo.svg), colored by background-color via a mask. */
|
|
300
|
+
.logo-mark {
|
|
301
|
+
display: inline-block;
|
|
302
|
+
-webkit-mask: url('/logo.svg') center / contain no-repeat;
|
|
303
|
+
mask: url('/logo.svg') center / contain no-repeat;
|
|
304
|
+
}
|
|
269
305
|
|
|
270
|
-
/* A block the theme places outside the text (Block.astro in EndBlock.astro and on the prices page): its
|
|
306
|
+
/* A block the theme places outside the text (Block.astro in EndBlock.astro and on the prices page): its
|
|
271
307
|
place gives the space around it, not the text's (.block-in-text). */
|
|
272
|
-
.block-place > .block-in-text {
|
|
273
|
-
|
|
274
|
-
}
|
|
275
|
-
/* The heading of a block placed outside the text (a front-page section): as the theme's other section headings
|
|
308
|
+
.block-place > .block-in-text {
|
|
309
|
+
margin-block: 0;
|
|
310
|
+
}
|
|
311
|
+
/* The heading of a block placed outside the text (a front-page section): as the theme's other section headings
|
|
276
312
|
(SectionHeading.tsx), not the text's; with a label or a subheading (.block-head, blocks.css) the space under the
|
|
277
313
|
whole head. */
|
|
278
|
-
.block-place > h2,
|
|
279
|
-
.block-place > .block-head {
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
.block-place > h2,
|
|
283
|
-
.block-place > .block-head > h2 {
|
|
284
|
-
font-size: var(--type-headline-large-size);
|
|
285
|
-
line-height: var(--type-headline-large-line-height);
|
|
286
|
-
font-weight: var(--type-headline-large-weight);
|
|
287
|
-
letter-spacing: var(--type-headline-large-tracking);
|
|
288
|
-
}
|
|
289
|
-
@media (width >= theme(--breakpoint-medium)) {
|
|
314
|
+
.block-place > h2,
|
|
315
|
+
.block-place > .block-head {
|
|
316
|
+
margin-block: 0 2rem;
|
|
317
|
+
}
|
|
290
318
|
.block-place > h2,
|
|
291
319
|
.block-place > .block-head > h2 {
|
|
292
|
-
font-size: var(--type-
|
|
293
|
-
line-height: var(--type-
|
|
294
|
-
font-weight: var(--type-
|
|
295
|
-
letter-spacing: var(--type-
|
|
320
|
+
font-size: var(--type-headline-large-size);
|
|
321
|
+
line-height: var(--type-headline-large-line-height);
|
|
322
|
+
font-weight: var(--type-headline-large-weight);
|
|
323
|
+
letter-spacing: var(--type-headline-large-tracking);
|
|
296
324
|
}
|
|
297
|
-
|
|
298
|
-
|
|
325
|
+
@media (width >= theme(--breakpoint-medium)) {
|
|
326
|
+
.block-place > h2,
|
|
327
|
+
.block-place > .block-head > h2 {
|
|
328
|
+
font-size: var(--type-display-medium-size);
|
|
329
|
+
line-height: var(--type-display-medium-line-height);
|
|
330
|
+
font-weight: var(--type-display-medium-weight);
|
|
331
|
+
letter-spacing: var(--type-display-medium-tracking);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/* Cards placed in the page's full width (a front-page section, PageBlock.astro): three in a row on a computer, as
|
|
299
335
|
there is room for (in the text, two). */
|
|
300
|
-
@media (width >= theme(--breakpoint-expanded)) {
|
|
301
|
-
|
|
302
|
-
|
|
336
|
+
@media (width >= theme(--breakpoint-expanded)) {
|
|
337
|
+
.block-place .block-cards {
|
|
338
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
339
|
+
}
|
|
303
340
|
}
|
|
304
|
-
}
|
|
305
341
|
|
|
306
|
-
/* The mark before the name on a testimonial (the standard block's card): a small dot in the accent, which the standard
|
|
342
|
+
/* The mark before the name on a testimonial (the standard block's card): a small dot in the accent, which the standard
|
|
307
343
|
theme's own look (global.css) makes an avatar with the initial. Another mark (e.g. a logo) is that
|
|
308
344
|
theme's own (its global.css), not the standard theme's. */
|
|
309
|
-
.block-testimonial-mark {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
345
|
+
.block-testimonial-mark {
|
|
346
|
+
display: inline-block;
|
|
347
|
+
flex-shrink: 0;
|
|
348
|
+
width: 0.5rem;
|
|
349
|
+
height: 0.5rem;
|
|
350
|
+
border-radius: 9999px;
|
|
351
|
+
background-color: var(--accent);
|
|
352
|
+
}
|
|
317
353
|
|
|
318
|
-
/* Boxes side by side ("Links", an app's boxes): the site's panels (outlined cards, ui.css, without a shadow), with
|
|
354
|
+
/* Boxes side by side ("Links", an app's boxes): the site's panels (outlined cards, ui.css, without a shadow), with
|
|
319
355
|
more room on a computer and the heading of a section in it. */
|
|
320
|
-
.block-panels .block-panel-title {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
356
|
+
.block-panels .block-panel-title {
|
|
357
|
+
font-size: var(--type-headline-small-size);
|
|
358
|
+
line-height: var(--type-headline-small-line-height);
|
|
359
|
+
font-weight: var(--type-headline-small-weight);
|
|
360
|
+
letter-spacing: var(--type-headline-small-tracking);
|
|
361
|
+
}
|
|
325
362
|
}
|
|
326
363
|
@media (width >= theme(--breakpoint-medium)) {
|
|
327
364
|
.block-panels > .block-panel {
|