213 lines
7.7 KiB
TypeScript
213 lines
7.7 KiB
TypeScript
import React from 'react';
|
|
import { OpenChamberVisualSettings } from './OpenChamberVisualSettings';
|
|
import { AboutSettings } from './AboutSettings';
|
|
import { SessionRetentionSettings } from './SessionRetentionSettings';
|
|
import { PasskeySettings } from './PasskeySettings';
|
|
import { DefaultsSettings } from './DefaultsSettings';
|
|
import { GitSettings } from './GitSettings';
|
|
import { NotificationSettings } from './NotificationSettings';
|
|
import { GitHubSettings } from './GitHubSettings';
|
|
import { VoiceSettings } from './VoiceSettings';
|
|
import { TunnelSettings } from './TunnelSettings';
|
|
import { OpenCodeCliSettings } from './OpenCodeCliSettings';
|
|
import { DesktopNetworkSettings } from './DesktopNetworkSettings';
|
|
import { KeyboardShortcutsSettings } from './KeyboardShortcutsSettings';
|
|
import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay';
|
|
import { useDeviceInfo } from '@/lib/device';
|
|
import { isDesktopLocalOriginActive, isDesktopShell, isVSCodeRuntime, isWebRuntime } from '@/lib/desktop';
|
|
import { subscribeRuntimeEndpointChanged } from '@/lib/runtime-switch';
|
|
import type { OpenChamberSection } from './types';
|
|
|
|
const useRuntimeEndpointEpoch = (): number => {
|
|
const [epoch, setEpoch] = React.useState(0);
|
|
|
|
React.useEffect(() => {
|
|
return subscribeRuntimeEndpointChanged(() => setEpoch((current) => current + 1));
|
|
}, []);
|
|
|
|
return epoch;
|
|
};
|
|
|
|
interface OpenChamberPageProps {
|
|
/** Which section to display. If undefined, shows all sections (mobile/legacy behavior) */
|
|
section?: OpenChamberSection;
|
|
}
|
|
|
|
export const OpenChamberPage: React.FC<OpenChamberPageProps> = ({ section }) => {
|
|
const { isMobile } = useDeviceInfo();
|
|
const runtimeEndpointEpoch = useRuntimeEndpointEpoch();
|
|
const showAbout = isMobile && isWebRuntime();
|
|
const isVSCode = isVSCodeRuntime();
|
|
void runtimeEndpointEpoch;
|
|
const showDesktopNetworkSettings = isDesktopShell() && isDesktopLocalOriginActive();
|
|
|
|
// If no section specified, show all (mobile/legacy behavior)
|
|
if (!section) {
|
|
return (
|
|
<ScrollableOverlay
|
|
outerClassName="h-full"
|
|
className="w-full"
|
|
>
|
|
<div className="openchamber-page-body mx-auto max-w-3xl space-y-3 p-3 sm:space-y-6 sm:p-6 sm:pt-8">
|
|
<OpenChamberVisualSettings />
|
|
<div className="border-t border-border/40 pt-6">
|
|
<DefaultsSettings />
|
|
</div>
|
|
{showDesktopNetworkSettings && (
|
|
<div className="border-t border-border/40 pt-6">
|
|
<DesktopNetworkSettings />
|
|
</div>
|
|
)}
|
|
{!isVSCode && (
|
|
<div className="border-t border-border/40 pt-6">
|
|
<OpenCodeCliSettings />
|
|
</div>
|
|
)}
|
|
<div className="border-t border-border/40 pt-6">
|
|
<SessionRetentionSettings />
|
|
</div>
|
|
<div className="border-t border-border/40 pt-6">
|
|
<PasskeySettings />
|
|
</div>
|
|
{showAbout && (
|
|
<div className="border-t border-border/40 pt-6">
|
|
<AboutSettings />
|
|
</div>
|
|
)}
|
|
</div>
|
|
</ScrollableOverlay>
|
|
);
|
|
}
|
|
|
|
// Show specific section content
|
|
const renderSectionContent = () => {
|
|
switch (section) {
|
|
case 'visual':
|
|
return <VisualSectionContent />;
|
|
case 'chat':
|
|
return <ChatSectionContent />;
|
|
case 'sessions':
|
|
return <SessionsSectionContent />;
|
|
case 'shortcuts':
|
|
return <ShortcutsSectionContent />;
|
|
case 'git':
|
|
return <GitSectionContent />;
|
|
case 'github':
|
|
return <GitHubSectionContent />;
|
|
case 'notifications':
|
|
return <NotificationSectionContent />;
|
|
case 'voice':
|
|
return <VoiceSectionContent />;
|
|
case 'tunnel':
|
|
return <TunnelSectionContent />;
|
|
default:
|
|
return null;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<ScrollableOverlay
|
|
outerClassName="h-full"
|
|
className="w-full"
|
|
>
|
|
<div className="openchamber-page-body mx-auto max-w-3xl space-y-6 p-3 sm:p-6 sm:pt-8">
|
|
{renderSectionContent()}
|
|
</div>
|
|
</ScrollableOverlay>
|
|
);
|
|
};
|
|
|
|
const ShortcutsSectionContent: React.FC = () => {
|
|
return <KeyboardShortcutsSettings />;
|
|
};
|
|
|
|
// Visual section: Theme Mode, Font Size, Spacing, Input Bar Offset (mobile), Nav Rail
|
|
const VisualSectionContent: React.FC = () => {
|
|
const isVSCode = isVSCodeRuntime();
|
|
return <OpenChamberVisualSettings visibleSettings={[
|
|
'theme',
|
|
'pwaInstallName',
|
|
'pwaOrientation',
|
|
'mobileKeyboardMode',
|
|
'timeFormat',
|
|
...(!isVSCode ? ['weekStart' as const] : []),
|
|
'fontSize',
|
|
'terminalFontSize',
|
|
'spacing',
|
|
'inputBarOffset',
|
|
...(!isVSCode ? ['terminalQuickKeys' as const] : []),
|
|
'reportUsage',
|
|
]} />;
|
|
};
|
|
|
|
// Chat section: User message rendering, Diff layout, Mobile status bar, Show reasoning traces, Queue mode, Persist draft
|
|
const ChatSectionContent: React.FC = () => {
|
|
return <OpenChamberVisualSettings visibleSettings={['chatRenderMode', 'messageTransport', 'activityRenderMode', 'userMessageRendering', 'mermaidRendering', 'reasoning', 'showToolFileIcons', 'showTurnChangedFiles', 'expandedTools', 'stickyUserHeader', 'wideChatLayout', 'splitAssistantMessageActions', 'diffLayout', 'mobileStatusBar', 'dotfiles', 'fileViewerPreview', 'queueMode', 'persistDraft', 'inputSpellcheck']} />;
|
|
};
|
|
|
|
// Sessions section: Default model & agent, Session retention
|
|
const SessionsSectionContent: React.FC = () => {
|
|
const isVSCode = isVSCodeRuntime();
|
|
const runtimeEndpointEpoch = useRuntimeEndpointEpoch();
|
|
void runtimeEndpointEpoch;
|
|
const showDesktopNetworkSettings = isDesktopShell() && isDesktopLocalOriginActive();
|
|
return (
|
|
<div className="space-y-6">
|
|
<DefaultsSettings />
|
|
{showDesktopNetworkSettings && (
|
|
<div className="border-t border-border/40 pt-6">
|
|
<DesktopNetworkSettings />
|
|
</div>
|
|
)}
|
|
{!isVSCode && (
|
|
<div className="border-t border-border/40 pt-6">
|
|
<OpenCodeCliSettings />
|
|
</div>
|
|
)}
|
|
<div className="border-t border-border/40 pt-6">
|
|
<SessionRetentionSettings />
|
|
</div>
|
|
<div className="border-t border-border/40 pt-6">
|
|
<PasskeySettings />
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// Git section: Commit message model, Worktree settings
|
|
const GitSectionContent: React.FC = () => {
|
|
return (
|
|
<div className="space-y-6">
|
|
<GitSettings />
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// GitHub section: Connect account for PR/issue workflows
|
|
const GitHubSectionContent: React.FC = () => {
|
|
if (isVSCodeRuntime()) {
|
|
return null;
|
|
}
|
|
return <GitHubSettings />;
|
|
};
|
|
|
|
// Notifications section: Native browser notifications
|
|
const NotificationSectionContent: React.FC = () => {
|
|
return <NotificationSettings />;
|
|
};
|
|
|
|
// Voice section: Language selection and continuous mode
|
|
const VoiceSectionContent: React.FC = () => {
|
|
if (isVSCodeRuntime()) {
|
|
return null;
|
|
}
|
|
return <VoiceSettings />;
|
|
};
|
|
|
|
const TunnelSectionContent: React.FC = () => {
|
|
if (isVSCodeRuntime()) {
|
|
return null;
|
|
}
|
|
return <TunnelSettings />;
|
|
};
|