@syscore/ui-library 1.1.11 → 1.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/client/components/icons/AchievementBadges.tsx +33 -0
  2. package/client/components/icons/ConceptIcons.tsx +169 -22
  3. package/client/components/icons/NavLogo.tsx +4 -4
  4. package/client/components/icons/ProviderBadges.tsx +28 -28
  5. package/client/components/icons/ProviderSeals.tsx +35 -35
  6. package/client/components/icons/StandardLogo.tsx +47 -0
  7. package/client/components/icons/UtilityChevronDown.tsx +1 -1
  8. package/client/components/icons/UtilityClearRegular.tsx +43 -0
  9. package/client/components/icons/UtilityCompare.tsx +71 -0
  10. package/client/components/icons/UtilityHome.tsx +26 -0
  11. package/client/components/icons/UtilityReset.tsx +7 -7
  12. package/client/components/icons/UtilitySave.tsx +35 -0
  13. package/client/components/icons/UtilityScopeLarge.tsx +86 -0
  14. package/client/components/icons/UtilityShow.tsx +41 -0
  15. package/client/components/icons/UtilityTarget.tsx +21 -0
  16. package/client/components/icons/UtilityTargetActive.tsx +34 -0
  17. package/client/components/icons/UtilityText.tsx +8 -8
  18. package/client/components/ui/breadcrumb.tsx +26 -4
  19. package/client/components/ui/button.tsx +30 -18
  20. package/client/components/ui/card.tsx +2 -2
  21. package/client/components/ui/code-badge.tsx +25 -0
  22. package/client/components/ui/dialog.tsx +4 -4
  23. package/client/components/ui/input.tsx +53 -9
  24. package/client/components/ui/label.tsx +2 -2
  25. package/client/components/ui/{Navigation.tsx → navigation.tsx} +291 -250
  26. package/client/components/ui/select.tsx +20 -20
  27. package/client/components/ui/tabs.tsx +27 -178
  28. package/client/components/ui/{Tag.tsx → tag.tsx} +11 -10
  29. package/client/components/ui/textarea.tsx +1 -1
  30. package/client/components/ui/toggle-group.tsx +19 -2
  31. package/client/components/ui/toggle.tsx +2 -2
  32. package/client/components/ui/tooltip.tsx +148 -8
  33. package/client/global.css +18 -11
  34. package/client/ui/AspectRatio.stories.tsx +1 -1
  35. package/client/ui/Button.stories.tsx +5 -5
  36. package/client/ui/Card.stories.tsx +223 -2
  37. package/client/ui/CodeBadge.stories.tsx +76 -0
  38. package/client/ui/Dialog.stories.tsx +52 -5
  39. package/client/ui/Icons.stories.tsx +31 -31
  40. package/client/ui/Input.stories.tsx +125 -0
  41. package/client/ui/Label.stories.tsx +8 -11
  42. package/client/ui/Navigation.stories.tsx +1 -1
  43. package/client/ui/RadioGroup/RadioGroup.stories.tsx +1 -1
  44. package/client/ui/SearchField.stories.tsx +1 -1
  45. package/client/ui/{Select/Select.stories.tsx → Select.stories.tsx} +2 -2
  46. package/client/ui/{Switch/Switch.stories.tsx → Switch.stories.tsx} +3 -3
  47. package/client/ui/Tabs.stories.tsx +174 -10
  48. package/client/ui/Tag.stories.tsx +48 -1
  49. package/client/ui/{Textarea/Textarea.stories.tsx → Textarea.stories.tsx} +9 -10
  50. package/client/ui/Toggle.stories.tsx +3 -3
  51. package/client/ui/Tooltip.stories.tsx +28 -4
  52. package/client/ui/WELLDashboard/WELLDashboard.stories.tsx +1 -1
  53. package/client/ui/WELLDashboard/index.tsx +147 -51
  54. package/dist/ui/index.cjs.js +1 -1
  55. package/dist/ui/index.d.ts +8 -1
  56. package/dist/ui/index.es.js +2127 -561
  57. package/package.json +2 -2
  58. package/client/components/ui/StrategyTable.tsx +0 -303
  59. package/client/ui/Input/Input.stories.tsx +0 -69
  60. package/client/ui/StrategyTable.stories.tsx +0 -138
  61. /package/client/components/ui/{SearchField.tsx → search.tsx} +0 -0
  62. /package/client/hooks/{UseTabs.tsx → use-tabs.tsx} +0 -0
@@ -5,6 +5,21 @@ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
5
5
 
6
6
  import { cn } from "@/lib/utils";
7
7
 
8
+ type TriggerMode = "hover" | "click";
9
+
10
+ // Context for passing trigger mode and close function to children
11
+ const TooltipContext = React.createContext<{
12
+ trigger: TriggerMode;
13
+ toggle: () => void;
14
+ close: () => void;
15
+ triggerRef: React.RefObject<HTMLButtonElement | null>;
16
+ }>({
17
+ trigger: "hover",
18
+ toggle: () => { },
19
+ close: () => { },
20
+ triggerRef: { current: null },
21
+ });
22
+
8
23
  function TooltipProvider({
9
24
  delayDuration = 0,
10
25
  ...props
@@ -18,20 +33,114 @@ function TooltipProvider({
18
33
  );
19
34
  }
20
35
 
36
+ interface TooltipProps
37
+ extends Omit<
38
+ React.ComponentProps<typeof TooltipPrimitive.Root>,
39
+ "open" | "onOpenChange"
40
+ > {
41
+ /**
42
+ * Trigger mode: "hover" (default) or "click"
43
+ * - hover: Opens on mouse hover, closes on hover off (default tooltip behavior)
44
+ * - click: Opens on click, closes on trigger click or click outside
45
+ */
46
+ trigger?: TriggerMode;
47
+ /** Controlled open state (optional) */
48
+ open?: boolean;
49
+ /** Callback when open state changes (optional) */
50
+ onOpenChange?: (open: boolean) => void;
51
+ }
52
+
21
53
  function Tooltip({
54
+ trigger = "hover",
55
+ open: controlledOpen,
56
+ onOpenChange,
57
+ children,
22
58
  ...props
23
- }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
59
+ }: TooltipProps) {
60
+ const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
61
+ const triggerRef = React.useRef<HTMLButtonElement>(null);
62
+
63
+ // Use controlled or uncontrolled state
64
+ const isControlled = controlledOpen !== undefined;
65
+ const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
66
+
67
+ const handleOpenChange = React.useCallback(
68
+ (newOpen: boolean) => {
69
+ // For click mode, ignore hover-triggered changes
70
+ if (trigger === "click") return;
71
+
72
+ if (!isControlled) {
73
+ setUncontrolledOpen(newOpen);
74
+ }
75
+ onOpenChange?.(newOpen);
76
+ },
77
+ [isControlled, onOpenChange, trigger]
78
+ );
79
+
80
+ const close = React.useCallback(() => {
81
+ if (!isControlled) {
82
+ setUncontrolledOpen(false);
83
+ }
84
+ onOpenChange?.(false);
85
+ }, [isControlled, onOpenChange]);
86
+
87
+ const toggle = React.useCallback(() => {
88
+ const newOpen = !isOpen;
89
+ if (!isControlled) {
90
+ setUncontrolledOpen(newOpen);
91
+ }
92
+ onOpenChange?.(newOpen);
93
+ }, [isOpen, isControlled, onOpenChange]);
94
+
95
+ // For click mode, we fully control open state
96
+ const tooltipProps =
97
+ trigger === "click"
98
+ ? {
99
+ open: isOpen,
100
+ onOpenChange: handleOpenChange,
101
+ }
102
+ : {
103
+ open: isControlled ? controlledOpen : undefined,
104
+ onOpenChange,
105
+ };
106
+
24
107
  return (
25
- <TooltipProvider>
26
- <TooltipPrimitive.Root data-slot="tooltip" {...props} />
27
- </TooltipProvider>
108
+ <TooltipContext.Provider value={{ trigger, toggle, close, triggerRef }}>
109
+ <TooltipProvider delayDuration={trigger === "click" ? 100000 : 0}>
110
+ <TooltipPrimitive.Root data-slot="tooltip" {...tooltipProps} {...props}>
111
+ {children}
112
+ </TooltipPrimitive.Root>
113
+ </TooltipProvider>
114
+ </TooltipContext.Provider>
28
115
  );
29
116
  }
30
117
 
31
118
  function TooltipTrigger({
119
+ onClick,
32
120
  ...props
33
121
  }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
34
- return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
122
+ const { trigger, toggle, triggerRef } = React.useContext(TooltipContext);
123
+
124
+ const handleClick = React.useCallback(
125
+ (e: React.MouseEvent<HTMLButtonElement>) => {
126
+ if (trigger === "click") {
127
+ e.preventDefault();
128
+ e.stopPropagation();
129
+ toggle();
130
+ }
131
+ onClick?.(e);
132
+ },
133
+ [trigger, toggle, onClick]
134
+ );
135
+
136
+ return (
137
+ <TooltipPrimitive.Trigger
138
+ ref={triggerRef}
139
+ data-slot="tooltip-trigger"
140
+ onClick={handleClick}
141
+ {...props}
142
+ />
143
+ );
35
144
  }
36
145
 
37
146
  function TooltipContent({
@@ -42,21 +151,52 @@ function TooltipContent({
42
151
  alignOffset = 0,
43
152
  ...props
44
153
  }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
154
+ const { trigger, close, triggerRef } = React.useContext(TooltipContext);
155
+ const contentRef = React.useRef<HTMLDivElement>(null);
156
+
157
+ // Click outside detection for click mode
158
+ React.useEffect(() => {
159
+ if (trigger !== "click") return;
160
+
161
+ const handleClickOutside = (event: MouseEvent) => {
162
+ const target = event.target as Node;
163
+ const isOutsideContent =
164
+ contentRef.current && !contentRef.current.contains(target);
165
+ const isOutsideTrigger =
166
+ triggerRef.current && !triggerRef.current.contains(target);
167
+
168
+ if (isOutsideContent && isOutsideTrigger) {
169
+ close();
170
+ }
171
+ };
172
+
173
+ // Small delay to avoid closing immediately on the same click that opened it
174
+ const timeoutId = setTimeout(() => {
175
+ document.addEventListener("click", handleClickOutside);
176
+ }, 0);
177
+
178
+ return () => {
179
+ clearTimeout(timeoutId);
180
+ document.removeEventListener("click", handleClickOutside);
181
+ };
182
+ }, [trigger, close, triggerRef]);
183
+
45
184
  return (
46
185
  <TooltipPrimitive.Portal>
47
186
  <TooltipPrimitive.Content
187
+ ref={contentRef}
48
188
  data-slot="tooltip-content"
49
189
  sideOffset={sideOffset}
50
190
  alignOffset={alignOffset}
51
191
  side={side}
52
192
  className={cn(
53
- "group relative bg-gray-700 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-lg px-6 pt-8 pb-6 text-balance shadow-sm",
54
- className,
193
+ "group relative bg-gray-700 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-lg p-6 pt-8 shadow-sm mt-3",
194
+ className
55
195
  )}
56
196
  {...props}
57
197
  >
58
198
  {/* Marker/Arrow */}
59
- <div className="absolute left-1/2 -translate-x-1/2 flex justify-center group-data-[side=top]:bottom-0 group-data-[side=top]:rotate-180 group-data-[side=bottom]:top-0 group-data-[side=left]:right-0 group-data-[side=right]:left-0">
199
+ <div className="absolute left-1/2 -translate-x-1/2 flex justify-center group-data-[side=top]:bottom-0 group-data-[side=top]:rotate-180 group-data-[side=bottom]:top-0 group-data-[side=left]:right-0 group-data-[side=right]:left-0 ">
60
200
  <svg
61
201
  xmlns="http://www.w3.org/2000/svg"
62
202
  width="10"
package/client/global.css CHANGED
@@ -527,9 +527,10 @@ layer(base);
527
527
  --color-sidebar-border: hsl(var(--sidebar-border));
528
528
  --color-sidebar-ring: hsl(var(--sidebar-ring));
529
529
 
530
- --radius-lg: var(--radius);
531
- --radius-md: calc(var(--radius) - 2px);
532
- --radius-sm: calc(var(--radius) - 4px);
530
+ --radius-lg: 12px;
531
+ --radius-md: 8px;
532
+ --radius-sm: 6px;
533
+
533
534
 
534
535
  /* Figma Design System Colors */
535
536
  --color-white: #fff;
@@ -860,18 +861,16 @@ layer(base);
860
861
  "cv01" on;
861
862
  }
862
863
 
864
+ .container-xl {
865
+ @apply mx-auto max-w-[calc(1728px+64px)] w-full px-8;
866
+ }
867
+
863
868
  .container-lg {
864
- max-width: calc(1440px + 64px);
865
- width: 100%;
866
- padding-inline: 32px;
867
- margin-inline: auto;
869
+ @apply mx-auto max-w-[calc(1536px+64px)] w-full px-8;
868
870
  }
869
871
 
870
872
  .container-sm {
871
- max-width: calc(1072px + 64px);
872
- width: 100%;
873
- padding-inline: 32px;
874
- margin-inline: auto;
873
+ @apply mx-auto max-w-[calc(1072px+64px)] w-full px-8;
875
874
  }
876
875
  }
877
876
 
@@ -1156,3 +1155,11 @@ layer(base);
1156
1155
  display: table;
1157
1156
  }
1158
1157
  }
1158
+
1159
+ @utility underline-dotted {
1160
+ text-decoration-line: underline;
1161
+ text-decoration-style: dotted;
1162
+ text-decoration-skip-ink: none;
1163
+ text-decoration-thickness: 0.75px;
1164
+ text-underline-offset: 2px;
1165
+ }
@@ -1,5 +1,5 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
- import { AspectRatio } from "@/components/ui/aspect-ratio";
2
+ import { AspectRatio } from "../components/ui/aspect-ratio";
3
3
 
4
4
  const meta = {
5
5
  title: "Review/AspectRatio",
@@ -1,9 +1,9 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
- import { Button } from "@/components/ui/Button";
3
- import { UtilityReset } from "@/components/icons/UtilityReset";
4
- import { UtilityClose } from "@/components/icons/UtilityClose";
5
- import { UtilityChevronDown } from "@/components/icons/UtilityChevronDown";
6
- import { NavAccount } from "@/components/icons/NavAccount";
2
+ import { Button } from "../components/ui/button";
3
+ import { UtilityReset } from "../components/icons/UtilityReset";
4
+ import { UtilityClose } from "../components/icons/UtilityClose";
5
+ import { UtilityChevronDown } from "../components/icons/UtilityChevronDown";
6
+ import { NavAccount } from "../components/icons/NavAccount";
7
7
 
8
8
  const meta = {
9
9
  title: "Review/Button",
@@ -1,4 +1,6 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
+ import { useState } from "react";
3
+
2
4
  import {
3
5
  Card,
4
6
  CardHeader,
@@ -6,8 +8,19 @@ import {
6
8
  CardTitle,
7
9
  CardDescription,
8
10
  CardContent,
9
- } from "../components/ui/Card";
10
- import { Button } from "@/components/ui/button";
11
+ } from "../components/ui/card";
12
+ import { Button } from "../components/ui/button";
13
+ import {
14
+ Select,
15
+ SelectContent,
16
+ SelectItem,
17
+ SelectTrigger,
18
+ SelectValue,
19
+ } from "../components/ui/select";
20
+ import { Label } from "../components/ui/label";
21
+ import { Toggle } from "../components/ui/toggle";
22
+
23
+ import { UtilityReset } from "../components/icons/UtilityReset";
11
24
 
12
25
  const meta = {
13
26
  title: "Review/Card",
@@ -82,3 +95,211 @@ export const Multiple: Story = {
82
95
  </div>
83
96
  ),
84
97
  };
98
+
99
+ export const FiltersPanel: Story = {
100
+ render: () => (
101
+ <Card className="w-[344px] bg-cyan-50 border-gray-100 rounded-xl p-6 shadow-none flex flex-col gap-6">
102
+ <div className="flex items-center justify-between w-full h-8">
103
+ <Label className="text-gray-800 overline-large">Filters</Label>
104
+ <Button
105
+ variant="secondary-light"
106
+ size="icon"
107
+ className="size-8 rounded-full border-gray-100 bg-white p-0"
108
+ >
109
+ <UtilityReset className="size-4" />
110
+ </Button>
111
+ </div>
112
+
113
+ <div className="flex flex-col gap-6 w-full">
114
+ {/* Segmented Control */}
115
+ <div className="flex flex-col gap-3">
116
+ <Label className="text-gray-600">Label</Label>
117
+ <Toggle
118
+ options={[
119
+ { label: "Active", value: "active" },
120
+ { label: "Inactive", value: "inactive" },
121
+ ]}
122
+ defaultValue="active"
123
+ />
124
+ </div>
125
+
126
+ {/* Search Selects */}
127
+ {[1, 2, 3].map((i) => (
128
+ <div key={i} className="flex flex-col gap-3">
129
+ <Label className="text-gray-600">Label</Label>
130
+ <Select>
131
+ <SelectTrigger className="h-12 border-gray-200 rounded-[6px] bg-white px-4">
132
+ <SelectValue placeholder="Placeholder" />
133
+ </SelectTrigger>
134
+ <SelectContent>
135
+ <SelectItem value="option1">Option 1</SelectItem>
136
+ <SelectItem value="option2">Option 2</SelectItem>
137
+ </SelectContent>
138
+ </Select>
139
+ </div>
140
+ ))}
141
+ </div>
142
+ </Card>
143
+ ),
144
+ };
145
+
146
+ // export const AttributesPanel: Story = {
147
+ // render: () => {
148
+ // const [activeTag, setActiveTag] = useState<string>("tag1");
149
+ // const tags = [
150
+ // { id: "tag1", label: "Tag" },
151
+ // { id: "tag2", label: "Tag" },
152
+ // { id: "tag3", label: "Tag" },
153
+ // ];
154
+
155
+ // return (
156
+ // <Card className="w-[344px] bg-cyan-50 border-gray-100 rounded-xl p-6 shadow-none flex flex-col gap-6">
157
+ // <div className="flex items-center justify-between w-full h-8">
158
+ // <Label className="text-gray-800 overline-large">Attributes</Label>
159
+ // </div>
160
+
161
+ // <div className="flex flex-col gap-6 w-full">
162
+ // {/* Segmented Control */}
163
+ // <div className="flex flex-col gap-3">
164
+ // <Label className="text-gray-600">Label</Label>
165
+ // <Toggle
166
+ // options={[
167
+ // { label: "Active", value: "active" },
168
+ // { label: "Inactive", value: "inactive" },
169
+ // ]}
170
+ // defaultValue="active"
171
+ // />
172
+ // </div>
173
+
174
+ // {/* Tags */}
175
+ // <div className="flex flex-col gap-3">
176
+ // <Label className="text-gray-600">Field name</Label>
177
+ // <div className="flex flex-wrap gap-3 items-start">
178
+ // {tags.map((tag) => (
179
+ // <Tag
180
+ // key={tag.id}
181
+ // active={activeTag === tag.id}
182
+ // onClick={() => setActiveTag(tag.id)}
183
+ // >
184
+ // {tag.label}
185
+ // </Tag>
186
+ // ))}
187
+ // </div>
188
+ // </div>
189
+ // </div>
190
+ // </Card>
191
+ // );
192
+ // },
193
+ // };
194
+
195
+ import {
196
+ IconConceptAir,
197
+ IconConceptCommunity,
198
+ IconConceptLight,
199
+ IconConceptMaterials,
200
+ IconConceptMind,
201
+ IconConceptMovement,
202
+ IconConceptNourishment,
203
+ IconConceptSound,
204
+ IconConceptThermalComfort,
205
+ IconConceptWater,
206
+ } from "../components/icons/ConceptIcons";
207
+
208
+ // ... existing imports
209
+
210
+ export const NavigatorPanel: Story = {
211
+ render: () => {
212
+ const [activeConcept, setActiveConcept] = useState<string>("community");
213
+ const [activeTheme, setActiveTheme] = useState<string>("C7");
214
+ const [activeStrategy, setActiveStrategy] = useState<string>("C7.4");
215
+
216
+ const concepts = [
217
+ { id: "mind", Icon: IconConceptMind },
218
+ { id: "community", Icon: IconConceptCommunity },
219
+ { id: "movement", Icon: IconConceptMovement },
220
+ { id: "water", Icon: IconConceptWater },
221
+ { id: "air", Icon: IconConceptAir },
222
+ { id: "light", Icon: IconConceptLight },
223
+ { id: "thermal", Icon: IconConceptThermalComfort },
224
+ { id: "nourishment", Icon: IconConceptNourishment },
225
+ { id: "sound", Icon: IconConceptSound },
226
+ { id: "materials", Icon: IconConceptMaterials },
227
+ ];
228
+
229
+ const themes = Array.from({ length: 9 }, (_, i) => `C${9 - i}`).reverse();
230
+ const strategies = ["C7.1", "C7.2", "C7.3", "C7.4"];
231
+
232
+ return (
233
+ <Card className="w-[344px] bg-cyan-50 border-gray-100 rounded-xl p-6 shadow-none flex flex-col gap-6">
234
+ {/* Concepts */}
235
+ <div className="flex flex-col gap-3">
236
+ <Label className="text-gray-600">Concept</Label>
237
+ <div className="flex flex-wrap gap-2">
238
+ {concepts.map(({ id, Icon }) => (
239
+ <button
240
+ key={id}
241
+ onClick={() => setActiveConcept(id)}
242
+ className="rounded-full transition-transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-cyan-500 focus:ring-offset-2"
243
+ >
244
+ <Icon active={activeConcept === id} className="size-12" />
245
+ </button>
246
+ ))}
247
+ </div>
248
+ </div>
249
+
250
+ {/* Theme */}
251
+ <div className="flex flex-col gap-3">
252
+ <Label className="text-gray-600">Theme</Label>
253
+ <div className="flex flex-wrap gap-2">
254
+ {themes.map((theme) => (
255
+ <button
256
+ key={theme}
257
+ onClick={() => setActiveTheme(theme)}
258
+ className={`w-12 h-8 rounded-[6px] flex items-center justify-center transition-colors ${
259
+ activeTheme === theme
260
+ ? "bg-cyan-800 text-white"
261
+ : "bg-blue-100 text-blue-600 hover:bg-blue-200"
262
+ }`}
263
+ >
264
+ <span className="body-small font-semibold">{theme}</span>
265
+ </button>
266
+ ))}
267
+ </div>
268
+ </div>
269
+
270
+ {/* Strategy */}
271
+ <div className="flex flex-col gap-3">
272
+ <Label className="text-gray-600">Strategy</Label>
273
+ <div className="flex flex-wrap gap-2">
274
+ {strategies.map((strategy) => (
275
+ <button
276
+ key={strategy}
277
+ onClick={() => setActiveStrategy(strategy)}
278
+ className={`w-12 h-8 rounded-[6px] flex items-center justify-center transition-colors ${
279
+ activeStrategy === strategy
280
+ ? "bg-[#0F748A]/10 border border-[#0F748A]/20 text-cyan-900"
281
+ : "bg-blue-100 text-blue-600 hover:bg-blue-200"
282
+ }`}
283
+ >
284
+ <span className="body-small font-semibold">{strategy}</span>
285
+ </button>
286
+ ))}
287
+ </div>
288
+ </div>
289
+
290
+ {/* Scope */}
291
+ <div className="flex flex-col gap-3">
292
+ <Label className="text-gray-600">Scope</Label>
293
+ <Toggle
294
+ className="w-full h-8 border border-gray-100 bg-white rounded-full p-0 [&>button]:flex-1"
295
+ options={[
296
+ { label: "Non-core", value: "non-core" },
297
+ { label: "Core", value: "core" },
298
+ ]}
299
+ defaultValue="non-core"
300
+ />
301
+ </div>
302
+ </Card>
303
+ );
304
+ },
305
+ };
@@ -0,0 +1,76 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { CodeBadge } from "../components/ui/code-badge";
3
+
4
+ const meta = {
5
+ title: "Review/CodeBadge",
6
+ component: CodeBadge,
7
+ tags: ["autodocs"],
8
+ parameters: {
9
+ layout: "centered",
10
+ },
11
+ } satisfies Meta<typeof CodeBadge>;
12
+
13
+ export default meta;
14
+
15
+ type Story = StoryObj<typeof meta>;
16
+
17
+ export const Default: Story = {
18
+ args: {
19
+ code: "A01",
20
+ },
21
+ };
22
+
23
+ export const WithClassName: Story = {
24
+ render: () => (
25
+ <div className="flex gap-4">
26
+ <CodeBadge
27
+ code="C01"
28
+ className="bg-plum-50 border-plum-200 text-plum-800"
29
+ />
30
+ <CodeBadge
31
+ code="A02"
32
+ className="bg-cyan-50 border-cyan-200 text-cyan-800"
33
+ />
34
+ <CodeBadge
35
+ code="W03"
36
+ className="bg-blue-50 border-blue-200 text-blue-800"
37
+ />
38
+ <CodeBadge
39
+ code="N04"
40
+ className="bg-green-50 border-green-200 text-green-800"
41
+ />
42
+ </div>
43
+ ),
44
+ };
45
+
46
+ export const WithStyle: Story = {
47
+ render: () => (
48
+ <div className="flex gap-4">
49
+ <CodeBadge
50
+ code="R01"
51
+ className="border-none"
52
+ style={{
53
+ backgroundColor: "#EFF5FB",
54
+ color: "#2E74AD",
55
+ }}
56
+ />
57
+ <CodeBadge
58
+ code="R02"
59
+ className="border-none"
60
+ style={{
61
+ backgroundColor: "#7B4F9D",
62
+ color: "white",
63
+ }}
64
+ />
65
+ <CodeBadge
66
+ code="R03"
67
+ className="border-none"
68
+ style={{
69
+ backgroundColor: "#2E74AD",
70
+ color: "white",
71
+ }}
72
+ />
73
+ </div>
74
+ ),
75
+ };
76
+
@@ -1,15 +1,17 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
- import { Button } from "@/components/ui/Button";
2
+ import { Button } from "../components/ui/button";
3
+ import { Input } from "../components/ui/input";
4
+ import { Label } from "../components/ui/label";
3
5
  import { useState } from "react";
4
6
  import {
5
7
  Dialog,
6
8
  DialogContent,
7
9
  DialogDescription,
10
+ DialogFooter,
8
11
  DialogHeader,
9
12
  DialogTitle,
10
13
  DialogTrigger,
11
- } from "@/components/ui/dialog";
12
- import { cn } from "@/lib/utils";
14
+ } from "../components/ui/dialog";
13
15
 
14
16
  const meta = {
15
17
  title: "Review/Dialog",
@@ -29,7 +31,7 @@ export const Default: Story = {
29
31
  const [open, setOpen] = useState(false);
30
32
  return (
31
33
  <>
32
- <Dialog open={open}>
34
+ <Dialog open={open} onOpenChange={setOpen}>
33
35
  <DialogTrigger asChild>
34
36
  <Button
35
37
  size="large"
@@ -58,7 +60,7 @@ export const Default: Story = {
58
60
  variant="general-primary"
59
61
  onClick={() => setOpen(false)}
60
62
  >
61
- Yes
63
+ Yes, delete user
62
64
  </Button>
63
65
  </div>
64
66
  </DialogContent>
@@ -67,3 +69,48 @@ export const Default: Story = {
67
69
  );
68
70
  },
69
71
  };
72
+
73
+ export const WithForm: Story = {
74
+ render: () => {
75
+ const [open, setOpen] = useState(false);
76
+ return (
77
+ <Dialog open={open} onOpenChange={setOpen}>
78
+ <DialogTrigger asChild>
79
+ <Button variant="general-secondary">Edit Profile</Button>
80
+ </DialogTrigger>
81
+ <DialogContent className="sm:max-w-[425px]">
82
+ <DialogHeader>
83
+ <DialogTitle>Edit profile</DialogTitle>
84
+ <DialogDescription>
85
+ Make changes to your profile here. Click save when you're done.
86
+ </DialogDescription>
87
+ </DialogHeader>
88
+ <div className="grid gap-4 py-4">
89
+ <div className=" flex flex-col gap-y-3">
90
+ <Label htmlFor="name">Name</Label>
91
+ <Input id="name" defaultValue="Pedro Duarte" />
92
+ </div>
93
+ <div className=" flex flex-col gap-y-3">
94
+ <Label htmlFor="username">Username</Label>
95
+ <Input
96
+ id="username"
97
+ defaultValue="@peduarte"
98
+ className="col-span-3"
99
+ />
100
+ </div>
101
+ </div>
102
+ <DialogFooter>
103
+ <Button
104
+ size="utility"
105
+ variant="general-primary"
106
+ type="submit"
107
+ onClick={() => setOpen(false)}
108
+ >
109
+ Save changes
110
+ </Button>
111
+ </DialogFooter>
112
+ </DialogContent>
113
+ </Dialog>
114
+ );
115
+ },
116
+ };