| import { useState, useEffect } from 'react' | |
| import { X, ChevronRight, ChevronLeft, HelpCircle, Zap, Layers, Share2, Palette, Code } from 'lucide-react' | |
| import { useTutorial } from './TutorialContext' | |
| const tutorialSteps = [ | |
| { | |
| id: 'toolbar', | |
| title: 'The Toolbar', | |
| description: 'Access all neural layer types and tools from here. Drag nodes onto the canvas to start building.', | |
| position: { top: '120px', left: '20px' }, | |
| target: 'toolbar' | |
| }, | |
| { | |
| id: 'canvas', | |
| title: 'Design Canvas', | |
| description: 'This is your main workspace. Drop nodes here and connect them to create your neural architecture.', | |
| position: { top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }, | |
| target: 'canvas' | |
| }, | |
| { | |
| id: 'properties', | |
| title: 'Properties Panel', | |
| description: 'Select any node to view and edit its parameters here. All layer configurations are centralized.', | |
| position: { top: '120px', right: '20px' }, | |
| target: 'properties-panel' | |
| }, | |
| { | |
| id: 'connections', | |
| title: 'Making Connections', | |
| description: 'Click and drag from one node\'s output to another\'s input to create data flow connections.', | |
| position: { top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }, | |
| target: 'canvas' | |
| }, | |
| { | |
| id: 'export', | |
| title: 'Export & Share', | |
| description: 'Export your architecture to code or share with your team. Supports PyTorch, TensorFlow, and more.', | |
| position: { bottom: '120px', right: '20px' }, | |
| target: 'export-button' | |
| }, | |
| { | |
| id: 'theme', | |
| title: 'Dark Mode', | |
| description: 'Toggle between light and dark themes for comfortable viewing in any environment.', | |
| position: { top: '20px', right: '20px' }, | |
| target: 'theme-toggle' | |
| }, | |
| { | |
| id: 'complete', | |
| title: 'Tutorial Complete!', | |
| description: 'You\'re ready to start building. Remember, you can always access this tutorial from the help menu.', | |
| position: { top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }, | |
| target: null | |
| } | |
| ] | |
| export default function TutorialOverlay() { | |
| const { currentStep, nextStep, previousStep, endTutorial } = useTutorial() | |
| const [isVisible, setIsVisible] = useState(false) | |
| const [highlightedElement, setHighlightedElement] = useState(null) | |
| useEffect(() => { | |
| setIsVisible(true) | |
| const timer = setTimeout(() => { | |
| const step = tutorialSteps[currentStep] | |
| if (step.target) { | |
| const element = document.querySelector(`[data-tutorial-target="${step.target}"]`) | |
| setHighlightedElement(element) | |
| } else { | |
| setHighlightedElement(null) | |
| } | |
| }, 100) | |
| return () => clearTimeout(timer) | |
| }, [currentStep]) | |
| const handleNext = () => { | |
| if (currentStep < tutorialSteps.length - 1) { | |
| nextStep() | |
| } else { | |
| endTutorial() | |
| } | |
| } | |
| const handlePrevious = () => { | |
| if (currentStep > 0) { | |
| previousStep() | |
| } | |
| } | |
| const currentTutorialStep = tutorialSteps[currentStep] | |
| return ( | |
| <> | |
| {/* Overlay */} | |
| <div className="fixed inset-0 bg-black bg-opacity-60 z-40" onClick={endTutorial} /> | |
| {/* Highlight Overlay */} | |
| {highlightedElement && ( | |
| <div className="fixed inset-0 z-40 pointer-events-none"> | |
| <div | |
| className="absolute border-4 border-primary-500 rounded-lg shadow-2xl transition-all duration-300" | |
| style={{ | |
| ...highlightedElement.getBoundingClientRect(), | |
| boxShadow: '0 0 0 9999px rgba(0, 0, 0, 0.6)' | |
| /> | |
| </div> | |
| )} | |
| {/* Tutorial Tooltip */} | |
| <div | |
| className={`fixed z-50 bg-white rounded-2xl shadow-2xl p-6 max-w-sm transition-all duration-300 ${ | |
| isVisible ? 'opacity-100 scale-100' : 'opacity-0 scale-95' | |
| }`} | |
| style={currentTutorialStep.position} | |
| > | |
| {/* Progress Dots */} | |
| <div className="flex items-center justify-center space-x-2 mb-4"> | |
| {tutorialSteps.map((_, index) => ( | |
| <div | |
| key={index} | |
| className={`w-2 h-2 rounded-full transition-all duration-300 ${ | |
| index === currentStep ? 'bg-primary-600 w-8' : 'bg-gray-300' | |
| }`} | |
| /> | |
| ))} | |
| </div> | |
| {/* Icon */} | |
| <div className="w-12 h-12 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4"> | |
| {currentStep === 0 && <Zap className="w-6 h-6 text-primary-600" />} | |
| {currentStep === 1 && <Layers className="w-6 h-6 text-primary-600" />} | |
| {currentStep === 2 && <Settings className="w-6 h-6 text-primary-600" />} | |
| {currentStep === 3 && <Share2 className="w-6 h-6 text-primary-600" />} | |
| {currentStep === 4 && <Code className="w-6 h-6 text-primary-600" />} | |
| {currentStep === 5 && <Palette className="w-6 h-6 text-primary-600" />} | |
| {currentStep === 6 && <Check className="w-6 h-6 text-primary-600" />} | |
| </div> | |
| {/* Content */} | |
| <h3 className="text-xl font-bold text-gray-900 mb-3 text-center"> | |
| {currentTutorialStep.title} | |
| </h3> | |
| <p className="text-gray-600 mb-6 text-center"> | |
| {currentTutorialStep.description} | |
| </p> | |
| {/* Actions */} | |
| <div className="flex items-center justify-between"> | |
| <button | |
| onClick={handlePrevious} | |
| disabled={currentStep === 0} | |
| className={`flex items-center space-x-2 px-4 py-2 rounded-lg transition-colors ${ | |
| currentStep === 0 | |
| ? 'text-gray-300 cursor-not-allowed' | |
| : 'text-gray-700 hover:bg-gray-100' | |
| }`} | |
| > | |
| <ChevronLeft className="w-4 h-4" /> | |
| <span className="text-sm">Previous</span> | |
| </button> | |
| <span className="text-sm text-gray-500"> | |
| {currentStep + 1} / {tutorialSteps.length} | |
| </span> | |
| <button | |
| onClick={handleNext} | |
| className="flex items-center space-x-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors" | |
| > | |
| <span className="text-sm"> | |
| {currentStep === tutorialSteps.length - 1 ? 'Finish' : 'Next'} | |
| </span> | |
| <ChevronRight className="w-4 h-4" /> | |
| </button> | |
| </div> | |
| {/* Skip Tutorial */} | |
| <button | |
| onClick={endTutorial} | |
| className="w-full mt-4 text-sm text-gray-500 hover:text-gray-700 transition-colors" | |
| > | |
| Skip tutorial | |
| </button> | |
| </div> | |
| {/* Close Button */} | |
| <button | |
| onClick={endTutorial} | |
| className="fixed top-4 right-4 z-50 w-10 h-10 bg-white rounded-full shadow-lg flex items-center justify-center hover:bg-gray-50 transition-colors" | |
| > | |
| <X className="w-5 h-5 text-gray-600" /> | |
| </button> | |
| </> | |
| ) | |
| } |