Skip to content

Commit 0e5a84b

Browse files
authored
Merge pull request #239 from beNative/codex/replace-color-pickers-with-react-color-compact
Replace appearance color pickers
2 parents 232396c + 5df9c71 commit 0e5a84b

4 files changed

Lines changed: 198 additions & 32 deletions

File tree

components/ColorPicker.tsx

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import React, { useCallback, useEffect, useRef, useState } from 'react';
2+
import Compact from '@uiw/react-color-compact';
3+
import type { ColorResult } from '@uiw/color-convert';
4+
5+
interface ColorPickerProps {
6+
id?: string;
7+
color: string;
8+
onChange: (value: string) => void;
9+
ariaLabel: string;
10+
className?: string;
11+
anchorClassName?: string;
12+
}
13+
14+
const ColorPicker: React.FC<ColorPickerProps> = ({
15+
id,
16+
color,
17+
onChange,
18+
ariaLabel,
19+
className,
20+
anchorClassName,
21+
}) => {
22+
const [isOpen, setIsOpen] = useState(false);
23+
const containerRef = useRef<HTMLDivElement | null>(null);
24+
25+
const toggleOpen = useCallback(() => {
26+
setIsOpen((previous) => !previous);
27+
}, []);
28+
29+
const close = useCallback(() => {
30+
setIsOpen(false);
31+
}, []);
32+
33+
useEffect(() => {
34+
if (!isOpen || typeof document === 'undefined') {
35+
return undefined;
36+
}
37+
38+
const handleClickOutside = (event: MouseEvent) => {
39+
if (!containerRef.current) {
40+
return;
41+
}
42+
43+
if (!containerRef.current.contains(event.target as Node)) {
44+
close();
45+
}
46+
};
47+
48+
const handleKeyDown = (event: KeyboardEvent) => {
49+
if (event.key === 'Escape') {
50+
close();
51+
}
52+
};
53+
54+
document.addEventListener('mousedown', handleClickOutside);
55+
document.addEventListener('keydown', handleKeyDown);
56+
57+
return () => {
58+
document.removeEventListener('mousedown', handleClickOutside);
59+
document.removeEventListener('keydown', handleKeyDown);
60+
};
61+
}, [close, isOpen]);
62+
63+
const handleColorChange = useCallback((result: ColorResult) => {
64+
const next = result.hexa || result.hex;
65+
onChange(next);
66+
}, [onChange]);
67+
68+
return (
69+
<div ref={containerRef} className={`relative inline-flex ${className ?? ''}`}>
70+
<button
71+
id={id}
72+
type="button"
73+
aria-haspopup="dialog"
74+
aria-expanded={isOpen}
75+
aria-label={ariaLabel}
76+
onClick={toggleOpen}
77+
className={`h-10 w-14 rounded-md border border-border-color bg-background cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary/40 flex items-center justify-center ${anchorClassName ?? ''}`}
78+
>
79+
<span
80+
aria-hidden
81+
className="block h-7 w-10 rounded border border-border-color/60 shadow-inner"
82+
style={{ backgroundColor: color }}
83+
/>
84+
</button>
85+
{isOpen && (
86+
<div className="absolute left-0 z-50 mt-2 rounded-md border border-border-color bg-background shadow-lg p-3">
87+
<Compact color={color} onChange={handleColorChange} />
88+
</div>
89+
)}
90+
</div>
91+
);
92+
};
93+
94+
export default ColorPicker;

components/SettingsView.tsx

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import Modal from './Modal';
2727
import { repository } from '../services/repository';
2828
import ToggleSwitch from './ToggleSwitch';
2929
import SettingRow from './SettingRow';
30+
import ColorPicker from './ColorPicker';
3031
import SettingsTreeEditor from './SettingsTreeEditor';
3132
import { useLogger } from '../hooks/useLogger';
3233
import KeyboardShortcutsSection from './KeyboardShortcutsSection';
@@ -804,12 +805,10 @@ const AppearanceSettingsSection: React.FC<Pick<SectionProps, 'settings' | 'setCu
804805
return (
805806
<div key={`${mode}-${token}`} className="space-y-3 rounded-lg border border-border-color bg-secondary/60 p-3">
806807
<div className="flex items-center gap-3">
807-
<input
808-
type="color"
809-
value={colorPickerValue}
810-
onChange={(event) => handleColorOverrideChange(mode, token, event.target.value)}
811-
className="h-10 w-12 cursor-pointer rounded-md border border-border-color bg-background"
812-
aria-label={`${THEME_MODE_LABELS[mode]} ${COLOR_TOKEN_METADATA[token].label} color`}
808+
<ColorPicker
809+
color={colorPickerValue}
810+
onChange={(next) => handleColorOverrideChange(mode, token, next)}
811+
ariaLabel={`${THEME_MODE_LABELS[mode]} ${COLOR_TOKEN_METADATA[token].label} color`}
813812
/>
814813
<div>
815814
<h4 className="text-sm font-semibold text-text-main">{COLOR_TOKEN_METADATA[token].label}</h4>
@@ -1117,12 +1116,11 @@ const AppearanceSettingsSection: React.FC<Pick<SectionProps, 'settings' | 'setCu
11171116
>
11181117
<div className="space-y-2">
11191118
<div className="flex flex-wrap items-center gap-3">
1120-
<input
1119+
<ColorPicker
11211120
id="editorActiveLineHighlightColor"
1122-
type="color"
1123-
value={highlightColorPickerValueLight}
1124-
onChange={(event) => setCurrentSettings((prev) => ({ ...prev, editorActiveLineHighlightColor: event.target.value }))}
1125-
className="h-10 w-14 rounded-md border border-border-color bg-background cursor-pointer"
1121+
color={highlightColorPickerValueLight}
1122+
onChange={(next) => setCurrentSettings((prev) => ({ ...prev, editorActiveLineHighlightColor: next }))}
1123+
ariaLabel="Select active line highlight color for light theme"
11261124
/>
11271125
<span className="font-mono text-xs text-text-secondary break-all">
11281126
{highlightColorDisplayLight}
@@ -1155,12 +1153,11 @@ const AppearanceSettingsSection: React.FC<Pick<SectionProps, 'settings' | 'setCu
11551153
>
11561154
<div className="space-y-2">
11571155
<div className="flex flex-wrap items-center gap-3">
1158-
<input
1156+
<ColorPicker
11591157
id="editorActiveLineHighlightColorDark"
1160-
type="color"
1161-
value={highlightColorPickerValueDark}
1162-
onChange={(event) => setCurrentSettings((prev) => ({ ...prev, editorActiveLineHighlightColorDark: event.target.value }))}
1163-
className="h-10 w-14 rounded-md border border-border-color bg-background cursor-pointer"
1158+
color={highlightColorPickerValueDark}
1159+
onChange={(next) => setCurrentSettings((prev) => ({ ...prev, editorActiveLineHighlightColorDark: next }))}
1160+
ariaLabel="Select active line highlight color for dark theme"
11641161
/>
11651162
<span className="font-mono text-xs text-text-secondary break-all">
11661163
{highlightColorDisplayDark}
@@ -1192,12 +1189,11 @@ const AppearanceSettingsSection: React.FC<Pick<SectionProps, 'settings' | 'setCu
11921189
htmlFor="markdownCodeBlockBackgroundLight"
11931190
>
11941191
<div className="flex items-center gap-3">
1195-
<input
1192+
<ColorPicker
11961193
id="markdownCodeBlockBackgroundLight"
1197-
type="color"
1198-
value={lightCodeBlockBackground}
1199-
onChange={(event) => setCurrentSettings((prev) => ({ ...prev, markdownCodeBlockBackgroundLight: event.target.value }))}
1200-
className="h-10 w-14 rounded-md border border-border-color bg-background cursor-pointer"
1194+
color={lightCodeBlockBackground}
1195+
onChange={(next) => setCurrentSettings((prev) => ({ ...prev, markdownCodeBlockBackgroundLight: next }))}
1196+
ariaLabel="Select code block background color for light theme"
12011197
/>
12021198
<span className="font-mono text-xs text-text-secondary">
12031199
{lightCodeBlockBackground.toUpperCase()}
@@ -1218,12 +1214,11 @@ const AppearanceSettingsSection: React.FC<Pick<SectionProps, 'settings' | 'setCu
12181214
htmlFor="markdownCodeBlockBackgroundDark"
12191215
>
12201216
<div className="flex items-center gap-3">
1221-
<input
1217+
<ColorPicker
12221218
id="markdownCodeBlockBackgroundDark"
1223-
type="color"
1224-
value={darkCodeBlockBackground}
1225-
onChange={(event) => setCurrentSettings((prev) => ({ ...prev, markdownCodeBlockBackgroundDark: event.target.value }))}
1226-
className="h-10 w-14 rounded-md border border-border-color bg-background cursor-pointer"
1219+
color={darkCodeBlockBackground}
1220+
onChange={(next) => setCurrentSettings((prev) => ({ ...prev, markdownCodeBlockBackgroundDark: next }))}
1221+
ariaLabel="Select code block background color for dark theme"
12271222
/>
12281223
<span className="font-mono text-xs text-text-secondary">
12291224
{darkCodeBlockBackground.toUpperCase()}

package-lock.json

Lines changed: 82 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"url": "https://github.com/beNative/docforge.git"
3535
},
3636
"dependencies": {
37+
"@uiw/react-color-compact": "^2.9.2",
3738
"better-sqlite3": "^11.1.2",
3839
"electron-log": "^5.1.5",
3940
"electron-squirrel-startup": "^1.0.1",

0 commit comments

Comments
 (0)