Skip to content

Commit 08360c3

Browse files
rmzlbclaude
andcommitted
Add interactive How-To guide with accordion UI
- Created collapsible accordion for usage instructions - Added 3 clear steps: Configure, Add pieces, Optimize - Included helpful tips section with practical advice - Improved mobile UX with auto-scroll to results on optimize - Better mobile-responsive design with compact accordion 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 979f6ae commit 08360c3

2 files changed

Lines changed: 157 additions & 0 deletions

File tree

components/CuttingOptimizer.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import PositioningReport from './PositioningReport'
1212
import VerificationCard from './VerificationCard'
1313
import TestsCard from './TestsCard'
1414
import ExportPanel from './ExportPanel'
15+
import HowItWorks from './HowItWorks'
1516
import type { PieceSpec, OptimizationConfig, OptimizationResult } from '@/lib/types'
1617

1718
export default function CuttingOptimizer() {
@@ -52,6 +53,16 @@ export default function CuttingOptimizer() {
5253
setIsCalculating(false)
5354
setShowResults(true)
5455

56+
// Scroll to visualization on mobile devices
57+
if (window.innerWidth < 1024) { // lg breakpoint
58+
setTimeout(() => {
59+
const visualizationElement = document.getElementById('visualization-area')
60+
if (visualizationElement) {
61+
visualizationElement.scrollIntoView({ behavior: 'smooth', block: 'start' })
62+
}
63+
}, 100)
64+
}
65+
5566
// Trigger confetti for good results
5667
if (res.utilization > 0.75) {
5768
confetti({
@@ -138,6 +149,9 @@ export default function CuttingOptimizer() {
138149
</div>
139150

140151
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
152+
{/* How it works explanation */}
153+
<HowItWorks />
154+
141155
<div className="flex flex-col lg:flex-row gap-6">
142156
{/* Left sidebar - Controls */}
143157
<motion.aside
@@ -216,6 +230,7 @@ export default function CuttingOptimizer() {
216230

217231
{/* Main content - Visualization */}
218232
<motion.main
233+
id="visualization-area"
219234
initial={{ opacity: 0 }}
220235
animate={{ opacity: 1 }}
221236
transition={{ delay: 0.1 }}

components/HowItWorks.tsx

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
'use client'
2+
3+
import { useState } from 'react'
4+
import { motion, AnimatePresence } from 'motion/react'
5+
6+
export default function HowItWorks() {
7+
const [isExpanded, setIsExpanded] = useState(false)
8+
9+
return (
10+
<motion.div
11+
initial={{ opacity: 0, y: 20 }}
12+
animate={{ opacity: 1, y: 0 }}
13+
className="bg-gradient-to-br from-amber-50 via-orange-50 to-white rounded-2xl border border-amber-200 p-4 sm:p-5 mb-6"
14+
>
15+
{/* Header with toggle */}
16+
<button
17+
onClick={() => setIsExpanded(!isExpanded)}
18+
className="w-full flex items-center justify-between group"
19+
>
20+
<div className="flex items-center gap-3">
21+
<div className="w-8 h-8 bg-gradient-to-br from-amber-400 to-orange-500 rounded-lg flex items-center justify-center text-white text-sm font-bold">
22+
?
23+
</div>
24+
<div className="text-left">
25+
<h3 className="text-base font-medium text-neutral-900">Comment utiliser l'outil</h3>
26+
<p className="text-sm text-neutral-600">
27+
{isExpanded ? 'Cliquez pour masquer' : '3 étapes simples - Cliquez pour voir'}
28+
</p>
29+
</div>
30+
</div>
31+
32+
<motion.div
33+
animate={{ rotate: isExpanded ? 180 : 0 }}
34+
className="p-1.5 hover:bg-white/50 rounded-lg transition-colors"
35+
>
36+
<svg className="w-5 h-5 text-neutral-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
37+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
38+
</svg>
39+
</motion.div>
40+
</button>
41+
42+
{/* Expandable content */}
43+
<AnimatePresence initial={false}>
44+
{isExpanded && (
45+
<motion.div
46+
initial={{ height: 0, opacity: 0 }}
47+
animate={{ height: "auto", opacity: 1 }}
48+
exit={{ height: 0, opacity: 0 }}
49+
transition={{ duration: 0.3, ease: "easeInOut" }}
50+
className="overflow-hidden"
51+
>
52+
<div className="pt-6 space-y-4">
53+
{/* Step 1 */}
54+
<div className="flex gap-4">
55+
<div className="flex-shrink-0">
56+
<div className="w-8 h-8 bg-gradient-to-br from-blue-400 to-blue-600 rounded-full flex items-center justify-center text-white font-bold text-sm">
57+
1
58+
</div>
59+
</div>
60+
<div className="flex-1">
61+
<h4 className="font-medium text-neutral-900 mb-1">Configurez votre planche</h4>
62+
<p className="text-sm text-neutral-600 leading-relaxed">
63+
Entrez les dimensions de votre planche (largeur × hauteur) et l'épaisseur de trait de scie.
64+
Activez la rotation si vos pièces peuvent être tournées.
65+
</p>
66+
<div className="mt-2 inline-flex items-center gap-2 text-xs bg-blue-50 text-blue-700 px-3 py-1.5 rounded-lg">
67+
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
68+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
69+
</svg>
70+
Panneau de gauche
71+
</div>
72+
</div>
73+
</div>
74+
75+
{/* Step 2 */}
76+
<div className="flex gap-4">
77+
<div className="flex-shrink-0">
78+
<div className="w-8 h-8 bg-gradient-to-br from-green-400 to-green-600 rounded-full flex items-center justify-center text-white font-bold text-sm">
79+
2
80+
</div>
81+
</div>
82+
<div className="flex-1">
83+
<h4 className="font-medium text-neutral-900 mb-1">Ajoutez vos pièces</h4>
84+
<p className="text-sm text-neutral-600 leading-relaxed">
85+
Définissez chaque type de pièce avec ses dimensions (L × H) et la quantité désirée.
86+
Utilisez le bouton "+" pour ajouter de nouveaux types.
87+
</p>
88+
<div className="mt-2 inline-flex items-center gap-2 text-xs bg-green-50 text-green-700 px-3 py-1.5 rounded-lg">
89+
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
90+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
91+
</svg>
92+
Section "Pièces à découper"
93+
</div>
94+
</div>
95+
</div>
96+
97+
{/* Step 3 */}
98+
<div className="flex gap-4">
99+
<div className="flex-shrink-0">
100+
<div className="w-8 h-8 bg-gradient-to-br from-amber-400 to-orange-600 rounded-full flex items-center justify-center text-white font-bold text-sm">
101+
3
102+
</div>
103+
</div>
104+
<div className="flex-1">
105+
<h4 className="font-medium text-neutral-900 mb-1">Lancez l'optimisation</h4>
106+
<p className="text-sm text-neutral-600 leading-relaxed">
107+
Cliquez sur "Optimiser la découpe" pour calculer le placement optimal.
108+
Le résultat s'affiche avec un plan détaillé et les statistiques.
109+
</p>
110+
<div className="mt-2 inline-flex items-center gap-2 text-xs bg-gradient-to-r from-amber-50 to-orange-50 text-orange-700 px-3 py-1.5 rounded-lg">
111+
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
112+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
113+
</svg>
114+
Résultats instantanés
115+
</div>
116+
</div>
117+
</div>
118+
119+
{/* Tips section */}
120+
<div className="mt-6 p-4 bg-gradient-to-r from-neutral-50 to-white rounded-xl border border-neutral-200">
121+
<div className="flex items-start gap-3">
122+
<svg className="w-5 h-5 text-amber-500 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
123+
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clipRule="evenodd" />
124+
</svg>
125+
<div className="flex-1">
126+
<h5 className="text-sm font-medium text-neutral-900 mb-1">Astuces</h5>
127+
<ul className="text-xs text-neutral-600 space-y-1">
128+
<li>• Utilisez le <span className="font-medium">zoom</span> pour mieux voir les détails</li>
129+
<li>• Exportez le plan en <span className="font-medium">PDF</span> pour l'atelier</li>
130+
<li>• L'algorithme <span className="font-medium">minimise automatiquement</span> les coupes et les chutes</li>
131+
<li>• Sur mobile, l'écran <span className="font-medium">défile automatiquement</span> vers les résultats</li>
132+
</ul>
133+
</div>
134+
</div>
135+
</div>
136+
</div>
137+
</motion.div>
138+
)}
139+
</AnimatePresence>
140+
</motion.div>
141+
)
142+
}

0 commit comments

Comments
 (0)