fix: move file preview setting to chat settings
Moved file preview mode toggle next to Show Dotfiles Saved checkbox changes through settings config Applied preview mode changes to open editor tabs immediately
This commit is contained in:
@@ -32,8 +32,6 @@ export const DefaultsSettings: React.FC = () => {
|
|||||||
const setSettingsDefaultModel = useConfigStore((state) => state.setSettingsDefaultModel);
|
const setSettingsDefaultModel = useConfigStore((state) => state.setSettingsDefaultModel);
|
||||||
const setSettingsDefaultVariant = useConfigStore((state) => state.setSettingsDefaultVariant);
|
const setSettingsDefaultVariant = useConfigStore((state) => state.setSettingsDefaultVariant);
|
||||||
const setSettingsDefaultAgent = useConfigStore((state) => state.setSettingsDefaultAgent);
|
const setSettingsDefaultAgent = useConfigStore((state) => state.setSettingsDefaultAgent);
|
||||||
const setSettingsDefaultFileViewerPreview = useConfigStore((state) => state.setSettingsDefaultFileViewerPreview);
|
|
||||||
const settingsDefaultFileViewerPreview = useConfigStore((state) => state.settingsDefaultFileViewerPreview);
|
|
||||||
const showDeletionDialog = useUIStore((state) => state.showDeletionDialog);
|
const showDeletionDialog = useUIStore((state) => state.showDeletionDialog);
|
||||||
const setShowDeletionDialog = useUIStore((state) => state.setShowDeletionDialog);
|
const setShowDeletionDialog = useUIStore((state) => state.setShowDeletionDialog);
|
||||||
const providers = useConfigStore((state) => state.providers);
|
const providers = useConfigStore((state) => state.providers);
|
||||||
@@ -191,12 +189,6 @@ export const DefaultsSettings: React.FC = () => {
|
|||||||
[setAgent, setSettingsDefaultAgent]
|
[setAgent, setSettingsDefaultAgent]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleToggleFileViewerPreview = React.useCallback(() => {
|
|
||||||
const next = !settingsDefaultFileViewerPreview;
|
|
||||||
setSettingsDefaultFileViewerPreview(next);
|
|
||||||
updateDesktopSettings({ defaultFileViewerPreview: next }).catch(console.warn);
|
|
||||||
}, [settingsDefaultFileViewerPreview, setSettingsDefaultFileViewerPreview]);
|
|
||||||
|
|
||||||
const availableVariants = React.useMemo(() => {
|
const availableVariants = React.useMemo(() => {
|
||||||
if (!parsedModel.providerId || !parsedModel.modelId) return [];
|
if (!parsedModel.providerId || !parsedModel.modelId) return [];
|
||||||
const provider = providers.find((p) => p.id === parsedModel.providerId);
|
const provider = providers.find((p) => p.id === parsedModel.providerId);
|
||||||
@@ -311,23 +303,6 @@ export const DefaultsSettings: React.FC = () => {
|
|||||||
<span className="typography-ui-label text-foreground">{t('settings.openchamber.defaults.field.showDeletionDialog')}</span>
|
<span className="typography-ui-label text-foreground">{t('settings.openchamber.defaults.field.showDeletionDialog')}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
|
||||||
className="group flex cursor-pointer items-center gap-2 py-1"
|
|
||||||
role="button"
|
|
||||||
tabIndex={0}
|
|
||||||
aria-pressed={settingsDefaultFileViewerPreview}
|
|
||||||
onClick={handleToggleFileViewerPreview}
|
|
||||||
onKeyDown={(event) => {
|
|
||||||
if (event.key === ' ' || event.key === 'Enter') {
|
|
||||||
event.preventDefault();
|
|
||||||
handleToggleFileViewerPreview();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Checkbox checked={settingsDefaultFileViewerPreview} onChange={setSettingsDefaultFileViewerPreview} ariaLabel={t('settings.openchamber.defaults.field.openFilesPreviewAria')} />
|
|
||||||
<span className="typography-ui-label text-foreground">{t('settings.openchamber.defaults.field.openFilesPreview')}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ const VisualSectionContent: React.FC = () => {
|
|||||||
|
|
||||||
// Chat section: User message rendering, Diff layout, Mobile status bar, Show reasoning traces, Queue mode, Persist draft
|
// Chat section: User message rendering, Diff layout, Mobile status bar, Show reasoning traces, Queue mode, Persist draft
|
||||||
const ChatSectionContent: React.FC = () => {
|
const ChatSectionContent: React.FC = () => {
|
||||||
return <OpenChamberVisualSettings visibleSettings={['chatRenderMode', 'messageTransport', 'activityRenderMode', 'userMessageRendering', 'mermaidRendering', 'reasoning', 'showToolFileIcons', 'expandedTools', 'stickyUserHeader', 'wideChatLayout', 'splitAssistantMessageActions', 'diffLayout', 'mobileStatusBar', 'dotfiles', 'queueMode', 'persistDraft', 'inputSpellcheck']} />;
|
return <OpenChamberVisualSettings visibleSettings={['chatRenderMode', 'messageTransport', 'activityRenderMode', 'userMessageRendering', 'mermaidRendering', 'reasoning', 'showToolFileIcons', 'expandedTools', 'stickyUserHeader', 'wideChatLayout', 'splitAssistantMessageActions', 'diffLayout', 'mobileStatusBar', 'dotfiles', 'fileViewerPreview', 'queueMode', 'persistDraft', 'inputSpellcheck']} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sessions section: Default model & agent, Session retention
|
// Sessions section: Default model & agent, Session retention
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ const normalizeUserMessageRenderingMode = (mode: unknown): 'markdown' | 'plain'
|
|||||||
return mode === 'markdown' ? 'markdown' : 'plain';
|
return mode === 'markdown' ? 'markdown' : 'plain';
|
||||||
};
|
};
|
||||||
|
|
||||||
export type VisibleSetting = 'theme' | 'pwaInstallName' | 'pwaOrientation' | 'mobileKeyboardMode' | 'timeFormat' | 'weekStart' | 'fontSize' | 'terminalFontSize' | 'spacing' | 'inputBarOffset' | 'mermaidRendering' | 'userMessageRendering' | 'chatRenderMode' | 'messageTransport' | 'activityRenderMode' | 'stickyUserHeader' | 'wideChatLayout' | 'splitAssistantMessageActions' | 'diffLayout' | 'mobileStatusBar' | 'dotfiles' | 'reasoning' | 'showToolFileIcons' | 'expandedTools' | 'queueMode' | 'terminalQuickKeys' | 'persistDraft' | 'inputSpellcheck' | 'reportUsage';
|
export type VisibleSetting = 'theme' | 'pwaInstallName' | 'pwaOrientation' | 'mobileKeyboardMode' | 'timeFormat' | 'weekStart' | 'fontSize' | 'terminalFontSize' | 'spacing' | 'inputBarOffset' | 'mermaidRendering' | 'userMessageRendering' | 'chatRenderMode' | 'messageTransport' | 'activityRenderMode' | 'stickyUserHeader' | 'wideChatLayout' | 'splitAssistantMessageActions' | 'diffLayout' | 'mobileStatusBar' | 'dotfiles' | 'fileViewerPreview' | 'reasoning' | 'showToolFileIcons' | 'expandedTools' | 'queueMode' | 'terminalQuickKeys' | 'persistDraft' | 'inputSpellcheck' | 'reportUsage';
|
||||||
|
|
||||||
interface OpenChamberVisualSettingsProps {
|
interface OpenChamberVisualSettingsProps {
|
||||||
/** Which settings to show. If undefined, shows all. */
|
/** Which settings to show. If undefined, shows all. */
|
||||||
@@ -319,6 +319,8 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
|
|||||||
const setShowMobileSessionStatusBar = useUIStore(state => state.setShowMobileSessionStatusBar);
|
const setShowMobileSessionStatusBar = useUIStore(state => state.setShowMobileSessionStatusBar);
|
||||||
const messageStreamTransport = useConfigStore((state) => state.settingsMessageStreamTransport);
|
const messageStreamTransport = useConfigStore((state) => state.settingsMessageStreamTransport);
|
||||||
const setMessageStreamTransport = useConfigStore((state) => state.setSettingsMessageStreamTransport);
|
const setMessageStreamTransport = useConfigStore((state) => state.setSettingsMessageStreamTransport);
|
||||||
|
const settingsDefaultFileViewerPreview = useConfigStore((state) => state.settingsDefaultFileViewerPreview);
|
||||||
|
const setSettingsDefaultFileViewerPreview = useConfigStore((state) => state.setSettingsDefaultFileViewerPreview);
|
||||||
const isSettingsDialogOpen = useUIStore(state => state.isSettingsDialogOpen);
|
const isSettingsDialogOpen = useUIStore(state => state.isSettingsDialogOpen);
|
||||||
const {
|
const {
|
||||||
themeMode,
|
themeMode,
|
||||||
@@ -439,6 +441,12 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
|
|||||||
void updateDesktopSettings({ showToolFileIcons: enabled });
|
void updateDesktopSettings({ showToolFileIcons: enabled });
|
||||||
}, [setShowToolFileIcons]);
|
}, [setShowToolFileIcons]);
|
||||||
|
|
||||||
|
const handleFileViewerPreviewChange = React.useCallback((enabled: boolean) => {
|
||||||
|
setSettingsDefaultFileViewerPreview(enabled);
|
||||||
|
void updateDesktopSettings({ defaultFileViewerPreview: enabled });
|
||||||
|
window.dispatchEvent(new CustomEvent('openchamber:file-viewer-preview-mode-changed', { detail: { enabled } }));
|
||||||
|
}, [setSettingsDefaultFileViewerPreview]);
|
||||||
|
|
||||||
const handleShowExpandedBashToolsChange = React.useCallback((enabled: boolean) => {
|
const handleShowExpandedBashToolsChange = React.useCallback((enabled: boolean) => {
|
||||||
setShowExpandedBashTools(enabled);
|
setShowExpandedBashTools(enabled);
|
||||||
void updateDesktopSettings({ showExpandedBashTools: enabled });
|
void updateDesktopSettings({ showExpandedBashTools: enabled });
|
||||||
@@ -513,6 +521,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
|
|||||||
|| shouldShow('diffLayout')
|
|| shouldShow('diffLayout')
|
||||||
|| (shouldShow('mobileStatusBar') && isMobile)
|
|| (shouldShow('mobileStatusBar') && isMobile)
|
||||||
|| shouldShow('dotfiles')
|
|| shouldShow('dotfiles')
|
||||||
|
|| shouldShow('fileViewerPreview')
|
||||||
|| shouldShow('reasoning')
|
|| shouldShow('reasoning')
|
||||||
|| shouldShow('queueMode')
|
|| shouldShow('queueMode')
|
||||||
|| shouldShow('persistDraft')
|
|| shouldShow('persistDraft')
|
||||||
@@ -1578,7 +1587,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(shouldShow('stickyUserHeader') || shouldShow('wideChatLayout') || shouldShow('splitAssistantMessageActions') || (shouldShow('mobileStatusBar') && isMobile) || shouldShow('dotfiles') || shouldShow('queueMode') || shouldShow('persistDraft') || shouldShow('showToolFileIcons') || (!isMobile && shouldShow('inputSpellcheck')) || shouldShow('reasoning')) && (
|
{(shouldShow('stickyUserHeader') || shouldShow('wideChatLayout') || shouldShow('splitAssistantMessageActions') || (shouldShow('mobileStatusBar') && isMobile) || shouldShow('dotfiles') || shouldShow('fileViewerPreview') || shouldShow('queueMode') || shouldShow('persistDraft') || shouldShow('showToolFileIcons') || (!isMobile && shouldShow('inputSpellcheck')) || shouldShow('reasoning')) && (
|
||||||
<section className="p-2 space-y-0.5">
|
<section className="p-2 space-y-0.5">
|
||||||
{shouldShow('reasoning') && (
|
{shouldShow('reasoning') && (
|
||||||
<div
|
<div
|
||||||
@@ -1774,6 +1783,31 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{shouldShow('fileViewerPreview') && (
|
||||||
|
<div
|
||||||
|
className="group flex cursor-pointer items-center gap-2 py-0.5"
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
aria-pressed={settingsDefaultFileViewerPreview}
|
||||||
|
onClick={() => handleFileViewerPreviewChange(!settingsDefaultFileViewerPreview)}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if (event.key === ' ' || event.key === 'Enter') {
|
||||||
|
event.preventDefault();
|
||||||
|
handleFileViewerPreviewChange(!settingsDefaultFileViewerPreview);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span onClick={(event) => event.stopPropagation()}>
|
||||||
|
<Checkbox
|
||||||
|
checked={settingsDefaultFileViewerPreview}
|
||||||
|
onChange={handleFileViewerPreviewChange}
|
||||||
|
ariaLabel={t('settings.openchamber.defaults.field.openFilesPreviewAria')}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span className="typography-ui-label text-foreground">{t('settings.openchamber.defaults.field.openFilesPreview')}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{shouldShow('queueMode') && (
|
{shouldShow('queueMode') && (
|
||||||
<div
|
<div
|
||||||
className="group flex cursor-pointer items-center gap-2 py-0.5"
|
className="group flex cursor-pointer items-center gap-2 py-0.5"
|
||||||
|
|||||||
@@ -2258,6 +2258,48 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
|
|||||||
const getHtmlViewMode = React.useCallback((): PreviewViewMode => {
|
const getHtmlViewMode = React.useCallback((): PreviewViewMode => {
|
||||||
return htmlViewMode;
|
return htmlViewMode;
|
||||||
}, [htmlViewMode]);
|
}, [htmlViewMode]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const applyDefaultFileViewerMode = (enabled: boolean) => {
|
||||||
|
const textMode: TextViewMode = enabled ? 'view' : 'edit';
|
||||||
|
const previewMode: PreviewViewMode = enabled ? 'preview' : 'edit';
|
||||||
|
const nextJsonMode: 'tree' | 'text' = enabled ? 'tree' : 'text';
|
||||||
|
|
||||||
|
for (const path of openPaths) {
|
||||||
|
textViewModeByPathRef.current[path] = textMode;
|
||||||
|
if (isMarkdownFile(path)) {
|
||||||
|
mdViewModeByPathRef.current[path] = previewMode;
|
||||||
|
}
|
||||||
|
if (isHtmlFile(path)) {
|
||||||
|
htmlViewModeByPathRef.current[path] = previewMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTextViewMode(textMode);
|
||||||
|
setMdViewMode(previewMode);
|
||||||
|
setHtmlViewMode(previewMode);
|
||||||
|
setJsonViewMode(nextJsonMode);
|
||||||
|
|
||||||
|
try {
|
||||||
|
localStorage.setItem(MD_VIEWER_MODE_KEY, previewMode);
|
||||||
|
localStorage.setItem(HTML_VIEWER_MODE_KEY, previewMode);
|
||||||
|
localStorage.setItem(JSON_VIEWER_MODE_KEY, nextJsonMode);
|
||||||
|
} catch {
|
||||||
|
// Ignore localStorage errors
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFileViewerModeChanged = (event: Event) => {
|
||||||
|
const enabled = Boolean((event as CustomEvent<{ enabled?: boolean }>).detail?.enabled);
|
||||||
|
applyDefaultFileViewerMode(enabled);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('openchamber:file-viewer-preview-mode-changed', handleFileViewerModeChanged);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('openchamber:file-viewer-preview-mode-changed', handleFileViewerModeChanged);
|
||||||
|
};
|
||||||
|
}, [openPaths]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!pendingFileNavigation || !root) {
|
if (!pendingFileNavigation || !root) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user