@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.
Files changed (72) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/defaults/collections.ts +56 -0
  3. package/defaults/company.ts +13 -4
  4. package/defaults/texts.ts +17 -0
  5. package/icons/lucide/LICENSE-phosphor +21 -0
  6. package/icons/lucide/facebook-logo.svg +1 -0
  7. package/icons/lucide/linkedin-logo.svg +1 -0
  8. package/icons/lucide/pack.json +16 -1
  9. package/icons/lucide/pinterest-logo.svg +1 -0
  10. package/icons/lucide/x-logo.svg +1 -0
  11. package/icons/material-symbols/LICENSE-phosphor +21 -0
  12. package/icons/material-symbols/facebook-logo.svg +1 -0
  13. package/icons/material-symbols/linkedin-logo.svg +1 -0
  14. package/icons/material-symbols/pack.json +15 -0
  15. package/icons/material-symbols/pinterest-logo.svg +1 -0
  16. package/icons/material-symbols/x-logo.svg +1 -0
  17. package/icons/phosphor/facebook-logo.svg +1 -0
  18. package/icons/phosphor/linkedin-logo.svg +1 -0
  19. package/icons/phosphor/pinterest-logo.svg +1 -0
  20. package/icons/phosphor/x-logo.svg +1 -0
  21. package/lib/lead.d.mts +5 -0
  22. package/lib/lead.mjs +10 -0
  23. package/lib/lead.test.mjs +65 -0
  24. package/lib/licenses.mjs +1 -1
  25. package/package.json +2 -1
  26. package/scripts/icon-packs.mjs +51 -13
  27. package/scripts/material-fallback.test.mjs +49 -0
  28. package/site/icons.d.mts +13 -0
  29. package/site/icons.mjs +25 -3
  30. package/site/materialSymbols.d.mts +8 -2
  31. package/site/materialSymbols.mjs +27 -11
  32. package/site/materialSymbols.test.mjs +44 -0
  33. package/site/schema.ts +2 -0
  34. package/site/site.ts +9 -2
  35. package/site/social.d.mts +37 -0
  36. package/site/social.mjs +92 -0
  37. package/site/social.test.mjs +80 -0
  38. package/site/theme.d.mts +2 -0
  39. package/site/theme.mjs +28 -11
  40. package/site/themeImport.test.mjs +40 -0
  41. package/src/EntryForm.tsx +21 -58
  42. package/src/FormFrame.tsx +5 -5
  43. package/src/Parts.tsx +8 -30
  44. package/src/Screen.tsx +12 -5
  45. package/src/editor.css +70 -5
  46. package/src/i18n/da-DK/parts.ts +1 -1
  47. package/src/i18n/da-DK/theme.ts +4 -0
  48. package/src/i18n/en-US/parts.ts +1 -1
  49. package/src/i18n/en-US/theme.ts +4 -0
  50. package/src/icon.tsx +1 -1
  51. package/src/materialIcons.ts +5 -7
  52. package/src/pagePreview.tsx +21 -1
  53. package/src/postLead.d.mts +7 -0
  54. package/src/postLead.mjs +9 -0
  55. package/src/postLead.test.mjs +28 -0
  56. package/src/ui.tsx +41 -96
  57. package/src/virtual.d.ts +5 -0
  58. package/starter/package.json +1 -1
  59. package/starter/src/data/social.json +14 -0
  60. package/theme/components/PostAuthor.astro +20 -0
  61. package/theme/components/PostCard.tsx +26 -0
  62. package/theme/components/PostHeader.astro +36 -0
  63. package/theme/components/PostMeta.tsx +27 -2
  64. package/theme/components/RelatedPosts.astro +29 -0
  65. package/theme/components/ShareRow.astro +48 -0
  66. package/theme/layouts/PostLayout.astro +28 -54
  67. package/theme/styles/base.css +164 -127
  68. package/theme/styles/blocks.css +160 -155
  69. package/theme/styles/components.css +43 -34
  70. package/theme/styles/global.css +316 -303
  71. package/theme/styles/ui.css +43 -34
  72. package/theme/ui/copyLink.script.ts +17 -0
@@ -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
- color-scheme: dark;
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
- color-scheme: dark;
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
- .prose :where(:not(pre) > code):not(:where(.not-prose code))::before,
211
- .prose :where(:not(pre) > code):not(:where(.not-prose code))::after {
212
- content: none;
213
- }
214
- /* Not the links of a block in the text (not-prose): their look is the block's. */
215
- .prose :where(a):not(:where(.not-prose a)) {
216
- font-weight: 500;
217
- text-decoration-thickness: 1px;
218
- text-underline-offset: 0.2em;
219
- }
220
- /* Pictures in the text; not those in a block of the site in it (not-prose, RichText.astro). */
221
- .prose :where(img):not(:where(.not-prose img)) {
222
- border-radius: var(--radius);
223
- width: 100%;
224
- height: auto;
225
- }
226
- /* A picture in the text cut to a format in the editor (packages/editor/lib/crop.mjs): the box is the format, the
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
- display: block;
230
- position: relative;
231
- overflow: hidden;
232
- border-radius: var(--radius);
233
- margin-block: 2em;
234
- }
235
- .picture-crop > img {
236
- position: absolute;
237
- inset: 0 auto auto 0;
238
- max-width: none;
239
- height: auto;
240
- margin: 0;
241
- border-radius: 0;
242
- }
243
- /* Video embeds (an embed that needs another size, an app's calendar, sets its own). */
244
- .prose :where(iframe) {
245
- width: 100%;
246
- aspect-ratio: 16 / 9;
247
- height: auto;
248
- border: 0;
249
- border-radius: var(--radius);
250
- margin-block: 2em;
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
- .js:not([data-motion-scheme='calm']) [data-reveal] {
259
- opacity: 0;
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
- display: inline-block;
266
- -webkit-mask: url('/logo.svg') center / contain no-repeat;
267
- mask: url('/logo.svg') center / contain no-repeat;
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
- margin-block: 0;
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
- margin-block: 0 2rem;
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-display-medium-size);
293
- line-height: var(--type-display-medium-line-height);
294
- font-weight: var(--type-display-medium-weight);
295
- letter-spacing: var(--type-display-medium-tracking);
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
- /* Cards placed in the page's full width (a front-page section, PageBlock.astro): three in a row on a computer, as
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
- .block-place .block-cards {
302
- grid-template-columns: repeat(3, minmax(0, 1fr));
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
- display: inline-block;
311
- flex-shrink: 0;
312
- width: 0.5rem;
313
- height: 0.5rem;
314
- border-radius: 9999px;
315
- background-color: var(--accent);
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
- font-size: var(--type-headline-small-size);
322
- line-height: var(--type-headline-small-line-height);
323
- font-weight: var(--type-headline-small-weight);
324
- letter-spacing: var(--type-headline-small-tracking);
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 {