@wakastellar/ui 2.3.4 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/dist/blocks/dashboard/index.d.ts +4 -1
  2. package/dist/blocks/empty-states/index.d.ts +4 -1
  3. package/dist/blocks/error-pages/index.d.ts +4 -1
  4. package/dist/blocks/index.d.ts +1 -1
  5. package/dist/blocks/landing/index.d.ts +4 -1
  6. package/dist/blocks/pricing/index.d.ts +5 -1
  7. package/dist/blocks/sidebar/index.d.ts +5 -1
  8. package/dist/index.cjs.js +130 -130
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.es.js +7905 -7856
  11. package/dist/stories/Button.d.ts +14 -0
  12. package/dist/stories/Button.stories.d.ts +8 -0
  13. package/dist/stories/Header.d.ts +11 -0
  14. package/dist/stories/Header.stories.d.ts +6 -0
  15. package/dist/stories/Page.d.ts +2 -0
  16. package/dist/stories/Page.stories.d.ts +6 -0
  17. package/dist/types/index.d.ts +1 -0
  18. package/dist/types/link.d.ts +23 -0
  19. package/package.json +11 -3
  20. package/src/blocks/activity-timeline/ActivityTimeline.stories.tsx +460 -0
  21. package/src/blocks/apm-overview/APMOverview.stories.tsx +435 -0
  22. package/src/blocks/auth-2fa/Auth2FA.stories.tsx +308 -0
  23. package/src/blocks/calendar-view/CalendarView.stories.tsx +398 -0
  24. package/src/blocks/chat/Chat.stories.tsx +466 -0
  25. package/src/blocks/chat-interface/ChatInterface.stories.tsx +412 -0
  26. package/src/blocks/checkout-flow/CheckoutFlow.stories.tsx +408 -0
  27. package/src/blocks/cicd-builder/CICDBuilder.stories.tsx +499 -0
  28. package/src/blocks/cloud-cost-dashboard/CloudCostDashboard.stories.tsx +356 -0
  29. package/src/blocks/container-orchestrator/ContainerOrchestrator.stories.tsx +461 -0
  30. package/src/blocks/dashboard/Dashboard.stories.tsx +559 -0
  31. package/src/blocks/dashboard/index.tsx +68 -27
  32. package/src/blocks/dashboard-kpi/DashboardKPI.stories.tsx +422 -0
  33. package/src/blocks/database-admin/DatabaseAdmin.stories.tsx +393 -0
  34. package/src/blocks/deployment-dashboard/DeploymentDashboard.stories.tsx +457 -0
  35. package/src/blocks/empty-states/EmptyStates.stories.tsx +467 -0
  36. package/src/blocks/empty-states/index.tsx +26 -8
  37. package/src/blocks/error-pages/ErrorPages.stories.tsx +401 -0
  38. package/src/blocks/error-pages/index.tsx +26 -8
  39. package/src/blocks/faq/FAQ.stories.tsx +416 -0
  40. package/src/blocks/file-manager/FileManager.stories.tsx +413 -0
  41. package/src/blocks/footer/Footer.stories.tsx +328 -0
  42. package/src/blocks/gitops-sync-status/GitOpsSyncStatus.stories.tsx +529 -0
  43. package/src/blocks/header/WakaHeader.stories.tsx +455 -0
  44. package/src/blocks/headtab/Headtab.stories.tsx +369 -0
  45. package/src/blocks/i18n-editor/I18nEditor.stories.tsx +451 -0
  46. package/src/blocks/incident-manager/IncidentManager.stories.tsx +464 -0
  47. package/src/blocks/index.ts +1 -1
  48. package/src/blocks/infrastructure-map/InfrastructureMap.stories.tsx +533 -0
  49. package/src/blocks/kanban-board/KanbanBoard.stories.tsx +494 -0
  50. package/src/blocks/landing/WakaLanding.stories.tsx +449 -0
  51. package/src/blocks/landing/index.tsx +125 -66
  52. package/src/blocks/language-selector/LanguageSelector.stories.tsx +345 -0
  53. package/src/blocks/layout/Layout.stories.tsx +373 -0
  54. package/src/blocks/login/Login.stories.tsx +443 -0
  55. package/src/blocks/on-call-schedule/OnCallSchedule.stories.tsx +381 -0
  56. package/src/blocks/player-profile/PlayerProfile.stories.tsx +316 -0
  57. package/src/blocks/pricing/WakaPricing.stories.tsx +530 -0
  58. package/src/blocks/pricing/index.tsx +38 -4
  59. package/src/blocks/profile/Profile.stories.tsx +371 -0
  60. package/src/blocks/release-notes/ReleaseNotes.stories.tsx +431 -0
  61. package/src/blocks/settings/Settings.stories.tsx +520 -0
  62. package/src/blocks/sidebar/WakaSidebar.stories.tsx +513 -0
  63. package/src/blocks/sidebar/index.tsx +49 -20
  64. package/src/blocks/theme-creator-block/ThemeCreatorBlock.stories.tsx +370 -0
  65. package/src/blocks/user-management/UserManagement.stories.tsx +411 -0
  66. package/src/blocks/wizard/Wizard.stories.tsx +683 -0
  67. package/src/components/accordion/Accordion.stories.tsx +93 -0
  68. package/src/components/alert/Alert.stories.tsx +95 -0
  69. package/src/components/alert-dialog/AlertDialog.stories.tsx +126 -0
  70. package/src/components/aspect-ratio/AspectRatio.stories.tsx +118 -0
  71. package/src/components/avatar/Avatar.stories.tsx +104 -0
  72. package/src/components/button/Button.stories.tsx +12 -1
  73. package/src/components/calendar/Calendar.stories.tsx +102 -0
  74. package/src/components/card/Card.stories.tsx +125 -0
  75. package/src/components/checkbox/Checkbox.stories.tsx +100 -0
  76. package/src/components/code/Code.stories.tsx +402 -0
  77. package/src/components/collapsible/Collapsible.stories.tsx +123 -0
  78. package/src/components/command/Command.stories.tsx +207 -0
  79. package/src/components/context-menu/ContextMenu.stories.tsx +220 -0
  80. package/src/components/dialog/Dialog.stories.tsx +157 -0
  81. package/src/components/dropdown-menu/DropdownMenu.stories.tsx +225 -0
  82. package/src/components/form/Form.stories.tsx +413 -0
  83. package/src/components/hover-card/HoverCard.stories.tsx +148 -0
  84. package/src/components/input-otp/InputOTP.stories.tsx +255 -0
  85. package/src/components/label/Label.stories.tsx +68 -0
  86. package/src/components/menubar/Menubar.stories.tsx +278 -0
  87. package/src/components/navigation-menu/NavigationMenu.stories.tsx +202 -0
  88. package/src/components/popover/Popover.stories.tsx +199 -0
  89. package/src/components/progress/Progress.stories.tsx +104 -0
  90. package/src/components/radio-group/RadioGroup.stories.tsx +138 -0
  91. package/src/components/scroll-area/ScrollArea.stories.tsx +153 -0
  92. package/src/components/select/Select.stories.tsx +146 -0
  93. package/src/components/separator/Separator.stories.tsx +117 -0
  94. package/src/components/sheet/Sheet.stories.tsx +195 -0
  95. package/src/components/skeleton/Skeleton.stories.tsx +114 -0
  96. package/src/components/slider/Slider.stories.tsx +157 -0
  97. package/src/components/switch/Switch.stories.tsx +114 -0
  98. package/src/components/table/Table.stories.tsx +153 -0
  99. package/src/components/tabs/Tabs.stories.tsx +155 -0
  100. package/src/components/textarea/Textarea.stories.tsx +116 -0
  101. package/src/components/toast/Toast.stories.tsx +160 -0
  102. package/src/components/toggle/Toggle.stories.tsx +125 -0
  103. package/src/components/tooltip/Tooltip.stories.tsx +133 -0
  104. package/src/components/typography/Typography.stories.tsx +207 -0
  105. package/src/components/waka-3d-pie-chart/Waka3DPieChart.stories.tsx +308 -0
  106. package/src/components/waka-achievement-unlock/WakaAchievementUnlock.stories.tsx +353 -0
  107. package/src/components/waka-artifact-list/WakaArtifactList.stories.tsx +258 -0
  108. package/src/components/waka-autocomplete/WakaAutocomplete.stories.tsx +224 -0
  109. package/src/components/waka-badge-showcase/WakaBadgeShowcase.stories.tsx +269 -0
  110. package/src/components/waka-barcode/WakaBarcode.stories.tsx +227 -0
  111. package/src/components/waka-bottom-sheet/WakaBottomSheet.stories.tsx +408 -0
  112. package/src/components/waka-breadcrumb/WakaBreadcrumb.stories.tsx +237 -0
  113. package/src/components/waka-build-matrix/WakaBuildMatrix.stories.tsx +328 -0
  114. package/src/components/waka-carousel/WakaCarousel.stories.tsx +296 -0
  115. package/src/components/waka-charts/WakaCharts.stories.tsx +519 -0
  116. package/src/components/waka-color-picker/WakaColorPicker.stories.tsx +200 -0
  117. package/src/components/waka-combobox/WakaCombobox.stories.tsx +250 -0
  118. package/src/components/waka-container-list/WakaContainerList.stories.tsx +315 -0
  119. package/src/components/waka-contribution-graph/WakaContributionGraph.stories.tsx +354 -0
  120. package/src/components/waka-cost-breakdown/WakaCostBreakdown.stories.tsx +348 -0
  121. package/src/components/waka-daily-reward/WakaDailyReward.stories.tsx +365 -0
  122. package/src/components/waka-database-card/WakaDatabaseCard.stories.tsx +306 -0
  123. package/src/components/waka-date-range-picker/WakaDateRangePicker.stories.tsx +339 -0
  124. package/src/components/waka-datetime-picker/WakaDateTimePicker.stories.tsx +317 -0
  125. package/src/components/waka-deployment-lane/WakaDeploymentLane.stories.tsx +292 -0
  126. package/src/components/waka-dock/WakaDock.stories.tsx +332 -0
  127. package/src/components/waka-drawer/WakaDrawer.stories.tsx +437 -0
  128. package/src/components/waka-env-var-editor/WakaEnvVarEditor.stories.tsx +263 -0
  129. package/src/components/waka-error-shake/WakaErrorShake.stories.tsx +410 -0
  130. package/src/components/waka-file-upload/WakaFileUpload.stories.tsx +239 -0
  131. package/src/components/waka-flow-diagram/WakaFlowDiagram.stories.tsx +365 -0
  132. package/src/components/waka-funnel-chart/WakaFunnelChart.stories.tsx +281 -0
  133. package/src/components/waka-glow-card/WakaGlowCard.stories.tsx +274 -0
  134. package/src/components/waka-haptic-button/WakaHapticButton.stories.tsx +349 -0
  135. package/src/components/waka-health-pulse/WakaHealthPulse.stories.tsx +293 -0
  136. package/src/components/waka-heatmap/WakaHeatmap.stories.tsx +376 -0
  137. package/src/components/waka-image/WakaImage.stories.tsx +255 -0
  138. package/src/components/waka-incident-timeline/WakaIncidentTimeline.stories.tsx +300 -0
  139. package/src/components/waka-kanban/WakaKanban.stories.tsx +399 -0
  140. package/src/components/waka-kubernetes-overview/WakaKubernetesOverview.stories.tsx +281 -0
  141. package/src/components/waka-leaderboard/WakaLeaderboard.stories.tsx +300 -0
  142. package/src/components/waka-level-progress/WakaLevelProgress.stories.tsx +313 -0
  143. package/src/components/waka-loading-orbit/WakaLoadingOrbit.stories.tsx +413 -0
  144. package/src/components/waka-log-viewer/WakaLogViewer.stories.tsx +312 -0
  145. package/src/components/waka-loot-box/WakaLootBox.stories.tsx +374 -0
  146. package/src/components/waka-metric-sparkline/WakaMetricSparkline.stories.tsx +312 -0
  147. package/src/components/waka-migration-list/WakaMigrationList.stories.tsx +289 -0
  148. package/src/components/waka-modal/WakaModal.stories.tsx +434 -0
  149. package/src/components/waka-morph-button/WakaMorphButton.stories.tsx +405 -0
  150. package/src/components/waka-network-topology/WakaNetworkTopology.stories.tsx +364 -0
  151. package/src/components/waka-notifications/WakaNotifications.stories.tsx +290 -0
  152. package/src/components/waka-number-input/WakaNumberInput.stories.tsx +282 -0
  153. package/src/components/waka-pagination/WakaPagination.stories.tsx +328 -0
  154. package/src/components/waka-password-strength/WakaPasswordStrength.stories.tsx +318 -0
  155. package/src/components/waka-pipeline-view/WakaPipelineView.stories.tsx +386 -0
  156. package/src/components/waka-player-card/WakaPlayerCard.stories.tsx +333 -0
  157. package/src/components/waka-pod-card/WakaPodCard.stories.tsx +435 -0
  158. package/src/components/waka-qrcode/WakaQRCode.stories.tsx +232 -0
  159. package/src/components/waka-query-explain/WakaQueryExplain.stories.tsx +407 -0
  160. package/src/components/waka-quest-card/WakaQuestCard.stories.tsx +394 -0
  161. package/src/components/waka-quota-bar/WakaQuotaBar.stories.tsx +435 -0
  162. package/src/components/waka-radar-score/WakaRadarScore.stories.tsx +372 -0
  163. package/src/components/waka-resource-gauge/WakaResourceGauge.stories.tsx +366 -0
  164. package/src/components/waka-rich-text-editor/WakaRichTextEditor.stories.tsx +238 -0
  165. package/src/components/waka-sankey-diagram/WakaSankeyDiagram.stories.tsx +389 -0
  166. package/src/components/waka-scratch-card/WakaScratchCard.stories.tsx +388 -0
  167. package/src/components/waka-secret-card/WakaSecretCard.stories.tsx +314 -0
  168. package/src/components/waka-segmented-control/WakaSegmentedControl.stories.tsx +309 -0
  169. package/src/components/waka-server-rack/WakaServerRack.stories.tsx +382 -0
  170. package/src/components/waka-service-graph/WakaServiceGraph.stories.tsx +262 -0
  171. package/src/components/waka-skeleton-wave/WakaSkeletonWave.stories.tsx +321 -0
  172. package/src/components/waka-skill-tree/WakaSkillTree.stories.tsx +308 -0
  173. package/src/components/waka-spin-wheel/WakaSpinWheel.stories.tsx +368 -0
  174. package/src/components/waka-spinner/WakaSpinner.stories.tsx +156 -0
  175. package/src/components/waka-stat/WakaStat.stories.tsx +334 -0
  176. package/src/components/waka-status-matrix/WakaStatusMatrix.stories.tsx +331 -0
  177. package/src/components/waka-stepper/WakaStepper.stories.tsx +468 -0
  178. package/src/components/waka-streak-counter/WakaStreakCounter.stories.tsx +235 -0
  179. package/src/components/waka-success-explosion/WakaSuccessExplosion.stories.tsx +389 -0
  180. package/src/components/waka-tabs-morph/WakaTabsMorph.stories.tsx +471 -0
  181. package/src/components/waka-terminal-output/WakaTerminalOutput.stories.tsx +351 -0
  182. package/src/components/waka-test-report/WakaTestReport.stories.tsx +322 -0
  183. package/src/components/waka-tilt-card/WakaTiltCard.stories.tsx +300 -0
  184. package/src/components/waka-time-picker/WakaTimePicker.stories.tsx +227 -0
  185. package/src/components/waka-timeline/WakaTimeline.stories.tsx +383 -0
  186. package/src/components/waka-tournament-bracket/WakaTournamentBracket.stories.tsx +375 -0
  187. package/src/components/waka-trace-viewer/WakaTraceViewer.stories.tsx +445 -0
  188. package/src/components/waka-tree/WakaTree.stories.tsx +359 -0
  189. package/src/components/waka-treemap-chart/WakaTreemapChart.stories.tsx +378 -0
  190. package/src/components/waka-typewriter/WakaTypewriter.stories.tsx +366 -0
  191. package/src/components/waka-versus-card/WakaVersusCard.stories.tsx +530 -0
  192. package/src/components/waka-video/WakaVideo.stories.tsx +203 -0
  193. package/src/components/waka-virtual-list/WakaVirtualList.stories.tsx +273 -0
  194. package/src/components/waka-xp-bar/WakaXPBar.stories.tsx +305 -0
@@ -0,0 +1,530 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { WakaPricing, defaultPricingPlans, defaultPricingFAQ } from './index'
3
+ import type { PricingPlan, PricingFAQ } from './index'
4
+ import * as React from 'react'
5
+
6
+ const MockLink = ({ href, children, ...props }: any) => (
7
+ <a href={href} {...props} onClick={(e) => e.preventDefault()}>
8
+ {children}
9
+ </a>
10
+ )
11
+
12
+ const meta: Meta<typeof WakaPricing> = {
13
+ title: 'Blocks/Pricing',
14
+ component: WakaPricing,
15
+ parameters: {
16
+ layout: 'fullscreen',
17
+ docs: {
18
+ description: {
19
+ component:
20
+ 'A pricing section with plan cards, comparison table, billing toggle, and FAQ. Supports monthly/yearly pricing.',
21
+ },
22
+ },
23
+ },
24
+ tags: ['autodocs'],
25
+ argTypes: {
26
+ layout: {
27
+ control: 'select',
28
+ options: ['cards', 'table'],
29
+ },
30
+ columns: {
31
+ control: 'select',
32
+ options: [2, 3, 4],
33
+ },
34
+ showBillingToggle: {
35
+ control: 'boolean',
36
+ },
37
+ showComparison: {
38
+ control: 'boolean',
39
+ },
40
+ },
41
+ }
42
+
43
+ export default meta
44
+ type Story = StoryObj<typeof WakaPricing>
45
+
46
+ export const Default: Story = {
47
+ render: () => (
48
+ <WakaPricing
49
+ title="Choose your plan"
50
+ description="Start free and scale as you grow. No hidden fees."
51
+ plans={defaultPricingPlans}
52
+ yearlyDiscount="20%"
53
+ faq={defaultPricingFAQ}
54
+ LinkComponent={MockLink}
55
+ />
56
+ ),
57
+ }
58
+
59
+ export const WithoutBillingToggle: Story = {
60
+ render: () => (
61
+ <WakaPricing
62
+ title="Simple Pricing"
63
+ description="One price, all features included."
64
+ plans={defaultPricingPlans}
65
+ showBillingToggle={false}
66
+ LinkComponent={MockLink}
67
+ />
68
+ ),
69
+ }
70
+
71
+ export const TwoPlans: Story = {
72
+ render: () => {
73
+ const twoPlans: PricingPlan[] = [
74
+ {
75
+ id: 'starter',
76
+ name: 'Starter',
77
+ description: 'For individuals',
78
+ price: 9,
79
+ priceYearly: 7,
80
+ features: [
81
+ { name: '1 user', included: true },
82
+ { name: '10 projects', included: true },
83
+ { name: 'Basic support', included: true },
84
+ { name: 'API access', included: false },
85
+ ],
86
+ buttonText: 'Get Started',
87
+ buttonVariant: 'outline',
88
+ },
89
+ {
90
+ id: 'pro',
91
+ name: 'Pro',
92
+ description: 'For teams',
93
+ price: 29,
94
+ priceYearly: 24,
95
+ popular: true,
96
+ features: [
97
+ { name: 'Unlimited users', included: true },
98
+ { name: 'Unlimited projects', included: true },
99
+ { name: 'Priority support', included: true },
100
+ { name: 'API access', included: true },
101
+ ],
102
+ buttonText: 'Start Free Trial',
103
+ },
104
+ ]
105
+
106
+ return (
107
+ <WakaPricing
108
+ title="Pick a plan"
109
+ plans={twoPlans}
110
+ columns={2}
111
+ yearlyDiscount="20%"
112
+ LinkComponent={MockLink}
113
+ />
114
+ )
115
+ },
116
+ }
117
+
118
+ export const FourPlans: Story = {
119
+ render: () => {
120
+ const fourPlans: PricingPlan[] = [
121
+ {
122
+ id: 'hobby',
123
+ name: 'Hobby',
124
+ price: 0,
125
+ features: [
126
+ { name: '1 user', included: true },
127
+ { name: '3 projects', included: true },
128
+ { name: 'Community support', included: true },
129
+ ],
130
+ buttonText: 'Start Free',
131
+ buttonVariant: 'outline',
132
+ },
133
+ {
134
+ id: 'starter',
135
+ name: 'Starter',
136
+ price: 15,
137
+ priceYearly: 12,
138
+ features: [
139
+ { name: '3 users', included: true },
140
+ { name: '10 projects', included: true },
141
+ { name: 'Email support', included: true },
142
+ ],
143
+ buttonText: 'Get Started',
144
+ buttonVariant: 'outline',
145
+ },
146
+ {
147
+ id: 'pro',
148
+ name: 'Pro',
149
+ price: 49,
150
+ priceYearly: 39,
151
+ popular: true,
152
+ features: [
153
+ { name: '10 users', included: true },
154
+ { name: 'Unlimited projects', included: true },
155
+ { name: 'Priority support', included: true },
156
+ ],
157
+ buttonText: 'Start Trial',
158
+ },
159
+ {
160
+ id: 'enterprise',
161
+ name: 'Enterprise',
162
+ price: 'Custom',
163
+ features: [
164
+ { name: 'Unlimited users', included: true },
165
+ { name: 'Unlimited everything', included: true },
166
+ { name: 'Dedicated support', included: true },
167
+ ],
168
+ buttonText: 'Contact Sales',
169
+ buttonVariant: 'outline',
170
+ },
171
+ ]
172
+
173
+ return (
174
+ <WakaPricing
175
+ title="Plans for every team"
176
+ plans={fourPlans}
177
+ columns={4}
178
+ yearlyDiscount="20%"
179
+ LinkComponent={MockLink}
180
+ />
181
+ )
182
+ },
183
+ }
184
+
185
+ export const TableLayout: Story = {
186
+ render: () => (
187
+ <WakaPricing
188
+ title="Compare Plans"
189
+ description="See all features side by side"
190
+ plans={defaultPricingPlans}
191
+ layout="table"
192
+ showComparison
193
+ yearlyDiscount="20%"
194
+ LinkComponent={MockLink}
195
+ />
196
+ ),
197
+ }
198
+
199
+ export const WithFAQ: Story = {
200
+ render: () => {
201
+ const customFAQ: PricingFAQ[] = [
202
+ {
203
+ question: 'What payment methods do you accept?',
204
+ answer: 'We accept all major credit cards (Visa, Mastercard, Amex), PayPal, and wire transfers for enterprise customers.',
205
+ },
206
+ {
207
+ question: 'Can I change plans later?',
208
+ answer: 'Yes! You can upgrade or downgrade your plan at any time. Changes take effect immediately.',
209
+ },
210
+ {
211
+ question: 'Is there a free trial?',
212
+ answer: 'Yes, all paid plans include a 14-day free trial. No credit card required.',
213
+ },
214
+ {
215
+ question: 'What happens if I exceed my limits?',
216
+ answer: "We'll notify you when you're approaching your limits. You can upgrade or we'll help you optimize your usage.",
217
+ },
218
+ {
219
+ question: 'Do you offer refunds?',
220
+ answer: 'Yes, we offer a 30-day money-back guarantee for all paid plans.',
221
+ },
222
+ {
223
+ question: 'Is there a discount for nonprofits?',
224
+ answer: 'Yes! Nonprofits and educational institutions get 50% off all plans. Contact us for details.',
225
+ },
226
+ ]
227
+
228
+ return (
229
+ <WakaPricing
230
+ title="Pricing"
231
+ plans={defaultPricingPlans}
232
+ yearlyDiscount="20%"
233
+ faq={customFAQ}
234
+ faqTitle="Frequently Asked Questions"
235
+ LinkComponent={MockLink}
236
+ />
237
+ )
238
+ },
239
+ }
240
+
241
+ export const ControlledBillingPeriod: Story = {
242
+ render: () => {
243
+ const [period, setPeriod] = React.useState<'monthly' | 'yearly'>('monthly')
244
+
245
+ return (
246
+ <div>
247
+ <div className="text-center mb-4">
248
+ <p className="text-sm text-muted-foreground">
249
+ Current period: <strong>{period}</strong>
250
+ </p>
251
+ </div>
252
+ <WakaPricing
253
+ title="Pricing"
254
+ plans={defaultPricingPlans}
255
+ billingPeriod={period}
256
+ onBillingPeriodChange={setPeriod}
257
+ yearlyDiscount="20%"
258
+ LinkComponent={MockLink}
259
+ />
260
+ </div>
261
+ )
262
+ },
263
+ }
264
+
265
+ export const WithTooltips: Story = {
266
+ render: () => {
267
+ const plansWithTooltips: PricingPlan[] = [
268
+ {
269
+ id: 'basic',
270
+ name: 'Basic',
271
+ price: 0,
272
+ features: [
273
+ { name: 'Storage', included: true, value: '5 GB', tooltip: 'Cloud storage for your files' },
274
+ { name: 'API calls', included: 'limited', value: '1K/month', tooltip: 'Number of API requests per month' },
275
+ { name: 'Support', included: true, tooltip: 'Community forum support' },
276
+ { name: 'Analytics', included: false, tooltip: 'Advanced analytics and reporting' },
277
+ ],
278
+ buttonText: 'Start Free',
279
+ buttonVariant: 'outline',
280
+ },
281
+ {
282
+ id: 'pro',
283
+ name: 'Pro',
284
+ price: 29,
285
+ priceYearly: 24,
286
+ popular: true,
287
+ features: [
288
+ { name: 'Storage', included: true, value: '100 GB', tooltip: 'Cloud storage for your files' },
289
+ { name: 'API calls', included: true, value: '100K/month', tooltip: 'Number of API requests per month' },
290
+ { name: 'Support', included: true, tooltip: 'Priority email support' },
291
+ { name: 'Analytics', included: true, tooltip: 'Advanced analytics and reporting' },
292
+ ],
293
+ buttonText: 'Start Trial',
294
+ },
295
+ {
296
+ id: 'enterprise',
297
+ name: 'Enterprise',
298
+ price: 'Custom',
299
+ features: [
300
+ { name: 'Storage', included: true, value: 'Unlimited', tooltip: 'No storage limits' },
301
+ { name: 'API calls', included: true, value: 'Unlimited', tooltip: 'No API rate limits' },
302
+ { name: 'Support', included: true, tooltip: 'Dedicated account manager + SLA' },
303
+ { name: 'Analytics', included: true, tooltip: 'Custom analytics and white-label reports' },
304
+ ],
305
+ buttonText: 'Contact Sales',
306
+ buttonVariant: 'outline',
307
+ },
308
+ ]
309
+
310
+ return (
311
+ <WakaPricing
312
+ title="Compare Features"
313
+ description="Hover over features to learn more"
314
+ plans={plansWithTooltips}
315
+ yearlyDiscount="20%"
316
+ LinkComponent={MockLink}
317
+ />
318
+ )
319
+ },
320
+ }
321
+
322
+ export const CustomCurrency: Story = {
323
+ render: () => {
324
+ const euroPlans: PricingPlan[] = [
325
+ {
326
+ id: 'basic',
327
+ name: 'Basic',
328
+ price: 0,
329
+ currency: '€',
330
+ features: [
331
+ { name: '1 utilisateur', included: true },
332
+ { name: '5 projets', included: true },
333
+ ],
334
+ buttonText: 'Commencer',
335
+ buttonVariant: 'outline',
336
+ },
337
+ {
338
+ id: 'pro',
339
+ name: 'Pro',
340
+ price: 25,
341
+ priceYearly: 20,
342
+ currency: '€',
343
+ period: '/mois',
344
+ periodYearly: '/mois (facturé annuellement)',
345
+ popular: true,
346
+ features: [
347
+ { name: '5 utilisateurs', included: true },
348
+ { name: 'Projets illimités', included: true },
349
+ ],
350
+ buttonText: 'Essai gratuit',
351
+ },
352
+ {
353
+ id: 'enterprise',
354
+ name: 'Enterprise',
355
+ price: 'Sur devis',
356
+ currency: '',
357
+ features: [
358
+ { name: 'Utilisateurs illimités', included: true },
359
+ { name: 'Support dédié', included: true },
360
+ ],
361
+ buttonText: 'Contacter',
362
+ buttonVariant: 'outline',
363
+ },
364
+ ]
365
+
366
+ return (
367
+ <WakaPricing
368
+ title="Tarification"
369
+ description="Choisissez le plan qui vous convient"
370
+ plans={euroPlans}
371
+ yearlyDiscount="20%"
372
+ LinkComponent={MockLink}
373
+ />
374
+ )
375
+ },
376
+ }
377
+
378
+ export const Interactive: Story = {
379
+ render: () => {
380
+ const [selectedPlan, setSelectedPlan] = React.useState<string | null>(null)
381
+
382
+ const interactivePlans: PricingPlan[] = defaultPricingPlans.map((plan) => ({
383
+ ...plan,
384
+ onSelect: () => {
385
+ setSelectedPlan(plan.id)
386
+ console.log('Selected plan:', plan.name)
387
+ },
388
+ }))
389
+
390
+ return (
391
+ <div>
392
+ {selectedPlan && (
393
+ <div className="bg-primary/10 p-4 text-center mb-4 rounded-lg">
394
+ <p className="text-sm">
395
+ You selected: <strong className="capitalize">{selectedPlan}</strong>
396
+ </p>
397
+ </div>
398
+ )}
399
+ <WakaPricing
400
+ title="Select a Plan"
401
+ plans={interactivePlans}
402
+ yearlyDiscount="20%"
403
+ LinkComponent={MockLink}
404
+ />
405
+ </div>
406
+ )
407
+ },
408
+ }
409
+
410
+ export const PartialFeatures: Story = {
411
+ render: () => {
412
+ const plansWithPartial: PricingPlan[] = [
413
+ {
414
+ id: 'starter',
415
+ name: 'Starter',
416
+ price: 9,
417
+ features: [
418
+ { name: 'Projects', included: true, value: '5' },
419
+ { name: 'Storage', included: 'limited', value: '1 GB' },
420
+ { name: 'API Access', included: 'partial', value: 'Read-only' },
421
+ { name: 'Team members', included: false },
422
+ { name: 'Analytics', included: false },
423
+ ],
424
+ buttonText: 'Get Started',
425
+ buttonVariant: 'outline',
426
+ },
427
+ {
428
+ id: 'growth',
429
+ name: 'Growth',
430
+ price: 29,
431
+ popular: true,
432
+ features: [
433
+ { name: 'Projects', included: true, value: '25' },
434
+ { name: 'Storage', included: true, value: '25 GB' },
435
+ { name: 'API Access', included: true, value: 'Full access' },
436
+ { name: 'Team members', included: 'limited', value: 'Up to 5' },
437
+ { name: 'Analytics', included: 'partial', value: 'Basic' },
438
+ ],
439
+ buttonText: 'Start Trial',
440
+ },
441
+ {
442
+ id: 'scale',
443
+ name: 'Scale',
444
+ price: 99,
445
+ features: [
446
+ { name: 'Projects', included: true, value: 'Unlimited' },
447
+ { name: 'Storage', included: true, value: '100 GB' },
448
+ { name: 'API Access', included: true, value: 'Full access' },
449
+ { name: 'Team members', included: true, value: 'Unlimited' },
450
+ { name: 'Analytics', included: true, value: 'Advanced' },
451
+ ],
452
+ buttonText: 'Contact Sales',
453
+ },
454
+ ]
455
+
456
+ return (
457
+ <WakaPricing
458
+ title="Feature Comparison"
459
+ description="Yellow checkmarks indicate limited access"
460
+ plans={plansWithPartial}
461
+ showBillingToggle={false}
462
+ LinkComponent={MockLink}
463
+ />
464
+ )
465
+ },
466
+ }
467
+
468
+ export const DisabledPlans: Story = {
469
+ render: () => {
470
+ const plansWithDisabled: PricingPlan[] = [
471
+ {
472
+ ...defaultPricingPlans[0],
473
+ disabled: true,
474
+ buttonText: 'Coming Soon',
475
+ },
476
+ defaultPricingPlans[1],
477
+ {
478
+ ...defaultPricingPlans[2],
479
+ badge: 'Limited',
480
+ buttonText: 'Waitlist',
481
+ },
482
+ ]
483
+
484
+ return (
485
+ <WakaPricing
486
+ title="Available Plans"
487
+ plans={plansWithDisabled}
488
+ showBillingToggle={false}
489
+ LinkComponent={MockLink}
490
+ />
491
+ )
492
+ },
493
+ }
494
+
495
+ export const CompletePricingPage: Story = {
496
+ render: () => (
497
+ <div className="min-h-screen">
498
+ <header className="border-b py-4">
499
+ <div className="container flex items-center justify-between">
500
+ <span className="font-bold text-xl">SaaSApp</span>
501
+ <nav className="flex gap-6 text-sm">
502
+ <a href="#" className="text-muted-foreground hover:text-foreground">Features</a>
503
+ <a href="#" className="text-foreground font-medium">Pricing</a>
504
+ <a href="#" className="text-muted-foreground hover:text-foreground">Docs</a>
505
+ <a href="#" className="text-muted-foreground hover:text-foreground">Blog</a>
506
+ </nav>
507
+ <button className="px-4 py-2 bg-primary text-primary-foreground rounded-md text-sm">
508
+ Sign In
509
+ </button>
510
+ </div>
511
+ </header>
512
+
513
+ <WakaPricing
514
+ title="Simple, transparent pricing"
515
+ description="No hidden fees. No surprises. Start free and scale as you grow."
516
+ plans={defaultPricingPlans}
517
+ yearlyDiscount="20%"
518
+ faq={defaultPricingFAQ}
519
+ faqTitle="Common Questions"
520
+ LinkComponent={MockLink}
521
+ />
522
+
523
+ <footer className="border-t py-8 bg-muted/30">
524
+ <div className="container text-center text-sm text-muted-foreground">
525
+ © 2024 SaaSApp Inc. All rights reserved.
526
+ </div>
527
+ </footer>
528
+ </div>
529
+ ),
530
+ }
@@ -2,6 +2,7 @@
2
2
 
3
3
  import * as React from "react"
4
4
  import { cn } from "../../utils"
5
+ import type { LinkComponentProps } from "../../types/link"
5
6
  import { Button } from "../../components/button"
6
7
  import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "../../components/card"
7
8
  import { Badge } from "../../components/badge"
@@ -82,6 +83,22 @@ export interface WakaPricingProps {
82
83
  showComparison?: boolean
83
84
  /** Classes CSS additionnelles */
84
85
  className?: string
86
+ /** Composant de lien personnalisé (ex: next/link) pour navigation SPA */
87
+ LinkComponent?: React.ComponentType<LinkComponentProps>
88
+ }
89
+
90
+ // ============================================
91
+ // CONTEXT
92
+ // ============================================
93
+
94
+ interface PricingContextValue {
95
+ LinkComponent?: React.ComponentType<LinkComponentProps>
96
+ }
97
+
98
+ const PricingContext = React.createContext<PricingContextValue>({})
99
+
100
+ function usePricingContext() {
101
+ return React.useContext(PricingContext)
85
102
  }
86
103
 
87
104
  // ============================================
@@ -135,6 +152,8 @@ interface PricingCardProps {
135
152
  }
136
153
 
137
154
  function PricingCard({ plan, billingPeriod }: PricingCardProps) {
155
+ const { LinkComponent } = usePricingContext()
156
+
138
157
  const price = billingPeriod === "yearly" && plan.priceYearly !== undefined
139
158
  ? plan.priceYearly
140
159
  : plan.price
@@ -236,7 +255,11 @@ function PricingCard({ plan, billingPeriod }: PricingCardProps) {
236
255
  asChild={!!plan.href}
237
256
  >
238
257
  {plan.href ? (
239
- <a href={plan.href}>{plan.buttonText || "Choisir"}</a>
258
+ LinkComponent ? (
259
+ <LinkComponent href={plan.href}>{plan.buttonText || "Choisir"}</LinkComponent>
260
+ ) : (
261
+ <a href={plan.href}>{plan.buttonText || "Choisir"}</a>
262
+ )
240
263
  ) : (
241
264
  plan.buttonText || "Choisir"
242
265
  )}
@@ -252,6 +275,8 @@ interface PricingTableProps {
252
275
  }
253
276
 
254
277
  function PricingTable({ plans, billingPeriod }: PricingTableProps) {
278
+ const { LinkComponent } = usePricingContext()
279
+
255
280
  // Get all unique features
256
281
  const allFeatures = Array.from(
257
282
  new Set(plans.flatMap((plan) => plan.features.map((f) => f.name)))
@@ -367,7 +392,11 @@ function PricingTable({ plans, billingPeriod }: PricingTableProps) {
367
392
  asChild={!!plan.href}
368
393
  >
369
394
  {plan.href ? (
370
- <a href={plan.href}>{plan.buttonText || "Choisir"}</a>
395
+ LinkComponent ? (
396
+ <LinkComponent href={plan.href}>{plan.buttonText || "Choisir"}</LinkComponent>
397
+ ) : (
398
+ <a href={plan.href}>{plan.buttonText || "Choisir"}</a>
399
+ )
371
400
  ) : (
372
401
  plan.buttonText || "Choisir"
373
402
  )}
@@ -420,6 +449,7 @@ export function WakaPricing({
420
449
  columns = 3,
421
450
  showComparison = false,
422
451
  className,
452
+ LinkComponent,
423
453
  }: WakaPricingProps) {
424
454
  const [internalBillingPeriod, setInternalBillingPeriod] = React.useState<"monthly" | "yearly">("monthly")
425
455
 
@@ -439,8 +469,11 @@ export function WakaPricing({
439
469
  4: "md:grid-cols-2 lg:grid-cols-4",
440
470
  }
441
471
 
472
+ const contextValue = React.useMemo(() => ({ LinkComponent }), [LinkComponent])
473
+
442
474
  return (
443
- <div className={cn("container py-16", className)}>
475
+ <PricingContext.Provider value={contextValue}>
476
+ <div className={cn("container py-16", className)}>
444
477
  {/* Header */}
445
478
  <div className="text-center mb-12">
446
479
  <h1 className="text-3xl md:text-4xl font-bold tracking-tight mb-4">
@@ -477,7 +510,8 @@ export function WakaPricing({
477
510
  {faq && faq.length > 0 && (
478
511
  <PricingFAQSection title={faqTitle} items={faq} />
479
512
  )}
480
- </div>
513
+ </div>
514
+ </PricingContext.Provider>
481
515
  )
482
516
  }
483
517