diff --git a/apps/readest-app/src/app/reader/components/footerbar/ColorPanel.tsx b/apps/readest-app/src/app/reader/components/footerbar/ColorPanel.tsx index 33b9826b..7fad0be3 100644 --- a/apps/readest-app/src/app/reader/components/footerbar/ColorPanel.tsx +++ b/apps/readest-app/src/app/reader/components/footerbar/ColorPanel.tsx @@ -90,6 +90,22 @@ export const ColorPanel: React.FC = ({ actionTab, bottomOffset onChange={handleScreenBrightnessChange} min={SCREEN_BRIGHTNESS_LIMITS.MIN} max={SCREEN_BRIGHTNESS_LIMITS.MAX} + valueToPosition={(value: number, min: number, max: number): number => { + if (value <= min) return 0; + if (value >= max) return 100; + // Use exponential mapping: position = 100 * ((value/max)^0.5) + const normalized = value / max; + const position = Math.pow(normalized, 0.5) * 100; + return position; + }} + positionToValue={(position: number, min: number, max: number): number => { + if (position <= 0) return min; + if (position >= 100) return max; + // Inverse of the above: value = max * (position/100)^2 + const normalized = position / 100; + const value = Math.pow(normalized, 2) * max; + return Math.max(min, Math.min(max, value)); + }} /> )} diff --git a/apps/readest-app/src/components/Slider.tsx b/apps/readest-app/src/components/Slider.tsx index cee4406f..67eedad8 100644 --- a/apps/readest-app/src/components/Slider.tsx +++ b/apps/readest-app/src/components/Slider.tsx @@ -18,6 +18,8 @@ interface SliderProps { maxClassName?: string; bubbleClassName?: string; onChange?: (value: number) => void; + valueToPosition?: (value: number, min: number, max: number) => number; + positionToValue?: (position: number, min: number, max: number) => number; } const Slider: React.FC = ({ @@ -38,13 +40,28 @@ const Slider: React.FC = ({ maxClassName = '', bubbleClassName = '', onChange, + valueToPosition, + positionToValue, }) => { const [value, setValue] = useState(initialValue); const [isRtl, setIsRtl] = useState(false); const sliderRef = useRef(null); + // Default linear mapping functions + const defaultValueToPosition = (val: number, minVal: number, maxVal: number) => { + return ((val - minVal) / (maxVal - minVal)) * 100; + }; + + const defaultPositionToValue = (pos: number, minVal: number, maxVal: number) => { + return minVal + (pos / 100) * (maxVal - minVal); + }; + + const valueToPos = valueToPosition || defaultValueToPosition; + const posToValue = positionToValue || defaultPositionToValue; + const handleChange = (e: React.ChangeEvent) => { - const newValue = parseInt((e.target as HTMLInputElement).value, 10); + const position = parseInt((e.target as HTMLInputElement).value, 10); + const newValue = Math.round(posToValue(position, min, max) / step) * step; setValue(newValue); if (onChange) { onChange(newValue); @@ -66,7 +83,7 @@ const Slider: React.FC = ({ setValue(initialValue); }, [initialValue]); - const percentage = ((value - min) / (max - min)) * 100; + const percentage = valueToPos(value, min, max); const visualPercentage = (percentage / 100) * 95; return ( @@ -113,10 +130,10 @@ const Slider: React.FC = ({