mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-03-10 00:17:43 +00:00
refactor(quick-settings): migrate panel to typed feature-based modules
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
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
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)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user