ai-design-system 0.1.50 → 0.1.52

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 (44) hide show
  1. package/components/blocks/InboxPanel/InboxPanel.tsx +1 -1
  2. package/components/blocks/SectionLayout/SectionLayout.tsx +2 -0
  3. package/components/blocks/SectionLayout/interfaces.ts +1 -0
  4. package/components/blocks/WorkflowCanvas/WorkflowCanvas.tsx +1 -15
  5. package/components/composites/AdjustableLayout/AdjustableLayout.tsx +74 -43
  6. package/components/composites/AppHeader/AppHeader.tsx +16 -2
  7. package/components/composites/AppHeader/interfaces.ts +1 -0
  8. package/components/composites/ChatToggleButton/ChatToggleButton.stories.tsx +31 -0
  9. package/components/composites/ChatToggleButton/ChatToggleButton.tsx +26 -0
  10. package/components/composites/ChatToggleButton/index.ts +2 -0
  11. package/components/composites/DashboardChart/DashboardChart.stories.tsx +18 -0
  12. package/components/composites/DashboardHeader/DashboardHeader.stories.tsx +18 -0
  13. package/components/composites/FilePreviewDialog/FilePreviewDialog.stories.tsx +18 -0
  14. package/components/composites/FormReports/FormReports.stories.tsx +18 -0
  15. package/components/composites/LayoutProvider/LayoutProvider.stories.tsx +18 -0
  16. package/components/composites/LoadingShimmer/LoadingShimmer.stories.tsx +18 -0
  17. package/components/composites/ModeSwitcher/ModeSwitcher.stories.tsx +18 -0
  18. package/components/composites/NavigationList/NavigationList.tsx +8 -1
  19. package/components/composites/NavigationList/interfaces.ts +1 -0
  20. package/components/composites/OrchestratorMessage/OrchestratorMessage.tsx +15 -5
  21. package/components/composites/ProjectSwitcher/ProjectSwitcher.stories.tsx +18 -0
  22. package/components/composites/PromptInput/PromptInput.tsx +5 -1
  23. package/components/composites/TriggerNode/TriggerNode.stories.tsx +18 -0
  24. package/components/composites/UserMessage/UserMessage.tsx +15 -5
  25. package/components/composites/WorkflowRunObservabilityPanel/WorkflowRunObservabilityPanel.stories.tsx +18 -0
  26. package/components/composites/index.ts +4 -0
  27. package/components/features/PageLayout/PageLayout.stories.tsx +75 -63
  28. package/components/features/PageLayout/PageLayout.tsx +73 -4
  29. package/components/features/PageLayout/usePageLayout.mock.ts +9 -0
  30. package/components/features/RefinementPanel/RefinementPanel.tsx +5 -4
  31. package/components/features/WorkflowObservabilityFeature/WorkflowObservabilityFeature.stories.tsx +18 -22
  32. package/components/features/WorkflowObservabilityFeature/WorkflowObservabilityFeature.tsx +4 -1
  33. package/components/index.ts +4 -1
  34. package/components/primitives/Toaster/Toaster.stories.tsx +366 -0
  35. package/components/primitives/Toaster/Toaster.tsx +6 -0
  36. package/components/primitives/Toaster/index.ts +6 -0
  37. package/components/primitives/index.ts +1 -0
  38. package/dist/index.cjs +1719 -1613
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.css +92 -8
  41. package/dist/index.d.ts +41 -1
  42. package/dist/index.js +1712 -1615
  43. package/dist/index.js.map +1 -1
  44. package/package.json +1 -1
@@ -40,7 +40,7 @@ export const InboxPanel = React.memo<InboxPanelProps>(
40
40
  </div>
41
41
  ) : null}
42
42
 
43
- <div className="px-4 pb-2">
43
+ <div className="px-4 pt-4 pb-2">
44
44
  <Input
45
45
  aria-label="Search inbox items"
46
46
  className="h-8"
@@ -21,6 +21,7 @@ export const SectionLayout = React.memo<SectionLayoutProps>(
21
21
  resizable = true,
22
22
  dragHandleColor = "border",
23
23
  className,
24
+ padded = true,
24
25
  ...props
25
26
  }) => {
26
27
  // Transform sections to include headers
@@ -47,6 +48,7 @@ export const SectionLayout = React.memo<SectionLayoutProps>(
47
48
  onSectionResize={onSectionResize}
48
49
  dragHandleColor={dragHandleColor}
49
50
  className={className}
51
+ padded={padded}
50
52
  {...props}
51
53
  />
52
54
  )
@@ -20,4 +20,5 @@ export interface SectionLayoutProps extends React.ComponentPropsWithoutRef<"div"
20
20
  onSectionResize?: (sectionId: string, newSize: number) => void;
21
21
  resizable?: boolean;
22
22
  dragHandleColor?: "primary" | "secondary" | "accent" | "border" | "muted";
23
+ padded?: boolean;
23
24
  }
@@ -6,7 +6,7 @@ import {
6
6
  type Connection,
7
7
  useReactFlow,
8
8
  } from "@xyflow/react";
9
- import { useCallback, useEffect, useRef, useState } from "react";
9
+ import { useCallback, useEffect } from "react";
10
10
  import { Canvas } from "@/components/ai-elements/canvas";
11
11
  import { Connection as ConnectionLine } from "@/components/ai-elements/connection";
12
12
  import { Controls } from "@/components/ai-elements/controls";
@@ -47,18 +47,6 @@ function WorkflowCanvasInner({
47
47
  className,
48
48
  }: WorkflowCanvasProps) {
49
49
  const { fitView } = useReactFlow();
50
- const viewportInitialized = useRef(false);
51
- const [isCanvasReady, setIsCanvasReady] = useState(false);
52
-
53
- useEffect(() => {
54
- if (!viewportInitialized.current && nodes.length > 0) {
55
- setTimeout(() => {
56
- fitView({ maxZoom: 1, minZoom: 0.5, padding: 0.2, duration: 0 });
57
- viewportInitialized.current = true;
58
- setIsCanvasReady(true);
59
- }, 0);
60
- }
61
- }, [nodes.length, fitView]);
62
50
 
63
51
  useEffect(() => {
64
52
  const handleKeyDown = (event: KeyboardEvent) => {
@@ -85,8 +73,6 @@ function WorkflowCanvasInner({
85
73
  className={className}
86
74
  data-testid="workflow-canvas"
87
75
  style={{
88
- opacity: isCanvasReady ? 1 : 0,
89
- transition: "opacity 300ms",
90
76
  width: "100%",
91
77
  height: "100%",
92
78
  }}
@@ -18,6 +18,7 @@ export interface AdjustableLayoutProps extends React.ComponentPropsWithoutRef<"d
18
18
  storageKey?: string // localStorage key for persistence
19
19
  onSectionResize?: (sectionId: string, newSize: number) => void
20
20
  dragHandleColor?: "primary" | "secondary" | "accent" | "border" | "muted"
21
+ padded?: boolean
21
22
  }
22
23
 
23
24
  /**
@@ -28,19 +29,20 @@ export interface AdjustableLayoutProps extends React.ComponentPropsWithoutRef<"d
28
29
  * Supports localStorage persistence and responsive behavior.
29
30
  */
30
31
  export const AdjustableLayout = React.memo<AdjustableLayoutProps>(
31
- ({
32
- sections,
33
- orientation = "horizontal",
32
+ ({
33
+ sections,
34
+ orientation = "horizontal",
34
35
  storageKey,
35
36
  onSectionResize,
36
37
  dragHandleColor = "border",
37
38
  className,
38
- ...props
39
+ padded = false,
40
+ ...props
39
41
  }) => {
40
42
  // Color mapping for drag handles
41
43
  const colorMap = {
42
44
  primary: "bg-primary hover:bg-primary/90",
43
- secondary: "bg-secondary hover:bg-secondary/80",
45
+ secondary: "bg-secondary hover:bg-secondary/80",
44
46
  accent: "bg-accent hover:bg-accent/80",
45
47
  border: "bg-border hover:bg-border/80",
46
48
  muted: "bg-muted hover:bg-muted/80"
@@ -49,7 +51,7 @@ export const AdjustableLayout = React.memo<AdjustableLayoutProps>(
49
51
  const hoverColorMap = {
50
52
  primary: "group-hover:bg-primary/30",
51
53
  secondary: "group-hover:bg-secondary/30",
52
- accent: "group-hover:bg-accent/30",
54
+ accent: "group-hover:bg-accent/30",
53
55
  border: "group-hover:bg-border/30",
54
56
  muted: "group-hover:bg-muted/30"
55
57
  }
@@ -77,7 +79,7 @@ export const AdjustableLayout = React.memo<AdjustableLayoutProps>(
77
79
  } catch {
78
80
  // ignore malformed storage
79
81
  }
80
- // eslint-disable-next-line react-hooks/exhaustive-deps
82
+ // eslint-disable-next-line react-hooks/exhaustive-deps
81
83
  }, [storageKey])
82
84
 
83
85
  const [draggingIndex, setDraggingIndex] = React.useState<number | null>(null)
@@ -119,33 +121,51 @@ export const AdjustableLayout = React.memo<AdjustableLayoutProps>(
119
121
 
120
122
  const currentX = orientation === "horizontal" ? e.clientX : e.clientY
121
123
  const deltaX = currentX - startX
122
-
124
+
123
125
  const deltaPercent = (deltaX / containerSize) * 100
126
+
127
+ const p1 = sections[draggingIndex]
128
+ const p2 = sections[draggingIndex + 1]
129
+
130
+ const p1Start = startSizes[draggingIndex]
131
+ const p2Start = startSizes[draggingIndex + 1]
132
+
133
+ const p1Min = p1.minSize ?? 10
134
+ const p1Max = p1.maxSize ?? 80
135
+ const p2Min = p2.minSize ?? 10
136
+ const p2Max = p2.maxSize ?? 80
137
+
138
+ // Calculate how much we can actually change panel 1
139
+ // If deltaPercent > 0, we are growing p1 and shrinking p2
140
+ const maxPositiveDelta = Math.max(0, Math.min(
141
+ p1Max - p1Start, // Space p1 has to grow
142
+ p2Start - p2Min // Space p2 has to shrink
143
+ ))
144
+
145
+ // If deltaPercent < 0, we are shrinking p1 and growing p2
146
+ const maxNegativeDelta = Math.min(0, Math.max(
147
+ p1Min - p1Start, // Space p1 has to shrink (negative)
148
+ p2Start - p2Max // Space p2 has to grow (negative)
149
+ ))
150
+
151
+ // Clamp the delta
152
+ let clampedDelta = deltaPercent
153
+ if (clampedDelta > 0) {
154
+ clampedDelta = Math.min(clampedDelta, maxPositiveDelta)
155
+ } else {
156
+ clampedDelta = Math.max(clampedDelta, maxNegativeDelta)
157
+ }
158
+
124
159
  const newSizes = [...startSizes]
125
-
126
- // Adjust sizes of adjacent panels
127
- newSizes[draggingIndex] = Math.max(
128
- sections[draggingIndex].minSize ?? 10,
129
- Math.min(
130
- sections[draggingIndex].maxSize ?? 80,
131
- startSizes[draggingIndex] + deltaPercent
132
- )
133
- )
134
-
135
- newSizes[draggingIndex + 1] = Math.max(
136
- sections[draggingIndex + 1].minSize ?? 10,
137
- Math.min(
138
- sections[draggingIndex + 1].maxSize ?? 80,
139
- startSizes[draggingIndex + 1] - deltaPercent
140
- )
141
- )
142
-
143
- // Normalize to 100%
160
+ newSizes[draggingIndex] = p1Start + clampedDelta
161
+ newSizes[draggingIndex + 1] = p2Start - clampedDelta
162
+
163
+ // Normalize to 100% just in case of floating point drift
144
164
  const total = newSizes.reduce((sum, size) => sum + size, 0)
145
165
  const normalizedSizes = newSizes.map(size => (size / total) * 100)
146
-
166
+
147
167
  setSizes(normalizedSizes)
148
-
168
+
149
169
  // Notify parent
150
170
  if (onSectionResize) {
151
171
  onSectionResize(sections[draggingIndex].id, normalizedSizes[draggingIndex])
@@ -183,12 +203,12 @@ export const AdjustableLayout = React.memo<AdjustableLayoutProps>(
183
203
  ? { flex: `0 0 ${section.fixedSize}`, width: section.fixedSize, minWidth: section.fixedSize }
184
204
  : { flex: `0 0 ${section.fixedSize}`, height: section.fixedSize, minHeight: section.fixedSize }
185
205
  : null
186
-
206
+
187
207
  return (
188
208
  <React.Fragment key={section.id}>
189
209
  <div
190
210
  className={cn(
191
- "min-h-0 overflow-hidden bg-card border border-border rounded-md",
211
+ "min-h-0 overflow-hidden bg-card border border-border rounded-xl",
192
212
  section.className
193
213
  )}
194
214
  style={{
@@ -199,25 +219,35 @@ export const AdjustableLayout = React.memo<AdjustableLayoutProps>(
199
219
  >
200
220
  {section.content}
201
221
  </div>
202
-
222
+
203
223
  {/* Show drag handle after this panel if it's not the last one */}
204
224
  {isResizable && (
205
225
  <div
206
226
  className={cn(
207
- `${colorMap[dragHandleColor]} flex-shrink-0 transition-colors duration-200 relative group`,
208
- orientation === "vertical"
209
- ? "cursor-row-resize h-1 w-full"
210
- : "cursor-col-resize w-1 h-full"
227
+ "flex-shrink-0 flex items-center justify-center relative group",
228
+ orientation === "vertical"
229
+ ? "cursor-row-resize h-2 w-full"
230
+ : "cursor-col-resize w-2 h-full"
211
231
  )}
212
232
  onMouseDown={(e) => handleMouseDown(index, e)}
213
233
  >
214
- <div
234
+ {/* Visible pill */}
235
+ <div
236
+ className={cn(
237
+ `${colorMap[dragHandleColor]} transition-colors duration-200 rounded-full`,
238
+ orientation === "vertical"
239
+ ? "h-1 w-8"
240
+ : "w-1 h-8"
241
+ )}
242
+ />
243
+ {/* Invisible large hit area */}
244
+ <div
215
245
  className={cn(
216
- `absolute inset-0 ${hoverColorMap[dragHandleColor]}`,
217
- orientation === "vertical"
218
- ? "h-3 -translate-y-1"
219
- : "w-3 -translate-x-1"
220
- )}
246
+ "absolute z-10",
247
+ orientation === "vertical"
248
+ ? "inset-x-0 -top-2 -bottom-2"
249
+ : "inset-y-0 -left-2 -right-2"
250
+ )}
221
251
  />
222
252
  </div>
223
253
  )}
@@ -230,12 +260,13 @@ export const AdjustableLayout = React.memo<AdjustableLayoutProps>(
230
260
  ref={containerRef}
231
261
  className={cn(
232
262
  "flex overflow-hidden h-full gap-1 min-w-0",
263
+ padded && "p-4",
233
264
  orientation === "horizontal" ? "flex-row" : "flex-col",
234
265
  className
235
266
  )}
236
267
  {...props}
237
268
  >
238
- {sections.map((section, index) =>
269
+ {sections.map((section, index) =>
239
270
  renderPanel(section, sizes[index], index)
240
271
  )}
241
272
  </div>
@@ -11,6 +11,7 @@ export const AppHeader = React.memo<AppHeaderProps>(({
11
11
  defaultTab,
12
12
  onTabChange,
13
13
  className,
14
+ tabsPosition = 'center',
14
15
  showSidebarToggle = true,
15
16
  showTitle = true
16
17
  }) => {
@@ -30,7 +31,7 @@ export const AppHeader = React.memo<AppHeaderProps>(({
30
31
  </div>
31
32
 
32
33
  <div className="justify-self-center">
33
- {tabs && tabs.length > 0 && (
34
+ {tabsPosition === 'center' && tabs && tabs.length > 0 && (
34
35
  <Tabs defaultValue={defaultTab || tabs[0]?.value} onValueChange={onTabChange}>
35
36
  <TabsList>
36
37
  {tabs.map((tab) => (
@@ -43,7 +44,20 @@ export const AppHeader = React.memo<AppHeaderProps>(({
43
44
  )}
44
45
  </div>
45
46
 
46
- <div className="flex min-w-0 items-center justify-end gap-2">{actions}</div>
47
+ <div className="flex min-w-0 items-center justify-end gap-2">
48
+ {tabsPosition === 'right' && tabs && tabs.length > 0 && (
49
+ <Tabs defaultValue={defaultTab || tabs[0]?.value} onValueChange={onTabChange}>
50
+ <TabsList>
51
+ {tabs.map((tab) => (
52
+ <TabsTrigger key={tab.value} value={tab.value}>
53
+ {tab.label}
54
+ </TabsTrigger>
55
+ ))}
56
+ </TabsList>
57
+ </Tabs>
58
+ )}
59
+ {actions}
60
+ </div>
47
61
  </div>
48
62
  </header>
49
63
  )
@@ -11,6 +11,7 @@ export interface AppHeaderProps {
11
11
  tabs?: TabItem[];
12
12
  defaultTab?: string;
13
13
  onTabChange?: (value: string) => void;
14
+ tabsPosition?: 'center' | 'right';
14
15
  className?: string;
15
16
  showSidebarToggle?: boolean;
16
17
  showTitle?: boolean;
@@ -0,0 +1,31 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { ChatToggleButton } from './ChatToggleButton'
3
+ import { fn } from '@storybook/test'
4
+
5
+ const meta = {
6
+ title: 'Composites/ChatToggleButton',
7
+ component: ChatToggleButton,
8
+ tags: ['autodocs'],
9
+ parameters: {
10
+ layout: 'centered',
11
+ },
12
+ } satisfies Meta<typeof ChatToggleButton>
13
+
14
+ export default meta
15
+ type Story = StoryObj<typeof meta>
16
+
17
+ export const Default: Story = {
18
+ args: {
19
+ isOpen: true,
20
+ label: "Hide Chat",
21
+ onClick: fn(),
22
+ },
23
+ }
24
+
25
+ export const Closed: Story = {
26
+ args: {
27
+ isOpen: false,
28
+ label: "Show Chat",
29
+ onClick: fn(),
30
+ },
31
+ }
@@ -0,0 +1,26 @@
1
+ import { Button, type ButtonProps } from "@/components/primitives/Button"
2
+ import { Icon } from "@/components/primitives/Icon"
3
+ import * as React from "react"
4
+
5
+ export interface ChatToggleButtonProps extends Omit<ButtonProps, "children"> {
6
+ isOpen?: boolean
7
+ label?: string
8
+ }
9
+
10
+ export function ChatToggleButton({
11
+ isOpen = true,
12
+ label = "Hide Chat",
13
+ className,
14
+ ...props
15
+ }: ChatToggleButtonProps) {
16
+ return (
17
+ <Button
18
+ variant="ghost"
19
+ className={`-ml-2 h-8 text-muted-foreground hover:text-foreground ${className ?? ""}`}
20
+ {...props}
21
+ >
22
+ <Icon name="panel-left" size="sm" />
23
+ {label}
24
+ </Button>
25
+ )
26
+ }
@@ -0,0 +1,2 @@
1
+ export { ChatToggleButton } from "./ChatToggleButton"
2
+ export type { ChatToggleButtonProps } from "./ChatToggleButton"
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { DashboardChart } from './DashboardChart'
3
+
4
+ const meta = {
5
+ title: 'Composites/DashboardChart',
6
+ component: DashboardChart,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ } satisfies Meta<typeof DashboardChart>
12
+
13
+ export default meta
14
+ type Story = StoryObj<typeof meta>
15
+
16
+ export const Default: Story = {
17
+ args: {} as any,
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { DashboardHeader } from './DashboardHeader'
3
+
4
+ const meta = {
5
+ title: 'Composites/DashboardHeader',
6
+ component: DashboardHeader,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ } satisfies Meta<typeof DashboardHeader>
12
+
13
+ export default meta
14
+ type Story = StoryObj<typeof meta>
15
+
16
+ export const Default: Story = {
17
+ args: {} as any,
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { FilePreviewDialog } from './FilePreviewDialog'
3
+
4
+ const meta = {
5
+ title: 'Composites/FilePreviewDialog',
6
+ component: FilePreviewDialog,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ } satisfies Meta<typeof FilePreviewDialog>
12
+
13
+ export default meta
14
+ type Story = StoryObj<typeof meta>
15
+
16
+ export const Default: Story = {
17
+ args: {} as any,
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { FormReports } from './FormReports'
3
+
4
+ const meta = {
5
+ title: 'Composites/FormReports',
6
+ component: FormReports,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ } satisfies Meta<typeof FormReports>
12
+
13
+ export default meta
14
+ type Story = StoryObj<typeof meta>
15
+
16
+ export const Default: Story = {
17
+ args: {} as any,
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { LayoutProvider } from './LayoutProvider'
3
+
4
+ const meta = {
5
+ title: 'Composites/LayoutProvider',
6
+ component: LayoutProvider,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ } satisfies Meta<typeof LayoutProvider>
12
+
13
+ export default meta
14
+ type Story = StoryObj<typeof meta>
15
+
16
+ export const Default: Story = {
17
+ args: {} as any,
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { LoadingShimmer } from './LoadingShimmer'
3
+
4
+ const meta = {
5
+ title: 'Composites/LoadingShimmer',
6
+ component: LoadingShimmer,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ } satisfies Meta<typeof LoadingShimmer>
12
+
13
+ export default meta
14
+ type Story = StoryObj<typeof meta>
15
+
16
+ export const Default: Story = {
17
+ args: {} as any,
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { ModeSwitcher } from './ModeSwitcher'
3
+
4
+ const meta = {
5
+ title: 'Composites/ModeSwitcher',
6
+ component: ModeSwitcher,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ } satisfies Meta<typeof ModeSwitcher>
12
+
13
+ export default meta
14
+ type Story = StoryObj<typeof meta>
15
+
16
+ export const Default: Story = {
17
+ args: {} as any,
18
+ }
@@ -12,6 +12,7 @@ export interface NavigationItem {
12
12
  url: string
13
13
  icon?: string
14
14
  isActive?: boolean
15
+ onClick?: (e: React.MouseEvent) => void
15
16
  }
16
17
 
17
18
  export interface NavigationListProps {
@@ -29,7 +30,13 @@ export const NavigationList = React.memo<NavigationListProps>(
29
30
  <SidebarMenuButton
30
31
  tooltip={item.title}
31
32
  isActive={item.isActive}
32
- onClick={() => onItemClick?.(item)}
33
+ onClick={(e) => {
34
+ if (item.onClick) {
35
+ e.preventDefault();
36
+ item.onClick(e);
37
+ }
38
+ onItemClick?.(item)
39
+ }}
33
40
  asChild
34
41
  >
35
42
  <a href={item.url}>
@@ -3,5 +3,6 @@ export interface NavigationItem {
3
3
  url: string;
4
4
  icon?: string;
5
5
  isActive?: boolean;
6
+ onClick?: (e: React.MouseEvent) => void;
6
7
  items?: NavigationItem[];
7
8
  }
@@ -1,4 +1,9 @@
1
1
  import * as React from "react"
2
+ import {
3
+ Avatar,
4
+ AvatarFallback,
5
+ } from "@/components/primitives/Avatar"
6
+ import { Icon } from "@/components/primitives/Icon"
2
7
  import {
3
8
  Message,
4
9
  MessageContent,
@@ -49,11 +54,16 @@ export const OrchestratorMessage = React.memo<OrchestratorMessageProps>(
49
54
 
50
55
  return (
51
56
  <Message from="assistant">
52
- {showAvatar && (
53
- <MessageAvatar
54
- src={message.avatarSrc || "/coordinator-avatar.png"}
55
- name={message.avatarName || "Coordinator"}
56
- />
57
+ {showAvatar && (message.avatarSrc
58
+ ? <MessageAvatar
59
+ src={message.avatarSrc}
60
+ name={message.avatarName || "Coordinator"}
61
+ />
62
+ : <Avatar className="size-8 ring-1 ring-border">
63
+ <AvatarFallback>
64
+ <Icon name="bot" />
65
+ </AvatarFallback>
66
+ </Avatar>
57
67
  )}
58
68
 
59
69
  <div className="flex-1 min-w-0">
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { ProjectSwitcher } from './ProjectSwitcher'
3
+
4
+ const meta = {
5
+ title: 'Composites/ProjectSwitcher',
6
+ component: ProjectSwitcher,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ } satisfies Meta<typeof ProjectSwitcher>
12
+
13
+ export default meta
14
+ type Story = StoryObj<typeof meta>
15
+
16
+ export const Default: Story = {
17
+ args: {} as any,
18
+ }
@@ -14,6 +14,8 @@ import {
14
14
  type PromptInputProps as AIPromptInputProps,
15
15
  } from "@/components/ai-elements/prompt-input";
16
16
  import type { FormEvent } from "react";
17
+ import { Button } from "@/components/primitives/Button";
18
+ import { Icon } from "@/components/primitives/Icon";
17
19
 
18
20
  export interface PromptInputBlockProps
19
21
  extends Omit<
@@ -80,7 +82,9 @@ export const PromptInput = React.memo<PromptInputBlockProps>(
80
82
  </PromptInputBody>
81
83
  <PromptInputFooter>
82
84
  <PromptInputTools>
83
- {}
85
+ <Button variant="ghost" size="icon" className="h-8 w-8 rounded-full" type="button" disabled={disabled}>
86
+ <Icon name="plus" size="sm" />
87
+ </Button>
84
88
  </PromptInputTools>
85
89
  <PromptInputSubmit disabled={disabled} status={loading ? "submitted" : undefined} />
86
90
  </PromptInputFooter>
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { TriggerNode } from './TriggerNode'
3
+
4
+ const meta = {
5
+ title: 'Composites/TriggerNode',
6
+ component: TriggerNode,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ } satisfies Meta<typeof TriggerNode>
12
+
13
+ export default meta
14
+ type Story = StoryObj<typeof meta>
15
+
16
+ export const Default: Story = {
17
+ args: {} as any,
18
+ }