diff --git a/apps/readest-app/src/app/reader/components/annotator/Annotator.tsx b/apps/readest-app/src/app/reader/components/annotator/Annotator.tsx index 722a2f5a..30dd48ce 100644 --- a/apps/readest-app/src/app/reader/components/annotator/Annotator.tsx +++ b/apps/readest-app/src/app/reader/components/annotator/Annotator.tsx @@ -142,7 +142,8 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => { const detail = (event as CustomEvent).detail; const { draw, annotation, doc, range } = detail; const { style, color } = annotation as BookNote; - const hexColor = color ? HIGHLIGHT_COLOR_HEX[color] : color; + const customColors = settings.globalReadSettings.customHighlightColors; + const hexColor = color && customColors ? customColors[color] : color ? HIGHLIGHT_COLOR_HEX[color] : color; if (style === 'highlight') { draw(Overlayer.highlight, { color: hexColor }); } else if (['underline', 'squiggly'].includes(style as string)) { diff --git a/apps/readest-app/src/app/reader/components/annotator/HighlightOptions.tsx b/apps/readest-app/src/app/reader/components/annotator/HighlightOptions.tsx index b0963a46..f3c8e13f 100644 --- a/apps/readest-app/src/app/reader/components/annotator/HighlightOptions.tsx +++ b/apps/readest-app/src/app/reader/components/annotator/HighlightOptions.tsx @@ -4,6 +4,7 @@ import { FaCheckCircle } from 'react-icons/fa'; import { HighlightColor, HighlightStyle } from '@/types/book'; import { useSettingsStore } from '@/store/settingsStore'; import { useResponsiveSize } from '@/hooks/useResponsiveSize'; +import { DEFAULT_CUSTOM_HIGHLIGHT_COLORS } from '@/services/constants'; const styles = ['highlight', 'underline', 'squiggly'] as HighlightStyle[]; const colors = ['red', 'violet', 'blue', 'green', 'yellow'] as HighlightColor[]; @@ -25,6 +26,7 @@ const HighlightOptions: React.FC = ({ }) => { const { settings, setSettings } = useSettingsStore(); const globalReadSettings = settings.globalReadSettings; + const customColors = globalReadSettings.customHighlightColors || DEFAULT_CUSTOM_HIGHLIGHT_COLORS; const [selectedStyle, setSelectedStyle] = React.useState(_selectedStyle); const [selectedColor, setSelectedColor] = React.useState(_selectedColor); const size16 = useResponsiveSize(16); @@ -65,24 +67,26 @@ const HighlightOptions: React.FC = ({ style={{ width: size28, height: size28, minHeight: size28 }} >
A
@@ -101,11 +105,15 @@ const HighlightOptions: React.FC = ({ ))} diff --git a/apps/readest-app/src/components/settings/ColorInput.tsx b/apps/readest-app/src/components/settings/ColorInput.tsx index bb3a14a0..d863204a 100644 --- a/apps/readest-app/src/components/settings/ColorInput.tsx +++ b/apps/readest-app/src/components/settings/ColorInput.tsx @@ -5,9 +5,11 @@ type ColorInputProps = { label: string; value: string; onChange: (value: string) => void; + compact?: boolean; + pickerPosition?: 'left' | 'center' | 'right'; }; -const ColorInput: React.FC = ({ label, value, onChange }) => { +const ColorInput: React.FC = ({ label, value, onChange, compact = false, pickerPosition = 'left' }) => { const [isOpen, setIsOpen] = useState(false); const pickerRef = useRef(null); @@ -29,6 +31,44 @@ const ColorInput: React.FC = ({ 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 ( +
+ 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 && ( +
+ +
+ )} +
+ ); + } + return (
diff --git a/apps/readest-app/src/components/settings/ColorPanel.tsx b/apps/readest-app/src/components/settings/ColorPanel.tsx index 59f6d108..3937b819 100644 --- a/apps/readest-app/src/components/settings/ColorPanel.tsx +++ b/apps/readest-app/src/components/settings/ColorPanel.tsx @@ -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 = ({ bookKey, onRegisterReset }) => { const _ = useTranslation(); @@ -53,6 +56,10 @@ const ColorPanel: React.FC = ({ bookKey, onRegisterReset const [backgroundOpacity, setBackgroundOpacity] = useState(viewSettings.backgroundOpacity); const [backgroundSize, setBackgroundSize] = useState(viewSettings.backgroundSize); + const [customHighlightColors, setCustomHighlightColors] = useState>( + settings.globalReadSettings.customHighlightColors || DEFAULT_CUSTOM_HIGHLIGHT_COLORS, + ); + const { textures: customTextures, addTexture, @@ -78,6 +85,7 @@ const ColorPanel: React.FC = ({ bookKey, onRegisterReset setSelectedTextureId('none'); setBackgroundOpacity(0.4); setBackgroundSize('2048px'); + setCustomHighlightColors(DEFAULT_CUSTOM_HIGHLIGHT_COLORS); }; useEffect(() => { @@ -433,6 +441,37 @@ const ColorPanel: React.FC = ({ bookKey, onRegisterReset )}
+
+

{_('Custom Highlight Colors')}

+
+
+ {(['red', 'violet', 'blue', 'green', 'yellow'] as HighlightColor[]).map((color, index, array) => { + const position = index === 0 ? 'left' : index === array.length - 1 ? 'right' : 'center'; + return ( +
+
+ { + customHighlightColors[color] = value; + setCustomHighlightColors({ ...customHighlightColors }); + settings.globalReadSettings.customHighlightColors = customHighlightColors; + setSettings(settings); + }} + /> +
+ ); + })} +
+
+
+

{_('Code Highlighting')}

diff --git a/apps/readest-app/src/services/constants.ts b/apps/readest-app/src/services/constants.ts index 5c9ed650..42ed6915 100644 --- a/apps/readest-app/src/services/constants.ts +++ b/apps/readest-app/src/services/constants.ts @@ -78,6 +78,14 @@ export const DEFAULT_SYSTEM_SETTINGS: Partial = { lastSyncedAtNotes: 0, }; +export const DEFAULT_CUSTOM_HIGHLIGHT_COLORS: Record = { + red: '#fca5a5', // red-300 + yellow: '#fde047', // yellow-300 + green: '#86efac', // green-300 + blue: '#93c5fd', // blue-300 + violet: '#c4b5fd', // violet-300 +}; + export const DEFAULT_READSETTINGS: ReadSettings = { sideBarWidth: '15%', isSideBarPinned: true, @@ -94,6 +102,7 @@ export const DEFAULT_READSETTINGS: ReadSettings = { underline: 'green', squiggly: 'blue', }, + customHighlightColors: DEFAULT_CUSTOM_HIGHLIGHT_COLORS, }; export const DEFAULT_MOBILE_READSETTINGS: Partial = { diff --git a/apps/readest-app/src/types/settings.ts b/apps/readest-app/src/types/settings.ts index d217889c..34c600e0 100644 --- a/apps/readest-app/src/types/settings.ts +++ b/apps/readest-app/src/types/settings.ts @@ -22,6 +22,7 @@ export interface ReadSettings { highlightStyle: HighlightStyle; highlightStyles: Record; + customHighlightColors: Record; customThemes: CustomTheme[]; }