fix: add mode descriptions and remove double borders

Address two issues with the tab-style mode selector:

1. Add back helpful description text
   - Each mode now shows its description below the tabs
   - Description updates based on active tab
   - Preserves the helpful context from the old button layout

2. Remove double borders
   - Remove wrapper div that added extra background/padding
   - Let mode-specific controls use their own styling
   - Eliminates visual layering conflicts
   - Creates cleaner, more native tab-to-content flow

Mode descriptions:
- 🎯 Smart: "Research-backed progressive difficulty with adaptive scaffolding per problem"
- 🎛️ Manual: "Full control over display options with uniform scaffolding across all problems"
- 🎓 Mastery: "Skill-based progression with automatic review mixing for pedagogical practice"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-11-10 16:15:40 -06:00
parent 8910f6a197
commit 6f2f6d444c
2 changed files with 99 additions and 88 deletions

View File

@@ -105,39 +105,28 @@ export function ConfigPanel({ formState, onChange, isDark = false }: ConfigPanel
isDark={isDark} isDark={isDark}
/> />
{/* Mode Selector Tabs */} {/* Mode Selector Tabs with description */}
<ModeSelector <ModeSelector
currentMode={formState.mode ?? 'smart'} currentMode={formState.mode ?? 'smart'}
onChange={handleModeChange} onChange={handleModeChange}
isDark={isDark} isDark={isDark}
/> />
{/* Mode-specific controls as tab content */} {/* Mode-specific controls - no wrapper, let controls style themselves */}
<div {/* Smart Mode Controls */}
data-element="mode-content" {(!formState.mode || formState.mode === 'smart') && (
className={stack({ <SmartModeControls formState={formState} onChange={onChange} isDark={isDark} />
gap: '3', )}
padding: '1.5rem',
backgroundColor: isDark ? 'gray.700' : 'gray.50',
borderRadius: '0 0 8px 8px',
marginTop: '-1.5rem', // Connect visually to tabs
})}
>
{/* Smart Mode Controls */}
{(!formState.mode || formState.mode === 'smart') && (
<SmartModeControls formState={formState} onChange={onChange} isDark={isDark} />
)}
{/* Manual Mode Controls */} {/* Manual Mode Controls */}
{formState.mode === 'manual' && ( {formState.mode === 'manual' && (
<ManualModeControls formState={formState} onChange={onChange} isDark={isDark} /> <ManualModeControls formState={formState} onChange={onChange} isDark={isDark} />
)} )}
{/* Mastery Mode Controls */} {/* Mastery Mode Controls */}
{formState.mode === 'mastery' && ( {formState.mode === 'mastery' && (
<MasteryModePanel formState={formState} onChange={onChange} isDark={isDark} /> <MasteryModePanel formState={formState} onChange={onChange} isDark={isDark} />
)} )}
</div>
</div> </div>
) )
} }

View File

@@ -18,93 +18,115 @@ export function ModeSelector({ currentMode, onChange, isDark = false }: ModeSele
id: 'smart' as const, id: 'smart' as const,
emoji: '🎯', emoji: '🎯',
label: 'Smart Difficulty', label: 'Smart Difficulty',
description: 'Research-backed progressive difficulty with adaptive scaffolding per problem',
}, },
{ {
id: 'manual' as const, id: 'manual' as const,
emoji: '🎛️', emoji: '🎛️',
label: 'Manual Control', label: 'Manual Control',
description: 'Full control over display options with uniform scaffolding across all problems',
}, },
{ {
id: 'mastery' as const, id: 'mastery' as const,
emoji: '🎓', emoji: '🎓',
label: 'Mastery Progression', label: 'Mastery Progression',
description: 'Skill-based progression with automatic review mixing for pedagogical practice',
}, },
] ]
const currentModeData = modes.find((m) => m.id === currentMode)
return ( return (
<div <div data-component="mode-selector-tabs">
data-component="mode-selector-tabs" {/* Tab buttons */}
className={css({ <div
display: 'flex', className={css({
gap: '0.5rem', display: 'flex',
borderBottom: '2px solid', gap: '0.5rem',
borderColor: isDark ? 'gray.600' : 'gray.200', borderBottom: '2px solid',
marginBottom: '1.5rem', borderColor: isDark ? 'gray.600' : 'gray.200',
})} })}
> >
{modes.map((mode) => { {modes.map((mode) => {
const isActive = currentMode === mode.id const isActive = currentMode === mode.id
return ( return (
<button <button
key={mode.id} key={mode.id}
type="button" type="button"
data-action={`select-${mode.id}-mode`} data-action={`select-${mode.id}-mode`}
data-selected={isActive} data-selected={isActive}
onClick={() => onChange(mode.id)} onClick={() => onChange(mode.id)}
className={css({ className={css({
flex: 1, flex: 1,
padding: '1rem 1.5rem', padding: '1rem 1.5rem',
border: 'none', border: 'none',
borderBottom: '3px solid', borderBottom: '3px solid',
borderBottomColor: isActive ? 'blue.500' : 'transparent', borderBottomColor: isActive ? 'blue.500' : 'transparent',
backgroundColor: isActive
? isDark
? 'gray.700'
: 'white'
: isDark
? 'gray.800'
: 'gray.50',
color: isActive
? isDark
? 'blue.300'
: 'blue.600'
: isDark
? 'gray.400'
: 'gray.600',
cursor: 'pointer',
transition: 'all 0.2s',
fontSize: '0.95rem',
fontWeight: isActive ? '700' : '500',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '0.5rem',
borderTopLeftRadius: '8px',
borderTopRightRadius: '8px',
_hover: {
backgroundColor: isActive backgroundColor: isActive
? isDark ? isDark
? 'gray.700' ? 'gray.700'
: 'white' : 'white'
: isDark : isDark
? 'gray.700' ? 'gray.800'
: 'gray.100', : 'gray.50',
borderBottomColor: isActive ? 'blue.500' : isDark ? 'gray.500' : 'gray.400',
color: isActive color: isActive
? isDark ? isDark
? 'blue.300' ? 'blue.300'
: 'blue.600' : 'blue.600'
: isDark : isDark
? 'gray.300' ? 'gray.400'
: 'gray.700', : 'gray.600',
}, cursor: 'pointer',
})} transition: 'all 0.2s',
> fontSize: '0.95rem',
<span className={css({ fontSize: '1.25rem' })}>{mode.emoji}</span> fontWeight: isActive ? '700' : '500',
<span>{mode.label}</span> display: 'flex',
</button> alignItems: 'center',
) justifyContent: 'center',
})} gap: '0.5rem',
borderTopLeftRadius: '8px',
borderTopRightRadius: '8px',
_hover: {
backgroundColor: isActive
? isDark
? 'gray.700'
: 'white'
: isDark
? 'gray.700'
: 'gray.100',
borderBottomColor: isActive ? 'blue.500' : isDark ? 'gray.500' : 'gray.400',
color: isActive
? isDark
? 'blue.300'
: 'blue.600'
: isDark
? 'gray.300'
: 'gray.700',
},
})}
>
<span className={css({ fontSize: '1.25rem' })}>{mode.emoji}</span>
<span>{mode.label}</span>
</button>
)
})}
</div>
{/* Description of active mode */}
{currentModeData && (
<p
className={css({
fontSize: 'sm',
color: isDark ? 'gray.400' : 'gray.600',
mt: '3',
mb: '3',
px: '2',
lineHeight: '1.5',
})}
>
{currentModeData.description}
</p>
)}
</div> </div>
) )
} }