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
|
@@ -4,7 +4,7 @@ exports[`ServiceSummaryGrid > renders correct HTML structure 1`] = `
|
|
|
4
4
|
"<div class="service-summary-grid">
|
|
5
5
|
<div class="service-summary">
|
|
6
6
|
<div class="service-summary__grid">
|
|
7
|
-
<div class="service-summary__image-wrapper"><img data-nuxt-img="" srcset="/_ipx/
|
|
7
|
+
<div class="service-summary__image-wrapper"><img width="1080" height="1080" data-nuxt-img="" srcset="/_ipx/s_1080x1080/images/locs-installation.jpg 1x, /_ipx/s_2160x2160/images/locs-installation.jpg 2x" alt="Locs Installation" loading="eager" fetchpriority="high" class="service-summary__image" src="/_ipx/s_1080x1080/images/locs-installation.jpg"></div>
|
|
8
8
|
<div class="service-summary__info-wrapper service-summary__info-wrapper--align-center">
|
|
9
9
|
<div class="eyebrow-text large">Subtitle for Locs Installation</div>
|
|
10
10
|
<h2 id="v-0-0-0" class="hero-text mb-20 title axis-horizontal">
|
|
@@ -17,7 +17,7 @@ exports[`ServiceSummaryGrid > renders correct HTML structure 1`] = `
|
|
|
17
17
|
</div>
|
|
18
18
|
<div class="service-summary">
|
|
19
19
|
<div class="service-summary__grid">
|
|
20
|
-
<div class="service-summary__image-wrapper"><img data-nuxt-img="" srcset="/_ipx/
|
|
20
|
+
<div class="service-summary__image-wrapper"><img width="1080" height="1080" data-nuxt-img="" srcset="/_ipx/s_1080x1080/images/locs-retwist.jpg 1x, /_ipx/s_2160x2160/images/locs-retwist.jpg 2x" alt="Locs Retwist" loading="eager" fetchpriority="auto" class="service-summary__image" src="/_ipx/s_1080x1080/images/locs-retwist.jpg"></div>
|
|
21
21
|
<div class="service-summary__info-wrapper service-summary__info-wrapper--align-center">
|
|
22
22
|
<div class="eyebrow-text large">Subtitle for Locs Retwist</div>
|
|
23
23
|
<h2 id="v-0-0-1" class="hero-text mb-20 title axis-horizontal">
|
|
@@ -30,7 +30,7 @@ exports[`ServiceSummaryGrid > renders correct HTML structure 1`] = `
|
|
|
30
30
|
</div>
|
|
31
31
|
<div class="service-summary">
|
|
32
32
|
<div class="service-summary__grid">
|
|
33
|
-
<div class="service-summary__image-wrapper"><img data-nuxt-img="" srcset="/_ipx/
|
|
33
|
+
<div class="service-summary__image-wrapper"><img width="1080" height="1080" data-nuxt-img="" srcset="/_ipx/s_1080x1080/images/colour-treatment.jpg 1x, /_ipx/s_2160x2160/images/colour-treatment.jpg 2x" alt="Colour Treatment" loading="lazy" fetchpriority="auto" class="service-summary__image" src="/_ipx/s_1080x1080/images/colour-treatment.jpg"></div>
|
|
34
34
|
<div class="service-summary__info-wrapper service-summary__info-wrapper--align-center">
|
|
35
35
|
<div class="eyebrow-text large">Subtitle for Colour Treatment</div>
|
|
36
36
|
<h2 id="v-0-0-2" class="hero-text mb-20 title axis-horizontal">
|
|
@@ -3,20 +3,20 @@
|
|
|
3
3
|
exports[`ServicesCardGrid > renders correct HTML structure 1`] = `
|
|
4
4
|
"<div class="services-card-grid">
|
|
5
5
|
<div class="services-card">
|
|
6
|
-
<div class="grid-stack image-wrapper">
|
|
7
|
-
<div class="grid-stack__layer"><img data-nuxt-img="" srcset="/_ipx/
|
|
6
|
+
<div class="grid-stack services-card-image-wrapper">
|
|
7
|
+
<div class="grid-stack__layer"><img width="640" height="853" data-nuxt-img="" srcset="/_ipx/s_640x853/images/locs-installation.jpg 1x, /_ipx/s_1280x1706/images/locs-installation.jpg 2x" alt="Locs Installation" loading="lazy" class="services-card-image" src="/_ipx/s_640x853/images/locs-installation.jpg"></div>
|
|
8
8
|
<div class="grid-stack__layer"></div>
|
|
9
9
|
</div>
|
|
10
|
-
<div class="details
|
|
10
|
+
<div class="services-card-details">
|
|
11
11
|
<div class="eyebrow-text large">Subtitle for Locs Installation</div>
|
|
12
12
|
<h2 class="hero-text heading axis-horizontal">
|
|
13
13
|
<!--v-if--><span class="text-block-0 normal">Locs Installation</span>
|
|
14
14
|
</h2>
|
|
15
|
-
<div class="description">Short description for Locs Installation.</div>
|
|
16
|
-
<div class="footer">
|
|
17
|
-
<div class="meta">
|
|
18
|
-
<div class="meta-duration">60 mins</div>
|
|
19
|
-
<div class="meta-price">£50</div>
|
|
15
|
+
<div class="services-card-description">Short description for Locs Installation.</div>
|
|
16
|
+
<div class="services-card-footer">
|
|
17
|
+
<div class="services-card-meta">
|
|
18
|
+
<div class="services-card-meta-duration">60 mins</div>
|
|
19
|
+
<div class="services-card-meta-price">£50</div>
|
|
20
20
|
</div><a href="/services/locs-installation" data-testid="input-button" data-theme="default" class="input-button secondary mbs-24 is-link">
|
|
21
21
|
<!--v-if-->
|
|
22
22
|
<!--v-if--><span class="button-text">Enquire about Locs Installation</span><span class="btn-icon right"><span class="iconify i-mdi:arrow-right icon" aria-hidden="true"></span></span>
|
|
@@ -26,20 +26,20 @@ exports[`ServicesCardGrid > renders correct HTML structure 1`] = `
|
|
|
26
26
|
</div>
|
|
27
27
|
</div>
|
|
28
28
|
<div class="services-card">
|
|
29
|
-
<div class="grid-stack image-wrapper">
|
|
30
|
-
<div class="grid-stack__layer"><img data-nuxt-img="" srcset="/_ipx/
|
|
29
|
+
<div class="grid-stack services-card-image-wrapper">
|
|
30
|
+
<div class="grid-stack__layer"><img width="640" height="853" data-nuxt-img="" srcset="/_ipx/s_640x853/images/locs-retwist.jpg 1x, /_ipx/s_1280x1706/images/locs-retwist.jpg 2x" alt="Locs Retwist" loading="lazy" class="services-card-image" src="/_ipx/s_640x853/images/locs-retwist.jpg"></div>
|
|
31
31
|
<div class="grid-stack__layer"></div>
|
|
32
32
|
</div>
|
|
33
|
-
<div class="details
|
|
33
|
+
<div class="services-card-details">
|
|
34
34
|
<div class="eyebrow-text large">Subtitle for Locs Retwist</div>
|
|
35
35
|
<h2 class="hero-text heading axis-horizontal">
|
|
36
36
|
<!--v-if--><span class="text-block-0 normal">Locs Retwist</span>
|
|
37
37
|
</h2>
|
|
38
|
-
<div class="description">Short description for Locs Retwist.</div>
|
|
39
|
-
<div class="footer">
|
|
40
|
-
<div class="meta">
|
|
41
|
-
<div class="meta-duration">60 mins</div>
|
|
42
|
-
<div class="meta-price">£50</div>
|
|
38
|
+
<div class="services-card-description">Short description for Locs Retwist.</div>
|
|
39
|
+
<div class="services-card-footer">
|
|
40
|
+
<div class="services-card-meta">
|
|
41
|
+
<div class="services-card-meta-duration">60 mins</div>
|
|
42
|
+
<div class="services-card-meta-price">£50</div>
|
|
43
43
|
</div><a href="/services/locs-retwist" data-testid="input-button" data-theme="default" class="input-button secondary mbs-24 is-link">
|
|
44
44
|
<!--v-if-->
|
|
45
45
|
<!--v-if--><span class="button-text">Enquire about Locs Retwist</span><span class="btn-icon right"><span class="iconify i-mdi:arrow-right icon" aria-hidden="true"></span></span>
|
|
@@ -49,20 +49,20 @@ exports[`ServicesCardGrid > renders correct HTML structure 1`] = `
|
|
|
49
49
|
</div>
|
|
50
50
|
</div>
|
|
51
51
|
<div class="services-card">
|
|
52
|
-
<div class="grid-stack image-wrapper">
|
|
53
|
-
<div class="grid-stack__layer"><img data-nuxt-img="" srcset="/_ipx/
|
|
52
|
+
<div class="grid-stack services-card-image-wrapper">
|
|
53
|
+
<div class="grid-stack__layer"><img width="640" height="853" data-nuxt-img="" srcset="/_ipx/s_640x853/images/colour-treatment.jpg 1x, /_ipx/s_1280x1706/images/colour-treatment.jpg 2x" alt="Colour Treatment" loading="lazy" class="services-card-image" src="/_ipx/s_640x853/images/colour-treatment.jpg"></div>
|
|
54
54
|
<div class="grid-stack__layer"></div>
|
|
55
55
|
</div>
|
|
56
|
-
<div class="details
|
|
56
|
+
<div class="services-card-details">
|
|
57
57
|
<div class="eyebrow-text large">Subtitle for Colour Treatment</div>
|
|
58
58
|
<h2 class="hero-text heading axis-horizontal">
|
|
59
59
|
<!--v-if--><span class="text-block-0 normal">Colour Treatment</span>
|
|
60
60
|
</h2>
|
|
61
|
-
<div class="description">Short description for Colour Treatment.</div>
|
|
62
|
-
<div class="footer">
|
|
63
|
-
<div class="meta">
|
|
64
|
-
<div class="meta-duration">60 mins</div>
|
|
65
|
-
<div class="meta-price">£50</div>
|
|
61
|
+
<div class="services-card-description">Short description for Colour Treatment.</div>
|
|
62
|
+
<div class="services-card-footer">
|
|
63
|
+
<div class="services-card-meta">
|
|
64
|
+
<div class="services-card-meta-duration">60 mins</div>
|
|
65
|
+
<div class="services-card-meta-price">£50</div>
|
|
66
66
|
</div><a href="/services/colour-treatment" data-testid="input-button" data-theme="default" class="input-button secondary mbs-24 is-link">
|
|
67
67
|
<!--v-if-->
|
|
68
68
|
<!--v-if--><span class="button-text">Enquire about Colour Treatment</span><span class="btn-icon right"><span class="iconify i-mdi:arrow-right icon" aria-hidden="true"></span></span>
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
:main-nav-aria-label="mainNavAriaLabel"
|
|
21
21
|
:secondary-nav-aria-label="secondaryNavAriaLabel"
|
|
22
22
|
:overflow-menu-aria-label="overflowMenuAriaLabel"
|
|
23
|
+
:overflow-button-label="overflowButtonLabel"
|
|
24
|
+
:submenu-aria-label="submenuAriaLabel"
|
|
23
25
|
>
|
|
24
26
|
<template v-if="slots.secondaryNavigation" #secondaryNavigation>
|
|
25
27
|
<slot name="secondaryNavigation"></slot>
|
|
@@ -54,6 +56,10 @@ interface Props {
|
|
|
54
56
|
secondaryNavAriaLabel?: string;
|
|
55
57
|
/** Forwarded to ResponsiveHeader's overflowMenuAriaLabel — override for localisation. */
|
|
56
58
|
overflowMenuAriaLabel?: string;
|
|
59
|
+
/** Forwarded to ResponsiveHeader's overflowButtonLabel, the burger button's accessible name. */
|
|
60
|
+
overflowButtonLabel?: string;
|
|
61
|
+
/** Forwarded to ResponsiveHeader's submenuAriaLabel; {title} is replaced with the item's title. */
|
|
62
|
+
submenuAriaLabel?: string;
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
withDefaults(defineProps<Props>(), {
|
|
@@ -73,6 +79,8 @@ withDefaults(defineProps<Props>(), {
|
|
|
73
79
|
mainNavAriaLabel: "Main navigation",
|
|
74
80
|
secondaryNavAriaLabel: "Secondary navigation",
|
|
75
81
|
overflowMenuAriaLabel: "Overflow navigation menu",
|
|
82
|
+
overflowButtonLabel: "More navigation",
|
|
83
|
+
submenuAriaLabel: "{title} submenu",
|
|
76
84
|
});
|
|
77
85
|
|
|
78
86
|
const slots = useSlots();
|
|
@@ -9,7 +9,7 @@ exports[`SiteHeader > renders correct HTML structure with default props 1`] = `
|
|
|
9
9
|
<nav class="skip-links__nav" aria-label="Skip navigation"><a href="#main-content" class="skip-links__link">Skip to main content</a><a href="#footer-content" class="skip-links__link">Skip to footer</a></nav>
|
|
10
10
|
</div>
|
|
11
11
|
</nav>
|
|
12
|
-
<div class="responsive-header-stub" main-nav-aria-label="Main navigation" secondary-nav-aria-label="Secondary navigation" overflow-menu-aria-label="Overflow navigation menu"></div>
|
|
12
|
+
<div class="responsive-header-stub" main-nav-aria-label="Main navigation" secondary-nav-aria-label="Secondary navigation" overflow-menu-aria-label="Overflow navigation menu" overflow-button-label="More navigation" submenu-aria-label="{title} submenu"></div>
|
|
13
13
|
</header>
|
|
14
14
|
</div>"
|
|
15
15
|
`;
|
|
@@ -70,6 +70,14 @@ Same shape again:
|
|
|
70
70
|
something this token set changes. The animated border added by `has-pending-effect` has its own
|
|
71
71
|
`--pending-effect-*` tokens, see `../pending-effect/CONSUMER-STYLING.md`.
|
|
72
72
|
|
|
73
|
+
### Text wrapping
|
|
74
|
+
|
|
75
|
+
| Token | Default | Controls |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `--input-button-text-white-space` | `nowrap` | Set `normal` to let a long label wrap onto several lines instead of overflowing the button. Unbroken strings break anywhere once wrapping is on |
|
|
78
|
+
|
|
79
|
+
> Added 2026-10-06. `ServicesCardGrid` sets it to `normal` on its CTA buttons so a long service title stays inside the card.
|
|
80
|
+
|
|
73
81
|
`InputCopy` and `PricingCard` fall back through `--input-button-primary-*` for their own copy/CTA
|
|
74
82
|
buttons (see their own `CONSUMER-STYLING.md`) rather than duplicating this chain.
|
|
75
83
|
|
|
@@ -292,7 +292,9 @@ watch(
|
|
|
292
292
|
|
|
293
293
|
.button-text {
|
|
294
294
|
display: inline-block;
|
|
295
|
-
|
|
295
|
+
min-inline-size: 0;
|
|
296
|
+
white-space: var(--input-button-text-white-space, nowrap);
|
|
297
|
+
overflow-wrap: anywhere;
|
|
296
298
|
font-size: var(--button-font-size);
|
|
297
299
|
line-height: var(--button-line-height);
|
|
298
300
|
font-weight: var(--button-font-weight);
|
|
@@ -75,6 +75,14 @@ describe("useAnchorScroll", () => {
|
|
|
75
75
|
expect(history.pushState).not.toHaveBeenCalled();
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
+
it("still records the clicked hash as active", () => {
|
|
79
|
+
stubMatchMedia(true);
|
|
80
|
+
appendEl("overview");
|
|
81
|
+
const { handleNavClick, activeHash } = useAnchorScroll();
|
|
82
|
+
handleNavClick(makeEvent(), "#overview");
|
|
83
|
+
expect(activeHash.value).toBe("#overview");
|
|
84
|
+
});
|
|
85
|
+
|
|
78
86
|
it("does not scroll", () => {
|
|
79
87
|
stubMatchMedia(true);
|
|
80
88
|
const el = appendEl("overview");
|
|
@@ -47,10 +47,10 @@ export const useAnchorScroll = (options: UseAnchorScrollOptions = {}) => {
|
|
|
47
47
|
// and smooth-scroll ourselves.
|
|
48
48
|
const handleNavClick = (event: MouseEvent, href: string): void => {
|
|
49
49
|
if (!href.startsWith("#")) return;
|
|
50
|
+
activeHash.value = href;
|
|
50
51
|
if (prefersReducedMotion()) return;
|
|
51
52
|
|
|
52
53
|
event.preventDefault();
|
|
53
|
-
activeHash.value = href;
|
|
54
54
|
history.pushState(null, "", href);
|
|
55
55
|
scrollToAnchor(href);
|
|
56
56
|
};
|
|
@@ -8,8 +8,29 @@ import type {
|
|
|
8
8
|
|
|
9
9
|
const SCHEMA_DAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
// "HH:MM" from 00:00 to 23:59, else null so the caller can show the raw value instead of throwing
|
|
12
|
+
export const parseOpeningTime = (time: string): { hours: number; minutes: number } | null => {
|
|
13
|
+
const match = /^(\d{1,2}):(\d{2})$/.exec(time.trim());
|
|
14
|
+
if (!match) return null;
|
|
15
|
+
const hours = Number(match[1]);
|
|
16
|
+
const minutes = Number(match[2]);
|
|
17
|
+
return hours < 24 && minutes < 60 ? { hours, minutes } : null;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// A real calendar date in "YYYY-MM-DD" form, as a UTC midnight Date, else null
|
|
21
|
+
export const parseOpeningDate = (iso: string): Date | null => {
|
|
22
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso.trim());
|
|
23
|
+
if (!match) return null;
|
|
24
|
+
const [y, m, d] = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
25
|
+
const date = new Date(Date.UTC(y, m - 1, d));
|
|
26
|
+
return date.getUTCFullYear() === y && date.getUTCMonth() === m - 1 && date.getUTCDate() === d ? date : null;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// "open" with no sessions has nothing to show, so it's treated as closed
|
|
30
|
+
export const resolveOpeningStatus = (entry: { status?: OpeningStatus; sessions?: OpeningSession[] }): OpeningStatus => {
|
|
31
|
+
const status = entry.status ?? "open";
|
|
32
|
+
return status === "open" && !entry.sessions?.length ? "closed" : status;
|
|
33
|
+
};
|
|
13
34
|
|
|
14
35
|
const specsFor = (
|
|
15
36
|
entry: { status?: OpeningStatus; sessions?: OpeningSession[] },
|
package/nuxt.config.ts
CHANGED
|
@@ -150,7 +150,7 @@ export default defineNuxtConfig({
|
|
|
150
150
|
// "esbuild". lightningcss has an open bug where it drops the unprefixed `backdrop-filter`
|
|
151
151
|
// once autoprefixer adds `-webkit-backdrop-filter` alongside it, breaking glass/blur effects
|
|
152
152
|
// (see https://github.com/vitejs/vite/issues/22649) — this repo relies on backdrop-filter in
|
|
153
|
-
// several components (GlassPanel,
|
|
153
|
+
// several components (GlassPanel, TabNavigation, DisplayDialog,
|
|
154
154
|
// MagneticNavigation). Pin back to esbuild until upstream fixes it.
|
|
155
155
|
build: {
|
|
156
156
|
cssMinify: "esbuild",
|
package/package.json
CHANGED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
# SiteNavigation
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
`SiteNavigation` is a responsive site-wide navigation component. It renders a horizontal link list on wide viewports and automatically collapses to a burger-menu + slide-down panel on narrow viewports. Collapse is driven by a `ResizeObserver` that compares the list's natural `scrollWidth` against the nav container's `clientWidth` — no breakpoint prop needed.
|
|
6
|
-
|
|
7
|
-
Both the horizontal list and the panel include animated active/hover indicator decorators (underline indicator + background highlight) that snap into position using CSS custom properties set via JavaScript.
|
|
8
|
-
|
|
9
|
-
## Component location
|
|
10
|
-
|
|
11
|
-
`app/components/02.molecules/navigation/site-navigation/SiteNavigation.vue`
|
|
12
|
-
|
|
13
|
-
## Props
|
|
14
|
-
|
|
15
|
-
| Prop | Type | Default | Description |
|
|
16
|
-
|---|---|---|---|
|
|
17
|
-
| `navItemData` | `NavItemData` | — (required) | Navigation items — see type below |
|
|
18
|
-
| `navAlign` | `"left" \| "center" \| "right"` | `"left"` | Alignment of the horizontal nav list |
|
|
19
|
-
| `ariaLabel` | `string` | `"Site navigation"` | aria-label on the root `<nav>` landmark — override for localisation |
|
|
20
|
-
| `openMenuLabel` | `string` | `"Open navigation menu"` | Burger button text (screen-reader) while closed — override for localisation |
|
|
21
|
-
| `closeMenuLabel` | `string` | `"Close navigation menu"` | Burger button text (screen-reader) while open — override for localisation |
|
|
22
|
-
| `styleClassPassthrough` | `string \| string[]` | `[]` | Extra classes applied to the root `<nav>` |
|
|
23
|
-
|
|
24
|
-
## NavItemData type
|
|
25
|
-
|
|
26
|
-
**Within the layer:**
|
|
27
|
-
|
|
28
|
-
```ts
|
|
29
|
-
import type { NavItemData } from "~/types/components/nav-item.d";
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
**In a consuming app:**
|
|
33
|
-
|
|
34
|
-
```ts
|
|
35
|
-
import type { NavItemData } from "srcdev-nuxt-components";
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
const navItemData: NavItemData = {
|
|
40
|
-
main: [
|
|
41
|
-
{ text: "Home", href: "/" },
|
|
42
|
-
{ text: "About", href: "/about" },
|
|
43
|
-
{ text: "Services", href: "/services", cssName: "is-featured" },
|
|
44
|
-
{ text: "Contact", href: "/contact", iconName: "heroicons:envelope", isExternal: false },
|
|
45
|
-
],
|
|
46
|
-
};
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
`NavItem` fields:
|
|
50
|
-
|
|
51
|
-
| Field | Type | Description |
|
|
52
|
-
|---|---|---|
|
|
53
|
-
| `text` | `string` | Link label |
|
|
54
|
-
| `href` | `string` | Link destination |
|
|
55
|
-
| `isExternal` | `boolean?` | Passed to NuxtLink `:external` — opens in new tab |
|
|
56
|
-
| `iconName` | `string?` | Iconify icon name rendered before the label |
|
|
57
|
-
| `cssName` | `string?` | CSS class applied to the `<li>` element |
|
|
58
|
-
|
|
59
|
-
## Basic usage
|
|
60
|
-
|
|
61
|
-
```vue
|
|
62
|
-
<SiteNavigation :nav-item-data="navItemData" nav-align="left" />
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Always use hyphenated prop names in templates (ESLint enforces this).
|
|
66
|
-
|
|
67
|
-
## CSS token API
|
|
68
|
-
|
|
69
|
-
Set these tokens on a parent element (e.g. your `<header>`) to theme the navigation.
|
|
70
|
-
|
|
71
|
-
```css
|
|
72
|
-
.your-header {
|
|
73
|
-
/* ── Decorators ────────────────────────────────────── */
|
|
74
|
-
--site-nav-decorator-indicator-color: var(--rose-05); /* underline bar */
|
|
75
|
-
--site-nav-decorator-hovered-bg: transparent; /* hover pill behind a link */
|
|
76
|
-
--site-nav-decorator-active-bg: transparent; /* active pill behind a link */
|
|
77
|
-
|
|
78
|
-
/* ── Horizontal nav links ──────────────────────────── */
|
|
79
|
-
--site-nav-link-color: var(--warm-01);
|
|
80
|
-
--site-nav-link-hover-color: var(--rose-04);
|
|
81
|
-
--site-nav-link-active-color: var(--rose-05);
|
|
82
|
-
--site-nav-link-size: 1.6rem;
|
|
83
|
-
--site-nav-link-weight: 400;
|
|
84
|
-
--site-nav-link-tracking: 0.06em;
|
|
85
|
-
--site-nav-gap: 2.2rem;
|
|
86
|
-
--site-nav-transition: 250ms ease;
|
|
87
|
-
|
|
88
|
-
/* ── Mobile panel ──────────────────────────────────── */
|
|
89
|
-
--site-nav-panel-bg: var(--page-bg, #1a1614);
|
|
90
|
-
--site-nav-panel-border-color: color-mix(in oklch, var(--rose-05) 35%, transparent);
|
|
91
|
-
--site-nav-panel-link-color: var(--warm-01);
|
|
92
|
-
--site-nav-panel-link-hover-color: var(--rose-04);
|
|
93
|
-
--site-nav-panel-link-active-color: var(--rose-05);
|
|
94
|
-
--site-nav-panel-padding-block: 1.4rem;
|
|
95
|
-
--site-nav-panel-padding-inline: 1.5rem;
|
|
96
|
-
--site-nav-panel-slide-duration: 350ms;
|
|
97
|
-
--site-nav-panel-slide-easing: cubic-bezier(0.4, 0, 0.2, 1);
|
|
98
|
-
--site-nav-panel-decorator-indicator-color: var(--rose-05);
|
|
99
|
-
--site-nav-panel-indicator-left: 0; /* position the panel indicator bar */
|
|
100
|
-
--site-nav-panel-indicator-right: auto;
|
|
101
|
-
|
|
102
|
-
/* ── Burger button ─────────────────────────────────── */
|
|
103
|
-
--site-nav-burger-color: var(--warm-01);
|
|
104
|
-
--site-nav-burger-width: 22px;
|
|
105
|
-
--site-nav-burger-height: 1.5px;
|
|
106
|
-
--site-nav-burger-gap: 5px;
|
|
107
|
-
--site-nav-burger-transition: 300ms ease;
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
The backdrop is teleported to `<body>`, so its tokens only land when set on `:root`/`html`/`body`,
|
|
113
|
-
not on your header:
|
|
114
|
-
|
|
115
|
-
```css
|
|
116
|
-
:where(html) {
|
|
117
|
-
--site-nav-backdrop-bg: oklch(0% 0 0 / 55%);
|
|
118
|
-
--site-nav-backdrop-blur: 3px;
|
|
119
|
-
--site-nav-backdrop-duration: 350ms;
|
|
120
|
-
--site-nav-backdrop-z-index: 10; /* keep your header above this */
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Full reference: `app/components/02.molecules/navigation/site-navigation/CONSUMER-STYLING.md`.
|
|
125
|
-
|
|
126
|
-
## Behaviour notes
|
|
127
|
-
|
|
128
|
-
- **Collapse detection**: `ResizeObserver` fires on every container resize. The list's `scrollWidth` is cached whenever the list is in the DOM; that cached value is compared against the container's `clientWidth` to set `isCollapsed`.
|
|
129
|
-
- **isLoaded state**: The component uses `useState("site-nav-loaded")` — a Nuxt shared state — to gate visibility until the first measurement is complete, preventing a flash of the wrong nav state on load. The nav renders `opacity: 0` until `is-loaded` is applied.
|
|
130
|
-
- **Teleport**: The backdrop overlay is teleported to `<body>` via `<Teleport>` and is only mounted when `isCollapsed && isLoaded`.
|
|
131
|
-
- **Panel inert**: The panel div (id `site-nav-panel-{useId}`, unique per instance) receives `:inert="!isMenuOpen ? true : undefined"` — it is inert (keyboard/pointer-inaccessible) when closed.
|
|
132
|
-
- **Decorator init**: `initNavDecorators()` and `initPanelDecorators()` inject `<li>` elements with CSS-driven indicator `<div>`s. They query `[data-nav-item]` / `[data-panel-nav-item]` to find links, and look for `router-link-active` to set the initial active position.
|
|
133
|
-
|
|
134
|
-
## Accessibility
|
|
135
|
-
|
|
136
|
-
- Root `<nav>` has `aria-label` from the `ariaLabel` prop (default `"Site navigation"`).
|
|
137
|
-
- Burger button text comes from `openMenuLabel`/`closeMenuLabel`, with `aria-expanded` (string `"true"/"false"`) and `aria-controls` pointing at the panel's per-instance id (was a fixed `site-nav-panel`, which collided when two navs were on one page; fixed 2026-09-27).
|
|
138
|
-
- Backdrop and indicator `<li>` elements are `aria-hidden="true"`.
|
|
139
|
-
- Panel div is `inert` when closed.
|
|
140
|
-
|
|
141
|
-
## Related files
|
|
142
|
-
|
|
143
|
-
- Type: `app/types/components/nav-item.d.ts`
|
|
144
|
-
- Tests: `app/components/02.molecules/navigation/site-navigation/tests/SiteNavigation.spec.ts`
|
|
145
|
-
- Story: `app/components/02.molecules/navigation/site-navigation/stories/SiteNavigation.stories.ts`
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"SRCDEV SiteNavigation": {
|
|
3
|
-
"description": "SiteNavigation: horizontal links that collapse to a burger panel when they don't fit",
|
|
4
|
-
"scope": "vue,html",
|
|
5
|
-
"body": [
|
|
6
|
-
"<SiteNavigation",
|
|
7
|
-
" :nav-item-data=\"$1navItems\"",
|
|
8
|
-
" nav-align=\"${2|left,center,right|}\"",
|
|
9
|
-
" aria-label=\"${3:Site navigation}\"",
|
|
10
|
-
"/>"
|
|
11
|
-
]
|
|
12
|
-
},
|
|
13
|
-
"SRCDEV SiteNavigation Items": {
|
|
14
|
-
"description": "NavItemData object for SiteNavigation",
|
|
15
|
-
"scope": "javascript,typescript",
|
|
16
|
-
"body": [
|
|
17
|
-
"const $1navItems: NavItemData = {",
|
|
18
|
-
" main: [",
|
|
19
|
-
" { text: \"$2Home\", href: \"/\" },",
|
|
20
|
-
" { text: \"$3About\", href: \"/about\" },",
|
|
21
|
-
" ],",
|
|
22
|
-
"};"
|
|
23
|
-
]
|
|
24
|
-
},
|
|
25
|
-
"SRCDEV SiteNavigation CSS Override": {
|
|
26
|
-
"description": "CSS override scaffold for SiteNavigation tokens (backdrop tokens go on :root)",
|
|
27
|
-
"scope": "css",
|
|
28
|
-
"body": [
|
|
29
|
-
".$1site-header {",
|
|
30
|
-
" --site-nav-link-color: $2;",
|
|
31
|
-
" --site-nav-link-hover-color: $3;",
|
|
32
|
-
" --site-nav-decorator-indicator-color: $4;",
|
|
33
|
-
" --site-nav-panel-bg: $5;",
|
|
34
|
-
" --site-nav-burger-color: $6;",
|
|
35
|
-
"}"
|
|
36
|
-
]
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
# SiteNavigation — Consumer Styling Guide
|
|
2
|
-
|
|
3
|
-
## Public token API
|
|
4
|
-
|
|
5
|
-
Defaults that read `var(--slate-01, currentColor)` use the library palette when it's loaded and fall
|
|
6
|
-
back to the inherited text colour otherwise.
|
|
7
|
-
|
|
8
|
-
### Horizontal nav
|
|
9
|
-
|
|
10
|
-
| Token | Default | Controls |
|
|
11
|
-
|---|---|---|
|
|
12
|
-
| `--site-nav-link-color` | `var(--slate-01, currentColor)` | Link colour |
|
|
13
|
-
| `--site-nav-link-hover-color` | `var(--slate-04, <link colour>)` | Link colour on hover |
|
|
14
|
-
| `--site-nav-link-active-color` | `var(--slate-01, <link colour>)` | Active link colour |
|
|
15
|
-
| `--site-nav-link-accent` | `var(--slate-01, currentColor)` | Link accent colour |
|
|
16
|
-
| `--site-nav-link-size` | `1.6rem` | Link font size |
|
|
17
|
-
| `--site-nav-link-weight` | `400` | Link font weight |
|
|
18
|
-
| `--site-nav-link-tracking` | `0.06em` | Link letter spacing |
|
|
19
|
-
| `--site-nav-gap` | `2.2rem` | Gap between links |
|
|
20
|
-
| `--site-nav-transition` | `250ms ease` | Link colour transition |
|
|
21
|
-
| `--site-nav-decorator-indicator-color` | `var(--slate-01, currentColor)` | Sliding underline bar |
|
|
22
|
-
| `--site-nav-decorator-hovered-bg` | `transparent` | Sliding pill behind the hovered link |
|
|
23
|
-
| `--site-nav-decorator-active-bg` | `transparent` | Pill behind the active link |
|
|
24
|
-
|
|
25
|
-
> Changed 2026-09-27: `--site-nav-decorator-hovered-bg` and `--site-nav-decorator-active-bg` are
|
|
26
|
-
> new. The values were hardcoded `transparent` with no override, unlike the panel equivalents.
|
|
27
|
-
|
|
28
|
-
### Collapsed panel
|
|
29
|
-
|
|
30
|
-
| Token | Default | Controls |
|
|
31
|
-
|---|---|---|
|
|
32
|
-
| `--site-nav-panel-bg` | `var(--page-bg, #1a1614)` | Panel background |
|
|
33
|
-
| `--site-nav-panel-border-color` | `color-mix(in oklch, var(--slate-01, #c0847a) 35%, transparent)` | Top border when open |
|
|
34
|
-
| `--site-nav-panel-item-border` | `color-mix(in oklch, var(--slate-01, white) 8%, transparent)` | Divider between panel links |
|
|
35
|
-
| `--site-nav-panel-link-color` | `var(--slate-01, currentColor)` | Panel link colour |
|
|
36
|
-
| `--site-nav-panel-link-hover-color` | `var(--slate-04, <panel link colour>)` | Panel link hover colour |
|
|
37
|
-
| `--site-nav-panel-link-active-color` | `var(--slate-01, <panel link colour>)` | Active panel link colour |
|
|
38
|
-
| `--site-nav-panel-padding-block` | `1.4rem` | Panel link vertical padding |
|
|
39
|
-
| `--site-nav-panel-padding-inline` | `1.5rem` | Panel link horizontal padding |
|
|
40
|
-
| `--site-nav-panel-slide-duration` | `350ms` | Open/close slide duration |
|
|
41
|
-
| `--site-nav-panel-slide-easing` | `cubic-bezier(0.4, 0, 0.2, 1)` | Open/close easing |
|
|
42
|
-
| `--site-nav-panel-decorator-indicator-color` | `var(--slate-01, currentColor)` | Panel indicator bar |
|
|
43
|
-
| `--site-nav-panel-decorator-hovered-bg` | `transparent` | Pill behind the hovered panel link |
|
|
44
|
-
| `--site-nav-panel-decorator-active-bg` | `transparent` | Pill behind the active panel link |
|
|
45
|
-
| `--site-nav-panel-indicator-left` | `0` | Indicator bar left position |
|
|
46
|
-
| `--site-nav-panel-indicator-right` | `auto` | Indicator bar right position |
|
|
47
|
-
|
|
48
|
-
### Burger button
|
|
49
|
-
|
|
50
|
-
| Token | Default | Controls |
|
|
51
|
-
|---|---|---|
|
|
52
|
-
| `--site-nav-burger-color` | `var(--slate-01, currentColor)` | Bar colour |
|
|
53
|
-
| `--site-nav-burger-width` | `22px` | Bar width |
|
|
54
|
-
| `--site-nav-burger-height` | `1.5px` | Bar thickness |
|
|
55
|
-
| `--site-nav-burger-gap` | `5px` | Gap between bars |
|
|
56
|
-
| `--site-nav-burger-transition` | `300ms ease` | Open/close morph |
|
|
57
|
-
|
|
58
|
-
### Backdrop (teleported to `<body>`)
|
|
59
|
-
|
|
60
|
-
| Token | Default | Controls |
|
|
61
|
-
|---|---|---|
|
|
62
|
-
| `--site-nav-backdrop-bg` | `oklch(0% 0 0 / 55%)` | Scrim colour |
|
|
63
|
-
| `--site-nav-backdrop-blur` | `3px` | Blur behind the scrim |
|
|
64
|
-
| `--site-nav-backdrop-duration` | `350ms` | Fade duration |
|
|
65
|
-
| `--site-nav-backdrop-z-index` | `10` | Scrim stacking order; keep your header above it |
|
|
66
|
-
|
|
67
|
-
> Changed 2026-09-27: `--site-nav-backdrop-z-index` is new (was a hardcoded `10`).
|
|
68
|
-
|
|
69
|
-
The `--_*` variables declared on `.site-navigation` are the resolved copies of the tokens above
|
|
70
|
-
that are read in more than one place: not public API.
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
|
|
74
|
-
## State hooks
|
|
75
|
-
|
|
76
|
-
| Hook | Element | When |
|
|
77
|
-
|---|---|---|
|
|
78
|
-
| `.site-navigation--left`, `--center`, `--right` | root `<nav>` | `nav-align` |
|
|
79
|
-
| `.is-collapsed` | root | Links don't fit, so the burger and panel are shown |
|
|
80
|
-
| `.is-loaded` | root | First measurement done (the nav is `opacity: 0` until then) |
|
|
81
|
-
| `.menu-open` | root | Panel open |
|
|
82
|
-
| `.is-animated` | root | Indicator transitions enabled (after first layout) |
|
|
83
|
-
| `li.is-active` | nav and panel items | Item matches the current route |
|
|
84
|
-
| `.is-open` | `.site-nav-burger`, `.site-nav-panel`, `.site-nav-backdrop` | Panel open |
|
|
85
|
-
|
|
86
|
-
Inner classes: `.site-nav-list`, `.site-nav-link`, `.site-nav-burger`, `.burger-bar`,
|
|
87
|
-
`.site-nav-panel`, `.site-nav-panel-inner`, `.site-nav-panel-list`, `.site-nav-panel-link`,
|
|
88
|
-
`.site-nav-backdrop`; decorators `.nav__hovered`, `.nav__active`, `.nav__active-indicator`.
|
|
89
|
-
Each item `li` also gets its `NavItem.cssName`.
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## Local overrides
|
|
94
|
-
|
|
95
|
-
Set the tokens above on an element you own (a page or section class, or a class added with
|
|
96
|
-
`:style-class-passthrough`): they inherit down into the component. Keep the block **unlayered** (no
|
|
97
|
-
`@layer` wrapper) so it beats the library's `@layer components`. If your own file uses
|
|
98
|
-
`<style scoped>`, tokens set on your element still work, but selectors that reach inside the component need
|
|
99
|
-
`:deep()`. Patterns and examples: `.claude/skills/component-local-style-override.md`.
|
|
100
|
-
|
|
101
|
-
**Caveat:** the backdrop is teleported to `<body>`, outside your header, so the
|
|
102
|
-
`--site-nav-backdrop-*` tokens only land when set on `:root`, `html` or `body`.
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## Class passthrough
|
|
107
|
-
|
|
108
|
-
`style-class-passthrough` adds classes to the root `<nav>`. Reactive after mount. It doesn't reach
|
|
109
|
-
the teleported backdrop.
|