feat(settings): add custom highlight color picker (#2273)

Add ability to customize highlight colors with hex color picker. Users can now set custom colors for all five highlight styles (red, violet, blue, green, yellow) in the settings panel.

Fixes #2271
This commit is contained in:
AlI
2025-10-19 18:33:59 +03:30
committed by GitHub
parent f66642b8ec
commit cd71c494da
6 changed files with 121 additions and 23 deletions
@@ -5,9 +5,11 @@ type ColorInputProps = {
label: string;
value: string;
onChange: (value: string) => void;
compact?: boolean;
pickerPosition?: 'left' | 'center' | 'right';
};
const ColorInput: React.FC<ColorInputProps> = ({ label, value, onChange }) => {
const ColorInput: React.FC<ColorInputProps> = ({ label, value, onChange, compact = false, pickerPosition = 'left' }) => {
const [isOpen, setIsOpen] = useState(false);
const pickerRef = useRef<HTMLDivElement>(null);
@@ -29,6 +31,44 @@ const ColorInput: React.FC<ColorInputProps> = ({ label, value, onChange }) => {
onChange(colorResult.hex);
};
const getPickerPositionClass = () => {
if (pickerPosition === 'right') {
return 'right-0';
} else if (pickerPosition === 'center') {
return 'left-1/2 -translate-x-1/2';
}
return 'left-0';
};
if (compact) {
return (
<div className='relative'>
<input
type='text'
value={value}
spellCheck={false}
onChange={(e) => onChange(e.target.value)}
onClick={() => setIsOpen(!isOpen)}
className='bg-base-100 text-base-content border-base-200/75 w-16 cursor-pointer rounded border px-1 py-0.5 text-center font-mono text-xs'
/>
{isOpen && (
<div
ref={pickerRef}
className={`absolute top-full z-50 mt-1 ${getPickerPositionClass()}`}
>
<SketchPicker
width='200px'
color={value}
onChange={handlePickerChange}
disableAlpha={true}
/>
</div>
)}
</div>
);
}
return (
<div className='mb-3'>
<label className='mb-1 block text-sm font-medium'>{label}</label>
@@ -27,6 +27,9 @@ import { useFileSelector } from '@/hooks/useFileSelector';
import { PREDEFINED_TEXTURES } from '@/styles/textures';
import Select from '@/components/Select';
import ThemeEditor from './ThemeEditor';
import ColorInput from './ColorInput';
import { HighlightColor } from '@/types/book';
import { DEFAULT_CUSTOM_HIGHLIGHT_COLORS } from '@/services/constants';
const ColorPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset }) => {
const _ = useTranslation();
@@ -53,6 +56,10 @@ const ColorPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset
const [backgroundOpacity, setBackgroundOpacity] = useState(viewSettings.backgroundOpacity);
const [backgroundSize, setBackgroundSize] = useState(viewSettings.backgroundSize);
const [customHighlightColors, setCustomHighlightColors] = useState<Record<HighlightColor, string>>(
settings.globalReadSettings.customHighlightColors || DEFAULT_CUSTOM_HIGHLIGHT_COLORS,
);
const {
textures: customTextures,
addTexture,
@@ -78,6 +85,7 @@ const ColorPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset
setSelectedTextureId('none');
setBackgroundOpacity(0.4);
setBackgroundSize('2048px');
setCustomHighlightColors(DEFAULT_CUSTOM_HIGHLIGHT_COLORS);
};
useEffect(() => {
@@ -433,6 +441,37 @@ const ColorPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset
)}
</div>
<div>
<h2 className='mb-2 font-medium'>{_('Custom Highlight Colors')}</h2>
<div className='card border-base-200 bg-base-100 border p-4 shadow overflow-visible'>
<div className='flex items-center justify-around gap-2'>
{(['red', 'violet', 'blue', 'green', 'yellow'] as HighlightColor[]).map((color, index, array) => {
const position = index === 0 ? 'left' : index === array.length - 1 ? 'right' : 'center';
return (
<div key={color} className='flex flex-col items-center gap-2'>
<div
className='h-8 w-8 rounded-full border-2 border-base-300 shadow-sm'
style={{ backgroundColor: customHighlightColors[color] }}
/>
<ColorInput
label=''
value={customHighlightColors[color]}
compact={true}
pickerPosition={position}
onChange={(value: string) => {
customHighlightColors[color] = value;
setCustomHighlightColors({ ...customHighlightColors });
settings.globalReadSettings.customHighlightColors = customHighlightColors;
setSettings(settings);
}}
/>
</div>
);
})}
</div>
</div>
</div>
<div className='w-full'>
<h2 className='mb-2 font-medium'>{_('Code Highlighting')}</h2>
<div className='card border-base-200 bg-base-100 border shadow'>