@wakastellar/ui 2.4.0 → 3.1.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/antivirus-dashboard/index.d.ts +44 -0
- package/dist/blocks/clamav-service-status/index.d.ts +35 -0
- package/dist/blocks/file-scan-uploader/index.d.ts +29 -0
- package/dist/blocks/index.d.ts +18 -9
- package/dist/blocks/quarantine-manager/index.d.ts +27 -0
- package/dist/blocks/scan-history-log/index.d.ts +28 -0
- package/dist/blocks/scan-policy-editor/index.d.ts +27 -0
- package/dist/blocks/scan-report-generator/index.d.ts +47 -0
- package/dist/blocks/signature-database-manager/index.d.ts +39 -0
- package/dist/blocks/threat-alert-banner/index.d.ts +26 -0
- package/dist/components/index.d.ts +4 -4
- package/dist/components/waka-signature-pad/index.d.ts +1 -1
- package/dist/exceljs.min-BcLLX0PC.js +29 -0
- package/dist/exceljs.min-KOayaaQ4.mjs +23013 -0
- package/dist/export.cjs.js +1 -1
- package/dist/export.d.ts +2 -2
- package/dist/export.es.js +1 -1
- package/dist/index.cjs.js +136 -136
- package/dist/index.es.js +29978 -27215
- package/dist/stories/Button.stories.d.ts +1 -1
- package/dist/stories/Header.stories.d.ts +1 -1
- package/dist/stories/Page.stories.d.ts +1 -1
- package/dist/useDataTableImport-COVnvslz.js +9 -0
- package/dist/useDataTableImport-DAlxBY8w.mjs +237 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/package.json +6 -5
- package/src/blocks/antivirus-dashboard/AntivirusDashboard.stories.tsx +291 -0
- package/src/blocks/antivirus-dashboard/index.tsx +525 -0
- package/src/blocks/clamav-service-status/ClamAVServiceStatus.stories.tsx +195 -0
- package/src/blocks/clamav-service-status/index.tsx +370 -0
- package/src/blocks/file-scan-uploader/FileScanUploader.stories.tsx +257 -0
- package/src/blocks/file-scan-uploader/index.tsx +311 -0
- package/src/blocks/index.ts +163 -11
- package/src/blocks/quarantine-manager/QuarantineManager.stories.tsx +209 -0
- package/src/blocks/quarantine-manager/index.tsx +435 -0
- package/src/blocks/scan-history-log/ScanHistoryLog.stories.tsx +231 -0
- package/src/blocks/scan-history-log/index.tsx +406 -0
- package/src/blocks/scan-policy-editor/ScanPolicyEditor.stories.tsx +106 -0
- package/src/blocks/scan-policy-editor/index.tsx +418 -0
- package/src/blocks/scan-report-generator/ScanReportGenerator.stories.tsx +232 -0
- package/src/blocks/scan-report-generator/index.tsx +612 -0
- package/src/blocks/sidebar/index.tsx +2 -1
- package/src/blocks/signature-database-manager/SignatureDatabaseManager.stories.tsx +279 -0
- package/src/blocks/signature-database-manager/index.tsx +470 -0
- package/src/blocks/theme-creator-block/index.tsx +16 -2
- package/src/blocks/threat-alert-banner/ThreatAlertBanner.stories.tsx +152 -0
- package/src/blocks/threat-alert-banner/index.tsx +320 -0
- package/src/components/DataTable/DataTable.stories.tsx +203 -0
- package/src/components/DataTable/hooks/useDataTableExport.ts +38 -31
- package/src/components/DataTable/hooks/useDataTableImport.ts +31 -20
- package/src/components/error-boundary/ErrorBoundary.stories.tsx +125 -0
- package/src/components/index.ts +45 -4
- package/src/components/language-selector/LanguageSelector.stories.tsx +112 -0
- package/src/components/theme-selector/ThemeSelector.stories.tsx +77 -0
- package/src/components/toaster/Toaster.stories.tsx +67 -0
- package/src/components/waka-activity-feed/WakaActivityFeed.stories.tsx +116 -0
- package/src/components/waka-ad-banner/WakaAdBanner.stories.tsx +102 -0
- package/src/components/waka-ad-fallback/WakaAdFallback.stories.tsx +117 -0
- package/src/components/waka-ad-inline/WakaAdInline.stories.tsx +105 -0
- package/src/components/waka-ad-interstitial/WakaAdInterstitial.stories.tsx +92 -0
- package/src/components/waka-ad-placeholder/WakaAdPlaceholder.stories.tsx +89 -0
- package/src/components/waka-ad-provider/WakaAdProvider.stories.tsx +110 -0
- package/src/components/waka-ad-sidebar/WakaAdSidebar.stories.tsx +89 -0
- package/src/components/waka-ad-sidebar/index.tsx +3 -2
- package/src/components/waka-ad-sticky-footer/WakaAdStickyFooter.stories.tsx +88 -0
- package/src/components/waka-address-autocomplete/WakaAddressAutocomplete.stories.tsx +46 -0
- package/src/components/waka-admincrumb/WakaAdmincrumb.stories.tsx +166 -0
- package/src/components/waka-alert-panel/WakaAlertPanel.stories.tsx +45 -0
- package/src/components/waka-alert-stack/WakaAlertStack.stories.tsx +62 -0
- package/src/components/waka-allocation-matrix/WakaAllocationMatrix.stories.tsx +68 -0
- package/src/components/waka-approval-chain/WakaApprovalChain.stories.tsx +63 -0
- package/src/components/waka-audit-log/WakaAuditLog.stories.tsx +73 -0
- package/src/components/waka-autocomplete/WakaAutocomplete.stories.tsx +132 -172
- package/src/components/waka-biometric-prompt/WakaBiometricPrompt.stories.tsx +48 -0
- package/src/components/waka-breadcrumb/WakaBreadcrumb.stories.tsx +74 -191
- package/src/components/waka-breadcrumb-path/WakaBreadcrumbPath.stories.tsx +40 -0
- package/src/components/waka-budget-burn/WakaBudgetBurn.stories.tsx +86 -0
- package/src/components/waka-capacity-planner/WakaCapacityPlanner.stories.tsx +273 -0
- package/src/components/waka-cart-summary/WakaCartSummary.stories.tsx +176 -0
- package/src/components/waka-cart-summary/index.tsx +19 -10
- package/src/components/waka-challenge-timer/WakaChallengeTimer.stories.tsx +98 -0
- package/src/components/waka-chat-bubble/WakaChatBubble.stories.tsx +118 -0
- package/src/components/waka-checklist/WakaChecklist.stories.tsx +71 -0
- package/src/components/waka-checkout-stepper/WakaCheckoutStepper.stories.tsx +102 -0
- package/src/components/waka-cohort-table/WakaCohortTable.stories.tsx +56 -0
- package/src/components/waka-color-picker/WakaColorPicker.stories.tsx +99 -155
- package/src/components/waka-combo-counter/WakaComboCounter.stories.tsx +128 -0
- package/src/components/waka-command-bar/WakaCommandBar.stories.tsx +45 -0
- package/src/components/waka-compare-period/WakaComparePeriod.stories.tsx +76 -0
- package/src/components/waka-config-comparator/WakaConfigComparator.stories.tsx +143 -0
- package/src/components/waka-connection-matrix/WakaConnectionMatrix.stories.tsx +52 -0
- package/src/components/waka-content-recommendation/WakaContentRecommendation.stories.tsx +41 -0
- package/src/components/waka-coupon-input/WakaCouponInput.stories.tsx +126 -0
- package/src/components/waka-credit-card-input/WakaCreditCardInput.stories.tsx +120 -0
- package/src/components/waka-datetime-picker.form-integration/WakaDateTimePickerForm.stories.tsx +79 -0
- package/src/components/waka-dependency-tree/WakaDependencyTree.stories.tsx +72 -0
- package/src/components/waka-device-trust/WakaDeviceTrust.stories.tsx +109 -0
- package/src/components/waka-empty-state/WakaEmptyState.stories.tsx +87 -0
- package/src/components/waka-feature-announcement/WakaFeatureAnnouncement.stories.tsx +47 -0
- package/src/components/waka-feature-flag-row/WakaFeatureFlagRow.stories.tsx +188 -0
- package/src/components/waka-file-upload/WakaFileUpload.stories.tsx +118 -174
- package/src/components/waka-floating-nav/WakaFloatingNav.stories.tsx +53 -0
- package/src/components/waka-goal-progress/WakaGoalProgress.stories.tsx +137 -0
- package/src/components/waka-hotspot/WakaHotspot.stories.tsx +56 -0
- package/src/components/waka-invoice-preview/WakaInvoicePreview.stories.tsx +169 -0
- package/src/components/waka-kpi-dashboard/WakaKpiDashboard.stories.tsx +46 -0
- package/src/components/waka-level-progress/WakaLevelProgress.stories.tsx +94 -75
- package/src/components/waka-liquid-button/WakaLiquidButton.stories.tsx +45 -0
- package/src/components/waka-magic-link/WakaMagicLink.stories.tsx +61 -0
- package/src/components/waka-magnetic-button/WakaMagneticButton.stories.tsx +40 -0
- package/src/components/waka-mention-input/WakaMentionInput.stories.tsx +140 -0
- package/src/components/waka-milestone-road/WakaMilestoneRoad.stories.tsx +143 -0
- package/src/components/waka-orbital-menu/WakaOrbitalMenu.stories.tsx +54 -0
- package/src/components/waka-order-tracker/WakaOrderTracker.stories.tsx +163 -0
- package/src/components/waka-outstream-video/WakaOutstreamVideo.stories.tsx +94 -0
- package/src/components/waka-pagination/WakaPagination.stories.tsx +110 -280
- package/src/components/waka-password-strength/WakaPasswordStrength.stories.tsx +132 -268
- package/src/components/waka-payment-method-picker/WakaPaymentMethodPicker.stories.tsx +141 -0
- package/src/components/waka-permission-matrix/WakaPermissionMatrix.stories.tsx +124 -0
- package/src/components/waka-phone-input/WakaPhoneInput.stories.tsx +56 -0
- package/src/components/waka-points-popup/WakaPointsPopup.stories.tsx +96 -0
- package/src/components/waka-power-up/WakaPowerUp.stories.tsx +121 -0
- package/src/components/waka-presence-indicator/WakaPresenceIndicator.stories.tsx +49 -0
- package/src/components/waka-pricing-table/WakaPricingTable.stories.tsx +159 -0
- package/src/components/waka-product-card/WakaProductCard.stories.tsx +202 -0
- package/src/components/waka-progress-onboarding/WakaProgressOnboarding.stories.tsx +57 -0
- package/src/components/waka-pull-to-refresh/WakaPullToRefresh.stories.tsx +51 -0
- package/src/components/waka-rank-badge/WakaRankBadge.stories.tsx +108 -0
- package/src/components/waka-rating-input/WakaRatingInput.stories.tsx +51 -0
- package/src/components/waka-reaction-picker/WakaReactionPicker.stories.tsx +52 -0
- package/src/components/waka-region-map/WakaRegionMap.stories.tsx +181 -0
- package/src/components/waka-resource-pool/WakaResourcePool.stories.tsx +70 -0
- package/src/components/waka-rich-text-editor/WakaRichTextEditor.stories.tsx +108 -197
- package/src/components/waka-rollback-slider/WakaRollbackSlider.stories.tsx +41 -0
- package/src/components/waka-schedule-picker/WakaSchedulePicker.stories.tsx +64 -0
- package/src/components/waka-season-pass/WakaSeasonPass.stories.tsx +107 -0
- package/src/components/waka-security-scan-result/WakaSecurityScanResult.stories.tsx +146 -0
- package/src/components/waka-security-score/WakaSecurityScore.stories.tsx +63 -0
- package/src/components/waka-session-manager/WakaSessionManager.stories.tsx +68 -0
- package/src/components/waka-signature-pad/WakaSignaturePad.stories.tsx +159 -0
- package/src/components/waka-signature-pad/index.tsx +5 -3
- package/src/components/waka-sla-tracker/WakaSlaTracker.stories.tsx +65 -0
- package/src/components/waka-slider-range/WakaSliderRange.stories.tsx +66 -0
- package/src/components/waka-sponsored-badge/WakaSponsoredBadge.stories.tsx +60 -0
- package/src/components/waka-sponsored-card/WakaSponsoredCard.stories.tsx +64 -0
- package/src/components/waka-sponsored-feed/WakaSponsoredFeed.stories.tsx +58 -0
- package/src/components/waka-spotlight/WakaSpotlight.stories.tsx +53 -0
- package/src/components/waka-stats-hexagon/WakaStatsHexagon.stories.tsx +161 -0
- package/src/components/waka-stepper/WakaStepper.stories.tsx +137 -410
- package/src/components/waka-swipe-card/WakaSwipeCard.stories.tsx +51 -0
- package/src/components/waka-tag-input/WakaTagInput.stories.tsx +224 -0
- package/src/components/waka-team-banner/WakaTeamBanner.stories.tsx +50 -0
- package/src/components/waka-theme-creator/WakaThemeCreator.stories.tsx +58 -0
- package/src/components/waka-theme-manager/WakaThemeManager.stories.tsx +298 -0
- package/src/components/waka-theme-manager/index.tsx +6 -11
- package/src/components/waka-thread-view/WakaThreadView.stories.tsx +143 -0
- package/src/components/waka-timeline/WakaTimeline.stories.tsx +171 -324
- package/src/components/waka-tooltip-tour/WakaTooltipTour.stories.tsx +92 -0
- package/src/components/waka-tour-guide/WakaTourGuide.stories.tsx +89 -0
- package/src/components/waka-treemap-chart/WakaTreemapChart.stories.tsx +234 -129
- package/src/components/waka-treemap-chart/index.tsx +2 -2
- package/src/components/waka-two-factor-setup/WakaTwoFactorSetup.stories.tsx +142 -0
- package/src/components/waka-typing-indicator/WakaTypingIndicator.stories.tsx +134 -0
- package/src/components/waka-video-ad/WakaVideoAd.stories.tsx +138 -0
- package/src/components/waka-video-call/WakaVideoCall.stories.tsx +186 -0
- package/src/components/waka-video-overlay/WakaVideoOverlay.stories.tsx +100 -0
- package/src/components/waka-voice-message/WakaVoiceMessage.stories.tsx +190 -0
- package/src/components/waka-welcome-modal/WakaWelcomeModal.stories.tsx +87 -0
- package/src/components/waka-xp-bar/WakaXPBar.stories.tsx +29 -29
- package/dist/useDataTableImport-D8R2HQl6.mjs +0 -229
- package/dist/useDataTableImport-S_hhA5Wo.js +0 -9
- package/src/components/DataTable/README.md +0 -446
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import * as React from "react"
|
|
3
|
+
import { WakaTooltipTour, type TourStep } from "./index"
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof WakaTooltipTour> = {
|
|
6
|
+
title: "Navigation/WakaTooltipTour",
|
|
7
|
+
component: WakaTooltipTour,
|
|
8
|
+
parameters: { layout: "padded" },
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
argTypes: {
|
|
11
|
+
isActive: { control: "boolean", description: "Tour actif" },
|
|
12
|
+
showSkip: { control: "boolean", description: "Afficher le bouton skip" },
|
|
13
|
+
showProgress: { control: "boolean", description: "Afficher la progression" },
|
|
14
|
+
showNavigation: { control: "boolean", description: "Afficher la navigation" },
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default meta
|
|
19
|
+
type Story = StoryObj<typeof WakaTooltipTour>
|
|
20
|
+
|
|
21
|
+
const steps: TourStep[] = [
|
|
22
|
+
{
|
|
23
|
+
id: "step-1",
|
|
24
|
+
target: "#tour-target-1",
|
|
25
|
+
title: "Navigation principale",
|
|
26
|
+
content: "Accédez rapidement aux sections clés.",
|
|
27
|
+
placement: "bottom",
|
|
28
|
+
highlight: true,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "step-2",
|
|
32
|
+
target: "#tour-target-2",
|
|
33
|
+
title: "Recherche",
|
|
34
|
+
content: "Trouvez des ressources avec la recherche.",
|
|
35
|
+
placement: "bottom",
|
|
36
|
+
highlight: true,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "step-3",
|
|
40
|
+
target: "#tour-target-3",
|
|
41
|
+
title: "Actions rapides",
|
|
42
|
+
content: "Lancez des actions en un clic.",
|
|
43
|
+
placement: "top",
|
|
44
|
+
highlight: true,
|
|
45
|
+
},
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
const DemoLayout = () => (
|
|
49
|
+
<div className="tw-space-y-4">
|
|
50
|
+
<div className="tw-flex tw-gap-3">
|
|
51
|
+
<button id="tour-target-1" className="tw-px-3 tw-py-2 tw-rounded tw-bg-primary tw-text-primary-foreground">
|
|
52
|
+
Menu
|
|
53
|
+
</button>
|
|
54
|
+
<button id="tour-target-2" className="tw-px-3 tw-py-2 tw-rounded tw-bg-muted">
|
|
55
|
+
Recherche
|
|
56
|
+
</button>
|
|
57
|
+
<button id="tour-target-3" className="tw-px-3 tw-py-2 tw-rounded tw-bg-muted">
|
|
58
|
+
Actions
|
|
59
|
+
</button>
|
|
60
|
+
</div>
|
|
61
|
+
<div className="tw-p-4 tw-border tw-rounded-lg">
|
|
62
|
+
<p className="tw-text-sm tw-text-muted-foreground">Zone de contenu</p>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
export const Default: Story = {
|
|
68
|
+
args: {
|
|
69
|
+
tourId: "storybook-tooltip-tour",
|
|
70
|
+
steps,
|
|
71
|
+
isActive: true,
|
|
72
|
+
showSkip: true,
|
|
73
|
+
showProgress: true,
|
|
74
|
+
showNavigation: true,
|
|
75
|
+
closeOnOverlayClick: true,
|
|
76
|
+
},
|
|
77
|
+
render: (args) => {
|
|
78
|
+
const [active, setActive] = React.useState(Boolean(args.isActive))
|
|
79
|
+
|
|
80
|
+
React.useEffect(() => {
|
|
81
|
+
setActive(Boolean(args.isActive))
|
|
82
|
+
}, [args.isActive])
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div>
|
|
86
|
+
<DemoLayout />
|
|
87
|
+
<WakaTooltipTour {...args} isActive={active} onActiveChange={setActive} steps={steps} />
|
|
88
|
+
</div>
|
|
89
|
+
)
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import * as React from "react"
|
|
3
|
+
import { WakaTourGuide, type TourStep } from "./index"
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof WakaTourGuide> = {
|
|
6
|
+
title: "Navigation/WakaTourGuide",
|
|
7
|
+
component: WakaTourGuide,
|
|
8
|
+
parameters: { layout: "padded" },
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
argTypes: {
|
|
11
|
+
isOpen: { control: "boolean", description: "Tour ouvert" },
|
|
12
|
+
variant: { control: "select", options: ["modal", "tooltip"], description: "Variante" },
|
|
13
|
+
showSkip: { control: "boolean", description: "Afficher le bouton skip" },
|
|
14
|
+
showProgress: { control: "boolean", description: "Afficher la progression" },
|
|
15
|
+
showStepCounter: { control: "boolean", description: "Afficher le compteur" },
|
|
16
|
+
},
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default meta
|
|
20
|
+
type Story = StoryObj<typeof WakaTourGuide>
|
|
21
|
+
|
|
22
|
+
const steps: TourStep[] = [
|
|
23
|
+
{
|
|
24
|
+
id: "welcome",
|
|
25
|
+
target: "#guide-target-1",
|
|
26
|
+
title: "Bienvenue",
|
|
27
|
+
content: "Voici un tour rapide des fonctions principales.",
|
|
28
|
+
placement: "bottom",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "profile",
|
|
32
|
+
target: "#guide-target-2",
|
|
33
|
+
title: "Profil",
|
|
34
|
+
content: "Gérez vos préférences et votre compte.",
|
|
35
|
+
placement: "right",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "settings",
|
|
39
|
+
target: "#guide-target-3",
|
|
40
|
+
title: "Paramètres",
|
|
41
|
+
content: "Configurez votre application ici.",
|
|
42
|
+
placement: "left",
|
|
43
|
+
},
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
const DemoLayout = () => (
|
|
47
|
+
<div className="tw-space-y-4">
|
|
48
|
+
<div className="tw-flex tw-gap-3">
|
|
49
|
+
<button id="guide-target-1" className="tw-px-3 tw-py-2 tw-rounded tw-bg-primary tw-text-primary-foreground">
|
|
50
|
+
Démarrer
|
|
51
|
+
</button>
|
|
52
|
+
<button id="guide-target-2" className="tw-px-3 tw-py-2 tw-rounded tw-bg-muted">
|
|
53
|
+
Profil
|
|
54
|
+
</button>
|
|
55
|
+
<button id="guide-target-3" className="tw-px-3 tw-py-2 tw-rounded tw-bg-muted">
|
|
56
|
+
Paramètres
|
|
57
|
+
</button>
|
|
58
|
+
</div>
|
|
59
|
+
<div className="tw-p-4 tw-border tw-rounded-lg">
|
|
60
|
+
<p className="tw-text-sm tw-text-muted-foreground">Zone de contenu</p>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
export const Default: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
steps,
|
|
68
|
+
isOpen: true,
|
|
69
|
+
variant: "modal",
|
|
70
|
+
showSkip: true,
|
|
71
|
+
showProgress: true,
|
|
72
|
+
showStepCounter: true,
|
|
73
|
+
},
|
|
74
|
+
render: (args) => {
|
|
75
|
+
const [open, setOpen] = React.useState(Boolean(args.isOpen))
|
|
76
|
+
|
|
77
|
+
React.useEffect(() => {
|
|
78
|
+
setOpen(Boolean(args.isOpen))
|
|
79
|
+
}, [args.isOpen])
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div>
|
|
83
|
+
<DemoLayout />
|
|
84
|
+
<WakaTourGuide {...args} isOpen={open} onOpenChange={setOpen} steps={steps} />
|
|
85
|
+
</div>
|
|
86
|
+
)
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
|
|
@@ -3,104 +3,111 @@ import { WakaTreemapChart, useTreemapChart } from './index'
|
|
|
3
3
|
import type { TreemapNode } from './index'
|
|
4
4
|
import * as React from 'react'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
6
|
+
// Données pour l'utilisation du disque - format tableau
|
|
7
|
+
const diskUsageData: TreemapNode[] = [
|
|
8
|
+
{
|
|
9
|
+
id: 'documents',
|
|
10
|
+
label: 'Documents',
|
|
11
|
+
value: 5500,
|
|
12
|
+
category: 'files',
|
|
13
|
+
children: [
|
|
14
|
+
{ id: 'pdf', label: 'PDFs', value: 2500, category: 'files' },
|
|
15
|
+
{ id: 'word', label: 'Word Docs', value: 1800, category: 'files' },
|
|
16
|
+
{ id: 'spreadsheets', label: 'Spreadsheets', value: 1200, category: 'files' },
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 'media',
|
|
21
|
+
label: 'Media',
|
|
22
|
+
value: 26500,
|
|
23
|
+
category: 'media',
|
|
24
|
+
children: [
|
|
25
|
+
{ id: 'photos', label: 'Photos', value: 8000, category: 'media' },
|
|
26
|
+
{ id: 'videos', label: 'Videos', value: 15000, category: 'media' },
|
|
27
|
+
{ id: 'music', label: 'Music', value: 3500, category: 'media' },
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'apps',
|
|
32
|
+
label: 'Applications',
|
|
33
|
+
value: 12000,
|
|
34
|
+
category: 'apps',
|
|
35
|
+
children: [
|
|
36
|
+
{ id: 'system', label: 'System', value: 5000, category: 'apps' },
|
|
37
|
+
{ id: 'user', label: 'User Apps', value: 7000, category: 'apps' },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
{ id: 'other', label: 'Other', value: 2000, category: 'other' },
|
|
41
|
+
]
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
43
|
+
// Données de ventes par catégorie
|
|
44
|
+
const salesByCategoryData: TreemapNode[] = [
|
|
45
|
+
{
|
|
46
|
+
id: 'electronics',
|
|
47
|
+
label: 'Electronics',
|
|
48
|
+
value: 120000,
|
|
49
|
+
color: '#3b82f6',
|
|
50
|
+
category: 'electronics',
|
|
51
|
+
children: [
|
|
52
|
+
{ id: 'phones', label: 'Phones', value: 45000, category: 'electronics' },
|
|
53
|
+
{ id: 'laptops', label: 'Laptops', value: 38000, category: 'electronics' },
|
|
54
|
+
{ id: 'tablets', label: 'Tablets', value: 22000, category: 'electronics' },
|
|
55
|
+
{ id: 'accessories', label: 'Accessories', value: 15000, category: 'electronics' },
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'clothing',
|
|
60
|
+
label: 'Clothing',
|
|
61
|
+
value: 81000,
|
|
62
|
+
color: '#22c55e',
|
|
63
|
+
category: 'clothing',
|
|
64
|
+
children: [
|
|
65
|
+
{ id: 'mens', label: "Men's", value: 28000, category: 'clothing' },
|
|
66
|
+
{ id: 'womens', label: "Women's", value: 35000, category: 'clothing' },
|
|
67
|
+
{ id: 'kids', label: 'Kids', value: 18000, category: 'clothing' },
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'home',
|
|
72
|
+
label: 'Home & Garden',
|
|
73
|
+
value: 52000,
|
|
74
|
+
color: '#f59e0b',
|
|
75
|
+
category: 'home',
|
|
76
|
+
children: [
|
|
77
|
+
{ id: 'furniture', label: 'Furniture', value: 32000, category: 'home' },
|
|
78
|
+
{ id: 'decor', label: 'Decor', value: 12000, category: 'home' },
|
|
79
|
+
{ id: 'garden', label: 'Garden', value: 8000, category: 'home' },
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
]
|
|
77
83
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
84
|
+
// Données de portefeuille d'investissement
|
|
85
|
+
const portfolioData: TreemapNode[] = [
|
|
86
|
+
{
|
|
87
|
+
id: 'stocks',
|
|
88
|
+
label: 'Stocks',
|
|
89
|
+
value: 100000,
|
|
90
|
+
category: 'stocks',
|
|
91
|
+
children: [
|
|
92
|
+
{ id: 'tech', label: 'Tech', value: 45000, color: '#3b82f6', category: 'stocks' },
|
|
93
|
+
{ id: 'healthcare', label: 'Healthcare', value: 25000, color: '#22c55e', category: 'stocks' },
|
|
94
|
+
{ id: 'finance', label: 'Finance', value: 20000, color: '#f59e0b', category: 'stocks' },
|
|
95
|
+
{ id: 'energy', label: 'Energy', value: 10000, color: '#ef4444', category: 'stocks' },
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'bonds',
|
|
100
|
+
label: 'Bonds',
|
|
101
|
+
value: 45000,
|
|
102
|
+
category: 'bonds',
|
|
103
|
+
children: [
|
|
104
|
+
{ id: 'gov', label: 'Government', value: 30000, color: '#8b5cf6', category: 'bonds' },
|
|
105
|
+
{ id: 'corp', label: 'Corporate', value: 15000, color: '#ec4899', category: 'bonds' },
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
{ id: 'cash', label: 'Cash', value: 20000, color: '#6b7280', category: 'cash' },
|
|
109
|
+
{ id: 'crypto', label: 'Crypto', value: 5000, color: '#06b6d4', category: 'crypto' },
|
|
110
|
+
]
|
|
104
111
|
|
|
105
112
|
const meta: Meta<typeof WakaTreemapChart> = {
|
|
106
113
|
title: 'Components/Charts/WakaTreemapChart',
|
|
@@ -117,9 +124,14 @@ const meta: Meta<typeof WakaTreemapChart> = {
|
|
|
117
124
|
argTypes: {
|
|
118
125
|
colorScheme: {
|
|
119
126
|
control: 'select',
|
|
120
|
-
options: ['
|
|
127
|
+
options: ['default', 'cool', 'warm', 'neon', 'pastel'],
|
|
121
128
|
description: 'Color scheme for nodes',
|
|
122
129
|
},
|
|
130
|
+
colorBy: {
|
|
131
|
+
control: 'select',
|
|
132
|
+
options: ['category', 'value'],
|
|
133
|
+
description: 'How to assign colors',
|
|
134
|
+
},
|
|
123
135
|
showLabels: {
|
|
124
136
|
control: 'boolean',
|
|
125
137
|
description: 'Show node labels',
|
|
@@ -132,9 +144,13 @@ const meta: Meta<typeof WakaTreemapChart> = {
|
|
|
132
144
|
control: 'boolean',
|
|
133
145
|
description: 'Enable drill-down on click',
|
|
134
146
|
},
|
|
135
|
-
|
|
147
|
+
showLegend: {
|
|
136
148
|
control: 'boolean',
|
|
137
|
-
description: '
|
|
149
|
+
description: 'Show legend',
|
|
150
|
+
},
|
|
151
|
+
animationDuration: {
|
|
152
|
+
control: { type: 'range', min: 0, max: 1000, step: 50 },
|
|
153
|
+
description: 'Animation duration in ms',
|
|
138
154
|
},
|
|
139
155
|
padding: {
|
|
140
156
|
control: { type: 'range', min: 0, max: 8, step: 1 },
|
|
@@ -156,24 +172,41 @@ export const Default: Story = {
|
|
|
156
172
|
}
|
|
157
173
|
|
|
158
174
|
export const WithCustomColors: Story = {
|
|
159
|
-
render: () => <WakaTreemapChart data={salesByCategoryData} width={600} height={400}
|
|
175
|
+
render: () => <WakaTreemapChart data={salesByCategoryData} width={600} height={400} colorBy="category" />,
|
|
160
176
|
}
|
|
161
177
|
|
|
162
178
|
export const ColorSchemes: Story = {
|
|
163
179
|
render: () => (
|
|
164
180
|
<div className="space-y-6">
|
|
165
181
|
<div>
|
|
166
|
-
<p className="text-sm text-muted-foreground mb-2">
|
|
167
|
-
<WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="
|
|
182
|
+
<p className="text-sm text-muted-foreground mb-2">Default</p>
|
|
183
|
+
<WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="default" />
|
|
184
|
+
</div>
|
|
185
|
+
<div>
|
|
186
|
+
<p className="text-sm text-muted-foreground mb-2">Cool</p>
|
|
187
|
+
<WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="cool" />
|
|
168
188
|
</div>
|
|
169
189
|
<div>
|
|
170
|
-
<p className="text-sm text-muted-foreground mb-2">
|
|
171
|
-
<WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="
|
|
190
|
+
<p className="text-sm text-muted-foreground mb-2">Warm</p>
|
|
191
|
+
<WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="warm" />
|
|
172
192
|
</div>
|
|
173
193
|
<div>
|
|
174
|
-
<p className="text-sm text-muted-foreground mb-2">
|
|
175
|
-
<WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="
|
|
194
|
+
<p className="text-sm text-muted-foreground mb-2">Neon</p>
|
|
195
|
+
<WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="neon" />
|
|
176
196
|
</div>
|
|
197
|
+
<div>
|
|
198
|
+
<p className="text-sm text-muted-foreground mb-2">Pastel</p>
|
|
199
|
+
<WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="pastel" />
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
),
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export const ColorByValue: Story = {
|
|
206
|
+
render: () => (
|
|
207
|
+
<div className="space-y-4">
|
|
208
|
+
<p className="text-sm text-muted-foreground">Colors are based on value (gradient from blue to red)</p>
|
|
209
|
+
<WakaTreemapChart data={portfolioData} width={600} height={350} colorBy="value" showLegend={false} />
|
|
177
210
|
</div>
|
|
178
211
|
),
|
|
179
212
|
}
|
|
@@ -187,7 +220,8 @@ export const DrillDown: Story = {
|
|
|
187
220
|
width={650}
|
|
188
221
|
height={400}
|
|
189
222
|
enableDrillDown
|
|
190
|
-
|
|
223
|
+
showBreadcrumb
|
|
224
|
+
colorScheme="default"
|
|
191
225
|
/>
|
|
192
226
|
</div>
|
|
193
227
|
),
|
|
@@ -252,12 +286,12 @@ export const Interactive: Story = {
|
|
|
252
286
|
data={portfolioData}
|
|
253
287
|
width={600}
|
|
254
288
|
height={350}
|
|
255
|
-
colorScheme="
|
|
289
|
+
colorScheme="default"
|
|
256
290
|
onNodeClick={(node) => setSelected(node)}
|
|
257
291
|
/>
|
|
258
292
|
{selected && (
|
|
259
293
|
<div className="p-4 border rounded-lg bg-muted/50">
|
|
260
|
-
<h4 className="font-semibold">{selected.
|
|
294
|
+
<h4 className="font-semibold">{selected.label}</h4>
|
|
261
295
|
{selected.value && (
|
|
262
296
|
<p className="text-2xl font-bold text-primary">
|
|
263
297
|
${selected.value.toLocaleString()}
|
|
@@ -277,47 +311,79 @@ export const Interactive: Story = {
|
|
|
277
311
|
|
|
278
312
|
export const WithHook: Story = {
|
|
279
313
|
render: () => {
|
|
280
|
-
const
|
|
314
|
+
const [rootId, setRootId] = React.useState<string | null>(null)
|
|
315
|
+
const [path, setPath] = React.useState<TreemapNode[]>([])
|
|
316
|
+
|
|
317
|
+
const { computeLayout, getTotalValue, findNode, getPathToNode } = useTreemapChart({
|
|
318
|
+
width: 600,
|
|
319
|
+
height: 350,
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
const handleNodeClick = (node: TreemapNode) => {
|
|
323
|
+
if (node.children && node.children.length > 0) {
|
|
324
|
+
setRootId(node.id)
|
|
325
|
+
const newPath = getPathToNode(diskUsageData, node.id)
|
|
326
|
+
setPath(newPath)
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const handleReset = () => {
|
|
331
|
+
setRootId(null)
|
|
332
|
+
setPath([])
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const handleBack = () => {
|
|
336
|
+
if (path.length > 1) {
|
|
337
|
+
const parentId = path[path.length - 2].id
|
|
338
|
+
setRootId(parentId)
|
|
339
|
+
setPath(path.slice(0, -1))
|
|
340
|
+
} else {
|
|
341
|
+
handleReset()
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const currentData = rootId ? (findNode(diskUsageData, rootId)?.children || diskUsageData) : diskUsageData
|
|
281
346
|
|
|
282
347
|
return (
|
|
283
348
|
<div className="space-y-4">
|
|
284
349
|
<div className="flex items-center gap-2">
|
|
285
|
-
|
|
350
|
+
<button
|
|
351
|
+
onClick={handleReset}
|
|
352
|
+
className="text-sm hover:underline"
|
|
353
|
+
>
|
|
354
|
+
Root
|
|
355
|
+
</button>
|
|
356
|
+
{path.map((crumb, index) => (
|
|
286
357
|
<React.Fragment key={crumb.id}>
|
|
287
|
-
|
|
288
|
-
<
|
|
289
|
-
onClick={() => drillDown(crumb)}
|
|
290
|
-
className="text-sm hover:underline"
|
|
291
|
-
>
|
|
292
|
-
{crumb.name}
|
|
293
|
-
</button>
|
|
358
|
+
<span className="text-muted-foreground">/</span>
|
|
359
|
+
<span className="text-sm">{crumb.label}</span>
|
|
294
360
|
</React.Fragment>
|
|
295
361
|
))}
|
|
296
362
|
</div>
|
|
297
363
|
<div className="flex gap-2">
|
|
298
364
|
<button
|
|
299
|
-
onClick={
|
|
300
|
-
disabled={
|
|
365
|
+
onClick={handleBack}
|
|
366
|
+
disabled={path.length === 0}
|
|
301
367
|
className="px-3 py-1 text-sm border rounded hover:bg-muted disabled:opacity-50"
|
|
302
368
|
>
|
|
303
369
|
Back
|
|
304
370
|
</button>
|
|
305
371
|
<button
|
|
306
|
-
onClick={
|
|
372
|
+
onClick={handleReset}
|
|
307
373
|
className="px-3 py-1 text-sm border rounded hover:bg-muted"
|
|
308
374
|
>
|
|
309
375
|
Reset
|
|
310
376
|
</button>
|
|
311
377
|
<span className="px-3 py-1 text-sm bg-muted rounded">
|
|
312
|
-
Total: {getTotalValue(
|
|
378
|
+
Total: {getTotalValue(currentData).toLocaleString()} MB
|
|
313
379
|
</span>
|
|
314
380
|
</div>
|
|
315
381
|
<WakaTreemapChart
|
|
316
|
-
data={
|
|
382
|
+
data={currentData}
|
|
317
383
|
width={600}
|
|
318
384
|
height={350}
|
|
319
385
|
enableDrillDown={false}
|
|
320
|
-
onNodeClick={
|
|
386
|
+
onNodeClick={handleNodeClick}
|
|
321
387
|
/>
|
|
322
388
|
</div>
|
|
323
389
|
)
|
|
@@ -341,9 +407,9 @@ export const PortfolioDashboard: Story = {
|
|
|
341
407
|
data={portfolioData}
|
|
342
408
|
width={650}
|
|
343
409
|
height={400}
|
|
344
|
-
colorScheme="
|
|
410
|
+
colorScheme="default"
|
|
345
411
|
enableDrillDown
|
|
346
|
-
|
|
412
|
+
showBreadcrumb
|
|
347
413
|
/>
|
|
348
414
|
</div>
|
|
349
415
|
),
|
|
@@ -365,14 +431,53 @@ export const DiskUsageDashboard: Story = {
|
|
|
365
431
|
data={diskUsageData}
|
|
366
432
|
width={650}
|
|
367
433
|
height={380}
|
|
368
|
-
colorScheme="
|
|
434
|
+
colorScheme="cool"
|
|
369
435
|
enableDrillDown
|
|
370
|
-
|
|
436
|
+
showBreadcrumb
|
|
371
437
|
/>
|
|
372
438
|
</div>
|
|
373
439
|
),
|
|
374
440
|
}
|
|
375
441
|
|
|
376
442
|
export const NoAnimation: Story = {
|
|
377
|
-
render: () => <WakaTreemapChart data={diskUsageData} width={500} height={300}
|
|
443
|
+
render: () => <WakaTreemapChart data={diskUsageData} width={500} height={300} animationDuration={0} />,
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export const WithLegend: Story = {
|
|
447
|
+
render: () => (
|
|
448
|
+
<div className="space-y-6">
|
|
449
|
+
<div>
|
|
450
|
+
<p className="text-sm text-muted-foreground mb-2">Legend on the right</p>
|
|
451
|
+
<WakaTreemapChart
|
|
452
|
+
data={salesByCategoryData}
|
|
453
|
+
width={600}
|
|
454
|
+
height={350}
|
|
455
|
+
showLegend
|
|
456
|
+
legendPosition="right"
|
|
457
|
+
/>
|
|
458
|
+
</div>
|
|
459
|
+
<div>
|
|
460
|
+
<p className="text-sm text-muted-foreground mb-2">Legend at the bottom</p>
|
|
461
|
+
<WakaTreemapChart
|
|
462
|
+
data={salesByCategoryData}
|
|
463
|
+
width={600}
|
|
464
|
+
height={350}
|
|
465
|
+
showLegend
|
|
466
|
+
legendPosition="bottom"
|
|
467
|
+
/>
|
|
468
|
+
</div>
|
|
469
|
+
</div>
|
|
470
|
+
),
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
export const WithZoomControls: Story = {
|
|
474
|
+
render: () => (
|
|
475
|
+
<WakaTreemapChart
|
|
476
|
+
data={portfolioData}
|
|
477
|
+
width={600}
|
|
478
|
+
height={400}
|
|
479
|
+
showZoomControls
|
|
480
|
+
enableZoomToFit
|
|
481
|
+
/>
|
|
482
|
+
),
|
|
378
483
|
}
|
|
@@ -663,7 +663,7 @@ interface TreemapRectangleProps {
|
|
|
663
663
|
minLabelSize: number
|
|
664
664
|
animationDuration: number
|
|
665
665
|
onClick: () => void
|
|
666
|
-
onMouseEnter: () => void
|
|
666
|
+
onMouseEnter: (e: React.MouseEvent<SVGGElement>) => void
|
|
667
667
|
onMouseLeave: () => void
|
|
668
668
|
}
|
|
669
669
|
|
|
@@ -989,7 +989,7 @@ export function WakaTreemapChart({
|
|
|
989
989
|
minLabelSize={minLabelSize}
|
|
990
990
|
animationDuration={animationDuration}
|
|
991
991
|
onClick={() => handleNodeClick(node)}
|
|
992
|
-
onMouseEnter={(e:
|
|
992
|
+
onMouseEnter={(e: React.MouseEvent<SVGGElement>) => handleMouseEnter(node, e)}
|
|
993
993
|
onMouseLeave={handleMouseLeave}
|
|
994
994
|
/>
|
|
995
995
|
)
|