2026-01-16 01:32:53 +00:00
|
|
|
import * as React from 'react';
|
|
|
|
|
import { Dialog } from '@/components/ui/dialog';
|
|
|
|
|
import { Button } from '@/components/ui/button';
|
|
|
|
|
import { cn } from '@/lib/utils';
|
2026-01-18 12:55:28 +00:00
|
|
|
import { CheckCircle, ChevronRight, ChevronLeft } from 'lucide-react';
|
2026-01-16 01:32:53 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* OnboardingStep - Single step in the onboarding flow
|
|
|
|
|
*/
|
|
|
|
|
export interface OnboardingStep {
|
|
|
|
|
title: string;
|
|
|
|
|
description: string;
|
|
|
|
|
content?: React.ReactNode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* OnboardingProps - Properties for the Onboarding component
|
|
|
|
|
*/
|
|
|
|
|
export interface OnboardingProps {
|
|
|
|
|
/**
|
|
|
|
|
* Whether the onboarding is open
|
|
|
|
|
*/
|
|
|
|
|
open: boolean;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Callback when onboarding is closed
|
|
|
|
|
*/
|
|
|
|
|
onClose: () => void;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Steps to display in the onboarding flow
|
|
|
|
|
*/
|
|
|
|
|
steps: OnboardingStep[];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Optional callback when onboarding is completed
|
|
|
|
|
*/
|
|
|
|
|
onComplete?: () => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Onboarding - Multi-step onboarding flow component
|
|
|
|
|
*
|
|
|
|
|
* Guides new users through key features of the application.
|
|
|
|
|
* Displays steps sequentially with navigation controls.
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* ```tsx
|
|
|
|
|
* <Onboarding
|
|
|
|
|
* open={showOnboarding}
|
|
|
|
|
* onClose={() => setShowOnboarding(false)}
|
|
|
|
|
* steps={[
|
|
|
|
|
* { title: 'Welcome', description: 'Welcome to Veza!' },
|
|
|
|
|
* { title: 'Library', description: 'Manage your tracks here' },
|
|
|
|
|
* ]}
|
|
|
|
|
* onComplete={() => console.log('Onboarding complete')}
|
|
|
|
|
* />
|
|
|
|
|
* ```
|
|
|
|
|
*/
|
|
|
|
|
export function Onboarding({
|
|
|
|
|
open,
|
|
|
|
|
onClose,
|
|
|
|
|
steps,
|
|
|
|
|
onComplete,
|
|
|
|
|
}: OnboardingProps) {
|
|
|
|
|
const [currentStep, setCurrentStep] = React.useState(0);
|
|
|
|
|
|
|
|
|
|
const handleNext = () => {
|
|
|
|
|
if (currentStep < steps.length - 1) {
|
|
|
|
|
setCurrentStep(currentStep + 1);
|
|
|
|
|
} else {
|
|
|
|
|
handleComplete();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handlePrevious = () => {
|
|
|
|
|
if (currentStep > 0) {
|
|
|
|
|
setCurrentStep(currentStep - 1);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSkip = () => {
|
|
|
|
|
handleComplete();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleComplete = () => {
|
|
|
|
|
onComplete?.();
|
|
|
|
|
onClose();
|
|
|
|
|
// Reset to first step for next time
|
|
|
|
|
setCurrentStep(0);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (!open || steps.length === 0) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const step = steps[currentStep];
|
|
|
|
|
const isFirstStep = currentStep === 0;
|
|
|
|
|
const isLastStep = currentStep === steps.length - 1;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Dialog
|
|
|
|
|
open={open}
|
|
|
|
|
onClose={handleComplete}
|
|
|
|
|
title="Bienvenue sur Veza"
|
|
|
|
|
size="lg"
|
|
|
|
|
variant="info"
|
|
|
|
|
showCancel={false}
|
|
|
|
|
footer={
|
|
|
|
|
<div className="flex items-center justify-between w-full">
|
|
|
|
|
{/* Progress indicator */}
|
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
|
{steps.map((_, index) => (
|
|
|
|
|
<div
|
|
|
|
|
key={index}
|
|
|
|
|
className={cn(
|
|
|
|
|
'h-2 w-2 rounded-full transition-colors',
|
|
|
|
|
index === currentStep
|
ui(tokens): migrate kodo-cyan to primary (51 files, 88 instances)
Replace legacy text-kodo-cyan/border-kodo-cyan/bg-kodo-cyan with semantic
text-primary/border-primary/bg-primary across 51 components.
The brand primary color now uses the design system token, enabling proper
theme adaptation. Covers UI primitives, search, dashboard, chat, playlists,
settings, social, marketplace, and auth components.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 23:19:12 +00:00
|
|
|
? 'bg-primary w-8'
|
2026-01-16 01:32:53 +00:00
|
|
|
: index < currentStep
|
ui(tokens): migrate kodo-cyan to primary (51 files, 88 instances)
Replace legacy text-kodo-cyan/border-kodo-cyan/bg-kodo-cyan with semantic
text-primary/border-primary/bg-primary across 51 components.
The brand primary color now uses the design system token, enabling proper
theme adaptation. Covers UI primitives, search, dashboard, chat, playlists,
settings, social, marketplace, and auth components.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 23:19:12 +00:00
|
|
|
? 'bg-primary/50'
|
2026-02-08 23:08:42 +00:00
|
|
|
: 'bg-muted',
|
2026-01-16 01:32:53 +00:00
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Navigation buttons */}
|
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
|
<Button variant="ghost" onClick={handleSkip} size="sm">
|
|
|
|
|
Passer
|
|
|
|
|
</Button>
|
|
|
|
|
{!isFirstStep && (
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
onClick={handlePrevious}
|
|
|
|
|
size="sm"
|
|
|
|
|
>
|
|
|
|
|
<ChevronLeft className="w-4 h-4 mr-1" />
|
|
|
|
|
Précédent
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
<Button
|
|
|
|
|
variant="default"
|
|
|
|
|
onClick={handleNext}
|
|
|
|
|
size="sm"
|
|
|
|
|
>
|
|
|
|
|
{isLastStep ? (
|
|
|
|
|
<>
|
|
|
|
|
Terminer
|
|
|
|
|
<CheckCircle className="w-4 h-4 ml-1" />
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
Suivant
|
|
|
|
|
<ChevronRight className="w-4 h-4 ml-1" />
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
<div>
|
|
|
|
|
<h3 className="text-xl font-semibold text-white mb-2">
|
|
|
|
|
{step.title}
|
|
|
|
|
</h3>
|
2026-02-08 23:13:27 +00:00
|
|
|
<p className="text-muted-foreground text-sm leading-relaxed">
|
2026-01-16 01:32:53 +00:00
|
|
|
{step.description}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
{step.content && (
|
|
|
|
|
<div className="mt-6">{step.content}</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</Dialog>
|
|
|
|
|
);
|
|
|
|
|
}
|