ai-design-system 0.1.0 → 0.1.2

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 (67) hide show
  1. package/README.md +0 -269
  2. package/components/ai-elements/canvas.tsx +2 -1
  3. package/components/ai-elements/edge.tsx +28 -20
  4. package/components/ai-elements/node.tsx +23 -4
  5. package/components/blocks/SectionLayout/SectionLayout.stories.tsx +276 -0
  6. package/components/blocks/SectionLayout/SectionLayout.tsx +82 -0
  7. package/components/blocks/SectionLayout/index.ts +2 -0
  8. package/components/blocks/WorkflowCanvas/WorkflowCanvas.stories.tsx +279 -0
  9. package/components/blocks/WorkflowCanvas/WorkflowCanvas.tsx +180 -0
  10. package/components/blocks/WorkflowCanvas/index.ts +2 -0
  11. package/components/blocks/index.ts +17 -0
  12. package/components/composites/AdjustableLayout/AdjustableLayout.stories.tsx +203 -0
  13. package/components/composites/AdjustableLayout/AdjustableLayout.tsx +229 -0
  14. package/components/composites/AdjustableLayout/index.ts +2 -0
  15. package/components/composites/AppHeader/AppHeader.mocks.ts +26 -0
  16. package/components/composites/AppHeader/AppHeader.stories.tsx +102 -2
  17. package/components/composites/AppHeader/AppHeader.tsx +38 -5
  18. package/components/composites/AppHeader/index.ts +1 -1
  19. package/components/composites/NavigationList/NavigationList.tsx +1 -0
  20. package/components/composites/StateNode/StateNode.stories.tsx +281 -0
  21. package/components/composites/StateNode/StateNode.tsx +100 -0
  22. package/components/composites/StateNode/index.ts +2 -0
  23. package/components/composites/TransitionNode/TransitionNode.stories.tsx +260 -0
  24. package/components/composites/TransitionNode/TransitionNode.tsx +80 -0
  25. package/components/composites/TransitionNode/index.ts +2 -0
  26. package/components/composites/WorkflowToolbar/WorkflowToolbar.stories.tsx +352 -0
  27. package/components/composites/WorkflowToolbar/WorkflowToolbar.tsx +195 -0
  28. package/components/composites/WorkflowToolbar/index.ts +7 -0
  29. package/components/composites/index.ts +17 -2
  30. package/components/features/AIDocEditor/README.md +127 -0
  31. package/components/features/PageLayout/PageLayout.behaviors.stories.tsx +44 -1
  32. package/components/features/PageLayout/PageLayout.mocks.ts +9 -0
  33. package/components/features/PageLayout/PageLayout.stories.tsx +144 -43
  34. package/components/features/PageLayout/PageLayout.tsx +52 -2
  35. package/components/features/PageLayout/README.md +122 -0
  36. package/components/features/PageLayout/usePageLayout.d.ts +7 -1
  37. package/components/features/PageLayout/usePageLayout.mock.ts +18 -3
  38. package/components/features/RefinementPanel/RefinementPanel.stories.tsx +2 -2
  39. package/components/features/RefinementPanel/RefinementPanel.tsx +1 -1
  40. package/components/features/RefinementPanel/index.ts +1 -1
  41. package/components/features/RefinementPanel/useRefinementPanel.mock.ts +1 -1
  42. package/components/features/SpecNavigator/README.md +116 -0
  43. package/components/features/SpecNavigator/SpecNavigator.stories.tsx +2 -2
  44. package/components/features/SpecNavigator/useSpecNavigator.mock.ts +1 -1
  45. package/components/features/WorkflowBuilder/README.md +159 -0
  46. package/components/features/WorkflowBuilder/WorkflowBuilder.behaviors.stories.tsx +136 -0
  47. package/components/features/WorkflowBuilder/WorkflowBuilder.mocks.ts +36 -0
  48. package/components/features/WorkflowBuilder/WorkflowBuilder.stories.tsx +135 -0
  49. package/components/features/WorkflowBuilder/WorkflowBuilder.tsx +97 -0
  50. package/components/features/WorkflowBuilder/index.ts +2 -0
  51. package/components/features/WorkflowBuilder/useWorkflowBuilder.d.ts +44 -0
  52. package/components/features/WorkflowBuilder/useWorkflowBuilder.mock.ts +116 -0
  53. package/components/features/index.ts +8 -0
  54. package/components/index.ts +1 -1
  55. package/components/primitives/ButtonGroup/ButtonGroup.stories.tsx +35 -0
  56. package/components/primitives/ButtonGroup/ButtonGroup.tsx +39 -0
  57. package/components/primitives/ButtonGroup/index.ts +3 -0
  58. package/components/primitives/index.ts +1 -0
  59. package/components/ui/animated-border.tsx +79 -0
  60. package/components/ui/sidebar.tsx +2 -2
  61. package/dist/index.cjs +1143 -173
  62. package/dist/index.cjs.map +1 -1
  63. package/dist/index.css +156 -10
  64. package/dist/index.d.ts +124 -0
  65. package/dist/index.js +1130 -175
  66. package/dist/index.js.map +1 -1
  67. package/package.json +14 -12
package/README.md CHANGED
@@ -36,272 +36,3 @@ pnpm storybook
36
36
  ```
37
37
 
38
38
  Open [http://localhost:6006](http://localhost:6006) to view the component library.
39
-
40
- ## Design System Governance
41
-
42
- ### Pre-Commit Hooks
43
-
44
- The design system enforces strict quality standards through automated pre-commit hooks:
45
-
46
- **Master Validation Script**
47
- - Runs all design system validations in a single command
48
- - Run manually: `bash scripts/run-all-validations.sh` or `pnpm run prebuild`
49
-
50
- **Layer Import Architecture**
51
- - Validates that components follow the layered architecture pattern
52
- - Ensures primitives don't import from patterns or features
53
- - Ensures patterns don't import from features
54
- - Run manually: `python3 scripts/validate-layer-imports.py`
55
-
56
- **Storybook Coverage**
57
- - Ensures every component has a corresponding `.stories.tsx` file
58
- - Validates story file naming conventions
59
- - Run manually: `node scripts/validate-storybook-coverage.js`
60
-
61
- **Adding New Validations**
62
- To add a new validation to the master script, edit `scripts/run-all-validations.sh`:
63
- 1. Add a new section with clear header and description
64
- 2. Run your validation script and capture exit code
65
- 3. Add the exit code to the final results check
66
- 4. The script provides clear guidance with comments for adding new validations
67
-
68
- **Bypassing Hooks (Not Recommended)**
69
- ```bash
70
- git commit --no-verify
71
- ```
72
-
73
- Only bypass hooks if you have a valid reason and plan to fix violations immediately.
74
-
75
- ## Project Structure
76
-
77
- ```
78
- packages/ui-lib/
79
- ├── components/
80
- │ ├── primitives/ # Base components (buttons, inputs, etc.)
81
- │ ├── patterns/ # Composite components (cards, forms, etc.)
82
- │ └── features/ # Feature-specific components
83
- ├── scripts/
84
- │ ├── hooks/ # Git hooks (tracked in version control)
85
- │ │ └── pre-commit # Pre-commit validation hook
86
- │ ├── setup-hooks.sh # Hook installation script
87
- │ ├── run-all-validations.sh # Master validation script
88
- │ ├── validate-layer-imports.py
89
- │ └── validate-storybook-coverage.js
90
- ├── styles/ # Global styles and themes
91
- └── tokens/ # Design tokens
92
- ```
93
-
94
- ## Layer Architecture
95
-
96
- The design system follows a strict three-layer architecture:
97
-
98
- 1. **Primitives** - Base components with no dependencies on other layers
99
- - Examples: Button, Input, Textarea, Badge
100
- - Can only import from external libraries and utilities
101
-
102
- 2. **Patterns** - Composite components built from primitives
103
- - Examples: Card, Form, Dialog
104
- - Can import from primitives and external libraries
105
-
106
- 3. **Features** - Feature-specific components
107
- - Examples: AIConversation, RefinementPanel
108
- - Can import from primitives, patterns, and external libraries
109
-
110
- **Import Rules:**
111
- - Primitives → No internal imports
112
- - Patterns → Can import Primitives
113
- - Features → Can import Primitives + Patterns
114
-
115
- ## Available Scripts
116
-
117
- ```bash
118
- pnpm dev # Start development server
119
- pnpm build # Build for production
120
- pnpm start # Start production server
121
- pnpm lint # Run ESLint
122
- pnpm tokens:build # Build design tokens
123
- pnpm tokens:watch # Watch design tokens
124
- pnpm storybook # Start Storybook dev server
125
- pnpm build-storybook # Build Storybook for production
126
- ```
127
-
128
- ## Creating New Components
129
-
130
- ### 1. Choose the Correct Layer
131
-
132
- Determine which layer your component belongs to:
133
- - **Primitive**: Standalone, reusable UI element
134
- - **Pattern**: Combination of primitives
135
- - **Feature**: Domain-specific component
136
-
137
- ### 2. Create Component File
138
-
139
- Create your component following the established structure:
140
-
141
- ```tsx
142
- // components/primitives/YourComponent/YourComponent.tsx
143
- import { cva, type VariantProps } from "class-variance-authority";
144
- import { cn } from "@/lib/utils";
145
-
146
- const yourComponentVariants = cva(
147
- "base-classes",
148
- {
149
- variants: {
150
- variant: {
151
- default: "variant-classes",
152
- secondary: "variant-classes",
153
- },
154
- size: {
155
- default: "size-classes",
156
- sm: "size-classes",
157
- lg: "size-classes",
158
- },
159
- },
160
- defaultVariants: {
161
- variant: "default",
162
- size: "default",
163
- },
164
- }
165
- );
166
-
167
- export interface YourComponentProps
168
- extends React.HTMLAttributes<HTMLElement>,
169
- VariantProps<typeof yourComponentVariants> {
170
- // Additional props
171
- }
172
-
173
- export function YourComponent({
174
- className,
175
- variant,
176
- size,
177
- ...props
178
- }: YourComponentProps) {
179
- return (
180
- <div
181
- className={cn(yourComponentVariants({ variant, size, className }))}
182
- {...props}
183
- />
184
- );
185
- }
186
- ```
187
-
188
- ### 3. Create Index File
189
-
190
- ```tsx
191
- // components/primitives/YourComponent/index.ts
192
- export { YourComponent } from "./YourComponent";
193
- export type { YourComponentProps } from "./YourComponent";
194
- ```
195
-
196
- ### 4. Create Storybook Story (REQUIRED)
197
-
198
- Every component must have a `.stories.tsx` file:
199
-
200
- ```tsx
201
- // components/primitives/YourComponent/YourComponent.stories.tsx
202
- import type { Meta, StoryObj } from "@storybook/react";
203
- import { YourComponent } from "./YourComponent";
204
-
205
- const meta = {
206
- title: "Primitives/YourComponent",
207
- component: YourComponent,
208
- tags: ["autodocs"],
209
- parameters: {
210
- layout: "centered",
211
- },
212
- } satisfies Meta<typeof YourComponent>;
213
-
214
- export default meta;
215
- type Story = StoryObj<typeof meta>;
216
-
217
- export const Default: Story = {
218
- args: {
219
- // default props
220
- },
221
- };
222
-
223
- export const Variant: Story = {
224
- args: {
225
- variant: "secondary",
226
- },
227
- };
228
- ```
229
-
230
- ### 5. Validate
231
-
232
- Run validation scripts to ensure compliance:
233
-
234
- ```bash
235
- # Run all validations (recommended)
236
- bash scripts/run-all-validations.sh
237
- # or
238
- pnpm run prebuild
239
-
240
- # Run individual validations
241
- python3 scripts/validate-layer-imports.py # Layer architecture
242
- node scripts/validate-storybook-coverage.js # Storybook coverage
243
- ```
244
-
245
- ## Design Tokens
246
-
247
- The design system uses Style Dictionary for design tokens management:
248
-
249
- ```bash
250
- # Build tokens once
251
- pnpm tokens:build
252
-
253
- # Watch for changes
254
- pnpm tokens:watch
255
- ```
256
-
257
- Tokens are defined in the `tokens/` directory and compiled to CSS custom properties.
258
-
259
- ## Technology Stack
260
-
261
- - **Framework**: Next.js 16 with App Router
262
- - **UI**: React 19
263
- - **Styling**: Tailwind CSS 4
264
- - **Component Variants**: Class Variance Authority (CVA)
265
- - **Component Foundation**: Radix UI primitives
266
- - **Documentation**: Storybook 10
267
- - **Type Safety**: TypeScript 5 (strict mode)
268
- - **Icons**: Lucide React
269
- - **Animation**: Motion (Framer Motion)
270
-
271
- ## Accessibility
272
-
273
- All components must meet WCAG 2.1 Level AA standards:
274
- - Keyboard navigation support
275
- - Screen reader compatibility
276
- - Proper ARIA attributes
277
- - Focus management
278
- - Color contrast requirements
279
-
280
- ## Theming
281
-
282
- The design system supports:
283
- - Light and dark modes
284
- - Design token-based theming
285
- - CSS custom properties
286
- - Responsive design across all breakpoints
287
-
288
- ## Contributing
289
-
290
- 1. Set up git hooks: `./scripts/setup-hooks.sh`
291
- 2. Create components following the layer architecture
292
- 3. Include Storybook stories for all components
293
- 4. Ensure all validations pass before committing
294
- 5. Document accessibility features and keyboard shortcuts
295
-
296
- ## Learn More
297
-
298
- - [Next.js Documentation](https://nextjs.org/docs)
299
- - [Tailwind CSS](https://tailwindcss.com)
300
- - [Radix UI](https://www.radix-ui.com)
301
- - [shadcn/ui](https://ui.shadcn.com)
302
- - [Storybook](https://storybook.js.org)
303
- - [CVA](https://cva.style)
304
-
305
- ## Support
306
-
307
- For questions or issues with the design system, contact the Design System Guardian or open an issue in the repository.
@@ -9,13 +9,14 @@ type CanvasProps = ReactFlowProps & {
9
9
 
10
10
  export const Canvas = ({ children, ...props }: CanvasProps) => (
11
11
  <ReactFlow
12
+ {...props}
12
13
  deleteKeyCode={["Backspace", "Delete"]}
13
14
  fitView
14
15
  panOnDrag={false}
15
16
  panOnScroll
17
+ proOptions={{ hideAttribution: true }}
16
18
  selectionOnDrag={true}
17
19
  zoomOnDoubleClick={false}
18
- {...props}
19
20
  >
20
21
  <Background bgColor="var(--sidebar)" />
21
22
  <Controls />
@@ -41,11 +41,9 @@ const Temporary = ({
41
41
 
42
42
  const getHandleCoordsByPosition = (
43
43
  node: InternalNode<Node>,
44
- handlePosition: Position
44
+ handlePosition: Position,
45
+ handleType: "source" | "target"
45
46
  ) => {
46
- // Choose the handle type based on position - Left is for target, Right is for source
47
- const handleType = handlePosition === Position.Left ? "target" : "source";
48
-
49
47
  const handle = node.internals.handleBounds?.[handleType]?.find(
50
48
  (h) => h.position === handlePosition
51
49
  );
@@ -57,9 +55,6 @@ const getHandleCoordsByPosition = (
57
55
  let offsetX = handle.width / 2;
58
56
  let offsetY = handle.height / 2;
59
57
 
60
- // this is a tiny detail to make the markerEnd of an edge visible.
61
- // The handle position that gets calculated has the origin top-left, so depending which side we are using, we add a little offset
62
- // when the handlePosition is Position.Right for example, we need to add an offset as big as the handle itself in order to get the correct position
63
58
  switch (handlePosition) {
64
59
  case Position.Left:
65
60
  offsetX = 0;
@@ -87,19 +82,32 @@ const getEdgeParams = (
87
82
  source: InternalNode<Node>,
88
83
  target: InternalNode<Node>
89
84
  ) => {
90
- const sourcePos = Position.Right;
91
- const [sx, sy] = getHandleCoordsByPosition(source, sourcePos);
92
- const targetPos = Position.Left;
93
- const [tx, ty] = getHandleCoordsByPosition(target, targetPos);
94
-
95
- return {
96
- sx,
97
- sy,
98
- tx,
99
- ty,
100
- sourcePos,
101
- targetPos,
102
- };
85
+ const sx = source.internals.positionAbsolute.x + (source.measured?.width ?? 0) / 2;
86
+ const sy = source.internals.positionAbsolute.y + (source.measured?.height ?? 0) / 2;
87
+ const tx = target.internals.positionAbsolute.x + (target.measured?.width ?? 0) / 2;
88
+ const ty = target.internals.positionAbsolute.y + (target.measured?.height ?? 0) / 2;
89
+
90
+ const dx = tx - sx;
91
+ const dy = ty - sy;
92
+
93
+ // Pick source/target positions based on dominant direction
94
+ let sourcePos: Position;
95
+ let targetPos: Position;
96
+
97
+ if (Math.abs(dx) > Math.abs(dy)) {
98
+ // Horizontal dominant
99
+ sourcePos = dx > 0 ? Position.Right : Position.Left;
100
+ targetPos = dx > 0 ? Position.Left : Position.Right;
101
+ } else {
102
+ // Vertical dominant
103
+ sourcePos = dy > 0 ? Position.Bottom : Position.Top;
104
+ targetPos = dy > 0 ? Position.Top : Position.Bottom;
105
+ }
106
+
107
+ const [srcX, srcY] = getHandleCoordsByPosition(source, sourcePos, "source");
108
+ const [tgtX, tgtY] = getHandleCoordsByPosition(target, targetPos, "target");
109
+
110
+ return { sx: srcX, sy: srcY, tx: tgtX, ty: tgtY, sourcePos, targetPos };
103
111
  };
104
112
 
105
113
  const Animated = ({ id, source, target, markerEnd, style }: EdgeProps) => {
@@ -7,6 +7,7 @@ import {
7
7
  CardHeader,
8
8
  CardTitle,
9
9
  } from "@/components/ui/card";
10
+ import { AnimatedBorder } from "@/components/ui/animated-border";
10
11
  import { cn } from "@/lib/utils";
11
12
  import { Handle, Position } from "@xyflow/react";
12
13
  import type { ComponentProps } from "react";
@@ -16,18 +17,36 @@ export type NodeProps = ComponentProps<typeof Card> & {
16
17
  target: boolean;
17
18
  source: boolean;
18
19
  };
20
+ status?: "idle" | "running" | "success" | "error";
19
21
  };
20
22
 
21
- export const Node = ({ handles, className, ...props }: NodeProps) => (
23
+ export const Node = ({ handles, className, status, ...props }: NodeProps) => (
22
24
  <Card
23
25
  className={cn(
24
- "node-container relative size-full h-auto w-sm gap-0 rounded-md p-0",
26
+ "node-container relative size-full h-auto w-sm gap-0 rounded-md bg-card p-0 transition-all duration-200",
27
+ status === "success" && "border-green-500 border-2",
28
+ status === "error" && "border-red-500 border-2",
25
29
  className
26
30
  )}
27
31
  {...props}
28
32
  >
29
- {handles.target && <Handle position={Position.Left} type="target" />}
30
- {handles.source && <Handle position={Position.Right} type="source" />}
33
+ {status === "running" && <AnimatedBorder />}
34
+ {handles.target && (
35
+ <>
36
+ <Handle id="target-top" position={Position.Top} type="target" />
37
+ <Handle id="target-right" position={Position.Right} type="target" />
38
+ <Handle id="target-bottom" position={Position.Bottom} type="target" />
39
+ <Handle id="target-left" position={Position.Left} type="target" />
40
+ </>
41
+ )}
42
+ {handles.source && (
43
+ <>
44
+ <Handle id="source-top" position={Position.Top} type="source" />
45
+ <Handle id="source-right" position={Position.Right} type="source" />
46
+ <Handle id="source-bottom" position={Position.Bottom} type="source" />
47
+ <Handle id="source-left" position={Position.Left} type="source" />
48
+ </>
49
+ )}
31
50
  {props.children}
32
51
  </Card>
33
52
  );
@@ -0,0 +1,276 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { SectionLayout } from './SectionLayout'
3
+
4
+ /**
5
+ * SectionLayout Block Stories
6
+ *
7
+ * A layout block that provides adjustable panels with headers.
8
+ * Uses AdjustableLayout composite for panel management and AppHeader composite for headers.
9
+ *
10
+ * ## Features
11
+ * - Adjustable panel sizing with drag handles
12
+ * - Optional headers with tabs in each panel
13
+ * - Horizontal and vertical orientation support
14
+ * - Panel size persistence via localStorage
15
+ *
16
+ * ## Usage
17
+ * Perfect for creating multi-panel layouts with independent headers,
18
+ * such as code editors, chat interfaces, or dashboard layouts.
19
+ */
20
+ const meta = {
21
+ title: 'Blocks/SectionLayout',
22
+ component: SectionLayout,
23
+ tags: ['autodocs'],
24
+ parameters: { layout: 'fullscreen' },
25
+ } satisfies Meta<typeof SectionLayout>
26
+
27
+ export default meta
28
+ type Story = StoryObj<typeof meta>
29
+
30
+ /**
31
+ * Default SectionLayout
32
+ *
33
+ * 4-panel adjustable layout with headers using AppHeader composite.
34
+ */
35
+ export const Default: Story = {
36
+ render: () => {
37
+ const sections = [
38
+ {
39
+ id: 'top-left',
40
+ content: (
41
+ <div className="h-full bg-muted rounded-lg border p-4">
42
+ <h3 className="font-medium mb-2">Top Left Content</h3>
43
+ <p className="text-sm text-muted-foreground">Content area with AppHeader composite</p>
44
+ </div>
45
+ ),
46
+ defaultSize: 25,
47
+ header: {
48
+ tabs: [
49
+ { value: 'view', label: 'View' },
50
+ { value: 'edit', label: 'Edit' },
51
+ ],
52
+ defaultTab: 'view',
53
+ showSidebarToggle: false,
54
+ showTitle: false,
55
+ },
56
+ },
57
+ {
58
+ id: 'top-right',
59
+ content: (
60
+ <div className="h-full bg-muted rounded-lg border p-4">
61
+ <h3 className="font-medium mb-2">Top Right Content</h3>
62
+ <p className="text-sm text-muted-foreground">Content area with AppHeader composite</p>
63
+ </div>
64
+ ),
65
+ defaultSize: 25,
66
+ header: {
67
+ tabs: [
68
+ { value: 'tab1', label: 'Tab 1' },
69
+ { value: 'tab2', label: 'Tab 2' },
70
+ { value: 'tab3', label: 'Tab 3' },
71
+ ],
72
+ defaultTab: 'tab1',
73
+ showSidebarToggle: false,
74
+ showTitle: false,
75
+ },
76
+ },
77
+ {
78
+ id: 'bottom-left',
79
+ content: (
80
+ <div className="h-full bg-muted rounded-lg border p-4">
81
+ <h3 className="font-medium mb-2">Bottom Left Content</h3>
82
+ <p className="text-sm text-muted-foreground">Content area with minimal AppHeader</p>
83
+ </div>
84
+ ),
85
+ defaultSize: 25,
86
+ header: {
87
+ showSidebarToggle: false,
88
+ showTitle: false,
89
+ },
90
+ },
91
+ {
92
+ id: 'bottom-right',
93
+ content: (
94
+ <div className="h-full bg-muted rounded-lg border p-4">
95
+ <h3 className="font-medium mb-2">Bottom Right Content</h3>
96
+ <p className="text-sm text-muted-foreground">Content area with AppHeader composite</p>
97
+ </div>
98
+ ),
99
+ defaultSize: 25,
100
+ header: {
101
+ tabs: [
102
+ { value: 'log', label: 'Log' },
103
+ { value: 'console', label: 'Console' },
104
+ ],
105
+ defaultTab: 'log',
106
+ showSidebarToggle: false,
107
+ showTitle: false,
108
+ },
109
+ },
110
+ ]
111
+
112
+ return (
113
+ <div className="h-screen p-4">
114
+ <SectionLayout
115
+ sections={sections}
116
+ storageKey="section-layout-default"
117
+ />
118
+ </div>
119
+ )
120
+ },
121
+ }
122
+
123
+ /**
124
+ * Single Panel Layout
125
+ *
126
+ * Single panel with header using AppHeader composite.
127
+ */
128
+ export const SinglePanel: Story = {
129
+ render: () => {
130
+ const sections = [
131
+ {
132
+ id: 'main-panel',
133
+ content: (
134
+ <div className="h-full bg-muted rounded-lg border p-4">
135
+ <h3 className="font-medium mb-2">Single Panel Content</h3>
136
+ <p className="text-sm text-muted-foreground">Single panel with AppHeader composite</p>
137
+ </div>
138
+ ),
139
+ defaultSize: 100,
140
+ header: {
141
+ tabs: [
142
+ { value: 'overview', label: 'Overview' },
143
+ { value: 'details', label: 'Details' },
144
+ { value: 'settings', label: 'Settings' },
145
+ ],
146
+ defaultTab: 'overview',
147
+ showSidebarToggle: false,
148
+ showTitle: false,
149
+ },
150
+ },
151
+ ]
152
+
153
+ return (
154
+ <div className="h-screen p-4">
155
+ <SectionLayout
156
+ sections={sections}
157
+ storageKey="section-layout-single"
158
+ />
159
+ </div>
160
+ )
161
+ },
162
+ }
163
+
164
+ /**
165
+ * Primary Drag Handles
166
+ *
167
+ * Demonstrates primary colored drag handles.
168
+ */
169
+ export const PrimaryDragHandles: Story = {
170
+ render: () => {
171
+ const sections = [
172
+ {
173
+ id: 'left',
174
+ content: (
175
+ <div className="h-full bg-muted rounded-lg border p-4">
176
+ <h3 className="font-medium mb-2">Left Panel</h3>
177
+ <p className="text-sm text-muted-foreground">Primary drag handles</p>
178
+ </div>
179
+ ),
180
+ defaultSize: 50,
181
+ header: {
182
+ showSidebarToggle: false,
183
+ showTitle: false,
184
+ },
185
+ },
186
+ {
187
+ id: 'right',
188
+ content: (
189
+ <div className="h-full bg-muted rounded-lg border p-4">
190
+ <h3 className="font-medium mb-2">Right Panel</h3>
191
+ <p className="text-sm text-muted-foreground">Primary drag handles</p>
192
+ </div>
193
+ ),
194
+ defaultSize: 50,
195
+ header: {
196
+ showSidebarToggle: false,
197
+ showTitle: false,
198
+ },
199
+ },
200
+ ]
201
+
202
+ return (
203
+ <div className="h-screen p-4">
204
+ <SectionLayout
205
+ sections={sections}
206
+ dragHandleColor="primary"
207
+ storageKey="section-layout-primary"
208
+ />
209
+ </div>
210
+ )
211
+ },
212
+ }
213
+
214
+ /**
215
+ * Accent Drag Handles
216
+ *
217
+ * Demonstrates accent colored drag handles.
218
+ */
219
+ export const AccentDragHandles: Story = {
220
+ render: () => {
221
+ const sections = [
222
+ {
223
+ id: 'panel1',
224
+ content: (
225
+ <div className="h-full bg-muted rounded-lg border p-4">
226
+ <h3 className="font-medium mb-2">Panel 1</h3>
227
+ <p className="text-sm text-muted-foreground">Accent drag handles</p>
228
+ </div>
229
+ ),
230
+ defaultSize: 33,
231
+ header: {
232
+ showSidebarToggle: false,
233
+ showTitle: false,
234
+ },
235
+ },
236
+ {
237
+ id: 'panel2',
238
+ content: (
239
+ <div className="h-full bg-muted rounded-lg border p-4">
240
+ <h3 className="font-medium mb-2">Panel 2</h3>
241
+ <p className="text-sm text-muted-foreground">Accent drag handles</p>
242
+ </div>
243
+ ),
244
+ defaultSize: 34,
245
+ header: {
246
+ showSidebarToggle: false,
247
+ showTitle: false,
248
+ },
249
+ },
250
+ {
251
+ id: 'panel3',
252
+ content: (
253
+ <div className="h-full bg-muted rounded-lg border p-4">
254
+ <h3 className="font-medium mb-2">Panel 3</h3>
255
+ <p className="text-sm text-muted-foreground">Accent drag handles</p>
256
+ </div>
257
+ ),
258
+ defaultSize: 33,
259
+ header: {
260
+ showSidebarToggle: false,
261
+ showTitle: false,
262
+ },
263
+ },
264
+ ]
265
+
266
+ return (
267
+ <div className="h-screen p-4">
268
+ <SectionLayout
269
+ sections={sections}
270
+ dragHandleColor="accent"
271
+ storageKey="section-layout-accent"
272
+ />
273
+ </div>
274
+ )
275
+ },
276
+ }