@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,315 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { WakaContainerList, defaultContainers } from './index'
3
+ import type { Container, ContainerStatus } from './index'
4
+ import * as React from 'react'
5
+
6
+ const manyContainers: Container[] = [
7
+ ...defaultContainers,
8
+ {
9
+ id: 'mno345pqr678',
10
+ name: 'nginx-proxy',
11
+ image: 'nginx:alpine',
12
+ status: 'running',
13
+ createdAt: new Date(Date.now() - 10 * 24 * 3600000),
14
+ startedAt: new Date(Date.now() - 5 * 24 * 3600000),
15
+ ports: [
16
+ { host: 80, container: 80, protocol: 'tcp' },
17
+ { host: 443, container: 443, protocol: 'tcp' },
18
+ ],
19
+ resources: {
20
+ cpu: 2.1,
21
+ memory: 32 * 1024 * 1024,
22
+ memoryLimit: 128 * 1024 * 1024,
23
+ networkRx: 1024 * 1024 * 100,
24
+ networkTx: 1024 * 1024 * 80,
25
+ },
26
+ },
27
+ {
28
+ id: 'pqr678stu901',
29
+ name: 'elasticsearch',
30
+ image: 'elasticsearch:8.10',
31
+ status: 'running',
32
+ createdAt: new Date(Date.now() - 20 * 24 * 3600000),
33
+ startedAt: new Date(Date.now() - 10 * 24 * 3600000),
34
+ ports: [
35
+ { host: 9200, container: 9200, protocol: 'tcp' },
36
+ { host: 9300, container: 9300, protocol: 'tcp' },
37
+ ],
38
+ resources: {
39
+ cpu: 45.8,
40
+ memory: 2048 * 1024 * 1024,
41
+ memoryLimit: 4096 * 1024 * 1024,
42
+ networkRx: 1024 * 1024 * 20,
43
+ networkTx: 1024 * 1024 * 15,
44
+ },
45
+ },
46
+ {
47
+ id: 'stu901vwx234',
48
+ name: 'grafana',
49
+ image: 'grafana/grafana:10.0',
50
+ status: 'running',
51
+ createdAt: new Date(Date.now() - 15 * 24 * 3600000),
52
+ startedAt: new Date(Date.now() - 15 * 24 * 3600000),
53
+ ports: [{ host: 3000, container: 3000, protocol: 'tcp' }],
54
+ resources: {
55
+ cpu: 8.3,
56
+ memory: 128 * 1024 * 1024,
57
+ memoryLimit: 256 * 1024 * 1024,
58
+ networkRx: 1024 * 1024 * 5,
59
+ networkTx: 1024 * 1024 * 10,
60
+ },
61
+ },
62
+ {
63
+ id: 'vwx234yza567',
64
+ name: 'prometheus',
65
+ image: 'prom/prometheus:v2.45',
66
+ status: 'stopped',
67
+ createdAt: new Date(Date.now() - 30 * 24 * 3600000),
68
+ exitCode: 0,
69
+ },
70
+ {
71
+ id: 'yza567bcd890',
72
+ name: 'alertmanager',
73
+ image: 'prom/alertmanager:v0.26',
74
+ status: 'exited',
75
+ createdAt: new Date(Date.now() - 5 * 24 * 3600000),
76
+ exitCode: 1,
77
+ },
78
+ ]
79
+
80
+ const allStatuses: Container[] = [
81
+ { id: '1', name: 'running-container', image: 'nginx:latest', status: 'running', createdAt: new Date(), startedAt: new Date(Date.now() - 3600000), resources: { cpu: 15.5, memory: 64 * 1024 * 1024, memoryLimit: 128 * 1024 * 1024, networkRx: 1024 * 1024, networkTx: 512 * 1024 } },
82
+ { id: '2', name: 'stopped-container', image: 'redis:alpine', status: 'stopped', createdAt: new Date() },
83
+ { id: '3', name: 'paused-container', image: 'postgres:15', status: 'paused', createdAt: new Date() },
84
+ { id: '4', name: 'restarting-container', image: 'mysql:8', status: 'restarting', createdAt: new Date() },
85
+ { id: '5', name: 'exited-container', image: 'busybox', status: 'exited', createdAt: new Date(), exitCode: 137 },
86
+ { id: '6', name: 'created-container', image: 'alpine:latest', status: 'created', createdAt: new Date() },
87
+ ]
88
+
89
+ const meta: Meta<typeof WakaContainerList> = {
90
+ title: 'Components/DevOps/WakaContainerList',
91
+ component: WakaContainerList,
92
+ parameters: {
93
+ layout: 'centered',
94
+ docs: {
95
+ description: {
96
+ component: 'A container list with status, resource metrics, port mappings, search, and lifecycle actions (start, stop, restart, remove).',
97
+ },
98
+ },
99
+ },
100
+ tags: ['autodocs'],
101
+ argTypes: {
102
+ isLoading: {
103
+ control: 'boolean',
104
+ description: 'Loading state for refresh button',
105
+ },
106
+ },
107
+ }
108
+
109
+ export default meta
110
+ type Story = StoryObj<typeof WakaContainerList>
111
+
112
+ export const Default: Story = {
113
+ args: {
114
+ containers: defaultContainers,
115
+ },
116
+ render: (args) => (
117
+ <div className="w-[900px] h-[500px]">
118
+ <WakaContainerList
119
+ {...args}
120
+ onStart={(id) => console.log('Start:', id)}
121
+ onStop={(id) => console.log('Stop:', id)}
122
+ onRestart={(id) => console.log('Restart:', id)}
123
+ onRemove={(id) => console.log('Remove:', id)}
124
+ onViewLogs={(id) => console.log('View logs:', id)}
125
+ onExec={(id) => console.log('Exec:', id)}
126
+ onRefresh={() => console.log('Refresh')}
127
+ />
128
+ </div>
129
+ ),
130
+ }
131
+
132
+ export const AllStatuses: Story = {
133
+ render: () => (
134
+ <div className="w-[900px] h-[500px]">
135
+ <p className="text-sm text-muted-foreground mb-4">
136
+ Containers in all possible states
137
+ </p>
138
+ <WakaContainerList
139
+ containers={allStatuses}
140
+ onStart={(id) => console.log('Start:', id)}
141
+ onStop={(id) => console.log('Stop:', id)}
142
+ onRestart={(id) => console.log('Restart:', id)}
143
+ onRemove={(id) => console.log('Remove:', id)}
144
+ onViewLogs={(id) => console.log('View logs:', id)}
145
+ onExec={(id) => console.log('Exec:', id)}
146
+ />
147
+ </div>
148
+ ),
149
+ }
150
+
151
+ export const ManyContainers: Story = {
152
+ render: () => (
153
+ <div className="w-[900px] h-[600px]">
154
+ <WakaContainerList
155
+ containers={manyContainers}
156
+ title="Docker Containers"
157
+ onStart={(id) => console.log('Start:', id)}
158
+ onStop={(id) => console.log('Stop:', id)}
159
+ onRestart={(id) => console.log('Restart:', id)}
160
+ onRemove={(id) => console.log('Remove:', id)}
161
+ onViewLogs={(id) => console.log('View logs:', id)}
162
+ onExec={(id) => console.log('Exec:', id)}
163
+ onRefresh={() => console.log('Refresh')}
164
+ />
165
+ </div>
166
+ ),
167
+ }
168
+
169
+ export const Loading: Story = {
170
+ render: () => (
171
+ <div className="w-[900px] h-[400px]">
172
+ <WakaContainerList
173
+ containers={defaultContainers}
174
+ isLoading
175
+ onRefresh={() => console.log('Refresh')}
176
+ />
177
+ </div>
178
+ ),
179
+ }
180
+
181
+ export const Interactive: Story = {
182
+ render: () => {
183
+ const [containers, setContainers] = React.useState<Container[]>(defaultContainers)
184
+
185
+ const handleStart = (id: string) => {
186
+ setContainers((prev) =>
187
+ prev.map((c) =>
188
+ c.id === id
189
+ ? {
190
+ ...c,
191
+ status: 'running' as ContainerStatus,
192
+ startedAt: new Date(),
193
+ resources: {
194
+ cpu: Math.random() * 30,
195
+ memory: Math.random() * 256 * 1024 * 1024,
196
+ memoryLimit: 512 * 1024 * 1024,
197
+ networkRx: 0,
198
+ networkTx: 0,
199
+ },
200
+ }
201
+ : c
202
+ )
203
+ )
204
+ }
205
+
206
+ const handleStop = (id: string) => {
207
+ setContainers((prev) =>
208
+ prev.map((c) =>
209
+ c.id === id
210
+ ? { ...c, status: 'stopped' as ContainerStatus, startedAt: undefined, resources: undefined }
211
+ : c
212
+ )
213
+ )
214
+ }
215
+
216
+ const handleRestart = (id: string) => {
217
+ setContainers((prev) =>
218
+ prev.map((c) =>
219
+ c.id === id ? { ...c, status: 'restarting' as ContainerStatus } : c
220
+ )
221
+ )
222
+
223
+ setTimeout(() => {
224
+ setContainers((prev) =>
225
+ prev.map((c) =>
226
+ c.id === id
227
+ ? {
228
+ ...c,
229
+ status: 'running' as ContainerStatus,
230
+ startedAt: new Date(),
231
+ }
232
+ : c
233
+ )
234
+ )
235
+ }, 2000)
236
+ }
237
+
238
+ const handleRemove = (id: string) => {
239
+ setContainers((prev) => prev.filter((c) => c.id !== id))
240
+ }
241
+
242
+ return (
243
+ <div className="w-[900px] h-[500px]">
244
+ <p className="text-sm text-muted-foreground mb-4">
245
+ Interactive demo - try starting, stopping, and removing containers
246
+ </p>
247
+ <WakaContainerList
248
+ containers={containers}
249
+ title="Docker Containers"
250
+ onStart={handleStart}
251
+ onStop={handleStop}
252
+ onRestart={handleRestart}
253
+ onRemove={handleRemove}
254
+ onViewLogs={(id) => alert(`Viewing logs for container ${id}`)}
255
+ onExec={(id) => alert(`Opening terminal for container ${id}`)}
256
+ />
257
+ </div>
258
+ )
259
+ },
260
+ }
261
+
262
+ export const Empty: Story = {
263
+ render: () => (
264
+ <div className="w-[900px] h-[400px]">
265
+ <WakaContainerList
266
+ containers={[]}
267
+ title="No Containers"
268
+ />
269
+ </div>
270
+ ),
271
+ }
272
+
273
+ export const ReadOnly: Story = {
274
+ render: () => (
275
+ <div className="w-[900px] h-[500px]">
276
+ <p className="text-sm text-muted-foreground mb-4">
277
+ View-only mode (no action callbacks provided)
278
+ </p>
279
+ <WakaContainerList
280
+ containers={defaultContainers}
281
+ title="Container Status"
282
+ />
283
+ </div>
284
+ ),
285
+ }
286
+
287
+ export const DockerDashboard: Story = {
288
+ render: () => (
289
+ <div className="p-6 rounded-xl border bg-card">
290
+ <div className="flex items-center justify-between mb-6">
291
+ <div>
292
+ <h2 className="text-xl font-bold">Docker Dashboard</h2>
293
+ <p className="text-sm text-muted-foreground">Host: localhost</p>
294
+ </div>
295
+ <div className="flex items-center gap-2">
296
+ <div className="w-2 h-2 rounded-full bg-green-500" />
297
+ <span className="text-sm text-green-500 font-medium">Connected</span>
298
+ </div>
299
+ </div>
300
+
301
+ <div className="w-[850px]">
302
+ <WakaContainerList
303
+ containers={manyContainers}
304
+ onStart={(id) => console.log('Start:', id)}
305
+ onStop={(id) => console.log('Stop:', id)}
306
+ onRestart={(id) => console.log('Restart:', id)}
307
+ onRemove={(id) => console.log('Remove:', id)}
308
+ onViewLogs={(id) => console.log('View logs:', id)}
309
+ onExec={(id) => console.log('Exec:', id)}
310
+ onRefresh={() => console.log('Refresh')}
311
+ />
312
+ </div>
313
+ </div>
314
+ ),
315
+ }
@@ -0,0 +1,354 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { WakaContributionGraph } from './index'
3
+ import type { ContributionDay } from './index'
4
+ import * as React from 'react'
5
+
6
+ // Generate sample contribution data for the past year
7
+ function generateContributionData(days: number = 365): ContributionDay[] {
8
+ const data: ContributionDay[] = []
9
+ const today = new Date()
10
+
11
+ for (let i = days - 1; i >= 0; i--) {
12
+ const date = new Date(today)
13
+ date.setDate(date.getDate() - i)
14
+
15
+ // Generate realistic pattern: more activity on weekdays, less on weekends
16
+ const dayOfWeek = date.getDay()
17
+ const isWeekend = dayOfWeek === 0 || dayOfWeek === 6
18
+ const baseChance = isWeekend ? 0.3 : 0.7
19
+
20
+ let count = 0
21
+ if (Math.random() < baseChance) {
22
+ // Generate contribution count with some variation
23
+ const max = isWeekend ? 5 : 15
24
+ count = Math.floor(Math.random() * max)
25
+ }
26
+
27
+ data.push({
28
+ date: date.toISOString().split('T')[0],
29
+ count,
30
+ })
31
+ }
32
+
33
+ return data
34
+ }
35
+
36
+ // High activity data
37
+ function generateHighActivityData(): ContributionDay[] {
38
+ const data: ContributionDay[] = []
39
+ const today = new Date()
40
+
41
+ for (let i = 364; i >= 0; i--) {
42
+ const date = new Date(today)
43
+ date.setDate(date.getDate() - i)
44
+
45
+ data.push({
46
+ date: date.toISOString().split('T')[0],
47
+ count: Math.floor(Math.random() * 20) + 5,
48
+ })
49
+ }
50
+
51
+ return data
52
+ }
53
+
54
+ // Sparse data
55
+ function generateSparseData(): ContributionDay[] {
56
+ const data: ContributionDay[] = []
57
+ const today = new Date()
58
+
59
+ for (let i = 364; i >= 0; i--) {
60
+ const date = new Date(today)
61
+ date.setDate(date.getDate() - i)
62
+
63
+ data.push({
64
+ date: date.toISOString().split('T')[0],
65
+ count: Math.random() < 0.2 ? Math.floor(Math.random() * 5) : 0,
66
+ })
67
+ }
68
+
69
+ return data
70
+ }
71
+
72
+ const defaultData = generateContributionData()
73
+ const highActivityData = generateHighActivityData()
74
+ const sparseData = generateSparseData()
75
+
76
+ const meta: Meta<typeof WakaContributionGraph> = {
77
+ title: 'Components/Charts/WakaContributionGraph',
78
+ component: WakaContributionGraph,
79
+ parameters: {
80
+ layout: 'centered',
81
+ docs: {
82
+ description: {
83
+ component: 'A GitHub-style contribution graph showing activity over time with customizable colors and tooltips.',
84
+ },
85
+ },
86
+ },
87
+ tags: ['autodocs'],
88
+ argTypes: {
89
+ colorScheme: {
90
+ control: 'select',
91
+ options: ['green', 'blue', 'purple', 'orange', 'pink'],
92
+ description: 'Color scheme for cells',
93
+ },
94
+ cellSize: {
95
+ control: { type: 'range', min: 8, max: 16, step: 1 },
96
+ description: 'Size of each cell',
97
+ },
98
+ cellGap: {
99
+ control: { type: 'range', min: 1, max: 4, step: 1 },
100
+ description: 'Gap between cells',
101
+ },
102
+ showMonthLabels: {
103
+ control: 'boolean',
104
+ description: 'Show month labels',
105
+ },
106
+ showDayLabels: {
107
+ control: 'boolean',
108
+ description: 'Show day of week labels',
109
+ },
110
+ showTooltip: {
111
+ control: 'boolean',
112
+ description: 'Show tooltip on hover',
113
+ },
114
+ },
115
+ }
116
+
117
+ export default meta
118
+ type Story = StoryObj<typeof WakaContributionGraph>
119
+
120
+ export const Default: Story = {
121
+ args: {
122
+ data: defaultData,
123
+ colorScheme: 'green',
124
+ cellSize: 12,
125
+ cellGap: 2,
126
+ showMonthLabels: true,
127
+ showDayLabels: true,
128
+ showTooltip: true,
129
+ },
130
+ render: (args) => <WakaContributionGraph {...args} />,
131
+ }
132
+
133
+ export const ColorSchemes: Story = {
134
+ render: () => (
135
+ <div className="space-y-6">
136
+ <div>
137
+ <p className="text-sm text-muted-foreground mb-2">Green (Default)</p>
138
+ <WakaContributionGraph data={defaultData} colorScheme="green" />
139
+ </div>
140
+ <div>
141
+ <p className="text-sm text-muted-foreground mb-2">Blue</p>
142
+ <WakaContributionGraph data={defaultData} colorScheme="blue" />
143
+ </div>
144
+ <div>
145
+ <p className="text-sm text-muted-foreground mb-2">Purple</p>
146
+ <WakaContributionGraph data={defaultData} colorScheme="purple" />
147
+ </div>
148
+ <div>
149
+ <p className="text-sm text-muted-foreground mb-2">Orange</p>
150
+ <WakaContributionGraph data={defaultData} colorScheme="orange" />
151
+ </div>
152
+ <div>
153
+ <p className="text-sm text-muted-foreground mb-2">Pink</p>
154
+ <WakaContributionGraph data={defaultData} colorScheme="pink" />
155
+ </div>
156
+ </div>
157
+ ),
158
+ }
159
+
160
+ export const CellSizes: Story = {
161
+ render: () => (
162
+ <div className="space-y-6">
163
+ <div>
164
+ <p className="text-sm text-muted-foreground mb-2">Small (8px)</p>
165
+ <WakaContributionGraph data={defaultData} cellSize={8} cellGap={1} />
166
+ </div>
167
+ <div>
168
+ <p className="text-sm text-muted-foreground mb-2">Medium (11px - Default)</p>
169
+ <WakaContributionGraph data={defaultData} cellSize={11} cellGap={2} />
170
+ </div>
171
+ <div>
172
+ <p className="text-sm text-muted-foreground mb-2">Large (14px)</p>
173
+ <WakaContributionGraph data={defaultData} cellSize={14} cellGap={3} />
174
+ </div>
175
+ </div>
176
+ ),
177
+ }
178
+
179
+ export const HighActivity: Story = {
180
+ render: () => (
181
+ <div className="space-y-2">
182
+ <p className="text-sm text-muted-foreground">Highly active contributor</p>
183
+ <WakaContributionGraph data={highActivityData} />
184
+ </div>
185
+ ),
186
+ }
187
+
188
+ export const SparseActivity: Story = {
189
+ render: () => (
190
+ <div className="space-y-2">
191
+ <p className="text-sm text-muted-foreground">Occasional contributor</p>
192
+ <WakaContributionGraph data={sparseData} />
193
+ </div>
194
+ ),
195
+ }
196
+
197
+ export const WithoutLabels: Story = {
198
+ render: () => (
199
+ <div className="space-y-6">
200
+ <div>
201
+ <p className="text-sm text-muted-foreground mb-2">No month labels</p>
202
+ <WakaContributionGraph data={defaultData} showMonthLabels={false} />
203
+ </div>
204
+ <div>
205
+ <p className="text-sm text-muted-foreground mb-2">No day labels</p>
206
+ <WakaContributionGraph data={defaultData} showDayLabels={false} />
207
+ </div>
208
+ <div>
209
+ <p className="text-sm text-muted-foreground mb-2">No labels</p>
210
+ <WakaContributionGraph data={defaultData} showMonthLabels={false} showDayLabels={false} />
211
+ </div>
212
+ </div>
213
+ ),
214
+ }
215
+
216
+ export const NoTooltip: Story = {
217
+ render: () => <WakaContributionGraph data={defaultData} showTooltip={false} />,
218
+ }
219
+
220
+ export const CustomColors: Story = {
221
+ render: () => (
222
+ <WakaContributionGraph
223
+ data={defaultData}
224
+ colors={['#fef3c7', '#fcd34d', '#f59e0b', '#d97706', '#92400e']}
225
+ />
226
+ ),
227
+ }
228
+
229
+ export const Interactive: Story = {
230
+ render: () => {
231
+ const [selectedDay, setSelectedDay] = React.useState<ContributionDay | null>(null)
232
+
233
+ return (
234
+ <div className="space-y-4">
235
+ <WakaContributionGraph
236
+ data={defaultData}
237
+ onDayClick={(day) => setSelectedDay(day)}
238
+ />
239
+ {selectedDay && (
240
+ <div className="p-4 border rounded-lg bg-muted/50">
241
+ <p className="text-sm text-muted-foreground">{selectedDay.date}</p>
242
+ <p className="text-2xl font-bold">
243
+ {selectedDay.count} contribution{selectedDay.count !== 1 ? 's' : ''}
244
+ </p>
245
+ </div>
246
+ )}
247
+ </div>
248
+ )
249
+ },
250
+ }
251
+
252
+ export const GitHubProfile: Story = {
253
+ render: () => {
254
+ const stats = {
255
+ total: defaultData.reduce((sum, d) => sum + d.count, 0),
256
+ activeDays: defaultData.filter((d) => d.count > 0).length,
257
+ }
258
+
259
+ return (
260
+ <div className="w-[900px] p-6 border rounded-lg">
261
+ <div className="flex items-center gap-4 mb-6">
262
+ <div className="w-16 h-16 rounded-full bg-gradient-to-br from-violet-500 to-purple-600" />
263
+ <div>
264
+ <h3 className="text-xl font-bold">developer_jane</h3>
265
+ <p className="text-sm text-muted-foreground">
266
+ {stats.total} contributions in the last year
267
+ </p>
268
+ </div>
269
+ </div>
270
+ <WakaContributionGraph data={defaultData} />
271
+ <div className="flex items-center justify-end gap-2 mt-4 text-xs text-muted-foreground">
272
+ <span>Less</span>
273
+ <div className="flex gap-1">
274
+ {['#ebedf0', '#9be9a8', '#40c463', '#30a14e', '#216e39'].map((color) => (
275
+ <div
276
+ key={color}
277
+ className="w-3 h-3 rounded-sm"
278
+ style={{ backgroundColor: color }}
279
+ />
280
+ ))}
281
+ </div>
282
+ <span>More</span>
283
+ </div>
284
+ </div>
285
+ )
286
+ },
287
+ }
288
+
289
+ export const CompactWidget: Story = {
290
+ render: () => {
291
+ // Last 3 months only
292
+ const recentData = defaultData.slice(-90)
293
+
294
+ return (
295
+ <div className="p-4 border rounded-lg w-fit">
296
+ <h4 className="text-sm font-medium mb-2">Recent Activity</h4>
297
+ <WakaContributionGraph
298
+ data={recentData}
299
+ cellSize={10}
300
+ cellGap={2}
301
+ showMonthLabels={false}
302
+ showDayLabels={false}
303
+ />
304
+ </div>
305
+ )
306
+ },
307
+ }
308
+
309
+ export const MultipleUsers: Story = {
310
+ render: () => (
311
+ <div className="space-y-8">
312
+ <div>
313
+ <div className="flex items-center gap-2 mb-2">
314
+ <div className="w-6 h-6 rounded-full bg-blue-500" />
315
+ <span className="font-medium">alice</span>
316
+ <span className="text-sm text-muted-foreground">2,847 contributions</span>
317
+ </div>
318
+ <WakaContributionGraph data={highActivityData} colorScheme="blue" cellSize={9} />
319
+ </div>
320
+ <div>
321
+ <div className="flex items-center gap-2 mb-2">
322
+ <div className="w-6 h-6 rounded-full bg-green-500" />
323
+ <span className="font-medium">bob</span>
324
+ <span className="text-sm text-muted-foreground">1,234 contributions</span>
325
+ </div>
326
+ <WakaContributionGraph data={defaultData} colorScheme="green" cellSize={9} />
327
+ </div>
328
+ <div>
329
+ <div className="flex items-center gap-2 mb-2">
330
+ <div className="w-6 h-6 rounded-full bg-purple-500" />
331
+ <span className="font-medium">carol</span>
332
+ <span className="text-sm text-muted-foreground">342 contributions</span>
333
+ </div>
334
+ <WakaContributionGraph data={sparseData} colorScheme="purple" cellSize={9} />
335
+ </div>
336
+ </div>
337
+ ),
338
+ }
339
+
340
+ export const CustomTooltip: Story = {
341
+ render: () => (
342
+ <WakaContributionGraph
343
+ data={defaultData}
344
+ tooltipFormatter={(day) =>
345
+ `${day.count} commit${day.count !== 1 ? 's' : ''} on ${new Date(day.date).toLocaleDateString('en-US', {
346
+ weekday: 'long',
347
+ year: 'numeric',
348
+ month: 'long',
349
+ day: 'numeric',
350
+ })}`
351
+ }
352
+ />
353
+ ),
354
+ }