refactor: convert mode selector to large tab-style interface

Transform the mode selector from small buttons within a card to large,
prominent tabs that visually integrate with the mode-specific content.

Changes:
- Replace grid of mode buttons with horizontal tab layout
- Active tab has blue bottom border and highlighted background
- Mode-specific controls now appear in a visually connected content area
- Tabs show emoji + label for clear mode identification:
  🎯 Smart Difficulty
  🎛️ Manual Control
  🎓 Mastery Progression

Visual improvements:
- More discoverable mode selection (tabs are prominent)
- Clear indication of which mode is active
- Natural tab-to-content visual flow
- Hover states provide better affordance
- Content area uses subtle background to separate from tabs

This creates a more intuitive UI where modes are the primary navigation
and the mode-specific controls are clearly scoped to the selected tab.

🤖 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:13:41 -06:00
parent 0425033080
commit 8910f6a197
2 changed files with 107 additions and 207 deletions

View File

@@ -105,27 +105,39 @@ export function ConfigPanel({ formState, onChange, isDark = false }: ConfigPanel
isDark={isDark}
/>
{/* Mode Selector */}
{/* Mode Selector Tabs */}
<ModeSelector
currentMode={formState.mode ?? 'smart'}
onChange={handleModeChange}
isDark={isDark}
/>
{/* Smart Mode Controls */}
{(!formState.mode || formState.mode === 'smart') && (
<SmartModeControls formState={formState} onChange={onChange} isDark={isDark} />
)}
{/* Mode-specific controls as tab content */}
<div
data-element="mode-content"
className={stack({
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 */}
{formState.mode === 'manual' && (
<ManualModeControls formState={formState} onChange={onChange} isDark={isDark} />
)}
{/* Manual Mode Controls */}
{formState.mode === 'manual' && (
<ManualModeControls formState={formState} onChange={onChange} isDark={isDark} />
)}
{/* Mastery Mode Controls */}
{formState.mode === 'mastery' && (
<MasteryModePanel formState={formState} onChange={onChange} isDark={isDark} />
)}
{/* Mastery Mode Controls */}
{formState.mode === 'mastery' && (
<MasteryModePanel formState={formState} onChange={onChange} isDark={isDark} />
)}
</div>
</div>
)
}

View File

@@ -9,214 +9,102 @@ interface ModeSelectorProps {
}
/**
* Mode selector for worksheet generation
* Allows switching between Smart Difficulty, Manual Control, and Mastery Progression modes
* Mode selector tabs for worksheet generation
* Large, prominent tabs that switch between Smart Difficulty, Manual Control, and Mastery Progression modes
*/
export function ModeSelector({ currentMode, onChange, isDark = false }: ModeSelectorProps) {
const modes = [
{
id: 'smart' as const,
emoji: '🎯',
label: 'Smart Difficulty',
},
{
id: 'manual' as const,
emoji: '🎛️',
label: 'Manual Control',
},
{
id: 'mastery' as const,
emoji: '🎓',
label: 'Mastery Progression',
},
]
return (
<div
data-component="mode-selector"
data-component="mode-selector-tabs"
className={css({
marginBottom: '1.5rem',
padding: '1rem',
backgroundColor: isDark ? 'gray.700' : 'gray.50',
borderRadius: '8px',
border: '1px solid',
display: 'flex',
gap: '0.5rem',
borderBottom: '2px solid',
borderColor: isDark ? 'gray.600' : 'gray.200',
marginBottom: '1.5rem',
})}
>
<h3
className={css({
fontSize: '0.875rem',
fontWeight: '600',
color: isDark ? 'gray.200' : 'gray.700',
marginBottom: '0.75rem',
textTransform: 'uppercase',
letterSpacing: '0.05em',
})}
>
Worksheet Mode
</h3>
<div
data-element="mode-buttons"
className={css({
display: 'grid',
gridTemplateColumns: 'repeat(3, 1fr)',
gap: '0.75rem',
})}
>
{/* Smart Difficulty Mode Button */}
<button
type="button"
data-action="select-smart-mode"
data-selected={currentMode === 'smart'}
onClick={() => onChange('smart')}
className={css({
padding: '1rem',
borderRadius: '6px',
border: '2px solid',
borderColor: currentMode === 'smart' ? 'blue.500' : isDark ? 'gray.500' : 'gray.300',
backgroundColor: currentMode === 'smart' ? 'blue.50' : isDark ? 'gray.600' : 'white',
cursor: 'pointer',
transition: 'all 0.2s',
textAlign: 'left',
_hover: {
borderColor: 'blue.400',
backgroundColor: 'blue.50',
},
})}
>
<div
{modes.map((mode) => {
const isActive = currentMode === mode.id
return (
<button
key={mode.id}
type="button"
data-action={`select-${mode.id}-mode`}
data-selected={isActive}
onClick={() => onChange(mode.id)}
className={css({
flex: 1,
padding: '1rem 1.5rem',
border: 'none',
borderBottom: '3px solid',
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',
marginBottom: '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',
})}
>
🎯
</span>
<span
className={css({
fontSize: '0.875rem',
fontWeight: '600',
color: currentMode === 'smart' ? 'blue.700' : isDark ? 'gray.200' : 'gray.700',
})}
>
Smart Difficulty
</span>
</div>
<p
className={css({
fontSize: '0.75rem',
color: currentMode === 'smart' ? 'blue.600' : isDark ? 'gray.400' : 'gray.600',
lineHeight: '1.4',
})}
>
Research-backed progressive difficulty with adaptive scaffolding per problem
</p>
</button>
{/* Manual Control Mode Button */}
<button
type="button"
data-action="select-manual-mode"
data-selected={currentMode === 'manual'}
onClick={() => onChange('manual')}
className={css({
padding: '1rem',
borderRadius: '6px',
border: '2px solid',
borderColor: currentMode === 'manual' ? 'blue.500' : isDark ? 'gray.500' : 'gray.300',
backgroundColor: currentMode === 'manual' ? 'blue.50' : isDark ? 'gray.600' : 'white',
cursor: 'pointer',
transition: 'all 0.2s',
textAlign: 'left',
_hover: {
borderColor: 'blue.400',
backgroundColor: 'blue.50',
},
})}
>
<div
className={css({
display: 'flex',
alignItems: 'center',
gap: '0.5rem',
marginBottom: '0.5rem',
})}
>
<span
className={css({
fontSize: '1.25rem',
})}
>
🎛
</span>
<span
className={css({
fontSize: '0.875rem',
fontWeight: '600',
color: currentMode === 'manual' ? 'blue.700' : isDark ? 'gray.200' : 'gray.700',
})}
>
Manual Control
</span>
</div>
<p
className={css({
fontSize: '0.75rem',
color: currentMode === 'manual' ? 'blue.600' : isDark ? 'gray.400' : 'gray.600',
lineHeight: '1.4',
})}
>
Full control over display options with uniform scaffolding across all problems
</p>
</button>
{/* Mastery Progression Mode Button */}
<button
type="button"
data-action="select-mastery-mode"
data-selected={currentMode === 'mastery'}
onClick={() => onChange('mastery')}
className={css({
padding: '1rem',
borderRadius: '6px',
border: '2px solid',
borderColor: currentMode === 'mastery' ? 'blue.500' : isDark ? 'gray.500' : 'gray.300',
backgroundColor: currentMode === 'mastery' ? 'blue.50' : isDark ? 'gray.600' : 'white',
cursor: 'pointer',
transition: 'all 0.2s',
textAlign: 'left',
_hover: {
borderColor: 'blue.400',
backgroundColor: 'blue.50',
},
})}
>
<div
className={css({
display: 'flex',
alignItems: 'center',
gap: '0.5rem',
marginBottom: '0.5rem',
})}
>
<span
className={css({
fontSize: '1.25rem',
})}
>
🎓
</span>
<span
className={css({
fontSize: '0.875rem',
fontWeight: '600',
color: currentMode === 'mastery' ? 'blue.700' : isDark ? 'gray.200' : 'gray.700',
})}
>
Mastery Progression
</span>
</div>
<p
className={css({
fontSize: '0.75rem',
color: currentMode === 'mastery' ? 'blue.600' : isDark ? 'gray.400' : 'gray.600',
lineHeight: '1.4',
})}
>
Skill-based progression with automatic review mixing for pedagogical practice
</p>
</button>
</div>
<span className={css({ fontSize: '1.25rem' })}>{mode.emoji}</span>
<span>{mode.label}</span>
</button>
)
})}
</div>
)
}