Skip to content

Commit 929dfde

Browse files
committed
feat: enhance SettingsDialog with user settings management
- Added UserSettings interface and default settings for embed lock debounce time. - Integrated settings management into SettingsDialog, allowing users to adjust embed lock debounce time via a range input. - Updated normalizeCanvasData to preserve user settings when normalizing canvas data. - Improved styles for SettingsDialog to enhance user experience and organization.
1 parent 386e93e commit 929dfde

File tree

6 files changed

+141
-15
lines changed

6 files changed

+141
-15
lines changed

src/frontend/src/ExcalidrawWrapper.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export const ExcalidrawWrapper: React.FC<ExcalidrawWrapperProps> = ({
5959
}
6060
}, [isAuthenticated]);
6161

62+
6263
// Handlers for closing modals
6364
const handleCloseBackupsModal = () => {
6465
setShowBackupsModal(false);
@@ -122,6 +123,7 @@ export const ExcalidrawWrapper: React.FC<ExcalidrawWrapperProps> = ({
122123

123124
{showSettingsModal && (
124125
<SettingsDialog
126+
excalidrawAPI={excalidrawAPI}
125127
onClose={handleCloseSettingsModal}
126128
/>
127129
)}

src/frontend/src/types/settings.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* Types for user settings
3+
*/
4+
5+
export interface UserSettings {
6+
/**
7+
* The debounce time in milliseconds for the embed lock
8+
* Range: 150ms to 5000ms (5 seconds)
9+
* Default: 350ms
10+
*/
11+
embedLockDebounceTime?: number;
12+
}
13+
14+
export const DEFAULT_SETTINGS: UserSettings = {
15+
embedLockDebounceTime: 350, // Default value from CustomEmbeddableRenderer.tsx
16+
};

src/frontend/src/ui/SettingsDialog.scss

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
right: 0;
77
bottom: 0;
88
z-index: 1000;
9-
background-color: rgba(0, 0, 0, 0.2);
10-
backdrop-filter: blur(1px);
119
}
1210

1311
&__title-container {
@@ -37,4 +35,41 @@
3735
color: #888;
3836
font-style: italic;
3937
}
38+
39+
&__section {
40+
margin-bottom: 1.5rem;
41+
}
42+
43+
&__section-title {
44+
margin: 0 0 1rem 0;
45+
font-size: 1rem;
46+
font-weight: 600;
47+
color: var(--text-primary-color);
48+
}
49+
50+
&__setting {
51+
margin-bottom: 1rem;
52+
padding: 0.5rem;
53+
border-radius: 4px;
54+
background-color: var(--dialog-bg-color);
55+
}
56+
57+
&__label {
58+
display: block;
59+
margin-bottom: 0.5rem;
60+
font-size: 0.9rem;
61+
color: var(--text-primary-color);
62+
}
63+
64+
&__range-container {
65+
margin: 1rem 0;
66+
}
67+
68+
&__range-labels {
69+
display: flex;
70+
justify-content: space-between;
71+
font-size: 0.8rem;
72+
color: var(--text-primary-color);
73+
opacity: 0.7;
74+
}
4075
}

src/frontend/src/ui/SettingsDialog.tsx

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
1-
import React, { useState, useCallback } from "react";
2-
import { Dialog } from "@atyrode/excalidraw";
1+
import React, { useState, useCallback, useEffect } from "react";
2+
import { Dialog, Range } from "@atyrode/excalidraw";
3+
import { UserSettings, DEFAULT_SETTINGS } from "../types/settings";
34
import "./SettingsDialog.scss";
45

56
interface SettingsDialogProps {
7+
excalidrawAPI?: any;
68
onClose?: () => void;
79
}
810

911
const SettingsDialog: React.FC<SettingsDialogProps> = ({
12+
excalidrawAPI,
1013
onClose,
1114
}) => {
1215
const [modalIsShown, setModalIsShown] = useState(true);
16+
const [settings, setSettings] = useState<UserSettings>(DEFAULT_SETTINGS);
17+
18+
// Get current settings from excalidrawAPI when component mounts
19+
useEffect(() => {
20+
if (excalidrawAPI) {
21+
const appState = excalidrawAPI.getAppState();
22+
const userSettings = appState?.pad?.userSettings || {};
23+
setSettings({
24+
...DEFAULT_SETTINGS,
25+
...userSettings
26+
});
27+
}
28+
}, [excalidrawAPI]);
1329

1430
const handleClose = useCallback(() => {
1531
setModalIsShown(false);
@@ -18,11 +34,61 @@ const SettingsDialog: React.FC<SettingsDialogProps> = ({
1834
}
1935
}, [onClose]);
2036

37+
const handleEmbedLockDebounceTimeChange = (value: number) => {
38+
if (!excalidrawAPI) return;
39+
40+
const newSettings = {
41+
...settings,
42+
embedLockDebounceTime: value
43+
};
44+
45+
setSettings(newSettings);
46+
47+
// Update the appState
48+
const appState = excalidrawAPI.getAppState();
49+
const updatedAppState = {
50+
...appState,
51+
pad: {
52+
...appState.pad,
53+
userSettings: newSettings
54+
}
55+
};
56+
57+
excalidrawAPI.updateScene({
58+
appState: updatedAppState
59+
});
60+
};
61+
2162
// Dialog content
2263
const dialogContent = (
2364
<div className="settings-dialog__content">
24-
{/* Settings content will go here in the future */}
25-
<div className="settings-dialog__empty">Settings dialog is empty for now</div>
65+
<div className="settings-dialog__section">
66+
<h3 className="settings-dialog__section-title">Embed Settings</h3>
67+
<div className="settings-dialog__setting">
68+
<label className="settings-dialog__label">
69+
Embed Lock Debounce Time: {settings.embedLockDebounceTime}ms
70+
</label>
71+
<div className="settings-dialog__range-container">
72+
<Range
73+
updateData={(value) => handleEmbedLockDebounceTimeChange(
74+
// Map 0-100 range to 150-5000ms
75+
Math.round(150 + (value / 100) * 4850)
76+
)}
77+
appState={{
78+
currentItemOpacity:
79+
// Map 150-5000ms to 0-100 range
80+
Math.round(((settings.embedLockDebounceTime || 350) - 150) / 4850 * 100)
81+
}}
82+
elements={[]}
83+
testId="embed-lock-debounce-time"
84+
/>
85+
</div>
86+
<div className="settings-dialog__range-labels">
87+
<span>150ms</span>
88+
<span>5000ms</span>
89+
</div>
90+
</div>
91+
</div>
2692
</div>
2793
);
2894

src/frontend/src/utils/canvasUtils.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1+
import { DEFAULT_SETTINGS } from '../types/settings';
2+
13
/**
2-
* Normalizes canvas data by removing width and height properties from appState
3-
* and resetting collaborators to an empty Map.
4-
*
5-
* This is necessary when loading canvas data to ensure it fits properly in the current viewport
6-
* and doesn't carry over collaborator information that might be stale.
74
*
85
* @param data The canvas data to normalize
96
* @returns Normalized canvas data
@@ -21,13 +18,23 @@ export function normalizeCanvasData(data: any) {
2118
delete appState.height;
2219
}
2320

21+
// Preserve existing pad settings if they exist, otherwise create new ones
22+
const existingPad = appState.pad || {};
23+
const existingUserSettings = existingPad.userSettings || {};
24+
25+
// Merge existing user settings with default settings
2426
appState.pad = {
2527
moduleBorderOffset: {
2628
left: 10,
2729
right: 10,
2830
top: 40,
2931
bottom: 10,
3032
},
33+
// Merge existing user settings with default settings
34+
userSettings: {
35+
...DEFAULT_SETTINGS,
36+
...existingUserSettings
37+
}
3138
};
3239

3340
// Reset collaborators (https://github.com/excalidraw/excalidraw/issues/8637)

src/frontend/yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
# yarn lockfile v1
33

44

5-
"@atyrode/excalidraw@^0.18.0-3":
6-
version "0.18.0-3"
7-
resolved "https://registry.yarnpkg.com/@atyrode/excalidraw/-/excalidraw-0.18.0-3.tgz#445176d5b9828f033205a46f227fd76e722019ec"
8-
integrity sha512-iWLyYMZNV9VQCcWAtrLmg52NkfCw1CDrigXXRrxa3H2KW6nyrlbFm3KZAF5Y0mOJDYzAtxclPvHoTvcRruMjGg==
5+
"@atyrode/excalidraw@^0.18.0-4":
6+
version "0.18.0-4"
7+
resolved "https://registry.yarnpkg.com/@atyrode/excalidraw/-/excalidraw-0.18.0-4.tgz#3350bd09533cb424105fa615ec0e2e4e243f798e"
8+
integrity sha512-MDYAXT34cNmhoc49eC7iuoweGHsirKKH0VnwDT9CJPWTjUfOrXp/NsL1PHyFIyhBu14NI1osSpGTD0qi1FPegQ==
99
dependencies:
1010
"@braintree/sanitize-url" "6.0.2"
1111
"@excalidraw/laser-pointer" "1.3.1"

0 commit comments

Comments
 (0)