11'use client' ;
22
33import { AnimatePresence , motion } from 'framer-motion' ;
4- import { useEffect , useState } from 'react' ;
4+ import { useCallback , useEffect , useState } from 'react' ;
55import type { Card , Comparison } from '../../types' ;
66import { Button } from '../ui/Button' ;
77import { SwipeableCard } from './SwipeableCard' ;
@@ -41,22 +41,40 @@ export function SwipeComparisonView({
4141 return ( ) => clearTimeout ( timer ) ;
4242 } , [ ] ) ;
4343
44+ const handleSelection = useCallback (
45+ async ( card : Card ) => {
46+ setIsSubmitting ( true ) ;
47+ setShowInstructions ( false ) ;
48+
49+ try {
50+ onSelect ( card ) ;
51+ } finally {
52+ setIsSubmitting ( false ) ;
53+ setSelectedCard ( null ) ;
54+ }
55+ } ,
56+ [ onSelect ]
57+ ) ;
58+
4459 // Helper function to execute the current mode action
45- const executeAction = ( card : Card ) => {
46- if ( mode === 'pick' ) {
47- handleSelection ( card ) ;
48- } else {
49- // In discard mode, select the other card(s)
50- const otherCards = comparison . cards . filter ( c => c . id !== card . id ) ;
51- if ( otherCards . length === 1 ) {
52- handleSelection ( otherCards [ 0 ] ) ;
53- } else if ( otherCards . length > 1 ) {
54- // For multi-card comparisons in discard mode, we'd need more complex logic
55- // For now, just pick the first non-discarded card
56- handleSelection ( otherCards [ 0 ] ) ;
60+ const executeAction = useCallback (
61+ ( card : Card ) => {
62+ if ( mode === 'pick' ) {
63+ handleSelection ( card ) ;
64+ } else {
65+ // In discard mode, select the other card(s)
66+ const otherCards = comparison . cards . filter ( c => c . id !== card . id ) ;
67+ if ( otherCards . length === 1 ) {
68+ handleSelection ( otherCards [ 0 ] ) ;
69+ } else if ( otherCards . length > 1 ) {
70+ // For multi-card comparisons in discard mode, we'd need more complex logic
71+ // For now, just pick the first non-discarded card
72+ handleSelection ( otherCards [ 0 ] ) ;
73+ }
5774 }
58- }
59- } ;
75+ } ,
76+ [ mode , comparison . cards , handleSelection ]
77+ ) ;
6078
6179 // Keyboard navigation
6280 useEffect ( ( ) => {
@@ -135,7 +153,18 @@ export function SwipeComparisonView({
135153
136154 document . addEventListener ( 'keydown' , handleKeyDown ) ;
137155 return ( ) => document . removeEventListener ( 'keydown' , handleKeyDown ) ;
138- } , [ disabled , isSubmitting , selectedCard , focusedCardIndex , comparison . cards , mode ] ) ;
156+ } , [
157+ disabled ,
158+ isSubmitting ,
159+ selectedCard ,
160+ focusedCardIndex ,
161+ comparison . cards ,
162+ executeAction ,
163+ handleSelection ,
164+ setMode ,
165+ setFocusedCardIndex ,
166+ setSelectedCard ,
167+ ] ) ;
139168
140169 const handleCardSwipeRight = ( card : Card ) => {
141170 if ( disabled || isSubmitting ) return ;
@@ -157,18 +186,6 @@ export function SwipeComparisonView({
157186 setSelectedCard ( card ) ;
158187 } ;
159188
160- const handleSelection = async ( card : Card ) => {
161- setIsSubmitting ( true ) ;
162- setShowInstructions ( false ) ;
163-
164- try {
165- onSelect ( card ) ;
166- } finally {
167- setIsSubmitting ( false ) ;
168- setSelectedCard ( null ) ;
169- }
170- } ;
171-
172189 const handleConfirm = ( ) => {
173190 if ( selectedCard ) {
174191 handleSelection ( selectedCard ) ;
@@ -203,32 +220,43 @@ export function SwipeComparisonView({
203220 </ div >
204221 ) }
205222
206- { /* Mode toggle */ }
223+ { /* Mode toggle - simplified and less prominent */ }
207224 < div className = "flex items-center justify-center" >
208- < div className = "bg-muted p-1 rounded-lg flex gap-1" >
225+ < div className = "flex items-center gap-2 text-sm text-muted-foreground" >
226+ < span > Mode:</ span >
209227 < button
210228 type = "button"
211- onClick = { ( ) => setMode ( 'pick' ) }
212- className = { `px-4 py-2 text-sm font-medium rounded-md transition-all ${
213- mode === 'pick'
214- ? 'bg-primary text-primary-foreground shadow-sm'
215- : 'text-muted-foreground hover:text-foreground hover:bg-background/50'
216- } `}
217- aria-pressed = { mode === 'pick' }
229+ onClick = { ( ) => setMode ( mode === 'pick' ? 'discard' : 'pick' ) }
230+ className = "inline-flex items-center gap-2 px-3 py-1 rounded-md bg-muted hover:bg-muted/80 transition-colors"
231+ aria-label = { `Switch to ${ mode === 'pick' ? 'discard' : 'pick' } mode. Currently in ${ mode } mode.` }
218232 >
219- Pick Mode
220- </ button >
221- < button
222- type = "button"
223- onClick = { ( ) => setMode ( 'discard' ) }
224- className = { `px-4 py-2 text-sm font-medium rounded-md transition-all ${
225- mode === 'discard'
226- ? 'bg-primary text-primary-foreground shadow-sm'
227- : 'text-muted-foreground hover:text-foreground hover:bg-background/50'
228- } `}
229- aria-pressed = { mode === 'discard' }
230- >
231- Discard Mode
233+ { mode === 'pick' ? (
234+ < >
235+ < span className = "w-2 h-2 rounded-full bg-green-500" />
236+ Choose favorite
237+ </ >
238+ ) : (
239+ < >
240+ < span className = "w-2 h-2 rounded-full bg-red-500" />
241+ Remove unwanted
242+ </ >
243+ ) }
244+ < svg
245+ className = "w-3 h-3"
246+ fill = "none"
247+ stroke = "currentColor"
248+ viewBox = "0 0 24 24"
249+ role = "img"
250+ aria-label = "Switch mode"
251+ >
252+ < title > Switch mode</ title >
253+ < path
254+ strokeLinecap = "round"
255+ strokeLinejoin = "round"
256+ strokeWidth = { 2 }
257+ d = "M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4"
258+ />
259+ </ svg >
232260 </ button >
233261 </ div >
234262 </ div >
@@ -244,35 +272,13 @@ export function SwipeComparisonView({
244272 transition = { { duration : 0.3 } }
245273 >
246274 < h2 className = "text-2xl font-semibold" >
247- { mode === 'pick' ? 'Which do you prefer?' : 'Which do you want to discard ?' }
275+ { mode === 'pick' ? 'Which do you prefer?' : 'Which would you eliminate ?' }
248276 </ h2 >
249277 < p className = "text-muted-foreground" >
250278 { comparison . cards . length === 2 ? (
251- mode === 'pick' ? (
252- < >
253- Use < kbd className = "px-1 py-0.5 bg-muted rounded text-xs" > ←</ kbd > { ' ' }
254- < kbd className = "px-1 py-0.5 bg-muted rounded text-xs" > →</ kbd > to pick, or tap to
255- select manually
256- </ >
257- ) : (
258- < >
259- Use < kbd className = "px-1 py-0.5 bg-muted rounded text-xs" > ←</ kbd > { ' ' }
260- < kbd className = "px-1 py-0.5 bg-muted rounded text-xs" > →</ kbd > to discard, or tap
261- to select manually
262- </ >
263- )
264- ) : mode === 'pick' ? (
265- < >
266- Use < kbd className = "px-1 py-0.5 bg-muted rounded text-xs" > ←</ kbd > { ' ' }
267- < kbd className = "px-1 py-0.5 bg-muted rounded text-xs" > →</ kbd > to navigate,{ ' ' }
268- < kbd className = "px-1 py-0.5 bg-muted rounded text-xs" > Space</ kbd > to pick
269- </ >
279+ < > Use arrow keys or tap to choose</ >
270280 ) : (
271- < >
272- Use < kbd className = "px-1 py-0.5 bg-muted rounded text-xs" > ←</ kbd > { ' ' }
273- < kbd className = "px-1 py-0.5 bg-muted rounded text-xs" > →</ kbd > to navigate,{ ' ' }
274- < kbd className = "px-1 py-0.5 bg-muted rounded text-xs" > Space</ kbd > to discard
275- </ >
281+ < > Use arrow keys to browse, Space to select</ >
276282 ) }
277283 </ p >
278284 </ motion . div >
@@ -319,16 +325,16 @@ export function SwipeComparisonView({
319325 />
320326 </ button >
321327
322- { /* Focus indicator for multi-card comparisons */ }
328+ { /* Subtle focus indicator for multi-card comparisons */ }
323329 { comparison . cards . length > 2 && focusedCardIndex === index && (
324330 < motion . div
325- className = "absolute top-2 right-2 bg-primary text-primary- foreground px-2 py-1 rounded-md text-xs font-medium shadow-lg "
331+ className = "absolute top-2 right-2 bg-background/80 backdrop-blur-sm text- foreground px-2 py-1 rounded text-xs font-medium shadow-sm border "
326332 initial = { { scale : 0 , opacity : 0 } }
327- animate = { { scale : 1 , opacity : 1 } }
333+ animate = { { scale : 1 , opacity : 0.9 } }
328334 exit = { { scale : 0 , opacity : 0 } }
329335 transition = { { duration : 0.2 } }
330336 >
331- Press Space to { mode }
337+ Space to { mode === 'pick' ? 'choose' : 'eliminate' }
332338 </ motion . div >
333339 ) }
334340 </ motion . div >
@@ -392,24 +398,18 @@ export function SwipeComparisonView({
392398 </ div >
393399 ) }
394400
395- { /* Keyboard shortcuts hint */ }
396- < motion . section
397- className = "text-center text-xs text-muted-foreground space-y-1 "
401+ { /* Simplified keyboard hints */ }
402+ < motion . div
403+ className = "text-center text-xs text-muted-foreground"
398404 initial = { { opacity : 0 } }
399405 animate = { { opacity : 1 } }
400- transition = { { delay : 1 } }
401- aria-label = "Keyboard shortcuts"
406+ transition = { { delay : 2 } }
402407 >
403408 < div >
404- { comparison . cards . length === 2
405- ? `${ mode === 'pick' ? 'Pick' : 'Discard' } mode: ← → arrows to ${ mode } • P/D to switch mode • Enter to confirm • Esc to cancel`
406- : `${ mode === 'pick' ? 'Pick' : 'Discard' } mode: ← → to navigate • Space to ${ mode } • P/D to switch mode • Enter to confirm` }
407- </ div >
408- < div >
409- Quick select: 1 for left option • 2 for right option • P for pick mode • D for discard
410- mode
409+ Keyboard: { comparison . cards . length === 2 ? '← → to choose' : '← → Space to select' } • P/D
410+ to switch mode
411411 </ div >
412- </ motion . section >
412+ </ motion . div >
413413
414414 { /* Loading overlay */ }
415415 < AnimatePresence >
0 commit comments