@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,300 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { WakaLeaderboard, useLeaderboard } from './index'
3
+ import type { LeaderboardEntry } from './index'
4
+ import * as React from 'react'
5
+
6
+ const sampleEntries: LeaderboardEntry[] = [
7
+ { id: '1', rank: 1, name: 'ProGamer123', score: 15420, avatar: 'https://i.pravatar.cc/100?img=1', change: 2, level: 45 },
8
+ { id: '2', rank: 2, name: 'SpeedRunner', score: 14890, avatar: 'https://i.pravatar.cc/100?img=2', change: -1, level: 42 },
9
+ { id: '3', rank: 3, name: 'NightOwl', score: 14350, avatar: 'https://i.pravatar.cc/100?img=3', change: 1, level: 41 },
10
+ { id: '4', rank: 4, name: 'CodeNinja', score: 13920, avatar: 'https://i.pravatar.cc/100?img=4', change: 0, level: 39 },
11
+ { id: '5', rank: 5, name: 'PixelMaster', score: 13500, avatar: 'https://i.pravatar.cc/100?img=5', change: -2, level: 38 },
12
+ { id: '6', rank: 6, name: 'SkyWalker42', score: 12890, avatar: 'https://i.pravatar.cc/100?img=6', change: 3, level: 36 },
13
+ { id: '7', rank: 7, name: 'ByteMe', score: 12450, avatar: 'https://i.pravatar.cc/100?img=7', change: 1, level: 35 },
14
+ { id: '8', rank: 8, name: 'FireStorm', score: 11980, avatar: 'https://i.pravatar.cc/100?img=8', change: -1, level: 34 },
15
+ { id: '9', rank: 9, name: 'CoolCat', score: 11500, avatar: 'https://i.pravatar.cc/100?img=9', change: 0, level: 32 },
16
+ { id: '10', rank: 10, name: 'ZeroHero', score: 11050, avatar: 'https://i.pravatar.cc/100?img=10', change: 2, level: 31 },
17
+ ]
18
+
19
+ const meta: Meta<typeof WakaLeaderboard> = {
20
+ title: 'Components/Gamification/WakaLeaderboard',
21
+ component: WakaLeaderboard,
22
+ parameters: {
23
+ layout: 'centered',
24
+ docs: {
25
+ description: {
26
+ component: 'A leaderboard component with podium display, rank changes, and animations for competitive gamification.',
27
+ },
28
+ },
29
+ },
30
+ tags: ['autodocs'],
31
+ argTypes: {
32
+ variant: {
33
+ control: 'select',
34
+ options: ['default', 'compact', 'podium'],
35
+ description: 'Display variant',
36
+ },
37
+ showPodium: {
38
+ control: 'boolean',
39
+ description: 'Show podium for top 3',
40
+ },
41
+ showRankChange: {
42
+ control: 'boolean',
43
+ description: 'Show rank change indicators',
44
+ },
45
+ animated: {
46
+ control: 'boolean',
47
+ description: 'Enable animations',
48
+ },
49
+ highlightUserId: {
50
+ control: 'text',
51
+ description: 'ID of user to highlight',
52
+ },
53
+ },
54
+ }
55
+
56
+ export default meta
57
+ type Story = StoryObj<typeof WakaLeaderboard>
58
+
59
+ export const Default: Story = {
60
+ args: {
61
+ entries: sampleEntries,
62
+ variant: 'default',
63
+ showPodium: false,
64
+ showRankChange: false,
65
+ animated: true,
66
+ },
67
+ render: (args) => (
68
+ <div className="w-[450px]">
69
+ <WakaLeaderboard {...args} />
70
+ </div>
71
+ ),
72
+ }
73
+
74
+ export const Variants: Story = {
75
+ render: () => (
76
+ <div className="space-y-8">
77
+ <div>
78
+ <p className="text-sm text-muted-foreground mb-2">Default</p>
79
+ <div className="w-[450px]">
80
+ <WakaLeaderboard entries={sampleEntries.slice(0, 5)} variant="default" />
81
+ </div>
82
+ </div>
83
+ <div>
84
+ <p className="text-sm text-muted-foreground mb-2">Compact</p>
85
+ <div className="w-[350px]">
86
+ <WakaLeaderboard entries={sampleEntries.slice(0, 5)} variant="compact" />
87
+ </div>
88
+ </div>
89
+ <div>
90
+ <p className="text-sm text-muted-foreground mb-2">Podium</p>
91
+ <div className="w-[500px]">
92
+ <WakaLeaderboard entries={sampleEntries.slice(0, 5)} variant="podium" showPodium />
93
+ </div>
94
+ </div>
95
+ </div>
96
+ ),
97
+ }
98
+
99
+ export const WithPodium: Story = {
100
+ render: () => (
101
+ <div className="w-[500px]">
102
+ <WakaLeaderboard entries={sampleEntries} showPodium />
103
+ </div>
104
+ ),
105
+ }
106
+
107
+ export const WithRankChanges: Story = {
108
+ render: () => (
109
+ <div className="w-[450px]">
110
+ <WakaLeaderboard entries={sampleEntries} showRankChange />
111
+ </div>
112
+ ),
113
+ }
114
+
115
+ export const HighlightCurrentUser: Story = {
116
+ render: () => (
117
+ <div className="w-[450px]">
118
+ <WakaLeaderboard
119
+ entries={sampleEntries}
120
+ highlightUserId="5"
121
+ showRankChange
122
+ />
123
+ </div>
124
+ ),
125
+ }
126
+
127
+ export const TopThreeOnly: Story = {
128
+ render: () => (
129
+ <div className="w-[400px]">
130
+ <WakaLeaderboard
131
+ entries={sampleEntries.slice(0, 3)}
132
+ showPodium
133
+ variant="podium"
134
+ />
135
+ </div>
136
+ ),
137
+ }
138
+
139
+ export const WithCustomScoreLabel: Story = {
140
+ render: () => (
141
+ <div className="w-[450px]">
142
+ <WakaLeaderboard
143
+ entries={sampleEntries.map(e => ({ ...e, score: Math.round(e.score / 100) }))}
144
+ scoreLabel="Wins"
145
+ showRankChange
146
+ />
147
+ </div>
148
+ ),
149
+ }
150
+
151
+ export const Interactive: Story = {
152
+ render: () => {
153
+ const [entries, setEntries] = React.useState(sampleEntries)
154
+
155
+ const shuffleScores = () => {
156
+ const shuffled = [...entries].map(entry => ({
157
+ ...entry,
158
+ score: entry.score + Math.floor(Math.random() * 1000) - 500,
159
+ change: Math.floor(Math.random() * 5) - 2,
160
+ })).sort((a, b) => b.score - a.score).map((entry, index) => ({
161
+ ...entry,
162
+ rank: index + 1,
163
+ }))
164
+ setEntries(shuffled)
165
+ }
166
+
167
+ return (
168
+ <div className="w-[450px] space-y-4">
169
+ <WakaLeaderboard entries={entries} showPodium showRankChange animated />
170
+ <button
171
+ onClick={shuffleScores}
172
+ className="w-full px-4 py-2 rounded-lg bg-primary text-primary-foreground font-medium hover:bg-primary/90"
173
+ >
174
+ Simulate Score Update
175
+ </button>
176
+ </div>
177
+ )
178
+ },
179
+ }
180
+
181
+ export const WithHook: Story = {
182
+ render: () => {
183
+ const {
184
+ entries,
185
+ updateScore,
186
+ getTopN,
187
+ getUserRank,
188
+ sortBy,
189
+ } = useLeaderboard({
190
+ initialEntries: sampleEntries,
191
+ })
192
+
193
+ return (
194
+ <div className="w-[500px] space-y-4">
195
+ <WakaLeaderboard entries={entries} showPodium showRankChange />
196
+
197
+ <div className="flex gap-2">
198
+ <button
199
+ onClick={() => updateScore('5', sampleEntries[4].score + 5000)}
200
+ className="px-3 py-1.5 text-sm rounded bg-green-500 text-white hover:bg-green-600"
201
+ >
202
+ Boost #5
203
+ </button>
204
+ <button
205
+ onClick={() => sortBy('level')}
206
+ className="px-3 py-1.5 text-sm rounded bg-blue-500 text-white hover:bg-blue-600"
207
+ >
208
+ Sort by Level
209
+ </button>
210
+ <button
211
+ onClick={() => sortBy('score')}
212
+ className="px-3 py-1.5 text-sm rounded border hover:bg-muted"
213
+ >
214
+ Sort by Score
215
+ </button>
216
+ </div>
217
+
218
+ <p className="text-sm text-muted-foreground">
219
+ PixelMaster's rank: #{getUserRank('5')}
220
+ </p>
221
+ </div>
222
+ )
223
+ },
224
+ }
225
+
226
+ export const WeeklyLeaderboard: Story = {
227
+ render: () => (
228
+ <div className="w-[500px] p-6 rounded-xl border bg-card">
229
+ <div className="flex items-center justify-between mb-6">
230
+ <div>
231
+ <h2 className="text-xl font-bold">Weekly Leaderboard</h2>
232
+ <p className="text-sm text-muted-foreground">Resets in 3 days</p>
233
+ </div>
234
+ <div className="flex gap-2">
235
+ <button className="px-3 py-1 text-sm rounded-full bg-primary text-primary-foreground">
236
+ This Week
237
+ </button>
238
+ <button className="px-3 py-1 text-sm rounded-full border hover:bg-muted">
239
+ All Time
240
+ </button>
241
+ </div>
242
+ </div>
243
+ <WakaLeaderboard
244
+ entries={sampleEntries}
245
+ showPodium
246
+ showRankChange
247
+ highlightUserId="7"
248
+ />
249
+ </div>
250
+ ),
251
+ }
252
+
253
+ export const TournamentStandings: Story = {
254
+ render: () => (
255
+ <div className="w-[550px] p-6 rounded-xl border bg-gradient-to-br from-amber-500/10 to-orange-500/10">
256
+ <div className="flex items-center gap-4 mb-6">
257
+ <div className="w-12 h-12 rounded-lg bg-gradient-to-br from-amber-400 to-orange-500 flex items-center justify-center">
258
+ <span className="text-2xl">🏆</span>
259
+ </div>
260
+ <div>
261
+ <h2 className="text-xl font-bold">Summer Championship 2024</h2>
262
+ <p className="text-sm text-muted-foreground">Grand Finals - Round 3</p>
263
+ </div>
264
+ </div>
265
+ <WakaLeaderboard
266
+ entries={sampleEntries.slice(0, 8)}
267
+ showPodium
268
+ showRankChange
269
+ variant="podium"
270
+ />
271
+ <div className="mt-4 pt-4 border-t flex justify-between text-sm">
272
+ <span className="text-muted-foreground">Prize Pool: $10,000</span>
273
+ <span className="font-medium text-amber-500">16 Players Remaining</span>
274
+ </div>
275
+ </div>
276
+ ),
277
+ }
278
+
279
+ export const SmallWidget: Story = {
280
+ render: () => (
281
+ <div className="w-[280px] p-4 rounded-lg border">
282
+ <div className="flex items-center justify-between mb-3">
283
+ <h4 className="text-sm font-semibold">Top Players</h4>
284
+ <a href="#" className="text-xs text-primary hover:underline">View All</a>
285
+ </div>
286
+ <WakaLeaderboard
287
+ entries={sampleEntries.slice(0, 5)}
288
+ variant="compact"
289
+ />
290
+ </div>
291
+ ),
292
+ }
293
+
294
+ export const NoAnimation: Story = {
295
+ render: () => (
296
+ <div className="w-[450px]">
297
+ <WakaLeaderboard entries={sampleEntries} animated={false} />
298
+ </div>
299
+ ),
300
+ }
@@ -0,0 +1,313 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { WakaLevelProgress, useLevelProgress } from './index'
3
+ import * as React from 'react'
4
+
5
+ const meta: Meta<typeof WakaLevelProgress> = {
6
+ title: 'Components/Gamification/WakaLevelProgress',
7
+ component: WakaLevelProgress,
8
+ parameters: {
9
+ layout: 'centered',
10
+ docs: {
11
+ description: {
12
+ component: 'A level progress indicator with milestones, themes, and celebration effects for gamification.',
13
+ },
14
+ },
15
+ },
16
+ tags: ['autodocs'],
17
+ argTypes: {
18
+ level: {
19
+ control: { type: 'number', min: 1, max: 100 },
20
+ description: 'Current level',
21
+ },
22
+ progress: {
23
+ control: { type: 'range', min: 0, max: 100, step: 1 },
24
+ description: 'Progress to next level (0-100)',
25
+ },
26
+ theme: {
27
+ control: 'select',
28
+ options: ['default', 'gold', 'silver', 'bronze', 'emerald', 'ruby'],
29
+ description: 'Color theme',
30
+ },
31
+ size: {
32
+ control: 'select',
33
+ options: ['sm', 'md', 'lg'],
34
+ description: 'Size variant',
35
+ },
36
+ showMilestones: {
37
+ control: 'boolean',
38
+ description: 'Show milestone markers',
39
+ },
40
+ animated: {
41
+ control: 'boolean',
42
+ description: 'Enable animations',
43
+ },
44
+ },
45
+ }
46
+
47
+ export default meta
48
+ type Story = StoryObj<typeof WakaLevelProgress>
49
+
50
+ export const Default: Story = {
51
+ args: {
52
+ level: 15,
53
+ progress: 65,
54
+ theme: 'default',
55
+ size: 'md',
56
+ showMilestones: false,
57
+ animated: true,
58
+ },
59
+ render: (args) => (
60
+ <div className="w-[350px]">
61
+ <WakaLevelProgress {...args} />
62
+ </div>
63
+ ),
64
+ }
65
+
66
+ export const Themes: Story = {
67
+ render: () => (
68
+ <div className="w-[350px] space-y-6">
69
+ <div>
70
+ <p className="text-sm text-muted-foreground mb-2">Default</p>
71
+ <WakaLevelProgress level={10} progress={50} theme="default" />
72
+ </div>
73
+ <div>
74
+ <p className="text-sm text-muted-foreground mb-2">Gold</p>
75
+ <WakaLevelProgress level={25} progress={75} theme="gold" />
76
+ </div>
77
+ <div>
78
+ <p className="text-sm text-muted-foreground mb-2">Silver</p>
79
+ <WakaLevelProgress level={15} progress={40} theme="silver" />
80
+ </div>
81
+ <div>
82
+ <p className="text-sm text-muted-foreground mb-2">Bronze</p>
83
+ <WakaLevelProgress level={5} progress={60} theme="bronze" />
84
+ </div>
85
+ <div>
86
+ <p className="text-sm text-muted-foreground mb-2">Emerald</p>
87
+ <WakaLevelProgress level={30} progress={85} theme="emerald" />
88
+ </div>
89
+ <div>
90
+ <p className="text-sm text-muted-foreground mb-2">Ruby</p>
91
+ <WakaLevelProgress level={50} progress={30} theme="ruby" />
92
+ </div>
93
+ </div>
94
+ ),
95
+ }
96
+
97
+ export const Sizes: Story = {
98
+ render: () => (
99
+ <div className="w-[400px] space-y-6">
100
+ <div>
101
+ <p className="text-sm text-muted-foreground mb-2">Small</p>
102
+ <WakaLevelProgress level={8} progress={45} size="sm" />
103
+ </div>
104
+ <div>
105
+ <p className="text-sm text-muted-foreground mb-2">Medium (Default)</p>
106
+ <WakaLevelProgress level={15} progress={60} size="md" />
107
+ </div>
108
+ <div>
109
+ <p className="text-sm text-muted-foreground mb-2">Large</p>
110
+ <WakaLevelProgress level={25} progress={80} size="lg" />
111
+ </div>
112
+ </div>
113
+ ),
114
+ }
115
+
116
+ export const WithMilestones: Story = {
117
+ render: () => (
118
+ <div className="w-[400px] space-y-6">
119
+ <div>
120
+ <p className="text-sm text-muted-foreground mb-2">With Milestones</p>
121
+ <WakaLevelProgress level={12} progress={70} showMilestones />
122
+ </div>
123
+ <div>
124
+ <p className="text-sm text-muted-foreground mb-2">Without Milestones</p>
125
+ <WakaLevelProgress level={12} progress={70} showMilestones={false} />
126
+ </div>
127
+ </div>
128
+ ),
129
+ }
130
+
131
+ export const ProgressStages: Story = {
132
+ render: () => (
133
+ <div className="w-[400px] space-y-6">
134
+ <div>
135
+ <p className="text-sm text-muted-foreground mb-2">Just Started (10%)</p>
136
+ <WakaLevelProgress level={1} progress={10} theme="bronze" />
137
+ </div>
138
+ <div>
139
+ <p className="text-sm text-muted-foreground mb-2">Quarter Way (25%)</p>
140
+ <WakaLevelProgress level={5} progress={25} theme="silver" />
141
+ </div>
142
+ <div>
143
+ <p className="text-sm text-muted-foreground mb-2">Halfway (50%)</p>
144
+ <WakaLevelProgress level={10} progress={50} theme="default" />
145
+ </div>
146
+ <div>
147
+ <p className="text-sm text-muted-foreground mb-2">Almost There (90%)</p>
148
+ <WakaLevelProgress level={24} progress={90} theme="gold" />
149
+ </div>
150
+ <div>
151
+ <p className="text-sm text-muted-foreground mb-2">Max Level</p>
152
+ <WakaLevelProgress level={100} progress={100} theme="emerald" />
153
+ </div>
154
+ </div>
155
+ ),
156
+ }
157
+
158
+ export const Interactive: Story = {
159
+ render: () => {
160
+ const [level, setLevel] = React.useState(5)
161
+ const [progress, setProgress] = React.useState(30)
162
+
163
+ const gainXP = () => {
164
+ const newProgress = progress + 15
165
+ if (newProgress >= 100) {
166
+ setLevel((prev) => prev + 1)
167
+ setProgress(newProgress - 100)
168
+ } else {
169
+ setProgress(newProgress)
170
+ }
171
+ }
172
+
173
+ return (
174
+ <div className="w-[400px] space-y-4">
175
+ <WakaLevelProgress level={level} progress={progress} theme="gold" showMilestones animated />
176
+
177
+ <div className="flex gap-2">
178
+ <button
179
+ onClick={gainXP}
180
+ className="flex-1 px-4 py-2 rounded-lg bg-amber-500 text-white font-medium hover:bg-amber-600"
181
+ >
182
+ Gain XP (+15%)
183
+ </button>
184
+ <button
185
+ onClick={() => { setLevel(5); setProgress(30) }}
186
+ className="px-4 py-2 rounded-lg border font-medium hover:bg-muted"
187
+ >
188
+ Reset
189
+ </button>
190
+ </div>
191
+
192
+ <p className="text-sm text-muted-foreground text-center">
193
+ Level {level} • {progress}% to next level
194
+ </p>
195
+ </div>
196
+ )
197
+ },
198
+ }
199
+
200
+ export const WithHook: Story = {
201
+ render: () => {
202
+ const {
203
+ level,
204
+ progress,
205
+ addProgress,
206
+ levelUp,
207
+ reset,
208
+ canLevelUp,
209
+ progressToNextLevel,
210
+ } = useLevelProgress({
211
+ initialLevel: 10,
212
+ initialProgress: 45,
213
+ })
214
+
215
+ return (
216
+ <div className="w-[400px] space-y-4">
217
+ <WakaLevelProgress level={level} progress={progress} theme="emerald" showMilestones />
218
+
219
+ <div className="grid grid-cols-2 gap-4 text-center">
220
+ <div className="p-3 rounded-lg border">
221
+ <p className="text-2xl font-bold">{level}</p>
222
+ <p className="text-xs text-muted-foreground">Current Level</p>
223
+ </div>
224
+ <div className="p-3 rounded-lg border">
225
+ <p className="text-2xl font-bold">{progressToNextLevel}%</p>
226
+ <p className="text-xs text-muted-foreground">To Next Level</p>
227
+ </div>
228
+ </div>
229
+
230
+ <div className="flex gap-2 flex-wrap">
231
+ <button
232
+ onClick={() => addProgress(10)}
233
+ className="px-3 py-1.5 text-sm rounded bg-green-500 text-white hover:bg-green-600"
234
+ >
235
+ +10%
236
+ </button>
237
+ <button
238
+ onClick={() => addProgress(25)}
239
+ className="px-3 py-1.5 text-sm rounded bg-blue-500 text-white hover:bg-blue-600"
240
+ >
241
+ +25%
242
+ </button>
243
+ <button
244
+ onClick={levelUp}
245
+ disabled={!canLevelUp}
246
+ className="px-3 py-1.5 text-sm rounded bg-amber-500 text-white hover:bg-amber-600 disabled:opacity-50"
247
+ >
248
+ Level Up
249
+ </button>
250
+ <button
251
+ onClick={reset}
252
+ className="px-3 py-1.5 text-sm rounded border hover:bg-muted"
253
+ >
254
+ Reset
255
+ </button>
256
+ </div>
257
+ </div>
258
+ )
259
+ },
260
+ }
261
+
262
+ export const RankSystem: Story = {
263
+ render: () => (
264
+ <div className="w-[450px] space-y-4">
265
+ <div className="p-4 rounded-xl border bg-gradient-to-r from-amber-900/20 to-yellow-900/20">
266
+ <div className="flex items-center gap-3 mb-3">
267
+ <div className="w-10 h-10 rounded-full bg-gradient-to-br from-amber-400 to-yellow-600 flex items-center justify-center">
268
+ <span className="text-white font-bold text-sm">G</span>
269
+ </div>
270
+ <div>
271
+ <p className="font-bold text-amber-500">Gold Rank</p>
272
+ <p className="text-xs text-muted-foreground">Elite Player</p>
273
+ </div>
274
+ </div>
275
+ <WakaLevelProgress level={25} progress={78} theme="gold" showMilestones />
276
+ </div>
277
+
278
+ <div className="p-4 rounded-xl border bg-gradient-to-r from-slate-900/20 to-gray-900/20">
279
+ <div className="flex items-center gap-3 mb-3">
280
+ <div className="w-10 h-10 rounded-full bg-gradient-to-br from-slate-400 to-gray-600 flex items-center justify-center">
281
+ <span className="text-white font-bold text-sm">S</span>
282
+ </div>
283
+ <div>
284
+ <p className="font-bold text-slate-400">Silver Rank</p>
285
+ <p className="text-xs text-muted-foreground">Skilled Player</p>
286
+ </div>
287
+ </div>
288
+ <WakaLevelProgress level={15} progress={45} theme="silver" showMilestones />
289
+ </div>
290
+
291
+ <div className="p-4 rounded-xl border bg-gradient-to-r from-orange-900/20 to-amber-900/20">
292
+ <div className="flex items-center gap-3 mb-3">
293
+ <div className="w-10 h-10 rounded-full bg-gradient-to-br from-orange-500 to-amber-700 flex items-center justify-center">
294
+ <span className="text-white font-bold text-sm">B</span>
295
+ </div>
296
+ <div>
297
+ <p className="font-bold text-orange-500">Bronze Rank</p>
298
+ <p className="text-xs text-muted-foreground">Rising Player</p>
299
+ </div>
300
+ </div>
301
+ <WakaLevelProgress level={5} progress={20} theme="bronze" showMilestones />
302
+ </div>
303
+ </div>
304
+ ),
305
+ }
306
+
307
+ export const NoAnimation: Story = {
308
+ render: () => (
309
+ <div className="w-[350px]">
310
+ <WakaLevelProgress level={15} progress={65} animated={false} />
311
+ </div>
312
+ ),
313
+ }