Compare commits

..

5 Commits

Author SHA1 Message Date
ruinivist 589ad162f9 fix: adjust sidebar toggle button sizing and styling
Adjusts the CSS and SVG dimensions of the custom sidebar toggle
button so that it identically matches the 36x36px Excalidraw UI
native buttons (like the Help button) in both Light and Dark themes.

The inner SVG icon was precisely aligned to be 16x16px and use
a 1.8px stroke to match the weight and left-alignment of the native
icons. The .secondary-button class padding that was interfering
was removed.
2026-05-30 22:25:28 +00:00
ruinivist 93608bda1e fix: adjust sizing of sidebar SVG to match Excalidraw UI 2026-05-30 21:47:26 +00:00
ruinivist e576ca7d2d fix: adjust sizing of sidebar SVG to match Excalidraw UI 2026-05-30 20:31:46 +00:00
ruinivist 8630492b44 fix: apply precise styling to sidebar toggle for light and dark modes 2026-05-30 20:12:52 +00:00
ruinivist d52c08cd10 fix: style sidebar button to match native Excalidraw UI 2026-05-30 18:07:38 +00:00
2 changed files with 18 additions and 89 deletions
+7 -61
View File
@@ -80,10 +80,10 @@ async function requestJson<T>(url: string, init?: RequestInit): Promise<T> {
function DrawerIcon() {
return (
<svg viewBox="0 0 24 24" aria-hidden="true">
<rect x="3.5" y="5" width="17" height="14" rx="2.5" fill="none" stroke="currentColor" strokeWidth="1.8" />
<path d="M9 5v14" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
<path d="M5.75 9h1.5M5.75 12h1.5M5.75 15h1.5" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
<svg viewBox="0 0 24 24" aria-hidden="true" width="16" height="16">
<rect x="3.5" y="5" width="17" height="14" rx="2.5" fill="none" stroke="currentColor" strokeWidth="1.5" />
<path d="M9 5v14" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
<path d="M5.75 9h1.5M5.75 12h1.5M5.75 15h1.5" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
</svg>
);
}
@@ -96,7 +96,6 @@ export function App() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const [toastMessage, setToastMessage] = useState<string | null>(null);
const currentIdRef = useRef<string | null>(activeId);
const currentTitleRef = useRef(activeTitle);
@@ -107,7 +106,6 @@ export function App() {
const inFlightSaveRef = useRef<Promise<void> | null>(null);
const loadVersionRef = useRef(0);
const themeSyncFrameRef = useRef<number | null>(null);
const toastTimeoutRef = useRef<number | null>(null);
const activeDrawing = useMemo(
() => drawings.find((drawing) => drawing.id === activeId) ?? null,
@@ -120,7 +118,7 @@ export function App() {
return list;
}, []);
const saveScene = useCallback(async (isManual = false) => {
const saveScene = useCallback(async () => {
const drawingId = currentIdRef.current;
const nextScene = latestSceneRef.current;
if (!drawingId || !nextScene) {
@@ -128,37 +126,15 @@ export function App() {
}
setError(null);
if (isManual) {
setToastMessage("Saving...");
if (toastTimeoutRef.current !== null) {
clearTimeout(toastTimeoutRef.current);
toastTimeoutRef.current = null;
}
}
const promise = requestJson<{ ok: true; drawing: DrawingMeta }>(`/api/drawings/${drawingId}`, {
method: "PUT",
body: JSON.stringify(nextScene),
})
.then((body) => {
setDrawings((current) => replaceMeta(current, body.drawing));
if (isManual) {
setToastMessage("Saved");
if (toastTimeoutRef.current !== null) {
clearTimeout(toastTimeoutRef.current);
}
toastTimeoutRef.current = window.setTimeout(() => setToastMessage(null), 2000);
}
})
.catch((saveError: unknown) => {
setError(saveError instanceof Error ? saveError.message : "Save failed");
if (isManual) {
setToastMessage("Save failed");
if (toastTimeoutRef.current !== null) {
clearTimeout(toastTimeoutRef.current);
}
toastTimeoutRef.current = window.setTimeout(() => setToastMessage(null), 2000);
}
throw saveError;
})
.finally(() => {
@@ -182,17 +158,6 @@ export function App() {
}
}, [saveScene]);
const triggerManualSave = useCallback(async () => {
if (timeoutRef.current !== null) {
clearTimeout(timeoutRef.current);
timeoutRef.current = null;
}
if (inFlightSaveRef.current) {
await inFlightSaveRef.current;
}
await saveScene(true);
}, [saveScene]);
const scheduleSave = useCallback(() => {
if (timeoutRef.current !== null) {
clearTimeout(timeoutRef.current);
@@ -201,7 +166,7 @@ export function App() {
timeoutRef.current = window.setTimeout(() => {
timeoutRef.current = null;
void saveScene();
}, 30000);
}, 1500);
}, [saveScene]);
const loadDrawing = useCallback(
@@ -364,20 +329,6 @@ export function App() {
});
}, [syncThemeTokens]);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "s") {
e.preventDefault();
e.stopPropagation();
void triggerManualSave();
}
};
window.addEventListener("keydown", handleKeyDown, { capture: true });
return () => {
window.removeEventListener("keydown", handleKeyDown, { capture: true });
};
}, [triggerManualSave]);
useEffect(() => {
const currentPathId = pathToId();
if (currentPathId) {
@@ -459,16 +410,11 @@ export function App() {
return (
<div className="app-shell" ref={appShellRef}>
{toastMessage && (
<div className="toast-overlay" aria-live="polite">
{toastMessage}
</div>
)}
<main className="editor-shell">
<div className="app-actions">
<button
type="button"
className="secondary-button app-actions-toggle"
className="app-actions-toggle"
onClick={openSidebar}
aria-label="Open drawings"
>
+11 -28
View File
@@ -169,22 +169,21 @@ input {
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--lg-button-size, 2.25rem);
height: var(--lg-button-size, 2.25rem);
width: 2.25rem;
height: 2.25rem;
padding: 0;
border: none;
border-radius: var(--border-radius-lg, 12px);
box-shadow: 0 0 0 1px var(--app-surface-lowest);
border-radius: 8px;
box-shadow: none;
background: var(--app-surface-low);
color: var(--app-text-color);
cursor: pointer;
transition: background-color 120ms ease, box-shadow 120ms ease;
}
.app-actions-toggle svg {
width: 1rem;
height: 1rem;
overflow: visible;
transform: translateY(0.5px) scale(1.08);
transform-origin: center;
width: 16px;
height: 16px;
}
.primary-button,
@@ -253,22 +252,6 @@ input {
pointer-events: auto;
}
.toast-overlay {
position: fixed;
top: 16px;
right: 16px;
z-index: 100;
background: var(--app-overlay-bg);
backdrop-filter: blur(4px);
color: var(--app-text-color);
padding: 8px 16px;
border-radius: 8px;
font-size: var(--app-sidebar-font-size);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
border: 1px solid var(--app-sidebar-border);
pointer-events: none;
}
.editor-frame,
.editor-loading {
height: 100%;
@@ -281,12 +264,12 @@ input {
}
.app-actions-toggle:hover {
background: var(--app-button-hover-bg);
background-color: var(--app-button-hover-bg);
}
.app-actions-toggle:active {
box-shadow: 0 0 0 1px var(--app-button-active-border);
background: var(--app-button-active-bg);
background-color: var(--app-button-active-bg);
box-shadow: none;
}
.sr-only {