mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-03-07 23:17:37 +00:00
Refactor QuickSettingsPanel from a single JSX component into a modular TypeScript feature structure while preserving behavior and translations. Highlights: - Replace legacy src/components/QuickSettingsPanel.jsx with a typed entrypoint (src/components/QuickSettingsPanel.tsx). - Introduce src/components/quick-settings-panel/ with clear separation of concerns: - view/: panel shell, header, handle, section wrappers, toggle rows, and content sections. - hooks/: drag interactions and whisper mode persistence. - constants.ts and types.ts for shared config and strict local typing. - Move drag logic into useQuickSettingsDrag with explicit touch/mouse handling, drag threshold detection, click suppression after drag, position clamping, and localStorage persistence. - Keep user-visible behavior intact: - same open/close panel interactions. - same mobile/desktop drag behavior and persisted handle position. - same quick preference toggles and wiring to useUiPreferences. - same hidden whisper section behavior and localStorage/event updates. - Improve readability and maintainability by extracting repetitive setting rows and section scaffolding into reusable components. - Add focused comments around non-obvious behavior (drag click suppression, touch scroll lock, hidden whisper section intent). - Keep files small and reviewable (all new/changed files are under 300 lines). Validation: - npm run typecheck - npm run build
92 lines
3.1 KiB
TypeScript
92 lines
3.1 KiB
TypeScript
import { useCallback, useMemo, useState } from 'react';
|
|
import type { MouseEvent as ReactMouseEvent } from 'react';
|
|
import { useDeviceSettings } from '../../../hooks/useDeviceSettings';
|
|
import { useUiPreferences } from '../../../hooks/useUiPreferences';
|
|
import { useTheme } from '../../../contexts/ThemeContext';
|
|
import { useQuickSettingsDrag } from '../hooks/useQuickSettingsDrag';
|
|
import type { PreferenceToggleKey, QuickSettingsPreferences } from '../types';
|
|
import QuickSettingsContent from './QuickSettingsContent';
|
|
import QuickSettingsHandle from './QuickSettingsHandle';
|
|
import QuickSettingsPanelHeader from './QuickSettingsPanelHeader';
|
|
|
|
export default function QuickSettingsPanelView() {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const { isMobile } = useDeviceSettings({ trackPWA: false });
|
|
const { isDarkMode } = useTheme();
|
|
const { preferences, setPreference } = useUiPreferences();
|
|
const {
|
|
isDragging,
|
|
handleStyle,
|
|
startDrag,
|
|
consumeSuppressedClick,
|
|
} = useQuickSettingsDrag({ isMobile });
|
|
|
|
const quickSettingsPreferences = useMemo<QuickSettingsPreferences>(() => ({
|
|
autoExpandTools: preferences.autoExpandTools,
|
|
showRawParameters: preferences.showRawParameters,
|
|
showThinking: preferences.showThinking,
|
|
autoScrollToBottom: preferences.autoScrollToBottom,
|
|
sendByCtrlEnter: preferences.sendByCtrlEnter,
|
|
}), [
|
|
preferences.autoExpandTools,
|
|
preferences.autoScrollToBottom,
|
|
preferences.sendByCtrlEnter,
|
|
preferences.showRawParameters,
|
|
preferences.showThinking,
|
|
]);
|
|
|
|
const handlePreferenceChange = useCallback(
|
|
(key: PreferenceToggleKey, value: boolean) => {
|
|
setPreference(key, value);
|
|
},
|
|
[setPreference],
|
|
);
|
|
|
|
const handleToggleFromHandle = useCallback(
|
|
(event: ReactMouseEvent<HTMLButtonElement>) => {
|
|
// A drag releases a click event as well; this guard prevents accidental toggles.
|
|
if (consumeSuppressedClick()) {
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
|
|
setIsOpen((previous) => !previous);
|
|
},
|
|
[consumeSuppressedClick],
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<QuickSettingsHandle
|
|
isOpen={isOpen}
|
|
isDragging={isDragging}
|
|
style={handleStyle}
|
|
onClick={handleToggleFromHandle}
|
|
onMouseDown={startDrag}
|
|
onTouchStart={startDrag}
|
|
/>
|
|
|
|
<div
|
|
className={`fixed top-0 right-0 h-full w-64 bg-background border-l border-border shadow-xl transform transition-transform duration-150 ease-out z-40 ${isOpen ? 'translate-x-0' : 'translate-x-full'} ${isMobile ? 'h-screen' : ''}`}
|
|
>
|
|
<div className="h-full flex flex-col">
|
|
<QuickSettingsPanelHeader />
|
|
<QuickSettingsContent
|
|
isDarkMode={isDarkMode}
|
|
isMobile={isMobile}
|
|
preferences={quickSettingsPreferences}
|
|
onPreferenceChange={handlePreferenceChange}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{isOpen && (
|
|
<div
|
|
className="fixed inset-0 bg-background/80 backdrop-blur-sm z-30 transition-opacity duration-150 ease-out"
|
|
onClick={() => setIsOpen(false)}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|