srcdev-nuxt-components 9.0.6 → 9.0.7
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.
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# LayoutRow Component
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`LayoutRow` is a CSS grid-based layout wrapper that controls how wide its content sits within the page. It uses a named-column grid system (full → popout → content → inset-content) so content can be precisely placed at different widths without custom CSS. It is the primary layout primitive for page sections.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## How to use this skill
|
|
10
|
+
|
|
11
|
+
When a developer asks to add a `LayoutRow`, follow the interactive flow below. Do not skip to writing code — work through the questions first to ensure the right variant is chosen. Developers unfamiliar with this system will not know what the options mean without guidance.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Step 1 — Read the current context
|
|
16
|
+
|
|
17
|
+
Before asking anything, read the file the developer is working in and any parent components or pages to determine:
|
|
18
|
+
|
|
19
|
+
1. **Is this LayoutRow inside another LayoutRow?**
|
|
20
|
+
- If yes, note the parent's `variant`. The inner grid resets relative to the parent's inner width, not the page. Warn the developer (see side effects below).
|
|
21
|
+
- If no, this is page-level — the grid spans the full viewport.
|
|
22
|
+
|
|
23
|
+
2. **What is the effective current max width?**
|
|
24
|
+
Report this before asking any questions. Examples:
|
|
25
|
+
- "This row will sit at **page level** — the grid spans the full viewport width."
|
|
26
|
+
- "This row is nested inside a `LayoutRow variant="content"` — its maximum available width is **1064px**, not the full viewport."
|
|
27
|
+
- "This row is nested inside `variant="inset-content"` — maximum available width is **840px**."
|
|
28
|
+
|
|
29
|
+
3. **What content is already nearby?** Note any sibling LayoutRows, headings, or components to give context for alignment.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Step 2 — Ask what the row will contain
|
|
34
|
+
|
|
35
|
+
Ask the developer what is going in this row. Do not assume. Examples to listen for:
|
|
36
|
+
|
|
37
|
+
| Content type | Suggested variant |
|
|
38
|
+
|---|---|
|
|
39
|
+
| Hero, banner, full-bleed image or video | `full` or `full-content` |
|
|
40
|
+
| Coloured background band containing constrained content | `full` wrapping inner `content` |
|
|
41
|
+
| Card grid, media grid, feature row | `popout` |
|
|
42
|
+
| Standard page section (text + components) | `content` |
|
|
43
|
+
| Long-form article, blog post, form | `inset-content` |
|
|
44
|
+
| Sidebar or aside | `inset-content` |
|
|
45
|
+
|
|
46
|
+
Give a suggestion based on their answer, but confirm before proceeding.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Step 3 — Present the width and margin consequences
|
|
51
|
+
|
|
52
|
+
Once you have a candidate variant (or 2–3 options), show the developer exactly what they will get at common viewport widths. Use this reference table:
|
|
53
|
+
|
|
54
|
+
### Approximate rendered widths by variant
|
|
55
|
+
|
|
56
|
+
| Viewport | `inset-content` | `content` | `popout` | `full` |
|
|
57
|
+
|----------|----------------|-----------|----------|--------|
|
|
58
|
+
| 375px (mobile) | ~355px | ~355px | ~355px | 375px |
|
|
59
|
+
| 768px (tablet) | ~748px | ~748px | ~748px | 768px |
|
|
60
|
+
| 1080px | **840px** | ~1060px | ~1060px | 1080px |
|
|
61
|
+
| 1280px | **840px** | **1064px** | ~1260px | 1280px |
|
|
62
|
+
| 1440px | **840px** | **1064px** | **1400px** | 1440px |
|
|
63
|
+
| 1920px | **840px** | **1064px** | **1400px** | 1920px |
|
|
64
|
+
|
|
65
|
+
> Bold = the variant has reached its maximum and is now letterboxed. Below that threshold it fills the available width minus the minimum gutter (default `1rem` = 10px each side).
|
|
66
|
+
|
|
67
|
+
### Approximate margin (space each side at wider viewports)
|
|
68
|
+
|
|
69
|
+
| Variant | @ 1080px | @ 1280px | @ 1440px | @ 1920px |
|
|
70
|
+
|---------|---------|---------|---------|---------|
|
|
71
|
+
| `inset-content` | ~120px | ~220px | ~300px | ~540px |
|
|
72
|
+
| `content` | ~10px | ~108px | ~188px | ~428px |
|
|
73
|
+
| `popout` | ~10px | ~10px | ~20px | ~260px |
|
|
74
|
+
| `full` | 0 | 0 | 0 | 0 |
|
|
75
|
+
|
|
76
|
+
Phrase this conversationally. For example:
|
|
77
|
+
> "With `content`, your section will max out at **1064px** wide. On a 1440px screen that leaves about **188px of margin on each side**. On a 1280px screen it's tighter — around **108px** each side. Does that sound right for what you're building?"
|
|
78
|
+
|
|
79
|
+
If they want more breathing room → suggest `inset-content`.
|
|
80
|
+
If they want the content to feel wider → suggest `popout`.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Step 4 — Flag side effects for the chosen variant
|
|
85
|
+
|
|
86
|
+
Before writing code, flag any relevant consequences:
|
|
87
|
+
|
|
88
|
+
**`full` or `full-width`** — Content is completely edge-to-edge with no gutter at any viewport width. If text is placed directly inside without a nested layout wrapper it will touch screen edges on mobile. Suggest `full-content` or a nested `content` LayoutRow for the text.
|
|
89
|
+
|
|
90
|
+
**`full-content`** — Adds `--minimum-content-padding` (default `1rem` = 10px) as inline padding. Still full-bleed visually at most viewport sizes. Good for coloured bands.
|
|
91
|
+
|
|
92
|
+
**`full-content-nopad`** — Truly zero padding. Only use if the child component manages its own edge spacing.
|
|
93
|
+
|
|
94
|
+
**`popout`** — At viewports below ~1400px the popout track shrinks. Between 1280–1440px the margin is very small (~10–20px each side). If the design needs consistent breathing room at 1280px, `content` may be a better choice.
|
|
95
|
+
|
|
96
|
+
**`inset-content` or `content` nested inside a `full` LayoutRow** — This is a common and valid pattern: `full` gives edge-to-edge background, the inner row constrains the text/content. Confirm this is intentional if you see it.
|
|
97
|
+
|
|
98
|
+
**Nested LayoutRow (any variant)** — The inner grid takes the parent's `.layout-row-inner` width as 100%. The `full` variant of the inner LayoutRow will only be as wide as the parent's inner column, not the viewport. Warn the developer if this is surprising.
|
|
99
|
+
|
|
100
|
+
**`-start` / `-end` variants** — These only set `grid-column-start` or `grid-column-end`, not both. Content will stretch to the opposite edge of the grid unless the other end is also constrained. Best for intentional asymmetric designs.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Step 5 — Confirm the remaining props
|
|
105
|
+
|
|
106
|
+
Once the variant is agreed, ask about:
|
|
107
|
+
|
|
108
|
+
1. **`tag`** — what HTML element? Default is `div`. Common choices:
|
|
109
|
+
- `section` — for a thematic page section (most common)
|
|
110
|
+
- `article` — for self-contained content
|
|
111
|
+
- `header` / `footer` — for page-level header/footer rows
|
|
112
|
+
- `main` — for the primary content area (only once per page)
|
|
113
|
+
- `nav` — for navigation rows
|
|
114
|
+
|
|
115
|
+
2. **`id`** — needed if this section is a scroll target, skip-link destination, or anchor in navigation. Ask if unsure.
|
|
116
|
+
|
|
117
|
+
3. **`isLandmark`** — default `false`. Only set `true` if the row is a navigable landmark that needs keyboard focus. Usually `tag="section"` is sufficient — `isLandmark` is rarely needed.
|
|
118
|
+
|
|
119
|
+
4. **`styleClassPassthrough`** — any extra classes for spacing, background colour, etc.?
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Props reference
|
|
124
|
+
|
|
125
|
+
| Prop | Type | Default | Required |
|
|
126
|
+
|------|------|---------|----------|
|
|
127
|
+
| `variant` | see variant list | — | **yes** |
|
|
128
|
+
| `tag` | `"div" \| "section" \| "article" \| "aside" \| "header" \| "footer" \| "main" \| "nav" \| "ul" \| "ol"` | `"div"` | no |
|
|
129
|
+
| `id` | `string` | `null` | no |
|
|
130
|
+
| `isLandmark` | `boolean` | `false` | no |
|
|
131
|
+
| `styleClassPassthrough` | `string \| string[]` | `[]` | no |
|
|
132
|
+
| `dataTestid` | `string` | `"layout-row"` | no |
|
|
133
|
+
|
|
134
|
+
All valid `variant` values:
|
|
135
|
+
`full` · `full-start` · `full-end` · `popout` · `popout-start` · `popout-end` · `content` · `content-start` · `content-end` · `inset-content` · `inset-content-start` · `inset-content-end` · `full-width` · `full-content` · `full-content-nopad`
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Usage examples
|
|
140
|
+
|
|
141
|
+
### Standard section
|
|
142
|
+
|
|
143
|
+
```vue
|
|
144
|
+
<LayoutRow variant="content" tag="section">
|
|
145
|
+
<p>Sits within the 1064px content track with ~188px margin at 1440px.</p>
|
|
146
|
+
</LayoutRow>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Full-bleed hero, text constrained inside
|
|
150
|
+
|
|
151
|
+
```vue
|
|
152
|
+
<LayoutRow variant="full" tag="section">
|
|
153
|
+
<!-- Background is edge-to-edge -->
|
|
154
|
+
<LayoutRow variant="content">
|
|
155
|
+
<HeroText tag="h1" :textContent="[{ text: 'Welcome' }]" />
|
|
156
|
+
</LayoutRow>
|
|
157
|
+
</LayoutRow>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Coloured band (full width + safe padding)
|
|
161
|
+
|
|
162
|
+
```vue
|
|
163
|
+
<LayoutRow variant="full-content" tag="section" :styleClassPassthrough="['bg-brand']">
|
|
164
|
+
<p>Full-width background, content padded by --minimum-content-padding.</p>
|
|
165
|
+
</LayoutRow>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Long-form article body
|
|
169
|
+
|
|
170
|
+
```vue
|
|
171
|
+
<LayoutRow variant="inset-content" tag="article">
|
|
172
|
+
<p>Comfortable reading column at 840px max.</p>
|
|
173
|
+
</LayoutRow>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Feature / card grid (popout)
|
|
177
|
+
|
|
178
|
+
```vue
|
|
179
|
+
<LayoutRow variant="popout" tag="section">
|
|
180
|
+
<!-- Card grid, image gallery, etc. -->
|
|
181
|
+
</LayoutRow>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## CSS custom properties
|
|
187
|
+
|
|
188
|
+
Override in consuming app to adjust all track sizes globally:
|
|
189
|
+
|
|
190
|
+
| Property | Default | Effect |
|
|
191
|
+
|----------|---------|--------|
|
|
192
|
+
| `--popout-max-width` | `1400px` | Maximum width of the popout track |
|
|
193
|
+
| `--content-max-width` | `1064px` | Maximum width of the content track |
|
|
194
|
+
| `--inset-content-max-width` | `840px` | Maximum width of the inset-content track |
|
|
195
|
+
| `--minimum-content-padding` | `1rem` (10px) | Minimum gutter at small viewports |
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Notes
|
|
200
|
+
|
|
201
|
+
- Auto-imported in Nuxt — no import needed.
|
|
202
|
+
- `.layout-row-inner` has `container-type: inline-size` — children can use CSS container queries.
|
|
203
|
+
- The `full`, `full-content`, and `full-width` variants all map to `grid-column: full` — the difference is only whether inline padding is applied.
|
|
204
|
+
- `isLandmark` adds `tabindex="0"` and `aria-label="Layout Row Landmark"`. Prefer a semantic `tag` over this prop where possible.
|
package/.claude/skills/index.md
CHANGED
|
@@ -27,6 +27,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
|
|
|
27
27
|
└── components/
|
|
28
28
|
├── eyebrow-text.md — EyebrowText props, usage patterns, styling
|
|
29
29
|
├── hero-text.md — HeroText props, usage patterns, styling
|
|
30
|
+
├── layout-row.md — LayoutRow variant guide, width/margin decisions, usage patterns
|
|
30
31
|
└── link-text.md — LinkText props, slots, usage patterns, styling
|
|
31
32
|
```
|
|
32
33
|
|