@syscore/ui-library 1.4.0 → 1.5.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/client/components/ui/page-header.tsx +145 -0
- package/client/components/ui/standard-table.tsx +554 -0
- package/client/global.css +184 -33
- package/client/lib/concepts-mock-data.ts +797 -0
- package/client/ui/PageHeader.stories.tsx +150 -0
- package/client/ui/Panel.stories.tsx +1 -1
- package/client/ui/StandardTable.stories.tsx +311 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +42 -0
- package/dist/index.es.js +371 -0
- package/package.json +1 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import {
|
|
3
|
+
PageHeader,
|
|
4
|
+
PageHeaderTopSection,
|
|
5
|
+
PageHeaderLeftContent,
|
|
6
|
+
PageHeaderBadge,
|
|
7
|
+
PageHeaderTitle,
|
|
8
|
+
PageHeaderDescription,
|
|
9
|
+
} from "../components/ui/page-header";
|
|
10
|
+
import { BadgeCertificationBronze } from "../components/icons/AchievementBadges";
|
|
11
|
+
import { CodeBadge } from "../components/ui/code-badge";
|
|
12
|
+
import {
|
|
13
|
+
Tooltip,
|
|
14
|
+
TooltipTrigger,
|
|
15
|
+
TooltipContent,
|
|
16
|
+
} from "../components/ui/tooltip";
|
|
17
|
+
|
|
18
|
+
const meta = {
|
|
19
|
+
title: "Review/PageHeader",
|
|
20
|
+
component: PageHeader,
|
|
21
|
+
parameters: {
|
|
22
|
+
layout: "padded",
|
|
23
|
+
},
|
|
24
|
+
tags: ["autodocs"],
|
|
25
|
+
} satisfies Meta<typeof PageHeader>;
|
|
26
|
+
|
|
27
|
+
export default meta;
|
|
28
|
+
type Story = StoryObj<typeof meta>;
|
|
29
|
+
|
|
30
|
+
// Header variant 1: Explore the standard (simple title + conditional animated badge)
|
|
31
|
+
export const ExploreStandard: Story = {
|
|
32
|
+
render: () => {
|
|
33
|
+
const hasAnyExpanded = true;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<PageHeader>
|
|
37
|
+
<PageHeaderTopSection>
|
|
38
|
+
<PageHeaderTitle className="heading-small">
|
|
39
|
+
Explore the standard
|
|
40
|
+
</PageHeaderTitle>
|
|
41
|
+
<PageHeaderBadge animated show={hasAnyExpanded}>
|
|
42
|
+
<BadgeCertificationBronze />
|
|
43
|
+
</PageHeaderBadge>
|
|
44
|
+
</PageHeaderTopSection>
|
|
45
|
+
|
|
46
|
+
<PageHeaderDescription className="body-large">
|
|
47
|
+
Dive into a unified, harmonized WELL. Browse concepts, themes and
|
|
48
|
+
strategies that drive progress toward healthier, people-first places.
|
|
49
|
+
</PageHeaderDescription>
|
|
50
|
+
</PageHeader>
|
|
51
|
+
);
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Header variant 1: Without badge
|
|
56
|
+
export const ExploreStandardNoBadge: Story = {
|
|
57
|
+
render: () => {
|
|
58
|
+
const hasAnyExpanded = false;
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<PageHeader>
|
|
62
|
+
<PageHeaderTopSection>
|
|
63
|
+
<PageHeaderTitle className="heading-small">
|
|
64
|
+
Explore the standard
|
|
65
|
+
</PageHeaderTitle>
|
|
66
|
+
<PageHeaderBadge animated show={hasAnyExpanded}>
|
|
67
|
+
<BadgeCertificationBronze />
|
|
68
|
+
</PageHeaderBadge>
|
|
69
|
+
</PageHeaderTopSection>
|
|
70
|
+
|
|
71
|
+
<PageHeaderDescription className="body-large">
|
|
72
|
+
Dive into a unified, harmonized WELL. Browse concepts, themes and
|
|
73
|
+
strategies that drive progress toward healthier, people-first places.
|
|
74
|
+
</PageHeaderDescription>
|
|
75
|
+
</PageHeader>
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Header variant 2: Theme header (CodeBadge + Tooltip + permanent badge)
|
|
81
|
+
export const ThemeHeader: Story = {
|
|
82
|
+
render: () => {
|
|
83
|
+
const themeCode = "C8";
|
|
84
|
+
const conceptColor = {
|
|
85
|
+
solid: "#0f748a",
|
|
86
|
+
contrast: "#0f748a",
|
|
87
|
+
border: "#0f748a",
|
|
88
|
+
};
|
|
89
|
+
const themeData = {
|
|
90
|
+
name: "Occupant experience",
|
|
91
|
+
description:
|
|
92
|
+
"This theme focuses on understanding and improving the overall experience of building occupants through research and feedback mechanisms.",
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<PageHeader>
|
|
97
|
+
<PageHeaderTopSection className="mb-4">
|
|
98
|
+
<PageHeaderLeftContent>
|
|
99
|
+
<CodeBadge
|
|
100
|
+
code={themeCode}
|
|
101
|
+
style={{
|
|
102
|
+
backgroundColor: conceptColor.contrast || conceptColor.solid,
|
|
103
|
+
borderColor: conceptColor.border,
|
|
104
|
+
color: "white",
|
|
105
|
+
}}
|
|
106
|
+
/>
|
|
107
|
+
<Tooltip trigger="click">
|
|
108
|
+
<TooltipTrigger>
|
|
109
|
+
<span className="body-base text-gray-600 underline-dotted cursor-pointer">
|
|
110
|
+
Theme
|
|
111
|
+
</span>
|
|
112
|
+
</TooltipTrigger>
|
|
113
|
+
<TooltipContent className="max-w-[400px]">
|
|
114
|
+
<p className="body-base text-white">
|
|
115
|
+
Themes are groupings of related strategies that address
|
|
116
|
+
specific aspects of health and well-being within a concept
|
|
117
|
+
area.
|
|
118
|
+
</p>
|
|
119
|
+
</TooltipContent>
|
|
120
|
+
</Tooltip>
|
|
121
|
+
</PageHeaderLeftContent>
|
|
122
|
+
|
|
123
|
+
<PageHeaderBadge>
|
|
124
|
+
<BadgeCertificationBronze />
|
|
125
|
+
</PageHeaderBadge>
|
|
126
|
+
</PageHeaderTopSection>
|
|
127
|
+
|
|
128
|
+
<PageHeaderTitle className="heading-small mb-3">
|
|
129
|
+
{themeData.name}
|
|
130
|
+
</PageHeaderTitle>
|
|
131
|
+
<PageHeaderDescription className="body-large">
|
|
132
|
+
{themeData.description}
|
|
133
|
+
</PageHeaderDescription>
|
|
134
|
+
</PageHeader>
|
|
135
|
+
);
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Title only
|
|
140
|
+
export const TitleOnly: Story = {
|
|
141
|
+
render: () => {
|
|
142
|
+
return (
|
|
143
|
+
<PageHeader>
|
|
144
|
+
<PageHeaderTitle className="heading-small">
|
|
145
|
+
Title only header
|
|
146
|
+
</PageHeaderTitle>
|
|
147
|
+
</PageHeader>
|
|
148
|
+
);
|
|
149
|
+
},
|
|
150
|
+
};
|
|
@@ -57,7 +57,7 @@ const ExploreSidePanelView = (args: any) => {
|
|
|
57
57
|
|
|
58
58
|
return (
|
|
59
59
|
<LayoutGroup>
|
|
60
|
-
<Card className="space-y-
|
|
60
|
+
<Card className="space-y-2 rounded-r-none pt-8 border-r-0">
|
|
61
61
|
{/* CONCEPT Section */}
|
|
62
62
|
<motion.section layout="position" className="flex flex-col gap-3">
|
|
63
63
|
<Label className="px-2 text-gray-600 flex items-center min-w-0">
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import {
|
|
3
|
+
StandardTable,
|
|
4
|
+
StandardTableRow,
|
|
5
|
+
StandardTableContent,
|
|
6
|
+
StandardTableContainer,
|
|
7
|
+
StandardTableHeader,
|
|
8
|
+
StandardTableRowHeader,
|
|
9
|
+
StandardTableTrigger,
|
|
10
|
+
StandardTableListRow,
|
|
11
|
+
} from "@/components/ui/standard-table";
|
|
12
|
+
import { CodeBadge } from "@/components/ui/code-badge";
|
|
13
|
+
import { useState } from "react";
|
|
14
|
+
import { concepts } from "@/lib/concepts-mock-data";
|
|
15
|
+
import { getConceptColor } from "@/lib/concept-colors";
|
|
16
|
+
import { CONCEPT_ICONS } from "@/lib/concept-icons";
|
|
17
|
+
import { Text } from "@/components/ui/typography";
|
|
18
|
+
|
|
19
|
+
const meta = {
|
|
20
|
+
title: "Review/StandardTable",
|
|
21
|
+
component: StandardTable,
|
|
22
|
+
tags: ["autodocs"],
|
|
23
|
+
parameters: {
|
|
24
|
+
layout: "fullscreen",
|
|
25
|
+
},
|
|
26
|
+
} satisfies Meta<typeof StandardTable>;
|
|
27
|
+
|
|
28
|
+
export default meta;
|
|
29
|
+
|
|
30
|
+
type Story = StoryObj<typeof meta>;
|
|
31
|
+
|
|
32
|
+
export const Default: Story = {
|
|
33
|
+
render: () => {
|
|
34
|
+
const [expandedConcepts, setExpandedConcepts] = useState<Set<string>>(
|
|
35
|
+
new Set(),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const hasAnyExpanded = expandedConcepts.size > 0;
|
|
39
|
+
|
|
40
|
+
const toggleAllConcepts = () => {
|
|
41
|
+
if (hasAnyExpanded) {
|
|
42
|
+
setExpandedConcepts(new Set());
|
|
43
|
+
} else {
|
|
44
|
+
setExpandedConcepts(new Set(concepts.map((c) => c.id)));
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const navigateTo = (path: string) => {
|
|
49
|
+
console.log(path);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
function getSlugFromName(name: string) {
|
|
53
|
+
return name.toLowerCase().replace(/\s+/g, "-");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<StandardTableContainer>
|
|
58
|
+
<StandardTableHeader
|
|
59
|
+
title="CONCEPTS"
|
|
60
|
+
hasExpanded={hasAnyExpanded}
|
|
61
|
+
onToggleAll={toggleAllConcepts}
|
|
62
|
+
/>
|
|
63
|
+
|
|
64
|
+
<StandardTable
|
|
65
|
+
allowMultiple={true}
|
|
66
|
+
expandedValues={expandedConcepts}
|
|
67
|
+
onExpandedChange={setExpandedConcepts}
|
|
68
|
+
>
|
|
69
|
+
{[...concepts].map((concept) => {
|
|
70
|
+
const slug = getSlugFromName(concept.name);
|
|
71
|
+
const Icon = CONCEPT_ICONS[slug];
|
|
72
|
+
const color = getConceptColor(slug);
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<StandardTableRow key={concept.id} value={concept.id}>
|
|
76
|
+
<StandardTableRowHeader onClick={() => navigateTo("/")}>
|
|
77
|
+
<Icon active={true} className="size-12 shrink-0" />
|
|
78
|
+
<span className="overline-large flex-1">{concept.name}</span>
|
|
79
|
+
<StandardTableTrigger />
|
|
80
|
+
</StandardTableRowHeader>
|
|
81
|
+
|
|
82
|
+
<StandardTableContent>
|
|
83
|
+
{concept.themes.map((theme) => (
|
|
84
|
+
<StandardTableListRow
|
|
85
|
+
key={theme.id}
|
|
86
|
+
badge={
|
|
87
|
+
<CodeBadge
|
|
88
|
+
code={theme.code}
|
|
89
|
+
style={{
|
|
90
|
+
backgroundColor: color.contrast || color.solid,
|
|
91
|
+
borderColor: color.border,
|
|
92
|
+
color: "white",
|
|
93
|
+
}}
|
|
94
|
+
/>
|
|
95
|
+
}
|
|
96
|
+
title={theme.name}
|
|
97
|
+
variant="nested"
|
|
98
|
+
onClick={() => navigateTo("/")}
|
|
99
|
+
/>
|
|
100
|
+
))}
|
|
101
|
+
</StandardTableContent>
|
|
102
|
+
</StandardTableRow>
|
|
103
|
+
);
|
|
104
|
+
})}
|
|
105
|
+
</StandardTable>
|
|
106
|
+
</StandardTableContainer>
|
|
107
|
+
);
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const ConceptsTable: Story = {
|
|
112
|
+
render: () => {
|
|
113
|
+
const conceptSlug = "community";
|
|
114
|
+
|
|
115
|
+
const [expandedThemes, setExpandedThemes] = useState<Set<string>>(
|
|
116
|
+
new Set(),
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const hasAnyExpanded = expandedThemes.size > 0;
|
|
120
|
+
|
|
121
|
+
const toggleAllThemes = () => {
|
|
122
|
+
if (hasAnyExpanded) {
|
|
123
|
+
setExpandedThemes(new Set());
|
|
124
|
+
} else {
|
|
125
|
+
setExpandedThemes(new Set(conceptData?.themes.map((t) => t.id) || []));
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const navigateTo = (path: string) => {
|
|
130
|
+
console.log(path);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const conceptData = concepts.find(
|
|
134
|
+
(c) => c.name.toLowerCase() === conceptSlug.toLowerCase(),
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
const conceptColor = getConceptColor(conceptSlug);
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<StandardTableContainer>
|
|
141
|
+
<StandardTableHeader
|
|
142
|
+
title="THEMES"
|
|
143
|
+
hasExpanded={hasAnyExpanded}
|
|
144
|
+
onToggleAll={toggleAllThemes}
|
|
145
|
+
/>
|
|
146
|
+
|
|
147
|
+
<StandardTable
|
|
148
|
+
allowMultiple={true}
|
|
149
|
+
expandedValues={expandedThemes}
|
|
150
|
+
onExpandedChange={setExpandedThemes}
|
|
151
|
+
>
|
|
152
|
+
{conceptData?.themes.map((theme) => {
|
|
153
|
+
return (
|
|
154
|
+
<StandardTableRow key={theme.id} value={theme.id}>
|
|
155
|
+
<StandardTableRowHeader onClick={() => navigateTo("/")}>
|
|
156
|
+
<CodeBadge
|
|
157
|
+
code={theme.code}
|
|
158
|
+
style={{
|
|
159
|
+
backgroundColor:
|
|
160
|
+
conceptColor.contrast || conceptColor.solid,
|
|
161
|
+
borderColor: conceptColor.border,
|
|
162
|
+
color: "white",
|
|
163
|
+
}}
|
|
164
|
+
/>
|
|
165
|
+
<Text as="p" variant="body-large" className="flex-1">
|
|
166
|
+
{theme.name}
|
|
167
|
+
</Text>
|
|
168
|
+
<StandardTableTrigger />
|
|
169
|
+
</StandardTableRowHeader>
|
|
170
|
+
|
|
171
|
+
<StandardTableContent>
|
|
172
|
+
{theme.strategies.map((strategy) => (
|
|
173
|
+
<StandardTableListRow
|
|
174
|
+
key={strategy.id}
|
|
175
|
+
badge={
|
|
176
|
+
<CodeBadge
|
|
177
|
+
code={strategy.code}
|
|
178
|
+
style={{
|
|
179
|
+
backgroundColor: conceptColor.light,
|
|
180
|
+
borderColor: conceptColor.border,
|
|
181
|
+
color: conceptColor.contrast || conceptColor.solid,
|
|
182
|
+
}}
|
|
183
|
+
/>
|
|
184
|
+
}
|
|
185
|
+
title={strategy.name}
|
|
186
|
+
variant="nested"
|
|
187
|
+
onClick={() => navigateTo("/")}
|
|
188
|
+
rightContent={
|
|
189
|
+
<span className="flex justify-center items-center number-large font-semibold">
|
|
190
|
+
{strategy.points}{" "}
|
|
191
|
+
<span className="overline-medium ml-1">
|
|
192
|
+
PT
|
|
193
|
+
<span
|
|
194
|
+
className={
|
|
195
|
+
strategy.points === "1"
|
|
196
|
+
? "opacity-0"
|
|
197
|
+
: "opacity-100"
|
|
198
|
+
}
|
|
199
|
+
>
|
|
200
|
+
S
|
|
201
|
+
</span>
|
|
202
|
+
</span>
|
|
203
|
+
</span>
|
|
204
|
+
}
|
|
205
|
+
/>
|
|
206
|
+
))}
|
|
207
|
+
</StandardTableContent>
|
|
208
|
+
</StandardTableRow>
|
|
209
|
+
);
|
|
210
|
+
})}
|
|
211
|
+
</StandardTable>
|
|
212
|
+
</StandardTableContainer>
|
|
213
|
+
);
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export const ThemesTable: Story = {
|
|
218
|
+
render: () => {
|
|
219
|
+
const conceptSlug = "community";
|
|
220
|
+
const themeCode = "C8";
|
|
221
|
+
|
|
222
|
+
const navigateTo = (path: string) => {
|
|
223
|
+
console.log(path);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const conceptData = concepts.find(
|
|
227
|
+
(c) => c.name.toLowerCase() === conceptSlug.toLowerCase(),
|
|
228
|
+
);
|
|
229
|
+
const themeData = conceptData?.themes.find((t) => t.code === themeCode);
|
|
230
|
+
|
|
231
|
+
const conceptColor = getConceptColor(conceptSlug);
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
<StandardTableContainer>
|
|
235
|
+
<StandardTableHeader title="STRATEGIES" />
|
|
236
|
+
|
|
237
|
+
<StandardTable>
|
|
238
|
+
{themeData?.strategies.map((strategy) => {
|
|
239
|
+
return (
|
|
240
|
+
<StandardTableRow key={strategy.id} value={strategy.id}>
|
|
241
|
+
<StandardTableRowHeader onClick={() => navigateTo("/")}>
|
|
242
|
+
<CodeBadge
|
|
243
|
+
code={strategy.code}
|
|
244
|
+
style={{
|
|
245
|
+
backgroundColor: conceptColor.light,
|
|
246
|
+
borderColor: conceptColor.border,
|
|
247
|
+
color: conceptColor.contrast || conceptColor.solid,
|
|
248
|
+
}}
|
|
249
|
+
/>
|
|
250
|
+
<Text as="p" variant="body-large" className="flex-1">
|
|
251
|
+
{strategy.name}
|
|
252
|
+
</Text>
|
|
253
|
+
<span className="flex justify-center items-center number-large font-semibold">
|
|
254
|
+
{strategy.points}{" "}
|
|
255
|
+
<span className="overline-medium ml-1">
|
|
256
|
+
PT
|
|
257
|
+
<span
|
|
258
|
+
className={
|
|
259
|
+
strategy.points === "1" ? "opacity-0" : "opacity-100"
|
|
260
|
+
}
|
|
261
|
+
>
|
|
262
|
+
S
|
|
263
|
+
</span>
|
|
264
|
+
</span>
|
|
265
|
+
</span>
|
|
266
|
+
</StandardTableRowHeader>
|
|
267
|
+
|
|
268
|
+
{/* <StandardTableContent>
|
|
269
|
+
{themeData?.strategies.map((strategy) => (
|
|
270
|
+
<StandardTableListRow
|
|
271
|
+
key={strategy.id}
|
|
272
|
+
badge={
|
|
273
|
+
<CodeBadge
|
|
274
|
+
code={strategy.code}
|
|
275
|
+
style={{
|
|
276
|
+
backgroundColor: themeColor.light,
|
|
277
|
+
borderColor: themeColor.border,
|
|
278
|
+
color: themeColor.contrast || themeColor.solid,
|
|
279
|
+
}}
|
|
280
|
+
/>
|
|
281
|
+
}
|
|
282
|
+
title={strategy.name}
|
|
283
|
+
onClick={() => navigateTo("/")}
|
|
284
|
+
rightContent={
|
|
285
|
+
<span className="flex justify-center items-center number-large font-semibold">
|
|
286
|
+
{strategy.points}{" "}
|
|
287
|
+
<span className="overline-medium ml-1">
|
|
288
|
+
PT
|
|
289
|
+
<span
|
|
290
|
+
className={
|
|
291
|
+
strategy.points === "1"
|
|
292
|
+
? "opacity-0"
|
|
293
|
+
: "opacity-100"
|
|
294
|
+
}
|
|
295
|
+
>
|
|
296
|
+
S
|
|
297
|
+
</span>
|
|
298
|
+
</span>
|
|
299
|
+
</span>
|
|
300
|
+
}
|
|
301
|
+
/>
|
|
302
|
+
))}
|
|
303
|
+
</StandardTableContent> */}
|
|
304
|
+
</StandardTableRow>
|
|
305
|
+
);
|
|
306
|
+
})}
|
|
307
|
+
</StandardTable>
|
|
308
|
+
</StandardTableContainer>
|
|
309
|
+
);
|
|
310
|
+
},
|
|
311
|
+
};
|