This commit is contained in:
2026-01-31 14:14:47 +02:00
parent 04fe8fb814
commit cdbf0127bf

View File

@@ -1,4 +1,4 @@
import { useEffect, useState, useCallback } from 'react'; import { useEffect, useState, useCallback, useRef } from 'react';
import type { Site } from '@/types/index.ts'; import type { Site } from '@/types/index.ts';
import type { Preset } from '@/services/api.ts'; import type { Preset } from '@/services/api.ts';
import { api } from '@/services/api.ts'; import { api } from '@/services/api.ts';
@@ -117,6 +117,46 @@ export default function App() {
const [showShortcuts, setShowShortcuts] = useState(false); const [showShortcuts, setShowShortcuts] = useState(false);
const [kbDeleteTarget, setKbDeleteTarget] = useState<{ id: string; name: string } | null>(null); const [kbDeleteTarget, setKbDeleteTarget] = useState<{ id: string; name: string } | null>(null);
// Resizable sidebar
const PANEL_MIN = 300;
const PANEL_MAX = 600;
const PANEL_DEFAULT = 380;
const [panelWidth, setPanelWidth] = useState(() => {
const saved = localStorage.getItem('rfcp-panel-width');
const n = saved ? Number(saved) : PANEL_DEFAULT;
return n >= PANEL_MIN && n <= PANEL_MAX ? n : PANEL_DEFAULT;
});
const isDragging = useRef(false);
const handleDragStart = useCallback((e: React.MouseEvent) => {
e.preventDefault();
isDragging.current = true;
document.body.style.cursor = 'col-resize';
document.body.style.userSelect = 'none';
const onMove = (ev: MouseEvent) => {
if (!isDragging.current) return;
const newWidth = window.innerWidth - ev.clientX;
const clamped = Math.max(PANEL_MIN, Math.min(PANEL_MAX, newWidth));
setPanelWidth(clamped);
};
const onUp = () => {
isDragging.current = false;
document.body.style.cursor = '';
document.body.style.userSelect = '';
document.removeEventListener('mousemove', onMove);
document.removeEventListener('mouseup', onUp);
setPanelWidth((w) => {
localStorage.setItem('rfcp-panel-width', String(w));
return w;
});
};
document.addEventListener('mousemove', onMove);
document.addEventListener('mouseup', onUp);
}, []);
// Load sites from IndexedDB on mount // Load sites from IndexedDB on mount
useEffect(() => { useEffect(() => {
loadSites(); loadSites();
@@ -587,9 +627,16 @@ export default function App() {
<div <div
className={`${ className={`${
panelCollapsed ? 'hidden' : 'flex' panelCollapsed ? 'hidden' : 'flex'
} flex-col w-full sm:w-80 lg:w-96 bg-gray-50 dark:bg-dark-bg border-l border-gray-200 dark:border-dark-border } flex-col bg-gray-50 dark:bg-dark-bg border-l border-gray-200 dark:border-dark-border
overflow-y-auto absolute sm:relative inset-0 sm:inset-auto z-[1001]`} overflow-y-auto absolute sm:relative inset-0 sm:inset-auto z-[1001]`}
style={{ width: window.innerWidth >= 640 ? panelWidth : undefined }}
> >
{/* Resize drag handle (desktop only) */}
<div
onMouseDown={handleDragStart}
className="hidden sm:block absolute left-0 top-0 bottom-0 w-1 cursor-col-resize z-10
hover:bg-blue-400/50 active:bg-blue-500/60 transition-colors"
/>
{/* Mobile drag handle + close */} {/* Mobile drag handle + close */}
<div className="sm:hidden flex flex-col items-center pt-2 pb-1"> <div className="sm:hidden flex flex-col items-center pt-2 pb-1">
<div className="w-12 h-1 bg-gray-300 dark:bg-dark-border rounded-full mb-2" /> <div className="w-12 h-1 bg-gray-300 dark:bg-dark-border rounded-full mb-2" />