Skip to content

Commit 1a61651

Browse files
committed
feat: add keyboard controls to interactive sliders
- Add arrow key navigation (left/right) for both Values and ProductPrinciples sliders - Add space/enter key to pause/resume auto-advance - Add Home/End keys to jump to first/last slide - Add visual hints showing available keyboard controls - Controls only active when sliders are in view - Maintain existing mouse/touch interactions - Improve accessibility and user control
1 parent a9ebdcd commit 1a61651

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

src/components/ProductPrinciples.tsx

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,46 @@ const ProductPrinciples = () => {
138138
}
139139
}, [selectedPrinciple, isHovered]);
140140

141+
// Keyboard navigation
142+
useEffect(() => {
143+
const handleKeyDown = (event: KeyboardEvent) => {
144+
if (!isPrinciplesInView) return;
145+
146+
switch (event.key) {
147+
case 'ArrowLeft':
148+
event.preventDefault();
149+
setSelectedPrinciple(prev => prev === 0 ? translatedPrinciples.length - 1 : prev - 1);
150+
break;
151+
case 'ArrowRight':
152+
event.preventDefault();
153+
setSelectedPrinciple(prev => (prev + 1) % translatedPrinciples.length);
154+
break;
155+
case ' ':
156+
case 'Enter':
157+
event.preventDefault();
158+
// Pause/resume auto-advance
159+
setIsHovered(prev => !prev);
160+
break;
161+
case 'Home':
162+
event.preventDefault();
163+
setSelectedPrinciple(0);
164+
break;
165+
case 'End':
166+
event.preventDefault();
167+
setSelectedPrinciple(translatedPrinciples.length - 1);
168+
break;
169+
}
170+
};
171+
172+
if (isPrinciplesInView) {
173+
document.addEventListener('keydown', handleKeyDown);
174+
}
175+
176+
return () => {
177+
document.removeEventListener('keydown', handleKeyDown);
178+
};
179+
}, [isPrinciplesInView, translatedPrinciples.length]);
180+
141181
const containerVariants = {
142182
hidden: { opacity: 0 },
143183
visible: {
@@ -168,9 +208,14 @@ const ProductPrinciples = () => {
168208
<h2 className="text-4xl md:text-5xl font-bold text-white mb-6">
169209
{t('principles.title')}
170210
</h2>
171-
<p className="text-xl text-muted-foreground max-w-3xl mx-auto">
211+
<p className="text-xl text-muted-foreground max-w-3xl mx-auto mb-4">
172212
{t('principles.subtitle')}
173213
</p>
214+
<div className="text-sm text-muted-foreground/70 flex items-center justify-center gap-2">
215+
<span>Use arrow keys to navigate</span>
216+
<span></span>
217+
<span>Space to pause/resume</span>
218+
</div>
174219
</SectionTitle>
175220
</BlurReveal>
176221
</motion.div>

src/components/Values.tsx

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,16 +180,61 @@ const Values = () => {
180180
}
181181
}, [selectedValue]);
182182

183+
// Keyboard navigation
184+
useEffect(() => {
185+
const handleKeyDown = (event: KeyboardEvent) => {
186+
if (!isValuesInView) return;
187+
188+
switch (event.key) {
189+
case 'ArrowLeft':
190+
event.preventDefault();
191+
setSelectedValue(prev => prev === 0 ? translatedValues.length - 1 : prev - 1);
192+
break;
193+
case 'ArrowRight':
194+
event.preventDefault();
195+
setSelectedValue(prev => (prev + 1) % translatedValues.length);
196+
break;
197+
case ' ':
198+
case 'Enter':
199+
event.preventDefault();
200+
// Pause/resume auto-advance
201+
setIsHovered(prev => !prev);
202+
break;
203+
case 'Home':
204+
event.preventDefault();
205+
setSelectedValue(0);
206+
break;
207+
case 'End':
208+
event.preventDefault();
209+
setSelectedValue(translatedValues.length - 1);
210+
break;
211+
}
212+
};
213+
214+
if (isValuesInView) {
215+
document.addEventListener('keydown', handleKeyDown);
216+
}
217+
218+
return () => {
219+
document.removeEventListener('keydown', handleKeyDown);
220+
};
221+
}, [isValuesInView, translatedValues.length]);
222+
183223
return (
184224
<section className="py-20 px-4 sm:px-6 lg:px-8" ref={valuesSectionRef}>
185225
<div className="max-w-7xl mx-auto">
186226
<div className="text-center mb-16">
187227
<h2 className="text-5xl md:text-7xl font-bold mb-6 bg-gradient-to-r from-foreground to-muted-foreground bg-clip-text text-transparent">
188228
{t('values.title')}
189229
</h2>
190-
<p className="text-xl text-muted-foreground max-w-3xl mx-auto">
230+
<p className="text-xl text-muted-foreground max-w-3xl mx-auto mb-4">
191231
{t('values.subtitle')}
192232
</p>
233+
<div className="text-sm text-muted-foreground/70 flex items-center justify-center gap-2">
234+
<span>Use arrow keys to navigate</span>
235+
<span></span>
236+
<span>Space to pause/resume</span>
237+
</div>
193238
</div>
194239

195240
{/* Value Navigation */}

0 commit comments

Comments
 (0)