From 1dc46d869b49aaeba2bd28d03f83ac5591448cec Mon Sep 17 00:00:00 2001 From: Alex Netsch Date: Wed, 15 Oct 2025 17:27:25 +0100 Subject: [PATCH] Close settings X (vibe-kanban) (#1012) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Excellent! All changes have been successfully implemented. Here's a summary of what was done: ## Changes Made ### 1. **Updated SettingsLayout.tsx** (`frontend/src/pages/settings/SettingsLayout.tsx:33-46`) - Changed import from `ArrowLeft` to `X` icon from lucide-react - Moved the close button from the left side to the right side within a flex container - Replaced the "Back to app" button with an icon-only X button - Applied consistent styling matching the dialog component pattern (opacity, hover effects, focus ring) - Added screen reader text "Close" for accessibility ### 2. **Removed unused translation keys** from all locale files: - `frontend/src/i18n/locales/en/settings.json` - `frontend/src/i18n/locales/es/settings.json` - `frontend/src/i18n/locales/ja/settings.json` - `frontend/src/i18n/locales/ko/settings.json` Removed the `"backToApp"` key since it's no longer needed. The settings page now has an X button in the top right corner (next to the "Settings" title) instead of a "Back to app" button in the top left, matching the standard UX pattern used throughout the application. * Perfect! I've successfully moved the X button to the absolute top right of the settings page. Here's what changed: ## Changes Made **Updated SettingsLayout.tsx** (`frontend/src/pages/settings/SettingsLayout.tsx:28-44`) 1. Added `relative` positioning to the main container div 2. Moved the X button outside of the sidebar, placing it as an absolutely positioned element at `top-4 right-4` 3. Simplified the sidebar header - the "Settings" title now stands alone without the flex container 4. The X button now appears in the top right corner of the entire settings page, independent of the sidebar layout The X button is now positioned at the absolute top right of the settings page container, exactly where you'd expect a close button to be in most applications! * Perfect! I've made the adjustment to move the X button to the absolute top right of the settings page. Here's what I changed: ## Changes Made **Updated SettingsLayout.tsx** (`frontend/src/pages/settings/SettingsLayout.tsx:29-37`) 1. Changed `top-4` to `top-0` - This positions the button at the very top edge of the container, right below the navbar 2. Added `z-10` - Ensures the button appears above other content and doesn't get hidden The X button is now positioned at the absolute top right corner of the settings page container (just below the navbar), which should provide better visual separation from the hamburger menu and look cleaner overall. The button will be at the top edge of the settings content area without the extra spacing that was causing the cramped appearance. * I've adjusted the X button positioning from `top-0` to `top-2`, which adds 0.5rem (8px) of spacing. This should create a bit more breathing room between the navbar hamburger menu and the X button. However, looking at the screenshot you shared, it seems like we may need even more spacing. If this still looks too cramped, we could increase it to `top-4` (16px), `top-6` (24px), or even `top-8` (32px) to match the vertical padding of the container. Could you check if this looks better? If it still needs more spacing, let me know and I can adjust it further. * Revert "I've adjusted the X button positioning from `top-0` to `top-2`, which adds 0.5rem (8px) of spacing. This should create a bit more breathing room between the navbar hamburger menu and the X button." This reverts commit e2d5617562e23edbfb25d7514f5a8758ba501eb1. * Perfect! I've adjusted the X button positioning from `right-4` to `right-3` to match the navbar's `px-3` padding. ## Changes Made **Updated SettingsLayout.tsx** (`frontend/src/pages/settings/SettingsLayout.tsx:33`) Changed the X button's horizontal positioning from `right-4` (16px) to `right-3` (12px) to match the navbar's padding, ensuring the X button is now vertically aligned with the hamburger menu icon above it. The X button should now be perfectly aligned with the hamburger menu in the navbar! Both icons are now 12px from the right edge of their respective containers. * Perfect! I've successfully fixed the i18n regression. Here's a summary of what was done: ## Changes Made ### 1. Added "close" translation to all locale files **en/common.json**: Added `"close": "Close"` **es/common.json**: Added `"close": "Cerrar"` **ja/common.json**: Added `"close": "閉じる"` **ko/common.json**: Added `"close": "닫기"` All added to the `buttons` section to maintain consistency with other button translations. ### 2. Updated SettingsLayout.tsx (`frontend/src/pages/settings/SettingsLayout.tsx:25,37`) - Added a second translation hook: `const { t: tCommon } = useTranslation('common');` - Changed the hardcoded text from `Close` to `{tCommon('buttons.close')}` Now the close button's accessibility label will be properly translated based on the user's language preference, maintaining consistency with the rest of the application's i18n implementation! * new settings close button (vibe-kanban) (#1018) adds an esc button to settings in a new sticky header * Lint --------- Co-authored-by: Britannio Jarrett Co-authored-by: Britannio Jarrett <33752528+britannio@users.noreply.github.com> --- frontend/src/i18n/locales/en/common.json | 3 +- frontend/src/i18n/locales/en/settings.json | 3 +- frontend/src/i18n/locales/es/common.json | 3 +- frontend/src/i18n/locales/es/settings.json | 3 +- frontend/src/i18n/locales/ja/common.json | 3 +- frontend/src/i18n/locales/ja/settings.json | 3 +- frontend/src/i18n/locales/ko/common.json | 3 +- frontend/src/i18n/locales/ko/settings.json | 3 +- frontend/src/keyboard/registry.ts | 8 ++++ .../src/pages/settings/SettingsLayout.tsx | 43 ++++++++++++++----- 10 files changed, 53 insertions(+), 22 deletions(-) diff --git a/frontend/src/i18n/locales/en/common.json b/frontend/src/i18n/locales/en/common.json index 41c936d8..b5745952 100644 --- a/frontend/src/i18n/locales/en/common.json +++ b/frontend/src/i18n/locales/en/common.json @@ -10,7 +10,8 @@ "reset": "Reset", "manage": "Manage", "connect": "Connect", - "disconnect": "Disconnect" + "disconnect": "Disconnect", + "close": "Close" }, "states": { "loading": "Loading...", diff --git a/frontend/src/i18n/locales/en/settings.json b/frontend/src/i18n/locales/en/settings.json index 6753c50f..30b0e904 100644 --- a/frontend/src/i18n/locales/en/settings.json +++ b/frontend/src/i18n/locales/en/settings.json @@ -8,8 +8,7 @@ "agents": "Agents", "agentsDesc": "Coding agent configurations", "mcp": "MCP Servers", - "mcpDesc": "Model Context Protocol servers", - "backToApp": "Back to app" + "mcpDesc": "Model Context Protocol servers" } }, "general": { diff --git a/frontend/src/i18n/locales/es/common.json b/frontend/src/i18n/locales/es/common.json index 68b2f233..559afa6f 100644 --- a/frontend/src/i18n/locales/es/common.json +++ b/frontend/src/i18n/locales/es/common.json @@ -10,7 +10,8 @@ "reset": "Restablecer", "manage": "Gestionar", "connect": "Conectar", - "disconnect": "Desconectar" + "disconnect": "Desconectar", + "close": "Cerrar" }, "states": { "loading": "Cargando...", diff --git a/frontend/src/i18n/locales/es/settings.json b/frontend/src/i18n/locales/es/settings.json index f6cc62e3..116c412d 100644 --- a/frontend/src/i18n/locales/es/settings.json +++ b/frontend/src/i18n/locales/es/settings.json @@ -8,8 +8,7 @@ "agents": "Agentes", "agentsDesc": "Configuraciones de agentes", "mcp": "Servidores MCP", - "mcpDesc": "Servidores de Protocolo de Contexto de Modelo (MCP)", - "backToApp": "Volver a la app" + "mcpDesc": "Servidores de Protocolo de Contexto de Modelo (MCP)" } }, "general": { diff --git a/frontend/src/i18n/locales/ja/common.json b/frontend/src/i18n/locales/ja/common.json index a5d7f180..0c6955ac 100644 --- a/frontend/src/i18n/locales/ja/common.json +++ b/frontend/src/i18n/locales/ja/common.json @@ -10,7 +10,8 @@ "reset": "リセット", "manage": "管理", "connect": "接続", - "disconnect": "切断" + "disconnect": "切断", + "close": "閉じる" }, "states": { "loading": "読み込み中...", diff --git a/frontend/src/i18n/locales/ja/settings.json b/frontend/src/i18n/locales/ja/settings.json index 68e249dd..2989df61 100644 --- a/frontend/src/i18n/locales/ja/settings.json +++ b/frontend/src/i18n/locales/ja/settings.json @@ -8,8 +8,7 @@ "agents": "エージェント", "agentsDesc": "コーディングエージェントの設定", "mcp": "MCPサーバー", - "mcpDesc": "モデルコンテキストプロトコルサーバー", - "backToApp": "アプリに戻る" + "mcpDesc": "モデルコンテキストプロトコルサーバー" } }, "general": { diff --git a/frontend/src/i18n/locales/ko/common.json b/frontend/src/i18n/locales/ko/common.json index a994d897..6cff3a49 100644 --- a/frontend/src/i18n/locales/ko/common.json +++ b/frontend/src/i18n/locales/ko/common.json @@ -10,7 +10,8 @@ "reset": "초기화", "manage": "관리", "connect": "연결", - "disconnect": "연결 해제" + "disconnect": "연결 해제", + "close": "닫기" }, "states": { "loading": "로딩 중...", diff --git a/frontend/src/i18n/locales/ko/settings.json b/frontend/src/i18n/locales/ko/settings.json index 2bb27698..896d19bb 100644 --- a/frontend/src/i18n/locales/ko/settings.json +++ b/frontend/src/i18n/locales/ko/settings.json @@ -8,8 +8,7 @@ "agents": "에이전트", "agentsDesc": "코딩 에이전트 구성", "mcp": "MCP 서버", - "mcpDesc": "Model Context Protocol 서버", - "backToApp": "앱으로 돌아가기" + "mcpDesc": "Model Context Protocol 서버" } }, "general": { diff --git a/frontend/src/keyboard/registry.ts b/frontend/src/keyboard/registry.ts index a8161ebc..42936230 100644 --- a/frontend/src/keyboard/registry.ts +++ b/frontend/src/keyboard/registry.ts @@ -3,6 +3,7 @@ export enum Scope { DIALOG = 'dialog', KANBAN = 'kanban', PROJECTS = 'projects', + SETTINGS = 'settings', EDIT_COMMENT = 'edit-comment', APPROVALS = 'approvals', FOLLOW_UP = 'follow-up', @@ -62,6 +63,13 @@ export const keyBindings: KeyBinding[] = [ description: 'Cancel comment', group: 'Comments', }, + { + action: Action.EXIT, + keys: 'esc', + scopes: [Scope.SETTINGS], + description: 'Close settings', + group: 'Navigation', + }, // Creation actions { diff --git a/frontend/src/pages/settings/SettingsLayout.tsx b/frontend/src/pages/settings/SettingsLayout.tsx index 7d9fc2d0..79153dd6 100644 --- a/frontend/src/pages/settings/SettingsLayout.tsx +++ b/frontend/src/pages/settings/SettingsLayout.tsx @@ -1,9 +1,13 @@ import { NavLink, Outlet } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { Settings, Cpu, Server, ArrowLeft } from 'lucide-react'; +import { Settings, Cpu, Server, X } from 'lucide-react'; import { cn } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { usePreviousPath } from '@/hooks/usePreviousPath'; +import { useEffect } from 'react'; +import { useHotkeysContext } from 'react-hotkeys-hook'; +import { useKeyExit } from '@/keyboard/hooks'; +import { Scope } from '@/keyboard/registry'; const settingsNavigation = [ { @@ -23,20 +27,39 @@ const settingsNavigation = [ export function SettingsLayout() { const { t } = useTranslation('settings'); const goToPreviousPath = usePreviousPath(); + const { enableScope, disableScope } = useHotkeysContext(); + + // Enable SETTINGS scope when component mounts + useEffect(() => { + enableScope(Scope.SETTINGS); + return () => { + disableScope(Scope.SETTINGS); + }; + }, [enableScope, disableScope]); + + // Register ESC keyboard shortcut + useKeyExit(goToPreviousPath, { scope: Scope.SETTINGS }); return ( -
+
+ {/* Header with title and close button */} +
+

+ {t('settings.layout.nav.title')} +

+ +
{/* Sidebar Navigation */} -