@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.
@@ -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 ref={ref} className={cn(className)} {...props}>
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 ref={ref} onClick={onClick} className={cn(className)} {...props}>
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={{ willChange: "opacity" }}
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
- <DialogPrimitive.Overlay
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
- <DialogPrimitive.Content
56
- data-slot="dialog-content"
57
- className={cn("dialog-content", className)}
58
- {...props}
59
- >
60
- <div className="dialog-content-inner">{children}</div>
61
- {showCloseButton && (
62
- <DialogPrimitive.Close
63
- data-slot="dialog-close"
64
- className="dialog-close"
65
- >
66
- <XIcon />
67
- <span className="sr-only">Close</span>
68
- </DialogPrimitive.Close>
69
- )}
70
- </DialogPrimitive.Content>
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={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={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={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: fixed;
2477
- top: 50%;
2478
- left: 50%;
2468
+ position: relative;
2479
2469
  z-index: 50;
2480
2470
  display: grid;
2481
2471
  gap: 1rem;
2482
- overflow: hidden;
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
- border-radius: 2px;
2511
- opacity: 0.7;
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
- height: 1rem;
2534
- width: 1rem;
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
+ };