@wakastellar/ui 2.3.4 → 2.4.0

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 (194) hide show
  1. package/dist/blocks/dashboard/index.d.ts +4 -1
  2. package/dist/blocks/empty-states/index.d.ts +4 -1
  3. package/dist/blocks/error-pages/index.d.ts +4 -1
  4. package/dist/blocks/index.d.ts +1 -1
  5. package/dist/blocks/landing/index.d.ts +4 -1
  6. package/dist/blocks/pricing/index.d.ts +5 -1
  7. package/dist/blocks/sidebar/index.d.ts +5 -1
  8. package/dist/index.cjs.js +130 -130
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.es.js +7905 -7856
  11. package/dist/stories/Button.d.ts +14 -0
  12. package/dist/stories/Button.stories.d.ts +8 -0
  13. package/dist/stories/Header.d.ts +11 -0
  14. package/dist/stories/Header.stories.d.ts +6 -0
  15. package/dist/stories/Page.d.ts +2 -0
  16. package/dist/stories/Page.stories.d.ts +6 -0
  17. package/dist/types/index.d.ts +1 -0
  18. package/dist/types/link.d.ts +23 -0
  19. package/package.json +11 -3
  20. package/src/blocks/activity-timeline/ActivityTimeline.stories.tsx +460 -0
  21. package/src/blocks/apm-overview/APMOverview.stories.tsx +435 -0
  22. package/src/blocks/auth-2fa/Auth2FA.stories.tsx +308 -0
  23. package/src/blocks/calendar-view/CalendarView.stories.tsx +398 -0
  24. package/src/blocks/chat/Chat.stories.tsx +466 -0
  25. package/src/blocks/chat-interface/ChatInterface.stories.tsx +412 -0
  26. package/src/blocks/checkout-flow/CheckoutFlow.stories.tsx +408 -0
  27. package/src/blocks/cicd-builder/CICDBuilder.stories.tsx +499 -0
  28. package/src/blocks/cloud-cost-dashboard/CloudCostDashboard.stories.tsx +356 -0
  29. package/src/blocks/container-orchestrator/ContainerOrchestrator.stories.tsx +461 -0
  30. package/src/blocks/dashboard/Dashboard.stories.tsx +559 -0
  31. package/src/blocks/dashboard/index.tsx +68 -27
  32. package/src/blocks/dashboard-kpi/DashboardKPI.stories.tsx +422 -0
  33. package/src/blocks/database-admin/DatabaseAdmin.stories.tsx +393 -0
  34. package/src/blocks/deployment-dashboard/DeploymentDashboard.stories.tsx +457 -0
  35. package/src/blocks/empty-states/EmptyStates.stories.tsx +467 -0
  36. package/src/blocks/empty-states/index.tsx +26 -8
  37. package/src/blocks/error-pages/ErrorPages.stories.tsx +401 -0
  38. package/src/blocks/error-pages/index.tsx +26 -8
  39. package/src/blocks/faq/FAQ.stories.tsx +416 -0
  40. package/src/blocks/file-manager/FileManager.stories.tsx +413 -0
  41. package/src/blocks/footer/Footer.stories.tsx +328 -0
  42. package/src/blocks/gitops-sync-status/GitOpsSyncStatus.stories.tsx +529 -0
  43. package/src/blocks/header/WakaHeader.stories.tsx +455 -0
  44. package/src/blocks/headtab/Headtab.stories.tsx +369 -0
  45. package/src/blocks/i18n-editor/I18nEditor.stories.tsx +451 -0
  46. package/src/blocks/incident-manager/IncidentManager.stories.tsx +464 -0
  47. package/src/blocks/index.ts +1 -1
  48. package/src/blocks/infrastructure-map/InfrastructureMap.stories.tsx +533 -0
  49. package/src/blocks/kanban-board/KanbanBoard.stories.tsx +494 -0
  50. package/src/blocks/landing/WakaLanding.stories.tsx +449 -0
  51. package/src/blocks/landing/index.tsx +125 -66
  52. package/src/blocks/language-selector/LanguageSelector.stories.tsx +345 -0
  53. package/src/blocks/layout/Layout.stories.tsx +373 -0
  54. package/src/blocks/login/Login.stories.tsx +443 -0
  55. package/src/blocks/on-call-schedule/OnCallSchedule.stories.tsx +381 -0
  56. package/src/blocks/player-profile/PlayerProfile.stories.tsx +316 -0
  57. package/src/blocks/pricing/WakaPricing.stories.tsx +530 -0
  58. package/src/blocks/pricing/index.tsx +38 -4
  59. package/src/blocks/profile/Profile.stories.tsx +371 -0
  60. package/src/blocks/release-notes/ReleaseNotes.stories.tsx +431 -0
  61. package/src/blocks/settings/Settings.stories.tsx +520 -0
  62. package/src/blocks/sidebar/WakaSidebar.stories.tsx +513 -0
  63. package/src/blocks/sidebar/index.tsx +49 -20
  64. package/src/blocks/theme-creator-block/ThemeCreatorBlock.stories.tsx +370 -0
  65. package/src/blocks/user-management/UserManagement.stories.tsx +411 -0
  66. package/src/blocks/wizard/Wizard.stories.tsx +683 -0
  67. package/src/components/accordion/Accordion.stories.tsx +93 -0
  68. package/src/components/alert/Alert.stories.tsx +95 -0
  69. package/src/components/alert-dialog/AlertDialog.stories.tsx +126 -0
  70. package/src/components/aspect-ratio/AspectRatio.stories.tsx +118 -0
  71. package/src/components/avatar/Avatar.stories.tsx +104 -0
  72. package/src/components/button/Button.stories.tsx +12 -1
  73. package/src/components/calendar/Calendar.stories.tsx +102 -0
  74. package/src/components/card/Card.stories.tsx +125 -0
  75. package/src/components/checkbox/Checkbox.stories.tsx +100 -0
  76. package/src/components/code/Code.stories.tsx +402 -0
  77. package/src/components/collapsible/Collapsible.stories.tsx +123 -0
  78. package/src/components/command/Command.stories.tsx +207 -0
  79. package/src/components/context-menu/ContextMenu.stories.tsx +220 -0
  80. package/src/components/dialog/Dialog.stories.tsx +157 -0
  81. package/src/components/dropdown-menu/DropdownMenu.stories.tsx +225 -0
  82. package/src/components/form/Form.stories.tsx +413 -0
  83. package/src/components/hover-card/HoverCard.stories.tsx +148 -0
  84. package/src/components/input-otp/InputOTP.stories.tsx +255 -0
  85. package/src/components/label/Label.stories.tsx +68 -0
  86. package/src/components/menubar/Menubar.stories.tsx +278 -0
  87. package/src/components/navigation-menu/NavigationMenu.stories.tsx +202 -0
  88. package/src/components/popover/Popover.stories.tsx +199 -0
  89. package/src/components/progress/Progress.stories.tsx +104 -0
  90. package/src/components/radio-group/RadioGroup.stories.tsx +138 -0
  91. package/src/components/scroll-area/ScrollArea.stories.tsx +153 -0
  92. package/src/components/select/Select.stories.tsx +146 -0
  93. package/src/components/separator/Separator.stories.tsx +117 -0
  94. package/src/components/sheet/Sheet.stories.tsx +195 -0
  95. package/src/components/skeleton/Skeleton.stories.tsx +114 -0
  96. package/src/components/slider/Slider.stories.tsx +157 -0
  97. package/src/components/switch/Switch.stories.tsx +114 -0
  98. package/src/components/table/Table.stories.tsx +153 -0
  99. package/src/components/tabs/Tabs.stories.tsx +155 -0
  100. package/src/components/textarea/Textarea.stories.tsx +116 -0
  101. package/src/components/toast/Toast.stories.tsx +160 -0
  102. package/src/components/toggle/Toggle.stories.tsx +125 -0
  103. package/src/components/tooltip/Tooltip.stories.tsx +133 -0
  104. package/src/components/typography/Typography.stories.tsx +207 -0
  105. package/src/components/waka-3d-pie-chart/Waka3DPieChart.stories.tsx +308 -0
  106. package/src/components/waka-achievement-unlock/WakaAchievementUnlock.stories.tsx +353 -0
  107. package/src/components/waka-artifact-list/WakaArtifactList.stories.tsx +258 -0
  108. package/src/components/waka-autocomplete/WakaAutocomplete.stories.tsx +224 -0
  109. package/src/components/waka-badge-showcase/WakaBadgeShowcase.stories.tsx +269 -0
  110. package/src/components/waka-barcode/WakaBarcode.stories.tsx +227 -0
  111. package/src/components/waka-bottom-sheet/WakaBottomSheet.stories.tsx +408 -0
  112. package/src/components/waka-breadcrumb/WakaBreadcrumb.stories.tsx +237 -0
  113. package/src/components/waka-build-matrix/WakaBuildMatrix.stories.tsx +328 -0
  114. package/src/components/waka-carousel/WakaCarousel.stories.tsx +296 -0
  115. package/src/components/waka-charts/WakaCharts.stories.tsx +519 -0
  116. package/src/components/waka-color-picker/WakaColorPicker.stories.tsx +200 -0
  117. package/src/components/waka-combobox/WakaCombobox.stories.tsx +250 -0
  118. package/src/components/waka-container-list/WakaContainerList.stories.tsx +315 -0
  119. package/src/components/waka-contribution-graph/WakaContributionGraph.stories.tsx +354 -0
  120. package/src/components/waka-cost-breakdown/WakaCostBreakdown.stories.tsx +348 -0
  121. package/src/components/waka-daily-reward/WakaDailyReward.stories.tsx +365 -0
  122. package/src/components/waka-database-card/WakaDatabaseCard.stories.tsx +306 -0
  123. package/src/components/waka-date-range-picker/WakaDateRangePicker.stories.tsx +339 -0
  124. package/src/components/waka-datetime-picker/WakaDateTimePicker.stories.tsx +317 -0
  125. package/src/components/waka-deployment-lane/WakaDeploymentLane.stories.tsx +292 -0
  126. package/src/components/waka-dock/WakaDock.stories.tsx +332 -0
  127. package/src/components/waka-drawer/WakaDrawer.stories.tsx +437 -0
  128. package/src/components/waka-env-var-editor/WakaEnvVarEditor.stories.tsx +263 -0
  129. package/src/components/waka-error-shake/WakaErrorShake.stories.tsx +410 -0
  130. package/src/components/waka-file-upload/WakaFileUpload.stories.tsx +239 -0
  131. package/src/components/waka-flow-diagram/WakaFlowDiagram.stories.tsx +365 -0
  132. package/src/components/waka-funnel-chart/WakaFunnelChart.stories.tsx +281 -0
  133. package/src/components/waka-glow-card/WakaGlowCard.stories.tsx +274 -0
  134. package/src/components/waka-haptic-button/WakaHapticButton.stories.tsx +349 -0
  135. package/src/components/waka-health-pulse/WakaHealthPulse.stories.tsx +293 -0
  136. package/src/components/waka-heatmap/WakaHeatmap.stories.tsx +376 -0
  137. package/src/components/waka-image/WakaImage.stories.tsx +255 -0
  138. package/src/components/waka-incident-timeline/WakaIncidentTimeline.stories.tsx +300 -0
  139. package/src/components/waka-kanban/WakaKanban.stories.tsx +399 -0
  140. package/src/components/waka-kubernetes-overview/WakaKubernetesOverview.stories.tsx +281 -0
  141. package/src/components/waka-leaderboard/WakaLeaderboard.stories.tsx +300 -0
  142. package/src/components/waka-level-progress/WakaLevelProgress.stories.tsx +313 -0
  143. package/src/components/waka-loading-orbit/WakaLoadingOrbit.stories.tsx +413 -0
  144. package/src/components/waka-log-viewer/WakaLogViewer.stories.tsx +312 -0
  145. package/src/components/waka-loot-box/WakaLootBox.stories.tsx +374 -0
  146. package/src/components/waka-metric-sparkline/WakaMetricSparkline.stories.tsx +312 -0
  147. package/src/components/waka-migration-list/WakaMigrationList.stories.tsx +289 -0
  148. package/src/components/waka-modal/WakaModal.stories.tsx +434 -0
  149. package/src/components/waka-morph-button/WakaMorphButton.stories.tsx +405 -0
  150. package/src/components/waka-network-topology/WakaNetworkTopology.stories.tsx +364 -0
  151. package/src/components/waka-notifications/WakaNotifications.stories.tsx +290 -0
  152. package/src/components/waka-number-input/WakaNumberInput.stories.tsx +282 -0
  153. package/src/components/waka-pagination/WakaPagination.stories.tsx +328 -0
  154. package/src/components/waka-password-strength/WakaPasswordStrength.stories.tsx +318 -0
  155. package/src/components/waka-pipeline-view/WakaPipelineView.stories.tsx +386 -0
  156. package/src/components/waka-player-card/WakaPlayerCard.stories.tsx +333 -0
  157. package/src/components/waka-pod-card/WakaPodCard.stories.tsx +435 -0
  158. package/src/components/waka-qrcode/WakaQRCode.stories.tsx +232 -0
  159. package/src/components/waka-query-explain/WakaQueryExplain.stories.tsx +407 -0
  160. package/src/components/waka-quest-card/WakaQuestCard.stories.tsx +394 -0
  161. package/src/components/waka-quota-bar/WakaQuotaBar.stories.tsx +435 -0
  162. package/src/components/waka-radar-score/WakaRadarScore.stories.tsx +372 -0
  163. package/src/components/waka-resource-gauge/WakaResourceGauge.stories.tsx +366 -0
  164. package/src/components/waka-rich-text-editor/WakaRichTextEditor.stories.tsx +238 -0
  165. package/src/components/waka-sankey-diagram/WakaSankeyDiagram.stories.tsx +389 -0
  166. package/src/components/waka-scratch-card/WakaScratchCard.stories.tsx +388 -0
  167. package/src/components/waka-secret-card/WakaSecretCard.stories.tsx +314 -0
  168. package/src/components/waka-segmented-control/WakaSegmentedControl.stories.tsx +309 -0
  169. package/src/components/waka-server-rack/WakaServerRack.stories.tsx +382 -0
  170. package/src/components/waka-service-graph/WakaServiceGraph.stories.tsx +262 -0
  171. package/src/components/waka-skeleton-wave/WakaSkeletonWave.stories.tsx +321 -0
  172. package/src/components/waka-skill-tree/WakaSkillTree.stories.tsx +308 -0
  173. package/src/components/waka-spin-wheel/WakaSpinWheel.stories.tsx +368 -0
  174. package/src/components/waka-spinner/WakaSpinner.stories.tsx +156 -0
  175. package/src/components/waka-stat/WakaStat.stories.tsx +334 -0
  176. package/src/components/waka-status-matrix/WakaStatusMatrix.stories.tsx +331 -0
  177. package/src/components/waka-stepper/WakaStepper.stories.tsx +468 -0
  178. package/src/components/waka-streak-counter/WakaStreakCounter.stories.tsx +235 -0
  179. package/src/components/waka-success-explosion/WakaSuccessExplosion.stories.tsx +389 -0
  180. package/src/components/waka-tabs-morph/WakaTabsMorph.stories.tsx +471 -0
  181. package/src/components/waka-terminal-output/WakaTerminalOutput.stories.tsx +351 -0
  182. package/src/components/waka-test-report/WakaTestReport.stories.tsx +322 -0
  183. package/src/components/waka-tilt-card/WakaTiltCard.stories.tsx +300 -0
  184. package/src/components/waka-time-picker/WakaTimePicker.stories.tsx +227 -0
  185. package/src/components/waka-timeline/WakaTimeline.stories.tsx +383 -0
  186. package/src/components/waka-tournament-bracket/WakaTournamentBracket.stories.tsx +375 -0
  187. package/src/components/waka-trace-viewer/WakaTraceViewer.stories.tsx +445 -0
  188. package/src/components/waka-tree/WakaTree.stories.tsx +359 -0
  189. package/src/components/waka-treemap-chart/WakaTreemapChart.stories.tsx +378 -0
  190. package/src/components/waka-typewriter/WakaTypewriter.stories.tsx +366 -0
  191. package/src/components/waka-versus-card/WakaVersusCard.stories.tsx +530 -0
  192. package/src/components/waka-video/WakaVideo.stories.tsx +203 -0
  193. package/src/components/waka-virtual-list/WakaVirtualList.stories.tsx +273 -0
  194. package/src/components/waka-xp-bar/WakaXPBar.stories.tsx +305 -0
@@ -0,0 +1,365 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { WakaFlowDiagram, useFlowDiagram } from './index'
3
+ import type { FlowNode, FlowConnection } from './index'
4
+ import * as React from 'react'
5
+ import { PlayCircle, CheckCircle2, XCircle, Mail, Database, Code } from 'lucide-react'
6
+
7
+ const basicNodes: FlowNode[] = [
8
+ { id: 'start', type: 'start', label: 'Start', position: { x: 100, y: 200 } },
9
+ { id: 'process1', type: 'process', label: 'Process Data', position: { x: 300, y: 200 } },
10
+ { id: 'decision', type: 'decision', label: 'Valid?', position: { x: 500, y: 200 } },
11
+ { id: 'success', type: 'action', label: 'Save', position: { x: 700, y: 150 } },
12
+ { id: 'error', type: 'action', label: 'Log Error', position: { x: 700, y: 280 } },
13
+ { id: 'end', type: 'end', label: 'End', position: { x: 900, y: 200 } },
14
+ ]
15
+
16
+ const basicConnections: FlowConnection[] = [
17
+ { id: 'conn1', from: 'start', to: 'process1' },
18
+ { id: 'conn2', from: 'process1', to: 'decision' },
19
+ { id: 'conn3', from: 'decision', to: 'success', label: 'Yes' },
20
+ { id: 'conn4', from: 'decision', to: 'error', label: 'No' },
21
+ { id: 'conn5', from: 'success', to: 'end' },
22
+ { id: 'conn6', from: 'error', to: 'end' },
23
+ ]
24
+
25
+ const cicdNodes: FlowNode[] = [
26
+ { id: 'commit', type: 'start', label: 'Git Commit', position: { x: 100, y: 200 }, icon: <Code className="h-4 w-4" /> },
27
+ { id: 'build', type: 'process', label: 'Build', position: { x: 280, y: 200 } },
28
+ { id: 'test', type: 'process', label: 'Run Tests', position: { x: 460, y: 200 } },
29
+ { id: 'testPass', type: 'decision', label: 'Pass?', position: { x: 640, y: 200 } },
30
+ { id: 'deploy', type: 'action', label: 'Deploy', position: { x: 820, y: 150 } },
31
+ { id: 'notify', type: 'action', label: 'Notify', position: { x: 820, y: 280 }, icon: <Mail className="h-4 w-4" /> },
32
+ { id: 'done', type: 'end', label: 'Done', position: { x: 1000, y: 200 } },
33
+ ]
34
+
35
+ const cicdConnections: FlowConnection[] = [
36
+ { id: 'c1', from: 'commit', to: 'build', animated: true },
37
+ { id: 'c2', from: 'build', to: 'test', animated: true },
38
+ { id: 'c3', from: 'test', to: 'testPass', animated: true },
39
+ { id: 'c4', from: 'testPass', to: 'deploy', label: 'Yes', color: '#22c55e' },
40
+ { id: 'c5', from: 'testPass', to: 'notify', label: 'No', color: '#ef4444' },
41
+ { id: 'c6', from: 'deploy', to: 'done' },
42
+ { id: 'c7', from: 'notify', to: 'done' },
43
+ ]
44
+
45
+ const approvalNodes: FlowNode[] = [
46
+ { id: 'submit', type: 'start', label: 'Submit Request', position: { x: 150, y: 200 } },
47
+ { id: 'review', type: 'process', label: 'Manager Review', position: { x: 350, y: 200 } },
48
+ { id: 'approved', type: 'decision', label: 'Approved?', position: { x: 550, y: 200 } },
49
+ { id: 'implement', type: 'action', label: 'Implement', position: { x: 750, y: 100 } },
50
+ { id: 'revise', type: 'action', label: 'Revise', position: { x: 750, y: 300 } },
51
+ { id: 'complete', type: 'end', label: 'Complete', position: { x: 950, y: 200 } },
52
+ ]
53
+
54
+ const approvalConnections: FlowConnection[] = [
55
+ { id: 'a1', from: 'submit', to: 'review' },
56
+ { id: 'a2', from: 'review', to: 'approved' },
57
+ { id: 'a3', from: 'approved', to: 'implement', label: 'Yes', color: '#22c55e' },
58
+ { id: 'a4', from: 'approved', to: 'revise', label: 'No', color: '#f59e0b' },
59
+ { id: 'a5', from: 'implement', to: 'complete' },
60
+ { id: 'a6', from: 'revise', to: 'review', label: 'Resubmit' },
61
+ ]
62
+
63
+ const meta: Meta<typeof WakaFlowDiagram> = {
64
+ title: 'Components/Charts/WakaFlowDiagram',
65
+ component: WakaFlowDiagram,
66
+ parameters: {
67
+ layout: 'centered',
68
+ docs: {
69
+ description: {
70
+ component: 'A flow diagram component for visualizing processes, workflows, and decision trees with draggable nodes and customizable connections.',
71
+ },
72
+ },
73
+ },
74
+ tags: ['autodocs'],
75
+ argTypes: {
76
+ draggable: {
77
+ control: 'boolean',
78
+ description: 'Enable node dragging',
79
+ },
80
+ editable: {
81
+ control: 'boolean',
82
+ description: 'Enable editing (add/remove nodes)',
83
+ },
84
+ zoom: {
85
+ control: { type: 'range', min: 0.5, max: 2, step: 0.1 },
86
+ description: 'Zoom level',
87
+ },
88
+ gridSize: {
89
+ control: { type: 'range', min: 10, max: 50, step: 5 },
90
+ description: 'Grid size for snapping',
91
+ },
92
+ showGrid: {
93
+ control: 'boolean',
94
+ description: 'Show grid background',
95
+ },
96
+ },
97
+ }
98
+
99
+ export default meta
100
+ type Story = StoryObj<typeof WakaFlowDiagram>
101
+
102
+ export const Default: Story = {
103
+ args: {
104
+ nodes: basicNodes,
105
+ connections: basicConnections,
106
+ },
107
+ render: (args) => (
108
+ <div className="w-[1000px] h-[400px]">
109
+ <WakaFlowDiagram {...args} />
110
+ </div>
111
+ ),
112
+ }
113
+
114
+ export const CICDPipeline: Story = {
115
+ render: () => (
116
+ <div className="w-[1100px] h-[400px]">
117
+ <WakaFlowDiagram
118
+ nodes={cicdNodes}
119
+ connections={cicdConnections}
120
+ />
121
+ </div>
122
+ ),
123
+ }
124
+
125
+ export const ApprovalWorkflow: Story = {
126
+ render: () => (
127
+ <div className="w-[1100px] h-[450px]">
128
+ <WakaFlowDiagram
129
+ nodes={approvalNodes}
130
+ connections={approvalConnections}
131
+ />
132
+ </div>
133
+ ),
134
+ }
135
+
136
+ export const NoDragging: Story = {
137
+ render: () => (
138
+ <div className="w-[1000px] h-[400px]">
139
+ <WakaFlowDiagram
140
+ nodes={basicNodes}
141
+ connections={basicConnections}
142
+ draggable={false}
143
+ />
144
+ </div>
145
+ ),
146
+ }
147
+
148
+ export const NoEditing: Story = {
149
+ render: () => (
150
+ <div className="w-[1000px] h-[400px]">
151
+ <WakaFlowDiagram
152
+ nodes={basicNodes}
153
+ connections={basicConnections}
154
+ editable={false}
155
+ />
156
+ </div>
157
+ ),
158
+ }
159
+
160
+ export const NoGrid: Story = {
161
+ render: () => (
162
+ <div className="w-[1000px] h-[400px]">
163
+ <WakaFlowDiagram
164
+ nodes={basicNodes}
165
+ connections={basicConnections}
166
+ showGrid={false}
167
+ />
168
+ </div>
169
+ ),
170
+ }
171
+
172
+ export const ZoomLevels: Story = {
173
+ render: () => (
174
+ <div className="space-y-8">
175
+ <div>
176
+ <p className="text-sm text-muted-foreground mb-2">Zoom: 0.75x</p>
177
+ <div className="w-[800px] h-[300px] border rounded">
178
+ <WakaFlowDiagram
179
+ nodes={basicNodes}
180
+ connections={basicConnections}
181
+ zoom={0.75}
182
+ editable={false}
183
+ />
184
+ </div>
185
+ </div>
186
+ <div>
187
+ <p className="text-sm text-muted-foreground mb-2">Zoom: 1.25x</p>
188
+ <div className="w-[800px] h-[400px] border rounded overflow-hidden">
189
+ <WakaFlowDiagram
190
+ nodes={basicNodes}
191
+ connections={basicConnections}
192
+ zoom={1.25}
193
+ editable={false}
194
+ />
195
+ </div>
196
+ </div>
197
+ </div>
198
+ ),
199
+ }
200
+
201
+ export const GridSizes: Story = {
202
+ render: () => (
203
+ <div className="space-y-8">
204
+ <div>
205
+ <p className="text-sm text-muted-foreground mb-2">Grid: 10px (fine)</p>
206
+ <div className="w-[600px] h-[250px]">
207
+ <WakaFlowDiagram
208
+ nodes={basicNodes.slice(0, 3)}
209
+ connections={basicConnections.slice(0, 2)}
210
+ gridSize={10}
211
+ editable={false}
212
+ />
213
+ </div>
214
+ </div>
215
+ <div>
216
+ <p className="text-sm text-muted-foreground mb-2">Grid: 40px (coarse)</p>
217
+ <div className="w-[600px] h-[250px]">
218
+ <WakaFlowDiagram
219
+ nodes={basicNodes.slice(0, 3)}
220
+ connections={basicConnections.slice(0, 2)}
221
+ gridSize={40}
222
+ editable={false}
223
+ />
224
+ </div>
225
+ </div>
226
+ </div>
227
+ ),
228
+ }
229
+
230
+ export const WithHook: Story = {
231
+ render: () => {
232
+ const { nodes, connections, addNode, addConnection, removeNode, clear } = useFlowDiagram(
233
+ basicNodes.slice(0, 3),
234
+ basicConnections.slice(0, 2)
235
+ )
236
+
237
+ return (
238
+ <div className="space-y-4">
239
+ <div className="flex gap-2 flex-wrap">
240
+ <button
241
+ onClick={() => {
242
+ const newNode = addNode({
243
+ type: 'action',
244
+ label: `Action ${nodes.length + 1}`,
245
+ position: { x: 200 + nodes.length * 100, y: 100 + Math.random() * 200 },
246
+ })
247
+ }}
248
+ className="px-3 py-1 text-sm border rounded hover:bg-muted"
249
+ >
250
+ Add Action Node
251
+ </button>
252
+ <button
253
+ onClick={() => {
254
+ addNode({
255
+ type: 'decision',
256
+ label: `Decision ${nodes.length + 1}`,
257
+ position: { x: 300 + nodes.length * 80, y: 150 + Math.random() * 150 },
258
+ })
259
+ }}
260
+ className="px-3 py-1 text-sm border rounded hover:bg-muted"
261
+ >
262
+ Add Decision Node
263
+ </button>
264
+ <button
265
+ onClick={clear}
266
+ className="px-3 py-1 text-sm border rounded hover:bg-muted text-red-600"
267
+ >
268
+ Clear All
269
+ </button>
270
+ </div>
271
+ <div className="w-[900px] h-[400px]">
272
+ <WakaFlowDiagram
273
+ nodes={nodes}
274
+ connections={connections}
275
+ onNodesChange={(n) => console.log('Nodes changed:', n)}
276
+ onConnectionsChange={(c) => console.log('Connections changed:', c)}
277
+ />
278
+ </div>
279
+ <p className="text-sm text-muted-foreground">
280
+ Nodes: {nodes.length} | Connections: {connections.length}
281
+ </p>
282
+ </div>
283
+ )
284
+ },
285
+ }
286
+
287
+ export const Interactive: Story = {
288
+ render: () => {
289
+ const [selectedNode, setSelectedNode] = React.useState<FlowNode | null>(null)
290
+
291
+ return (
292
+ <div className="space-y-4">
293
+ <div className="w-[1000px] h-[400px]">
294
+ <WakaFlowDiagram
295
+ nodes={cicdNodes}
296
+ connections={cicdConnections}
297
+ onNodeClick={(node) => setSelectedNode(node)}
298
+ />
299
+ </div>
300
+ {selectedNode && (
301
+ <div className="p-4 border rounded-lg bg-muted/50">
302
+ <h4 className="font-semibold">{selectedNode.label}</h4>
303
+ <p className="text-sm text-muted-foreground">Type: {selectedNode.type}</p>
304
+ <p className="text-sm text-muted-foreground">
305
+ Position: ({selectedNode.position.x}, {selectedNode.position.y})
306
+ </p>
307
+ {selectedNode.description && (
308
+ <p className="text-sm mt-2">{selectedNode.description}</p>
309
+ )}
310
+ </div>
311
+ )}
312
+ </div>
313
+ )
314
+ },
315
+ }
316
+
317
+ export const PipelineDashboard: Story = {
318
+ render: () => (
319
+ <div className="w-[1150px] p-6 border rounded-lg">
320
+ <div className="flex justify-between items-start mb-4">
321
+ <div>
322
+ <h3 className="text-xl font-semibold">CI/CD Pipeline</h3>
323
+ <p className="text-sm text-muted-foreground">main branch • Last run: 2 minutes ago</p>
324
+ </div>
325
+ <div className="flex items-center gap-2">
326
+ <div className="w-3 h-3 rounded-full bg-green-500 animate-pulse" />
327
+ <span className="text-sm text-green-600 font-medium">Running</span>
328
+ </div>
329
+ </div>
330
+ <div className="h-[350px]">
331
+ <WakaFlowDiagram
332
+ nodes={cicdNodes}
333
+ connections={cicdConnections}
334
+ editable={false}
335
+ draggable={false}
336
+ />
337
+ </div>
338
+ </div>
339
+ ),
340
+ }
341
+
342
+ export const NodeTypes: Story = {
343
+ render: () => {
344
+ const typeNodes: FlowNode[] = [
345
+ { id: 'start', type: 'start', label: 'Start', position: { x: 100, y: 100 } },
346
+ { id: 'end', type: 'end', label: 'End', position: { x: 300, y: 100 } },
347
+ { id: 'action', type: 'action', label: 'Action', position: { x: 100, y: 220 } },
348
+ { id: 'process', type: 'process', label: 'Process', position: { x: 300, y: 220 } },
349
+ { id: 'decision', type: 'decision', label: 'Decision', position: { x: 200, y: 340 } },
350
+ ]
351
+
352
+ return (
353
+ <div className="space-y-4">
354
+ <p className="text-sm text-muted-foreground">Available node types:</p>
355
+ <div className="w-[500px] h-[450px]">
356
+ <WakaFlowDiagram
357
+ nodes={typeNodes}
358
+ connections={[]}
359
+ editable={false}
360
+ />
361
+ </div>
362
+ </div>
363
+ )
364
+ },
365
+ }
@@ -0,0 +1,281 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { WakaFunnelChart, useFunnelChart } from './index'
3
+ import type { FunnelStage } from './index'
4
+ import * as React from 'react'
5
+
6
+ const conversionData: FunnelStage[] = [
7
+ { id: 'visitors', label: 'Visitors', value: 10000 },
8
+ { id: 'signups', label: 'Sign Ups', value: 4500 },
9
+ { id: 'trials', label: 'Free Trials', value: 2000 },
10
+ { id: 'purchases', label: 'Purchases', value: 800 },
11
+ { id: 'retention', label: 'Retained', value: 600 },
12
+ ]
13
+
14
+ const salesPipelineData: FunnelStage[] = [
15
+ { id: 'leads', label: 'Leads', value: 5000, color: '#3b82f6' },
16
+ { id: 'qualified', label: 'Qualified', value: 2500, color: '#8b5cf6' },
17
+ { id: 'proposals', label: 'Proposals', value: 1200, color: '#ec4899' },
18
+ { id: 'negotiations', label: 'Negotiations', value: 600, color: '#f59e0b' },
19
+ { id: 'closed', label: 'Closed Won', value: 300, color: '#22c55e' },
20
+ ]
21
+
22
+ const recruitmentData: FunnelStage[] = [
23
+ { id: 'applications', label: 'Applications', value: 1000 },
24
+ { id: 'screening', label: 'Phone Screening', value: 350 },
25
+ { id: 'interviews', label: 'Interviews', value: 120 },
26
+ { id: 'offers', label: 'Offers Made', value: 40 },
27
+ { id: 'hired', label: 'Hired', value: 25 },
28
+ ]
29
+
30
+ const meta: Meta<typeof WakaFunnelChart> = {
31
+ title: 'Components/Charts/WakaFunnelChart',
32
+ component: WakaFunnelChart,
33
+ parameters: {
34
+ layout: 'centered',
35
+ docs: {
36
+ description: {
37
+ component: 'A funnel chart for visualizing conversion rates and process flows with smooth transitions between stages.',
38
+ },
39
+ },
40
+ },
41
+ tags: ['autodocs'],
42
+ argTypes: {
43
+ orientation: {
44
+ control: 'select',
45
+ options: ['vertical', 'horizontal'],
46
+ description: 'Funnel orientation',
47
+ },
48
+ showLabels: {
49
+ control: 'boolean',
50
+ description: 'Show stage labels',
51
+ },
52
+ showValues: {
53
+ control: 'boolean',
54
+ description: 'Show stage values',
55
+ },
56
+ showPercentages: {
57
+ control: 'boolean',
58
+ description: 'Show conversion percentages',
59
+ },
60
+ animated: {
61
+ control: 'boolean',
62
+ description: 'Enable animations',
63
+ },
64
+ curved: {
65
+ control: 'boolean',
66
+ description: 'Use curved edges',
67
+ },
68
+ },
69
+ }
70
+
71
+ export default meta
72
+ type Story = StoryObj<typeof WakaFunnelChart>
73
+
74
+ export const Default: Story = {
75
+ args: {
76
+ data: conversionData,
77
+ },
78
+ render: (args) => <WakaFunnelChart {...args} />,
79
+ }
80
+
81
+ export const Orientations: Story = {
82
+ render: () => (
83
+ <div className="space-y-8">
84
+ <div>
85
+ <p className="text-sm text-muted-foreground mb-2">Vertical (Default)</p>
86
+ <WakaFunnelChart data={conversionData} orientation="vertical" width={400} height={300} />
87
+ </div>
88
+ <div>
89
+ <p className="text-sm text-muted-foreground mb-2">Horizontal</p>
90
+ <WakaFunnelChart data={conversionData} orientation="horizontal" width={600} height={200} />
91
+ </div>
92
+ </div>
93
+ ),
94
+ }
95
+
96
+ export const WithCustomColors: Story = {
97
+ render: () => <WakaFunnelChart data={salesPipelineData} width={400} height={350} />,
98
+ }
99
+
100
+ export const CurvedEdges: Story = {
101
+ render: () => (
102
+ <div className="flex gap-8">
103
+ <div className="text-center">
104
+ <WakaFunnelChart data={conversionData} curved={false} width={300} height={280} />
105
+ <p className="text-sm text-muted-foreground mt-2">Sharp Edges</p>
106
+ </div>
107
+ <div className="text-center">
108
+ <WakaFunnelChart data={conversionData} curved width={300} height={280} />
109
+ <p className="text-sm text-muted-foreground mt-2">Curved Edges</p>
110
+ </div>
111
+ </div>
112
+ ),
113
+ }
114
+
115
+ export const ShowPercentages: Story = {
116
+ render: () => (
117
+ <WakaFunnelChart
118
+ data={conversionData}
119
+ showPercentages
120
+ width={450}
121
+ height={350}
122
+ />
123
+ ),
124
+ }
125
+
126
+ export const HideLabels: Story = {
127
+ render: () => (
128
+ <div className="flex gap-8">
129
+ <div className="text-center">
130
+ <WakaFunnelChart data={conversionData} showLabels={false} width={250} height={250} />
131
+ <p className="text-sm text-muted-foreground mt-2">No Labels</p>
132
+ </div>
133
+ <div className="text-center">
134
+ <WakaFunnelChart data={conversionData} showValues={false} width={250} height={250} />
135
+ <p className="text-sm text-muted-foreground mt-2">No Values</p>
136
+ </div>
137
+ </div>
138
+ ),
139
+ }
140
+
141
+ export const Sizes: Story = {
142
+ render: () => (
143
+ <div className="flex items-end gap-8">
144
+ <div className="text-center">
145
+ <WakaFunnelChart data={conversionData} width={200} height={180} />
146
+ <p className="text-sm text-muted-foreground mt-2">Small</p>
147
+ </div>
148
+ <div className="text-center">
149
+ <WakaFunnelChart data={conversionData} width={350} height={300} />
150
+ <p className="text-sm text-muted-foreground mt-2">Medium</p>
151
+ </div>
152
+ <div className="text-center">
153
+ <WakaFunnelChart data={conversionData} width={500} height={400} />
154
+ <p className="text-sm text-muted-foreground mt-2">Large</p>
155
+ </div>
156
+ </div>
157
+ ),
158
+ }
159
+
160
+ export const Interactive: Story = {
161
+ render: () => {
162
+ const [selectedStage, setSelectedStage] = React.useState<FunnelStage | null>(null)
163
+
164
+ return (
165
+ <div className="space-y-4">
166
+ <WakaFunnelChart
167
+ data={salesPipelineData}
168
+ width={450}
169
+ height={350}
170
+ onStageClick={(stage) => setSelectedStage(stage)}
171
+ showPercentages
172
+ />
173
+ {selectedStage && (
174
+ <div className="p-4 border rounded-lg bg-muted/50">
175
+ <h4 className="font-semibold">{selectedStage.label}</h4>
176
+ <p className="text-2xl font-bold text-primary">{selectedStage.value.toLocaleString()}</p>
177
+ <p className="text-sm text-muted-foreground">
178
+ {((selectedStage.value / salesPipelineData[0].value) * 100).toFixed(1)}% of total leads
179
+ </p>
180
+ </div>
181
+ )}
182
+ </div>
183
+ )
184
+ },
185
+ }
186
+
187
+ export const WithHook: Story = {
188
+ render: () => {
189
+ const { highlightedStage, setHighlightedStage, reset, getConversionRate } = useFunnelChart()
190
+
191
+ return (
192
+ <div className="space-y-4">
193
+ <div className="flex gap-2 flex-wrap">
194
+ {conversionData.map((stage, index) => (
195
+ <button
196
+ key={stage.id}
197
+ onClick={() => setHighlightedStage(stage.id)}
198
+ className={`px-3 py-1 text-sm border rounded transition-colors ${
199
+ highlightedStage === stage.id ? 'bg-primary text-primary-foreground' : 'hover:bg-muted'
200
+ }`}
201
+ >
202
+ {stage.label}
203
+ </button>
204
+ ))}
205
+ <button onClick={reset} className="px-3 py-1 text-sm border rounded hover:bg-muted">
206
+ Reset
207
+ </button>
208
+ </div>
209
+ <WakaFunnelChart data={conversionData} width={400} height={300} />
210
+ <div className="grid grid-cols-2 gap-4 text-sm">
211
+ {conversionData.slice(1).map((stage, index) => (
212
+ <div key={stage.id} className="p-2 bg-muted/30 rounded">
213
+ <span className="text-muted-foreground">
214
+ {conversionData[index].label} → {stage.label}:
215
+ </span>{' '}
216
+ <span className="font-semibold">
217
+ {getConversionRate(conversionData[index].value, stage.value)}%
218
+ </span>
219
+ </div>
220
+ ))}
221
+ </div>
222
+ </div>
223
+ )
224
+ },
225
+ }
226
+
227
+ export const RecruitmentFunnel: Story = {
228
+ render: () => (
229
+ <div className="w-[500px] p-6 border rounded-lg">
230
+ <h3 className="text-lg font-semibold mb-1">Recruitment Pipeline</h3>
231
+ <p className="text-sm text-muted-foreground mb-4">Q4 2024 Hiring Campaign</p>
232
+ <WakaFunnelChart
233
+ data={recruitmentData}
234
+ width={450}
235
+ height={350}
236
+ showPercentages
237
+ curved
238
+ />
239
+ </div>
240
+ ),
241
+ }
242
+
243
+ export const CompactFunnel: Story = {
244
+ render: () => (
245
+ <div className="flex gap-6">
246
+ <div className="p-4 border rounded-lg">
247
+ <h4 className="text-sm font-medium mb-2">Marketing Funnel</h4>
248
+ <WakaFunnelChart
249
+ data={conversionData.slice(0, 3)}
250
+ width={180}
251
+ height={150}
252
+ showLabels={false}
253
+ />
254
+ </div>
255
+ <div className="p-4 border rounded-lg">
256
+ <h4 className="text-sm font-medium mb-2">Sales Funnel</h4>
257
+ <WakaFunnelChart
258
+ data={salesPipelineData.slice(0, 3)}
259
+ width={180}
260
+ height={150}
261
+ showLabels={false}
262
+ />
263
+ </div>
264
+ <div className="p-4 border rounded-lg">
265
+ <h4 className="text-sm font-medium mb-2">Hiring Funnel</h4>
266
+ <WakaFunnelChart
267
+ data={recruitmentData.slice(0, 3)}
268
+ width={180}
269
+ height={150}
270
+ showLabels={false}
271
+ />
272
+ </div>
273
+ </div>
274
+ ),
275
+ }
276
+
277
+ export const NoAnimation: Story = {
278
+ render: () => (
279
+ <WakaFunnelChart data={conversionData} animated={false} width={400} height={300} />
280
+ ),
281
+ }