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:
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user