@syscore/ui-library 1.9.1 → 1.10.1
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/accordion.tsx +39 -9
- package/client/components/ui/dialog.tsx +25 -21
- package/client/components/ui/tag.tsx +16 -3
- package/client/global.css +17 -27
- package/client/lib/concept-icons.ts +16 -0
- package/client/ui/Accordion.stories.tsx +187 -0
- package/client/ui/Dialog.stories.tsx +106 -0
- package/client/ui/Panel.stories.tsx +1 -16
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.es.js +141 -83
- package/package.json +1 -1
|
@@ -33,6 +33,8 @@ interface AccordionItemContextValue {
|
|
|
33
33
|
value: string;
|
|
34
34
|
/** Whether this item is expanded */
|
|
35
35
|
isExpanded: boolean;
|
|
36
|
+
/** Whether to remove borders when open */
|
|
37
|
+
noBorderOnOpen?: boolean;
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
const AccordionItemContext =
|
|
@@ -324,21 +326,32 @@ AccordionHeaderRow.displayName = "AccordionHeaderRow";
|
|
|
324
326
|
interface AccordionItemProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
325
327
|
/** Unique value for this item */
|
|
326
328
|
value: string;
|
|
329
|
+
/** Remove bottom border when the accordion item is open */
|
|
330
|
+
noBorderOnOpen?: boolean;
|
|
327
331
|
}
|
|
328
332
|
|
|
329
333
|
const AccordionItem = React.forwardRef<HTMLDivElement, AccordionItemProps>(
|
|
330
|
-
({ value, children, className, ...props }, ref) => {
|
|
334
|
+
({ value, children, className, noBorderOnOpen, ...props }, ref) => {
|
|
331
335
|
const { isExpanded: isExpandedFn } = useAccordion();
|
|
332
336
|
const isExpanded = isExpandedFn(value);
|
|
333
337
|
|
|
334
338
|
const itemContextValue = React.useMemo(
|
|
335
|
-
() => ({ value, isExpanded }),
|
|
336
|
-
[value, isExpanded],
|
|
339
|
+
() => ({ value, isExpanded, noBorderOnOpen }),
|
|
340
|
+
[value, isExpanded, noBorderOnOpen],
|
|
337
341
|
);
|
|
338
342
|
|
|
339
343
|
return (
|
|
340
344
|
<AccordionItemContext.Provider value={itemContextValue}>
|
|
341
|
-
<div
|
|
345
|
+
<div
|
|
346
|
+
ref={ref}
|
|
347
|
+
className={cn(className)}
|
|
348
|
+
style={
|
|
349
|
+
noBorderOnOpen && isExpanded
|
|
350
|
+
? { borderBottom: "none" }
|
|
351
|
+
: undefined
|
|
352
|
+
}
|
|
353
|
+
{...props}
|
|
354
|
+
>
|
|
342
355
|
{children}
|
|
343
356
|
</div>
|
|
344
357
|
</AccordionItemContext.Provider>
|
|
@@ -349,12 +362,26 @@ const AccordionItem = React.forwardRef<HTMLDivElement, AccordionItemProps>(
|
|
|
349
362
|
AccordionItem.displayName = "AccordionItem";
|
|
350
363
|
|
|
351
364
|
// AccordionHeader
|
|
352
|
-
type AccordionHeaderProps = React.ComponentPropsWithoutRef<"div"
|
|
365
|
+
type AccordionHeaderProps = React.ComponentPropsWithoutRef<"div"> & {
|
|
366
|
+
/** Remove background color when the accordion item is open */
|
|
367
|
+
transparentOnOpen?: boolean;
|
|
368
|
+
};
|
|
353
369
|
|
|
354
370
|
const AccordionHeader = React.forwardRef<HTMLDivElement, AccordionHeaderProps>(
|
|
355
|
-
({ children, className, onClick, ...props }, ref) => {
|
|
371
|
+
({ children, className, onClick, transparentOnOpen, ...props }, ref) => {
|
|
372
|
+
const { isExpanded } = useAccordionItem();
|
|
356
373
|
return (
|
|
357
|
-
<div
|
|
374
|
+
<div
|
|
375
|
+
ref={ref}
|
|
376
|
+
onClick={onClick}
|
|
377
|
+
className={cn(className)}
|
|
378
|
+
style={
|
|
379
|
+
transparentOnOpen && isExpanded
|
|
380
|
+
? { backgroundColor: "transparent" }
|
|
381
|
+
: undefined
|
|
382
|
+
}
|
|
383
|
+
{...props}
|
|
384
|
+
>
|
|
358
385
|
{children}
|
|
359
386
|
</div>
|
|
360
387
|
);
|
|
@@ -409,7 +436,7 @@ type AccordionContentProps = React.ComponentPropsWithoutRef<"div">;
|
|
|
409
436
|
|
|
410
437
|
const AccordionContent = React.forwardRef<HTMLDivElement, AccordionContentProps>(
|
|
411
438
|
({ children, className, ...props }, ref) => {
|
|
412
|
-
const { isExpanded } = useAccordionItem();
|
|
439
|
+
const { isExpanded, noBorderOnOpen } = useAccordionItem();
|
|
413
440
|
|
|
414
441
|
return (
|
|
415
442
|
<AnimatePresence initial={false}>
|
|
@@ -420,7 +447,10 @@ const AccordionContent = React.forwardRef<HTMLDivElement, AccordionContentProps>
|
|
|
420
447
|
exit={{ height: 0, opacity: 0 }}
|
|
421
448
|
transition={{ duration: 0.3, ease: [0.25, 0.46, 0.45, 0.94] }}
|
|
422
449
|
className={cn(className)}
|
|
423
|
-
style={{
|
|
450
|
+
style={{
|
|
451
|
+
willChange: "opacity",
|
|
452
|
+
...(noBorderOnOpen ? { borderTop: "none" } : {}),
|
|
453
|
+
}}
|
|
424
454
|
>
|
|
425
455
|
<div ref={ref} {...props}>
|
|
426
456
|
{children}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
3
|
-
import { XIcon } from "lucide-react";
|
|
4
3
|
|
|
5
4
|
import { cn } from "@/lib/utils";
|
|
5
|
+
import { UtilityClose } from "../icons/UtilityClose";
|
|
6
6
|
|
|
7
7
|
function Dialog({
|
|
8
8
|
...props
|
|
@@ -30,14 +30,17 @@ function DialogClose({
|
|
|
30
30
|
|
|
31
31
|
function DialogOverlay({
|
|
32
32
|
className,
|
|
33
|
+
children,
|
|
33
34
|
...props
|
|
34
35
|
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
35
36
|
return (
|
|
36
|
-
|
|
37
|
+
<DialogPrimitive.Overlay
|
|
37
38
|
data-slot="dialog-overlay"
|
|
38
39
|
className={cn("dialog-overlay", className)}
|
|
39
40
|
{...props}
|
|
40
|
-
|
|
41
|
+
>
|
|
42
|
+
{children}
|
|
43
|
+
</DialogPrimitive.Overlay>
|
|
41
44
|
);
|
|
42
45
|
}
|
|
43
46
|
|
|
@@ -51,23 +54,24 @@ function DialogContent({
|
|
|
51
54
|
}) {
|
|
52
55
|
return (
|
|
53
56
|
<DialogPortal data-slot="dialog-portal">
|
|
54
|
-
<DialogOverlay
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
57
|
+
<DialogOverlay>
|
|
58
|
+
<DialogPrimitive.Content
|
|
59
|
+
data-slot="dialog-content"
|
|
60
|
+
className={cn("dialog-content", className)}
|
|
61
|
+
{...props}
|
|
62
|
+
>
|
|
63
|
+
<div className="dialog-content-inner">{children}</div>
|
|
64
|
+
{showCloseButton && (
|
|
65
|
+
<DialogPrimitive.Close
|
|
66
|
+
data-slot="dialog-close"
|
|
67
|
+
className="dialog-close"
|
|
68
|
+
>
|
|
69
|
+
<UtilityClose />
|
|
70
|
+
<span className="sr-only">Close</span>
|
|
71
|
+
</DialogPrimitive.Close>
|
|
72
|
+
)}
|
|
73
|
+
</DialogPrimitive.Content>
|
|
74
|
+
</DialogOverlay>
|
|
71
75
|
</DialogPortal>
|
|
72
76
|
);
|
|
73
77
|
}
|
|
@@ -99,7 +103,7 @@ function DialogTitle({
|
|
|
99
103
|
return (
|
|
100
104
|
<DialogPrimitive.Title
|
|
101
105
|
data-slot="dialog-title"
|
|
102
|
-
className={cn("dialog-title heading-xxsmall", className)}
|
|
106
|
+
className={cn("dialog-title heading-xxsmall text-center", className)}
|
|
103
107
|
{...props}
|
|
104
108
|
/>
|
|
105
109
|
);
|
|
@@ -15,6 +15,11 @@ export interface TagProps
|
|
|
15
15
|
status?: TagStatus;
|
|
16
16
|
/** Color scheme for status tags */
|
|
17
17
|
colorScheme?: "light" | "dark";
|
|
18
|
+
/** Minimum width */
|
|
19
|
+
minWidth?: number | string;
|
|
20
|
+
/** Minimum height */
|
|
21
|
+
minHeight?: number | string;
|
|
22
|
+
|
|
18
23
|
onClick?: () => void;
|
|
19
24
|
}
|
|
20
25
|
|
|
@@ -34,12 +39,20 @@ export const Tag = React.forwardRef<HTMLButtonElement, TagProps>(
|
|
|
34
39
|
status,
|
|
35
40
|
colorScheme = "light",
|
|
36
41
|
className,
|
|
42
|
+
minWidth,
|
|
43
|
+
minHeight,
|
|
37
44
|
style,
|
|
38
45
|
onClick,
|
|
39
46
|
...props
|
|
40
47
|
},
|
|
41
48
|
ref,
|
|
42
49
|
) => {
|
|
50
|
+
const mergedStyle = {
|
|
51
|
+
minWidth,
|
|
52
|
+
minHeight,
|
|
53
|
+
...style,
|
|
54
|
+
};
|
|
55
|
+
|
|
43
56
|
// Status tag styling (highest priority)
|
|
44
57
|
if (status) {
|
|
45
58
|
const statusClass = getStatusClass(status, colorScheme);
|
|
@@ -48,7 +61,7 @@ export const Tag = React.forwardRef<HTMLButtonElement, TagProps>(
|
|
|
48
61
|
ref={ref}
|
|
49
62
|
onClick={onClick}
|
|
50
63
|
className={cn("overline-medium", statusClass, className)}
|
|
51
|
-
style={
|
|
64
|
+
style={mergedStyle}
|
|
52
65
|
{...props}
|
|
53
66
|
>
|
|
54
67
|
{children}
|
|
@@ -63,7 +76,7 @@ export const Tag = React.forwardRef<HTMLButtonElement, TagProps>(
|
|
|
63
76
|
ref={ref}
|
|
64
77
|
onClick={onClick}
|
|
65
78
|
className={cn("tag-code", className)}
|
|
66
|
-
style={
|
|
79
|
+
style={mergedStyle}
|
|
67
80
|
{...props}
|
|
68
81
|
>
|
|
69
82
|
<span className="number-small font-semibold" style={{ color: "inherit" }}>
|
|
@@ -83,7 +96,7 @@ export const Tag = React.forwardRef<HTMLButtonElement, TagProps>(
|
|
|
83
96
|
active ? "tag-general--active" : "tag-general--inactive",
|
|
84
97
|
className,
|
|
85
98
|
)}
|
|
86
|
-
style={
|
|
99
|
+
style={mergedStyle}
|
|
87
100
|
{...props}
|
|
88
101
|
>
|
|
89
102
|
{children}
|
package/client/global.css
CHANGED
|
@@ -2020,19 +2020,6 @@ body {
|
|
|
2020
2020
|
color: currentColor;
|
|
2021
2021
|
}
|
|
2022
2022
|
|
|
2023
|
-
/* Code Badge Styles */
|
|
2024
|
-
.code-badge {
|
|
2025
|
-
display: flex;
|
|
2026
|
-
align-items: center;
|
|
2027
|
-
justify-content: center;
|
|
2028
|
-
height: 2rem;
|
|
2029
|
-
width: 3rem;
|
|
2030
|
-
border-radius: calc(var(--radius-sm, 6px));
|
|
2031
|
-
flex-shrink: 0;
|
|
2032
|
-
border: 1.5px solid currentColor;
|
|
2033
|
-
padding-left: 1px;
|
|
2034
|
-
padding-right: 1px;
|
|
2035
|
-
}
|
|
2036
2023
|
|
|
2037
2024
|
/* Tooltip Styles */
|
|
2038
2025
|
.tooltip-content {
|
|
@@ -2461,6 +2448,11 @@ body {
|
|
|
2461
2448
|
position: fixed;
|
|
2462
2449
|
inset: 0;
|
|
2463
2450
|
z-index: 50;
|
|
2451
|
+
display: flex;
|
|
2452
|
+
align-items: center;
|
|
2453
|
+
justify-content: center;
|
|
2454
|
+
overflow-y: auto;
|
|
2455
|
+
padding-block: 1.5rem;
|
|
2464
2456
|
background-color: rgba(0, 0, 0, 0.5);
|
|
2465
2457
|
}
|
|
2466
2458
|
|
|
@@ -2473,16 +2465,13 @@ body {
|
|
|
2473
2465
|
}
|
|
2474
2466
|
|
|
2475
2467
|
.dialog-content {
|
|
2476
|
-
position:
|
|
2477
|
-
top: 50%;
|
|
2478
|
-
left: 50%;
|
|
2468
|
+
position: relative;
|
|
2479
2469
|
z-index: 50;
|
|
2480
2470
|
display: grid;
|
|
2481
2471
|
gap: 1rem;
|
|
2482
|
-
|
|
2472
|
+
margin: auto;
|
|
2483
2473
|
border-radius: 40px;
|
|
2484
2474
|
border: 12px solid rgba(255, 255, 255, 0.2);
|
|
2485
|
-
transform: translate(-50%, -50%);
|
|
2486
2475
|
transition: all 0.2s ease-in-out;
|
|
2487
2476
|
}
|
|
2488
2477
|
|
|
@@ -2500,6 +2489,7 @@ body {
|
|
|
2500
2489
|
|
|
2501
2490
|
.dialog-content-inner {
|
|
2502
2491
|
padding: 1.5rem;
|
|
2492
|
+
border-radius: 28px;
|
|
2503
2493
|
background-color: var(--color-gray-50, #f9f9fa);
|
|
2504
2494
|
}
|
|
2505
2495
|
|
|
@@ -2507,13 +2497,8 @@ body {
|
|
|
2507
2497
|
position: absolute;
|
|
2508
2498
|
top: 1rem;
|
|
2509
2499
|
right: 1rem;
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
transition: opacity 0.15s ease-in-out;
|
|
2513
|
-
}
|
|
2514
|
-
|
|
2515
|
-
.dialog-close:hover {
|
|
2516
|
-
opacity: 1;
|
|
2500
|
+
z-index: 10;
|
|
2501
|
+
cursor: pointer;
|
|
2517
2502
|
}
|
|
2518
2503
|
|
|
2519
2504
|
.dialog-close:focus {
|
|
@@ -2530,8 +2515,12 @@ body {
|
|
|
2530
2515
|
.dialog-close svg {
|
|
2531
2516
|
pointer-events: none;
|
|
2532
2517
|
flex-shrink: 0;
|
|
2533
|
-
|
|
2534
|
-
|
|
2518
|
+
color: var(--color-gray-400);
|
|
2519
|
+
transition: color 0.2s ease-in-out;
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
.dialog-close:hover svg {
|
|
2523
|
+
color: var(--color-gray-500);
|
|
2535
2524
|
}
|
|
2536
2525
|
|
|
2537
2526
|
.dialog-header {
|
|
@@ -2539,6 +2528,7 @@ body {
|
|
|
2539
2528
|
flex-direction: column;
|
|
2540
2529
|
gap: 0.5rem;
|
|
2541
2530
|
text-align: center;
|
|
2531
|
+
align-items: center;
|
|
2542
2532
|
}
|
|
2543
2533
|
|
|
2544
2534
|
@media (min-width: 640px) {
|
|
@@ -36,6 +36,7 @@ export const CONCEPT_ICONS: Record<
|
|
|
36
36
|
nourishment: IconConceptNourishment,
|
|
37
37
|
light: IconConceptLight,
|
|
38
38
|
movement: IconConceptMovement,
|
|
39
|
+
thermal: IconConceptThermalComfort,
|
|
39
40
|
"thermal-comfort": IconConceptThermalComfort,
|
|
40
41
|
sound: IconConceptSound,
|
|
41
42
|
materials: IconConceptMaterials,
|
|
@@ -43,3 +44,18 @@ export const CONCEPT_ICONS: Record<
|
|
|
43
44
|
mind: IconConceptMind,
|
|
44
45
|
innovation: IconConceptInnovation,
|
|
45
46
|
};
|
|
47
|
+
|
|
48
|
+
// Order of concepts for display
|
|
49
|
+
export const conceptOrder: ConceptSlug[] = [
|
|
50
|
+
"air",
|
|
51
|
+
"water",
|
|
52
|
+
"nourishment",
|
|
53
|
+
"light",
|
|
54
|
+
"movement",
|
|
55
|
+
"thermal-comfort",
|
|
56
|
+
"sound",
|
|
57
|
+
"materials",
|
|
58
|
+
"community",
|
|
59
|
+
"mind",
|
|
60
|
+
"innovation",
|
|
61
|
+
];
|
|
@@ -195,6 +195,7 @@ export const IWBIConceptsTable: Story = {
|
|
|
195
195
|
<AccordionHeader
|
|
196
196
|
onClick={() => navigateTo("/")}
|
|
197
197
|
className="standard-table-row-header"
|
|
198
|
+
transparentOnOpen
|
|
198
199
|
>
|
|
199
200
|
<Icon active={true} className="size-12 shrink-0" />
|
|
200
201
|
<span className="overline-large flex-1">{concept.name}</span>
|
|
@@ -235,6 +236,190 @@ export const IWBIConceptsTable: Story = {
|
|
|
235
236
|
},
|
|
236
237
|
};
|
|
237
238
|
|
|
239
|
+
// Showcases transparentOnOpen and noBorderOnOpen props
|
|
240
|
+
export const TransparentOnOpen: Story = {
|
|
241
|
+
render: () => {
|
|
242
|
+
const [expandedConcepts, setExpandedConcepts] = useState<Set<string>>(
|
|
243
|
+
new Set(),
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
const hasAnyExpanded = expandedConcepts.size > 0;
|
|
247
|
+
|
|
248
|
+
const toggleAllConcepts = () => {
|
|
249
|
+
if (hasAnyExpanded) {
|
|
250
|
+
setExpandedConcepts(new Set());
|
|
251
|
+
} else {
|
|
252
|
+
setExpandedConcepts(new Set(concepts.map((c) => c.id)));
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const navigateTo = (path: string) => {
|
|
257
|
+
console.log(path);
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
function getSlugFromName(name: string) {
|
|
261
|
+
return name.toLowerCase().replace(/\s+/g, "-");
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return (
|
|
265
|
+
<div className="grid grid-cols-2 gap-4">
|
|
266
|
+
<div className="flex flex-col gap-2">
|
|
267
|
+
<div className="flex gap-2">
|
|
268
|
+
<code className="text-xs bg-gray-100 px-2 py-1 rounded">
|
|
269
|
+
AccordionItem: noBorderOnOpen
|
|
270
|
+
</code>
|
|
271
|
+
<code className="text-xs bg-gray-100 px-2 py-1 rounded">
|
|
272
|
+
AccordionHeader: transparentOnOpen
|
|
273
|
+
</code>
|
|
274
|
+
</div>
|
|
275
|
+
<AccordionContainer className="standard-table-container">
|
|
276
|
+
<AccordionSectionHeader
|
|
277
|
+
title="no border and transparent on open"
|
|
278
|
+
hasExpanded={hasAnyExpanded}
|
|
279
|
+
onToggleAll={toggleAllConcepts}
|
|
280
|
+
className="standard-table-header"
|
|
281
|
+
/>
|
|
282
|
+
|
|
283
|
+
<Accordion
|
|
284
|
+
allowMultiple={true}
|
|
285
|
+
expandedValues={expandedConcepts}
|
|
286
|
+
onExpandedChange={setExpandedConcepts}
|
|
287
|
+
className="border border-blue-200 rounded-xl overflow-hidden"
|
|
288
|
+
>
|
|
289
|
+
{[...concepts].map((concept) => {
|
|
290
|
+
const slug = getSlugFromName(concept.name);
|
|
291
|
+
const Icon = CONCEPT_ICONS[slug];
|
|
292
|
+
const color = getConceptColor(slug);
|
|
293
|
+
|
|
294
|
+
return (
|
|
295
|
+
<AccordionItem
|
|
296
|
+
key={concept.id}
|
|
297
|
+
value={concept.id}
|
|
298
|
+
className="standard-table-row"
|
|
299
|
+
noBorderOnOpen
|
|
300
|
+
>
|
|
301
|
+
<AccordionHeader
|
|
302
|
+
onClick={() => navigateTo("/")}
|
|
303
|
+
className="standard-table-row-header"
|
|
304
|
+
transparentOnOpen
|
|
305
|
+
>
|
|
306
|
+
<Icon active={true} className="size-12 shrink-0" />
|
|
307
|
+
<span className="overline-large flex-1">
|
|
308
|
+
{concept.name}
|
|
309
|
+
</span>
|
|
310
|
+
<AccordionTrigger className="standard-table-trigger" />
|
|
311
|
+
</AccordionHeader>
|
|
312
|
+
|
|
313
|
+
<AccordionContent className="standard-table-content">
|
|
314
|
+
<div className="standard-table-content__inner">
|
|
315
|
+
{concept.themes.slice(0, 1).map((theme) => (
|
|
316
|
+
<AccordionListRow
|
|
317
|
+
key={theme.id}
|
|
318
|
+
badge={
|
|
319
|
+
<Tag
|
|
320
|
+
variant="code"
|
|
321
|
+
style={{
|
|
322
|
+
backgroundColor: color.contrast || color.solid,
|
|
323
|
+
borderColor: color.border,
|
|
324
|
+
color: "white",
|
|
325
|
+
}}
|
|
326
|
+
>
|
|
327
|
+
{theme.code}
|
|
328
|
+
</Tag>
|
|
329
|
+
}
|
|
330
|
+
title={theme.name}
|
|
331
|
+
titleClassName="standard-table-list-row__title body-large"
|
|
332
|
+
className="standard-table-list-row standard-table-list-row--nested"
|
|
333
|
+
onClick={() => navigateTo("/")}
|
|
334
|
+
/>
|
|
335
|
+
))}
|
|
336
|
+
</div>
|
|
337
|
+
</AccordionContent>
|
|
338
|
+
</AccordionItem>
|
|
339
|
+
);
|
|
340
|
+
})}
|
|
341
|
+
</Accordion>
|
|
342
|
+
</AccordionContainer>
|
|
343
|
+
</div>
|
|
344
|
+
|
|
345
|
+
<div className="flex flex-col gap-2">
|
|
346
|
+
<div className="flex gap-2">
|
|
347
|
+
<code className="text-xs bg-gray-100 px-2 py-1 rounded">
|
|
348
|
+
No props
|
|
349
|
+
</code>
|
|
350
|
+
</div>
|
|
351
|
+
<AccordionContainer className="standard-table-container">
|
|
352
|
+
<AccordionSectionHeader
|
|
353
|
+
title="Default"
|
|
354
|
+
hasExpanded={hasAnyExpanded}
|
|
355
|
+
onToggleAll={toggleAllConcepts}
|
|
356
|
+
className="standard-table-header"
|
|
357
|
+
/>
|
|
358
|
+
|
|
359
|
+
<Accordion
|
|
360
|
+
allowMultiple={true}
|
|
361
|
+
expandedValues={expandedConcepts}
|
|
362
|
+
onExpandedChange={setExpandedConcepts}
|
|
363
|
+
className="border border-blue-200 rounded-xl overflow-hidden"
|
|
364
|
+
>
|
|
365
|
+
{[...concepts].map((concept) => {
|
|
366
|
+
const slug = getSlugFromName(concept.name);
|
|
367
|
+
const Icon = CONCEPT_ICONS[slug];
|
|
368
|
+
const color = getConceptColor(slug);
|
|
369
|
+
|
|
370
|
+
return (
|
|
371
|
+
<AccordionItem
|
|
372
|
+
key={concept.id}
|
|
373
|
+
value={concept.id}
|
|
374
|
+
className="standard-table-row"
|
|
375
|
+
>
|
|
376
|
+
<AccordionHeader
|
|
377
|
+
onClick={() => navigateTo("/")}
|
|
378
|
+
className="standard-table-row-header"
|
|
379
|
+
>
|
|
380
|
+
<Icon active={true} className="size-12 shrink-0" />
|
|
381
|
+
<span className="overline-large flex-1">
|
|
382
|
+
{concept.name}
|
|
383
|
+
</span>
|
|
384
|
+
<AccordionTrigger className="standard-table-trigger" />
|
|
385
|
+
</AccordionHeader>
|
|
386
|
+
|
|
387
|
+
<AccordionContent className="standard-table-content">
|
|
388
|
+
<div className="standard-table-content__inner">
|
|
389
|
+
{concept.themes.slice(0, 1).map((theme) => (
|
|
390
|
+
<AccordionListRow
|
|
391
|
+
key={theme.id}
|
|
392
|
+
badge={
|
|
393
|
+
<Tag
|
|
394
|
+
variant="code"
|
|
395
|
+
style={{
|
|
396
|
+
backgroundColor: color.contrast || color.solid,
|
|
397
|
+
borderColor: color.border,
|
|
398
|
+
color: "white",
|
|
399
|
+
}}
|
|
400
|
+
>
|
|
401
|
+
{theme.code}
|
|
402
|
+
</Tag>
|
|
403
|
+
}
|
|
404
|
+
title={theme.name}
|
|
405
|
+
titleClassName="standard-table-list-row__title body-large"
|
|
406
|
+
className="standard-table-list-row standard-table-list-row--nested"
|
|
407
|
+
onClick={() => navigateTo("/")}
|
|
408
|
+
/>
|
|
409
|
+
))}
|
|
410
|
+
</div>
|
|
411
|
+
</AccordionContent>
|
|
412
|
+
</AccordionItem>
|
|
413
|
+
);
|
|
414
|
+
})}
|
|
415
|
+
</Accordion>
|
|
416
|
+
</AccordionContainer>
|
|
417
|
+
</div>
|
|
418
|
+
</div>
|
|
419
|
+
);
|
|
420
|
+
},
|
|
421
|
+
};
|
|
422
|
+
|
|
238
423
|
export const IWBIThemesTable: Story = {
|
|
239
424
|
render: () => {
|
|
240
425
|
const conceptSlug = "community";
|
|
@@ -288,6 +473,7 @@ export const IWBIThemesTable: Story = {
|
|
|
288
473
|
<AccordionHeader
|
|
289
474
|
onClick={() => navigateTo("/")}
|
|
290
475
|
className="standard-table-row-header"
|
|
476
|
+
transparentOnOpen
|
|
291
477
|
>
|
|
292
478
|
<Tag
|
|
293
479
|
variant="code"
|
|
@@ -392,6 +578,7 @@ export const IWBIStrategiesTable: Story = {
|
|
|
392
578
|
<AccordionHeader
|
|
393
579
|
onClick={() => navigateTo("/")}
|
|
394
580
|
className="standard-table-row-header"
|
|
581
|
+
transparentOnOpen
|
|
395
582
|
>
|
|
396
583
|
<Tag
|
|
397
584
|
variant="code"
|
|
@@ -114,3 +114,109 @@ export const WithForm: Story = {
|
|
|
114
114
|
);
|
|
115
115
|
},
|
|
116
116
|
};
|
|
117
|
+
|
|
118
|
+
export const LongContentScroll: Story = {
|
|
119
|
+
render: () => {
|
|
120
|
+
const [open, setOpen] = useState(false);
|
|
121
|
+
return (
|
|
122
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
123
|
+
<DialogTrigger asChild>
|
|
124
|
+
<Button variant="general-secondary">Terms & Conditions</Button>
|
|
125
|
+
</DialogTrigger>
|
|
126
|
+
<DialogContent className="sm:max-w-[540px]">
|
|
127
|
+
<DialogHeader>
|
|
128
|
+
<DialogTitle>Terms of Service</DialogTitle>
|
|
129
|
+
<DialogDescription>
|
|
130
|
+
Please review the following terms before proceeding.
|
|
131
|
+
</DialogDescription>
|
|
132
|
+
</DialogHeader>
|
|
133
|
+
<div className="flex flex-col gap-4 py-4 body-base text-gray-700">
|
|
134
|
+
<h3 className="heading-xxxsmall">1. Acceptance of Terms</h3>
|
|
135
|
+
<p>
|
|
136
|
+
By accessing and using the WELL Building Standard platform, you
|
|
137
|
+
acknowledge that you have read, understood, and agree to be bound
|
|
138
|
+
by these Terms of Service. If you do not agree to these terms, you
|
|
139
|
+
must not use the platform. These terms constitute a legally binding
|
|
140
|
+
agreement between you and the International WELL Building
|
|
141
|
+
Institute.
|
|
142
|
+
</p>
|
|
143
|
+
|
|
144
|
+
<h3 className="heading-xxxsmall">2. Use of Services</h3>
|
|
145
|
+
<p>
|
|
146
|
+
You agree to use the platform only for lawful purposes and in
|
|
147
|
+
accordance with these Terms. You are responsible for ensuring that
|
|
148
|
+
your use of the platform complies with all applicable laws,
|
|
149
|
+
regulations, and professional standards. Unauthorized use of the
|
|
150
|
+
platform may give rise to a claim for damages and/or be a criminal
|
|
151
|
+
offense.
|
|
152
|
+
</p>
|
|
153
|
+
|
|
154
|
+
<h3 className="heading-xxxsmall">3. User Accounts</h3>
|
|
155
|
+
<p>
|
|
156
|
+
To access certain features of the platform, you may be required to
|
|
157
|
+
create an account. You are responsible for maintaining the
|
|
158
|
+
confidentiality of your account credentials and for all activities
|
|
159
|
+
that occur under your account. You agree to notify us immediately
|
|
160
|
+
of any unauthorized use of your account or any other breach of
|
|
161
|
+
security.
|
|
162
|
+
</p>
|
|
163
|
+
|
|
164
|
+
<h3 className="heading-xxxsmall">4. Intellectual Property</h3>
|
|
165
|
+
<p>
|
|
166
|
+
All content, features, and functionality of the platform,
|
|
167
|
+
including but not limited to text, graphics, logos, icons, images,
|
|
168
|
+
audio clips, digital downloads, and data compilations, are the
|
|
169
|
+
exclusive property of the International WELL Building Institute
|
|
170
|
+
and are protected by international copyright, trademark, patent,
|
|
171
|
+
trade secret, and other intellectual property laws.
|
|
172
|
+
</p>
|
|
173
|
+
|
|
174
|
+
<h3 className="heading-xxxsmall">5. Data Privacy</h3>
|
|
175
|
+
<p>
|
|
176
|
+
We are committed to protecting your privacy. Our collection and
|
|
177
|
+
use of personal information is governed by our Privacy Policy,
|
|
178
|
+
which is incorporated into these Terms by reference. By using the
|
|
179
|
+
platform, you consent to the collection, use, and sharing of your
|
|
180
|
+
information as described in the Privacy Policy.
|
|
181
|
+
</p>
|
|
182
|
+
|
|
183
|
+
<h3 className="heading-xxxsmall">6. Limitation of Liability</h3>
|
|
184
|
+
<p>
|
|
185
|
+
To the fullest extent permitted by applicable law, the
|
|
186
|
+
International WELL Building Institute shall not be liable for any
|
|
187
|
+
indirect, incidental, special, consequential, or punitive damages,
|
|
188
|
+
or any loss of profits or revenues, whether incurred directly or
|
|
189
|
+
indirectly, or any loss of data, use, goodwill, or other
|
|
190
|
+
intangible losses resulting from your use of the platform.
|
|
191
|
+
</p>
|
|
192
|
+
|
|
193
|
+
<h3 className="heading-xxxsmall">7. Modifications</h3>
|
|
194
|
+
<p>
|
|
195
|
+
We reserve the right to modify these Terms at any time. We will
|
|
196
|
+
provide notice of any material changes by posting the updated
|
|
197
|
+
Terms on the platform. Your continued use of the platform after
|
|
198
|
+
such modifications constitutes your acceptance of the revised
|
|
199
|
+
Terms.
|
|
200
|
+
</p>
|
|
201
|
+
</div>
|
|
202
|
+
<DialogFooter>
|
|
203
|
+
<Button
|
|
204
|
+
size="utility"
|
|
205
|
+
variant="general-secondary"
|
|
206
|
+
onClick={() => setOpen(false)}
|
|
207
|
+
>
|
|
208
|
+
Decline
|
|
209
|
+
</Button>
|
|
210
|
+
<Button
|
|
211
|
+
size="utility"
|
|
212
|
+
variant="general-primary"
|
|
213
|
+
onClick={() => setOpen(false)}
|
|
214
|
+
>
|
|
215
|
+
Accept
|
|
216
|
+
</Button>
|
|
217
|
+
</DialogFooter>
|
|
218
|
+
</DialogContent>
|
|
219
|
+
</Dialog>
|
|
220
|
+
);
|
|
221
|
+
},
|
|
222
|
+
};
|