kmcom-nuxt-layers 2.6.2 → 2.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/docs/ARCHITECTURE.md +21 -17
- package/docs/FEEDS.md +42 -34
- package/docs/IMPROVE-AUDIT-README.md +9 -10
- package/docs/IMPROVE-AUDIT-RESULTS.md +16 -17
- package/docs/IMPROVE-DEEP-AUDIT-RESULTS.md +29 -29
- package/docs/LAYERS-FIXES.md +1 -0
- package/docs/LAYOUT.md +91 -86
- package/docs/MIGRATION.md +93 -60
- package/docs/UPAGE-GRID-INTEGRATION.md +12 -10
- package/docs/USAGE.md +29 -38
- package/layers/animations/app/utils/pointerMotion.ts +1 -4
- package/layers/baseline/app/components/BaselineStatus.vue +13 -13
- package/layers/baseline/app/plugins/baseline-status.client.ts +4 -1
- package/layers/canvas/app/composables/useRendererCapabilities.ts +2 -2
- package/layers/content/app/components/Blog/Card.vue +1 -0
- package/layers/content/app/components/Gallery/Card.vue +1 -1
- package/layers/content/app/components/Gallery/Detail.vue +8 -1
- package/layers/content/app/components/Portfolio/Card.vue +1 -0
- package/layers/content/app/components/Portfolio/ColorPalette.vue +8 -1
- package/layers/content/app/components/Portfolio/Typography.vue +12 -2
- package/layers/content/app/composables/useGalleryItems.ts +3 -2
- package/layers/content/app/composables/usePortfolioItems.ts +3 -2
- package/layers/core/app/components/DiagnosticsPage.vue +15 -3
- package/layers/core/app/utils/featureClasses.test.ts +1 -3
- package/layers/core/app/utils/featureClasses.ts +1 -3
- package/layers/core/app/utils/helpers.test.ts +6 -2
- package/layers/core/nuxt.config.ts +2 -0
- package/layers/feeds/app/assets/css/feeds.css +3 -2
- package/layers/feeds/app/components/Feeds/Index.vue +36 -6
- package/layers/feeds/app/components/Feeds/RouteCard.vue +1 -3
- package/layers/feeds/app/plugins/feed-head.ts +2 -2
- package/layers/feeds/package.json +1 -1
- package/layers/feeds/public/feed/style.css +9 -9
- package/layers/feeds/server/utils/content-adapter.test.ts +3 -4
- package/layers/feeds/server/utils/content-adapter.ts +1 -1
- package/layers/feeds/server/utils/feed-author.test.ts +3 -3
- package/layers/feeds/server/utils/feed-config.test.ts +28 -6
- package/layers/feeds/server/utils/feed-config.ts +1 -4
- package/layers/feeds/server/utils/feed-service.ts +1 -1
- package/layers/feeds/server/utils/formats/rss.ts +1 -1
- package/layers/feeds/server/utils/formats.test.ts +1 -1
- package/layers/forms/app/utils/fieldProps.ts +1 -2
- package/layers/forms/server/api/contact.post.ts +4 -1
- package/layers/layout/app/assets/css/layout/grids.css +12 -3
- package/layers/layout/app/assets/css/layout/modes/fluid.css +9 -0
- package/layers/layout/app/components/Layout/Section/Sidebar.vue +11 -4
- package/layers/layout/app/utils/gridPlacementStyle.test.ts +3 -9
- package/layers/layout/app/utils/gridPlacementStyle.ts +10 -7
- package/layers/mailer/server/utils/email.ts +4 -3
- package/layers/mailer/server/utils/hooks.ts +1 -1
- package/layers/metadata/app/composables/useMetadataItem.ts +6 -2
- package/layers/metadata/app/composables/useMetadataSearch.ts +6 -2
- package/layers/metadata/providers/comicvine/server/utils/metadata-comicvine/client.ts +5 -5
- package/layers/metadata/providers/comicvine/server/utils/metadata-comicvine/provider.ts +11 -3
- package/layers/metadata/providers/google-books/server/utils/metadata-google-books/client.ts +9 -6
- package/layers/metadata/providers/google-books/server/utils/metadata-google-books/provider.ts +6 -3
- package/layers/metadata/providers/openlibrary/server/utils/metadata-openlibrary/normalise.test.ts +3 -1
- package/layers/metadata/providers/openlibrary/server/utils/metadata-openlibrary/provider.ts +4 -2
- package/layers/metadata/providers/themoviedb/server/utils/metadata-tmdb/client.test.ts +1 -3
- package/layers/metadata/providers/themoviedb/server/utils/metadata-tmdb/provider.ts +3 -1
- package/layers/metadata/server/api/metadata/status.get.ts +13 -18
- package/layers/metadata/server/utils/metadata/provider-registry.test.ts +1 -1
- package/layers/metadata/server/utils/metadata/search.test.ts +18 -18
- package/layers/metadata/server/utils/metadata/search.ts +16 -8
- package/layers/navigation/app/utils/site.test.ts +1 -3
- package/layers/scroll/app/components/Motion/PinnedSection.vue +11 -1
- package/layers/scroll/app/composables/useSectionProgress.ts +1 -1
- package/layers/scroll/app/plugins/locomotive-scroll.client.ts +6 -0
- package/layers/scroll/app/utils/scroll.ts +5 -1
- package/layers/seo/app/utils/seoConfig.test.ts +1 -1
- package/layers/shader/app/assets/css/shader.css +1 -1
- package/layers/shader/app/components/Material/AmbientAurora.client.vue +16 -4
- package/layers/shader/app/components/Material/AmbientFlow.client.vue +21 -5
- package/layers/shader/app/components/Material/AmbientGradientMesh.client.vue +21 -5
- package/layers/shader/app/components/Material/AmbientNebula.client.vue +21 -5
- package/layers/shader/app/components/Material/AmbientOcean.client.vue +16 -4
- package/layers/shader/app/components/Material/Gradient.client.vue +1 -1
- package/layers/shader/app/components/Material/Image.client.vue +1 -1
- package/layers/shader/app/components/Material/Noise.client.vue +11 -3
- package/layers/shader/app/composables/useAmbientMaterials.ts +0 -1
- package/layers/shader/app/shaders/common/blend.ts +5 -1
- package/layers/shader/app/shaders/common/grain.ts +5 -1
- package/layers/shader/app/shaders/common/lighting.ts +1 -6
- package/layers/shader/app/shaders/common/noise.ts +3 -1
- package/layers/shader/app/shaders/common/patterns.ts +1 -1
- package/layers/shader/app/shaders/common/shapes.ts +5 -1
- package/layers/shader/app/shaders/common/uv.ts +19 -2
- package/layers/shader/app/shaders/createMaterial.ts +11 -6
- package/layers/shader/app/shaders/layers/shaderGradient.ts +2 -12
- package/layers/shader/app/shaders/types.ts +1 -1
- package/layers/shader/app/types/uniforms.ts +1 -0
- package/layers/shader/app/utils/tsl/animation.ts +34 -36
- package/layers/starter/app/components/StarterDesignSystem.vue +120 -120
- package/layers/starter/app/components/StarterHome.vue +233 -208
- package/layers/theme/app/assets/css/theme.css +1 -1
- package/layers/theme/server/utils/accent-css.test.ts +17 -2
- package/layers/theme/server/utils/fouc-config.test.ts +7 -3
- package/layers/theme/server/utils/fouc-config.ts +24 -12
- package/layers/transitions/app/assets/css/transitions.css +6 -0
- package/layers/typography/app/assets/css/typography.css +313 -0
- package/layers/typography/app/components/Typography/Headline.vue +23 -14
- package/layers/typography/app/components/Typography/HeadlineScreen.vue +5 -12
- package/layers/typography/app/components/Typography/index.vue +4 -0
- package/layers/typography/app/composables/typography.ts +45 -5
- package/layers/typography/app/types/typography.ts +36 -7
- package/layers/typography/nuxt.config.ts +2 -0
- package/layers/visual/app/app.config.ts +1 -1
- package/layers/visual/app/assets/css/visual.css +1 -1
- package/layers/visual/app/composables/accent.ts +1 -2
- package/layers/visual/app/composables/tint.ts +1 -2
- package/layers/visual/app/types/media.ts +2 -2
- package/layers/visual/app/utils/gradientStyle.test.ts +1 -2
- package/layers/visual/app/utils/responsiveSizes.ts +0 -1
- package/package.json +36 -16
package/docs/LAYOUT.md
CHANGED
|
@@ -51,7 +51,7 @@ The layout layer requires a dedicated Nuxt layout file and page-level layout dec
|
|
|
51
51
|
|
|
52
52
|
```vue
|
|
53
53
|
<script setup lang="ts">
|
|
54
|
-
definePageMeta({ layout: 'grid' })
|
|
54
|
+
definePageMeta({ layout: 'grid' })
|
|
55
55
|
</script>
|
|
56
56
|
```
|
|
57
57
|
|
|
@@ -65,11 +65,11 @@ definePageMeta({ layout: 'grid' })
|
|
|
65
65
|
|
|
66
66
|
The grid has three modes controlled via `app.config.ts`:
|
|
67
67
|
|
|
68
|
-
| Mode
|
|
69
|
-
|
|
70
|
-
| `'swiss'`
|
|
71
|
-
| `'fluid'`
|
|
72
|
-
| `'disabled'` | `LayoutMain` renders a plain `<main>` without grid CSS.
|
|
68
|
+
| Mode | Behaviour |
|
|
69
|
+
| ------------ | ------------------------------------------------------------------------------- |
|
|
70
|
+
| `'swiss'` | Default. Full Swiss grid with `mastmain`/`basesection` CSS subgrid. |
|
|
71
|
+
| `'fluid'` | Container-query-based auto-fit grid. `basesection` still gets `container-type`. |
|
|
72
|
+
| `'disabled'` | `LayoutMain` renders a plain `<main>` without grid CSS. |
|
|
73
73
|
|
|
74
74
|
Set in your `app.config.ts`:
|
|
75
75
|
|
|
@@ -78,7 +78,7 @@ export default defineAppConfig({
|
|
|
78
78
|
layoutLayer: {
|
|
79
79
|
ui: {
|
|
80
80
|
grid: {
|
|
81
|
-
mode: 'swiss',
|
|
81
|
+
mode: 'swiss', // 'swiss' | 'fluid' | 'disabled'
|
|
82
82
|
},
|
|
83
83
|
},
|
|
84
84
|
},
|
|
@@ -110,8 +110,8 @@ Renders `<main class="mastmain">`. When `mode === 'disabled'` it renders a plain
|
|
|
110
110
|
|
|
111
111
|
**Props:**
|
|
112
112
|
|
|
113
|
-
| Prop
|
|
114
|
-
|
|
113
|
+
| Prop | Type | Default |
|
|
114
|
+
| ----- | -------- | -------- |
|
|
115
115
|
| `tag` | `string` | `'main'` |
|
|
116
116
|
|
|
117
117
|
Place this in your layout file (`layouts/grid.vue`), not in individual pages.
|
|
@@ -132,10 +132,10 @@ Constrains content width and centres it. Use inside sections or anywhere you nee
|
|
|
132
132
|
|
|
133
133
|
**Props:**
|
|
134
134
|
|
|
135
|
-
| Prop
|
|
136
|
-
|
|
135
|
+
| Prop | Type | Default |
|
|
136
|
+
| ------ | ------------------------------------------ | -------- |
|
|
137
137
|
| `size` | `'content' \| 'wide' \| 'fluid' \| 'full'` | `'wide'` |
|
|
138
|
-
| `tag`
|
|
138
|
+
| `tag` | `string` | `'div'` |
|
|
139
139
|
|
|
140
140
|
The `full` size uses negative `margin-inline` to escape the grid's `--grid-padding`, reaching the true viewport edge.
|
|
141
141
|
|
|
@@ -159,11 +159,11 @@ Fragment component (no wrapper element). Handles `useHead()` SEO and optionally
|
|
|
159
159
|
|
|
160
160
|
**Props:**
|
|
161
161
|
|
|
162
|
-
| Prop
|
|
163
|
-
|
|
164
|
-
| `title`
|
|
165
|
-
| `description` | `string`
|
|
166
|
-
| `showHeader`
|
|
162
|
+
| Prop | Type | Default |
|
|
163
|
+
| ------------- | --------- | ------------ |
|
|
164
|
+
| `title` | `string` | — (required) |
|
|
165
|
+
| `description` | `string` | `''` |
|
|
166
|
+
| `showHeader` | `boolean` | `false` |
|
|
167
167
|
|
|
168
168
|
---
|
|
169
169
|
|
|
@@ -179,11 +179,11 @@ Full-viewport subgrid section. Spans 12 rows (= 100vh). Inherits the parent `.ma
|
|
|
179
179
|
|
|
180
180
|
**Props:**
|
|
181
181
|
|
|
182
|
-
| Prop
|
|
183
|
-
|
|
184
|
-
| `fullHeight` | `boolean` | `false`
|
|
185
|
-
| `fullWidth`
|
|
186
|
-
| `tag`
|
|
182
|
+
| Prop | Type | Default |
|
|
183
|
+
| ------------ | --------- | ----------- |
|
|
184
|
+
| `fullHeight` | `boolean` | `false` |
|
|
185
|
+
| `fullWidth` | `boolean` | `false` |
|
|
186
|
+
| `tag` | `string` | `'section'` |
|
|
187
187
|
|
|
188
188
|
---
|
|
189
189
|
|
|
@@ -200,37 +200,37 @@ Positioned child within a subgrid section. Use `preset` for common layouts or se
|
|
|
200
200
|
|
|
201
201
|
**Props:**
|
|
202
202
|
|
|
203
|
-
| Prop
|
|
204
|
-
|
|
205
|
-
| `preset`
|
|
206
|
-
| `colStart`
|
|
207
|
-
| `colSpan`
|
|
208
|
-
| `rowStart`
|
|
209
|
-
| `rowSpan`
|
|
210
|
-
| `layer`
|
|
211
|
-
| `align`
|
|
212
|
-
| `justify`
|
|
213
|
-
| `container` | `string`
|
|
214
|
-
| `gap`
|
|
215
|
-
| `density`
|
|
216
|
-
| `bleed`
|
|
217
|
-
| `as`
|
|
203
|
+
| Prop | Type | Notes |
|
|
204
|
+
| ----------- | --------------------------- | --------------------------------------------------------------------------- |
|
|
205
|
+
| `preset` | `string` | Named preset from config |
|
|
206
|
+
| `colStart` | `number \| ResponsiveValue` | Grid column start |
|
|
207
|
+
| `colSpan` | `number \| ResponsiveValue` | Column span |
|
|
208
|
+
| `rowStart` | `number \| ResponsiveValue` | Grid row start |
|
|
209
|
+
| `rowSpan` | `number \| ResponsiveValue` | Row span |
|
|
210
|
+
| `layer` | `keyof GridLayers` | Z-index layer: `back`, `mid`, `front`, `top` |
|
|
211
|
+
| `align` | `string` | `align-self` value: `start`, `center`, `end`, `stretch` |
|
|
212
|
+
| `justify` | `string` | `justify-self` value: `start`, `center`, `end`, `stretch` |
|
|
213
|
+
| `container` | `string` | Content width constraint: `content` (65ch), `wide` (90rem), `fluid`, `full` |
|
|
214
|
+
| `gap` | `string` | Override `--grid-gap` for nested content (e.g. `'1rem'`) |
|
|
215
|
+
| `density` | `string` | Rhythm base unit: `compact` (2px), `normal` (4px), `relaxed` (8px) |
|
|
216
|
+
| `bleed` | `boolean` | Negative margin to reach viewport edge |
|
|
217
|
+
| `as` | `string` | Tag override |
|
|
218
218
|
|
|
219
219
|
**Built-in presets:**
|
|
220
220
|
|
|
221
|
-
| Preset
|
|
222
|
-
|
|
223
|
-
| `hero`
|
|
224
|
-
| `centered`
|
|
225
|
-
| `fullWidth`
|
|
226
|
-
| `sidebar`
|
|
227
|
-
| `content`
|
|
228
|
-
| `splitLeft`
|
|
229
|
-
| `splitRight`
|
|
230
|
-
| `quarterLeft`
|
|
231
|
-
| `threeQuarterRight` | right 3/4
|
|
232
|
-
| `halfTop`
|
|
233
|
-
| `halfBottom`
|
|
221
|
+
| Preset | Columns | Rows |
|
|
222
|
+
| ------------------- | -------------- | ----------- |
|
|
223
|
+
| `hero` | full width | full height |
|
|
224
|
+
| `centered` | centre 10 cols | rows 2–10 |
|
|
225
|
+
| `fullWidth` | full width | auto |
|
|
226
|
+
| `sidebar` | cols 1–4 | full height |
|
|
227
|
+
| `content` | cols 5–14 | rows 2–10 |
|
|
228
|
+
| `splitLeft` | left half | full |
|
|
229
|
+
| `splitRight` | right half | full |
|
|
230
|
+
| `quarterLeft` | first quarter | full |
|
|
231
|
+
| `threeQuarterRight` | right 3/4 | full |
|
|
232
|
+
| `halfTop` | full width | top half |
|
|
233
|
+
| `halfBottom` | full width | bottom half |
|
|
234
234
|
|
|
235
235
|
---
|
|
236
236
|
|
|
@@ -258,7 +258,8 @@ Two-column 50/50 layout.
|
|
|
258
258
|
<template #right>Right content</template>
|
|
259
259
|
</LayoutSectionSplit>
|
|
260
260
|
|
|
261
|
-
<LayoutSectionSplit reverse />
|
|
261
|
+
<LayoutSectionSplit reverse />
|
|
262
|
+
<!-- right renders first visually -->
|
|
262
263
|
```
|
|
263
264
|
|
|
264
265
|
---
|
|
@@ -293,20 +294,20 @@ Column overlay toggled with `Cmd+G`. Place once in your grid layout file, not in
|
|
|
293
294
|
const { config, getPreset, isEnabled, mode, layers, useZIndex } = useGridConfig()
|
|
294
295
|
```
|
|
295
296
|
|
|
296
|
-
| Return
|
|
297
|
-
|
|
298
|
-
| `config`
|
|
299
|
-
| `isEnabled`
|
|
300
|
-
| `mode`
|
|
301
|
-
| `layers`
|
|
302
|
-
| `getPreset(name)`
|
|
303
|
-
| `useZIndex(layer)` | `number`
|
|
297
|
+
| Return | Type | Description |
|
|
298
|
+
| ------------------ | ------------------------------ | ---------------------------------- |
|
|
299
|
+
| `config` | `Ref<GridConfig>` | Raw config from `app.config` |
|
|
300
|
+
| `isEnabled` | `ComputedRef<boolean>` | `true` when `mode !== 'disabled'` |
|
|
301
|
+
| `mode` | `ComputedRef<GridMode>` | `'swiss' \| 'fluid' \| 'disabled'` |
|
|
302
|
+
| `layers` | `ComputedRef<GridLayers>` | All z-index values |
|
|
303
|
+
| `getPreset(name)` | `GridPresetsItem \| undefined` | Look up a preset by name |
|
|
304
|
+
| `useZIndex(layer)` | `number` | Get a z-index value by layer name |
|
|
304
305
|
|
|
305
306
|
**`useZIndex` example:**
|
|
306
307
|
|
|
307
308
|
```ts
|
|
308
309
|
const { useZIndex } = useGridConfig()
|
|
309
|
-
const zModal = useZIndex('modal')
|
|
310
|
+
const zModal = useZIndex('modal') // 400
|
|
310
311
|
const zHeader = useZIndex('header') // 100
|
|
311
312
|
```
|
|
312
313
|
|
|
@@ -331,13 +332,13 @@ All grid CSS is in `layers/layout/app/assets/css/layout/`.
|
|
|
331
332
|
|
|
332
333
|
CSS custom properties exposed:
|
|
333
334
|
|
|
334
|
-
| Variable
|
|
335
|
-
|
|
336
|
-
| `--grid-cols`
|
|
337
|
-
| `--grid-gap`
|
|
338
|
-
| `--grid-padding`
|
|
339
|
-
| `--section-height`
|
|
340
|
-
| `--grid-row-height` | computed
|
|
335
|
+
| Variable | Value | Purpose |
|
|
336
|
+
| ------------------- | ------------------------------- | ---------------------------- |
|
|
337
|
+
| `--grid-cols` | 6 / 12 / 18 | Active column count |
|
|
338
|
+
| `--grid-gap` | `clamp(0.75rem, 1.5vw, 1.5rem)` | Gap between columns and rows |
|
|
339
|
+
| `--grid-padding` | `clamp(1rem, 2.5vw, 2rem)` | Outer left/right gutters |
|
|
340
|
+
| `--section-height` | `100vh` | Height of one section |
|
|
341
|
+
| `--grid-row-height` | computed | Height of one grid row |
|
|
341
342
|
|
|
342
343
|
**`.basesection`** — Subgrid section (12 rows = 100vh).
|
|
343
344
|
|
|
@@ -362,12 +363,12 @@ Tune minimum column width per-instance:
|
|
|
362
363
|
|
|
363
364
|
**Container size classes** (used by `LayoutContainer`):
|
|
364
365
|
|
|
365
|
-
| Class
|
|
366
|
-
|
|
367
|
-
| `.layout-container-content` | `max-width: 65ch`, centred
|
|
368
|
-
| `.layout-container-wide`
|
|
369
|
-
| `.layout-container-fluid`
|
|
370
|
-
| `.layout-container-full`
|
|
366
|
+
| Class | Effect |
|
|
367
|
+
| --------------------------- | ------------------------------------ |
|
|
368
|
+
| `.layout-container-content` | `max-width: 65ch`, centred |
|
|
369
|
+
| `.layout-container-wide` | `max-width: 90rem`, centred |
|
|
370
|
+
| `.layout-container-fluid` | `max-width: 100%` |
|
|
371
|
+
| `.layout-container-full` | `width: 100vw`, escapes grid padding |
|
|
371
372
|
|
|
372
373
|
---
|
|
373
374
|
|
|
@@ -375,17 +376,17 @@ Tune minimum column width per-instance:
|
|
|
375
376
|
|
|
376
377
|
The grid manages z-index through named layers. Use `useZIndex()` or the `layer` prop on `LayoutGridItem` — never raw numbers.
|
|
377
378
|
|
|
378
|
-
| Layer
|
|
379
|
-
|
|
380
|
-
| `back`
|
|
381
|
-
| `mid`
|
|
382
|
-
| `front`
|
|
383
|
-
| `top`
|
|
384
|
-
| `header`
|
|
385
|
-
| `dropdown` | 200
|
|
386
|
-
| `overlay`
|
|
387
|
-
| `modal`
|
|
388
|
-
| `toast`
|
|
379
|
+
| Layer | Value | Use |
|
|
380
|
+
| ---------- | ----- | ---------------------- |
|
|
381
|
+
| `back` | 0 | Background elements |
|
|
382
|
+
| `mid` | 10 | Content |
|
|
383
|
+
| `front` | 20 | Floating content |
|
|
384
|
+
| `top` | 30 | Pinned / sticky |
|
|
385
|
+
| `header` | 100 | Site header / nav |
|
|
386
|
+
| `dropdown` | 200 | Dropdown menus, popups |
|
|
387
|
+
| `overlay` | 300 | Drawers, sidebars |
|
|
388
|
+
| `modal` | 400 | Modal dialogs |
|
|
389
|
+
| `toast` | 500 | Toasts, notifications |
|
|
389
390
|
|
|
390
391
|
```ts
|
|
391
392
|
// In a component
|
|
@@ -495,10 +496,14 @@ The CSS overflow interaction rule: setting `overflow-x: hidden` on any element f
|
|
|
495
496
|
|
|
496
497
|
```css
|
|
497
498
|
/* Wrong */
|
|
498
|
-
.mastmain {
|
|
499
|
+
.mastmain {
|
|
500
|
+
overflow-x: hidden;
|
|
501
|
+
} /* becomes a scroll container */
|
|
499
502
|
|
|
500
503
|
/* Correct */
|
|
501
|
-
.mastmain {
|
|
504
|
+
.mastmain {
|
|
505
|
+
overflow-x: clip;
|
|
506
|
+
} /* clips without scroll container */
|
|
502
507
|
```
|
|
503
508
|
|
|
504
509
|
### Locomotive Scroll intercepts wheel events globally
|
package/docs/MIGRATION.md
CHANGED
|
@@ -25,7 +25,11 @@ Site metadata is no longer namespaced under `feedsLayer.site`. It now lives at t
|
|
|
25
25
|
// app/app.config.ts — BEFORE
|
|
26
26
|
export default defineAppConfig({
|
|
27
27
|
feedsLayer: {
|
|
28
|
-
site: {
|
|
28
|
+
site: {
|
|
29
|
+
title: 'My Site',
|
|
30
|
+
url: 'https://example.com',
|
|
31
|
+
author: { name: 'Jane', email: 'jane@example.com' },
|
|
32
|
+
},
|
|
29
33
|
},
|
|
30
34
|
})
|
|
31
35
|
|
|
@@ -34,7 +38,7 @@ export default defineAppConfig({
|
|
|
34
38
|
site: {
|
|
35
39
|
title: 'My Site',
|
|
36
40
|
description: 'Short description used in feed channels and meta tags',
|
|
37
|
-
url: 'https://example.com',
|
|
41
|
+
url: 'https://example.com', // canonical origin, NO trailing slash
|
|
38
42
|
author: { name: 'Jane', email: 'jane@example.com' },
|
|
39
43
|
},
|
|
40
44
|
})
|
|
@@ -52,11 +56,11 @@ export default defineAppConfig({
|
|
|
52
56
|
|
|
53
57
|
```ts
|
|
54
58
|
// BEFORE
|
|
55
|
-
|
|
59
|
+
// AFTER
|
|
60
|
+
import type { Author, SiteAuthor } from '#layers/core/app/types/site'
|
|
61
|
+
|
|
56
62
|
const author: SiteAuthor = { name: 'Jane' }
|
|
57
63
|
|
|
58
|
-
// AFTER
|
|
59
|
-
import type { Author } from '#layers/core/app/types/site'
|
|
60
64
|
const author: Author = { name: 'Jane' }
|
|
61
65
|
```
|
|
62
66
|
|
|
@@ -72,9 +76,13 @@ The author `url` field is renamed to `link` to match core's `Author`. This touch
|
|
|
72
76
|
|
|
73
77
|
```ts
|
|
74
78
|
// BEFORE
|
|
75
|
-
authors: z.array(
|
|
79
|
+
authors: z.array(
|
|
80
|
+
z.object({ name: z.string(), avatar: z.string().optional(), url: z.string().optional() })
|
|
81
|
+
)
|
|
76
82
|
// AFTER
|
|
77
|
-
authors: z.array(
|
|
83
|
+
authors: z.array(
|
|
84
|
+
z.object({ name: z.string(), avatar: z.string().optional(), link: z.string().optional() })
|
|
85
|
+
)
|
|
78
86
|
```
|
|
79
87
|
|
|
80
88
|
**3b. Markdown frontmatter** (every content file with authors):
|
|
@@ -98,7 +106,10 @@ authors: authors:
|
|
|
98
106
|
|
|
99
107
|
```ts
|
|
100
108
|
import type { BaseContent } from '#layers/content/app/types/content'
|
|
101
|
-
|
|
109
|
+
|
|
110
|
+
interface MyCustomPage extends BaseContent {
|
|
111
|
+
featuredVideo?: string
|
|
112
|
+
}
|
|
102
113
|
```
|
|
103
114
|
|
|
104
115
|
## 5. Next: add feeds (feature, not breaking)
|
|
@@ -114,13 +125,13 @@ Once the breaking changes are applied and `site` is set, wire RSS/Atom/JSON feed
|
|
|
114
125
|
|
|
115
126
|
## Quick reference
|
|
116
127
|
|
|
117
|
-
| Change
|
|
118
|
-
|
|
128
|
+
| Change | Type | Action |
|
|
129
|
+
| -------------------------- | -------- | ----------------------------------------------- |
|
|
119
130
|
| `feedsLayer.site` → `site` | Breaking | Move to top-level `site` in `app/app.config.ts` |
|
|
120
|
-
| `SiteAuthor` → `Author`
|
|
121
|
-
| Author `url` → `link`
|
|
122
|
-
| `BaseContent`
|
|
123
|
-
| Add feeds
|
|
131
|
+
| `SiteAuthor` → `Author` | Breaking | Rename imports/annotations |
|
|
132
|
+
| Author `url` → `link` | Breaking | Update Zod schema + frontmatter + TS (3 places) |
|
|
133
|
+
| `BaseContent` | Additive | Extend it in custom content types |
|
|
134
|
+
| Add feeds | Feature | Follow [`FEEDS.md`](./FEEDS.md) |
|
|
124
135
|
|
|
125
136
|
The sections below are the detailed, chronological history these summaries were distilled from.
|
|
126
137
|
|
|
@@ -137,6 +148,7 @@ Four related changes landed together. None are strictly breaking for existing pa
|
|
|
137
148
|
Site metadata is no longer namespaced under `feedsLayer`. It lives at the top-level `site` key in `app.config.ts`, owned by the core layer's type declarations. Any layer can read it.
|
|
138
149
|
|
|
139
150
|
**Before:**
|
|
151
|
+
|
|
140
152
|
```ts
|
|
141
153
|
// app/app.config.ts
|
|
142
154
|
export default defineAppConfig({
|
|
@@ -151,6 +163,7 @@ export default defineAppConfig({
|
|
|
151
163
|
```
|
|
152
164
|
|
|
153
165
|
**After:**
|
|
166
|
+
|
|
154
167
|
```ts
|
|
155
168
|
// app/app.config.ts
|
|
156
169
|
export default defineAppConfig({
|
|
@@ -171,6 +184,7 @@ The `site` key is typed via `SiteConfig` from the core layer — `useAppConfig()
|
|
|
171
184
|
The core type previously exported as `SiteAuthor` is now exported as `Author`. It's the base author shape used by `SiteConfig.author`, `ContentAuthor`, and any other layer that deals with authorship.
|
|
172
185
|
|
|
173
186
|
**Before:**
|
|
187
|
+
|
|
174
188
|
```ts
|
|
175
189
|
import type { SiteAuthor } from '#layers/core/app/types/site'
|
|
176
190
|
|
|
@@ -178,6 +192,7 @@ const author: SiteAuthor = { name: 'Jane' }
|
|
|
178
192
|
```
|
|
179
193
|
|
|
180
194
|
**After:**
|
|
195
|
+
|
|
181
196
|
```ts
|
|
182
197
|
import type { Author } from '#layers/core/app/types/site'
|
|
183
198
|
|
|
@@ -193,15 +208,21 @@ const author: Author = { name: 'Jane' }
|
|
|
193
208
|
The `url` field on blog post authors has been renamed to `link` to align with core's `Author` type. The Zod schema, TypeScript interface, and markdown frontmatter all need updating.
|
|
194
209
|
|
|
195
210
|
**Zod schema (in your `content.config.ts`):**
|
|
211
|
+
|
|
196
212
|
```ts
|
|
197
213
|
// Before
|
|
198
|
-
authors: z.array(
|
|
214
|
+
authors: z.array(
|
|
215
|
+
z.object({ name: z.string(), avatar: z.string().optional(), url: z.string().optional() })
|
|
216
|
+
)
|
|
199
217
|
|
|
200
218
|
// After
|
|
201
|
-
authors: z.array(
|
|
219
|
+
authors: z.array(
|
|
220
|
+
z.object({ name: z.string(), avatar: z.string().optional(), link: z.string().optional() })
|
|
221
|
+
)
|
|
202
222
|
```
|
|
203
223
|
|
|
204
224
|
**Markdown frontmatter:**
|
|
225
|
+
|
|
205
226
|
```yaml
|
|
206
227
|
# Before
|
|
207
228
|
authors:
|
|
@@ -215,6 +236,7 @@ authors:
|
|
|
215
236
|
```
|
|
216
237
|
|
|
217
238
|
**TypeScript interface** — `ContentAuthor` now extends `Author` instead of being a standalone type:
|
|
239
|
+
|
|
218
240
|
```ts
|
|
219
241
|
import type { Author } from '#layers/core/app/types/site'
|
|
220
242
|
|
|
@@ -274,20 +296,23 @@ export default defineAppConfig({
|
|
|
274
296
|
|
|
275
297
|
Available feed URLs for each collection:
|
|
276
298
|
|
|
277
|
-
| URL
|
|
278
|
-
|
|
279
|
-
| `/feed/:collection/rss`
|
|
280
|
-
| `/feed/:collection/atom` | Atom 1.0
|
|
281
|
-
| `/feed/:collection/json` | JSON Feed 1.1
|
|
282
|
-
| `/feed/rss`
|
|
283
|
-
| `/feed/atom`
|
|
284
|
-
| `/feed/json`
|
|
285
|
-
| `/feed`
|
|
299
|
+
| URL | Format |
|
|
300
|
+
| ------------------------ | ---------------------------------- |
|
|
301
|
+
| `/feed/:collection/rss` | RSS 2.0 |
|
|
302
|
+
| `/feed/:collection/atom` | Atom 1.0 |
|
|
303
|
+
| `/feed/:collection/json` | JSON Feed 1.1 |
|
|
304
|
+
| `/feed/rss` | RSS for `defaultCollection` |
|
|
305
|
+
| `/feed/atom` | Atom for `defaultCollection` |
|
|
306
|
+
| `/feed/json` | JSON Feed for `defaultCollection` |
|
|
307
|
+
| `/feed` | JSON index of all configured feeds |
|
|
286
308
|
|
|
287
309
|
To expose portfolio items as a feed:
|
|
310
|
+
|
|
288
311
|
```ts
|
|
289
312
|
feedsLayer: {
|
|
290
|
-
feed: {
|
|
313
|
+
feed: {
|
|
314
|
+
collections: ['blog', 'portfolio']
|
|
315
|
+
}
|
|
291
316
|
}
|
|
292
317
|
```
|
|
293
318
|
|
|
@@ -318,11 +343,11 @@ The feeds layer automatically injects `<link rel="alternate">` tags so RSS reade
|
|
|
318
343
|
|
|
319
344
|
**The rule:** every page gets the main site feeds. Pages that belong to a non-default collection also get that collection's specific feeds.
|
|
320
345
|
|
|
321
|
-
| Page
|
|
322
|
-
|
|
323
|
-
| `/`, `/about`, any non-collection page
|
|
346
|
+
| Page | Links injected |
|
|
347
|
+
| -------------------------------------------------------------- | ----------------------------------------------- |
|
|
348
|
+
| `/`, `/about`, any non-collection page | 3 main site feeds |
|
|
324
349
|
| `/blog`, `/blog/hello-world` (if `blog` = `defaultCollection`) | 3 main site feeds (these already point to blog) |
|
|
325
|
-
| `/portfolio`, `/portfolio/project` (non-default collection)
|
|
350
|
+
| `/portfolio`, `/portfolio/project` (non-default collection) | 3 main site feeds + 3 portfolio feeds |
|
|
326
351
|
|
|
327
352
|
The main site feeds use the shorthand routes (`/feed/rss`, `/feed/atom`, `/feed/json`) which always serve `defaultCollection`. Collection-specific links are only added for non-default collections — where you're actively browsing content not covered by the main feeds.
|
|
328
353
|
|
|
@@ -332,14 +357,14 @@ No action required. The collection a page belongs to is inferred from the first
|
|
|
332
357
|
|
|
333
358
|
## Quick Reference
|
|
334
359
|
|
|
335
|
-
| Change
|
|
336
|
-
|
|
337
|
-
| Site metadata
|
|
338
|
-
| `SiteAuthor` type import
|
|
339
|
-
| Author `url` in frontmatter | Rename `url:` → `link:` in blog author blocks
|
|
340
|
-
| Author `url` in Zod schema
|
|
341
|
-
| Collection feeds
|
|
342
|
-
| Feed autodiscovery
|
|
360
|
+
| Change | Action required |
|
|
361
|
+
| --------------------------- | ------------------------------------------------------------ |
|
|
362
|
+
| Site metadata | Move `feedsLayer.site` → top-level `site` in `app.config.ts` |
|
|
363
|
+
| `SiteAuthor` type import | Rename to `Author` |
|
|
364
|
+
| Author `url` in frontmatter | Rename `url:` → `link:` in blog author blocks |
|
|
365
|
+
| Author `url` in Zod schema | Rename `url` → `link` in `authors` object schema |
|
|
366
|
+
| Collection feeds | Set `feedsLayer.feed.collections` in `app.config.ts` |
|
|
367
|
+
| Feed autodiscovery | Nothing — automatic via the feeds layer plugin |
|
|
343
368
|
|
|
344
369
|
---
|
|
345
370
|
|
|
@@ -385,14 +410,14 @@ Each factory defaults to the conventional source glob if you omit the argument.
|
|
|
385
410
|
In your app's `content.config.ts`, import the factory and register it under any name you like:
|
|
386
411
|
|
|
387
412
|
```ts
|
|
388
|
-
import {
|
|
413
|
+
import { createBlogCollection, createPortfolioCollection } from '#layers/content/content.config'
|
|
389
414
|
|
|
390
415
|
export default defineContentConfig({
|
|
391
416
|
collections: {
|
|
392
417
|
blog: createBlogCollection(),
|
|
393
418
|
works: createPortfolioCollection('works/**/*.md'),
|
|
394
419
|
// gallery omitted — not needed
|
|
395
|
-
}
|
|
420
|
+
},
|
|
396
421
|
})
|
|
397
422
|
```
|
|
398
423
|
|
|
@@ -442,8 +467,8 @@ export default defineAppConfig({
|
|
|
442
467
|
contentLayer: {
|
|
443
468
|
sections: {
|
|
444
469
|
blog: true,
|
|
445
|
-
portfolio: false,
|
|
446
|
-
gallery: false,
|
|
470
|
+
portfolio: false, // /portfolio and /portfolio/[slug] → 404
|
|
471
|
+
gallery: false, // /gallery and all nested routes → 404
|
|
447
472
|
},
|
|
448
473
|
},
|
|
449
474
|
})
|
|
@@ -457,12 +482,12 @@ All three flags default to `true` in the layer, so you only need to declare the
|
|
|
457
482
|
|
|
458
483
|
## Quick Reference
|
|
459
484
|
|
|
460
|
-
| Goal
|
|
461
|
-
|
|
485
|
+
| Goal | How |
|
|
486
|
+
| --------------------------------- | -------------------------------------------------------------------------- |
|
|
462
487
|
| Reuse portfolio schema as `works` | `works: createPortfolioCollection('works/**/*.md')` in `content.config.ts` |
|
|
463
|
-
| Query custom-named collection
|
|
464
|
-
| Disable the gallery section
|
|
465
|
-
| Disable multiple sections
|
|
488
|
+
| Query custom-named collection | `createPortfolioComposables('works')` → `useItems` / `useItem` |
|
|
489
|
+
| Disable the gallery section | `contentLayer: { sections: { gallery: false } }` in `app.config.ts` |
|
|
490
|
+
| Disable multiple sections | List each with `false` in `sections` |
|
|
466
491
|
|
|
467
492
|
---
|
|
468
493
|
|
|
@@ -479,12 +504,14 @@ v1.6.0 restructures the layout and content systems. The main theme is **opt-in c
|
|
|
479
504
|
Header and footer are no longer rendered by default. Pages that relied on `layout: 'grid'` to get them must now pass props.
|
|
480
505
|
|
|
481
506
|
**Before (v1.5.x):**
|
|
507
|
+
|
|
482
508
|
```ts
|
|
483
509
|
definePageMeta({ layout: 'grid' })
|
|
484
510
|
// header + footer always rendered
|
|
485
511
|
```
|
|
486
512
|
|
|
487
513
|
**After (v1.6.0):**
|
|
514
|
+
|
|
488
515
|
```ts
|
|
489
516
|
// Opt-in to header and footer:
|
|
490
517
|
definePageMeta({
|
|
@@ -500,11 +527,11 @@ definePageMeta({ layout: false })
|
|
|
500
527
|
|
|
501
528
|
Available props on `grid.vue` (all `boolean`, default `false`):
|
|
502
529
|
|
|
503
|
-
| Prop
|
|
504
|
-
|
|
505
|
-
| `showHeader`
|
|
506
|
-
| `showNav`
|
|
507
|
-
| `showFooter`
|
|
530
|
+
| Prop | Description |
|
|
531
|
+
| --------------- | ----------------------------------- |
|
|
532
|
+
| `showHeader` | Renders `<MastHeader>` |
|
|
533
|
+
| `showNav` | Renders `<MastNav>` |
|
|
534
|
+
| `showFooter` | Renders `<MastFooter>` |
|
|
508
535
|
| `showGridDebug` | Renders `<LayoutGridDebug>` overlay |
|
|
509
536
|
|
|
510
537
|
---
|
|
@@ -514,12 +541,14 @@ Available props on `grid.vue` (all `boolean`, default `false`):
|
|
|
514
541
|
The global Locomotive Scroll wrapper in `default.vue` has been removed. Smooth scroll is now per-page via the `useSmoothScroll()` composable.
|
|
515
542
|
|
|
516
543
|
**Before (v1.5.x):**
|
|
544
|
+
|
|
517
545
|
```vue
|
|
518
546
|
<!-- default.vue automatically wrapped everything in MastScroller -->
|
|
519
547
|
<!-- No per-page setup required -->
|
|
520
548
|
```
|
|
521
549
|
|
|
522
550
|
**After (v1.6.0):**
|
|
551
|
+
|
|
523
552
|
```ts
|
|
524
553
|
// In any page that needs smooth scroll:
|
|
525
554
|
const { scrollTo, scrollToTop, velocity, progress } = useSmoothScroll()
|
|
@@ -534,6 +563,7 @@ Pages that don't call `useSmoothScroll()` will use native browser scroll — no
|
|
|
534
563
|
`LayoutPageContainer` has been superseded by `LayoutPage`. The legacy component still exists for backwards compatibility but is no longer maintained.
|
|
535
564
|
|
|
536
565
|
**Before (v1.5.x):**
|
|
566
|
+
|
|
537
567
|
```vue
|
|
538
568
|
<LayoutPageContainer title="My Page" :show-header="false">
|
|
539
569
|
<LayoutSection>...</LayoutSection>
|
|
@@ -541,6 +571,7 @@ Pages that don't call `useSmoothScroll()` will use native browser scroll — no
|
|
|
541
571
|
```
|
|
542
572
|
|
|
543
573
|
**After (v1.6.0):**
|
|
574
|
+
|
|
544
575
|
```vue
|
|
545
576
|
<LayoutPage title="My Page">
|
|
546
577
|
<LayoutSection>...</LayoutSection>
|
|
@@ -581,11 +612,13 @@ definePageMeta({ ssr: false, layout: false })
|
|
|
581
612
|
All built-in content composables now use `useContentData` — a `createUseAsyncData` wrapper with `dedupe: 'cancel'` — instead of calling `useAsyncData` directly. If you've extended or wrapped any content composables, update the inner call:
|
|
582
613
|
|
|
583
614
|
**Before (v1.5.x):**
|
|
615
|
+
|
|
584
616
|
```ts
|
|
585
617
|
return useAsyncData('my-key', () => queryCollection('blog').all())
|
|
586
618
|
```
|
|
587
619
|
|
|
588
620
|
**After (v1.6.0):**
|
|
621
|
+
|
|
589
622
|
```ts
|
|
590
623
|
return useContentData('my-key', () => queryCollection('blog').all())
|
|
591
624
|
```
|
|
@@ -617,11 +650,11 @@ export default defineNuxtConfig({
|
|
|
617
650
|
|
|
618
651
|
## Quick Reference
|
|
619
652
|
|
|
620
|
-
| Pattern
|
|
621
|
-
|
|
622
|
-
| Grid page with header + footer | `layout: 'grid'`
|
|
623
|
-
| Grid page, no chrome
|
|
624
|
-
| Full-bleed / animation page
|
|
625
|
-
| Page wrapper component
|
|
626
|
-
| Global smooth scroll
|
|
627
|
-
| Content async data
|
|
653
|
+
| Pattern | v1.5.x | v1.6.0 |
|
|
654
|
+
| ------------------------------ | ------------------------------- | ------------------------------------------------------------------------- |
|
|
655
|
+
| Grid page with header + footer | `layout: 'grid'` | `layout: { name: 'grid', props: { showHeader: true, showFooter: true } }` |
|
|
656
|
+
| Grid page, no chrome | `layout: 'grid'` | `layout: 'grid'` |
|
|
657
|
+
| Full-bleed / animation page | `layout: 'grid'` (broken) | `layout: false` |
|
|
658
|
+
| Page wrapper component | `<LayoutPageContainer>` | `<LayoutPage>` |
|
|
659
|
+
| Global smooth scroll | `MastScroller` in layout (auto) | `useSmoothScroll()` per-page |
|
|
660
|
+
| Content async data | `useAsyncData(...)` | `useContentData(...)` |
|