feat: redesign settings pages to match canonical flat UI patterns (#493)

* refactor(settings): new IA shell + projects section + skills catalog discoverability

* chore(settings): split providers list by scope; show user before project

* fix: navigation flow in mobile Settings

* feat: redesign settings pages to use modern elevated surface patterns

* feat: replace helper text with tooltips in settings

* ui: redesign update dialog and fix external link routing

- Restructures UpdateDialog to focus on changelog readability with a wider max-w-4xl canvas
- Highlights @username contributor mentions with theme primary color
- Strips excessive vertical padding and right-aligns compact action buttons
- Disables streamdown's internal link safety dialog in favor of direct Tauri shell routing

* feat: refactor Git identities into dedicated Git settings page

* feat: unify sidebar background styling across VS Code and web/mobile

* fix: adjust button styling and layout for mobile settings pages

* feat: add MCP settings page and sidebar

* feat: hide models in provider view (thanks to @nguyenngothuong)

* feat: add "Add new provider" option to model selector dropdown

* fix: local evroc logo + provider dropdown icons

* fix: increase width of provider menu

* fix: dark theme background color for better contrast

* feat: update @opencode-ai/sdk dependency to v1.2.10

* fix: restore session sorting to only use updated time

* fix: added settings for sessions deletion dialog

* fix: adjust padding on settings pages for better layout

* fix: standardize select dropdown height across UI

* fix: agent selector UI and notification settings

* fix: remove redundant helper text from settings pages

* fix: update UI layout for description fields

* fix: remove border-none and shadow-none from textarea classes

* fix: enable context menu on sidebar items

* feat: refactor UI controls and layout patterns across settings pages

* fix: use headerless blocks when page title already provides context

* fix: remove subtask option from command settings

* fix: refactor mcp page settings

* fix: reduce spacing in skills configuration pages

* feat: refactor voice settings

* feat: refactor settings sidebar sections
This commit is contained in:
Bohdan Triapitsyn
2026-02-24 03:28:30 +02:00
committed by GitHub
parent d2d39c48ac
commit d2358c2c03
90 changed files with 8062 additions and 7128 deletions
+17 -18
View File
@@ -3,8 +3,8 @@ import { useSessionStore } from '@/stores/useSessionStore';
import { useUIStore } from '@/stores/useUIStore';
import { parseRoute, updateBrowserURL, hasRouteParams } from '@/lib/router';
import type { RouteState, AppRouteState } from '@/lib/router';
import type { SidebarSection } from '@/constants/sidebar';
import type { MainTab } from '@/stores/useUIStore';
import { resolveSettingsSlug } from '@/lib/settings/metadata';
/**
* Check if running in VS Code webview context.
@@ -41,7 +41,7 @@ export function useRouter(): void {
const setCurrentSession = useSessionStore((state) => state.setCurrentSession);
const setActiveMainTab = useUIStore((state) => state.setActiveMainTab);
const setSettingsDialogOpen = useUIStore((state) => state.setSettingsDialogOpen);
const setSidebarSection = useUIStore((state) => state.setSidebarSection);
const setSettingsPage = useUIStore((state) => state.setSettingsPage);
const navigateToDiff = useUIStore((state) => state.navigateToDiff);
/**
@@ -65,8 +65,8 @@ export function useRouter(): void {
}
// 2. Handle settings (takes precedence over tabs - it's a full-screen overlay)
if (route.settingsSection) {
setSidebarSection(route.settingsSection);
if (route.settingsPath) {
setSettingsPage(resolveSettingsSlug(route.settingsPath));
setSettingsDialogOpen(true);
// Don't process tab when settings is open
return;
@@ -90,7 +90,7 @@ export function useRouter(): void {
isApplyingRouteRef.current = false;
}
},
[setCurrentSession, setActiveMainTab, setSettingsDialogOpen, setSidebarSection, navigateToDiff]
[setCurrentSession, setActiveMainTab, setSettingsDialogOpen, setSettingsPage, navigateToDiff]
);
/**
@@ -104,7 +104,7 @@ export function useRouter(): void {
sessionId: sessionState.currentSessionId,
tab: uiState.activeMainTab,
isSettingsOpen: uiState.isSettingsDialogOpen,
settingsSection: uiState.sidebarSection,
settingsPath: uiState.settingsPage,
diffFile: uiState.pendingDiffFile,
};
}, []);
@@ -183,7 +183,7 @@ export function useRouter(): void {
let prevTab: MainTab = useUIStore.getState().activeMainTab;
let prevSettingsOpen: boolean = useUIStore.getState().isSettingsDialogOpen;
let prevSettingsSection: SidebarSection = useUIStore.getState().sidebarSection;
let prevSettingsPath: string = useUIStore.getState().settingsPage;
let prevDiffFile: string | null = useUIStore.getState().pendingDiffFile;
const unsubscribe = useUIStore.subscribe((state) => {
@@ -194,17 +194,17 @@ export function useRouter(): void {
const tabChanged = state.activeMainTab !== prevTab;
const settingsOpenChanged = state.isSettingsDialogOpen !== prevSettingsOpen;
const settingsSectionChanged = state.sidebarSection !== prevSettingsSection;
const settingsPathChanged = state.settingsPage !== prevSettingsPath;
const diffFileChanged = state.pendingDiffFile !== prevDiffFile && state.activeMainTab === 'diff';
// Update tracking vars
prevTab = state.activeMainTab;
prevSettingsOpen = state.isSettingsDialogOpen;
prevSettingsSection = state.sidebarSection;
prevSettingsPath = state.settingsPage;
prevDiffFile = state.pendingDiffFile;
// Only sync if something relevant changed
if (tabChanged || settingsOpenChanged || settingsSectionChanged || diffFileChanged) {
if (tabChanged || settingsOpenChanged || settingsPathChanged || diffFileChanged) {
syncURLFromState();
}
});
@@ -263,8 +263,8 @@ export function navigateToRoute(route: Partial<RouteState>): void {
if (route.sessionId) {
void useSessionStore.getState().setCurrentSession(route.sessionId);
}
if (route.settingsSection) {
useUIStore.getState().setSidebarSection(route.settingsSection);
if (route.settingsPath) {
useUIStore.getState().setSettingsPage(resolveSettingsSlug(route.settingsPath));
useUIStore.getState().setSettingsDialogOpen(true);
} else if (route.tab) {
useUIStore.getState().setActiveMainTab(route.tab);
@@ -281,8 +281,8 @@ export function navigateToRoute(route: Partial<RouteState>): void {
if (route.sessionId) {
params.set('session', route.sessionId);
}
if (route.settingsSection) {
params.set('settings', route.settingsSection);
if (route.settingsPath) {
params.set('settings', route.settingsPath);
} else if (route.tab && route.tab !== 'chat') {
if (useUIStore.getState().isSettingsDialogOpen) {
useUIStore.getState().setSettingsDialogOpen(false);
@@ -302,8 +302,8 @@ export function navigateToRoute(route: Partial<RouteState>): void {
if (route.sessionId) {
void useSessionStore.getState().setCurrentSession(route.sessionId);
}
if (route.settingsSection) {
useUIStore.getState().setSidebarSection(route.settingsSection);
if (route.settingsPath) {
useUIStore.getState().setSettingsPage(resolveSettingsSlug(route.settingsPath));
useUIStore.getState().setSettingsDialogOpen(true);
} else if (route.tab) {
useUIStore.getState().setActiveMainTab(route.tab);
@@ -331,8 +331,7 @@ export function getShareableURL(): string {
}
if (uiState.isSettingsDialogOpen) {
const settingsSection = uiState.sidebarSection === 'sessions' ? 'settings' : uiState.sidebarSection;
params.set('settings', settingsSection);
params.set('settings', uiState.settingsPage || 'home');
} else if (uiState.activeMainTab !== 'chat') {
params.set('tab', uiState.activeMainTab);
}