@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,413 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import {
|
|
3
|
+
Form,
|
|
4
|
+
FormControl,
|
|
5
|
+
FormDescription,
|
|
6
|
+
FormField,
|
|
7
|
+
FormItem,
|
|
8
|
+
FormLabel,
|
|
9
|
+
FormMessage,
|
|
10
|
+
} from './index'
|
|
11
|
+
import { Input } from '../input'
|
|
12
|
+
import { Button } from '../button'
|
|
13
|
+
import { Textarea } from '../textarea'
|
|
14
|
+
import { Checkbox } from '../checkbox'
|
|
15
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../select'
|
|
16
|
+
import * as React from 'react'
|
|
17
|
+
import { useForm } from 'react-hook-form'
|
|
18
|
+
|
|
19
|
+
const meta: Meta<typeof Form> = {
|
|
20
|
+
title: 'Components/Forms/Form',
|
|
21
|
+
component: Form,
|
|
22
|
+
parameters: {
|
|
23
|
+
layout: 'centered',
|
|
24
|
+
docs: {
|
|
25
|
+
description: {
|
|
26
|
+
component: 'Form components for building accessible forms with React Hook Form.',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
tags: ['autodocs'],
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default meta
|
|
34
|
+
type Story = StoryObj<typeof Form>
|
|
35
|
+
|
|
36
|
+
interface LoginFormData {
|
|
37
|
+
email: string
|
|
38
|
+
password: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const LoginForm: Story = {
|
|
42
|
+
render: function LoginFormDemo() {
|
|
43
|
+
const form = useForm<LoginFormData>({
|
|
44
|
+
defaultValues: {
|
|
45
|
+
email: '',
|
|
46
|
+
password: '',
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const onSubmit = (data: LoginFormData) => {
|
|
51
|
+
console.log('Form submitted:', data)
|
|
52
|
+
alert(`Login: ${data.email}`)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<Form {...form}>
|
|
57
|
+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4 w-[350px]">
|
|
58
|
+
<FormField
|
|
59
|
+
control={form.control}
|
|
60
|
+
name="email"
|
|
61
|
+
rules={{ required: 'Email is required' }}
|
|
62
|
+
render={({ field }) => (
|
|
63
|
+
<FormItem>
|
|
64
|
+
<FormLabel>Email</FormLabel>
|
|
65
|
+
<FormControl>
|
|
66
|
+
<Input type="email" placeholder="email@example.com" {...field} />
|
|
67
|
+
</FormControl>
|
|
68
|
+
<FormMessage />
|
|
69
|
+
</FormItem>
|
|
70
|
+
)}
|
|
71
|
+
/>
|
|
72
|
+
<FormField
|
|
73
|
+
control={form.control}
|
|
74
|
+
name="password"
|
|
75
|
+
rules={{ required: 'Password is required', minLength: { value: 8, message: 'Minimum 8 characters' } }}
|
|
76
|
+
render={({ field }) => (
|
|
77
|
+
<FormItem>
|
|
78
|
+
<FormLabel>Password</FormLabel>
|
|
79
|
+
<FormControl>
|
|
80
|
+
<Input type="password" placeholder="********" {...field} />
|
|
81
|
+
</FormControl>
|
|
82
|
+
<FormMessage />
|
|
83
|
+
</FormItem>
|
|
84
|
+
)}
|
|
85
|
+
/>
|
|
86
|
+
<Button type="submit" className="w-full">
|
|
87
|
+
Sign In
|
|
88
|
+
</Button>
|
|
89
|
+
</form>
|
|
90
|
+
</Form>
|
|
91
|
+
)
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface ContactFormData {
|
|
96
|
+
name: string
|
|
97
|
+
email: string
|
|
98
|
+
subject: string
|
|
99
|
+
message: string
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const ContactForm: Story = {
|
|
103
|
+
render: function ContactFormDemo() {
|
|
104
|
+
const form = useForm<ContactFormData>({
|
|
105
|
+
defaultValues: {
|
|
106
|
+
name: '',
|
|
107
|
+
email: '',
|
|
108
|
+
subject: '',
|
|
109
|
+
message: '',
|
|
110
|
+
},
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
const onSubmit = (data: ContactFormData) => {
|
|
114
|
+
console.log('Contact form:', data)
|
|
115
|
+
alert('Message sent!')
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<Form {...form}>
|
|
120
|
+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4 w-[400px]">
|
|
121
|
+
<div className="grid grid-cols-2 gap-4">
|
|
122
|
+
<FormField
|
|
123
|
+
control={form.control}
|
|
124
|
+
name="name"
|
|
125
|
+
rules={{ required: 'Name is required' }}
|
|
126
|
+
render={({ field }) => (
|
|
127
|
+
<FormItem>
|
|
128
|
+
<FormLabel>Name</FormLabel>
|
|
129
|
+
<FormControl>
|
|
130
|
+
<Input placeholder="Your name" {...field} />
|
|
131
|
+
</FormControl>
|
|
132
|
+
<FormMessage />
|
|
133
|
+
</FormItem>
|
|
134
|
+
)}
|
|
135
|
+
/>
|
|
136
|
+
<FormField
|
|
137
|
+
control={form.control}
|
|
138
|
+
name="email"
|
|
139
|
+
rules={{ required: 'Email is required' }}
|
|
140
|
+
render={({ field }) => (
|
|
141
|
+
<FormItem>
|
|
142
|
+
<FormLabel>Email</FormLabel>
|
|
143
|
+
<FormControl>
|
|
144
|
+
<Input type="email" placeholder="email@example.com" {...field} />
|
|
145
|
+
</FormControl>
|
|
146
|
+
<FormMessage />
|
|
147
|
+
</FormItem>
|
|
148
|
+
)}
|
|
149
|
+
/>
|
|
150
|
+
</div>
|
|
151
|
+
<FormField
|
|
152
|
+
control={form.control}
|
|
153
|
+
name="subject"
|
|
154
|
+
rules={{ required: 'Subject is required' }}
|
|
155
|
+
render={({ field }) => (
|
|
156
|
+
<FormItem>
|
|
157
|
+
<FormLabel>Subject</FormLabel>
|
|
158
|
+
<FormControl>
|
|
159
|
+
<Input placeholder="Subject" {...field} />
|
|
160
|
+
</FormControl>
|
|
161
|
+
<FormMessage />
|
|
162
|
+
</FormItem>
|
|
163
|
+
)}
|
|
164
|
+
/>
|
|
165
|
+
<FormField
|
|
166
|
+
control={form.control}
|
|
167
|
+
name="message"
|
|
168
|
+
rules={{ required: 'Message is required' }}
|
|
169
|
+
render={({ field }) => (
|
|
170
|
+
<FormItem>
|
|
171
|
+
<FormLabel>Message</FormLabel>
|
|
172
|
+
<FormControl>
|
|
173
|
+
<Textarea placeholder="Your message..." rows={4} {...field} />
|
|
174
|
+
</FormControl>
|
|
175
|
+
<FormDescription>
|
|
176
|
+
Please provide as much detail as possible.
|
|
177
|
+
</FormDescription>
|
|
178
|
+
<FormMessage />
|
|
179
|
+
</FormItem>
|
|
180
|
+
)}
|
|
181
|
+
/>
|
|
182
|
+
<Button type="submit" className="w-full">
|
|
183
|
+
Send Message
|
|
184
|
+
</Button>
|
|
185
|
+
</form>
|
|
186
|
+
</Form>
|
|
187
|
+
)
|
|
188
|
+
},
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
interface ProfileFormData {
|
|
192
|
+
username: string
|
|
193
|
+
bio: string
|
|
194
|
+
role: string
|
|
195
|
+
notifications: boolean
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export const ProfileForm: Story = {
|
|
199
|
+
render: function ProfileFormDemo() {
|
|
200
|
+
const form = useForm<ProfileFormData>({
|
|
201
|
+
defaultValues: {
|
|
202
|
+
username: '',
|
|
203
|
+
bio: '',
|
|
204
|
+
role: '',
|
|
205
|
+
notifications: true,
|
|
206
|
+
},
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
const onSubmit = (data: ProfileFormData) => {
|
|
210
|
+
console.log('Profile:', data)
|
|
211
|
+
alert('Profile updated!')
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<Form {...form}>
|
|
216
|
+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6 w-[400px]">
|
|
217
|
+
<FormField
|
|
218
|
+
control={form.control}
|
|
219
|
+
name="username"
|
|
220
|
+
rules={{ required: 'Username is required' }}
|
|
221
|
+
render={({ field }) => (
|
|
222
|
+
<FormItem>
|
|
223
|
+
<FormLabel>Username</FormLabel>
|
|
224
|
+
<FormControl>
|
|
225
|
+
<Input placeholder="username" {...field} />
|
|
226
|
+
</FormControl>
|
|
227
|
+
<FormDescription>
|
|
228
|
+
This is your public display name.
|
|
229
|
+
</FormDescription>
|
|
230
|
+
<FormMessage />
|
|
231
|
+
</FormItem>
|
|
232
|
+
)}
|
|
233
|
+
/>
|
|
234
|
+
<FormField
|
|
235
|
+
control={form.control}
|
|
236
|
+
name="bio"
|
|
237
|
+
render={({ field }) => (
|
|
238
|
+
<FormItem>
|
|
239
|
+
<FormLabel>Bio</FormLabel>
|
|
240
|
+
<FormControl>
|
|
241
|
+
<Textarea placeholder="Tell us about yourself" rows={3} {...field} />
|
|
242
|
+
</FormControl>
|
|
243
|
+
<FormDescription>
|
|
244
|
+
Brief description for your profile.
|
|
245
|
+
</FormDescription>
|
|
246
|
+
<FormMessage />
|
|
247
|
+
</FormItem>
|
|
248
|
+
)}
|
|
249
|
+
/>
|
|
250
|
+
<FormField
|
|
251
|
+
control={form.control}
|
|
252
|
+
name="role"
|
|
253
|
+
rules={{ required: 'Please select a role' }}
|
|
254
|
+
render={({ field }) => (
|
|
255
|
+
<FormItem>
|
|
256
|
+
<FormLabel>Role</FormLabel>
|
|
257
|
+
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
|
258
|
+
<FormControl>
|
|
259
|
+
<SelectTrigger>
|
|
260
|
+
<SelectValue placeholder="Select your role" />
|
|
261
|
+
</SelectTrigger>
|
|
262
|
+
</FormControl>
|
|
263
|
+
<SelectContent>
|
|
264
|
+
<SelectItem value="developer">Developer</SelectItem>
|
|
265
|
+
<SelectItem value="designer">Designer</SelectItem>
|
|
266
|
+
<SelectItem value="manager">Manager</SelectItem>
|
|
267
|
+
<SelectItem value="other">Other</SelectItem>
|
|
268
|
+
</SelectContent>
|
|
269
|
+
</Select>
|
|
270
|
+
<FormMessage />
|
|
271
|
+
</FormItem>
|
|
272
|
+
)}
|
|
273
|
+
/>
|
|
274
|
+
<FormField
|
|
275
|
+
control={form.control}
|
|
276
|
+
name="notifications"
|
|
277
|
+
render={({ field }) => (
|
|
278
|
+
<FormItem className="flex flex-row items-start space-x-3 space-y-0 rounded-md border p-4">
|
|
279
|
+
<FormControl>
|
|
280
|
+
<Checkbox
|
|
281
|
+
checked={field.value}
|
|
282
|
+
onCheckedChange={field.onChange}
|
|
283
|
+
/>
|
|
284
|
+
</FormControl>
|
|
285
|
+
<div className="space-y-1 leading-none">
|
|
286
|
+
<FormLabel>Email notifications</FormLabel>
|
|
287
|
+
<FormDescription>
|
|
288
|
+
Receive emails about account activity.
|
|
289
|
+
</FormDescription>
|
|
290
|
+
</div>
|
|
291
|
+
</FormItem>
|
|
292
|
+
)}
|
|
293
|
+
/>
|
|
294
|
+
<Button type="submit" className="w-full">
|
|
295
|
+
Save Profile
|
|
296
|
+
</Button>
|
|
297
|
+
</form>
|
|
298
|
+
</Form>
|
|
299
|
+
)
|
|
300
|
+
},
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
interface SettingsFormData {
|
|
304
|
+
displayName: string
|
|
305
|
+
email: string
|
|
306
|
+
marketing: boolean
|
|
307
|
+
security: boolean
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export const SettingsForm: Story = {
|
|
311
|
+
render: function SettingsFormDemo() {
|
|
312
|
+
const form = useForm<SettingsFormData>({
|
|
313
|
+
defaultValues: {
|
|
314
|
+
displayName: 'John Doe',
|
|
315
|
+
email: 'john@example.com',
|
|
316
|
+
marketing: false,
|
|
317
|
+
security: true,
|
|
318
|
+
},
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
const onSubmit = (data: SettingsFormData) => {
|
|
322
|
+
console.log('Settings:', data)
|
|
323
|
+
alert('Settings saved!')
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return (
|
|
327
|
+
<Form {...form}>
|
|
328
|
+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6 w-[400px]">
|
|
329
|
+
<div>
|
|
330
|
+
<h3 className="text-lg font-medium">Account Settings</h3>
|
|
331
|
+
<p className="text-sm text-muted-foreground">
|
|
332
|
+
Manage your account preferences
|
|
333
|
+
</p>
|
|
334
|
+
</div>
|
|
335
|
+
<div className="space-y-4">
|
|
336
|
+
<FormField
|
|
337
|
+
control={form.control}
|
|
338
|
+
name="displayName"
|
|
339
|
+
render={({ field }) => (
|
|
340
|
+
<FormItem>
|
|
341
|
+
<FormLabel>Display Name</FormLabel>
|
|
342
|
+
<FormControl>
|
|
343
|
+
<Input {...field} />
|
|
344
|
+
</FormControl>
|
|
345
|
+
<FormMessage />
|
|
346
|
+
</FormItem>
|
|
347
|
+
)}
|
|
348
|
+
/>
|
|
349
|
+
<FormField
|
|
350
|
+
control={form.control}
|
|
351
|
+
name="email"
|
|
352
|
+
render={({ field }) => (
|
|
353
|
+
<FormItem>
|
|
354
|
+
<FormLabel>Email</FormLabel>
|
|
355
|
+
<FormControl>
|
|
356
|
+
<Input type="email" {...field} />
|
|
357
|
+
</FormControl>
|
|
358
|
+
<FormMessage />
|
|
359
|
+
</FormItem>
|
|
360
|
+
)}
|
|
361
|
+
/>
|
|
362
|
+
</div>
|
|
363
|
+
<div>
|
|
364
|
+
<h4 className="text-sm font-medium mb-3">Email Preferences</h4>
|
|
365
|
+
<div className="space-y-3">
|
|
366
|
+
<FormField
|
|
367
|
+
control={form.control}
|
|
368
|
+
name="marketing"
|
|
369
|
+
render={({ field }) => (
|
|
370
|
+
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-3">
|
|
371
|
+
<div className="space-y-0.5">
|
|
372
|
+
<FormLabel className="text-base">Marketing emails</FormLabel>
|
|
373
|
+
<FormDescription>
|
|
374
|
+
Receive product updates and promotions.
|
|
375
|
+
</FormDescription>
|
|
376
|
+
</div>
|
|
377
|
+
<FormControl>
|
|
378
|
+
<Checkbox
|
|
379
|
+
checked={field.value}
|
|
380
|
+
onCheckedChange={field.onChange}
|
|
381
|
+
/>
|
|
382
|
+
</FormControl>
|
|
383
|
+
</FormItem>
|
|
384
|
+
)}
|
|
385
|
+
/>
|
|
386
|
+
<FormField
|
|
387
|
+
control={form.control}
|
|
388
|
+
name="security"
|
|
389
|
+
render={({ field }) => (
|
|
390
|
+
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-3">
|
|
391
|
+
<div className="space-y-0.5">
|
|
392
|
+
<FormLabel className="text-base">Security alerts</FormLabel>
|
|
393
|
+
<FormDescription>
|
|
394
|
+
Get notified about security events.
|
|
395
|
+
</FormDescription>
|
|
396
|
+
</div>
|
|
397
|
+
<FormControl>
|
|
398
|
+
<Checkbox
|
|
399
|
+
checked={field.value}
|
|
400
|
+
onCheckedChange={field.onChange}
|
|
401
|
+
/>
|
|
402
|
+
</FormControl>
|
|
403
|
+
</FormItem>
|
|
404
|
+
)}
|
|
405
|
+
/>
|
|
406
|
+
</div>
|
|
407
|
+
</div>
|
|
408
|
+
<Button type="submit">Save Changes</Button>
|
|
409
|
+
</form>
|
|
410
|
+
</Form>
|
|
411
|
+
)
|
|
412
|
+
},
|
|
413
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import { HoverCard, HoverCardContent, HoverCardTrigger } from './index'
|
|
3
|
+
import { Avatar, AvatarFallback, AvatarImage } from '../avatar'
|
|
4
|
+
import { Button } from '../button'
|
|
5
|
+
import { CalendarDays } from 'lucide-react'
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof HoverCard> = {
|
|
8
|
+
title: 'Components/HoverCard',
|
|
9
|
+
component: HoverCard,
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: 'centered',
|
|
12
|
+
docs: {
|
|
13
|
+
description: {
|
|
14
|
+
component: 'For sighted users to preview content available behind a link.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
tags: ['autodocs'],
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default meta
|
|
22
|
+
type Story = StoryObj<typeof HoverCard>
|
|
23
|
+
|
|
24
|
+
export const Default: Story = {
|
|
25
|
+
args: {},
|
|
26
|
+
render: (args) => (
|
|
27
|
+
<HoverCard {...args}>
|
|
28
|
+
<HoverCardTrigger asChild>
|
|
29
|
+
<Button variant="link">@nextjs</Button>
|
|
30
|
+
</HoverCardTrigger>
|
|
31
|
+
<HoverCardContent className="w-80">
|
|
32
|
+
<div className="flex justify-between space-x-4">
|
|
33
|
+
<Avatar>
|
|
34
|
+
<AvatarImage src="https://github.com/vercel.png" />
|
|
35
|
+
<AvatarFallback>VC</AvatarFallback>
|
|
36
|
+
</Avatar>
|
|
37
|
+
<div className="space-y-1">
|
|
38
|
+
<h4 className="text-sm font-semibold">@nextjs</h4>
|
|
39
|
+
<p className="text-sm">
|
|
40
|
+
The React Framework – created and maintained by @vercel.
|
|
41
|
+
</p>
|
|
42
|
+
<div className="flex items-center pt-2">
|
|
43
|
+
<CalendarDays className="mr-2 h-4 w-4 opacity-70" />{' '}
|
|
44
|
+
<span className="text-xs text-muted-foreground">
|
|
45
|
+
Joined December 2021
|
|
46
|
+
</span>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</HoverCardContent>
|
|
51
|
+
</HoverCard>
|
|
52
|
+
),
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const UserProfile: Story = {
|
|
56
|
+
render: () => (
|
|
57
|
+
<HoverCard>
|
|
58
|
+
<HoverCardTrigger asChild>
|
|
59
|
+
<a href="#" className="text-sm font-medium hover:underline">John Doe</a>
|
|
60
|
+
</HoverCardTrigger>
|
|
61
|
+
<HoverCardContent className="w-80">
|
|
62
|
+
<div className="flex space-x-4">
|
|
63
|
+
<Avatar className="h-12 w-12">
|
|
64
|
+
<AvatarImage src="https://github.com/shadcn.png" />
|
|
65
|
+
<AvatarFallback>JD</AvatarFallback>
|
|
66
|
+
</Avatar>
|
|
67
|
+
<div className="space-y-1">
|
|
68
|
+
<h4 className="text-sm font-semibold">John Doe</h4>
|
|
69
|
+
<p className="text-sm text-muted-foreground">
|
|
70
|
+
Software Engineer at Acme Inc.
|
|
71
|
+
</p>
|
|
72
|
+
<div className="flex items-center gap-4 pt-2 text-xs text-muted-foreground">
|
|
73
|
+
<span><strong className="text-foreground">1.2k</strong> followers</span>
|
|
74
|
+
<span><strong className="text-foreground">342</strong> following</span>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</HoverCardContent>
|
|
79
|
+
</HoverCard>
|
|
80
|
+
),
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const ProductPreview: Story = {
|
|
84
|
+
render: () => (
|
|
85
|
+
<HoverCard>
|
|
86
|
+
<HoverCardTrigger asChild>
|
|
87
|
+
<Button variant="outline">View Product</Button>
|
|
88
|
+
</HoverCardTrigger>
|
|
89
|
+
<HoverCardContent className="w-80">
|
|
90
|
+
<div className="space-y-3">
|
|
91
|
+
<div className="h-32 bg-muted rounded-md" />
|
|
92
|
+
<div>
|
|
93
|
+
<h4 className="font-semibold">Premium Headphones</h4>
|
|
94
|
+
<p className="text-sm text-muted-foreground">
|
|
95
|
+
High-quality wireless headphones with active noise cancellation.
|
|
96
|
+
</p>
|
|
97
|
+
</div>
|
|
98
|
+
<div className="flex items-center justify-between">
|
|
99
|
+
<span className="text-lg font-bold">$299.00</span>
|
|
100
|
+
<span className="text-sm text-green-600">In Stock</span>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</HoverCardContent>
|
|
104
|
+
</HoverCard>
|
|
105
|
+
),
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export const Positions: Story = {
|
|
109
|
+
render: () => (
|
|
110
|
+
<div className="flex gap-8 items-center">
|
|
111
|
+
<HoverCard>
|
|
112
|
+
<HoverCardTrigger asChild>
|
|
113
|
+
<Button variant="outline">Top</Button>
|
|
114
|
+
</HoverCardTrigger>
|
|
115
|
+
<HoverCardContent side="top">
|
|
116
|
+
<p className="text-sm">This appears on top</p>
|
|
117
|
+
</HoverCardContent>
|
|
118
|
+
</HoverCard>
|
|
119
|
+
|
|
120
|
+
<HoverCard>
|
|
121
|
+
<HoverCardTrigger asChild>
|
|
122
|
+
<Button variant="outline">Right</Button>
|
|
123
|
+
</HoverCardTrigger>
|
|
124
|
+
<HoverCardContent side="right">
|
|
125
|
+
<p className="text-sm">This appears on the right</p>
|
|
126
|
+
</HoverCardContent>
|
|
127
|
+
</HoverCard>
|
|
128
|
+
|
|
129
|
+
<HoverCard>
|
|
130
|
+
<HoverCardTrigger asChild>
|
|
131
|
+
<Button variant="outline">Bottom</Button>
|
|
132
|
+
</HoverCardTrigger>
|
|
133
|
+
<HoverCardContent side="bottom">
|
|
134
|
+
<p className="text-sm">This appears on bottom</p>
|
|
135
|
+
</HoverCardContent>
|
|
136
|
+
</HoverCard>
|
|
137
|
+
|
|
138
|
+
<HoverCard>
|
|
139
|
+
<HoverCardTrigger asChild>
|
|
140
|
+
<Button variant="outline">Left</Button>
|
|
141
|
+
</HoverCardTrigger>
|
|
142
|
+
<HoverCardContent side="left">
|
|
143
|
+
<p className="text-sm">This appears on the left</p>
|
|
144
|
+
</HoverCardContent>
|
|
145
|
+
</HoverCard>
|
|
146
|
+
</div>
|
|
147
|
+
),
|
|
148
|
+
}
|