srcdev-nuxt-components 9.6.6 → 9.6.7
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/components/page-hero-highlights.md +22 -18
- package/.claude/skills/index.md +1 -1
- package/.vscode/srcdev-component-page-hero-highlights.code-snippets +2 -1
- package/app/components/04.templates/page-hero-highlights/CONSUMER-STYLING.md +32 -12
- package/app/components/04.templates/page-hero-highlights/PageHeroHighlights.vue +56 -47
- package/app/components/04.templates/page-hero-highlights/stories/PageHeroHighlights.stories.ts +158 -307
- package/app/components/04.templates/page-hero-highlights/stories/PageHeroHighlightsHeader.stories.ts +10 -0
- package/app/components/04.templates/page-hero-highlights/tests/PageHeroHighlights.spec.ts +49 -27
- package/app/components/04.templates/page-hero-highlights/tests/PageHeroHighlightsHeader.spec.ts +42 -7
- package/app/components/04.templates/page-hero-highlights/tests/__snapshots__/PageHeroHighlights.spec.ts.snap +12 -10
- package/package.json +1 -1
package/app/components/04.templates/page-hero-highlights/stories/PageHeroHighlights.stories.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { computed } from "vue";
|
|
1
|
+
import { computed, ref } from "vue";
|
|
2
2
|
import PageHeroHighlights from "../PageHeroHighlights.vue";
|
|
3
|
+
import CanvasSwitcher from "../../../01.atoms/canvas-switcher/CanvasSwitcher.vue";
|
|
3
4
|
import type { Meta, StoryObj } from "@nuxtjs/storybook";
|
|
5
|
+
import type { MediaCanvas } from "~/types/components";
|
|
4
6
|
|
|
5
7
|
type StoryArgs = {
|
|
6
8
|
tag?: "div" | "section" | "main";
|
|
@@ -12,7 +14,7 @@ type StoryArgs = {
|
|
|
12
14
|
highlightTitleBaseline?: boolean;
|
|
13
15
|
headerBackground?: string;
|
|
14
16
|
contentBackground?: string;
|
|
15
|
-
highlightCount?:
|
|
17
|
+
highlightCount?: number;
|
|
16
18
|
styleClassPassthrough?: string | string[];
|
|
17
19
|
};
|
|
18
20
|
|
|
@@ -23,11 +25,12 @@ const meta: Meta<StoryArgs> = {
|
|
|
23
25
|
tag: {
|
|
24
26
|
control: { type: "select" },
|
|
25
27
|
options: ["div", "section", "main"],
|
|
26
|
-
description: "HTML element to render as the root",
|
|
28
|
+
description: "HTML element to render as the root. `section` wires `aria-labelledby` to the heading bound to the `header` slot's `headingId`.",
|
|
27
29
|
},
|
|
28
30
|
highlightsEqualWidths: {
|
|
29
31
|
control: "boolean",
|
|
30
|
-
description:
|
|
32
|
+
description:
|
|
33
|
+
"When true, highlight items share equal widths and wrap onto new rows below `--page-hero-highlights-item-min-width` (default 12rem). When false, items size to content (flex).",
|
|
31
34
|
},
|
|
32
35
|
highlightsJustify: {
|
|
33
36
|
control: { type: "select" },
|
|
@@ -37,36 +40,38 @@ const meta: Meta<StoryArgs> = {
|
|
|
37
40
|
widthConstrained: {
|
|
38
41
|
control: "boolean",
|
|
39
42
|
description:
|
|
40
|
-
"When true, caps the central column at
|
|
43
|
+
"When true, caps the central column at `--page-hero-highlights-max-width` (default 1064px); the gutters grow to enforce it. When false, the column fills the width between the gutters.",
|
|
41
44
|
},
|
|
42
45
|
contentAlign: {
|
|
43
46
|
control: { type: "inline-radio" },
|
|
44
47
|
options: ["start", "center"],
|
|
45
48
|
description:
|
|
46
|
-
"
|
|
49
|
+
"With `widthConstrained`: `center` grows both gutters equally, `start` keeps the start gutter and gives the remaining space to the end gutter. No effect otherwise.",
|
|
47
50
|
},
|
|
48
51
|
contentPanel: {
|
|
49
52
|
control: "boolean",
|
|
50
53
|
description:
|
|
51
|
-
"When true (default), renders a decorative panel behind the content slot and
|
|
54
|
+
"When true (default), renders a decorative panel behind the content slot and insets the highlights strip. Set to false for a flat layout with no backdrop.",
|
|
52
55
|
},
|
|
53
56
|
highlightTitleBaseline: {
|
|
54
57
|
control: "boolean",
|
|
55
58
|
description:
|
|
56
|
-
"When true, fixes the highlight title row to
|
|
59
|
+
"When true, fixes the highlight title row to `--page-hero-highlights-title-height-baseline` so titles line up on the header's baseline.",
|
|
57
60
|
},
|
|
58
61
|
headerBackground: {
|
|
59
62
|
control: "color",
|
|
60
|
-
description: "
|
|
63
|
+
description: "**Story control, not a prop.** Sets `--page-hero-highlights-header-background`.",
|
|
64
|
+
table: { category: "Story only" },
|
|
61
65
|
},
|
|
62
66
|
contentBackground: {
|
|
63
67
|
control: "color",
|
|
64
|
-
description: "
|
|
68
|
+
description: "**Story control, not a prop.** Sets `--page-hero-highlights-content-background`.",
|
|
69
|
+
table: { category: "Story only" },
|
|
65
70
|
},
|
|
66
71
|
highlightCount: {
|
|
67
|
-
control: { type: "
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
control: { type: "range", min: 1, max: 6, step: 1 },
|
|
73
|
+
description: "**Story control, not a prop.** Number of highlight items rendered in the `highlights` slot.",
|
|
74
|
+
table: { category: "Story only" },
|
|
70
75
|
},
|
|
71
76
|
styleClassPassthrough: {
|
|
72
77
|
control: "object",
|
|
@@ -83,252 +88,137 @@ const meta: Meta<StoryArgs> = {
|
|
|
83
88
|
highlightTitleBaseline: false,
|
|
84
89
|
headerBackground: "",
|
|
85
90
|
contentBackground: "",
|
|
86
|
-
highlightCount:
|
|
91
|
+
highlightCount: 3,
|
|
87
92
|
styleClassPassthrough: [],
|
|
88
93
|
},
|
|
94
|
+
decorators: [
|
|
95
|
+
(story, context) => ({
|
|
96
|
+
components: { story, CanvasSwitcher },
|
|
97
|
+
setup() {
|
|
98
|
+
const canvasName = ref<MediaCanvas>(context.parameters.initialCanvas ?? "fullWidthCanvas");
|
|
99
|
+
return { canvasName };
|
|
100
|
+
},
|
|
101
|
+
template: `
|
|
102
|
+
<div style="padding: 1.2rem 1.6rem; border-block-end: 1px solid currentColor;">
|
|
103
|
+
<CanvasSwitcher v-model:canvas-name="canvasName" />
|
|
104
|
+
</div>
|
|
105
|
+
<div :class="canvasName" style="margin-inline: auto; outline: 1px dashed currentColor;">
|
|
106
|
+
<story />
|
|
107
|
+
</div>
|
|
108
|
+
`,
|
|
109
|
+
}),
|
|
110
|
+
],
|
|
111
|
+
parameters: {
|
|
112
|
+
layout: "fullscreen",
|
|
113
|
+
docs: {
|
|
114
|
+
description: {
|
|
115
|
+
component:
|
|
116
|
+
"A page-level template: a full-bleed header zone (`header` slot, scoped `headingId`), a highlights strip that straddles the header/content boundary (`highlights` slot), " +
|
|
117
|
+
"and a content zone with an optional decorative panel (`content` slot). Give each highlight the `page-hero-highlights-item` class with `-item-title` and `-item-body` children for the card styling. " +
|
|
118
|
+
"Gutters step at 768px and 1024px of the component's own width. Every colour and spacing value is a `--page-hero-highlights-*` token (see CONSUMER-STYLING.md). " +
|
|
119
|
+
"Pair it with `PageHeroHighlightsHeader` for a title plus actions header.",
|
|
120
|
+
},
|
|
121
|
+
story: { inline: false, height: "640px" },
|
|
122
|
+
},
|
|
123
|
+
},
|
|
89
124
|
};
|
|
90
125
|
|
|
91
126
|
export default meta;
|
|
92
|
-
type Story = StoryObj<
|
|
127
|
+
type Story = StoryObj<StoryArgs>;
|
|
93
128
|
|
|
94
129
|
// ─── Shared setup helper ──────────────────────────────────────────────────────
|
|
95
130
|
|
|
131
|
+
const sampleHighlights = [
|
|
132
|
+
{ title: "Total revenue", body: "£24,500" },
|
|
133
|
+
{ title: "Active users", body: "1,284" },
|
|
134
|
+
{ title: "Open tasks", body: "37" },
|
|
135
|
+
{ title: "Bookings this week", body: "112" },
|
|
136
|
+
{ title: "Average rating", body: "4.8" },
|
|
137
|
+
{ title: "Repeat clients", body: "62%" },
|
|
138
|
+
];
|
|
139
|
+
|
|
96
140
|
function useStorySetup(args: StoryArgs) {
|
|
97
141
|
const bgStyles = computed(() => ({
|
|
98
142
|
...(args.headerBackground ? { "--page-hero-highlights-header-background": args.headerBackground } : {}),
|
|
99
143
|
...(args.contentBackground ? { "--page-hero-highlights-content-background": args.contentBackground } : {}),
|
|
100
144
|
}));
|
|
101
|
-
const
|
|
145
|
+
const highlights = computed(() => sampleHighlights.slice(0, args.highlightCount ?? 3));
|
|
102
146
|
const componentArgs = computed(() => {
|
|
103
147
|
const { headerBackground: _h, contentBackground: _c, highlightCount: _n, ...rest } = args;
|
|
104
148
|
return rest;
|
|
105
149
|
});
|
|
106
|
-
return { bgStyles, componentArgs,
|
|
150
|
+
return { bgStyles, componentArgs, highlights };
|
|
107
151
|
}
|
|
108
152
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
--page-hero-highlights-header-background: darkblue;
|
|
129
|
-
|
|
130
|
-
/* Highlights strip */
|
|
131
|
-
--page-hero-highlights-strip-gap: 1rem;
|
|
132
|
-
--page-hero-highlights-strip-inset: 1.2rem;
|
|
133
|
-
|
|
134
|
-
/* Highlight cards */
|
|
135
|
-
--page-hero-highlights-item-rows-gap: 1.2rem;
|
|
136
|
-
--page-hero-highlights-title-height: 1fr; /* see: highlight-title-baseline prop */
|
|
137
|
-
--page-hero-highlights-item-padding-block-start: 1.2rem;
|
|
138
|
-
--page-hero-highlights-item-padding: 1.2rem;
|
|
139
|
-
--page-hero-highlights-item-background: white;
|
|
140
|
-
--page-hero-highlights-item-border: 1px solid black;
|
|
141
|
-
--page-hero-highlights-item-border-radius: 8px;
|
|
142
|
-
--page-hero-highlights-item-colour: black;
|
|
143
|
-
|
|
144
|
-
/* Content zone */
|
|
145
|
-
--page-hero-highlights-content-background: var(--slate-01); /* transparent */
|
|
146
|
-
--page-hero-highlights-content-start-gap: 1.2rem;
|
|
147
|
-
--page-hero-highlights-content-end-gap: 1.2rem;
|
|
148
|
-
|
|
149
|
-
/* Content slot decorative border */
|
|
150
|
-
--page-hero-highlights-content-margin-block-start: 2.4rem;
|
|
151
|
-
--page-hero-highlights-content-margin: var(--page-hero-highlights-strip-inset);
|
|
152
|
-
--page-hero-highlights-panel-background: var(--slate-00);
|
|
153
|
-
--page-hero-highlights-panel-border: 1px solid var(--slate-06);
|
|
154
|
-
--page-hero-highlights-panel-border-radius: 0.8rem;
|
|
155
|
-
--page-hero-highlights-panel-outline: 1px solid var(--slate-02);
|
|
156
|
-
|
|
157
|
-
/* When using :highlight-title-baseline="true" */
|
|
158
|
-
--page-hero-highlights-title-height-baseline: 4rem; /* proportional value preferred */
|
|
159
|
-
--page-hero-highlights-item-padding-block-start-baseline: 0;
|
|
160
|
-
}
|
|
161
|
-
\`\`\`
|
|
162
|
-
`,
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
render: (args: StoryArgs) => ({
|
|
153
|
+
const highlightsTemplate = `
|
|
154
|
+
<template #highlights>
|
|
155
|
+
<div v-for="item in highlights" :key="item.title" class="page-hero-highlights-item">
|
|
156
|
+
<p class="page-hero-highlights-item-title page-heading-4">{{ item.title }}</p>
|
|
157
|
+
<p class="page-hero-highlights-item-body page-body-normal">{{ item.body }}</p>
|
|
158
|
+
</div>
|
|
159
|
+
</template>
|
|
160
|
+
`;
|
|
161
|
+
|
|
162
|
+
const contentTemplate = `
|
|
163
|
+
<template #content>
|
|
164
|
+
<p class="page-heading-2">Recent activity</p>
|
|
165
|
+
<p class="page-body-normal">Your most recent transactions and events will appear here.</p>
|
|
166
|
+
</template>
|
|
167
|
+
`;
|
|
168
|
+
|
|
169
|
+
const render =
|
|
170
|
+
(header: string): Story["render"] =>
|
|
171
|
+
(args) => ({
|
|
167
172
|
components: { PageHeroHighlights },
|
|
168
173
|
setup() {
|
|
169
174
|
return useStorySetup(args);
|
|
170
175
|
},
|
|
171
176
|
template: `
|
|
172
177
|
<PageHeroHighlights v-bind="componentArgs" :style="bgStyles">
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
<template #highlights>
|
|
181
|
-
<div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
182
|
-
<p class="page-heading-2">Total Revenue</p>
|
|
183
|
-
<p class="page-body-normal">£24,500</p>
|
|
184
|
-
</div>
|
|
185
|
-
<div v-if="highlightCount >= 2" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
186
|
-
<p class="page-heading-2">Active Users</p>
|
|
187
|
-
<p class="page-body-normal">1,284</p>
|
|
188
|
-
</div>
|
|
189
|
-
<div v-if="highlightCount >= 3" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
190
|
-
<p class="page-heading-2">Open Tasks</p>
|
|
191
|
-
<p class="page-body-normal">37</p>
|
|
192
|
-
</div>
|
|
193
|
-
</template>
|
|
194
|
-
|
|
195
|
-
<template #content>
|
|
196
|
-
<pre style="padding: 1.6rem; font-size: 1.2rem; line-height: 1.6; overflow-x: auto;">/* ─── PageHeroHighlights CSS tokens ─────────────────────────────────
|
|
197
|
-
Set on .page-hero-highlights (or a scoped styleClassPassthrough class).
|
|
198
|
-
Update values as needed. Delete tokens you are not overriding.
|
|
199
|
-
─────────────────────────────────────────────────────────────────── */
|
|
200
|
-
.page-hero-highlights {
|
|
201
|
-
|
|
202
|
-
/* Grid layout */
|
|
203
|
-
--page-hero-highlights-max-width: 1064px;
|
|
204
|
-
--page-hero-highlights-gutter-mobile: 16px;
|
|
205
|
-
--page-hero-highlights-gutter-tablet: 40px;
|
|
206
|
-
--page-hero-highlights-gutter-desktop: 32px;
|
|
207
|
-
|
|
208
|
-
/* Header zone */
|
|
209
|
-
--page-hero-highlights-header-background: darkblue;
|
|
210
|
-
|
|
211
|
-
/* Highlights strip */
|
|
212
|
-
--page-hero-highlights-strip-gap: 1rem;
|
|
213
|
-
--page-hero-highlights-strip-inset: 1.2rem;
|
|
214
|
-
|
|
215
|
-
/* Highlight cards */
|
|
216
|
-
--page-hero-highlights-item-rows-gap: 1.2rem;
|
|
217
|
-
--page-hero-highlights-title-height: 1fr; /* see: highlight-title-baseline prop */
|
|
218
|
-
--page-hero-highlights-item-padding-block-start: 1.2rem;
|
|
219
|
-
--page-hero-highlights-item-padding: 1.2rem;
|
|
220
|
-
--page-hero-highlights-item-background: white;
|
|
221
|
-
--page-hero-highlights-item-border: 1px solid black;
|
|
222
|
-
--page-hero-highlights-item-border-radius: 8px;
|
|
223
|
-
--page-hero-highlights-item-colour: black;
|
|
178
|
+
${header}
|
|
179
|
+
${highlightsTemplate}
|
|
180
|
+
${contentTemplate}
|
|
181
|
+
</PageHeroHighlights>
|
|
182
|
+
`,
|
|
183
|
+
});
|
|
224
184
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
185
|
+
const plainHeader = (copy: string) => `
|
|
186
|
+
<template #header>
|
|
187
|
+
<p class="page-heading-1">Dashboard</p>
|
|
188
|
+
<p class="page-body-normal">${copy}</p>
|
|
189
|
+
</template>
|
|
190
|
+
`;
|
|
229
191
|
|
|
230
|
-
|
|
231
|
-
--page-hero-highlights-content-margin-block-start: 2.4rem;
|
|
232
|
-
--page-hero-highlights-content-margin: var(--page-hero-highlights-strip-inset);
|
|
233
|
-
--page-hero-highlights-panel-background: var(--slate-00);
|
|
234
|
-
--page-hero-highlights-panel-border: 1px solid var(--slate-06);
|
|
235
|
-
--page-hero-highlights-panel-border-radius: 0.8rem;
|
|
236
|
-
--page-hero-highlights-panel-outline: 1px solid var(--slate-02);
|
|
192
|
+
// ─── Stories ─────────────────────────────────────────────────────────────────
|
|
237
193
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}</pre>
|
|
242
|
-
</template>
|
|
243
|
-
</PageHeroHighlights>
|
|
244
|
-
`,
|
|
245
|
-
}),
|
|
194
|
+
/** Default — header, highlights strip and page content, with the library's light defaults. */
|
|
195
|
+
export const Default: Story = {
|
|
196
|
+
render: render(plainHeader("Overview of your account activity and key metrics.")),
|
|
246
197
|
};
|
|
247
198
|
|
|
248
199
|
/** As section tag — root renders as a semantic section with aria-labelledby wired to the heading. */
|
|
249
200
|
export const AsSectionTag: Story = {
|
|
250
201
|
name: "As section Tag",
|
|
251
202
|
args: { tag: "section" },
|
|
252
|
-
render: (
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
<PageHeroHighlights v-bind="componentArgs" :style="bgStyles">
|
|
259
|
-
<template #header="{ headingId }">
|
|
260
|
-
<h1 :id="headingId" class="page-heading-1">Dashboard</h1>
|
|
261
|
-
<p class="page-body-normal">Overview of your account activity and key metrics.</p>
|
|
262
|
-
</template>
|
|
263
|
-
|
|
264
|
-
<template #highlights>
|
|
265
|
-
<div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
266
|
-
<p class="page-heading-2">Total Revenue</p>
|
|
267
|
-
<p class="page-body-normal">£24,500</p>
|
|
268
|
-
</div>
|
|
269
|
-
<div v-if="highlightCount >= 2" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
270
|
-
<p class="page-heading-2">Active Users</p>
|
|
271
|
-
<p class="page-body-normal">1,284</p>
|
|
272
|
-
</div>
|
|
273
|
-
<div v-if="highlightCount >= 3" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
274
|
-
<p class="page-heading-2">Open Tasks</p>
|
|
275
|
-
<p class="page-body-normal">37</p>
|
|
276
|
-
</div>
|
|
277
|
-
</template>
|
|
278
|
-
|
|
279
|
-
<template #content>
|
|
280
|
-
<p class="page-heading-2">Recent Activity</p>
|
|
281
|
-
<p class="page-body-normal">Your most recent transactions and events will appear here.</p>
|
|
282
|
-
</template>
|
|
283
|
-
</PageHeroHighlights>
|
|
284
|
-
`,
|
|
285
|
-
}),
|
|
203
|
+
render: render(`
|
|
204
|
+
<template #header="{ headingId }">
|
|
205
|
+
<h1 :id="headingId" class="page-heading-1">Dashboard</h1>
|
|
206
|
+
<p class="page-body-normal">The section is labelled by this heading through the header slot's headingId.</p>
|
|
207
|
+
</template>
|
|
208
|
+
`),
|
|
286
209
|
};
|
|
287
210
|
|
|
288
|
-
/** Equal widths —
|
|
211
|
+
/** Equal widths — highlight items share equal widths and wrap below their minimum width. */
|
|
289
212
|
export const EqualWidthHighlights: Story = {
|
|
290
213
|
name: "Equal Width Highlights",
|
|
291
|
-
args: { highlightsEqualWidths: true },
|
|
292
|
-
render: (
|
|
293
|
-
components: { PageHeroHighlights },
|
|
294
|
-
setup() {
|
|
295
|
-
return useStorySetup(args);
|
|
296
|
-
},
|
|
297
|
-
template: `
|
|
298
|
-
<PageHeroHighlights v-bind="componentArgs" :style="bgStyles">
|
|
299
|
-
<template #header>
|
|
300
|
-
<p class="page-heading-1">Dashboard</p>
|
|
301
|
-
<p class="page-body-normal">Overview of your account activity and key metrics.</p>
|
|
302
|
-
</template>
|
|
303
|
-
|
|
304
|
-
<template #highlights>
|
|
305
|
-
<div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
306
|
-
<p class="page-heading-2">Total Revenue</p>
|
|
307
|
-
<p class="page-body-normal">£24,500</p>
|
|
308
|
-
</div>
|
|
309
|
-
<div v-if="highlightCount >= 2" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
310
|
-
<p class="page-heading-2">Active Users</p>
|
|
311
|
-
<p class="page-body-normal">1,284</p>
|
|
312
|
-
</div>
|
|
313
|
-
<div v-if="highlightCount >= 3" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
314
|
-
<p class="page-heading-2">Open Tasks</p>
|
|
315
|
-
<p class="page-body-normal">37</p>
|
|
316
|
-
</div>
|
|
317
|
-
</template>
|
|
318
|
-
|
|
319
|
-
<template #content>
|
|
320
|
-
<p class="page-heading-2">Recent Activity</p>
|
|
321
|
-
<p class="page-body-normal">Your most recent transactions and events will appear here.</p>
|
|
322
|
-
</template>
|
|
323
|
-
</PageHeroHighlights>
|
|
324
|
-
`,
|
|
325
|
-
}),
|
|
214
|
+
args: { highlightsEqualWidths: true, highlightCount: 4 },
|
|
215
|
+
render: render(plainHeader("Four equal-width highlights. Switch to the mobile canvas to see them wrap two by two, then one per row.")),
|
|
326
216
|
};
|
|
327
217
|
|
|
328
218
|
/** Minimal — renders with no slot content to show the bare grid structure. */
|
|
329
219
|
export const NoSlotContent: Story = {
|
|
330
220
|
name: "No Slot Content",
|
|
331
|
-
render: (args
|
|
221
|
+
render: (args) => ({
|
|
332
222
|
components: { PageHeroHighlights },
|
|
333
223
|
setup() {
|
|
334
224
|
return useStorySetup(args);
|
|
@@ -337,122 +227,83 @@ export const NoSlotContent: Story = {
|
|
|
337
227
|
}),
|
|
338
228
|
};
|
|
339
229
|
|
|
340
|
-
/**
|
|
230
|
+
/** Width constrained, centred — content column capped at --page-hero-highlights-max-width with equal growing gutters. */
|
|
341
231
|
export const MaxWidthCentered: Story = {
|
|
342
232
|
name: "Max Width — Centered",
|
|
343
233
|
args: { widthConstrained: true, contentAlign: "center" },
|
|
344
|
-
render: (
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
return useStorySetup(args);
|
|
348
|
-
},
|
|
349
|
-
template: `
|
|
350
|
-
<PageHeroHighlights v-bind="componentArgs" :style="bgStyles">
|
|
351
|
-
<template #header>
|
|
352
|
-
<p class="page-heading-1">Dashboard</p>
|
|
353
|
-
<p class="page-body-normal">Content column is capped at --page-hero-highlights-max-width (1064px by default) — gutters grow equally on both sides.</p>
|
|
354
|
-
</template>
|
|
355
|
-
|
|
356
|
-
<template #highlights>
|
|
357
|
-
<div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
358
|
-
<p class="page-heading-2">Total Revenue</p>
|
|
359
|
-
<p class="page-body-normal">£24,500</p>
|
|
360
|
-
</div>
|
|
361
|
-
<div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
362
|
-
<p class="page-heading-2">Active Users</p>
|
|
363
|
-
<p class="page-body-normal">1,284</p>
|
|
364
|
-
</div>
|
|
365
|
-
<div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
366
|
-
<p class="page-heading-2">Open Tasks</p>
|
|
367
|
-
<p class="page-body-normal">37</p>
|
|
368
|
-
</div>
|
|
369
|
-
</template>
|
|
370
|
-
|
|
371
|
-
<template #content>
|
|
372
|
-
<p class="page-heading-2">Recent Activity</p>
|
|
373
|
-
<p class="page-body-normal">Your most recent transactions and events will appear here.</p>
|
|
374
|
-
</template>
|
|
375
|
-
</PageHeroHighlights>
|
|
376
|
-
`,
|
|
377
|
-
}),
|
|
234
|
+
render: render(
|
|
235
|
+
plainHeader("The central column is capped at --page-hero-highlights-max-width (1064px by default); both gutters grow equally. Use the full-width canvas on a wide screen.")
|
|
236
|
+
),
|
|
378
237
|
};
|
|
379
238
|
|
|
380
|
-
/**
|
|
239
|
+
/** Width constrained, start — content column capped at --page-hero-highlights-max-width and pinned to the start. */
|
|
381
240
|
export const MaxWidthStart: Story = {
|
|
382
241
|
name: "Max Width — Start",
|
|
383
242
|
args: { widthConstrained: true, contentAlign: "start" },
|
|
384
|
-
render: (
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
return useStorySetup(args);
|
|
388
|
-
},
|
|
389
|
-
template: `
|
|
390
|
-
<PageHeroHighlights v-bind="componentArgs" :style="bgStyles">
|
|
391
|
-
<template #header>
|
|
392
|
-
<p class="page-heading-1">Dashboard</p>
|
|
393
|
-
<p class="page-body-normal">Content column is capped at --page-hero-highlights-max-width (1064px by default), aligned to the start — right side takes the remaining space.</p>
|
|
394
|
-
</template>
|
|
395
|
-
|
|
396
|
-
<template #highlights>
|
|
397
|
-
<div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
398
|
-
<p class="page-heading-2">Total Revenue</p>
|
|
399
|
-
<p class="page-body-normal">£24,500</p>
|
|
400
|
-
</div>
|
|
401
|
-
<div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
402
|
-
<p class="page-heading-2">Active Users</p>
|
|
403
|
-
<p class="page-body-normal">1,284</p>
|
|
404
|
-
</div>
|
|
405
|
-
<div style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
406
|
-
<p class="page-heading-2">Open Tasks</p>
|
|
407
|
-
<p class="page-body-normal">37</p>
|
|
408
|
-
</div>
|
|
409
|
-
</template>
|
|
410
|
-
|
|
411
|
-
<template #content>
|
|
412
|
-
<p class="page-heading-2">Recent Activity</p>
|
|
413
|
-
<p class="page-body-normal">Your most recent transactions and events will appear here.</p>
|
|
414
|
-
</template>
|
|
415
|
-
</PageHeroHighlights>
|
|
416
|
-
`,
|
|
417
|
-
}),
|
|
243
|
+
render: render(
|
|
244
|
+
plainHeader("The central column is capped at --page-hero-highlights-max-width (1064px by default) and pinned to the start; the end gutter takes the remaining space.")
|
|
245
|
+
),
|
|
418
246
|
};
|
|
419
247
|
|
|
420
|
-
/** No content panel — flat layout with no backdrop or highlight
|
|
248
|
+
/** No content panel — flat layout with no backdrop or highlight inset behind the content slot. */
|
|
421
249
|
export const NoContentPanel: Story = {
|
|
422
250
|
name: "No Content Panel",
|
|
423
251
|
args: { contentPanel: false },
|
|
424
|
-
render: (
|
|
252
|
+
render: render(plainHeader("Flat layout: no decorative panel behind the content slot.")),
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const stressHighlights = [
|
|
256
|
+
{ title: "Donaudampfschifffahrtselektrizitätenhauptbetriebswerkbauunterbeamtengesellschaft", body: "Unbroken German compound in the title." },
|
|
257
|
+
{ title: "Monatlicher Gesamtumsatz aller Filialen im Vergleich zum Vorjahreszeitraum", body: "€1.234.567,89" },
|
|
258
|
+
{ title: "😀 Emoji first", body: "🎉🎉🎉" },
|
|
259
|
+
{ title: "<script>alert('xss')</script>", body: "HTML-like text must render as text." },
|
|
260
|
+
{ title: "إجمالي الإيرادات", body: "٢٤٬٥٠٠ ج.م", dir: "rtl" },
|
|
261
|
+
{ title: "", body: "Empty title." },
|
|
262
|
+
{ title: "A", body: "" },
|
|
263
|
+
{ title: "Link", body: "https://example.com/a-very-long-path-segment-without-any-spaces-at-all-in-it" },
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Stress test — unbroken and long translated text in the header, eight hostile highlights, a
|
|
268
|
+
* long URL in the content, inside the CanvasSwitcher (starts on mobile).
|
|
269
|
+
*/
|
|
270
|
+
export const StressTest: Story = {
|
|
271
|
+
name: "Stress Test (Worst-Case Data)",
|
|
272
|
+
args: { tag: "section", highlightsEqualWidths: true, widthConstrained: true },
|
|
273
|
+
render: (args) => ({
|
|
425
274
|
components: { PageHeroHighlights },
|
|
426
275
|
setup() {
|
|
427
|
-
return useStorySetup(args);
|
|
276
|
+
return { ...useStorySetup(args), stressHighlights };
|
|
428
277
|
},
|
|
429
278
|
template: `
|
|
430
279
|
<PageHeroHighlights v-bind="componentArgs" :style="bgStyles">
|
|
431
|
-
<template #header>
|
|
432
|
-
<
|
|
433
|
-
<p class="page-body-normal"
|
|
280
|
+
<template #header="{ headingId }">
|
|
281
|
+
<h1 :id="headingId" class="page-heading-1" style="overflow-wrap: anywhere;">Kundendienstmitarbeiterkontaktaufnahmeformularübersicht</h1>
|
|
282
|
+
<p class="page-body-normal">Übersicht über die Aktivitäten Ihres Kontos, die wichtigsten Kennzahlen und alle offenen Vorgänge der letzten dreißig Tage.</p>
|
|
434
283
|
</template>
|
|
435
|
-
|
|
436
284
|
<template #highlights>
|
|
437
|
-
<div
|
|
438
|
-
<p class="page-heading-
|
|
439
|
-
<p class="page-body-normal"
|
|
440
|
-
</div>
|
|
441
|
-
<div v-if="highlightCount >= 2" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
442
|
-
<p class="page-heading-2">Active Users</p>
|
|
443
|
-
<p class="page-body-normal">1,284</p>
|
|
444
|
-
</div>
|
|
445
|
-
<div v-if="highlightCount >= 3" style="border-radius: 12px; background: #1a1a2e; color: white; padding: 1.6rem;">
|
|
446
|
-
<p class="page-heading-2">Open Tasks</p>
|
|
447
|
-
<p class="page-body-normal">37</p>
|
|
285
|
+
<div v-for="(item, i) in stressHighlights" :key="i" class="page-hero-highlights-item" :dir="item.dir">
|
|
286
|
+
<p class="page-hero-highlights-item-title page-heading-4">{{ item.title }}</p>
|
|
287
|
+
<p class="page-hero-highlights-item-body page-body-normal">{{ item.body }}</p>
|
|
448
288
|
</div>
|
|
449
289
|
</template>
|
|
450
|
-
|
|
451
290
|
<template #content>
|
|
452
|
-
<p class="page-heading-2">
|
|
453
|
-
<p class="page-body-normal"
|
|
291
|
+
<p class="page-heading-2">Ergebnisse</p>
|
|
292
|
+
<p class="page-body-normal" style="overflow-wrap: anywhere;">https://example.com/another-very-long-path-segment-without-any-spaces-that-must-wrap-inside-the-panel</p>
|
|
454
293
|
</template>
|
|
455
294
|
</PageHeroHighlights>
|
|
456
295
|
`,
|
|
457
296
|
}),
|
|
297
|
+
parameters: {
|
|
298
|
+
initialCanvas: "mobileCanvas",
|
|
299
|
+
docs: {
|
|
300
|
+
description: {
|
|
301
|
+
story:
|
|
302
|
+
"Check every canvas width, with `highlightsEqualWidths` on and off: no horizontal scroll, the strip still straddles the header and content zones, " +
|
|
303
|
+
"cards wrap onto new rows rather than squeezing (equal widths) or overflowing (flexible), and the unbroken title and URL wrap inside their card. " +
|
|
304
|
+
"Gutters should step from 16px to 40px at 768px and to 32px at 1024px of the component's width. Slot text is the consumer's own markup, so the header and " +
|
|
305
|
+
"content paragraphs set their own `overflow-wrap`; highlight items get `overflow-wrap: anywhere` from the item class.",
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
},
|
|
458
309
|
};
|
package/app/components/04.templates/page-hero-highlights/stories/PageHeroHighlightsHeader.stories.ts
CHANGED
|
@@ -18,6 +18,16 @@ const meta: Meta<StoryArgs> = {
|
|
|
18
18
|
args: {
|
|
19
19
|
styleClassPassthrough: [],
|
|
20
20
|
},
|
|
21
|
+
parameters: {
|
|
22
|
+
docs: {
|
|
23
|
+
description: {
|
|
24
|
+
component:
|
|
25
|
+
"Lays out the `header` slot of [PageHeroHighlights](?path=/docs/templates-pageherohighlights--docs): a `start` slot (title and description) and an optional `end` slot (actions). " +
|
|
26
|
+
"They stack in a narrow header and sit side by side from 768px of the header slot's own width. `.page-hero-highlights-header-end` only renders when `end` is filled. Tokens: `--page-hero-highlights-header-*`. " +
|
|
27
|
+
"These stories set a dark header background to show light text; the library default is light.",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
21
31
|
};
|
|
22
32
|
|
|
23
33
|
export default meta;
|