@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,348 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { WakaCostBreakdown, useCostBreakdown } from './index'
3
+ import type { CostItem } from './index'
4
+ import * as React from 'react'
5
+
6
+ const cloudCostData: CostItem[] = [
7
+ {
8
+ id: 'compute',
9
+ name: 'Compute',
10
+ value: 0,
11
+ change: 12.5,
12
+ children: [
13
+ { id: 'ec2', name: 'EC2 Instances', value: 4500, change: 8.2 },
14
+ { id: 'lambda', name: 'Lambda', value: 1200, change: 25.0 },
15
+ { id: 'ecs', name: 'ECS/Fargate', value: 2300, change: -5.0 },
16
+ ],
17
+ },
18
+ {
19
+ id: 'storage',
20
+ name: 'Storage',
21
+ value: 0,
22
+ change: -3.2,
23
+ children: [
24
+ { id: 's3', name: 'S3', value: 2000, change: 2.0 },
25
+ { id: 'ebs', name: 'EBS Volumes', value: 1500, change: -8.0 },
26
+ { id: 'glacier', name: 'Glacier', value: 300, change: 0 },
27
+ ],
28
+ },
29
+ {
30
+ id: 'database',
31
+ name: 'Database',
32
+ value: 0,
33
+ change: 5.8,
34
+ children: [
35
+ { id: 'rds', name: 'RDS', value: 3200, change: 10.0 },
36
+ { id: 'dynamodb', name: 'DynamoDB', value: 800, change: -2.0 },
37
+ { id: 'elasticache', name: 'ElastiCache', value: 600, change: 15.0 },
38
+ ],
39
+ },
40
+ {
41
+ id: 'network',
42
+ name: 'Network',
43
+ value: 0,
44
+ change: 18.0,
45
+ children: [
46
+ { id: 'data-transfer', name: 'Data Transfer', value: 1800, change: 20.0 },
47
+ { id: 'cloudfront', name: 'CloudFront', value: 900, change: 15.0 },
48
+ { id: 'route53', name: 'Route 53', value: 100, change: 0 },
49
+ ],
50
+ },
51
+ { id: 'other', name: 'Other Services', value: 1200, change: 5.0 },
52
+ ]
53
+
54
+ const departmentBudgetData: CostItem[] = [
55
+ {
56
+ id: 'engineering',
57
+ name: 'Engineering',
58
+ value: 0,
59
+ color: '#3b82f6',
60
+ children: [
61
+ { id: 'salaries-eng', name: 'Salaries', value: 450000 },
62
+ { id: 'tools-eng', name: 'Tools & Licenses', value: 35000 },
63
+ { id: 'infra', name: 'Infrastructure', value: 80000 },
64
+ ],
65
+ },
66
+ {
67
+ id: 'marketing',
68
+ name: 'Marketing',
69
+ value: 0,
70
+ color: '#22c55e',
71
+ children: [
72
+ { id: 'salaries-mkt', name: 'Salaries', value: 180000 },
73
+ { id: 'ads', name: 'Advertising', value: 120000 },
74
+ { id: 'events', name: 'Events', value: 50000 },
75
+ ],
76
+ },
77
+ {
78
+ id: 'sales',
79
+ name: 'Sales',
80
+ value: 0,
81
+ color: '#f59e0b',
82
+ children: [
83
+ { id: 'salaries-sales', name: 'Salaries', value: 320000 },
84
+ { id: 'commissions', name: 'Commissions', value: 95000 },
85
+ { id: 'travel', name: 'Travel', value: 45000 },
86
+ ],
87
+ },
88
+ {
89
+ id: 'operations',
90
+ name: 'Operations',
91
+ value: 0,
92
+ color: '#8b5cf6',
93
+ children: [
94
+ { id: 'salaries-ops', name: 'Salaries', value: 150000 },
95
+ { id: 'facilities', name: 'Facilities', value: 80000 },
96
+ { id: 'legal', name: 'Legal & Compliance', value: 40000 },
97
+ ],
98
+ },
99
+ ]
100
+
101
+ const simpleData: CostItem[] = [
102
+ { id: 'rent', name: 'Rent', value: 2500 },
103
+ { id: 'utilities', name: 'Utilities', value: 350 },
104
+ { id: 'groceries', name: 'Groceries', value: 600 },
105
+ { id: 'transport', name: 'Transport', value: 400 },
106
+ { id: 'entertainment', name: 'Entertainment', value: 250 },
107
+ { id: 'savings', name: 'Savings', value: 800 },
108
+ ]
109
+
110
+ const meta: Meta<typeof WakaCostBreakdown> = {
111
+ title: 'Components/Charts/WakaCostBreakdown',
112
+ component: WakaCostBreakdown,
113
+ parameters: {
114
+ layout: 'centered',
115
+ docs: {
116
+ description: {
117
+ component: 'A cost breakdown visualization with treemap and sunburst variants, drill-down navigation, and comparison indicators.',
118
+ },
119
+ },
120
+ },
121
+ tags: ['autodocs'],
122
+ argTypes: {
123
+ variant: {
124
+ control: 'select',
125
+ options: ['treemap', 'sunburst'],
126
+ description: 'Visualization variant',
127
+ },
128
+ currency: {
129
+ control: 'text',
130
+ description: 'Currency symbol',
131
+ },
132
+ showLegend: {
133
+ control: 'boolean',
134
+ description: 'Show legend sidebar',
135
+ },
136
+ showComparison: {
137
+ control: 'boolean',
138
+ description: 'Show comparison indicators',
139
+ },
140
+ animated: {
141
+ control: 'boolean',
142
+ description: 'Enable animations',
143
+ },
144
+ },
145
+ }
146
+
147
+ export default meta
148
+ type Story = StoryObj<typeof WakaCostBreakdown>
149
+
150
+ export const Default: Story = {
151
+ args: {
152
+ data: cloudCostData,
153
+ currency: '$',
154
+ },
155
+ render: (args) => <WakaCostBreakdown {...args} />,
156
+ }
157
+
158
+ export const TreemapVariant: Story = {
159
+ render: () => (
160
+ <WakaCostBreakdown
161
+ data={departmentBudgetData}
162
+ variant="treemap"
163
+ currency="$"
164
+ />
165
+ ),
166
+ }
167
+
168
+ export const SunburstVariant: Story = {
169
+ render: () => (
170
+ <WakaCostBreakdown
171
+ data={departmentBudgetData}
172
+ variant="sunburst"
173
+ currency="$"
174
+ />
175
+ ),
176
+ }
177
+
178
+ export const WithComparison: Story = {
179
+ render: () => (
180
+ <WakaCostBreakdown
181
+ data={cloudCostData}
182
+ showComparison
183
+ currency="$"
184
+ />
185
+ ),
186
+ }
187
+
188
+ export const SimpleData: Story = {
189
+ render: () => (
190
+ <WakaCostBreakdown
191
+ data={simpleData}
192
+ currency="$"
193
+ showComparison={false}
194
+ />
195
+ ),
196
+ }
197
+
198
+ export const NoLegend: Story = {
199
+ render: () => (
200
+ <WakaCostBreakdown
201
+ data={cloudCostData}
202
+ showLegend={false}
203
+ currency="$"
204
+ />
205
+ ),
206
+ }
207
+
208
+ export const DrillDownExample: Story = {
209
+ render: () => (
210
+ <div className="space-y-4">
211
+ <p className="text-sm text-muted-foreground text-center">
212
+ Click on a category to drill down into its subcategories
213
+ </p>
214
+ <WakaCostBreakdown
215
+ data={cloudCostData}
216
+ currency="$"
217
+ showComparison
218
+ onItemClick={(id, path) => console.log('Clicked:', id, 'Path:', path)}
219
+ />
220
+ </div>
221
+ ),
222
+ }
223
+
224
+ export const CustomFormatter: Story = {
225
+ render: () => (
226
+ <WakaCostBreakdown
227
+ data={cloudCostData}
228
+ currency=""
229
+ formatValue={(value) => {
230
+ if (value >= 1000) {
231
+ return `${(value / 1000).toFixed(1)}K USD`
232
+ }
233
+ return `${value} USD`
234
+ }}
235
+ />
236
+ ),
237
+ }
238
+
239
+ export const WithHook: Story = {
240
+ render: () => {
241
+ const { path, drillDown, drillUp, reset, getCurrentData } = useCostBreakdown({
242
+ data: cloudCostData,
243
+ onDrillDown: (path) => console.log('Drill down:', path),
244
+ })
245
+
246
+ const currentData = getCurrentData()
247
+
248
+ return (
249
+ <div className="space-y-4">
250
+ <div className="flex gap-2 items-center">
251
+ <button
252
+ onClick={drillUp}
253
+ disabled={path.length === 0}
254
+ className="px-3 py-1 text-sm border rounded hover:bg-muted disabled:opacity-50"
255
+ >
256
+ Back
257
+ </button>
258
+ <button
259
+ onClick={reset}
260
+ className="px-3 py-1 text-sm border rounded hover:bg-muted"
261
+ >
262
+ Reset
263
+ </button>
264
+ <span className="text-sm text-muted-foreground">
265
+ Path: {path.length === 0 ? 'Root' : path.join(' / ')}
266
+ </span>
267
+ </div>
268
+ <WakaCostBreakdown
269
+ data={cloudCostData}
270
+ currency="$"
271
+ />
272
+ </div>
273
+ )
274
+ },
275
+ }
276
+
277
+ export const CloudCostDashboard: Story = {
278
+ render: () => (
279
+ <div className="w-[750px] p-6 border rounded-lg">
280
+ <div className="flex justify-between items-start mb-6">
281
+ <div>
282
+ <h3 className="text-xl font-semibold">Cloud Cost Analysis</h3>
283
+ <p className="text-sm text-muted-foreground">December 2024</p>
284
+ </div>
285
+ <div className="text-right">
286
+ <p className="text-sm text-muted-foreground">Month-over-Month</p>
287
+ <p className="text-lg font-semibold text-red-600">+8.5%</p>
288
+ </div>
289
+ </div>
290
+ <WakaCostBreakdown
291
+ data={cloudCostData}
292
+ currency="$"
293
+ showComparison
294
+ />
295
+ </div>
296
+ ),
297
+ }
298
+
299
+ export const DepartmentBudgetDashboard: Story = {
300
+ render: () => (
301
+ <div className="w-[750px] p-6 border rounded-lg">
302
+ <div className="mb-6">
303
+ <h3 className="text-xl font-semibold">Department Budget Allocation</h3>
304
+ <p className="text-sm text-muted-foreground">Fiscal Year 2024</p>
305
+ </div>
306
+ <WakaCostBreakdown
307
+ data={departmentBudgetData}
308
+ variant="sunburst"
309
+ currency="$"
310
+ />
311
+ </div>
312
+ ),
313
+ }
314
+
315
+ export const ComparisonVariants: Story = {
316
+ render: () => (
317
+ <div className="space-y-8">
318
+ <div>
319
+ <h4 className="text-sm font-medium mb-2">Treemap View</h4>
320
+ <WakaCostBreakdown
321
+ data={simpleData}
322
+ variant="treemap"
323
+ currency="$"
324
+ showLegend={false}
325
+ />
326
+ </div>
327
+ <div>
328
+ <h4 className="text-sm font-medium mb-2">Sunburst View</h4>
329
+ <WakaCostBreakdown
330
+ data={simpleData}
331
+ variant="sunburst"
332
+ currency="$"
333
+ showLegend={false}
334
+ />
335
+ </div>
336
+ </div>
337
+ ),
338
+ }
339
+
340
+ export const NoAnimation: Story = {
341
+ render: () => (
342
+ <WakaCostBreakdown
343
+ data={cloudCostData}
344
+ animated={false}
345
+ currency="$"
346
+ />
347
+ ),
348
+ }
@@ -0,0 +1,365 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { WakaDailyReward, WakaCompactDailyReward, useDailyRewards } from './index'
3
+ import type { DailyReward, Reward } from './index'
4
+ import * as React from 'react'
5
+ import { Crown, Gem, Zap, Gift } from 'lucide-react'
6
+
7
+ const defaultRewards: DailyReward[] = [
8
+ { day: 1, reward: { type: 'coins', value: 100 }, claimed: true },
9
+ { day: 2, reward: { type: 'xp', value: 50 }, claimed: true },
10
+ { day: 3, reward: { type: 'coins', value: 200 }, claimed: false },
11
+ { day: 4, reward: { type: 'item', value: 'Mystery Box' }, claimed: false },
12
+ { day: 5, reward: { type: 'xp', value: 100 }, claimed: false },
13
+ { day: 6, reward: { type: 'coins', value: 500 }, claimed: false },
14
+ { day: 7, reward: { type: 'badge', value: 'Weekly Champion' }, claimed: false, isBonus: true },
15
+ ]
16
+
17
+ const meta: Meta<typeof WakaDailyReward> = {
18
+ title: 'Components/Gamification/WakaDailyReward',
19
+ component: WakaDailyReward,
20
+ parameters: {
21
+ layout: 'centered',
22
+ docs: {
23
+ description: {
24
+ component: 'A daily reward calendar with streak tracking, confetti celebration, countdown timer, and multiple reward types.',
25
+ },
26
+ },
27
+ },
28
+ tags: ['autodocs'],
29
+ argTypes: {
30
+ variant: {
31
+ control: 'select',
32
+ options: ['horizontal', 'calendar'],
33
+ description: 'Layout variant',
34
+ },
35
+ size: {
36
+ control: 'select',
37
+ options: ['sm', 'md', 'lg'],
38
+ description: 'Size variant',
39
+ },
40
+ canClaim: {
41
+ control: 'boolean',
42
+ description: 'Whether the user can claim today\'s reward',
43
+ },
44
+ },
45
+ }
46
+
47
+ export default meta
48
+ type Story = StoryObj<typeof WakaDailyReward>
49
+
50
+ export const Default: Story = {
51
+ args: {
52
+ currentDay: 3,
53
+ rewards: defaultRewards,
54
+ streak: 3,
55
+ nextRewardIn: 43200,
56
+ variant: 'horizontal',
57
+ size: 'md',
58
+ canClaim: true,
59
+ },
60
+ render: (args) => <WakaDailyReward {...args} />,
61
+ }
62
+
63
+ export const Sizes: Story = {
64
+ render: () => (
65
+ <div className="space-y-8">
66
+ <div>
67
+ <p className="text-sm text-muted-foreground mb-2">Small</p>
68
+ <WakaDailyReward
69
+ currentDay={3}
70
+ rewards={defaultRewards}
71
+ streak={3}
72
+ size="sm"
73
+ />
74
+ </div>
75
+ <div>
76
+ <p className="text-sm text-muted-foreground mb-2">Medium (Default)</p>
77
+ <WakaDailyReward
78
+ currentDay={3}
79
+ rewards={defaultRewards}
80
+ streak={3}
81
+ size="md"
82
+ />
83
+ </div>
84
+ <div>
85
+ <p className="text-sm text-muted-foreground mb-2">Large</p>
86
+ <WakaDailyReward
87
+ currentDay={3}
88
+ rewards={defaultRewards}
89
+ streak={3}
90
+ size="lg"
91
+ />
92
+ </div>
93
+ </div>
94
+ ),
95
+ }
96
+
97
+ export const DayProgression: Story = {
98
+ render: () => (
99
+ <div className="space-y-6">
100
+ <div>
101
+ <p className="text-sm text-muted-foreground mb-2">Day 1 - First Day</p>
102
+ <WakaDailyReward
103
+ currentDay={1}
104
+ rewards={defaultRewards.map((r, i) => ({ ...r, claimed: false }))}
105
+ streak={0}
106
+ />
107
+ </div>
108
+ <div>
109
+ <p className="text-sm text-muted-foreground mb-2">Day 4 - Mid Week</p>
110
+ <WakaDailyReward
111
+ currentDay={4}
112
+ rewards={defaultRewards.map((r, i) => ({ ...r, claimed: i < 3 }))}
113
+ streak={3}
114
+ />
115
+ </div>
116
+ <div>
117
+ <p className="text-sm text-muted-foreground mb-2">Day 7 - Bonus Day</p>
118
+ <WakaDailyReward
119
+ currentDay={7}
120
+ rewards={defaultRewards.map((r, i) => ({ ...r, claimed: i < 6 }))}
121
+ streak={6}
122
+ />
123
+ </div>
124
+ </div>
125
+ ),
126
+ }
127
+
128
+ export const MissedDays: Story = {
129
+ render: () => {
130
+ const rewardsWithMissed: DailyReward[] = [
131
+ { day: 1, reward: { type: 'coins', value: 100 }, claimed: true },
132
+ { day: 2, reward: { type: 'xp', value: 50 }, claimed: false }, // Missed
133
+ { day: 3, reward: { type: 'coins', value: 200 }, claimed: false }, // Missed
134
+ { day: 4, reward: { type: 'item', value: 'Mystery Box' }, claimed: true },
135
+ { day: 5, reward: { type: 'xp', value: 100 }, claimed: false }, // Current
136
+ { day: 6, reward: { type: 'coins', value: 500 }, claimed: false },
137
+ { day: 7, reward: { type: 'badge', value: 'Weekly Champion' }, claimed: false, isBonus: true },
138
+ ]
139
+
140
+ return (
141
+ <div className="space-y-4">
142
+ <p className="text-sm text-muted-foreground text-center">
143
+ Days 2 and 3 were missed (shown with X)
144
+ </p>
145
+ <WakaDailyReward
146
+ currentDay={5}
147
+ rewards={rewardsWithMissed}
148
+ streak={1}
149
+ />
150
+ </div>
151
+ )
152
+ },
153
+ }
154
+
155
+ export const AllClaimed: Story = {
156
+ render: () => (
157
+ <div className="space-y-4">
158
+ <p className="text-sm text-muted-foreground text-center">
159
+ Perfect week - all rewards claimed!
160
+ </p>
161
+ <WakaDailyReward
162
+ currentDay={7}
163
+ rewards={defaultRewards.map(r => ({ ...r, claimed: true }))}
164
+ streak={7}
165
+ />
166
+ </div>
167
+ ),
168
+ }
169
+
170
+ export const Interactive: Story = {
171
+ render: () => {
172
+ const [rewards, setRewards] = React.useState<DailyReward[]>(
173
+ defaultRewards.map((r, i) => ({ ...r, claimed: i < 2 }))
174
+ )
175
+ const [currentDay, setCurrentDay] = React.useState(3)
176
+ const [streak, setStreak] = React.useState(2)
177
+
178
+ const handleClaim = (day: number) => {
179
+ setRewards(prev => prev.map(r =>
180
+ r.day === day ? { ...r, claimed: true } : r
181
+ ))
182
+ setStreak(prev => prev + 1)
183
+ if (currentDay < 7) {
184
+ setTimeout(() => setCurrentDay(prev => prev + 1), 1500)
185
+ }
186
+ }
187
+
188
+ const reset = () => {
189
+ setRewards(defaultRewards.map((r, i) => ({ ...r, claimed: i < 2 })))
190
+ setCurrentDay(3)
191
+ setStreak(2)
192
+ }
193
+
194
+ return (
195
+ <div className="space-y-6">
196
+ <WakaDailyReward
197
+ currentDay={currentDay}
198
+ rewards={rewards}
199
+ streak={streak}
200
+ onClaim={handleClaim}
201
+ />
202
+
203
+ <div className="flex justify-center gap-4">
204
+ <button
205
+ onClick={reset}
206
+ className="px-4 py-2 text-sm rounded border hover:bg-muted"
207
+ >
208
+ Reset Demo
209
+ </button>
210
+ </div>
211
+ </div>
212
+ )
213
+ },
214
+ }
215
+
216
+ export const WithHook: Story = {
217
+ render: () => {
218
+ const {
219
+ rewards,
220
+ currentDay,
221
+ streak,
222
+ claimReward,
223
+ advanceDay,
224
+ canClaimToday,
225
+ getSecondsUntilMidnight,
226
+ } = useDailyRewards({
227
+ initialRewards: defaultRewards,
228
+ initialDay: 3,
229
+ initialStreak: 2,
230
+ onRewardClaimed: (day, reward) => {
231
+ console.log(`Claimed day ${day}:`, reward)
232
+ },
233
+ })
234
+
235
+ return (
236
+ <div className="space-y-6">
237
+ <WakaDailyReward
238
+ currentDay={currentDay}
239
+ rewards={rewards}
240
+ streak={streak}
241
+ onClaim={claimReward}
242
+ nextRewardIn={getSecondsUntilMidnight()}
243
+ />
244
+
245
+ <div className="p-4 rounded-lg border">
246
+ <h4 className="font-medium mb-2">Hook State</h4>
247
+ <div className="grid grid-cols-2 gap-2 text-sm mb-3">
248
+ <div>Current Day: {currentDay}</div>
249
+ <div>Streak: {streak}</div>
250
+ <div>Can Claim: {canClaimToday ? 'Yes' : 'No'}</div>
251
+ </div>
252
+
253
+ <div className="flex gap-2">
254
+ <button
255
+ onClick={advanceDay}
256
+ className="px-3 py-1.5 text-xs rounded bg-primary text-primary-foreground"
257
+ >
258
+ Advance Day
259
+ </button>
260
+ </div>
261
+ </div>
262
+ </div>
263
+ )
264
+ },
265
+ }
266
+
267
+ export const CompactVariant: Story = {
268
+ render: () => (
269
+ <div className="space-y-6">
270
+ <div>
271
+ <p className="text-sm text-muted-foreground mb-2">Can Claim</p>
272
+ <WakaCompactDailyReward
273
+ currentDay={3}
274
+ streak={2}
275
+ claimed={false}
276
+ onClaim={() => console.log('Claimed!')}
277
+ />
278
+ </div>
279
+ <div>
280
+ <p className="text-sm text-muted-foreground mb-2">Already Claimed</p>
281
+ <WakaCompactDailyReward
282
+ currentDay={5}
283
+ streak={5}
284
+ claimed={true}
285
+ />
286
+ </div>
287
+ <div>
288
+ <p className="text-sm text-muted-foreground mb-2">Perfect Week</p>
289
+ <WakaCompactDailyReward
290
+ currentDay={7}
291
+ streak={7}
292
+ claimed={true}
293
+ />
294
+ </div>
295
+ </div>
296
+ ),
297
+ }
298
+
299
+ export const WithCountdown: Story = {
300
+ render: () => (
301
+ <WakaDailyReward
302
+ currentDay={3}
303
+ rewards={defaultRewards.map((r, i) => ({ ...r, claimed: i < 3 }))}
304
+ streak={3}
305
+ nextRewardIn={7200} // 2 hours
306
+ canClaim={false}
307
+ />
308
+ ),
309
+ }
310
+
311
+ export const CustomRewardIcons: Story = {
312
+ render: () => {
313
+ const customRewards: DailyReward[] = [
314
+ { day: 1, reward: { type: 'xp', value: 100, icon: <Zap className="h-6 w-6 text-yellow-500" /> }, claimed: true },
315
+ { day: 2, reward: { type: 'item', value: 'Gift', icon: <Gift className="h-6 w-6 text-blue-500" /> }, claimed: true },
316
+ { day: 3, reward: { type: 'coins', value: 500, icon: <Gem className="h-6 w-6 text-purple-500" /> }, claimed: false },
317
+ { day: 4, reward: { type: 'xp', value: 200, icon: <Zap className="h-6 w-6 text-yellow-500" /> }, claimed: false },
318
+ { day: 5, reward: { type: 'item', value: 'Rare Box', icon: <Gift className="h-6 w-6 text-green-500" /> }, claimed: false },
319
+ { day: 6, reward: { type: 'coins', value: 1000, icon: <Gem className="h-6 w-6 text-purple-500" /> }, claimed: false },
320
+ { day: 7, reward: { type: 'badge', value: 'Crown', icon: <Crown className="h-6 w-6 text-amber-500" /> }, claimed: false, isBonus: true },
321
+ ]
322
+
323
+ return (
324
+ <WakaDailyReward
325
+ currentDay={3}
326
+ rewards={customRewards}
327
+ streak={2}
328
+ />
329
+ )
330
+ },
331
+ }
332
+
333
+ export const DashboardWidget: Story = {
334
+ render: () => (
335
+ <div className="w-[400px] p-4 rounded-xl border bg-card">
336
+ <div className="flex items-center justify-between mb-4">
337
+ <h3 className="font-semibold">Daily Check-In</h3>
338
+ <span className="text-xs text-muted-foreground">Week 12</span>
339
+ </div>
340
+ <WakaDailyReward
341
+ currentDay={4}
342
+ rewards={defaultRewards.map((r, i) => ({ ...r, claimed: i < 3 }))}
343
+ streak={10}
344
+ size="sm"
345
+ />
346
+ </div>
347
+ ),
348
+ }
349
+
350
+ export const CannotClaim: Story = {
351
+ render: () => (
352
+ <div className="space-y-4">
353
+ <p className="text-sm text-muted-foreground text-center">
354
+ Cannot claim - waiting for next day
355
+ </p>
356
+ <WakaDailyReward
357
+ currentDay={3}
358
+ rewards={defaultRewards.map((r, i) => ({ ...r, claimed: i < 3 }))}
359
+ streak={3}
360
+ canClaim={false}
361
+ nextRewardIn={28800}
362
+ />
363
+ </div>
364
+ ),
365
+ }