srcdev-nuxt-components 9.1.0 → 9.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/.claude/settings.json +2 -1
  2. package/.claude/skills/components/page-hero-highlights.md +60 -0
  3. package/.claude/skills/components/services-card-grid.md +110 -0
  4. package/.claude/skills/components/services-card.md +65 -30
  5. package/.claude/skills/components/site-navigation.md +120 -0
  6. package/.claude/skills/index.md +3 -2
  7. package/app/components/02.molecules/navigation/site-navigation/SiteNavigation.vue +780 -0
  8. package/app/components/02.molecules/navigation/site-navigation/stories/SiteNavigation.stories.ts +335 -0
  9. package/app/components/02.molecules/navigation/site-navigation/tests/SiteNavigation.spec.ts +328 -0
  10. package/app/components/02.molecules/navigation/site-navigation/tests/__snapshots__/SiteNavigation.spec.ts.snap +30 -0
  11. package/app/components/03.organisms/services/services-card/ServicesCard.vue +26 -10
  12. package/app/components/03.organisms/services/services-grids/ServicesCardGrid.vue +27 -3
  13. package/app/components/04.templates/page-hero-highlights/PageHeroHighlights.vue +36 -21
  14. package/app/components/04.templates/page-hero-highlights/PageHeroHighlightsHeader.vue +66 -0
  15. package/app/components/04.templates/page-hero-highlights/stories/PageHeroHighlights.stories.ts +50 -3
  16. package/app/components/04.templates/page-hero-highlights/stories/PageHeroHighlightsHeader.stories.ts +77 -0
  17. package/app/components/04.templates/page-hero-highlights/tests/PageHeroHighlights.spec.ts +15 -7
  18. package/app/components/04.templates/page-hero-highlights/tests/PageHeroHighlightsHeader.spec.ts +51 -0
  19. package/app/components/04.templates/page-hero-highlights/tests/__snapshots__/PageHeroHighlights.spec.ts.snap +1 -1
  20. package/app/layouts/default.vue +2 -0
  21. package/app/layouts/site-navigation-demo.vue +69 -0
  22. package/app/pages/page-hero-highlights.vue +15 -11
  23. package/app/pages/ui/navigation/site-navigation/about.vue +11 -0
  24. package/app/pages/ui/navigation/site-navigation/contact.vue +11 -0
  25. package/app/pages/ui/navigation/site-navigation/index.vue +11 -0
  26. package/app/pages/ui/navigation/site-navigation/portfolio.vue +11 -0
  27. package/app/pages/ui/navigation/site-navigation/services.vue +11 -0
  28. package/app/pages/ui/services/services-cards.vue +16 -1
  29. package/nuxt.config.ts +7 -0
  30. package/package.json +6 -6
  31. package/.claude/skills/components/treatment-consultant.md +0 -128
@@ -3,18 +3,26 @@
3
3
  <NuxtLayout name="default">
4
4
  <template #layout-content>
5
5
  <PageHeroHighlights
6
+ tag="section"
6
7
  max-width="1064px"
7
8
  content-align="start"
9
+ :content-panel="true"
8
10
  :highlights-equal-widths="false"
9
11
  highlights-justify="start"
10
12
  :highlight-title-baseline="true"
11
13
  :style-class-passthrough="['mbe-32']"
12
14
  >
13
- <template #header>
14
- <div class="some-header-content">
15
- <p class="page-heading-1">Dashboard</p>
16
- <p class="page-body-normal">Overview of your account activity and key metrics.</p>
17
- </div>
15
+ <template #header="{ headingId }">
16
+ <PageHeroHighlightsHeader>
17
+ <template #start>
18
+ <h1 :id="headingId" class="page-heading-1">Dashboard</h1>
19
+ <p class="page-body-normal">Overview of your account activity and key metrics.</p>
20
+ </template>
21
+ <template #end>
22
+ <h1 :id="headingId" class="page-heading-1">Dashboard</h1>
23
+ <p class="page-body-normal">Overview of your account activity and key metrics.</p>
24
+ </template>
25
+ </PageHeroHighlightsHeader>
18
26
  </template>
19
27
  <template #highlights>
20
28
  <div class="highlight">
@@ -59,12 +67,8 @@ useHead({
59
67
  <style lang="css">
60
68
  .page-hero-highlights-page {
61
69
  .page-hero-highlights {
62
- .header-row {
63
- .header-slot {
64
- .some-header-content {
65
- padding-block: 4rem 3rem;
66
- }
67
- }
70
+ .page-hero-highlights-header {
71
+ padding-block: 4rem 3rem;
68
72
  }
69
73
 
70
74
  .content-row {
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div>
3
+ <h1>About</h1>
4
+ <p>This is the About page. The active indicator in the navigation above should be sitting under "About".</p>
5
+ </div>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ definePageMeta({ layout: "site-navigation-demo" });
10
+ useHead({ title: "SiteNavigation Demo — About" });
11
+ </script>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div>
3
+ <h1>Contact</h1>
4
+ <p>This is the Contact page. The active indicator in the navigation above should be sitting under "Contact".</p>
5
+ </div>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ definePageMeta({ layout: "site-navigation-demo" });
10
+ useHead({ title: "SiteNavigation Demo — Contact" });
11
+ </script>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div>
3
+ <h1>Home</h1>
4
+ <p>Welcome to the SiteNavigation component demo. Resize the window to see the burger menu collapse, and navigate between pages to see the active indicator update.</p>
5
+ </div>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ definePageMeta({ layout: "site-navigation-demo" });
10
+ useHead({ title: "SiteNavigation Demo — Home" });
11
+ </script>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div>
3
+ <h1>Portfolio</h1>
4
+ <p>This is the Portfolio page. The active indicator in the navigation above should be sitting under "Portfolio".</p>
5
+ </div>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ definePageMeta({ layout: "site-navigation-demo" });
10
+ useHead({ title: "SiteNavigation Demo — Portfolio" });
11
+ </script>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div>
3
+ <h1>Services</h1>
4
+ <p>This is the Services page. The active indicator in the navigation above should be sitting under "Services".</p>
5
+ </div>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ definePageMeta({ layout: "site-navigation-demo" });
10
+ useHead({ title: "SiteNavigation Demo — Services" });
11
+ </script>
@@ -8,7 +8,11 @@
8
8
  </LayoutRow>
9
9
 
10
10
  <LayoutRow tag="div" variant="content" :style-class-passthrough="['mbe-20']">
11
- <ServicesCardGrid :services-data="servicesData ?? []" />
11
+ <ServicesCardGrid
12
+ :services-data="servicesData ?? []"
13
+ :eyebrow-config="{ fontSize: 'large' }"
14
+ :hero-config="{ tag: 'h2', fontSize: 'heading' }"
15
+ />
12
16
  </LayoutRow>
13
17
  </template>
14
18
  </NuxtLayout>
@@ -38,5 +42,16 @@ if (servicesData.value.length === 0) {
38
42
 
39
43
  <style lang="css">
40
44
  .page-services-card-grid {
45
+ /* Page specific styles here */
46
+ .services-card-grid {
47
+ --_gap: 4rem;
48
+ --_column-min-width: 250px;
49
+
50
+ .services-card {
51
+ --_eyebrow-text-margin-block: 0.8rem 0;
52
+ --_hero-text-margin-block: 2rem 1rem;
53
+ --_description-text-colour: var(--colour-text-secondary);
54
+ }
55
+ }
41
56
  }
42
57
  </style>
package/nuxt.config.ts CHANGED
@@ -5,6 +5,8 @@ const { resolve } = createResolver(import.meta.url);
5
5
  const isStandalone = !!process.env.SRCDEV_STANDALONE;
6
6
 
7
7
  export default defineNuxtConfig({
8
+ // debug: !isProduction,
9
+ debug: false,
8
10
  devtools: { enabled: true },
9
11
 
10
12
  // Server-only secrets — Nuxt reads matching NUXT_* env vars automatically.
@@ -104,6 +106,11 @@ export default defineNuxtConfig({
104
106
  // (avoids /_vercel/image which has no source images in storybook-static/)
105
107
  provider: process.env.STORYBOOK ? "none" : undefined,
106
108
  },
109
+ vite: {
110
+ optimizeDeps: {
111
+ include: ["@oddbird/css-anchor-positioning"],
112
+ },
113
+ },
107
114
  vue: {
108
115
  runtimeCompiler: true,
109
116
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "9.1.0",
4
+ "version": "9.1.2",
5
5
  "main": "nuxt.config.ts",
6
6
  "types": "types.d.ts",
7
7
  "license": "MIT",
@@ -84,10 +84,10 @@
84
84
  "@iconify-json/akar-icons": "1.2.7",
85
85
  "@iconify-json/bi": "1.2.7",
86
86
  "@iconify-json/bitcoin-icons": "1.2.4",
87
- "@iconify-json/gravity-ui": "1.2.11",
87
+ "@iconify-json/gravity-ui": "1.2.12",
88
88
  "@iconify-json/ic": "*",
89
89
  "@iconify-json/lucide": "*",
90
- "@iconify-json/material-symbols": "1.2.53",
90
+ "@iconify-json/material-symbols": "1.2.64",
91
91
  "@iconify-json/mdi": "1.2.3",
92
92
  "@iconify-json/radix-icons": "*",
93
93
  "@nuxt/eslint": "1.13.0",
@@ -98,6 +98,7 @@
98
98
  "@storybook/addon-docs": "10.0.7",
99
99
  "@storybook/builder-vite": "10.0.7",
100
100
  "@vue/test-utils": "2.4.6",
101
+ "@vueuse/core": "14.2.1",
101
102
  "eslint": "9.39.2",
102
103
  "eslint-plugin-storybook": "10.0.7",
103
104
  "happy-dom": "20.5.0",
@@ -125,10 +126,9 @@
125
126
  "@nuxt/image": "2.0.0",
126
127
  "@oddbird/css-anchor-positioning": "0.9.0",
127
128
  "@pinia/nuxt": "0.11.3",
128
- "@vueuse/core": "14.2.0",
129
- "@vueuse/motion": "^3.0.3",
129
+ "@vueuse/motion": "3.0.3",
130
130
  "focus-trap-vue": "4.1.0",
131
- "nuxt": "4.3.0",
131
+ "nuxt": "4.4.2",
132
132
  "pinia": "3.0.4",
133
133
  "pinia-plugin-persistedstate": "4.7.1",
134
134
  "zod": "4.3.6"
@@ -1,128 +0,0 @@
1
- # TreatmentConsultant Component
2
-
3
- ## Overview
4
-
5
- `TreatmentConsultant` is a self-contained 5-step hair consultation wizard (`03.organisms`). It collects a user's hair profile across four steps (hair type, natural colour, dream colour, style & treatments) and renders a personalised recommendation on the final step.
6
-
7
- All data — hair types, colour swatches, treatments, and the recommendation matrix — is hard-coded inside the component. There are no external data dependencies.
8
-
9
- ## Props
10
-
11
- | Prop | Type | Default | Purpose |
12
- |------|------|---------|---------|
13
- | `autoAdvance` | `boolean` | `false` | Automatically advances to the next step immediately after each selection (steps 0–2). On step 3, a "View Results" button still appears when `allowMultipleTreatments` is also `true`. |
14
- | `allowMultipleTreatments` | `boolean` | `false` | Enables multi-select on the treatments step. When `false`, selecting a treatment deselects any previous choice. |
15
- | `styleClassPassthrough` | `string \| string[]` | `[]` | Standard passthrough prop for HOC styling. |
16
-
17
- ## Basic usage
18
-
19
- ```vue
20
- <TreatmentConsultant :auto-advance="true" :allow-multiple-treatments="true" />
21
- ```
22
-
23
- ## Steps
24
-
25
- | Index | Label | Behaviour |
26
- |-------|-------|-----------|
27
- | 0 | Hair Type | Single select — straight, wavy, curly, coily |
28
- | 1 | Your Colour | Single select — 7 natural colour swatches |
29
- | 2 | Dream Colour | Single select — 8 desired colours (incl. "none") |
30
- | 3 | Style & Treatments | Single or multi-select (see `allowMultipleTreatments`) |
31
- | 4 | Results | Read-only — recommendation, treatment cards, summary, CTA |
32
-
33
- ## Navigation rules
34
-
35
- - Completed steps (index < current) are clickable to go back.
36
- - Future steps are disabled via `aria-disabled` + `tabindex="-1"`.
37
- - Steps 0–2 require a selection before proceeding (`canProceed`).
38
- - Step 3 is always passable — treatments are optional.
39
- - `reset()` clears all state and returns to step 0.
40
-
41
- ## Treatment selection logic
42
-
43
- - Selecting `"none"` clears all other treatments (and vice versa).
44
- - In multi-select mode, selecting a treatment automatically removes any conflicting ones (defined by each treatment's `excludes` array).
45
- - Conflicting treatments are visually marked with a `lucide:ban` icon and a "Conflicts with X" label.
46
-
47
- ## Treatment–Colour compatibility
48
-
49
- Some treatments clash with same-day colour services: `keratin-smoothing`, `perm`, `relaxer`, `japanese-straightening`. These show a "Not same-day as colour" badge in the results view when a colour change was also selected.
50
-
51
- ## Recommendation matrix
52
-
53
- `getColourRecommendation(naturalColour, desiredColour, hairType)` maps the combination to:
54
-
55
- ```ts
56
- interface Recommendation {
57
- suitability: "great" | "possible" | "difficult" | "not-recommended";
58
- method: string; // e.g. "Semi-Permanent", "Bleach Required"
59
- notes: string; // one-line summary
60
- details: string[]; // bullet points
61
- }
62
- ```
63
-
64
- Curly or coily hair type appends an extra conditioning note to `details`. Unmapped combinations fall back to `suitability: "possible"` with a consultation prompt.
65
-
66
- ## Image assets
67
-
68
- Swatch JPEGs live at `public/images/treatment-consultant/`:
69
- - `swatch-{light-blonde,dark-blonde,light-brown,dark-brown,red,black,grey-white}.jpeg` (natural colours)
70
- - `swatch-dream-{blonde,brown,red,black,grey-silver,vivid,balayage}.jpeg` (desired colours)
71
-
72
- All `NuxtImg` usages include explicit `width` and `height` (128×128 in options, 96×96 in results summary).
73
-
74
- ## Styling
75
-
76
- Amber-toned dark theme. Tokens scoped to `.treatment-consultant`:
77
-
78
- ```css
79
- .treatment-consultant {
80
- --_canvas-color: var(--amber-09);
81
- --_canvas-text: var(--amber-02);
82
- --_surface-active: var(--amber-10);
83
- --_surface-checked: var(--green-09);
84
- --_surface-excluded: color-mix(in srgb, var(--red-07) 10%, transparent);
85
- /* … */
86
- }
87
- ```
88
-
89
- Fonts: Inter (body), Playfair Display (accent).
90
- Step transitions: `<Transition name="slide" mode="out-in">`.
91
- Results cards use `v-motion` with staggered enter animations.
92
-
93
- ## Local style override scaffold
94
-
95
- ```vue
96
- <TreatmentConsultant :style-class-passthrough="['my-consultant']" />
97
-
98
- <style>
99
- /* ─── TreatmentConsultant local overrides ──────────────────────────
100
- Colours, borders, geometry only — do not override behaviour.
101
- Delete this block if no overrides are needed.
102
- ─────────────────────────────────────────────────────────────────── */
103
- .treatment-consultant {
104
- &.my-consultant {
105
- /* Canvas background */
106
- /* --_canvas-color: var(--brand-surface); */
107
-
108
- /* Option selected state */
109
- /* --_surface-checked: var(--brand-accent); */
110
- /* --_border-checked: var(--brand-accent-border); */
111
- }
112
- }
113
- </style>
114
- ```
115
-
116
- See [component-local-style-override.md](../component-local-style-override.md) for the full pattern.
117
-
118
- ## CTA (results step)
119
-
120
- - "Book Consultation" links to `/#contact` (hardcoded anchor).
121
- - "Start Again" calls `reset()`.
122
-
123
- ## Notes
124
-
125
- - Component is auto-imported in Nuxt — no import needed.
126
- - No slots — entirely self-contained UI and data.
127
- - `styleClassPassthrough` is accepted but not currently wired to `useStyleClassPassthrough` inside the component.
128
- - Storybook story at `Organisms/TreatmentConsultant` — controls for both props.