kmcom-nuxt-layers 2.2.6 → 2.2.9
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/FEEDS.md +197 -0
- package/docs/LAYERS-FIXES.md +101 -0
- package/docs/MIGRATION.md +627 -0
- package/docs/feed-layer.md +374 -0
- package/docs/patch-picture-provider-type.md +52 -0
- package/docs/shaderGuide.md +2071 -0
- package/docs/types-architecture.md +234 -0
- package/layers/animations/app/components/Motion/CountUp.vue +1 -2
- package/layers/animations/app/components/Motion/Magnetic.vue +1 -2
- package/layers/animations/app/components/Motion/Marquee.vue +2 -5
- package/layers/animations/app/components/Motion/MarqueeText.vue +1 -2
- package/layers/animations/app/components/Motion/Tilt.vue +1 -2
- package/layers/animations/app/composables/useCountUp.ts +4 -1
- package/layers/animations/app/composables/useMagneticElement.ts +1 -3
- package/layers/animations/app/composables/useMarqueeCopies.ts +3 -3
- package/layers/animations/app/types/animations.ts +8 -0
- package/layers/animations/app/types/index.ts +1 -0
- package/layers/animations/package.json +4 -1
- package/layers/canvas/app/components/ShaderCanvas.vue +4 -4
- package/layers/canvas/app/composables/useRendererCapabilities.ts +19 -15
- package/layers/canvas/app/types/index.ts +1 -0
- package/layers/canvas/package.json +2 -1
- package/layers/canvas/tsconfig.json +2 -1
- package/layers/content/app/components/Blog/Card.vue +5 -5
- package/layers/content/app/components/Gallery/AmbientImage.vue +3 -3
- package/layers/content/app/components/Gallery/Card.vue +3 -3
- package/layers/content/app/components/NuxtContent/Detail.vue +5 -1
- package/layers/content/app/components/NuxtContent/Surround.vue +5 -3
- package/layers/content/app/components/NuxtContent/Toc.vue +1 -1
- package/layers/content/app/components/Portfolio/Card.vue +5 -5
- package/layers/content/app/components/content/Figure.vue +3 -3
- package/layers/content/app/types/index.ts +1 -0
- package/layers/content/package.json +2 -1
- package/layers/core/app/composables/useErrorLog.ts +9 -11
- package/layers/core/app/utils/helpers.ts +14 -12
- package/layers/core/nuxt.config.ts +1 -0
- package/layers/feeds/app/plugins/feed-head.ts +1 -2
- package/layers/feeds/package.json +2 -1
- package/layers/feeds/public/feed/style.css +256 -0
- package/layers/feeds/server/routes/feed/discovery.get.ts +1 -2
- package/layers/feeds/server/utils/content-adapter.ts +3 -2
- package/layers/forms/app/components/Form/Field.vue +4 -4
- package/layers/forms/app/types/index.ts +1 -0
- package/layers/forms/package.json +2 -1
- package/layers/layout/app/components/Layout/Grid/Item.vue +33 -19
- package/layers/layout/app/components/Layout/Page/Container.vue +11 -11
- package/layers/layout/app/components/Layout/Page/Header.vue +1 -1
- package/layers/layout/app/components/Layout/Page/index.vue +1 -1
- package/layers/layout/app/components/Layout/Section/Gallery.vue +6 -1
- package/layers/layout/app/components/Layout/Section/Title.vue +1 -1
- package/layers/layout/app/types/index.ts +1 -0
- package/layers/layout/package.json +2 -1
- package/layers/mailer/app/types/index.ts +1 -0
- package/layers/mailer/app/types/mailer.ts +25 -0
- package/layers/mailer/package.json +2 -1
- package/layers/motion/package.json +2 -1
- package/layers/navigation/app/components/Links/Group.vue +1 -0
- package/layers/navigation/app/components/Links/Named.vue +2 -0
- package/layers/navigation/app/types/index.ts +1 -0
- package/layers/navigation/package.json +4 -1
- package/layers/page-transitions/package.json +4 -1
- package/layers/routing/app/types/app-config.d.ts +3 -1
- package/layers/routing/app/types/index.ts +1 -0
- package/layers/routing/package.json +2 -1
- package/layers/scripts/app/composables/useGtm.ts +1 -1
- package/layers/scripts/app/types/index.ts +1 -0
- package/layers/scripts/app/types/scripts.ts +14 -0
- package/layers/scripts/package.json +2 -1
- package/layers/scroll/app/components/Motion/ScrollScene.vue +3 -1
- package/layers/scroll/app/composables/useScrollSteps.ts +2 -9
- package/layers/scroll/app/composables/useSectionProgress.ts +2 -1
- package/layers/scroll/app/plugins/locomotive-scroll.client.ts +1 -8
- package/layers/scroll/app/types/index.ts +1 -0
- package/layers/scroll/app/types/scroll.ts +32 -0
- package/layers/scroll/package.json +3 -0
- package/layers/seo/package.json +2 -1
- package/layers/shader/app/components/Material/Fresnel.client.vue +1 -1
- package/layers/shader/app/components/Material/Image.client.vue +1 -1
- package/layers/shader/app/components/Material/Node.client.vue +7 -7
- package/layers/shader/app/components/Material/Noise.client.vue +1 -1
- package/layers/shader/app/components/Node/Color.client.vue +17 -20
- package/layers/shader/app/components/Node/Noise.client.vue +31 -34
- package/layers/shader/app/components/Pipeline/Aurora.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/BilinearGradient.client.vue +8 -11
- package/layers/shader/app/components/Pipeline/BillowNoise.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/BrightnessContrast.client.vue +6 -2
- package/layers/shader/app/components/Pipeline/CellularNoise.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/Checkerboard.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/Circle.client.vue +5 -8
- package/layers/shader/app/components/Pipeline/Clouds.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/ColorBurnBlend.client.vue +2 -19
- package/layers/shader/app/components/Pipeline/ColorDodgeBlend.client.vue +2 -19
- package/layers/shader/app/components/Pipeline/ColourRamp.client.vue +5 -9
- package/layers/shader/app/components/Pipeline/ConicGradient.client.vue +5 -8
- package/layers/shader/app/components/Pipeline/Cross.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/CurlNoise.client.vue +3 -7
- package/layers/shader/app/components/Pipeline/DarkenBlend.client.vue +2 -19
- package/layers/shader/app/components/Pipeline/DayNightCycle.client.vue +5 -8
- package/layers/shader/app/components/Pipeline/DiagonalGradient.client.vue +5 -8
- package/layers/shader/app/components/Pipeline/DiamondGradient.client.vue +5 -8
- package/layers/shader/app/components/Pipeline/DifferenceBlend.client.vue +2 -19
- package/layers/shader/app/components/Pipeline/DomainWarpedNoise.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/Dots.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/DuoTone.client.vue +5 -9
- package/layers/shader/app/components/Pipeline/ExclusionBlend.client.vue +3 -23
- package/layers/shader/app/components/Pipeline/ExponentialFog.client.vue +4 -7
- package/layers/shader/app/components/Pipeline/FilmBurn.client.vue +4 -7
- package/layers/shader/app/components/Pipeline/Flame.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/FocalGradient.client.vue +5 -8
- package/layers/shader/app/components/Pipeline/GodRays.client.vue +4 -7
- package/layers/shader/app/components/Pipeline/GradientNoise.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/Grid.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/Halation.client.vue +3 -7
- package/layers/shader/app/components/Pipeline/HardLightBlend.client.vue +2 -19
- package/layers/shader/app/components/Pipeline/Haze.client.vue +4 -7
- package/layers/shader/app/components/Pipeline/Hexagon.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/LensFlare.client.vue +4 -7
- package/layers/shader/app/components/Pipeline/LightenBlend.client.vue +2 -19
- package/layers/shader/app/components/Pipeline/LinearGradient4.client.vue +2 -2
- package/layers/shader/app/components/Pipeline/Marble.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/MonochromeTint.client.vue +3 -7
- package/layers/shader/app/components/Pipeline/MultiplyBlend.client.vue +2 -19
- package/layers/shader/app/components/Pipeline/NoisyGradient.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/NoisyGradientBlend.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/OverlayBlend.client.vue +2 -19
- package/layers/shader/app/components/Pipeline/Polygon.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/RaymarchTunnel.client.vue +4 -7
- package/layers/shader/app/components/Pipeline/Rectangle.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/RidgedNoise.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/Ring.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/ScreenBlend.client.vue +2 -19
- package/layers/shader/app/components/Pipeline/SkyAtmosphere.client.vue +6 -9
- package/layers/shader/app/components/Pipeline/SoftLightBlend.client.vue +2 -19
- package/layers/shader/app/components/Pipeline/SplitTone.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/Star.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/Stripes.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/Tint.client.vue +4 -7
- package/layers/shader/app/components/Pipeline/Triangle.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/ValueNoise.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/VoronoiEdges.client.vue +4 -8
- package/layers/shader/app/components/Pipeline/Water.client.vue +5 -8
- package/layers/shader/app/components/Pipeline/WaveBendLayer.client.vue +4 -7
- package/layers/shader/app/components/Pipeline/WaveColourLayer.client.vue +3 -7
- package/layers/shader/app/components/Pipeline/Wood.client.vue +4 -8
- package/layers/shader/app/components/Preset/Aurora.client.vue +15 -21
- package/layers/shader/app/components/Preset/Flow.client.vue +2 -1
- package/layers/shader/app/components/Preset/GradientMesh.client.vue +2 -1
- package/layers/shader/app/components/Preset/Nebula.client.vue +2 -1
- package/layers/shader/app/components/Preset/Ocean.client.vue +2 -1
- package/layers/shader/app/components/Preset/ThemeAurora.client.vue +30 -90
- package/layers/shader/app/components/Preset/ThemeBubble.client.vue +30 -91
- package/layers/shader/app/components/Preset/ThemeFlow.client.vue +30 -90
- package/layers/shader/app/components/Preset/ThemeGradient.client.vue +30 -91
- package/layers/shader/app/components/Preset/ThemeLavaLamp.client.vue +30 -90
- package/layers/shader/app/components/Preset/ThemePlasma.client.vue +30 -90
- package/layers/shader/app/components/Preset/ThemeWave.client.vue +30 -90
- package/layers/shader/app/components/Shader/Background.client.vue +4 -4
- package/layers/shader/app/components/Shader/Host.client.vue +31 -33
- package/layers/shader/app/components/Shader/Runtime.client.vue +15 -23
- package/layers/shader/app/composables/useAmbientMaterials.ts +53 -51
- package/layers/shader/app/composables/useShaderMixBlend.ts +26 -0
- package/layers/shader/app/composables/useThemePreset.ts +75 -0
- package/layers/shader/app/shaders/common/noise.ts +2 -7
- package/layers/shader/app/shaders/types.ts +6 -6
- package/layers/shader/app/types/tsl.ts +7 -25
- package/layers/shader/app/types/uniforms.ts +2 -1
- package/layers/shader/app/utils/tsl/color.ts +7 -1
- package/layers/shader/package.json +2 -1
- package/layers/theme/app/components/ThemePicker/Colors.vue +1 -3
- package/layers/theme/app/types/app-config.d.ts +4 -2
- package/layers/theme/app/types/index.ts +1 -0
- package/layers/theme/app/types/theme.ts +3 -18
- package/layers/theme/package.json +2 -1
- package/layers/theme/server/plugins/theme-fouc.ts +1 -1
- package/layers/transitions/package.json +4 -1
- package/layers/typography/app/components/Typography/CodeBlock.vue +2 -2
- package/layers/typography/app/components/Typography/Headline.vue +2 -2
- package/layers/typography/app/components/Typography/HeadlineScreen.vue +1 -1
- package/layers/typography/app/components/Typography/QuoteBlock.vue +4 -1
- package/layers/typography/app/components/Typography/TextStroke.vue +2 -0
- package/layers/typography/app/components/Typography/index.vue +36 -27
- package/layers/typography/app/composables/typography.ts +27 -21
- package/layers/typography/app/types/colors.ts +9 -29
- package/layers/typography/app/types/index.ts +2 -0
- package/layers/typography/package.json +4 -1
- package/layers/ui/package.json +2 -1
- package/layers/visual/app/app.config.ts +5 -2
- package/layers/visual/app/components/Accent/Blob.vue +20 -20
- package/layers/visual/app/components/Accent/Scene.vue +2 -2
- package/layers/visual/app/components/Base/Modal.vue +2 -2
- package/layers/visual/app/components/Gradient/Background.vue +2 -2
- package/layers/visual/app/components/Gradient/Text.vue +2 -2
- package/layers/visual/app/components/Media/Picture.vue +3 -1
- package/layers/visual/app/components/Progress/Bar.vue +6 -6
- package/layers/visual/app/components/Tint/Overlay.vue +14 -14
- package/layers/visual/app/composables/accent.ts +10 -8
- package/layers/visual/app/composables/tint.ts +7 -7
- package/layers/visual/app/types/index.ts +6 -0
- package/layers/visual/app/types/media.ts +4 -2
- package/layers/visual/app/types/tint.ts +2 -1
- package/layers/visual/package.json +4 -1
- package/package.json +6 -2
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
# Agent Migration Guide — Update an app to nuxt-layers v2.2.x
|
|
2
|
+
|
|
3
|
+
**Audience:** an AI coding agent (or developer) updating a downstream Nuxt app that consumes these layers.
|
|
4
|
+
**Goal:** apply the breaking changes from the `feeds` / `site` / content-type work.
|
|
5
|
+
|
|
6
|
+
> Adding feeds to your content sections is a **feature task**, not a breaking change — it has its own guide: [`FEEDS.md`](./FEEDS.md). Do the breaking changes below first, then follow that.
|
|
7
|
+
|
|
8
|
+
Work top to bottom. Each change has a **Detect** step (how to tell if it applies) and an **Apply** step. Skip anything Detect doesn't find. Run the **Verify** checklist before declaring done. Where this summary and the detailed history sections below disagree, the code wins — check the cited files.
|
|
9
|
+
|
|
10
|
+
## 0. Preconditions
|
|
11
|
+
|
|
12
|
+
- Confirm the app extends these layers (an `extends` array, or a `LAYER_PATHS` / resolver block like the playground's, in `nuxt.config.ts`).
|
|
13
|
+
- Confirm the layer checkout is at **v2.2.x** (`git -C <layers-repo> describe --tags`).
|
|
14
|
+
- The app must use `@nuxt/content` v3 with a `content.config.ts` at the **app root** (Nuxt Content v3 resolves it from the app root, not the layer).
|
|
15
|
+
|
|
16
|
+
## 1. BREAKING — Site metadata moved to top-level `site`
|
|
17
|
+
|
|
18
|
+
Site metadata is no longer namespaced under `feedsLayer.site`. It now lives at the top-level `site` key in `app.config.ts`, typed by the **core** layer (`SiteConfig` in `layers/core/app/types/site.ts`). Any layer can read it via `useAppConfig().site`.
|
|
19
|
+
|
|
20
|
+
**Detect:** grep the app for `feedsLayer.site` or a `feedsLayer: { site:` block in `app/app.config.ts`.
|
|
21
|
+
|
|
22
|
+
**Apply:** move the object out to a top-level `site` key.
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
// app/app.config.ts — BEFORE
|
|
26
|
+
export default defineAppConfig({
|
|
27
|
+
feedsLayer: {
|
|
28
|
+
site: { title: 'My Site', url: 'https://example.com', author: { name: 'Jane', email: 'jane@example.com' } },
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// app/app.config.ts — AFTER
|
|
33
|
+
export default defineAppConfig({
|
|
34
|
+
site: {
|
|
35
|
+
title: 'My Site',
|
|
36
|
+
description: 'Short description used in feed channels and meta tags',
|
|
37
|
+
url: 'https://example.com', // canonical origin, NO trailing slash
|
|
38
|
+
author: { name: 'Jane', email: 'jane@example.com' },
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`SiteConfig` fields: `title`, `subtitle`, `description`, `url`, `author`, `image`, `favicon`, `copyright`. All optional, but feeds need at least `title` and `url` for valid channel metadata.
|
|
44
|
+
|
|
45
|
+
> Reminder: `app.config.ts` MUST be inside `app/` (the srcDir). A root-level `app.config.ts` is silently ignored in Nuxt 4.
|
|
46
|
+
|
|
47
|
+
## 2. BREAKING — `SiteAuthor` type renamed to `Author`
|
|
48
|
+
|
|
49
|
+
**Detect:** grep for `SiteAuthor`.
|
|
50
|
+
|
|
51
|
+
**Apply:** rename every import and annotation.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
// BEFORE
|
|
55
|
+
import type { SiteAuthor } from '#layers/core/app/types/site'
|
|
56
|
+
const author: SiteAuthor = { name: 'Jane' }
|
|
57
|
+
|
|
58
|
+
// AFTER
|
|
59
|
+
import type { Author } from '#layers/core/app/types/site'
|
|
60
|
+
const author: Author = { name: 'Jane' }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Shape is unchanged: `{ name: string; email?: string; link?: string }`.
|
|
64
|
+
|
|
65
|
+
## 3. BREAKING — Content author `url` → `link`
|
|
66
|
+
|
|
67
|
+
The author `url` field is renamed to `link` to match core's `Author`. This touches **three** places — change all of them or feeds/templates silently drop the author link.
|
|
68
|
+
|
|
69
|
+
**Detect:** grep the app's `content.config.ts` and `content/**/*.md` frontmatter for `url:` inside an `authors` block.
|
|
70
|
+
|
|
71
|
+
**3a. Zod schema** (app `content.config.ts`):
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
// BEFORE
|
|
75
|
+
authors: z.array(z.object({ name: z.string(), avatar: z.string().optional(), url: z.string().optional() }))
|
|
76
|
+
// AFTER
|
|
77
|
+
authors: z.array(z.object({ name: z.string(), avatar: z.string().optional(), link: z.string().optional() }))
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**3b. Markdown frontmatter** (every content file with authors):
|
|
81
|
+
|
|
82
|
+
```yaml
|
|
83
|
+
# BEFORE # AFTER
|
|
84
|
+
authors: authors:
|
|
85
|
+
- name: Jane Doe - name: Jane Doe
|
|
86
|
+
url: https://... link: https://...
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**3c. TypeScript** — `ContentAuthor` now extends `Author`. If the app defines its own author type, extend `Author` rather than redeclaring `url`.
|
|
90
|
+
|
|
91
|
+
> Do NOT pass `schema:` to `defineCollection`. c12 uses jiti with `moduleCache:false`, so the validator never initializes. Define the Zod object inline in the collection, the established pattern in this repo.
|
|
92
|
+
|
|
93
|
+
## 4. NON-BREAKING — `BaseContent` shared interface
|
|
94
|
+
|
|
95
|
+
`BlogPost`, `PortfolioItem`, `GalleryItem`, and `ContentPage` now extend a shared `BaseContent` (`title`, `description?`, `image?`, `tags?`, `date?`, `draft?`) from `#layers/content/app/types/content`.
|
|
96
|
+
|
|
97
|
+
**Apply only if** the app has custom content types that duplicate those fields — extend `BaseContent` instead:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import type { BaseContent } from '#layers/content/app/types/content'
|
|
101
|
+
interface MyCustomPage extends BaseContent { featuredVideo?: string }
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## 5. Next: add feeds (feature, not breaking)
|
|
105
|
+
|
|
106
|
+
Once the breaking changes are applied and `site` is set, wire RSS/Atom/JSON feeds into your content sections by following [`FEEDS.md`](./FEEDS.md).
|
|
107
|
+
|
|
108
|
+
## 6. Verify
|
|
109
|
+
|
|
110
|
+
1. **Grep clean:** no remaining `SiteAuthor`, no `feedsLayer.site`, no `url:` inside `authors` blocks (frontmatter + Zod).
|
|
111
|
+
2. **Typecheck:** `pnpm typecheck` passes (catches `Author`/`BaseContent`/`ContentAuthor` mismatches).
|
|
112
|
+
3. **Lint:** `pnpm lint` passes (no semicolons, single quotes, ES5 trailing commas, ≤100 cols).
|
|
113
|
+
4. **Dev smoke:** `pnpm dev` boots and content pages render with author links intact.
|
|
114
|
+
|
|
115
|
+
## Quick reference
|
|
116
|
+
|
|
117
|
+
| Change | Type | Action |
|
|
118
|
+
|--------|------|--------|
|
|
119
|
+
| `feedsLayer.site` → `site` | Breaking | Move to top-level `site` in `app/app.config.ts` |
|
|
120
|
+
| `SiteAuthor` → `Author` | Breaking | Rename imports/annotations |
|
|
121
|
+
| Author `url` → `link` | Breaking | Update Zod schema + frontmatter + TS (3 places) |
|
|
122
|
+
| `BaseContent` | Additive | Extend it in custom content types |
|
|
123
|
+
| Add feeds | Feature | Follow [`FEEDS.md`](./FEEDS.md) |
|
|
124
|
+
|
|
125
|
+
The sections below are the detailed, chronological history these summaries were distilled from.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
# Migration Guide: Feeds Layer, Site Config & Content Type Normalisation
|
|
130
|
+
|
|
131
|
+
Four related changes landed together. None are strictly breaking for existing pages, but anything that reads `feedsLayer.site`, imports `SiteAuthor`, or uses the `authors[].url` frontmatter field needs updating.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 1. Shared `site` config (replaces `feedsLayer.site`)
|
|
136
|
+
|
|
137
|
+
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
|
+
|
|
139
|
+
**Before:**
|
|
140
|
+
```ts
|
|
141
|
+
// app/app.config.ts
|
|
142
|
+
export default defineAppConfig({
|
|
143
|
+
feedsLayer: {
|
|
144
|
+
site: {
|
|
145
|
+
title: 'My Site',
|
|
146
|
+
url: 'https://example.com',
|
|
147
|
+
author: { name: 'Jane', email: 'jane@example.com' },
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**After:**
|
|
154
|
+
```ts
|
|
155
|
+
// app/app.config.ts
|
|
156
|
+
export default defineAppConfig({
|
|
157
|
+
site: {
|
|
158
|
+
title: 'My Site',
|
|
159
|
+
url: 'https://example.com',
|
|
160
|
+
author: { name: 'Jane', email: 'jane@example.com' },
|
|
161
|
+
},
|
|
162
|
+
})
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The `site` key is typed via `SiteConfig` from the core layer — `useAppConfig().site` has full TypeScript completion.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 2. `SiteAuthor` renamed to `Author`
|
|
170
|
+
|
|
171
|
+
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
|
+
|
|
173
|
+
**Before:**
|
|
174
|
+
```ts
|
|
175
|
+
import type { SiteAuthor } from '#layers/core/app/types/site'
|
|
176
|
+
|
|
177
|
+
const author: SiteAuthor = { name: 'Jane' }
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**After:**
|
|
181
|
+
```ts
|
|
182
|
+
import type { Author } from '#layers/core/app/types/site'
|
|
183
|
+
|
|
184
|
+
const author: Author = { name: 'Jane' }
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
`SiteConfig.author` still has the same shape — only the type name changed.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 3. Content author `url` renamed to `link`
|
|
192
|
+
|
|
193
|
+
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
|
+
|
|
195
|
+
**Zod schema (in your `content.config.ts`):**
|
|
196
|
+
```ts
|
|
197
|
+
// Before
|
|
198
|
+
authors: z.array(z.object({ name: z.string(), avatar: z.string().optional(), url: z.string().optional() }))
|
|
199
|
+
|
|
200
|
+
// After
|
|
201
|
+
authors: z.array(z.object({ name: z.string(), avatar: z.string().optional(), link: z.string().optional() }))
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Markdown frontmatter:**
|
|
205
|
+
```yaml
|
|
206
|
+
# Before
|
|
207
|
+
authors:
|
|
208
|
+
- name: Jane Doe
|
|
209
|
+
url: https://github.com/janedoe
|
|
210
|
+
|
|
211
|
+
# After
|
|
212
|
+
authors:
|
|
213
|
+
- name: Jane Doe
|
|
214
|
+
link: https://github.com/janedoe
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**TypeScript interface** — `ContentAuthor` now extends `Author` instead of being a standalone type:
|
|
218
|
+
```ts
|
|
219
|
+
import type { Author } from '#layers/core/app/types/site'
|
|
220
|
+
|
|
221
|
+
// ContentAuthor from the content layer
|
|
222
|
+
interface ContentAuthor extends Author {
|
|
223
|
+
avatar?: string
|
|
224
|
+
// inherits: name, email?, link?
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## 4. `BaseContent` base interface
|
|
231
|
+
|
|
232
|
+
A `BaseContent` interface was extracted from the shared fields across `BlogPost`, `PortfolioItem`, `GalleryItem`, and `ContentPage`. All four now extend it.
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
interface BaseContent {
|
|
236
|
+
title: string
|
|
237
|
+
description?: string
|
|
238
|
+
image?: string
|
|
239
|
+
tags?: string[]
|
|
240
|
+
date?: string
|
|
241
|
+
draft?: boolean
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
If you have custom types that replicate these fields, you can now extend `BaseContent` directly:
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
import type { BaseContent } from '#layers/content/app/types/content'
|
|
249
|
+
|
|
250
|
+
interface MyCustomPage extends BaseContent {
|
|
251
|
+
featuredVideo?: string
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 5. Feeds layer: collection wiring
|
|
258
|
+
|
|
259
|
+
Feeds are now driven by `feedsLayer.feed.collections` — an array of collection names to expose as feeds. The default is `['blog']`. Add more collections to get automatic feed routes for each.
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
// app/app.config.ts
|
|
263
|
+
export default defineAppConfig({
|
|
264
|
+
site: { ... },
|
|
265
|
+
feedsLayer: {
|
|
266
|
+
feed: {
|
|
267
|
+
limit: 30,
|
|
268
|
+
collections: ['blog'], // expose these collections as feeds
|
|
269
|
+
defaultCollection: 'blog', // used by /feed/rss shorthand routes
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
})
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Available feed URLs for each collection:
|
|
276
|
+
|
|
277
|
+
| URL | Format |
|
|
278
|
+
|-----|--------|
|
|
279
|
+
| `/feed/:collection/rss` | RSS 2.0 |
|
|
280
|
+
| `/feed/:collection/atom` | Atom 1.0 |
|
|
281
|
+
| `/feed/:collection/json` | JSON Feed 1.1 |
|
|
282
|
+
| `/feed/rss` | RSS for `defaultCollection` |
|
|
283
|
+
| `/feed/atom` | Atom for `defaultCollection` |
|
|
284
|
+
| `/feed/json` | JSON Feed for `defaultCollection` |
|
|
285
|
+
| `/feed` | JSON index of all configured feeds |
|
|
286
|
+
|
|
287
|
+
To expose portfolio items as a feed:
|
|
288
|
+
```ts
|
|
289
|
+
feedsLayer: {
|
|
290
|
+
feed: { collections: ['blog', 'portfolio'] }
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Netlify / static deployment: prerender collection routes
|
|
295
|
+
|
|
296
|
+
Feed routes are server routes — they aren't discoverable by the prerender crawler. The feeds layer automatically prerenders the shorthand routes (`/feed`, `/feed/rss`, `/feed/atom`, `/feed/json`), but **collection-specific routes must be listed explicitly** in your app's `nuxt.config.ts`:
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
nitro: {
|
|
300
|
+
prerender: {
|
|
301
|
+
routes: [
|
|
302
|
+
'/feed/blog/rss',
|
|
303
|
+
'/feed/blog/atom',
|
|
304
|
+
'/feed/blog/json',
|
|
305
|
+
// one set per collection in feedsLayer.feed.collections
|
|
306
|
+
],
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Without this, collection routes return 404 on Netlify and other static hosts.
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## 6. Feed autodiscovery in `<head>`
|
|
316
|
+
|
|
317
|
+
The feeds layer automatically injects `<link rel="alternate">` tags so RSS readers and browsers can discover feeds without cluttering every page with links for every collection.
|
|
318
|
+
|
|
319
|
+
**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
|
+
|
|
321
|
+
| Page | Links injected |
|
|
322
|
+
|------|---------------|
|
|
323
|
+
| `/`, `/about`, any non-collection page | 3 main site feeds |
|
|
324
|
+
| `/blog`, `/blog/hello-world` (if `blog` = `defaultCollection`) | 3 main site feeds (these already point to blog) |
|
|
325
|
+
| `/portfolio`, `/portfolio/project` (non-default collection) | 3 main site feeds + 3 portfolio feeds |
|
|
326
|
+
|
|
327
|
+
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
|
+
|
|
329
|
+
No action required. The collection a page belongs to is inferred from the first path segment matching an entry in `feedsLayer.feed.collections`.
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## Quick Reference
|
|
334
|
+
|
|
335
|
+
| Change | Action required |
|
|
336
|
+
|--------|----------------|
|
|
337
|
+
| Site metadata | Move `feedsLayer.site` → top-level `site` in `app.config.ts` |
|
|
338
|
+
| `SiteAuthor` type import | Rename to `Author` |
|
|
339
|
+
| Author `url` in frontmatter | Rename `url:` → `link:` in blog author blocks |
|
|
340
|
+
| Author `url` in Zod schema | Rename `url` → `link` in `authors` object schema |
|
|
341
|
+
| Collection feeds | Set `feedsLayer.feed.collections` in `app.config.ts` |
|
|
342
|
+
| Feed autodiscovery | Nothing — automatic via the feeds layer plugin |
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
# Migration Guide: v1.6.34 — Content Layer Collection Aliases & Section Disabling
|
|
347
|
+
|
|
348
|
+
Two new capabilities have been added to the content layer:
|
|
349
|
+
|
|
350
|
+
1. **Collection aliases** — reuse a collection schema under a custom name (e.g. `works` instead of `portfolio`)
|
|
351
|
+
2. **Section disabling** — suppress content routes you don't need via `app.config.ts`
|
|
352
|
+
|
|
353
|
+
Neither change is breaking. Existing apps using `portfolio`, `blog`, or `gallery` work exactly as before.
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## 1. Collection Aliases
|
|
358
|
+
|
|
359
|
+
### The problem
|
|
360
|
+
|
|
361
|
+
The content layer hard-codes the collection names `blog`, `portfolio`, and `gallery`. If your app wants a `works` section that uses the portfolio schema, you previously had to duplicate the entire Zod schema in your own `content.config.ts`.
|
|
362
|
+
|
|
363
|
+
### The solution
|
|
364
|
+
|
|
365
|
+
The layer now exports named schemas and factory functions from `content.config.ts`:
|
|
366
|
+
|
|
367
|
+
```ts
|
|
368
|
+
// Named schema exports:
|
|
369
|
+
contentCollectionSchema
|
|
370
|
+
blogCollectionSchema
|
|
371
|
+
portfolioCollectionSchema
|
|
372
|
+
galleryCollectionSchema
|
|
373
|
+
|
|
374
|
+
// Factory functions (return a ready-to-use defineCollection(...) object):
|
|
375
|
+
createContentCollection(source?: string)
|
|
376
|
+
createBlogCollection(source?: string)
|
|
377
|
+
createPortfolioCollection(source?: string)
|
|
378
|
+
createGalleryCollection(source?: string)
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Each factory defaults to the conventional source glob if you omit the argument.
|
|
382
|
+
|
|
383
|
+
### Registering a custom-named collection
|
|
384
|
+
|
|
385
|
+
In your app's `content.config.ts`, import the factory and register it under any name you like:
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
import { createPortfolioCollection, createBlogCollection } from '#layers/content/content.config'
|
|
389
|
+
|
|
390
|
+
export default defineContentConfig({
|
|
391
|
+
collections: {
|
|
392
|
+
blog: createBlogCollection(),
|
|
393
|
+
works: createPortfolioCollection('works/**/*.md'),
|
|
394
|
+
// gallery omitted — not needed
|
|
395
|
+
}
|
|
396
|
+
})
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Your markdown files now live at `content/works/`, and `queryCollection('works')` returns portfolio-shaped items.
|
|
400
|
+
|
|
401
|
+
### Querying the aliased collection
|
|
402
|
+
|
|
403
|
+
The layer also exports `createPortfolioComposables`, a factory that returns fully-wired `useItems` and `useItem` composables bound to your custom collection name:
|
|
404
|
+
|
|
405
|
+
```ts
|
|
406
|
+
// app/composables/useWorks.ts
|
|
407
|
+
import { createPortfolioComposables } from '#layers/content/app/composables/createPortfolioComposables'
|
|
408
|
+
|
|
409
|
+
const { useItems: useWorksItems, useItem: useWorksItem } = createPortfolioComposables('works')
|
|
410
|
+
export { useWorksItems, useWorksItem }
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
`useWorksItems` accepts the same options as `usePortfolioItems` (`featured`, `tags`, `limit`). `useWorksItem(slug)` fetches a single item by slug.
|
|
414
|
+
|
|
415
|
+
### Using Portfolio components with a custom collection
|
|
416
|
+
|
|
417
|
+
The `PortfolioList`, `PortfolioCard`, and `PortfolioDetail` components accept data via props — they don't query the collection directly. Pass your `works` data in to reuse them:
|
|
418
|
+
|
|
419
|
+
```vue
|
|
420
|
+
<PortfolioList :items="worksItems" />
|
|
421
|
+
<PortfolioDetail :item="worksItem" />
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## 2. Section Disabling
|
|
427
|
+
|
|
428
|
+
### The problem
|
|
429
|
+
|
|
430
|
+
Layer pages at `/blog`, `/portfolio`, and `/gallery` are always registered. Previously there was no way to suppress a route you didn't want without creating a 404 override page in your app.
|
|
431
|
+
|
|
432
|
+
### The solution
|
|
433
|
+
|
|
434
|
+
All content routes now check `useAppConfig().contentLayer.sections` at runtime and throw a 404 if a section is explicitly set to `false`.
|
|
435
|
+
|
|
436
|
+
### Disabling sections
|
|
437
|
+
|
|
438
|
+
In your app's `app.config.ts` (must be inside `app/`):
|
|
439
|
+
|
|
440
|
+
```ts
|
|
441
|
+
export default defineAppConfig({
|
|
442
|
+
contentLayer: {
|
|
443
|
+
sections: {
|
|
444
|
+
blog: true,
|
|
445
|
+
portfolio: false, // /portfolio and /portfolio/[slug] → 404
|
|
446
|
+
gallery: false, // /gallery and all nested routes → 404
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
})
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
All three flags default to `true` in the layer, so you only need to declare the ones you want to disable.
|
|
453
|
+
|
|
454
|
+
**Note:** The routes still exist at the Nuxt router level — they are compiled at build time from the layer's page files. Disabling returns a 404 response at runtime. Links to disabled routes will hit a 404 error page rather than being absent from the router.
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## Quick Reference
|
|
459
|
+
|
|
460
|
+
| Goal | How |
|
|
461
|
+
|---|---|
|
|
462
|
+
| Reuse portfolio schema as `works` | `works: createPortfolioCollection('works/**/*.md')` in `content.config.ts` |
|
|
463
|
+
| Query custom-named collection | `createPortfolioComposables('works')` → `useItems` / `useItem` |
|
|
464
|
+
| Disable the gallery section | `contentLayer: { sections: { gallery: false } }` in `app.config.ts` |
|
|
465
|
+
| Disable multiple sections | List each with `false` in `sections` |
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
# Migration Guide: v1.5.x → v1.6.0
|
|
470
|
+
|
|
471
|
+
v1.6.0 restructures the layout and content systems. The main theme is **opt-in chrome** — header, footer, and nav are no longer always-on, full-bleed pages now use `layout: false`, and the global Locomotive Scroll wrapper is gone.
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Breaking Changes
|
|
476
|
+
|
|
477
|
+
### 1. `grid.vue` layout now requires explicit props for header/footer
|
|
478
|
+
|
|
479
|
+
Header and footer are no longer rendered by default. Pages that relied on `layout: 'grid'` to get them must now pass props.
|
|
480
|
+
|
|
481
|
+
**Before (v1.5.x):**
|
|
482
|
+
```ts
|
|
483
|
+
definePageMeta({ layout: 'grid' })
|
|
484
|
+
// header + footer always rendered
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
**After (v1.6.0):**
|
|
488
|
+
```ts
|
|
489
|
+
// Opt-in to header and footer:
|
|
490
|
+
definePageMeta({
|
|
491
|
+
layout: { name: 'grid', props: { showHeader: true, showFooter: true } },
|
|
492
|
+
})
|
|
493
|
+
|
|
494
|
+
// No chrome needed (content-only page):
|
|
495
|
+
definePageMeta({ layout: 'grid' })
|
|
496
|
+
|
|
497
|
+
// Full-bleed pages (no mastmain grid at all):
|
|
498
|
+
definePageMeta({ layout: false })
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
Available props on `grid.vue` (all `boolean`, default `false`):
|
|
502
|
+
|
|
503
|
+
| Prop | Description |
|
|
504
|
+
|---|---|
|
|
505
|
+
| `showHeader` | Renders `<MastHeader>` |
|
|
506
|
+
| `showNav` | Renders `<MastNav>` |
|
|
507
|
+
| `showFooter` | Renders `<MastFooter>` |
|
|
508
|
+
| `showGridDebug` | Renders `<LayoutGridDebug>` overlay |
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
### 2. `MastScroller` removed
|
|
513
|
+
|
|
514
|
+
The global Locomotive Scroll wrapper in `default.vue` has been removed. Smooth scroll is now per-page via the `useSmoothScroll()` composable.
|
|
515
|
+
|
|
516
|
+
**Before (v1.5.x):**
|
|
517
|
+
```vue
|
|
518
|
+
<!-- default.vue automatically wrapped everything in MastScroller -->
|
|
519
|
+
<!-- No per-page setup required -->
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
**After (v1.6.0):**
|
|
523
|
+
```ts
|
|
524
|
+
// In any page that needs smooth scroll:
|
|
525
|
+
const { scrollTo, scrollToTop, velocity, progress } = useSmoothScroll()
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
Pages that don't call `useSmoothScroll()` will use native browser scroll — no behaviour change for those pages.
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
### 3. `LayoutPageContainer` deprecated → use `LayoutPage`
|
|
533
|
+
|
|
534
|
+
`LayoutPageContainer` has been superseded by `LayoutPage`. The legacy component still exists for backwards compatibility but is no longer maintained.
|
|
535
|
+
|
|
536
|
+
**Before (v1.5.x):**
|
|
537
|
+
```vue
|
|
538
|
+
<LayoutPageContainer title="My Page" :show-header="false">
|
|
539
|
+
<LayoutSection>...</LayoutSection>
|
|
540
|
+
</LayoutPageContainer>
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
**After (v1.6.0):**
|
|
544
|
+
```vue
|
|
545
|
+
<LayoutPage title="My Page">
|
|
546
|
+
<LayoutSection>...</LayoutSection>
|
|
547
|
+
</LayoutPage>
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
**Key difference:** `LayoutPage` defaults `showHeader` to `false`. If you need the page header block, pass it explicitly:
|
|
551
|
+
|
|
552
|
+
```vue
|
|
553
|
+
<LayoutPage title="My Page" :show-header="true">
|
|
554
|
+
...
|
|
555
|
+
</LayoutPage>
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
### 4. Full-bleed / animation pages must use `layout: false`
|
|
561
|
+
|
|
562
|
+
Pages with custom full-screen sections (WebGL canvases, GSAP hero animations, horizontal scroll tracks) must opt out of `LayoutMain` entirely. Using `layout: 'grid'` constrains them to a single `1fr` column which breaks full-width layouts.
|
|
563
|
+
|
|
564
|
+
```ts
|
|
565
|
+
// Full-bleed or animation-heavy page:
|
|
566
|
+
definePageMeta({ layout: false })
|
|
567
|
+
|
|
568
|
+
// With SSR disabled (e.g. WebGL):
|
|
569
|
+
definePageMeta({ ssr: false, layout: false })
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
**Rule of thumb:**
|
|
573
|
+
|
|
574
|
+
- Page uses `LayoutSection` + `LayoutGridItem`? → `layout: 'grid'` (with props as needed)
|
|
575
|
+
- Page uses custom full-width `<div>`/`<section>` elements? → `layout: false`
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
### 5. Content composables: `useContentData` replaces bare `useAsyncData`
|
|
580
|
+
|
|
581
|
+
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
|
+
|
|
583
|
+
**Before (v1.5.x):**
|
|
584
|
+
```ts
|
|
585
|
+
return useAsyncData('my-key', () => queryCollection('blog').all())
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
**After (v1.6.0):**
|
|
589
|
+
```ts
|
|
590
|
+
return useContentData('my-key', () => queryCollection('blog').all())
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
`useContentData` is exported from the content layer and available as a Nuxt auto-import. The API is identical to `useAsyncData`.
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
### 6. `payloadExtraction: 'client'` (nuxt.config.ts)
|
|
598
|
+
|
|
599
|
+
Add this experimental flag to your app's `nuxt.config.ts` if you use content collections or data-heavy pages. It moves payload extraction to the client, reducing SSR bundle size for content-driven routes.
|
|
600
|
+
|
|
601
|
+
```ts
|
|
602
|
+
export default defineNuxtConfig({
|
|
603
|
+
experimental: {
|
|
604
|
+
payloadExtraction: 'client',
|
|
605
|
+
},
|
|
606
|
+
})
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
---
|
|
610
|
+
|
|
611
|
+
## Non-Breaking Additions
|
|
612
|
+
|
|
613
|
+
- **`MastNav` component** — renders `<nav><slot /></nav>`. Enable via `showNav: true` on the `grid.vue` layout.
|
|
614
|
+
- **`showGridDebug` prop** — `LayoutGridDebug` is now controlled by the `showGridDebug` prop on `grid.vue` instead of always rendering.
|
|
615
|
+
|
|
616
|
+
---
|
|
617
|
+
|
|
618
|
+
## Quick Reference
|
|
619
|
+
|
|
620
|
+
| Pattern | v1.5.x | v1.6.0 |
|
|
621
|
+
|---|---|---|
|
|
622
|
+
| Grid page with header + footer | `layout: 'grid'` | `layout: { name: 'grid', props: { showHeader: true, showFooter: true } }` |
|
|
623
|
+
| Grid page, no chrome | `layout: 'grid'` | `layout: 'grid'` |
|
|
624
|
+
| Full-bleed / animation page | `layout: 'grid'` (broken) | `layout: false` |
|
|
625
|
+
| Page wrapper component | `<LayoutPageContainer>` | `<LayoutPage>` |
|
|
626
|
+
| Global smooth scroll | `MastScroller` in layout (auto) | `useSmoothScroll()` per-page |
|
|
627
|
+
| Content async data | `useAsyncData(...)` | `useContentData(...)` |
|