From e58dabf75f03a0b65f95d91ee06f9c8b1e16f226 Mon Sep 17 00:00:00 2001
From: "Plamen K. Kosseff" <333840+blackd@users.noreply.github.com>
Date: Thu, 27 Aug 2026 23:32:32 +0300
Subject: [PATCH 1/2] feat(ui): add 'Focus mode' option in chat settings to
persistently toggle the sidebar auto-collapse (#11750)
Assisted-by: Claude:claude-fable-5
Signed-off-by: Plamen K. Kosseff
---
.../http/react-ui/public/locales/en/chat.json | 2 ++
core/http/react-ui/src/pages/Chat.jsx | 28 +++++++++++++++++--
2 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/core/http/react-ui/public/locales/en/chat.json b/core/http/react-ui/public/locales/en/chat.json
index f004cee56526..f1c0587905dd 100644
--- a/core/http/react-ui/public/locales/en/chat.json
+++ b/core/http/react-ui/public/locales/en/chat.json
@@ -33,6 +33,8 @@
"title": "Chat Settings",
"manageMode": "Manage mode",
"manageModeDesc": "Let this chat install models, switch backends, and edit configs by talking to LocalAI.",
+ "focusMode": "Focus mode",
+ "focusModeDesc": "Collapse the sidebar and slim the header while a conversation is active. Esc restores them temporarily; turn this off to keep the full layout.",
"systemPrompt": "System Prompt",
"systemPromptPlaceholder": "You are a helpful assistant...",
"temperature": "Temperature",
diff --git a/core/http/react-ui/src/pages/Chat.jsx b/core/http/react-ui/src/pages/Chat.jsx
index 5866a2514273..d799efba0a57 100644
--- a/core/http/react-ui/src/pages/Chat.jsx
+++ b/core/http/react-ui/src/pages/Chat.jsx
@@ -21,6 +21,8 @@ import { useOperations } from '../hooks/useOperations'
import { relativeTime } from '../utils/format'
import { copyToClipboard } from '../utils/clipboard'
+const FOCUS_MODE_KEY = 'localai_chat_focus_mode'
+
function getLastMessagePreview(chat) {
if (!chat.history || chat.history.length === 0) return ''
for (let i = chat.history.length - 1; i >= 0; i--) {
@@ -405,12 +407,20 @@ export default function Chat() {
// Focus mode: once a conversation has at least one message we slim the
// surrounding chrome (collapse the global app rail, fade non-essential
// header items). Esc gives the user back the full chrome for the rest of
- // this session.
+ // this session. The settings drawer offers a persistent opt-out.
const isInConversation = (activeChat?.history?.length || 0) > 0
const [focusOverride, setFocusOverride] = useState(false)
- const focusActive = isInConversation && !focusOverride
+ const [focusModeEnabled, setFocusModeEnabled] = useState(() => {
+ try { return localStorage.getItem(FOCUS_MODE_KEY) !== 'false' } catch (_) { return true }
+ })
+ const focusActive = focusModeEnabled && isInConversation && !focusOverride
const prevAppCollapseRef = useRef(null)
+ const toggleFocusMode = (next) => {
+ setFocusModeEnabled(next)
+ try { localStorage.setItem(FOCUS_MODE_KEY, String(next)) } catch (_) {}
+ }
+
const artifacts = useMemo(
() => canvasMode ? extractCodeArtifacts(activeChat?.history, 'role', 'assistant') : [],
[activeChat?.history, canvasMode]
@@ -1110,6 +1120,20 @@ export default function Chat() {
/>
)}
+
+
+
+ {t('settings.focusMode')}
+
+
+ {t('settings.focusModeDesc')}
+
+
+
+