srcdev-nuxt-components 9.0.14 → 9.0.16

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 (108) hide show
  1. package/.claude/settings.json +25 -0
  2. package/.claude/skills/component-aria-landmark.md +68 -0
  3. package/.claude/skills/component-dynamic-slots.md +150 -0
  4. package/.claude/skills/component-local-style-override.md +126 -0
  5. package/.claude/skills/component-prop-driven-container-layout.md +42 -0
  6. package/.claude/skills/components/accordian-core.md +159 -0
  7. package/.claude/skills/components/contact-section.md +101 -0
  8. package/.claude/skills/components/expanding-panel.md +156 -0
  9. package/.claude/skills/components/eyebrow-text.md +25 -0
  10. package/.claude/skills/components/hero-text.md +25 -0
  11. package/.claude/skills/components/layout-grid-by-cols.md +147 -0
  12. package/.claude/skills/components/layout-row.md +35 -0
  13. package/.claude/skills/components/link-text.md +33 -0
  14. package/.claude/skills/components/page-hero-highlights.md +224 -0
  15. package/.claude/skills/components/services-card.md +28 -0
  16. package/.claude/skills/components/services-section.md +25 -0
  17. package/.claude/skills/components/stepper-list.md +227 -0
  18. package/.claude/skills/css-grid-max-width-gutters.md +67 -0
  19. package/.claude/skills/index.md +14 -3
  20. package/.claude/skills/storybook-add-story.md +60 -0
  21. package/.claude/skills/testing-add-unit-test.md +56 -0
  22. package/app/assets/styles/setup/01.config/index.css +0 -1
  23. package/app/assets/styles/setup/03.theming/default/_dark.css +2 -2
  24. package/app/assets/styles/setup/04.elements/forms/02.typography.css +1 -0
  25. package/app/assets/styles/setup/05.typography/02.utility-classes/_font-classes-page-link.css +14 -14
  26. package/app/assets/styles/setup/index.css +0 -1
  27. package/app/components/01.atoms/card/CardCore.vue +92 -0
  28. package/app/components/01.atoms/card/stories/CardCore.stories.ts +132 -0
  29. package/app/components/01.atoms/card/tests/CardCore.spec.ts +207 -0
  30. package/app/components/01.atoms/card/tests/__snapshots__/CardCore.spec.ts.snap +43 -0
  31. package/app/components/01.atoms/content-wrappers/content-columns-2/ContentColumns2.vue +51 -0
  32. package/app/components/01.atoms/content-wrappers/content-columns-2/stories/ContentColumns2.stories.ts +110 -0
  33. package/app/components/01.atoms/content-wrappers/content-columns-2/tests/ContentColumns2.spec.ts +105 -0
  34. package/app/components/01.atoms/content-wrappers/content-columns-2/tests/__snapshots__/ContentColumns2.spec.ts.snap +14 -0
  35. package/app/components/01.atoms/content-wrappers/content-width/ContentWidth.vue +88 -0
  36. package/app/components/01.atoms/content-wrappers/content-width/stories/ContentWidth.stories.ts +362 -0
  37. package/app/components/01.atoms/content-wrappers/content-width/tests/ContentWidth.spec.ts +132 -0
  38. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/LayoutGridByCols.vue +71 -0
  39. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/stories/LayoutGridByCols.stories.ts +219 -0
  40. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/tests/LayoutGridByCols.spec.ts +174 -0
  41. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/tests/__snapshots__/LayoutGrid.spec.ts.snap +36 -0
  42. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-cols/tests/__snapshots__/LayoutGridByCols.spec.ts.snap +36 -0
  43. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-width/LayoutGridByWidth.vue +70 -0
  44. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-width/stories/LayoutGridByWidth.stories.ts +220 -0
  45. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-width/tests/LayoutGridByWidth.spec.ts +174 -0
  46. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-width/tests/__snapshots__/LayoutGrid.spec.ts.snap +36 -0
  47. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-width/tests/__snapshots__/LayoutGridByCols.spec.ts.snap +36 -0
  48. package/app/components/01.atoms/content-wrappers/layout-grid/layout-grid-by-width/tests/__snapshots__/LayoutGridByWidth.spec.ts.snap +36 -0
  49. package/app/components/01.atoms/text-blocks/eyebrow-text/stories/EyebrowText.stories.ts +1 -1
  50. package/app/components/01.atoms/text-blocks/hero-text/stories/HeroText.stories.ts +1 -1
  51. package/app/components/01.atoms/text-blocks/link-text/stories/LinkText.stories.ts +1 -1
  52. package/app/components/02.molecules/contact-section/stories/ContactSection.stories.ts +5 -0
  53. package/app/components/02.molecules/contact-section/tests/ContactSection.spec.ts +15 -0
  54. package/app/components/02.molecules/contact-section/tests/ContactSection.vue +25 -17
  55. package/app/components/{accordian → 02.molecules/expandable/accordian}/stories/AccordianCore.stories.ts +1 -1
  56. package/app/components/02.molecules/expandable/expanding-panel/stories/ExpandingPanel.stories.ts +245 -0
  57. package/app/components/02.molecules/expandable/expanding-panel/tests/ExpandingPanel.spec.ts +351 -0
  58. package/app/components/02.molecules/expandable/expanding-panel/tests/__snapshots__/ExpandingPanel.spec.ts.snap +38 -0
  59. package/app/components/02.molecules/navigation/navigation-horizontal/NavigationHorizontal.vue +139 -0
  60. package/app/components/02.molecules/navigation/navigation-horizontal/NavigationHorizontalAdvanced.vue +172 -0
  61. package/app/components/02.molecules/profile-section/ProfileSection.vue +2 -3
  62. package/app/components/02.molecules/profile-section/tests/ProfileSection.spec.ts +2 -2
  63. package/app/components/02.molecules/stepper-list/StepperList.vue +131 -92
  64. package/app/components/02.molecules/stepper-list/stories/StepperList.stories.ts +31 -0
  65. package/app/components/02.molecules/stepper-list/tests/StepperList.spec.ts +24 -0
  66. package/app/components/02.molecules/stepper-list/tests/__snapshots__/StepperList.spec.ts.snap +22 -9
  67. package/app/components/03.organisms/image-galleries/slider-gallery/SliderGallery.vue +782 -0
  68. package/app/components/03.organisms/image-galleries/slider-gallery/stories/SliderGallery.stories.ts +233 -0
  69. package/app/components/03.organisms/image-galleries/slider-gallery/tests/SliderGallery.spec.ts +226 -0
  70. package/app/components/03.organisms/image-galleries/slider-gallery/tests/__snapshots__/SliderGallery.spec.ts.snap +69 -0
  71. package/app/components/03.organisms/services/services-grids/ServicesCardGrid.vue +1 -1
  72. package/app/components/03.organisms/services/services-grids/ServicesSectionGrid.vue +1 -1
  73. package/app/components/03.organisms/services/services-section/ServicesSection.vue +2 -3
  74. package/app/components/04.templates/page-hero-highlights/PageHeroHighlights.vue +239 -0
  75. package/app/components/04.templates/page-hero-highlights/stories/PageHeroHighlights.stories.ts +404 -0
  76. package/app/components/04.templates/page-hero-highlights/tests/PageHeroHighlights.spec.ts +198 -0
  77. package/app/components/04.templates/page-hero-highlights/tests/__snapshots__/PageHeroHighlights.spec.ts.snap +19 -0
  78. package/app/components/container-glow/ContainerGlowCore.vue +20 -27
  79. package/app/components/forms/input-button/InputButtonCore.vue +105 -104
  80. package/app/components/glowing-border/stories/GlowingBorder.stories.ts +21 -21
  81. package/app/composables/useAriaLabelledById.ts +13 -0
  82. package/app/layouts/default.vue +8 -3
  83. package/app/pages/forms/examples/buttons/index.vue +6 -6
  84. package/app/pages/forms/examples/material/checkbox-radio-panels.vue +3 -3
  85. package/app/pages/forms/examples/material/text-fields.vue +607 -610
  86. package/app/pages/page-hero-highlights.vue +81 -0
  87. package/app/pages/ui/{display-card.vue → card-core.vue} +15 -15
  88. package/app/pages/ui/contact-section.vue +1 -1
  89. package/app/pages/ui/container-glow.vue +1 -1
  90. package/app/pages/ui/content-width.vue +126 -0
  91. package/app/pages/ui/glowing-border.vue +9 -9
  92. package/app/pages/ui/navigation/navigation-horizontal.vue +493 -0
  93. package/app/pages/ui/services/services-section/[slug].vue +3 -1
  94. package/nuxt.config.ts +4 -1
  95. package/package.json +2 -2
  96. package/app/assets/styles/setup/01.config/_basic-resets.css +0 -9
  97. package/app/components/content-columns/TwoColumns.vue +0 -59
  98. package/app/components/content-columns/stories/TwoColumns.stories.ts +0 -561
  99. package/app/components/content-containers/ContentContainer.vue +0 -89
  100. package/app/components/content-containers/stories/ContentContainer.stories.ts +0 -465
  101. package/app/components/content-grid/ContentGrid.vue +0 -85
  102. package/app/components/display-card/DisplayCard.vue +0 -122
  103. package/app/components/image-galleries/SliderGallery.vue +0 -786
  104. package/app/pages/ui/content-container.vue +0 -112
  105. /package/app/components/{accordian → 02.molecules/expandable/accordian}/AccordianCore.vue +0 -0
  106. /package/app/components/{accordian → 02.molecules/expandable/accordian}/tests/AccordianCore.spec.ts +0 -0
  107. /package/app/components/{accordian → 02.molecules/expandable/accordian}/tests/__snapshots__/AccordianCore.spec.ts.snap +0 -0
  108. /package/app/components/{expanding-panel → 02.molecules/expandable/expanding-panel}/ExpandingPanel.vue +0 -0
@@ -0,0 +1,239 @@
1
+ <template>
2
+ <component
3
+ :is="tag"
4
+ class="page-hero-highlights"
5
+ :class="[elementClasses, componentClasses]"
6
+ :aria-labelledby="ariaLabelledby"
7
+ >
8
+ <div class="header-row">
9
+ <div class="header-slot">
10
+ <slot name="header" :heading-id="headingId"></slot>
11
+ </div>
12
+ </div>
13
+ <div class="highlights-row" :class="highlightClasses">
14
+ <slot name="highlights"></slot>
15
+ </div>
16
+ <div class="content-row">
17
+ <div class="content-slot">
18
+ <slot name="content"></slot>
19
+ </div>
20
+ </div>
21
+ </component>
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ interface Props {
26
+ tag?: "div" | "section" | "main";
27
+ highlightsEqualWidths?: boolean;
28
+ highlightsJustify?: "start" | "center" | "end" | "space-between" | "space-around";
29
+ maxWidth?: string;
30
+ contentAlign?: "start" | "center";
31
+ highlightTitleBaseline?: boolean;
32
+ styleClassPassthrough?: string | string[];
33
+ }
34
+
35
+ const props = withDefaults(defineProps<Props>(), {
36
+ tag: "div",
37
+ highlightsEqualWidths: false,
38
+ highlightsJustify: "start",
39
+ maxWidth: undefined,
40
+ contentAlign: "center",
41
+ highlightTitleBaseline: false,
42
+ styleClassPassthrough: () => [],
43
+ });
44
+
45
+ const gridColumns = computed(() => {
46
+ if (!props.maxWidth) return "16px 1fr 16px";
47
+ if (props.contentAlign === "start") return `16px minmax(0, ${props.maxWidth}) 1fr`;
48
+ return `max(16px, (100% - ${props.maxWidth}) / 2) 1fr max(16px, (100% - ${props.maxWidth}) / 2)`;
49
+ });
50
+
51
+ const { headingId, ariaLabelledby } = useAriaLabelledById(() => props.tag);
52
+ const componentClasses = computed(() => ({
53
+ "highlight-title-baseline": props.highlightTitleBaseline,
54
+ }));
55
+
56
+ const highlightClasses = computed(() => ({
57
+ "equal-widths": props.highlightsEqualWidths,
58
+ "flexible-widths": !props.highlightsEqualWidths,
59
+ [`justify-${props.highlightsJustify}`]: true,
60
+ }));
61
+
62
+ const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
63
+
64
+ watch(
65
+ () => props.styleClassPassthrough,
66
+ () => {
67
+ resetElementClasses(props.styleClassPassthrough);
68
+ }
69
+ );
70
+ </script>
71
+
72
+ <style lang="css">
73
+ .page-hero-highlights {
74
+ /* User themable tokens */
75
+ --header-row-background-colour: darkblue;
76
+
77
+ --highlights-row-item-gap: 1rem;
78
+ --highlights-row-initial-item-offset: 1.2rem;
79
+
80
+ --highlight-rows-gap: 1.2rem;
81
+ --highlight-title-height: 1fr; /* see: highlight-title-baseline class below */
82
+ --highlight-padding-block-start: 1.2rem;
83
+ --highlight-padding: 1.2rem;
84
+
85
+ --highlight-background-color: white;
86
+ --highlight-border: 1px solid black;
87
+ --highlight-border-radius: 8px;
88
+ --highlight-color: black;
89
+
90
+ --content-row-background-color: var(--slate-01); /* transparent */
91
+ --content-row-start-gap: 1.2rem;
92
+ --content-row-end-gap: 1.2rem;
93
+
94
+ --content-slot-margin-block-start: 2.4rem;
95
+ --content-slot-margin: var(--highlights-row-initial-item-offset);
96
+ --content-slot-background-color: var(--slate-00);
97
+ --content-slot-border: 1px solid var(--slate-06);
98
+ --content-slot-border-radius: 0.8rem;
99
+ --content-slot-outline: 1px solid var(--slate-02);
100
+
101
+ &.highlight-title-baseline {
102
+ --highlight-title-height: 4rem; /* We need to manually tweak height, preferrably a proportional value as we're not setting an top padding when not prop.highlight-title-baseline */
103
+ --highlight-padding-block-start: 0; /* We're setting the title height via row height, so this should be exposed for override in consuming page */
104
+ }
105
+
106
+ display: grid;
107
+ grid-template-columns: v-bind(gridColumns);
108
+ grid-template-rows: auto var(--highlight-title-height) 1fr auto;
109
+ gap: 0;
110
+
111
+ .header-row {
112
+ /* Element geometry */
113
+ grid-column: 1 / -1;
114
+ grid-row: 1 / 3;
115
+ display: grid;
116
+ grid-template-columns: subgrid;
117
+ grid-template-rows: subgrid;
118
+
119
+ /* Element theme */
120
+ background-color: var(--header-row-background-colour);
121
+
122
+ .header-slot {
123
+ grid-column: 2;
124
+ grid-row: 1;
125
+ }
126
+ }
127
+
128
+ .highlights-row {
129
+ /* Element geometry */
130
+ grid-column: 2;
131
+ grid-row: 2 / 4; /* rows 2–3: straddles header/content boundary */
132
+
133
+ position: relative;
134
+ z-index: 1;
135
+
136
+ /* Element theme */
137
+ gap: var(--highlights-row-item-gap);
138
+ margin-inline-start: var(--highlights-row-initial-item-offset);
139
+
140
+ &.equal-widths {
141
+ display: grid;
142
+ grid-auto-columns: 1fr;
143
+ grid-auto-flow: column;
144
+ }
145
+
146
+ &.flexible-widths {
147
+ display: flex;
148
+ flex-wrap: wrap;
149
+ justify-content: center;
150
+ }
151
+
152
+ &.justify-start {
153
+ justify-content: start;
154
+ }
155
+ &.justify-center {
156
+ justify-content: center;
157
+ }
158
+ &.justify-end {
159
+ justify-content: end;
160
+ }
161
+ &.justify-space-between {
162
+ justify-content: space-between;
163
+ }
164
+ &.justify-space-around {
165
+ justify-content: space-around;
166
+ }
167
+
168
+ .highlight {
169
+ /* Element geometry */
170
+ display: grid;
171
+ grid-template-rows: subgrid;
172
+ grid-auto-flow: row;
173
+
174
+ /* Element theme */
175
+ padding-block: var(--highlight-padding-block-start) var(--highlight-padding);
176
+ padding-inline: var(--highlight-padding);
177
+
178
+ background-color: var(--highlight-background-color);
179
+ border: var(--highlight-border);
180
+ border-radius: var(--highlight-border-radius);
181
+ color: var(--highlight-color);
182
+
183
+ .title {
184
+ display: grid;
185
+ grid-row: 2;
186
+ align-items: end;
187
+ height: var(--highlight-title-height);
188
+ }
189
+ .body {
190
+ /* Element geometry */
191
+ grid-row: 3;
192
+ margin-block-start: var(--highlight-rows-gap);
193
+
194
+ /* Element theme */
195
+ }
196
+ }
197
+ }
198
+
199
+ .content-row {
200
+ /* Element geometry */
201
+ grid-column: 1 / span 3;
202
+ grid-row: 3 / span 2;
203
+ display: grid;
204
+ grid-template-columns: subgrid;
205
+ grid-template-rows: subgrid;
206
+
207
+ position: relative;
208
+ isolation: isolate;
209
+
210
+ /* Element theme */
211
+ background-color: var(--content-row-background-color);
212
+ padding-block-end: var(--content-row-end-gap);
213
+
214
+ &:before {
215
+ /* Element geometry */
216
+ content: "";
217
+ grid-template-columns: subgrid;
218
+ grid-template-rows: subgrid;
219
+ display: grid;
220
+ grid-column: 2;
221
+ grid-row: 1 / span 2;
222
+
223
+ /* Element theme */
224
+ margin-top: var(--content-row-start-gap);
225
+
226
+ background-color: var(--content-slot-background-color);
227
+ border: var(--content-slot-border);
228
+ outline: var(--content-slot-outline);
229
+ border-radius: var(--content-slot-border-radius);
230
+ }
231
+ .content-slot {
232
+ grid-column: 2;
233
+ grid-row: 2;
234
+ margin-block: var(--content-slot-margin-block-start) var(--content-slot-margin);
235
+ margin-inline: var(--content-slot-margin);
236
+ }
237
+ }
238
+ }
239
+ </style>
@@ -0,0 +1,404 @@
1
+ import { computed } from "vue";
2
+ import PageHeroHighlights from "../PageHeroHighlights.vue";
3
+ import type { Meta, StoryObj } from "@nuxtjs/storybook";
4
+
5
+ type StoryArgs = {
6
+ tag?: "div" | "section" | "main";
7
+ highlightsEqualWidths?: boolean;
8
+ highlightsJustify?: "start" | "center" | "end" | "space-between" | "space-around";
9
+ maxWidth?: string;
10
+ contentAlign?: "start" | "center";
11
+ highlightTitleBaseline?: boolean;
12
+ headerBackground?: string;
13
+ contentBackground?: string;
14
+ highlightCount?: 1 | 2 | 3;
15
+ styleClassPassthrough?: string | string[];
16
+ };
17
+
18
+ const meta: Meta<StoryArgs> = {
19
+ title: "Templates/PageHeroHighlights",
20
+ component: PageHeroHighlights,
21
+ argTypes: {
22
+ tag: {
23
+ control: { type: "select" },
24
+ options: ["div", "section", "main"],
25
+ description: "HTML element to render as the root",
26
+ },
27
+ highlightsEqualWidths: {
28
+ control: "boolean",
29
+ description: "When true, highlight items share equal widths (grid). When false, items size to content (flex).",
30
+ },
31
+ highlightsJustify: {
32
+ control: { type: "select" },
33
+ options: ["start", "center", "end", "space-between", "space-around"],
34
+ description: "Justification of highlight items along the main axis",
35
+ },
36
+ maxWidth: {
37
+ control: { type: "select" },
38
+ options: ["", "600px", "800px", "1024px", "1200px", "1440px"],
39
+ description:
40
+ "Max width of the central content column. Gutters grow to enforce the constraint; below this width they hold at 16px.",
41
+ },
42
+ contentAlign: {
43
+ control: { type: "inline-radio" },
44
+ options: ["start", "center"],
45
+ description:
46
+ "Align the content column to the start (left gutter stays 16px, right takes remaining space) or center (equal gutters). Only meaningful when maxWidth is set.",
47
+ },
48
+ highlightTitleBaseline: {
49
+ control: "boolean",
50
+ description:
51
+ "When true, fixes the highlight title row to a set height so titles align to the header baseline. Override --highlight-title-height in the consuming page to tune the value.",
52
+ },
53
+ headerBackground: {
54
+ control: "color",
55
+ description: "Background colour of the header zone (sets --header-row-background-colour)",
56
+ },
57
+ contentBackground: {
58
+ control: "color",
59
+ description: "Background colour of the content zone (sets --content-row-background-color)",
60
+ },
61
+ highlightCount: {
62
+ control: { type: "select" },
63
+ options: [1, 2, 3],
64
+ description: "Number of highlight items to display in the highlights slot",
65
+ },
66
+ styleClassPassthrough: {
67
+ control: "object",
68
+ description: "Additional CSS classes applied to the root element",
69
+ },
70
+ },
71
+ args: {
72
+ tag: "div",
73
+ highlightsEqualWidths: false,
74
+ highlightsJustify: "start",
75
+ maxWidth: "",
76
+ contentAlign: "center",
77
+ highlightTitleBaseline: false,
78
+ headerBackground: "",
79
+ contentBackground: "",
80
+ highlightCount: 1,
81
+ styleClassPassthrough: [],
82
+ },
83
+ };
84
+
85
+ export default meta;
86
+ type Story = StoryObj<typeof PageHeroHighlights>;
87
+
88
+ // ─── Shared setup helper ──────────────────────────────────────────────────────
89
+
90
+ function useStorySetup(args: StoryArgs) {
91
+ const bgStyles = computed(() => ({
92
+ ...(args.headerBackground ? { "--header-row-background-colour": args.headerBackground } : {}),
93
+ ...(args.contentBackground ? { "--content-row-background-color": args.contentBackground } : {}),
94
+ }));
95
+ const highlightCount = computed(() => args.highlightCount ?? 3);
96
+ const componentArgs = computed(() => {
97
+ const { headerBackground: _h, contentBackground: _c, highlightCount: _n, ...rest } = args;
98
+ return rest;
99
+ });
100
+ return { bgStyles, componentArgs, highlightCount };
101
+ }
102
+
103
+ // ─── Stories ─────────────────────────────────────────────────────────────────
104
+
105
+ /** Default — header, highlights strip, and page content with all three slots filled. */
106
+ export const Default: Story = {
107
+ parameters: {
108
+ docs: {
109
+ description: {
110
+ story: `
111
+ All layout and visual properties are customisable via CSS custom properties. Set them on \`.page-hero-highlights\` (or a scoped class via \`styleClassPassthrough\`):
112
+
113
+ \`\`\`css
114
+ .page-hero-highlights {
115
+ /* Header zone */
116
+ --header-row-background-colour: darkblue;
117
+
118
+ /* Highlights strip */
119
+ --highlights-row-item-gap: 1rem;
120
+ --highlights-row-initial-item-offset: 1.2rem;
121
+
122
+ /* Highlight cards */
123
+ --highlight-rows-gap: 1.2rem;
124
+ --highlight-title-height: 1fr; /* see: highlight-title-baseline prop */
125
+ --highlight-padding-block-start: 1.2rem;
126
+ --highlight-padding: 1.2rem;
127
+ --highlight-background-color: white;
128
+ --highlight-border: 1px solid black;
129
+ --highlight-border-radius: 8px;
130
+ --highlight-color: black;
131
+
132
+ /* Content zone */
133
+ --content-row-background-color: var(--slate-01); /* transparent */
134
+ --content-row-start-gap: 1.2rem;
135
+ --content-row-end-gap: 1.2rem;
136
+
137
+ /* Content slot decorative border */
138
+ --content-slot-margin-block-start: 2.4rem;
139
+ --content-slot-margin: var(--highlights-row-initial-item-offset);
140
+ --content-slot-background-color: var(--slate-00);
141
+ --content-slot-border: 1px solid var(--slate-06);
142
+ --content-slot-border-radius: 0.8rem;
143
+ --content-slot-outline: 1px solid var(--slate-02);
144
+
145
+ /* When using :highlight-title-baseline="true" */
146
+ &.highlight-title-baseline {
147
+ --highlight-title-height: 4rem; /* proportional value preferred */
148
+ --highlight-padding-block-start: 0;
149
+ }
150
+ }
151
+ \`\`\`
152
+ `,
153
+ },
154
+ },
155
+ },
156
+ render: (args: StoryArgs) => ({
157
+ components: { PageHeroHighlights },
158
+ setup() {
159
+ return useStorySetup(args);
160
+ },
161
+ template: `
162
+ <PageHeroHighlights v-bind="componentArgs" :style="bgStyles">
163
+ <template #header>
164
+ <div style="color: white; padding-block: 1.6rem;">
165
+ <p class="page-heading-1">Dashboard</p>
166
+ <p class="page-body-normal">Overview of your account activity and key metrics.</p>
167
+ </div>
168
+ </template>
169
+
170
+ <template #highlights>
171
+ <div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
172
+ <p class="page-heading-2">Total Revenue</p>
173
+ <p class="page-body-normal">£24,500</p>
174
+ </div>
175
+ <div v-if="highlightCount >= 2" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
176
+ <p class="page-heading-2">Active Users</p>
177
+ <p class="page-body-normal">1,284</p>
178
+ </div>
179
+ <div v-if="highlightCount >= 3" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
180
+ <p class="page-heading-2">Open Tasks</p>
181
+ <p class="page-body-normal">37</p>
182
+ </div>
183
+ </template>
184
+
185
+ <template #content>
186
+ <pre style="padding: 1.6rem; font-size: 1.2rem; line-height: 1.6; overflow-x: auto;">/* ─── PageHeroHighlights CSS tokens ─────────────────────────────────
187
+ Set on .page-hero-highlights (or a scoped styleClassPassthrough class).
188
+ Update values as needed. Delete tokens you are not overriding.
189
+ ─────────────────────────────────────────────────────────────────── */
190
+ .page-hero-highlights {
191
+
192
+ /* Header zone */
193
+ --header-row-background-colour: darkblue;
194
+
195
+ /* Highlights strip */
196
+ --highlights-row-item-gap: 1rem;
197
+ --highlights-row-initial-item-offset: 1.2rem;
198
+
199
+ /* Highlight cards */
200
+ --highlight-rows-gap: 1.2rem;
201
+ --highlight-title-height: 1fr; /* see: highlight-title-baseline prop */
202
+ --highlight-padding-block-start: 1.2rem;
203
+ --highlight-padding: 1.2rem;
204
+ --highlight-background-color: white;
205
+ --highlight-border: 1px solid black;
206
+ --highlight-border-radius: 8px;
207
+ --highlight-color: black;
208
+
209
+ /* Content zone */
210
+ --content-row-background-color: var(--slate-01); /* transparent */
211
+ --content-row-start-gap: 1.2rem;
212
+ --content-row-end-gap: 1.2rem;
213
+
214
+ /* Content slot decorative border */
215
+ --content-slot-margin-block-start: 2.4rem;
216
+ --content-slot-margin: var(--highlights-row-initial-item-offset);
217
+ --content-slot-background-color: var(--slate-00);
218
+ --content-slot-border: 1px solid var(--slate-06);
219
+ --content-slot-border-radius: 0.8rem;
220
+ --content-slot-outline: 1px solid var(--slate-02);
221
+
222
+ /* When using :highlight-title-baseline="true" */
223
+ &.highlight-title-baseline {
224
+ --highlight-title-height: 4rem; /* proportional value preferred */
225
+ --highlight-padding-block-start: 0;
226
+ }
227
+ }</pre>
228
+ </template>
229
+ </PageHeroHighlights>
230
+ `,
231
+ }),
232
+ };
233
+
234
+ /** As section tag — root renders as a semantic section with aria-labelledby wired to the heading. */
235
+ export const AsSectionTag: Story = {
236
+ name: "As section Tag",
237
+ args: { tag: "section" },
238
+ render: (args: StoryArgs) => ({
239
+ components: { PageHeroHighlights },
240
+ setup() {
241
+ return useStorySetup(args);
242
+ },
243
+ template: `
244
+ <PageHeroHighlights v-bind="componentArgs" :style="bgStyles">
245
+ <template #header="{ headingId }">
246
+ <h1 :id="headingId" class="page-heading-1">Dashboard</h1>
247
+ <p class="page-body-normal">Overview of your account activity and key metrics.</p>
248
+ </template>
249
+
250
+ <template #highlights>
251
+ <div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
252
+ <p class="page-heading-2">Total Revenue</p>
253
+ <p class="page-body-normal">£24,500</p>
254
+ </div>
255
+ <div v-if="highlightCount >= 2" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
256
+ <p class="page-heading-2">Active Users</p>
257
+ <p class="page-body-normal">1,284</p>
258
+ </div>
259
+ <div v-if="highlightCount >= 3" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
260
+ <p class="page-heading-2">Open Tasks</p>
261
+ <p class="page-body-normal">37</p>
262
+ </div>
263
+ </template>
264
+
265
+ <template #content>
266
+ <p class="page-heading-2">Recent Activity</p>
267
+ <p class="page-body-normal">Your most recent transactions and events will appear here.</p>
268
+ </template>
269
+ </PageHeroHighlights>
270
+ `,
271
+ }),
272
+ };
273
+
274
+ /** Equal widths — highlights items share equal column widths via grid. */
275
+ export const EqualWidthHighlights: Story = {
276
+ name: "Equal Width Highlights",
277
+ args: { highlightsEqualWidths: true },
278
+ render: (args: StoryArgs) => ({
279
+ components: { PageHeroHighlights },
280
+ setup() {
281
+ return useStorySetup(args);
282
+ },
283
+ template: `
284
+ <PageHeroHighlights v-bind="componentArgs" :style="bgStyles">
285
+ <template #header>
286
+ <p class="page-heading-1">Dashboard</p>
287
+ <p class="page-body-normal">Overview of your account activity and key metrics.</p>
288
+ </template>
289
+
290
+ <template #highlights>
291
+ <div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
292
+ <p class="page-heading-2">Total Revenue</p>
293
+ <p class="page-body-normal">£24,500</p>
294
+ </div>
295
+ <div v-if="highlightCount >= 2" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
296
+ <p class="page-heading-2">Active Users</p>
297
+ <p class="page-body-normal">1,284</p>
298
+ </div>
299
+ <div v-if="highlightCount >= 3" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
300
+ <p class="page-heading-2">Open Tasks</p>
301
+ <p class="page-body-normal">37</p>
302
+ </div>
303
+ </template>
304
+
305
+ <template #content>
306
+ <p class="page-heading-2">Recent Activity</p>
307
+ <p class="page-body-normal">Your most recent transactions and events will appear here.</p>
308
+ </template>
309
+ </PageHeroHighlights>
310
+ `,
311
+ }),
312
+ };
313
+
314
+ /** Minimal — renders with no slot content to show the bare grid structure. */
315
+ export const NoSlotContent: Story = {
316
+ name: "No Slot Content",
317
+ render: (args: StoryArgs) => ({
318
+ components: { PageHeroHighlights },
319
+ setup() {
320
+ return useStorySetup(args);
321
+ },
322
+ template: `<PageHeroHighlights v-bind="componentArgs" :style="bgStyles" />`,
323
+ }),
324
+ };
325
+
326
+ /** Max width centered — content column capped at 800px with equal growing gutters either side. */
327
+ export const MaxWidthCentered: Story = {
328
+ name: "Max Width — Centered",
329
+ args: { maxWidth: "800px", contentAlign: "center" },
330
+ render: (args: StoryArgs) => ({
331
+ components: { PageHeroHighlights },
332
+ setup() {
333
+ return useStorySetup(args);
334
+ },
335
+ template: `
336
+ <PageHeroHighlights v-bind="componentArgs" :style="bgStyles">
337
+ <template #header>
338
+ <p class="page-heading-1">Dashboard</p>
339
+ <p class="page-body-normal">Content column is capped at 800px — gutters grow equally on both sides.</p>
340
+ </template>
341
+
342
+ <template #highlights>
343
+ <div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
344
+ <p class="page-heading-2">Total Revenue</p>
345
+ <p class="page-body-normal">£24,500</p>
346
+ </div>
347
+ <div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
348
+ <p class="page-heading-2">Active Users</p>
349
+ <p class="page-body-normal">1,284</p>
350
+ </div>
351
+ <div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
352
+ <p class="page-heading-2">Open Tasks</p>
353
+ <p class="page-body-normal">37</p>
354
+ </div>
355
+ </template>
356
+
357
+ <template #content>
358
+ <p class="page-heading-2">Recent Activity</p>
359
+ <p class="page-body-normal">Your most recent transactions and events will appear here.</p>
360
+ </template>
361
+ </PageHeroHighlights>
362
+ `,
363
+ }),
364
+ };
365
+
366
+ /** Max width start — content column capped at 800px, pinned to the left with a fixed 16px gutter. */
367
+ export const MaxWidthStart: Story = {
368
+ name: "Max Width — Start",
369
+ args: { maxWidth: "800px", contentAlign: "start" },
370
+ render: (args: StoryArgs) => ({
371
+ components: { PageHeroHighlights },
372
+ setup() {
373
+ return useStorySetup(args);
374
+ },
375
+ template: `
376
+ <PageHeroHighlights v-bind="componentArgs" :style="bgStyles">
377
+ <template #header>
378
+ <p class="page-heading-1">Dashboard</p>
379
+ <p class="page-body-normal">Content column is capped at 800px, aligned to the start — right side takes the remaining space.</p>
380
+ </template>
381
+
382
+ <template #highlights>
383
+ <div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
384
+ <p class="page-heading-2">Total Revenue</p>
385
+ <p class="page-body-normal">£24,500</p>
386
+ </div>
387
+ <div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
388
+ <p class="page-heading-2">Active Users</p>
389
+ <p class="page-body-normal">1,284</p>
390
+ </div>
391
+ <div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
392
+ <p class="page-heading-2">Open Tasks</p>
393
+ <p class="page-body-normal">37</p>
394
+ </div>
395
+ </template>
396
+
397
+ <template #content>
398
+ <p class="page-heading-2">Recent Activity</p>
399
+ <p class="page-body-normal">Your most recent transactions and events will appear here.</p>
400
+ </template>
401
+ </PageHeroHighlights>
402
+ `,
403
+ }),
404
+ };