Skip to content

Commit 5f76d20

Browse files
authored
Merge pull request #14 from srcdev/responsive-header-refactor
Responsive header refactor
2 parents f96286e + a727e83 commit 5f76d20

12 files changed

Lines changed: 923 additions & 553 deletions

File tree

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# CSS Nesting Conventions
2+
3+
## Overview
4+
5+
This project uses **native CSS nesting** (W3C CSS Nesting spec), not Sass/SCSS. They look similar but behave differently in one important way: native CSS does not support BEM-style `&` concatenation for child element selectors.
6+
7+
## The key rule
8+
9+
> `&` must be followed by a combinator (space, `>`, `~`, `+`) or a selector starting with `.`, `#`, `:`, `[`, or `*`. It **cannot** be followed by a bare identifier or `__` prefix.
10+
11+
## ❌ What NOT to do — Sass-style BEM concatenation
12+
13+
```css
14+
/* Sass/SCSS — does NOT work in native CSS */
15+
.demo-controls {
16+
padding: 1.6rem;
17+
18+
&__heading { /* ← Invalid native CSS — esbuild converts to :is(__heading) */
19+
font-size: 1.1rem;
20+
}
21+
22+
&__fields { /* ← Invalid native CSS */
23+
display: flex;
24+
}
25+
}
26+
```
27+
28+
**Why it silently fails**: esbuild converts `&__heading` to `:is(__heading)`, which tries to match an HTML element named `__heading`. No such element exists, so the styles are never applied. There's no error — just missing styles.
29+
30+
The build will show this warning:
31+
```
32+
▲ [WARNING] Cannot use type selector "__heading" directly after nesting selector "&" [css-syntax-error]
33+
CSS nesting syntax does not allow the "&" selector to come before a type selector.
34+
```
35+
36+
## ✅ Correct patterns
37+
38+
### Nested descendant (preferred for BEM child elements)
39+
40+
```css
41+
.demo-controls {
42+
padding: 1.6rem;
43+
44+
& .demo-controls__heading { /* space + full class name */
45+
font-size: 1.1rem;
46+
}
47+
48+
& .demo-controls__fields {
49+
display: flex;
50+
}
51+
}
52+
```
53+
54+
### Flat top-level rules (also valid — avoids repetition for deeply nested structures)
55+
56+
```css
57+
.demo-controls {
58+
padding: 1.6rem;
59+
}
60+
61+
.demo-controls__heading {
62+
font-size: 1.1rem;
63+
}
64+
65+
.demo-controls__fields {
66+
display: flex;
67+
}
68+
```
69+
70+
### Same-element modifier (this IS valid)
71+
72+
```css
73+
/* & followed by a class — matches the same element that also has this class */
74+
.button {
75+
background: blue;
76+
77+
&.button--large { /* ← valid: & immediately followed by . */
78+
padding: 2rem;
79+
}
80+
81+
&:hover { /* ← valid: & immediately followed by : */
82+
background: darkblue;
83+
}
84+
85+
&[disabled] { /* ← valid: & immediately followed by [ */
86+
opacity: 0.5;
87+
}
88+
}
89+
```
90+
91+
### Pseudo-elements and pseudo-classes
92+
93+
```css
94+
.component {
95+
&::before { content: ""; } /* ✅ valid */
96+
&::after { content: ""; } /* ✅ valid */
97+
&:focus { outline: auto; } /* ✅ valid */
98+
&:not(.active) { opacity: 0.5; } /* ✅ valid */
99+
}
100+
```
101+
102+
### Media / container queries inside a rule
103+
104+
```css
105+
.component {
106+
grid-template-columns: 1fr;
107+
108+
@media (width >= 768px) {
109+
grid-template-columns: 1fr 2fr; /* ✅ valid — query wraps the property */
110+
}
111+
}
112+
```
113+
114+
## Spot-check during review
115+
116+
If you see `&__` or `&-` in a `.vue` `<style lang="css">` block, it's Sass syntax and will not work. Convert it to `& .full-class-name` or lift it to a top-level rule.
117+
118+
## Related
119+
120+
- `CLAUDE.md` → Styling Methodology section
121+
- `css-grid-max-width-gutters.md` — example of correct native nesting in a grid utility

.claude/skills/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
3333
├── component-dynamic-slots.md — named dynamic slots ($slots iteration) vs indexed dynamic slots (itemCount pattern)
3434
├── component-local-style-override.md — styleClassPassthrough + scoped style block for per-usage visual customisation
3535
├── component-prop-driven-container-layout.md — vary CSS grid layout inside @container queries using data-* attribute selectors
36+
├── css-nesting-conventions.md — native CSS nesting rules: why &__child Sass BEM concatenation silently breaks, correct patterns
3637
├── css-grid-max-width-gutters.md — cap a centre grid column width by growing gutters, with start/center alignment variants
3738
├── css-animation-utilities.md — scroll-driven animation utility classes: scroller-x (carousel), entry-zoom-reveal, entry-slide-in, entry-exit-blur, auto-rotate
3839
├── component-aria-landmark.md — useAriaLabelledById composable: aria-labelledby for section/main/article/aside tags
@@ -44,6 +45,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
4445
├── new-app-scaffold.md — scaffold a new Nuxt consumer app extending this layer (package.json, nuxt.config, app structure, CLAUDE.md)
4546
├── qa-panel.md — collapsible dev-only panel for toggling component props live on a page (demo pages and consuming apps)
4647
├── release-notes.md — produce release notes as a fenced markdown block from git log
48+
├── pull-request-description.md — produce a PR description as a fenced markdown block from git diff vs main
4749
├── composable-canonical-url.md — useCanonicalUrl: set <link rel="canonical"> from runtimeConfig.public.canonicalHost; layout setup, node types
4850
├── composable-whatsapp.md — useWhatsApp: open pre-filled wa.me link from form payload; runtime config, security, usage
4951
├── composable-zod-validation.md — useZodValidation: schema-driven form validation, error binding, submit flow, API error push
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Pull Request Description
2+
3+
## Overview
4+
5+
When asked to create a pull request description, produce a fenced markdown code block (` ```markdown `) so the content can be copied and pasted directly into GitHub's PR body field without formatting being stripped.
6+
7+
## Steps
8+
9+
### 1. Identify the base branch
10+
11+
Run `git log --oneline main..HEAD` to list all commits on the current branch since it diverged from `main`.
12+
13+
### 2. Review what changed
14+
15+
Run `git diff main...HEAD --stat` for a file-level summary, then `git diff main...HEAD` for the full diff. Focus on intent, not just mechanics.
16+
17+
### 3. Produce a fenced markdown block
18+
19+
Always wrap the output in a ` ```markdown ` code fence — never render it as plain markdown.
20+
21+
## Format
22+
23+
```markdown
24+
## Summary
25+
26+
One or two sentences explaining what this PR does and why. No bullet points here — write it as prose.
27+
28+
## Changes
29+
30+
- **`FileOrComponentName`** — what changed and why
31+
- Keep each bullet to one line where possible
32+
33+
## Testing
34+
35+
- How the change was verified (unit tests, manual check, build passing, etc.)
36+
- Note any areas that couldn't be covered automatically
37+
38+
## Notes
39+
40+
Any caveats, follow-up tickets, or decisions worth flagging for reviewers (optional — omit if nothing to say).
41+
```
42+
43+
## Notes
44+
45+
- Only include sections that have content — omit empty headings (especially `Notes` if there's nothing to flag)
46+
- Lead with the user-facing or functional change; CSS/test/doc tidy-ups can be secondary bullets
47+
- Keep the tone factual — describe what changed, not the effort involved
48+
- Do not include "Co-Authored-By" or other git trailer lines — those belong in the commit message, not the PR body

.vscode/settings.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,10 @@
3636
"editor.trimAutoWhitespace": "explicit"
3737
}
3838
},
39-
// Use workspace TypeScript (5.9.x) instead of VS Code's built-in version
40-
"typescript.tsdk": "node_modules/typescript/lib",
41-
4239
// More info: https://open-props.style/#getting-started
4340
"cssvar.files": ["assets/styles/main.css"],
4441
"cssvar.ignore": [],
4542
"cssvar.extensions": ["css", "sss", "postcss", "vue", "ts"],
46-
"js/ts.tsdk.path": "node_modules/typescript/lib"
43+
"js/ts.tsdk.path": "node_modules/typescript/lib",
44+
"git.addAICoAuthor": "off"
4745
}

Claude.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ See `.claude/skills/storybook-add-font.md` for the step-by-step process to add a
301301
8. **Incorrect type casting**: Use `as unknown as CustomType` for component instances
302302
9. **Unmocked browser APIs**: Always mock ResizeObserver, IntersectionObserver, etc.
303303
10. **Missing DOM element casting**: Cast to HTMLElement when accessing style properties
304+
11. **Sass-style BEM nesting in native CSS**: Never use `&__child` or `&-modifier` concatenation — this is Sass syntax and does not work in native CSS. esbuild silently converts `&__foo` to `:is(__foo)` which matches nothing. Use `& .block__child` (descendant selector) or a top-level `.block__child {}` rule instead. See `.claude/skills/css-nesting-conventions.md`.
304305

305306
## Development Workflow
306307

0 commit comments

Comments
 (0)