srcdev-nuxt-components 9.5.6 → 9.6.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/.claude/skills/component-compliance-checklist.md +6 -2
- package/.claude/skills/components/breadcrumb.md +5 -0
- package/.claude/skills/components/display-pill.md +2 -0
- package/.claude/skills/components/input-button.md +3 -0
- package/.claude/skills/components/navigation-items.md +1 -0
- package/.claude/skills/components/opening-hours.md +12 -0
- package/.claude/skills/components/price-list.md +10 -1
- package/.claude/skills/components/responsive-header.md +74 -0
- package/.claude/skills/components/service-detail.md +32 -0
- package/.claude/skills/components/service-summary.md +8 -0
- package/.claude/skills/components/services-card-grid.md +5 -3
- package/.claude/skills/components/services-card.md +22 -12
- package/.claude/skills/components/site-header.md +2 -0
- package/.claude/skills/components/slider-gallery.md +10 -4
- package/.claude/skills/components/tab-navigation.md +25 -9
- package/.claude/skills/index.md +1 -2
- package/.claude/skills/storybook-add-story.md +14 -0
- package/.vscode/srcdev-component-responsive-header.code-snippets +13 -1
- package/.vscode/srcdev-component-service-detail.code-snippets +1 -0
- package/.vscode/srcdev-component-service-summary.code-snippets +3 -1
- package/.vscode/srcdev-component-services-card.code-snippets +38 -36
- package/.vscode/srcdev-component-services-grids.code-snippets +2 -1
- package/.vscode/srcdev-component-site-header.code-snippets +3 -1
- package/.vscode/srcdev-component-tab-navigation.code-snippets +1 -1
- package/app/components/01.atoms/display-pill/CONSUMER-STYLING.md +3 -0
- package/app/components/01.atoms/display-pill/DisplayPill.vue +5 -2
- package/app/components/01.atoms/navigation/breadcrumb/Breadcrumb.vue +16 -4
- package/app/components/01.atoms/navigation/breadcrumb/CONSUMER-STYLING.md +28 -5
- package/app/components/01.atoms/navigation/breadcrumb/stories/Breadcrumb.stories.ts +94 -0
- package/app/components/01.atoms/navigation/breadcrumb/tests/Breadcrumb.spec.ts +27 -0
- package/app/components/02.molecules/navigation/tab-navigation/CONSUMER-STYLING.md +52 -11
- package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +55 -23
- package/app/components/02.molecules/navigation/tab-navigation/stories/TabNavigation.stories.ts +176 -257
- package/app/components/02.molecules/navigation/tab-navigation/tests/TabNavigation.spec.ts +42 -2
- package/app/components/02.molecules/opening-hours/CONSUMER-STYLING.md +11 -1
- package/app/components/02.molecules/opening-hours/OpeningHours.vue +71 -43
- package/app/components/02.molecules/opening-hours/stories/OpeningHours.stories.ts +138 -6
- package/app/components/02.molecules/opening-hours/tests/OpeningHours.spec.ts +53 -0
- package/app/components/02.molecules/opening-hours/tests/__snapshots__/OpeningHours.spec.ts.snap +1 -1
- package/app/components/02.molecules/opening-hours/tests/buildOpeningHoursSpecification.spec.ts +37 -1
- package/app/components/02.molecules/price-list/CONSUMER-STYLING.md +17 -5
- package/app/components/02.molecules/price-list/PriceList.vue +32 -9
- package/app/components/02.molecules/price-list/stories/PriceList.stories.ts +125 -29
- package/app/components/02.molecules/price-list/tests/PriceList.spec.ts +20 -0
- package/app/components/03.organisms/google-reviews/stories/GoogleReviews.stories.ts +9 -4
- package/app/components/03.organisms/image-galleries/slider-gallery/CONSUMER-STYLING.md +19 -1
- package/app/components/03.organisms/image-galleries/slider-gallery/SliderGallery.vue +65 -7
- package/app/components/03.organisms/image-galleries/slider-gallery/stories/SliderGallery.stories.ts +201 -63
- package/app/components/03.organisms/image-galleries/slider-gallery/tests/SliderGallery.spec.ts +41 -2
- package/app/components/03.organisms/image-galleries/slider-gallery/tests/__snapshots__/SliderGallery.spec.ts.snap +6 -6
- package/app/components/03.organisms/responsive-header/CONSUMER-STYLING.md +18 -0
- package/app/components/03.organisms/responsive-header/NavigationItems.vue +56 -18
- package/app/components/03.organisms/responsive-header/ResponsiveHeader.vue +106 -31
- package/app/components/03.organisms/responsive-header/stories/ResponsiveHeader.stories.ts +201 -18
- package/app/components/03.organisms/responsive-header/tests/.nuxt/app.config.mjs +21 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/components.d.ts +66 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/imports.d.ts +30 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/manifest/meta/test.json +1 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/app.config.d.ts +35 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/build.d.ts +23 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/builder-env.d.ts +1 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/components.d.ts +71 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/imports.d.ts +386 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/middleware.d.ts +11 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/modules.d.ts +79 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/nitro-layouts.d.ts +17 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/nitro-nuxt.d.ts +64 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/plugins.d.ts +29 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/runtime-config.d.ts +32 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/shared-imports.d.ts +10 -0
- package/app/components/03.organisms/responsive-header/tests/.nuxt/types/vue-shim.d.ts +0 -0
- package/app/components/03.organisms/responsive-header/tests/NavigationItems.spec.ts +36 -0
- package/app/components/03.organisms/responsive-header/tests/ResponsiveHeader.spec.ts +131 -6
- package/app/components/03.organisms/responsive-header/tests/__snapshots__/ResponsiveHeader.spec.ts.snap +9 -9
- package/app/components/03.organisms/responsive-header/tests/node_modules/.cache/nuxt/chrome-workspace.json +1 -0
- package/app/components/03.organisms/services/service-detail/CONSUMER-STYLING.md +92 -41
- package/app/components/03.organisms/services/service-detail/ServiceDetail.vue +198 -73
- package/app/components/03.organisms/services/service-detail/stories/ServiceDetail.stories.ts +157 -9
- package/app/components/03.organisms/services/service-detail/tests/ServiceDetail.spec.ts +58 -0
- package/app/components/03.organisms/services/service-detail/tests/__snapshots__/ServiceDetail.spec.ts.snap +4 -3
- package/app/components/03.organisms/services/service-summary/CONSUMER-STYLING.md +30 -0
- package/app/components/03.organisms/services/service-summary/ServiceSummary.vue +32 -8
- package/app/components/03.organisms/services/service-summary/stories/ServiceSummary.stories.ts +147 -0
- package/app/components/03.organisms/services/service-summary/tests/ServiceSummary.spec.ts +26 -0
- package/app/components/03.organisms/services/service-summary/tests/__snapshots__/ServiceSummary.spec.ts.snap +1 -1
- package/app/components/03.organisms/services/services-card/CONSUMER-STYLING.md +104 -63
- package/app/components/03.organisms/services/services-card/ServicesCard.vue +92 -66
- package/app/components/03.organisms/services/services-card/stories/ServicesCard.stories.ts +194 -27
- package/app/components/03.organisms/services/services-card/tests/ServicesCard.spec.ts +34 -8
- package/app/components/03.organisms/services/services-card/tests/__snapshots__/ServicesCard.spec.ts.snap +8 -8
- package/app/components/03.organisms/services/services-grids/CONSUMER-STYLING.md +9 -0
- package/app/components/03.organisms/services/services-grids/ServicesCardGrid.vue +2 -1
- package/app/components/03.organisms/services/services-grids/stories/ServiceSummaryGrid.stories.ts +46 -6
- package/app/components/03.organisms/services/services-grids/stories/ServicesCardGrid.stories.ts +89 -11
- package/app/components/03.organisms/services/services-grids/tests/ServicesCardGrid.spec.ts +8 -0
- package/app/components/03.organisms/services/services-grids/tests/__snapshots__/ServiceSummaryGrid.spec.ts.snap +3 -3
- package/app/components/03.organisms/services/services-grids/tests/__snapshots__/ServicesCardGrid.spec.ts.snap +24 -24
- package/app/components/03.organisms/site-header/SiteHeader.vue +8 -0
- package/app/components/03.organisms/site-header/tests/__snapshots__/SiteHeader.spec.ts.snap +1 -1
- package/app/components/05.forms/input-button/CONSUMER-STYLING.md +8 -0
- package/app/components/05.forms/input-button/InputButton.vue +3 -1
- package/app/composables/tests/useAnchorScroll.spec.ts +8 -0
- package/app/composables/useAnchorScroll.ts +1 -1
- package/app/utils/opening-hours.ts +23 -2
- package/nuxt.config.ts +1 -1
- package/package.json +1 -1
- package/.claude/skills/components/site-navigation.md +0 -145
- package/.vscode/srcdev-component-site-navigation.code-snippets +0 -38
- package/app/components/02.molecules/navigation/site-navigation/CONSUMER-STYLING.md +0 -109
- package/app/components/02.molecules/navigation/site-navigation/SiteNavigation.vue +0 -751
- package/app/components/02.molecules/navigation/site-navigation/stories/SiteNavigation.stories.ts +0 -356
- package/app/components/02.molecules/navigation/site-navigation/tests/SiteNavigation.spec.ts +0 -367
- package/app/components/02.molecules/navigation/site-navigation/tests/__snapshots__/SiteNavigation.spec.ts.snap +0 -30
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<nav
|
|
3
|
+
v-if="visibleItems.length"
|
|
3
4
|
ref="navRef"
|
|
4
5
|
class="tab-navigation"
|
|
5
6
|
:class="[
|
|
@@ -11,8 +12,8 @@
|
|
|
11
12
|
>
|
|
12
13
|
<ul v-if="!isCollapsed || !isLoaded" ref="navListRef" class="tab-nav-list" @mouseleave="hoveredItemHref = null">
|
|
13
14
|
<li
|
|
14
|
-
v-for="item in
|
|
15
|
-
:key="item.href"
|
|
15
|
+
v-for="(item, index) in visibleItems"
|
|
16
|
+
:key="`${index}-${item.href}`"
|
|
16
17
|
:data-href="item.href"
|
|
17
18
|
:class="[
|
|
18
19
|
item.cssName,
|
|
@@ -55,9 +56,9 @@
|
|
|
55
56
|
class="tab-nav-burger"
|
|
56
57
|
:class="{ 'is-open': isMenuOpen }"
|
|
57
58
|
variant="tertiary"
|
|
58
|
-
:button-text="isMenuOpen ?
|
|
59
|
+
:button-text="isMenuOpen ? closeMenuLabel : openMenuLabel"
|
|
59
60
|
:aria-expanded="String(isMenuOpen)"
|
|
60
|
-
aria-controls="
|
|
61
|
+
:aria-controls="panelId"
|
|
61
62
|
@click="toggleMenu"
|
|
62
63
|
>
|
|
63
64
|
<template #iconOnly>
|
|
@@ -79,14 +80,14 @@
|
|
|
79
80
|
|
|
80
81
|
<div
|
|
81
82
|
v-if="showCollapsed"
|
|
82
|
-
id="
|
|
83
|
+
:id="panelId"
|
|
83
84
|
class="tab-nav-panel"
|
|
84
85
|
:class="{ 'is-open': isMenuOpen }"
|
|
85
86
|
:inert="!isMenuOpen ? true : undefined"
|
|
86
87
|
>
|
|
87
88
|
<div class="tab-nav-panel-inner">
|
|
88
89
|
<ul class="tab-nav-panel-list">
|
|
89
|
-
<li v-for="item in
|
|
90
|
+
<li v-for="(item, index) in visibleItems" :key="`${index}-${item.href}`" :class="item.cssName">
|
|
90
91
|
<a
|
|
91
92
|
v-if="item.href?.startsWith('#')"
|
|
92
93
|
:href="item.href"
|
|
@@ -133,6 +134,10 @@ interface Props {
|
|
|
133
134
|
anchorScrollOffset?: number | (() => number);
|
|
134
135
|
/** aria-label on the nav landmark — override for localisation. */
|
|
135
136
|
ariaLabel?: string;
|
|
137
|
+
/** Burger button label while the menu is closed — override for localisation. */
|
|
138
|
+
openMenuLabel?: string;
|
|
139
|
+
/** Burger button label while the menu is open — override for localisation. */
|
|
140
|
+
closeMenuLabel?: string;
|
|
136
141
|
}
|
|
137
142
|
|
|
138
143
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -140,8 +145,22 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
140
145
|
styleClassPassthrough: () => [],
|
|
141
146
|
anchorScrollOffset: undefined,
|
|
142
147
|
ariaLabel: "Site navigation",
|
|
148
|
+
openMenuLabel: "Open navigation menu",
|
|
149
|
+
closeMenuLabel: "Close navigation menu",
|
|
143
150
|
});
|
|
144
151
|
|
|
152
|
+
if (import.meta.dev) {
|
|
153
|
+
console.warn(
|
|
154
|
+
"TabNavigation is deprecated: use ResponsiveHeader, which also handles #anchor links " +
|
|
155
|
+
"(anchorScrollOffset) and collapses item by item. See \"Migrating from TabNavigation\" in " +
|
|
156
|
+
".claude/skills/components/responsive-header.md."
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Items with no text would render links with no accessible name.
|
|
161
|
+
const visibleItems = computed(() => (props.navItemData.main ?? []).filter((item) => item.text?.trim()));
|
|
162
|
+
const panelId = useId();
|
|
163
|
+
|
|
145
164
|
const { navRef, navListRef, isCollapsed, isLoaded, isMenuOpen, isActiveItem, toggleMenu, closeMenu } =
|
|
146
165
|
useNavCollapse("tab-nav-loaded");
|
|
147
166
|
|
|
@@ -149,7 +168,7 @@ const { handleNavClick, activeHash } = useAnchorScroll({ offset: props.anchorScr
|
|
|
149
168
|
|
|
150
169
|
onMounted(() => {
|
|
151
170
|
if (!activeHash.value) {
|
|
152
|
-
const firstHashItem =
|
|
171
|
+
const firstHashItem = visibleItems.value.find((item) => item.href?.startsWith("#"));
|
|
153
172
|
if (firstHashItem?.href) activeHash.value = firstHashItem.href;
|
|
154
173
|
}
|
|
155
174
|
});
|
|
@@ -209,25 +228,22 @@ watch(
|
|
|
209
228
|
/* ─── Public token API ────────────────────────────────────────────── */
|
|
210
229
|
|
|
211
230
|
/* Horizontal nav */
|
|
212
|
-
--_link-color: var(--tab-nav-link-color, var(--
|
|
231
|
+
--_link-color: var(--tab-nav-link-color, var(--theme-text));
|
|
232
|
+
--_link-hover-color: var(--tab-nav-link-hover-color, var(--theme-accent));
|
|
213
233
|
--_link-size: var(--tab-nav-link-size, 1.6rem);
|
|
214
234
|
--_link-tracking: var(--tab-nav-link-tracking, 0.06em);
|
|
215
235
|
--_link-weight: var(--tab-nav-link-weight, 400);
|
|
216
236
|
--_nav-transition: var(--tab-nav-transition, 250ms ease);
|
|
217
237
|
|
|
218
238
|
/* Panel */
|
|
219
|
-
--_panel-
|
|
220
|
-
--tab-nav-panel-border-color,
|
|
221
|
-
color-mix(in oklch, var(--slate-01, #c0847a) 35%, transparent)
|
|
222
|
-
);
|
|
223
|
-
--_panel-link-color: var(--tab-nav-panel-link-color, var(--slate-01, currentColor));
|
|
239
|
+
--_panel-link-color: var(--tab-nav-panel-link-color, var(--_link-color));
|
|
224
240
|
--_panel-slide-duration: var(--tab-nav-panel-slide-duration, 350ms);
|
|
225
241
|
--_panel-slide-easing: var(--tab-nav-panel-slide-easing, cubic-bezier(0.4, 0, 0.2, 1));
|
|
226
242
|
|
|
227
243
|
/* Burger */
|
|
228
244
|
--_burger-bar-height: var(--tab-nav-burger-height, 1.5px);
|
|
229
245
|
--_burger-bar-gap: var(--tab-nav-burger-gap, 5px);
|
|
230
|
-
--_burger-color: var(--tab-nav-burger-color, var(--
|
|
246
|
+
--_burger-color: var(--tab-nav-burger-color, var(--_link-color));
|
|
231
247
|
--_burger-transition: var(--tab-nav-burger-transition, 300ms ease);
|
|
232
248
|
|
|
233
249
|
/* ─────────────────────────────────────────────────────────────────── */
|
|
@@ -287,12 +303,17 @@ watch(
|
|
|
287
303
|
|
|
288
304
|
&:hover,
|
|
289
305
|
&:focus-visible {
|
|
290
|
-
color: var(--
|
|
306
|
+
color: var(--_link-hover-color);
|
|
291
307
|
outline: none;
|
|
292
308
|
}
|
|
293
309
|
|
|
310
|
+
&:focus-visible {
|
|
311
|
+
outline: var(--tab-nav-focus-ring-width, 2px) solid var(--tab-nav-focus-ring-colour, currentColor);
|
|
312
|
+
outline-offset: var(--tab-nav-focus-ring-offset, 2px);
|
|
313
|
+
}
|
|
314
|
+
|
|
294
315
|
&.router-link-exact-active {
|
|
295
|
-
color: var(--tab-nav-link-active-color, var(--
|
|
316
|
+
color: var(--tab-nav-link-active-color, var(--_link-color));
|
|
296
317
|
}
|
|
297
318
|
}
|
|
298
319
|
}
|
|
@@ -390,12 +411,12 @@ watch(
|
|
|
390
411
|
|
|
391
412
|
&.is-open {
|
|
392
413
|
grid-template-rows: 1fr;
|
|
393
|
-
border-block-start-color: var(--
|
|
414
|
+
border-block-start-color: var(--tab-nav-panel-border-color, color-mix(in oklch, var(--_link-color) 20%, transparent));
|
|
394
415
|
}
|
|
395
416
|
|
|
396
417
|
.tab-nav-panel-inner {
|
|
397
418
|
overflow: hidden;
|
|
398
|
-
background-color: var(--tab-nav-panel-bg, var(--page-bg,
|
|
419
|
+
background-color: var(--tab-nav-panel-bg, var(--page-bg, var(--theme-surface-subtle)));
|
|
399
420
|
}
|
|
400
421
|
|
|
401
422
|
.tab-nav-panel-list {
|
|
@@ -404,14 +425,18 @@ watch(
|
|
|
404
425
|
padding: 0;
|
|
405
426
|
|
|
406
427
|
li {
|
|
407
|
-
border-block-end: 1px solid
|
|
428
|
+
border-block-end: 1px solid
|
|
429
|
+
var(--tab-nav-panel-item-border, color-mix(in oklch, var(--_panel-link-color) 12%, transparent));
|
|
408
430
|
|
|
409
431
|
&:last-child {
|
|
410
432
|
border-block-end: none;
|
|
411
433
|
}
|
|
412
434
|
|
|
413
435
|
&:hover {
|
|
414
|
-
background-color:
|
|
436
|
+
background-color: var(
|
|
437
|
+
--tab-nav-panel-item-hover-bg,
|
|
438
|
+
color-mix(in oklch, var(--_panel-link-color) 5%, transparent)
|
|
439
|
+
);
|
|
415
440
|
}
|
|
416
441
|
}
|
|
417
442
|
|
|
@@ -426,18 +451,25 @@ watch(
|
|
|
426
451
|
text-decoration: none;
|
|
427
452
|
padding-block: var(--tab-nav-panel-padding-block, 1.4rem);
|
|
428
453
|
padding-inline: var(--tab-nav-panel-padding-inline, 1.5rem);
|
|
454
|
+
overflow-wrap: anywhere;
|
|
455
|
+
min-inline-size: 0;
|
|
429
456
|
position: relative;
|
|
430
457
|
z-index: 1;
|
|
431
458
|
transition: color var(--_nav-transition);
|
|
432
459
|
|
|
433
460
|
&:hover,
|
|
434
461
|
&:focus-visible {
|
|
435
|
-
color: var(--tab-nav-panel-link-hover-color, var(--
|
|
462
|
+
color: var(--tab-nav-panel-link-hover-color, var(--_link-hover-color));
|
|
436
463
|
outline: none;
|
|
437
464
|
}
|
|
438
465
|
|
|
466
|
+
&:focus-visible {
|
|
467
|
+
outline: var(--tab-nav-focus-ring-width, 2px) solid var(--tab-nav-focus-ring-colour, currentColor);
|
|
468
|
+
outline-offset: calc(-1 * var(--tab-nav-focus-ring-width, 2px));
|
|
469
|
+
}
|
|
470
|
+
|
|
439
471
|
&.router-link-exact-active {
|
|
440
|
-
color: var(--tab-nav-panel-link-active-color, var(--
|
|
472
|
+
color: var(--tab-nav-panel-link-active-color, var(--_panel-link-color));
|
|
441
473
|
}
|
|
442
474
|
}
|
|
443
475
|
}
|
|
@@ -504,7 +536,7 @@ watch(
|
|
|
504
536
|
bottom: 0;
|
|
505
537
|
height: 2px;
|
|
506
538
|
pointer-events: none;
|
|
507
|
-
background-color: var(--tab-nav-decorator-indicator-color, var(--
|
|
539
|
+
background-color: var(--tab-nav-decorator-indicator-color, var(--theme-accent));
|
|
508
540
|
z-index: 3;
|
|
509
541
|
}
|
|
510
542
|
|