@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.
- package/dist/blocks/dashboard/index.d.ts +4 -1
- package/dist/blocks/empty-states/index.d.ts +4 -1
- package/dist/blocks/error-pages/index.d.ts +4 -1
- package/dist/blocks/index.d.ts +1 -1
- package/dist/blocks/landing/index.d.ts +4 -1
- package/dist/blocks/pricing/index.d.ts +5 -1
- package/dist/blocks/sidebar/index.d.ts +5 -1
- package/dist/index.cjs.js +130 -130
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +7905 -7856
- package/dist/stories/Button.d.ts +14 -0
- package/dist/stories/Button.stories.d.ts +8 -0
- package/dist/stories/Header.d.ts +11 -0
- package/dist/stories/Header.stories.d.ts +6 -0
- package/dist/stories/Page.d.ts +2 -0
- package/dist/stories/Page.stories.d.ts +6 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/link.d.ts +23 -0
- package/package.json +11 -3
- package/src/blocks/activity-timeline/ActivityTimeline.stories.tsx +460 -0
- package/src/blocks/apm-overview/APMOverview.stories.tsx +435 -0
- package/src/blocks/auth-2fa/Auth2FA.stories.tsx +308 -0
- package/src/blocks/calendar-view/CalendarView.stories.tsx +398 -0
- package/src/blocks/chat/Chat.stories.tsx +466 -0
- package/src/blocks/chat-interface/ChatInterface.stories.tsx +412 -0
- package/src/blocks/checkout-flow/CheckoutFlow.stories.tsx +408 -0
- package/src/blocks/cicd-builder/CICDBuilder.stories.tsx +499 -0
- package/src/blocks/cloud-cost-dashboard/CloudCostDashboard.stories.tsx +356 -0
- package/src/blocks/container-orchestrator/ContainerOrchestrator.stories.tsx +461 -0
- package/src/blocks/dashboard/Dashboard.stories.tsx +559 -0
- package/src/blocks/dashboard/index.tsx +68 -27
- package/src/blocks/dashboard-kpi/DashboardKPI.stories.tsx +422 -0
- package/src/blocks/database-admin/DatabaseAdmin.stories.tsx +393 -0
- package/src/blocks/deployment-dashboard/DeploymentDashboard.stories.tsx +457 -0
- package/src/blocks/empty-states/EmptyStates.stories.tsx +467 -0
- package/src/blocks/empty-states/index.tsx +26 -8
- package/src/blocks/error-pages/ErrorPages.stories.tsx +401 -0
- package/src/blocks/error-pages/index.tsx +26 -8
- package/src/blocks/faq/FAQ.stories.tsx +416 -0
- package/src/blocks/file-manager/FileManager.stories.tsx +413 -0
- package/src/blocks/footer/Footer.stories.tsx +328 -0
- package/src/blocks/gitops-sync-status/GitOpsSyncStatus.stories.tsx +529 -0
- package/src/blocks/header/WakaHeader.stories.tsx +455 -0
- package/src/blocks/headtab/Headtab.stories.tsx +369 -0
- package/src/blocks/i18n-editor/I18nEditor.stories.tsx +451 -0
- package/src/blocks/incident-manager/IncidentManager.stories.tsx +464 -0
- package/src/blocks/index.ts +1 -1
- package/src/blocks/infrastructure-map/InfrastructureMap.stories.tsx +533 -0
- package/src/blocks/kanban-board/KanbanBoard.stories.tsx +494 -0
- package/src/blocks/landing/WakaLanding.stories.tsx +449 -0
- package/src/blocks/landing/index.tsx +125 -66
- package/src/blocks/language-selector/LanguageSelector.stories.tsx +345 -0
- package/src/blocks/layout/Layout.stories.tsx +373 -0
- package/src/blocks/login/Login.stories.tsx +443 -0
- package/src/blocks/on-call-schedule/OnCallSchedule.stories.tsx +381 -0
- package/src/blocks/player-profile/PlayerProfile.stories.tsx +316 -0
- package/src/blocks/pricing/WakaPricing.stories.tsx +530 -0
- package/src/blocks/pricing/index.tsx +38 -4
- package/src/blocks/profile/Profile.stories.tsx +371 -0
- package/src/blocks/release-notes/ReleaseNotes.stories.tsx +431 -0
- package/src/blocks/settings/Settings.stories.tsx +520 -0
- package/src/blocks/sidebar/WakaSidebar.stories.tsx +513 -0
- package/src/blocks/sidebar/index.tsx +49 -20
- package/src/blocks/theme-creator-block/ThemeCreatorBlock.stories.tsx +370 -0
- package/src/blocks/user-management/UserManagement.stories.tsx +411 -0
- package/src/blocks/wizard/Wizard.stories.tsx +683 -0
- package/src/components/accordion/Accordion.stories.tsx +93 -0
- package/src/components/alert/Alert.stories.tsx +95 -0
- package/src/components/alert-dialog/AlertDialog.stories.tsx +126 -0
- package/src/components/aspect-ratio/AspectRatio.stories.tsx +118 -0
- package/src/components/avatar/Avatar.stories.tsx +104 -0
- package/src/components/button/Button.stories.tsx +12 -1
- package/src/components/calendar/Calendar.stories.tsx +102 -0
- package/src/components/card/Card.stories.tsx +125 -0
- package/src/components/checkbox/Checkbox.stories.tsx +100 -0
- package/src/components/code/Code.stories.tsx +402 -0
- package/src/components/collapsible/Collapsible.stories.tsx +123 -0
- package/src/components/command/Command.stories.tsx +207 -0
- package/src/components/context-menu/ContextMenu.stories.tsx +220 -0
- package/src/components/dialog/Dialog.stories.tsx +157 -0
- package/src/components/dropdown-menu/DropdownMenu.stories.tsx +225 -0
- package/src/components/form/Form.stories.tsx +413 -0
- package/src/components/hover-card/HoverCard.stories.tsx +148 -0
- package/src/components/input-otp/InputOTP.stories.tsx +255 -0
- package/src/components/label/Label.stories.tsx +68 -0
- package/src/components/menubar/Menubar.stories.tsx +278 -0
- package/src/components/navigation-menu/NavigationMenu.stories.tsx +202 -0
- package/src/components/popover/Popover.stories.tsx +199 -0
- package/src/components/progress/Progress.stories.tsx +104 -0
- package/src/components/radio-group/RadioGroup.stories.tsx +138 -0
- package/src/components/scroll-area/ScrollArea.stories.tsx +153 -0
- package/src/components/select/Select.stories.tsx +146 -0
- package/src/components/separator/Separator.stories.tsx +117 -0
- package/src/components/sheet/Sheet.stories.tsx +195 -0
- package/src/components/skeleton/Skeleton.stories.tsx +114 -0
- package/src/components/slider/Slider.stories.tsx +157 -0
- package/src/components/switch/Switch.stories.tsx +114 -0
- package/src/components/table/Table.stories.tsx +153 -0
- package/src/components/tabs/Tabs.stories.tsx +155 -0
- package/src/components/textarea/Textarea.stories.tsx +116 -0
- package/src/components/toast/Toast.stories.tsx +160 -0
- package/src/components/toggle/Toggle.stories.tsx +125 -0
- package/src/components/tooltip/Tooltip.stories.tsx +133 -0
- package/src/components/typography/Typography.stories.tsx +207 -0
- package/src/components/waka-3d-pie-chart/Waka3DPieChart.stories.tsx +308 -0
- package/src/components/waka-achievement-unlock/WakaAchievementUnlock.stories.tsx +353 -0
- package/src/components/waka-artifact-list/WakaArtifactList.stories.tsx +258 -0
- package/src/components/waka-autocomplete/WakaAutocomplete.stories.tsx +224 -0
- package/src/components/waka-badge-showcase/WakaBadgeShowcase.stories.tsx +269 -0
- package/src/components/waka-barcode/WakaBarcode.stories.tsx +227 -0
- package/src/components/waka-bottom-sheet/WakaBottomSheet.stories.tsx +408 -0
- package/src/components/waka-breadcrumb/WakaBreadcrumb.stories.tsx +237 -0
- package/src/components/waka-build-matrix/WakaBuildMatrix.stories.tsx +328 -0
- package/src/components/waka-carousel/WakaCarousel.stories.tsx +296 -0
- package/src/components/waka-charts/WakaCharts.stories.tsx +519 -0
- package/src/components/waka-color-picker/WakaColorPicker.stories.tsx +200 -0
- package/src/components/waka-combobox/WakaCombobox.stories.tsx +250 -0
- package/src/components/waka-container-list/WakaContainerList.stories.tsx +315 -0
- package/src/components/waka-contribution-graph/WakaContributionGraph.stories.tsx +354 -0
- package/src/components/waka-cost-breakdown/WakaCostBreakdown.stories.tsx +348 -0
- package/src/components/waka-daily-reward/WakaDailyReward.stories.tsx +365 -0
- package/src/components/waka-database-card/WakaDatabaseCard.stories.tsx +306 -0
- package/src/components/waka-date-range-picker/WakaDateRangePicker.stories.tsx +339 -0
- package/src/components/waka-datetime-picker/WakaDateTimePicker.stories.tsx +317 -0
- package/src/components/waka-deployment-lane/WakaDeploymentLane.stories.tsx +292 -0
- package/src/components/waka-dock/WakaDock.stories.tsx +332 -0
- package/src/components/waka-drawer/WakaDrawer.stories.tsx +437 -0
- package/src/components/waka-env-var-editor/WakaEnvVarEditor.stories.tsx +263 -0
- package/src/components/waka-error-shake/WakaErrorShake.stories.tsx +410 -0
- package/src/components/waka-file-upload/WakaFileUpload.stories.tsx +239 -0
- package/src/components/waka-flow-diagram/WakaFlowDiagram.stories.tsx +365 -0
- package/src/components/waka-funnel-chart/WakaFunnelChart.stories.tsx +281 -0
- package/src/components/waka-glow-card/WakaGlowCard.stories.tsx +274 -0
- package/src/components/waka-haptic-button/WakaHapticButton.stories.tsx +349 -0
- package/src/components/waka-health-pulse/WakaHealthPulse.stories.tsx +293 -0
- package/src/components/waka-heatmap/WakaHeatmap.stories.tsx +376 -0
- package/src/components/waka-image/WakaImage.stories.tsx +255 -0
- package/src/components/waka-incident-timeline/WakaIncidentTimeline.stories.tsx +300 -0
- package/src/components/waka-kanban/WakaKanban.stories.tsx +399 -0
- package/src/components/waka-kubernetes-overview/WakaKubernetesOverview.stories.tsx +281 -0
- package/src/components/waka-leaderboard/WakaLeaderboard.stories.tsx +300 -0
- package/src/components/waka-level-progress/WakaLevelProgress.stories.tsx +313 -0
- package/src/components/waka-loading-orbit/WakaLoadingOrbit.stories.tsx +413 -0
- package/src/components/waka-log-viewer/WakaLogViewer.stories.tsx +312 -0
- package/src/components/waka-loot-box/WakaLootBox.stories.tsx +374 -0
- package/src/components/waka-metric-sparkline/WakaMetricSparkline.stories.tsx +312 -0
- package/src/components/waka-migration-list/WakaMigrationList.stories.tsx +289 -0
- package/src/components/waka-modal/WakaModal.stories.tsx +434 -0
- package/src/components/waka-morph-button/WakaMorphButton.stories.tsx +405 -0
- package/src/components/waka-network-topology/WakaNetworkTopology.stories.tsx +364 -0
- package/src/components/waka-notifications/WakaNotifications.stories.tsx +290 -0
- package/src/components/waka-number-input/WakaNumberInput.stories.tsx +282 -0
- package/src/components/waka-pagination/WakaPagination.stories.tsx +328 -0
- package/src/components/waka-password-strength/WakaPasswordStrength.stories.tsx +318 -0
- package/src/components/waka-pipeline-view/WakaPipelineView.stories.tsx +386 -0
- package/src/components/waka-player-card/WakaPlayerCard.stories.tsx +333 -0
- package/src/components/waka-pod-card/WakaPodCard.stories.tsx +435 -0
- package/src/components/waka-qrcode/WakaQRCode.stories.tsx +232 -0
- package/src/components/waka-query-explain/WakaQueryExplain.stories.tsx +407 -0
- package/src/components/waka-quest-card/WakaQuestCard.stories.tsx +394 -0
- package/src/components/waka-quota-bar/WakaQuotaBar.stories.tsx +435 -0
- package/src/components/waka-radar-score/WakaRadarScore.stories.tsx +372 -0
- package/src/components/waka-resource-gauge/WakaResourceGauge.stories.tsx +366 -0
- package/src/components/waka-rich-text-editor/WakaRichTextEditor.stories.tsx +238 -0
- package/src/components/waka-sankey-diagram/WakaSankeyDiagram.stories.tsx +389 -0
- package/src/components/waka-scratch-card/WakaScratchCard.stories.tsx +388 -0
- package/src/components/waka-secret-card/WakaSecretCard.stories.tsx +314 -0
- package/src/components/waka-segmented-control/WakaSegmentedControl.stories.tsx +309 -0
- package/src/components/waka-server-rack/WakaServerRack.stories.tsx +382 -0
- package/src/components/waka-service-graph/WakaServiceGraph.stories.tsx +262 -0
- package/src/components/waka-skeleton-wave/WakaSkeletonWave.stories.tsx +321 -0
- package/src/components/waka-skill-tree/WakaSkillTree.stories.tsx +308 -0
- package/src/components/waka-spin-wheel/WakaSpinWheel.stories.tsx +368 -0
- package/src/components/waka-spinner/WakaSpinner.stories.tsx +156 -0
- package/src/components/waka-stat/WakaStat.stories.tsx +334 -0
- package/src/components/waka-status-matrix/WakaStatusMatrix.stories.tsx +331 -0
- package/src/components/waka-stepper/WakaStepper.stories.tsx +468 -0
- package/src/components/waka-streak-counter/WakaStreakCounter.stories.tsx +235 -0
- package/src/components/waka-success-explosion/WakaSuccessExplosion.stories.tsx +389 -0
- package/src/components/waka-tabs-morph/WakaTabsMorph.stories.tsx +471 -0
- package/src/components/waka-terminal-output/WakaTerminalOutput.stories.tsx +351 -0
- package/src/components/waka-test-report/WakaTestReport.stories.tsx +322 -0
- package/src/components/waka-tilt-card/WakaTiltCard.stories.tsx +300 -0
- package/src/components/waka-time-picker/WakaTimePicker.stories.tsx +227 -0
- package/src/components/waka-timeline/WakaTimeline.stories.tsx +383 -0
- package/src/components/waka-tournament-bracket/WakaTournamentBracket.stories.tsx +375 -0
- package/src/components/waka-trace-viewer/WakaTraceViewer.stories.tsx +445 -0
- package/src/components/waka-tree/WakaTree.stories.tsx +359 -0
- package/src/components/waka-treemap-chart/WakaTreemapChart.stories.tsx +378 -0
- package/src/components/waka-typewriter/WakaTypewriter.stories.tsx +366 -0
- package/src/components/waka-versus-card/WakaVersusCard.stories.tsx +530 -0
- package/src/components/waka-video/WakaVideo.stories.tsx +203 -0
- package/src/components/waka-virtual-list/WakaVirtualList.stories.tsx +273 -0
- 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
|
+
}
|