bolt-new / components /TutorialOverlay.js
00Boobs00's picture
Upload components/TutorialOverlay.js with huggingface_hub
591fafa verified
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>
</>
)
}