feat: move difficulty parameters into Smart mode
Group difficulty configuration parameters inside Smart Difficulty mode: - Digit Range moved from always-visible to Smart mode - Regrouping Frequency moved from always-visible to Smart mode - These are difficulty tuning parameters, not general settings Changes: - Add DigitRangeSection to top of SmartModeControls - Add RegroupingFrequencyPanel to bottom of SmartModeControls - Extract RegroupingFrequencyPanel as standalone component - Remove both from ConfigPanel's always-visible section 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
804fb1a2f6
commit
4b667587f8
|
|
@ -0,0 +1,168 @@
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import * as Slider from '@radix-ui/react-slider'
|
||||||
|
import { css } from '../../../../../../../styled-system/css'
|
||||||
|
import { stack } from '../../../../../../../styled-system/patterns'
|
||||||
|
import type { WorksheetFormState } from '../../types'
|
||||||
|
|
||||||
|
export interface RegroupingFrequencyPanelProps {
|
||||||
|
formState: WorksheetFormState
|
||||||
|
onChange: (updates: Partial<WorksheetFormState>) => void
|
||||||
|
isDark?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RegroupingFrequencyPanel({
|
||||||
|
formState,
|
||||||
|
onChange,
|
||||||
|
isDark = false,
|
||||||
|
}: RegroupingFrequencyPanelProps) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-section="regrouping"
|
||||||
|
className={css({
|
||||||
|
bg: isDark ? 'gray.800' : 'gray.50',
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: isDark ? 'gray.600' : 'gray.200',
|
||||||
|
rounded: 'xl',
|
||||||
|
p: '3',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div className={stack({ gap: '2.5' })}>
|
||||||
|
<div
|
||||||
|
className={css({
|
||||||
|
fontSize: 'xs',
|
||||||
|
fontWeight: 'semibold',
|
||||||
|
color: isDark ? 'gray.400' : 'gray.500',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
letterSpacing: 'wider',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
Regrouping Frequency
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Current values display */}
|
||||||
|
<div
|
||||||
|
className={css({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
fontSize: 'xs',
|
||||||
|
color: isDark ? 'gray.400' : 'gray.600',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
Both:{' '}
|
||||||
|
<span
|
||||||
|
className={css({
|
||||||
|
color: 'brand.600',
|
||||||
|
fontWeight: 'semibold',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{Math.round((formState.pAllStart || 0) * 100)}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Any:{' '}
|
||||||
|
<span
|
||||||
|
className={css({
|
||||||
|
color: 'brand.600',
|
||||||
|
fontWeight: 'semibold',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{Math.round((formState.pAnyStart || 0.25) * 100)}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Double-thumbed range slider */}
|
||||||
|
<Slider.Root
|
||||||
|
className={css({
|
||||||
|
position: 'relative',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
userSelect: 'none',
|
||||||
|
touchAction: 'none',
|
||||||
|
width: 'full',
|
||||||
|
height: '6',
|
||||||
|
})}
|
||||||
|
value={[(formState.pAllStart || 0) * 100, (formState.pAnyStart || 0.25) * 100]}
|
||||||
|
onValueChange={(values) => {
|
||||||
|
onChange({
|
||||||
|
pAllStart: values[0] / 100,
|
||||||
|
pAnyStart: values[1] / 100,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
min={0}
|
||||||
|
max={100}
|
||||||
|
step={5}
|
||||||
|
minStepsBetweenThumbs={0}
|
||||||
|
>
|
||||||
|
<Slider.Track
|
||||||
|
className={css({
|
||||||
|
position: 'relative',
|
||||||
|
flexGrow: 1,
|
||||||
|
bg: 'gray.200',
|
||||||
|
rounded: 'full',
|
||||||
|
height: '1.5',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Slider.Range
|
||||||
|
className={css({
|
||||||
|
position: 'absolute',
|
||||||
|
bg: 'brand.500',
|
||||||
|
rounded: 'full',
|
||||||
|
height: 'full',
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Slider.Track>
|
||||||
|
<Slider.Thumb
|
||||||
|
className={css({
|
||||||
|
display: 'block',
|
||||||
|
width: '3.5',
|
||||||
|
height: '3.5',
|
||||||
|
bg: 'white',
|
||||||
|
boxShadow: '0 2px 4px rgba(0,0,0,0.15)',
|
||||||
|
rounded: 'full',
|
||||||
|
border: '2px solid',
|
||||||
|
borderColor: 'brand.500',
|
||||||
|
cursor: 'pointer',
|
||||||
|
_hover: { transform: 'scale(1.1)' },
|
||||||
|
_focus: {
|
||||||
|
outline: 'none',
|
||||||
|
boxShadow: '0 0 0 3px rgba(59, 130, 246, 0.3)',
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<Slider.Thumb
|
||||||
|
className={css({
|
||||||
|
display: 'block',
|
||||||
|
width: '3.5',
|
||||||
|
height: '3.5',
|
||||||
|
bg: 'white',
|
||||||
|
boxShadow: '0 2px 4px rgba(0,0,0,0.15)',
|
||||||
|
rounded: 'full',
|
||||||
|
border: '2px solid',
|
||||||
|
borderColor: 'brand.600',
|
||||||
|
cursor: 'pointer',
|
||||||
|
_hover: { transform: 'scale(1.1)' },
|
||||||
|
_focus: {
|
||||||
|
outline: 'none',
|
||||||
|
boxShadow: '0 0 0 3px rgba(59, 130, 246, 0.3)',
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Slider.Root>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={css({
|
||||||
|
fontSize: '2xs',
|
||||||
|
color: isDark ? 'gray.400' : 'gray.500',
|
||||||
|
lineHeight: '1.3',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
Regrouping difficulty at worksheet start (Both = all columns regroup, Any = at least one
|
||||||
|
column regroups)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,8 @@ import {
|
||||||
} from '../../difficultyProfiles'
|
} from '../../difficultyProfiles'
|
||||||
import type { DisplayRules } from '../../displayRules'
|
import type { DisplayRules } from '../../displayRules'
|
||||||
import { getScaffoldingSummary } from './utils'
|
import { getScaffoldingSummary } from './utils'
|
||||||
|
import { RegroupingFrequencyPanel } from './RegroupingFrequencyPanel'
|
||||||
|
import { DigitRangeSection } from './DigitRangeSection'
|
||||||
|
|
||||||
export interface SmartModeControlsProps {
|
export interface SmartModeControlsProps {
|
||||||
formState: WorksheetFormState
|
formState: WorksheetFormState
|
||||||
|
|
@ -74,22 +76,21 @@ export function SmartModeControls({ formState, onChange, isDark = false }: Smart
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div data-section="smart-mode" className={stack({ gap: '3' })}>
|
||||||
data-section="difficulty"
|
{/* Digit Range */}
|
||||||
className={css({
|
<DigitRangeSection
|
||||||
bg: 'gray.50',
|
digitRange={formState.digitRange}
|
||||||
border: '1px solid',
|
onChange={(digitRange) => onChange({ digitRange })}
|
||||||
borderColor: 'gray.200',
|
isDark={isDark}
|
||||||
rounded: 'xl',
|
/>
|
||||||
p: '3',
|
|
||||||
})}
|
{/* Difficulty Level */}
|
||||||
>
|
<div data-section="difficulty" className={stack({ gap: '2.5' })}>
|
||||||
<div className={stack({ gap: '2.5' })}>
|
|
||||||
<div
|
<div
|
||||||
className={css({
|
className={css({
|
||||||
fontSize: 'xs',
|
fontSize: 'xs',
|
||||||
fontWeight: 'semibold',
|
fontWeight: 'semibold',
|
||||||
color: 'gray.500',
|
color: isDark ? 'gray.400' : 'gray.500',
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
letterSpacing: 'wider',
|
letterSpacing: 'wider',
|
||||||
})}
|
})}
|
||||||
|
|
@ -1478,6 +1479,9 @@ export function SmartModeControls({ formState, onChange, isDark = false }: Smart
|
||||||
)
|
)
|
||||||
})()}
|
})()}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Regrouping Frequency */}
|
||||||
|
<RegroupingFrequencyPanel formState={formState} onChange={onChange} isDark={isDark} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue