@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,381 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import { OnCallScheduleBlock, defaultOnCallSchedule } from './index'
|
|
3
|
+
import type { OnCallSchedule, OnCallUser, OnCallShift, EscalationLevel } from './index'
|
|
4
|
+
import * as React from 'react'
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof OnCallScheduleBlock> = {
|
|
7
|
+
title: 'Blocks/OnCallSchedule',
|
|
8
|
+
component: OnCallScheduleBlock,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'fullscreen',
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
'An on-call schedule component with weekly view, escalation policies, team members, current on-call status, and shift management.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
tags: ['autodocs'],
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default meta
|
|
22
|
+
type Story = StoryObj<typeof OnCallScheduleBlock>
|
|
23
|
+
|
|
24
|
+
export const Default: Story = {
|
|
25
|
+
render: () => (
|
|
26
|
+
<div className="p-6">
|
|
27
|
+
<OnCallScheduleBlock
|
|
28
|
+
schedule={defaultOnCallSchedule}
|
|
29
|
+
onEditSchedule={() => console.log('Edit schedule')}
|
|
30
|
+
onAddOverride={(date) => console.log('Add override:', date)}
|
|
31
|
+
onSwapShift={(shift) => console.log('Swap shift:', shift)}
|
|
32
|
+
onContactOnCall={(user) => console.log('Contact:', user)}
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
),
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const CurrentlyOnCall: Story = {
|
|
39
|
+
render: () => {
|
|
40
|
+
// Ensure someone is currently on call
|
|
41
|
+
const now = new Date()
|
|
42
|
+
const currentShift: OnCallShift = {
|
|
43
|
+
id: 'current-shift',
|
|
44
|
+
user: defaultOnCallSchedule.users[0],
|
|
45
|
+
startTime: new Date(now.getTime() - 4 * 3600000), // Started 4 hours ago
|
|
46
|
+
endTime: new Date(now.getTime() + 8 * 3600000), // Ends in 8 hours
|
|
47
|
+
level: 1,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const scheduleWithCurrent: OnCallSchedule = {
|
|
51
|
+
...defaultOnCallSchedule,
|
|
52
|
+
shifts: [currentShift, ...defaultOnCallSchedule.shifts],
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div className="p-6">
|
|
57
|
+
<OnCallScheduleBlock
|
|
58
|
+
schedule={scheduleWithCurrent}
|
|
59
|
+
onContactOnCall={(user) => alert(`Calling ${user.name}...`)}
|
|
60
|
+
/>
|
|
61
|
+
</div>
|
|
62
|
+
)
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const NoCurrentOnCall: Story = {
|
|
67
|
+
render: () => {
|
|
68
|
+
// All shifts in the future
|
|
69
|
+
const futureShifts: OnCallShift[] = defaultOnCallSchedule.shifts.map(shift => ({
|
|
70
|
+
...shift,
|
|
71
|
+
startTime: new Date(Date.now() + 24 * 3600000),
|
|
72
|
+
endTime: new Date(Date.now() + 48 * 3600000),
|
|
73
|
+
}))
|
|
74
|
+
|
|
75
|
+
const scheduleNoOnCall: OnCallSchedule = {
|
|
76
|
+
...defaultOnCallSchedule,
|
|
77
|
+
shifts: futureShifts,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div className="p-6">
|
|
82
|
+
<OnCallScheduleBlock schedule={scheduleNoOnCall} />
|
|
83
|
+
</div>
|
|
84
|
+
)
|
|
85
|
+
},
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const WithOverride: Story = {
|
|
89
|
+
render: () => {
|
|
90
|
+
const now = new Date()
|
|
91
|
+
const overrideShift: OnCallShift = {
|
|
92
|
+
id: 'override-shift',
|
|
93
|
+
user: defaultOnCallSchedule.users[2],
|
|
94
|
+
startTime: new Date(now.getTime() - 2 * 3600000),
|
|
95
|
+
endTime: new Date(now.getTime() + 10 * 3600000),
|
|
96
|
+
level: 1,
|
|
97
|
+
overrideReason: 'Covering for John who is on PTO',
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const scheduleWithOverride: OnCallSchedule = {
|
|
101
|
+
...defaultOnCallSchedule,
|
|
102
|
+
shifts: [overrideShift, ...defaultOnCallSchedule.shifts],
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<div className="p-6">
|
|
107
|
+
<OnCallScheduleBlock
|
|
108
|
+
schedule={scheduleWithOverride}
|
|
109
|
+
onContactOnCall={(user) => console.log('Contact:', user)}
|
|
110
|
+
/>
|
|
111
|
+
</div>
|
|
112
|
+
)
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export const DifferentRotations: Story = {
|
|
117
|
+
render: () => {
|
|
118
|
+
const weeklySchedule: OnCallSchedule = {
|
|
119
|
+
...defaultOnCallSchedule,
|
|
120
|
+
name: 'Backend Team On-Call',
|
|
121
|
+
team: 'Backend Engineering',
|
|
122
|
+
rotation: 'weekly',
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const dailySchedule: OnCallSchedule = {
|
|
126
|
+
...defaultOnCallSchedule,
|
|
127
|
+
id: 'daily',
|
|
128
|
+
name: 'Frontend Team On-Call',
|
|
129
|
+
team: 'Frontend Engineering',
|
|
130
|
+
rotation: 'daily',
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<div className="p-6 space-y-8">
|
|
135
|
+
<OnCallScheduleBlock schedule={weeklySchedule} />
|
|
136
|
+
<OnCallScheduleBlock schedule={dailySchedule} />
|
|
137
|
+
</div>
|
|
138
|
+
)
|
|
139
|
+
},
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const MultipleEscalationLevels: Story = {
|
|
143
|
+
render: () => {
|
|
144
|
+
const now = new Date()
|
|
145
|
+
const multiLevelShifts: OnCallShift[] = [
|
|
146
|
+
{
|
|
147
|
+
id: 'level1-shift',
|
|
148
|
+
user: defaultOnCallSchedule.users[0],
|
|
149
|
+
startTime: new Date(now.getTime() - 4 * 3600000),
|
|
150
|
+
endTime: new Date(now.getTime() + 8 * 3600000),
|
|
151
|
+
level: 1,
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: 'level2-shift',
|
|
155
|
+
user: defaultOnCallSchedule.users[1],
|
|
156
|
+
startTime: new Date(now.getTime() - 4 * 3600000),
|
|
157
|
+
endTime: new Date(now.getTime() + 8 * 3600000),
|
|
158
|
+
level: 2,
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: 'level3-shift',
|
|
162
|
+
user: defaultOnCallSchedule.users[2],
|
|
163
|
+
startTime: new Date(now.getTime() - 4 * 3600000),
|
|
164
|
+
endTime: new Date(now.getTime() + 8 * 3600000),
|
|
165
|
+
level: 3,
|
|
166
|
+
},
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
const multiLevelSchedule: OnCallSchedule = {
|
|
170
|
+
...defaultOnCallSchedule,
|
|
171
|
+
shifts: [...multiLevelShifts, ...defaultOnCallSchedule.shifts],
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<div className="p-6">
|
|
176
|
+
<OnCallScheduleBlock
|
|
177
|
+
schedule={multiLevelSchedule}
|
|
178
|
+
onContactOnCall={(user) => console.log('Contact:', user)}
|
|
179
|
+
/>
|
|
180
|
+
</div>
|
|
181
|
+
)
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export const SmallTeam: Story = {
|
|
186
|
+
render: () => {
|
|
187
|
+
const smallTeam: OnCallUser[] = [
|
|
188
|
+
{ id: '1', name: 'Alice', email: 'alice@example.com', phone: '+1 555-0101', status: 'available' },
|
|
189
|
+
{ id: '2', name: 'Bob', email: 'bob@example.com', phone: '+1 555-0102', status: 'available' },
|
|
190
|
+
]
|
|
191
|
+
|
|
192
|
+
const now = new Date()
|
|
193
|
+
const smallTeamShifts: OnCallShift[] = [
|
|
194
|
+
{
|
|
195
|
+
id: 's1',
|
|
196
|
+
user: smallTeam[0],
|
|
197
|
+
startTime: new Date(now.getTime() - 2 * 3600000),
|
|
198
|
+
endTime: new Date(now.getTime() + 22 * 3600000),
|
|
199
|
+
level: 1,
|
|
200
|
+
},
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
const smallTeamSchedule: OnCallSchedule = {
|
|
204
|
+
id: 'small-team',
|
|
205
|
+
name: 'Startup On-Call',
|
|
206
|
+
team: 'Engineering',
|
|
207
|
+
rotation: 'daily',
|
|
208
|
+
escalationPolicy: {
|
|
209
|
+
level1Timeout: 10,
|
|
210
|
+
level2Timeout: 20,
|
|
211
|
+
level3Timeout: 30,
|
|
212
|
+
},
|
|
213
|
+
shifts: smallTeamShifts,
|
|
214
|
+
users: smallTeam,
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<div className="p-6">
|
|
219
|
+
<OnCallScheduleBlock schedule={smallTeamSchedule} />
|
|
220
|
+
</div>
|
|
221
|
+
)
|
|
222
|
+
},
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export const LargeTeam: Story = {
|
|
226
|
+
render: () => {
|
|
227
|
+
const largeTeam: OnCallUser[] = Array.from({ length: 12 }, (_, i) => ({
|
|
228
|
+
id: `user-${i + 1}`,
|
|
229
|
+
name: `Team Member ${i + 1}`,
|
|
230
|
+
email: `member${i + 1}@example.com`,
|
|
231
|
+
phone: `+1 555-${String(i + 1).padStart(4, '0')}`,
|
|
232
|
+
status: (['available', 'busy', 'available', 'offline'] as const)[i % 4],
|
|
233
|
+
timezone: ['America/New_York', 'America/Los_Angeles', 'Europe/London', 'Asia/Tokyo'][i % 4],
|
|
234
|
+
}))
|
|
235
|
+
|
|
236
|
+
const largeTeamSchedule: OnCallSchedule = {
|
|
237
|
+
...defaultOnCallSchedule,
|
|
238
|
+
name: 'Global Support Team',
|
|
239
|
+
team: 'Customer Support',
|
|
240
|
+
users: largeTeam,
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return (
|
|
244
|
+
<div className="p-6">
|
|
245
|
+
<OnCallScheduleBlock schedule={largeTeamSchedule} />
|
|
246
|
+
</div>
|
|
247
|
+
)
|
|
248
|
+
},
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export const DifferentUserStatuses: Story = {
|
|
252
|
+
render: () => {
|
|
253
|
+
const usersWithStatuses: OnCallUser[] = [
|
|
254
|
+
{ id: '1', name: 'John (Available)', email: 'john@example.com', status: 'available' },
|
|
255
|
+
{ id: '2', name: 'Jane (Busy)', email: 'jane@example.com', status: 'busy' },
|
|
256
|
+
{ id: '3', name: 'Bob (DND)', email: 'bob@example.com', status: 'dnd' },
|
|
257
|
+
{ id: '4', name: 'Alice (Offline)', email: 'alice@example.com', status: 'offline' },
|
|
258
|
+
]
|
|
259
|
+
|
|
260
|
+
const statusSchedule: OnCallSchedule = {
|
|
261
|
+
...defaultOnCallSchedule,
|
|
262
|
+
users: usersWithStatuses,
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<div className="p-6">
|
|
267
|
+
<OnCallScheduleBlock schedule={statusSchedule} />
|
|
268
|
+
</div>
|
|
269
|
+
)
|
|
270
|
+
},
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export const CustomEscalationPolicy: Story = {
|
|
274
|
+
render: () => {
|
|
275
|
+
const criticalSchedule: OnCallSchedule = {
|
|
276
|
+
...defaultOnCallSchedule,
|
|
277
|
+
name: 'Critical Infrastructure',
|
|
278
|
+
team: 'SRE',
|
|
279
|
+
escalationPolicy: {
|
|
280
|
+
level1Timeout: 5, // Very fast escalation
|
|
281
|
+
level2Timeout: 10,
|
|
282
|
+
level3Timeout: 15,
|
|
283
|
+
},
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return (
|
|
287
|
+
<div className="p-6">
|
|
288
|
+
<OnCallScheduleBlock schedule={criticalSchedule} />
|
|
289
|
+
</div>
|
|
290
|
+
)
|
|
291
|
+
},
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export const Interactive: Story = {
|
|
295
|
+
render: () => {
|
|
296
|
+
const [schedule, setSchedule] = React.useState(defaultOnCallSchedule)
|
|
297
|
+
|
|
298
|
+
const handleAddOverride = (date: Date) => {
|
|
299
|
+
alert(`Add override for ${date.toLocaleDateString()}`)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const handleSwapShift = (shift: OnCallShift) => {
|
|
303
|
+
alert(`Swap shift: ${shift.user.name}'s shift on ${shift.startTime.toLocaleDateString()}`)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const handleContact = (user: OnCallUser) => {
|
|
307
|
+
alert(`Contacting ${user.name}:\nEmail: ${user.email}\nPhone: ${user.phone || 'N/A'}`)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const handleEditSchedule = () => {
|
|
311
|
+
alert('Opening schedule editor...')
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return (
|
|
315
|
+
<div className="p-6">
|
|
316
|
+
<OnCallScheduleBlock
|
|
317
|
+
schedule={schedule}
|
|
318
|
+
onEditSchedule={handleEditSchedule}
|
|
319
|
+
onAddOverride={handleAddOverride}
|
|
320
|
+
onSwapShift={handleSwapShift}
|
|
321
|
+
onContactOnCall={handleContact}
|
|
322
|
+
/>
|
|
323
|
+
</div>
|
|
324
|
+
)
|
|
325
|
+
},
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export const ReadOnly: Story = {
|
|
329
|
+
render: () => (
|
|
330
|
+
<div className="p-6">
|
|
331
|
+
<OnCallScheduleBlock schedule={defaultOnCallSchedule} />
|
|
332
|
+
</div>
|
|
333
|
+
),
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export const IncidentDashboard: Story = {
|
|
337
|
+
render: () => {
|
|
338
|
+
const now = new Date()
|
|
339
|
+
const currentOnCall: OnCallShift = {
|
|
340
|
+
id: 'current',
|
|
341
|
+
user: {
|
|
342
|
+
...defaultOnCallSchedule.users[0],
|
|
343
|
+
status: 'available',
|
|
344
|
+
},
|
|
345
|
+
startTime: new Date(now.getTime() - 6 * 3600000),
|
|
346
|
+
endTime: new Date(now.getTime() + 6 * 3600000),
|
|
347
|
+
level: 1,
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const incidentSchedule: OnCallSchedule = {
|
|
351
|
+
...defaultOnCallSchedule,
|
|
352
|
+
shifts: [currentOnCall, ...defaultOnCallSchedule.shifts],
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return (
|
|
356
|
+
<div className="min-h-screen bg-muted/30">
|
|
357
|
+
<header className="bg-background border-b px-6 py-4">
|
|
358
|
+
<div className="flex items-center justify-between">
|
|
359
|
+
<div>
|
|
360
|
+
<h1 className="font-bold text-xl">Incident Management</h1>
|
|
361
|
+
<p className="text-sm text-muted-foreground">On-Call & Escalation</p>
|
|
362
|
+
</div>
|
|
363
|
+
<div className="flex items-center gap-2">
|
|
364
|
+
<span className="text-sm text-muted-foreground">Current incident:</span>
|
|
365
|
+
<span className="px-2 py-1 bg-green-500/10 text-green-600 rounded text-sm font-medium">
|
|
366
|
+
No active incidents
|
|
367
|
+
</span>
|
|
368
|
+
</div>
|
|
369
|
+
</div>
|
|
370
|
+
</header>
|
|
371
|
+
<main className="p-6">
|
|
372
|
+
<OnCallScheduleBlock
|
|
373
|
+
schedule={incidentSchedule}
|
|
374
|
+
onContactOnCall={(user) => console.log('Contact:', user)}
|
|
375
|
+
onAddOverride={(date) => console.log('Override:', date)}
|
|
376
|
+
/>
|
|
377
|
+
</main>
|
|
378
|
+
</div>
|
|
379
|
+
)
|
|
380
|
+
},
|
|
381
|
+
}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import {
|
|
3
|
+
PlayerProfile,
|
|
4
|
+
defaultPlayerStats,
|
|
5
|
+
defaultAchievements,
|
|
6
|
+
defaultBadges,
|
|
7
|
+
defaultMatchHistory,
|
|
8
|
+
} from './index'
|
|
9
|
+
import type { PlayerStats, Achievement, PlayerBadge, MatchHistory } from './index'
|
|
10
|
+
import * as React from 'react'
|
|
11
|
+
import { Trophy, Star, Flame, Crown, Medal, Zap, Target, Shield, Swords, Users, Gamepad2 } from 'lucide-react'
|
|
12
|
+
|
|
13
|
+
const meta: Meta<typeof PlayerProfile> = {
|
|
14
|
+
title: 'Blocks/PlayerProfile',
|
|
15
|
+
component: PlayerProfile,
|
|
16
|
+
parameters: {
|
|
17
|
+
layout: 'centered',
|
|
18
|
+
docs: {
|
|
19
|
+
description: {
|
|
20
|
+
component:
|
|
21
|
+
'A gaming player profile page with XP progression, level display, stats, achievements with rarity tiers, badges, and match history tracking.',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
tags: ['autodocs'],
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default meta
|
|
29
|
+
type Story = StoryObj<typeof PlayerProfile>
|
|
30
|
+
|
|
31
|
+
export const Default: Story = {
|
|
32
|
+
render: () => (
|
|
33
|
+
<div className="p-6 max-w-4xl">
|
|
34
|
+
<PlayerProfile
|
|
35
|
+
name="ShadowHunter"
|
|
36
|
+
title="Elite Warrior"
|
|
37
|
+
level={42}
|
|
38
|
+
currentXP={7500}
|
|
39
|
+
maxXP={10000}
|
|
40
|
+
totalXP={125000}
|
|
41
|
+
rank="Diamond II"
|
|
42
|
+
stats={defaultPlayerStats}
|
|
43
|
+
achievements={defaultAchievements}
|
|
44
|
+
badges={defaultBadges}
|
|
45
|
+
matchHistory={defaultMatchHistory}
|
|
46
|
+
streak={14}
|
|
47
|
+
playtime="245h"
|
|
48
|
+
friendsCount={89}
|
|
49
|
+
isOnline={true}
|
|
50
|
+
joinDate={new Date('2023-06-15')}
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const NewPlayer: Story = {
|
|
57
|
+
render: () => {
|
|
58
|
+
const newPlayerStats: PlayerStats[] = [
|
|
59
|
+
{ label: 'Matches Played', value: 12, icon: <Gamepad2 className="h-5 w-5" />, color: 'blue' },
|
|
60
|
+
{ label: 'Wins', value: 5, icon: <Trophy className="h-5 w-5" />, color: 'green' },
|
|
61
|
+
{ label: 'Win Rate', value: '41.7%', icon: <Target className="h-5 w-5" />, color: 'yellow' },
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
const newPlayerAchievements: Achievement[] = [
|
|
65
|
+
{
|
|
66
|
+
id: 'first-match',
|
|
67
|
+
name: 'Welcome Aboard',
|
|
68
|
+
description: 'Play your first match',
|
|
69
|
+
rarity: 'common',
|
|
70
|
+
unlockedAt: new Date(),
|
|
71
|
+
icon: <Star className="h-6 w-6 text-yellow-500" />,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'first-win',
|
|
75
|
+
name: 'First Victory',
|
|
76
|
+
description: 'Win your first match',
|
|
77
|
+
rarity: 'common',
|
|
78
|
+
progress: 1,
|
|
79
|
+
maxProgress: 1,
|
|
80
|
+
icon: <Trophy className="h-6 w-6 text-yellow-500" />,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'ten-matches',
|
|
84
|
+
name: 'Getting Started',
|
|
85
|
+
description: 'Play 10 matches',
|
|
86
|
+
rarity: 'common',
|
|
87
|
+
progress: 12,
|
|
88
|
+
maxProgress: 10,
|
|
89
|
+
icon: <Gamepad2 className="h-6 w-6 text-blue-500" />,
|
|
90
|
+
},
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<div className="p-6 max-w-4xl">
|
|
95
|
+
<PlayerProfile
|
|
96
|
+
name="NewPlayer123"
|
|
97
|
+
level={3}
|
|
98
|
+
currentXP={350}
|
|
99
|
+
maxXP={500}
|
|
100
|
+
totalXP={850}
|
|
101
|
+
stats={newPlayerStats}
|
|
102
|
+
achievements={newPlayerAchievements}
|
|
103
|
+
matchHistory={defaultMatchHistory.slice(0, 3)}
|
|
104
|
+
streak={2}
|
|
105
|
+
playtime="3h"
|
|
106
|
+
friendsCount={2}
|
|
107
|
+
isOnline={true}
|
|
108
|
+
joinDate={new Date()}
|
|
109
|
+
/>
|
|
110
|
+
</div>
|
|
111
|
+
)
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export const TopPlayer: Story = {
|
|
116
|
+
render: () => {
|
|
117
|
+
const topStats: PlayerStats[] = [
|
|
118
|
+
{ label: 'Matches Played', value: '2,847', icon: <Gamepad2 className="h-5 w-5" />, color: 'blue' },
|
|
119
|
+
{ label: 'Wins', value: '1,923', icon: <Trophy className="h-5 w-5" />, color: 'green' },
|
|
120
|
+
{ label: 'Win Rate', value: '67.5%', icon: <Target className="h-5 w-5" />, color: 'yellow' },
|
|
121
|
+
{ label: 'Best Score', value: '98,450', icon: <Star className="h-5 w-5" />, color: 'purple' },
|
|
122
|
+
{ label: 'Kills', value: '45,230', icon: <Swords className="h-5 w-5" />, color: 'red' },
|
|
123
|
+
{ label: 'MVP Awards', value: 342, icon: <Crown className="h-5 w-5" />, color: 'default' },
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
const legendaryAchievements: Achievement[] = [
|
|
127
|
+
{ id: '1', name: 'Legendary Champion', description: 'Reach the top 100 global ranking', rarity: 'legendary', unlockedAt: new Date('2024-01-15'), icon: <Crown className="h-6 w-6 text-amber-500" /> },
|
|
128
|
+
{ id: '2', name: 'Master Strategist', description: 'Win 1000 matches', rarity: 'legendary', unlockedAt: new Date('2024-02-20'), icon: <Trophy className="h-6 w-6 text-amber-500" /> },
|
|
129
|
+
{ id: '3', name: 'Eternal Flame', description: 'Maintain a 100-day streak', rarity: 'legendary', unlockedAt: new Date('2024-03-01'), icon: <Flame className="h-6 w-6 text-amber-500" /> },
|
|
130
|
+
{ id: '4', name: 'Community Hero', description: 'Have 500 friends', rarity: 'epic', unlockedAt: new Date('2024-01-10'), icon: <Users className="h-6 w-6 text-purple-500" /> },
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
const topBadges: PlayerBadge[] = [
|
|
134
|
+
{ id: '1', name: 'Season 1 Champion', icon: <Crown className="h-4 w-4" />, color: '#f59e0b' },
|
|
135
|
+
{ id: '2', name: 'Top 100', icon: <Medal className="h-4 w-4" />, color: '#ef4444' },
|
|
136
|
+
{ id: '3', name: 'Pro Player', icon: <Zap className="h-4 w-4" />, color: '#8b5cf6' },
|
|
137
|
+
{ id: '4', name: 'Content Creator', icon: <Star className="h-4 w-4" />, color: '#ec4899' },
|
|
138
|
+
{ id: '5', name: 'Beta Veteran', icon: <Shield className="h-4 w-4" />, color: '#3b82f6' },
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<div className="p-6 max-w-4xl">
|
|
143
|
+
<PlayerProfile
|
|
144
|
+
name="xXLegendXx"
|
|
145
|
+
title="Grand Champion"
|
|
146
|
+
level={99}
|
|
147
|
+
currentXP={9500}
|
|
148
|
+
maxXP={10000}
|
|
149
|
+
totalXP={2500000}
|
|
150
|
+
rank="Challenger"
|
|
151
|
+
rankIcon={<Crown className="h-5 w-5 text-amber-500" />}
|
|
152
|
+
stats={topStats}
|
|
153
|
+
achievements={legendaryAchievements}
|
|
154
|
+
badges={topBadges}
|
|
155
|
+
matchHistory={defaultMatchHistory}
|
|
156
|
+
streak={142}
|
|
157
|
+
playtime="2,450h"
|
|
158
|
+
friendsCount={523}
|
|
159
|
+
isOnline={true}
|
|
160
|
+
joinDate={new Date('2022-01-01')}
|
|
161
|
+
/>
|
|
162
|
+
</div>
|
|
163
|
+
)
|
|
164
|
+
},
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export const OfflinePlayer: Story = {
|
|
168
|
+
render: () => (
|
|
169
|
+
<div className="p-6 max-w-4xl">
|
|
170
|
+
<PlayerProfile
|
|
171
|
+
name="GhostRider"
|
|
172
|
+
title="Veteran Player"
|
|
173
|
+
level={56}
|
|
174
|
+
currentXP={2300}
|
|
175
|
+
maxXP={8000}
|
|
176
|
+
totalXP={180000}
|
|
177
|
+
rank="Platinum I"
|
|
178
|
+
stats={defaultPlayerStats}
|
|
179
|
+
achievements={defaultAchievements}
|
|
180
|
+
badges={defaultBadges}
|
|
181
|
+
matchHistory={defaultMatchHistory}
|
|
182
|
+
streak={0}
|
|
183
|
+
playtime="320h"
|
|
184
|
+
friendsCount={45}
|
|
185
|
+
isOnline={false}
|
|
186
|
+
joinDate={new Date('2023-03-20')}
|
|
187
|
+
/>
|
|
188
|
+
</div>
|
|
189
|
+
),
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export const WithAvatar: Story = {
|
|
193
|
+
render: () => (
|
|
194
|
+
<div className="p-6 max-w-4xl">
|
|
195
|
+
<PlayerProfile
|
|
196
|
+
name="AcePlayer"
|
|
197
|
+
avatar="https://api.dicebear.com/7.x/avataaars/svg?seed=AcePlayer"
|
|
198
|
+
title="Rising Star"
|
|
199
|
+
level={28}
|
|
200
|
+
currentXP={4200}
|
|
201
|
+
maxXP={6000}
|
|
202
|
+
totalXP={75000}
|
|
203
|
+
rank="Gold III"
|
|
204
|
+
stats={defaultPlayerStats}
|
|
205
|
+
achievements={defaultAchievements}
|
|
206
|
+
badges={defaultBadges}
|
|
207
|
+
matchHistory={defaultMatchHistory}
|
|
208
|
+
streak={7}
|
|
209
|
+
playtime="120h"
|
|
210
|
+
friendsCount={34}
|
|
211
|
+
isOnline={true}
|
|
212
|
+
joinDate={new Date('2023-09-10')}
|
|
213
|
+
/>
|
|
214
|
+
</div>
|
|
215
|
+
),
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export const MinimalProfile: Story = {
|
|
219
|
+
render: () => (
|
|
220
|
+
<div className="p-6 max-w-4xl">
|
|
221
|
+
<PlayerProfile
|
|
222
|
+
name="CasualGamer"
|
|
223
|
+
level={15}
|
|
224
|
+
currentXP={1200}
|
|
225
|
+
maxXP={2000}
|
|
226
|
+
stats={[
|
|
227
|
+
{ label: 'Matches', value: 45, icon: <Gamepad2 className="h-5 w-5" />, color: 'blue' },
|
|
228
|
+
{ label: 'Wins', value: 18, icon: <Trophy className="h-5 w-5" />, color: 'green' },
|
|
229
|
+
]}
|
|
230
|
+
isOnline={false}
|
|
231
|
+
/>
|
|
232
|
+
</div>
|
|
233
|
+
),
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export const WinStreak: Story = {
|
|
237
|
+
render: () => {
|
|
238
|
+
const winStreakHistory: MatchHistory[] = [
|
|
239
|
+
{ id: '1', result: 'win', score: '5-0', opponent: 'Team Alpha', mode: 'Ranked', date: new Date(Date.now() - 1 * 3600000), xpGained: 250 },
|
|
240
|
+
{ id: '2', result: 'win', score: '3-1', opponent: 'Team Beta', mode: 'Ranked', date: new Date(Date.now() - 2 * 3600000), xpGained: 200 },
|
|
241
|
+
{ id: '3', result: 'win', score: '4-2', opponent: 'Team Gamma', mode: 'Ranked', date: new Date(Date.now() - 3 * 3600000), xpGained: 225 },
|
|
242
|
+
{ id: '4', result: 'win', score: '2-0', opponent: 'Team Delta', mode: 'Ranked', date: new Date(Date.now() - 4 * 3600000), xpGained: 175 },
|
|
243
|
+
{ id: '5', result: 'win', score: '3-0', opponent: 'Team Epsilon', mode: 'Ranked', date: new Date(Date.now() - 5 * 3600000), xpGained: 200 },
|
|
244
|
+
]
|
|
245
|
+
|
|
246
|
+
return (
|
|
247
|
+
<div className="p-6 max-w-4xl">
|
|
248
|
+
<PlayerProfile
|
|
249
|
+
name="OnFirePlayer"
|
|
250
|
+
title="Unstoppable"
|
|
251
|
+
level={67}
|
|
252
|
+
currentXP={8900}
|
|
253
|
+
maxXP={10000}
|
|
254
|
+
totalXP={450000}
|
|
255
|
+
rank="Master"
|
|
256
|
+
rankIcon={<Flame className="h-5 w-5 text-orange-500" />}
|
|
257
|
+
stats={defaultPlayerStats}
|
|
258
|
+
achievements={defaultAchievements}
|
|
259
|
+
badges={[
|
|
260
|
+
{ id: '1', name: 'Hot Streak', icon: <Flame className="h-4 w-4" />, color: '#f97316' },
|
|
261
|
+
...defaultBadges,
|
|
262
|
+
]}
|
|
263
|
+
matchHistory={winStreakHistory}
|
|
264
|
+
streak={28}
|
|
265
|
+
playtime="500h"
|
|
266
|
+
friendsCount={156}
|
|
267
|
+
isOnline={true}
|
|
268
|
+
joinDate={new Date('2023-01-01')}
|
|
269
|
+
/>
|
|
270
|
+
</div>
|
|
271
|
+
)
|
|
272
|
+
},
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export const GameProfile: Story = {
|
|
276
|
+
render: () => (
|
|
277
|
+
<div className="min-h-screen bg-gradient-to-b from-background to-muted/30">
|
|
278
|
+
<header className="bg-background/80 backdrop-blur border-b px-6 py-4">
|
|
279
|
+
<div className="flex items-center justify-between max-w-5xl mx-auto">
|
|
280
|
+
<div className="flex items-center gap-3">
|
|
281
|
+
<Gamepad2 className="h-6 w-6 text-primary" />
|
|
282
|
+
<h1 className="font-bold text-xl">Battle Arena</h1>
|
|
283
|
+
</div>
|
|
284
|
+
<nav className="flex gap-4 text-sm">
|
|
285
|
+
<a href="#" className="text-foreground font-medium">Profile</a>
|
|
286
|
+
<a href="#" className="text-muted-foreground hover:text-foreground">Leaderboard</a>
|
|
287
|
+
<a href="#" className="text-muted-foreground hover:text-foreground">Store</a>
|
|
288
|
+
<a href="#" className="text-muted-foreground hover:text-foreground">Settings</a>
|
|
289
|
+
</nav>
|
|
290
|
+
</div>
|
|
291
|
+
</header>
|
|
292
|
+
<main className="p-6 max-w-5xl mx-auto">
|
|
293
|
+
<PlayerProfile
|
|
294
|
+
name="DragonSlayer"
|
|
295
|
+
avatar="https://api.dicebear.com/7.x/avataaars/svg?seed=DragonSlayer"
|
|
296
|
+
title="Legendary Warrior"
|
|
297
|
+
level={88}
|
|
298
|
+
currentXP={7200}
|
|
299
|
+
maxXP={10000}
|
|
300
|
+
totalXP={1250000}
|
|
301
|
+
rank="Grandmaster"
|
|
302
|
+
rankIcon={<Crown className="h-5 w-5 text-amber-500" />}
|
|
303
|
+
stats={defaultPlayerStats}
|
|
304
|
+
achievements={defaultAchievements}
|
|
305
|
+
badges={defaultBadges}
|
|
306
|
+
matchHistory={defaultMatchHistory}
|
|
307
|
+
streak={45}
|
|
308
|
+
playtime="1,250h"
|
|
309
|
+
friendsCount={234}
|
|
310
|
+
isOnline={true}
|
|
311
|
+
joinDate={new Date('2022-06-01')}
|
|
312
|
+
/>
|
|
313
|
+
</main>
|
|
314
|
+
</div>
|
|
315
|
+
),
|
|
316
|
+
}
|