@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,293 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { WakaHealthPulse } from './index'
3
+ import type { HealthStatus } from './index'
4
+ import * as React from 'react'
5
+
6
+ const meta: Meta<typeof WakaHealthPulse> = {
7
+ title: 'Components/DevOps/WakaHealthPulse',
8
+ component: WakaHealthPulse,
9
+ parameters: {
10
+ layout: 'centered',
11
+ docs: {
12
+ description: {
13
+ component: 'An ECG-style health pulse visualization with status-specific patterns, animated waveforms, and metric display.',
14
+ },
15
+ },
16
+ },
17
+ tags: ['autodocs'],
18
+ argTypes: {
19
+ status: {
20
+ control: 'select',
21
+ options: ['healthy', 'warning', 'critical', 'down', 'unknown'],
22
+ description: 'Health status of the service',
23
+ },
24
+ size: {
25
+ control: 'select',
26
+ options: ['sm', 'md', 'lg'],
27
+ description: 'Size variant',
28
+ },
29
+ pulseRate: {
30
+ control: { type: 'number', min: 20, max: 120, step: 5 },
31
+ description: 'Pulse rate in beats per minute',
32
+ },
33
+ showValue: {
34
+ control: 'boolean',
35
+ description: 'Show the metric value',
36
+ },
37
+ animated: {
38
+ control: 'boolean',
39
+ description: 'Enable animations',
40
+ },
41
+ },
42
+ }
43
+
44
+ export default meta
45
+ type Story = StoryObj<typeof WakaHealthPulse>
46
+
47
+ export const Default: Story = {
48
+ args: {
49
+ status: 'healthy',
50
+ value: 245,
51
+ unit: 'req/s',
52
+ label: 'API Server',
53
+ pulseRate: 60,
54
+ },
55
+ }
56
+
57
+ export const AllStatuses: Story = {
58
+ render: () => {
59
+ const statuses: Array<{ status: HealthStatus; value: number; unit: string }> = [
60
+ { status: 'healthy', value: 245, unit: 'req/s' },
61
+ { status: 'warning', value: 89, unit: 'ms' },
62
+ { status: 'critical', value: 523, unit: 'ms' },
63
+ { status: 'down', value: 0, unit: 'req/s' },
64
+ { status: 'unknown', value: 42, unit: '?' },
65
+ ]
66
+
67
+ return (
68
+ <div className="space-y-4">
69
+ {statuses.map(({ status, value, unit }) => (
70
+ <WakaHealthPulse
71
+ key={status}
72
+ status={status}
73
+ value={value}
74
+ unit={unit}
75
+ label={`Service (${status})`}
76
+ pulseRate={status === 'down' ? 0 : status === 'critical' ? 120 : 60}
77
+ />
78
+ ))}
79
+ </div>
80
+ )
81
+ },
82
+ }
83
+
84
+ export const Sizes: Story = {
85
+ render: () => (
86
+ <div className="space-y-4">
87
+ <div>
88
+ <p className="text-sm text-muted-foreground mb-2">Small</p>
89
+ <WakaHealthPulse
90
+ status="healthy"
91
+ value={120}
92
+ unit="ms"
93
+ label="Response Time"
94
+ size="sm"
95
+ />
96
+ </div>
97
+ <div>
98
+ <p className="text-sm text-muted-foreground mb-2">Medium (Default)</p>
99
+ <WakaHealthPulse
100
+ status="healthy"
101
+ value={120}
102
+ unit="ms"
103
+ label="Response Time"
104
+ size="md"
105
+ />
106
+ </div>
107
+ <div>
108
+ <p className="text-sm text-muted-foreground mb-2">Large</p>
109
+ <WakaHealthPulse
110
+ status="healthy"
111
+ value={120}
112
+ unit="ms"
113
+ label="Response Time"
114
+ size="lg"
115
+ />
116
+ </div>
117
+ </div>
118
+ ),
119
+ }
120
+
121
+ export const PulseRates: Story = {
122
+ render: () => (
123
+ <div className="space-y-4">
124
+ <div>
125
+ <p className="text-sm text-muted-foreground mb-2">Slow (30 BPM)</p>
126
+ <WakaHealthPulse
127
+ status="healthy"
128
+ value={99.9}
129
+ unit="%"
130
+ label="Uptime"
131
+ pulseRate={30}
132
+ />
133
+ </div>
134
+ <div>
135
+ <p className="text-sm text-muted-foreground mb-2">Normal (60 BPM)</p>
136
+ <WakaHealthPulse
137
+ status="healthy"
138
+ value={245}
139
+ unit="req/s"
140
+ label="Throughput"
141
+ pulseRate={60}
142
+ />
143
+ </div>
144
+ <div>
145
+ <p className="text-sm text-muted-foreground mb-2">Fast (120 BPM)</p>
146
+ <WakaHealthPulse
147
+ status="critical"
148
+ value={2340}
149
+ unit="ms"
150
+ label="Latency"
151
+ pulseRate={120}
152
+ />
153
+ </div>
154
+ </div>
155
+ ),
156
+ }
157
+
158
+ export const NoValue: Story = {
159
+ render: () => (
160
+ <WakaHealthPulse
161
+ status="healthy"
162
+ label="Database Connection"
163
+ showValue={false}
164
+ />
165
+ ),
166
+ }
167
+
168
+ export const NoAnimation: Story = {
169
+ render: () => (
170
+ <WakaHealthPulse
171
+ status="healthy"
172
+ value={245}
173
+ unit="req/s"
174
+ label="Static Display"
175
+ animated={false}
176
+ />
177
+ ),
178
+ }
179
+
180
+ export const CustomColors: Story = {
181
+ render: () => (
182
+ <WakaHealthPulse
183
+ status="healthy"
184
+ value={100}
185
+ unit="%"
186
+ label="Custom Colors"
187
+ colors={{
188
+ healthy: '#06b6d4', // cyan
189
+ warning: '#f97316', // orange
190
+ critical: '#dc2626', // red
191
+ }}
192
+ />
193
+ ),
194
+ }
195
+
196
+ export const ServiceDashboard: Story = {
197
+ render: () => {
198
+ const [services] = React.useState([
199
+ { id: 'api', label: 'API Server', status: 'healthy' as const, value: 245, unit: 'req/s', pulseRate: 60 },
200
+ { id: 'db', label: 'Database', status: 'healthy' as const, value: 23, unit: 'ms', pulseRate: 45 },
201
+ { id: 'cache', label: 'Redis Cache', status: 'warning' as const, value: 89, unit: '%', pulseRate: 80 },
202
+ { id: 'queue', label: 'Message Queue', status: 'critical' as const, value: 1523, unit: 'pending', pulseRate: 100 },
203
+ { id: 'storage', label: 'Object Storage', status: 'down' as const, value: 0, unit: 'req/s', pulseRate: 0 },
204
+ { id: 'cdn', label: 'CDN', status: 'healthy' as const, value: 12, unit: 'ms', pulseRate: 50 },
205
+ ])
206
+
207
+ const healthyCount = services.filter(s => s.status === 'healthy').length
208
+ const warningCount = services.filter(s => s.status === 'warning').length
209
+ const criticalCount = services.filter(s => s.status === 'critical').length
210
+ const downCount = services.filter(s => s.status === 'down').length
211
+
212
+ return (
213
+ <div className="p-6 rounded-xl border bg-card">
214
+ <div className="flex justify-between items-center mb-6">
215
+ <h2 className="text-xl font-bold">Service Health</h2>
216
+ <div className="flex gap-4 text-sm">
217
+ <span className="text-green-500">● {healthyCount} Healthy</span>
218
+ <span className="text-yellow-500">● {warningCount} Warning</span>
219
+ <span className="text-red-500">● {criticalCount} Critical</span>
220
+ <span className="text-gray-500">● {downCount} Down</span>
221
+ </div>
222
+ </div>
223
+
224
+ <div className="grid grid-cols-2 gap-4">
225
+ {services.map((service) => (
226
+ <WakaHealthPulse
227
+ key={service.id}
228
+ status={service.status}
229
+ value={service.value}
230
+ unit={service.unit}
231
+ label={service.label}
232
+ pulseRate={service.pulseRate}
233
+ size="md"
234
+ />
235
+ ))}
236
+ </div>
237
+ </div>
238
+ )
239
+ },
240
+ }
241
+
242
+ export const LiveMetrics: Story = {
243
+ render: () => {
244
+ const [value, setValue] = React.useState(245)
245
+ const [status, setStatus] = React.useState<HealthStatus>('healthy')
246
+
247
+ React.useEffect(() => {
248
+ const interval = setInterval(() => {
249
+ const newValue = Math.floor(Math.random() * 100) + 200
250
+ setValue(newValue)
251
+
252
+ if (newValue > 280) {
253
+ setStatus('warning')
254
+ } else if (newValue < 220) {
255
+ setStatus('critical')
256
+ } else {
257
+ setStatus('healthy')
258
+ }
259
+ }, 2000)
260
+
261
+ return () => clearInterval(interval)
262
+ }, [])
263
+
264
+ return (
265
+ <div className="space-y-4">
266
+ <p className="text-sm text-muted-foreground">
267
+ Live updating metrics (simulated)
268
+ </p>
269
+ <WakaHealthPulse
270
+ status={status}
271
+ value={value}
272
+ unit="req/s"
273
+ label="API Throughput"
274
+ pulseRate={status === 'critical' ? 100 : status === 'warning' ? 80 : 60}
275
+ size="lg"
276
+ />
277
+ </div>
278
+ )
279
+ },
280
+ }
281
+
282
+ export const CompactGrid: Story = {
283
+ render: () => (
284
+ <div className="grid grid-cols-3 gap-2">
285
+ <WakaHealthPulse status="healthy" value={99.9} unit="%" label="Uptime" size="sm" />
286
+ <WakaHealthPulse status="healthy" value={23} unit="ms" label="Latency" size="sm" />
287
+ <WakaHealthPulse status="warning" value={85} unit="%" label="CPU" size="sm" />
288
+ <WakaHealthPulse status="healthy" value={64} unit="%" label="Memory" size="sm" />
289
+ <WakaHealthPulse status="healthy" value={245} unit="req/s" label="Requests" size="sm" />
290
+ <WakaHealthPulse status="critical" value={92} unit="%" label="Disk" size="sm" />
291
+ </div>
292
+ ),
293
+ }
@@ -0,0 +1,376 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { WakaHeatmap, useHeatmap } from './index'
3
+ import type { HeatmapData, HeatmapSelection } from './index'
4
+ import * as React from 'react'
5
+
6
+ // Generate sample data
7
+ function generateHeatmapData(rows: number, cols: number, pattern: 'random' | 'gradient' | 'checkerboard' = 'random'): HeatmapData {
8
+ const values: number[][] = []
9
+ const rowLabels: string[] = []
10
+ const columnLabels: string[] = []
11
+
12
+ for (let r = 0; r < rows; r++) {
13
+ rowLabels.push(`Row ${r + 1}`)
14
+ const row: number[] = []
15
+ for (let c = 0; c < cols; c++) {
16
+ if (r === 0) columnLabels.push(`Col ${c + 1}`)
17
+
18
+ let value: number
19
+ switch (pattern) {
20
+ case 'gradient':
21
+ value = (r + c) / (rows + cols - 2)
22
+ break
23
+ case 'checkerboard':
24
+ value = (r + c) % 2 === 0 ? 0.8 : 0.2
25
+ break
26
+ default:
27
+ value = Math.random()
28
+ }
29
+ row.push(value)
30
+ }
31
+ values.push(row)
32
+ }
33
+
34
+ return { values, rowLabels, columnLabels }
35
+ }
36
+
37
+ // Weekly activity data (hours worked per day)
38
+ const weeklyActivityData: HeatmapData = {
39
+ values: [
40
+ [8, 7, 6, 8, 7, 2, 0],
41
+ [7, 8, 9, 7, 8, 4, 1],
42
+ [6, 7, 8, 8, 6, 3, 0],
43
+ [9, 8, 7, 9, 8, 5, 2],
44
+ [7, 6, 8, 7, 7, 3, 1],
45
+ ],
46
+ rowLabels: ['Week 1', 'Week 2', 'Week 3', 'Week 4', 'Week 5'],
47
+ columnLabels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
48
+ }
49
+
50
+ // Correlation matrix
51
+ const correlationData: HeatmapData = {
52
+ values: [
53
+ [1.0, 0.8, 0.2, -0.3, 0.5],
54
+ [0.8, 1.0, 0.1, -0.5, 0.6],
55
+ [0.2, 0.1, 1.0, 0.4, -0.2],
56
+ [-0.3, -0.5, 0.4, 1.0, -0.1],
57
+ [0.5, 0.6, -0.2, -0.1, 1.0],
58
+ ],
59
+ rowLabels: ['Revenue', 'Users', 'Bounce Rate', 'Load Time', 'Conversions'],
60
+ columnLabels: ['Revenue', 'Users', 'Bounce Rate', 'Load Time', 'Conversions'],
61
+ }
62
+
63
+ const meta: Meta<typeof WakaHeatmap> = {
64
+ title: 'Components/Charts/WakaHeatmap',
65
+ component: WakaHeatmap,
66
+ parameters: {
67
+ layout: 'centered',
68
+ docs: {
69
+ description: {
70
+ component: 'An interactive heatmap component with multiple color schemes, zoom/pan controls, tooltips, and export functionality.',
71
+ },
72
+ },
73
+ },
74
+ tags: ['autodocs'],
75
+ argTypes: {
76
+ colorSchemeName: {
77
+ control: 'select',
78
+ options: ['blues', 'greens', 'reds', 'viridis', 'plasma', 'coolwarm', 'rdylgn'],
79
+ description: 'Predefined color scheme',
80
+ },
81
+ cellSize: {
82
+ control: { type: 'range', min: 12, max: 48, step: 4 },
83
+ description: 'Cell size in pixels',
84
+ },
85
+ cellGap: {
86
+ control: { type: 'range', min: 0, max: 8, step: 1 },
87
+ description: 'Gap between cells',
88
+ },
89
+ showRowLabels: {
90
+ control: 'boolean',
91
+ description: 'Show row labels',
92
+ },
93
+ showColumnLabels: {
94
+ control: 'boolean',
95
+ description: 'Show column labels',
96
+ },
97
+ showLegend: {
98
+ control: 'boolean',
99
+ description: 'Show color legend',
100
+ },
101
+ enableZoom: {
102
+ control: 'boolean',
103
+ description: 'Enable zoom controls',
104
+ },
105
+ enablePan: {
106
+ control: 'boolean',
107
+ description: 'Enable pan mode',
108
+ },
109
+ },
110
+ }
111
+
112
+ export default meta
113
+ type Story = StoryObj<typeof WakaHeatmap>
114
+
115
+ export const Default: Story = {
116
+ args: {
117
+ data: weeklyActivityData,
118
+ title: 'Weekly Activity',
119
+ cellSize: 32,
120
+ },
121
+ render: (args) => <WakaHeatmap {...args} valueFormatter={(v) => `${v}h`} />,
122
+ }
123
+
124
+ export const ColorSchemes: Story = {
125
+ render: () => {
126
+ const data = generateHeatmapData(5, 8, 'gradient')
127
+
128
+ return (
129
+ <div className="space-y-8">
130
+ <WakaHeatmap data={data} colorSchemeName="blues" title="Blues" cellSize={24} />
131
+ <WakaHeatmap data={data} colorSchemeName="greens" title="Greens" cellSize={24} />
132
+ <WakaHeatmap data={data} colorSchemeName="viridis" title="Viridis" cellSize={24} />
133
+ <WakaHeatmap data={data} colorSchemeName="plasma" title="Plasma" cellSize={24} />
134
+ </div>
135
+ )
136
+ },
137
+ }
138
+
139
+ export const DivergingSchemes: Story = {
140
+ render: () => (
141
+ <div className="space-y-8">
142
+ <WakaHeatmap
143
+ data={correlationData}
144
+ colorSchemeName="coolwarm"
145
+ title="Correlation Matrix (Coolwarm)"
146
+ cellSize={48}
147
+ valueFormatter={(v) => v.toFixed(2)}
148
+ />
149
+ <WakaHeatmap
150
+ data={correlationData}
151
+ colorSchemeName="rdylgn"
152
+ title="Correlation Matrix (Red-Yellow-Green)"
153
+ cellSize={48}
154
+ valueFormatter={(v) => v.toFixed(2)}
155
+ />
156
+ </div>
157
+ ),
158
+ }
159
+
160
+ export const CellSizes: Story = {
161
+ render: () => {
162
+ const data = generateHeatmapData(4, 6, 'random')
163
+
164
+ return (
165
+ <div className="space-y-8">
166
+ <WakaHeatmap data={data} cellSize={16} cellGap={1} title="Small (16px)" />
167
+ <WakaHeatmap data={data} cellSize={28} cellGap={2} title="Medium (28px)" />
168
+ <WakaHeatmap data={data} cellSize={40} cellGap={3} title="Large (40px)" />
169
+ </div>
170
+ )
171
+ },
172
+ }
173
+
174
+ export const WithoutLabels: Story = {
175
+ render: () => {
176
+ const data = generateHeatmapData(8, 12, 'random')
177
+
178
+ return (
179
+ <div className="space-y-8">
180
+ <WakaHeatmap
181
+ data={data}
182
+ showRowLabels
183
+ showColumnLabels
184
+ title="With Labels"
185
+ cellSize={20}
186
+ />
187
+ <WakaHeatmap
188
+ data={data}
189
+ showRowLabels={false}
190
+ showColumnLabels={false}
191
+ title="Without Labels"
192
+ cellSize={20}
193
+ />
194
+ </div>
195
+ )
196
+ },
197
+ }
198
+
199
+ export const LargeHeatmap: Story = {
200
+ render: () => {
201
+ const data = generateHeatmapData(20, 30, 'random')
202
+
203
+ return (
204
+ <WakaHeatmap
205
+ data={data}
206
+ title="Large Heatmap (20x30)"
207
+ cellSize={16}
208
+ cellGap={1}
209
+ width={700}
210
+ height={450}
211
+ showRowLabels={false}
212
+ showColumnLabels={false}
213
+ />
214
+ )
215
+ },
216
+ }
217
+
218
+ export const InteractiveSelection: Story = {
219
+ render: () => {
220
+ const [selected, setSelected] = React.useState<HeatmapSelection | null>(null)
221
+
222
+ return (
223
+ <div className="space-y-4">
224
+ <WakaHeatmap
225
+ data={weeklyActivityData}
226
+ title="Click to Select"
227
+ cellSize={32}
228
+ enableSelection
229
+ onCellClick={(cell) => setSelected(cell)}
230
+ onSelectionChange={(selection) => console.log('Selection:', selection)}
231
+ />
232
+ {selected && (
233
+ <div className="p-4 border rounded-lg bg-muted/50">
234
+ <p className="text-sm">
235
+ Selected: Row {selected.row + 1}, Column {selected.col + 1}
236
+ </p>
237
+ <p className="text-lg font-semibold">{selected.value} hours</p>
238
+ </div>
239
+ )}
240
+ </div>
241
+ )
242
+ },
243
+ }
244
+
245
+ export const ZoomAndPan: Story = {
246
+ render: () => {
247
+ const data = generateHeatmapData(15, 20, 'random')
248
+
249
+ return (
250
+ <WakaHeatmap
251
+ data={data}
252
+ title="Zoom & Pan (use scroll wheel and pan button)"
253
+ cellSize={18}
254
+ width={500}
255
+ height={350}
256
+ enableZoom
257
+ enablePan
258
+ initialZoom={1}
259
+ minZoom={0.5}
260
+ maxZoom={3}
261
+ />
262
+ )
263
+ },
264
+ }
265
+
266
+ export const MinMaxIndicators: Story = {
267
+ render: () => (
268
+ <WakaHeatmap
269
+ data={weeklyActivityData}
270
+ title="With Min/Max Indicators"
271
+ cellSize={32}
272
+ showMinMax
273
+ valueFormatter={(v) => `${v}h`}
274
+ />
275
+ ),
276
+ }
277
+
278
+ export const NoTooltip: Story = {
279
+ render: () => (
280
+ <WakaHeatmap
281
+ data={weeklyActivityData}
282
+ title="Without Tooltip"
283
+ cellSize={32}
284
+ showTooltip={false}
285
+ />
286
+ ),
287
+ }
288
+
289
+ export const WithHook: Story = {
290
+ render: () => {
291
+ const heatmap = useHeatmap({
292
+ initialZoom: 1,
293
+ minZoom: 0.5,
294
+ maxZoom: 2,
295
+ onSelectionChange: (selection) => console.log('Selection changed:', selection),
296
+ })
297
+
298
+ return (
299
+ <div className="space-y-4">
300
+ <div className="flex gap-2">
301
+ <button
302
+ onClick={heatmap.zoomIn}
303
+ className="px-3 py-1 text-sm border rounded hover:bg-muted"
304
+ >
305
+ Zoom In
306
+ </button>
307
+ <button
308
+ onClick={heatmap.zoomOut}
309
+ className="px-3 py-1 text-sm border rounded hover:bg-muted"
310
+ >
311
+ Zoom Out
312
+ </button>
313
+ <button
314
+ onClick={heatmap.resetZoom}
315
+ className="px-3 py-1 text-sm border rounded hover:bg-muted"
316
+ >
317
+ Reset
318
+ </button>
319
+ <span className="px-2 py-1 text-sm bg-muted rounded">
320
+ Zoom: {Math.round(heatmap.zoom * 100)}%
321
+ </span>
322
+ </div>
323
+ <WakaHeatmap
324
+ data={weeklyActivityData}
325
+ title="Controlled via Hook"
326
+ cellSize={32}
327
+ enableZoom={false}
328
+ enablePan={false}
329
+ initialZoom={heatmap.zoom}
330
+ />
331
+ </div>
332
+ )
333
+ },
334
+ }
335
+
336
+ export const CorrelationMatrix: Story = {
337
+ render: () => (
338
+ <WakaHeatmap
339
+ data={correlationData}
340
+ title="Feature Correlation Matrix"
341
+ colorSchemeName="coolwarm"
342
+ cellSize={60}
343
+ valueFormatter={(v) => v.toFixed(2)}
344
+ />
345
+ ),
346
+ }
347
+
348
+ export const ServerLoadExample: Story = {
349
+ render: () => {
350
+ const hours = Array.from({ length: 24 }, (_, i) => `${i}:00`)
351
+ const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
352
+
353
+ const values = days.map((_, dayIndex) =>
354
+ hours.map((_, hourIndex) => {
355
+ // Simulate server load pattern: higher during business hours, lower at night/weekends
356
+ const isWeekend = dayIndex >= 5
357
+ const isBusinessHours = hourIndex >= 9 && hourIndex <= 17
358
+ const baseLoad = isWeekend ? 20 : isBusinessHours ? 70 : 30
359
+ return Math.min(100, Math.max(0, baseLoad + (Math.random() - 0.5) * 40))
360
+ })
361
+ )
362
+
363
+ return (
364
+ <WakaHeatmap
365
+ data={{ values, rowLabels: days, columnLabels: hours }}
366
+ title="Server Load by Hour"
367
+ colorSchemeName="reds"
368
+ cellSize={16}
369
+ cellGap={1}
370
+ width={700}
371
+ height={250}
372
+ valueFormatter={(v) => `${Math.round(v)}%`}
373
+ />
374
+ )
375
+ },
376
+ }