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