- Add edit mode button next to settings in header
- Edit button turns blue when active
- Drag handles fade in/out with edit mode toggle
- Add smooth 200ms transition animation
- Add i18n support for edit mode (en/zh)
- Maintain consistent spacing between header elements
- Convert edit and usage buttons to icon-only ghost variant for cleaner appearance
- Reduce action button padding (px-2) and group spacing (gap-0) for more compact layout
- Add red hover effect to delete icon for better visual feedback
- Vertically center action buttons with provider info on desktop view
- Simplify provider URL link by removing icon and using soft blue color (blue-400/300)
- Reduce enable button width from 96px to 80px for better proportions
- Add dynamic hint text based on provider category (official, opensource, aggregator, third-party, custom)
- Display hints in ProviderPresetSelector below preset buttons
- Rename "Chinese official" to "Opensource official" for better clarity
- Add i18n keys for all category hints in both zh and en locales
- Remove redundant hint boxes from ClaudeFormFields and CodexFormFields
This improves user guidance by showing contextual hints that explain
what fields are required for each provider category.
Adjusted Add and Edit provider dialogs to use consistent sizing with MCP panel:
- Increased max width from max-w-2xl to max-w-3xl
- Unified max height to max-h-[85vh] (was 90vh)
- Added min-h-[600px] for minimum height constraint
This ensures visual consistency across all major dialog panels in the app.
- Add missing translation keys for all hint texts and descriptions
- Remove all hardcoded defaultValue parameters from components
- Add translations for window behavior, directory settings, and theme settings
- Add translations for provider-related UI elements
- Improve consistency across Chinese and English translations
Translation additions:
- common.toggleTheme
- settings.windowBehaviorHint, claudeConfigDirDescription, codexConfigDirDescription
- provider.* (12 new keys)
- providerForm.* (15 new keys)
- providerPreset.* (4 new keys)
Modified files: 10
Lines changed: +132 -74
Remove size="sm" from MCP panel buttons to use default text-sm instead of text-xs, ensuring visual consistency with buttons throughout the application.
Fix multiple alignment and spacing issues in dialog components to ensure
proper visual balance and symmetry across all dialog elements.
Changes to DialogHeader:
- Change padding from pt-6 pb-4 to py-5 for symmetric vertical spacing
- Ensures header content is equidistant from top and bottom borders
Changes to DialogFooter:
- Change padding from pt-4 pb-6 to py-5 for symmetric vertical spacing
- Replace sm:space-x-2 with gap-2 for consistent button spacing at all breakpoints
- Add sm:items-center to vertically center buttons in horizontal layout
- Ensures footer buttons align properly and are equidistant from borders
Changes to DialogTitle:
- Change line-height from leading-none to leading-tight (1 → 1.25)
- Provides better visual balance with button heights
- Improves readability and alignment with adjacent buttons
Impact:
All dialog components now have:
- Symmetric vertical padding (1.25rem top/bottom)
- Properly centered content regardless of viewport size
- Consistent button spacing and alignment
- Better visual harmony between text and interactive elements
Enhance visual consistency across MCP dialogs with better spacing
and appropriate icons for add/edit actions.
Changes:
- McpFormModal: Use Plus icon for "Add" button, Save icon for "Edit" button
- McpPanel: Balance spacing around server info line (py-4 for info section,
pb-4 for content area) to create equal visual weight between header and
server list
The MCP panel now has consistent vertical rhythm with 1rem spacing above
and below the server count info line.
Add visual indicators to the Add and Save buttons in provider dialogs
for improved UX and consistency with other dialogs.
Changes:
- AddProviderDialog: Add Plus icon to "Add" button
- EditProviderDialog: Add Save icon to "Save" button
Both dialogs now have clear visual affordances for primary actions,
matching the icon usage pattern in other modal dialogs throughout
the application.
Restructure AddProviderDialog and EditProviderDialog to follow the
standardized dialog layout pattern with buttons in DialogFooter.
Changes:
- Add DialogFooter to AddProviderDialog and EditProviderDialog
- Add `showButtons` prop to ProviderForm (default: true for backward compatibility)
- Add `id="provider-form"` to form element for external form submission
- Move Cancel and Submit buttons from ProviderForm to DialogFooter
- Use `form="provider-form"` attribute on DialogFooter buttons to trigger submission
Benefits:
- Consistent dialog footer appearance across all dialogs
- Proper spacing and alignment with other modal dialogs
- Better visual hierarchy with separated content and action areas
- Maintains backward compatibility for ProviderForm usage elsewhere
All provider dialogs now follow the unified pattern:
- DialogHeader: Title and description
- Content area: flex-1 overflow-y-auto px-6 py-4
- DialogFooter: Action buttons with standard styling
Remove custom styling from DialogFooter components across the application
to ensure consistent appearance and behavior. All dialogs now follow the
unified layout pattern defined in the base Dialog component.
Changes:
- Remove custom className overrides from DialogFooter in:
- EndpointSpeedTest.tsx
- CodexQuickWizardModal.tsx
- CodexCommonConfigModal.tsx
- ClaudeConfigEditor.tsx
- Fix McpWizardModal content area padding (remove -mx-6 negative margin)
- Fix McpPanel to use DialogFooter component instead of custom div
All dialogs now consistently use:
- DialogHeader: px-6 pt-6 pb-4 with border and background (built-in)
- Content area: flex-1 overflow-y-auto px-6 py-4
- DialogFooter: px-6 pb-6 pt-4 with border and background (built-in)
This ensures proper spacing, alignment, and visual consistency across
all modal dialogs in the application.
Fix two UX issues in the settings dialog:
1. Check for Updates button width stability
- Added min-w-[140px] to prevent layout shift during state changes
- Button maintains consistent width across all states:
* "Check for Updates" (idle)
* "Checking..." (with spinner)
* "Update to vX.X.X" (with download icon)
* "Installing..." (with spinner)
2. Settings dialog scrollbar behavior
- Changed overflow-y-scroll to overflow-y-auto
- Scrollbar now only appears when content actually overflows
- Prevents unnecessary scrollbar on About tab (content < 400px)
- Maintains min-h-[400px] on all tabs to prevent dialog height jump
These changes improve visual stability and reduce UI clutter while
maintaining consistent dialog dimensions during tab switching.
Move the theme toggle from the main header to the settings dialog for a
cleaner UI and better organization. The new theme selector uses a
button group design consistent with the language settings.
Changes:
- Created ThemeSettings component with three options: Light, Dark, System
- Added ThemeSettings to the General tab in settings dialog
- Removed ModeToggle component from main header
- Added theme-related i18n keys for all options
- Theme selection takes effect immediately without requiring save
Design:
- Uses button group style matching LanguageSettings
- Icons for each theme option (Sun, Moon, Monitor)
- Consistent with app's blue theme for active state
- Smooth transitions and hover effects
This change simplifies the main header and consolidates all appearance
settings in one place, improving the overall user experience.
Remove the config file location display from settings dialog to simplify
the user interface. Users who need to access the config file can still do
so through the advanced settings section.
Changes:
- Removed ConfigPathDisplay component and its usage
- Removed configPath and openConfigFolder from useSettings hook
- Removed configPath and openConfigFolder from useSettingsMetadata hook
- Removed related i18n keys: configFileLocation, openFolder
- Updated settings dialog to remove the config path display section
This simplifies the settings UI while maintaining access to config
directory management through the advanced settings tab.
Improve the visual hierarchy and interaction feedback in the settings dialog:
1. Tab navigation enhancement:
- Active tabs now use blue background (blue-500/600) with white text
- Add shadow effect to active tabs for better depth perception
- Inactive tabs show hover effects (opacity + background)
- Consistent with app's primary blue theme color
2. Switch component visual improvement:
- Checked state: blue background (blue-500/600) for clear indication
- Unchecked state: gray background (gray-300/700) for neutral appearance
- White thumb color for better contrast on both states
- Enhanced focus ring (ring-2 + offset-2) for accessibility
3. Layout spacing refinement:
- Change content area padding from pb-4 to py-4 for symmetrical spacing
- Ensure consistent 4-unit spacing between all dialog sections
4. Clarify plugin integration description:
- Update description to accurately reflect that provider switching
in this app will sync with VS Code Claude Code extension
- Previous wording was ambiguous about the synchronization behavior
Files changed:
- src/components/ui/tabs.tsx: Enhanced tab visual states
- src/components/ui/switch.tsx: Improved switch contrast
- src/components/settings/SettingsDialog.tsx: Fixed spacing
- src/i18n/locales/{zh,en}.json: Updated plugin description
This commit refines the visual hierarchy and fixes layout issues in the
settings dialog:
1. Add visual separators to dialog sections:
- Add bottom border and background to DialogHeader
- Both header and footer now have consistent border + bg-muted/20 styling
- Creates clear three-section layout: header | content | footer
2. Fix footer overflow issue:
- Remove min-h-[480px] from content area that conflicted with max-h-[90vh]
- Keep min-h-[400px] on TabsContent to prevent height jumps
- Add flex-shrink-0 to header and footer to ensure they stay visible
- Content area uses flex-1 to fill remaining space naturally
3. Improve spacing:
- Add pb-4 to content area for breathing room above footer
- Add pb-4 to DialogHeader for consistent spacing below title
- Ensure proper padding hierarchy across all dialog sections
Layout calculation (small screens, 90vh ≈ 540px):
- Header: ~70px (fixed)
- Content: 400px minimum, scrollable (flexible)
- Footer: ~70px (fixed)
- Total: ≤ 540px, footer always visible ✓
Files modified:
- src/components/ui/dialog.tsx (DialogHeader, DialogFooter styling)
- src/components/settings/SettingsDialog.tsx (content area height constraint)
Fixed multiple layout issues in the settings dialog:
1. Dialog structure: Changed from grid to flexbox layout
- Removed global padding from DialogContent
- Added individual padding to DialogHeader (px-6 pt-6) and DialogFooter (px-6 pb-6 pt-4)
- Added max-h-[90vh] constraint to prevent dialog from exceeding viewport
2. Content area improvements:
- Replaced max-h-[70vh] with flex-1 for better space utilization
- Set min-h-[480px] on content wrapper to maintain consistent dialog height
- Applied min-h-[400px] to all TabsContent components to prevent height jumps
3. Scrollbar optimization:
- Changed overflow-y-auto to overflow-y-scroll to force scrollbar gutter
- Eliminates horizontal shift when switching between tabs with different content heights
- Consistent with main app layout approach (App.tsx)
4. Footer enhancement:
- Added border-t and bg-muted/20 for visual separation
- Fixed footer overlapping content in advanced tab
Result: Settings dialog now displays all content properly without requiring
fullscreen, maintains consistent height across tabs, and eliminates layout shift
when switching tabs.
Fixed dual-source jitter issue:
1. Horizontal shift: Use overflow-y-scroll to force scrollbar gutter
2. Vertical jump: Use keepPreviousData to maintain content during app switch
Fix inconsistent modal overlays by migrating all custom implementations
to the unified shadcn/ui Dialog component with proper z-index layering.
Changes:
- Update Dialog component to support three z-index levels:
- base (z-40): First-level dialogs
- nested (z-50): Nested dialogs
- alert (z-[60]): Alert/confirmation dialogs (using Tailwind arbitrary value)
- Refactor all custom modal implementations to use Dialog:
- EndpointSpeedTest: API endpoint speed testing panel
- ClaudeConfigEditor: Claude common config editor
- CodexQuickWizardModal: Codex quick setup wizard
- CodexCommonConfigModal: Codex common config editor
- SettingsDialog: Restart confirmation prompt
- Remove custom backdrop implementations and manual z-index
- Leverage Radix UI Portal for automatic DOM order management
- Ensure consistent overlay behavior and keyboard interactions
This eliminates the "background residue" issue where overlays from
different layers would conflict, providing a unified and professional
user experience across all modal interactions.
Introduce `closeAfterSave` callback to distinguish between save-and-close and cancel-and-close scenarios. Previously, saving settings would trigger `resetSettings()`, causing language changes to revert and requiring users to save twice for the change to take effect.
Changes:
- Add `closeAfterSave()`: close dialog without resetting settings after successful save
- Keep `closeDialog()`: reset settings when canceling or directly closing dialog
- Update save flow to use `closeAfterSave()` in `handleSaveClick`, `handleRestartLater`, and `handleRestartNow`
Fixed an issue where clicking the language switcher would cause a brief flash
and fail to persist the language change. The root cause was a dependency cycle
in useSettingsForm where readPersistedLanguage depended on i18n.language,
causing the initialization effect to re-run and reset state whenever the
language changed.
Changed the dependency from [i18n.language] to [i18n] since the i18n object
itself is stable and doesn't change when the language changes, while the
function can still access the current language value via closure.
Before optimization:
- McpPanel.tsx: 298 lines (component + business logic)
After optimization:
- McpPanel.tsx: 234 lines (-21%, UI focused)
- useMcpActions.ts: 137 lines (business logic)
Benefits:
✅ Separation of concerns: UI vs business logic
✅ Reusability: MCP operations can be used in other components
✅ Testability: business logic can be tested independently
✅ Consistency: follows same pattern as useProviderActions
✅ Optimistic updates: toggle enabled status with rollback on error
✅ Unified error handling: all MCP errors use toast notifications
Technical details:
- Extract reload, toggleEnabled, saveServer, deleteServer
- Implement optimistic UI updates for toggle
- Centralize error handling and toast messages
- Remove duplicate error handling code from component
Before optimization:
- useSettings.ts: 516 lines (single monolithic hook)
After optimization:
- useSettingsForm.ts: 158 lines (form state management)
- useDirectorySettings.ts: 297 lines (directory management)
- useSettingsMetadata.ts: 95 lines (metadata management)
- useSettings.ts: 215 lines (composition layer)
- Total: 765 lines (+249 lines, but with clear separation of concerns)
Benefits:
✅ Single Responsibility Principle: each hook focuses on one domain
✅ Testability: independent hooks are easier to unit test
✅ Reusability: specialized hooks can be reused in other components
✅ Maintainability: reduced cognitive load per file
✅ Zero breaking changes: SettingsDialog auto-adapted to new interface
Technical details:
- useSettingsForm: pure form state + language sync
- useDirectorySettings: directory selection/reset + default value computation
- useSettingsMetadata: config path + portable mode + restart flag
- useSettings: composition layer + save logic + reset logic
- Remove unused useDarkMode hook (now using shadcn theme-provider)
- Clean up MCP components (remove redundant code)
- Add restart API to settings
- Minor type improvements
Extract all MCP form validation logic into a reusable custom hook to
improve code organization and enable reuse across components.
Changes:
- Create useMcpValidation hook with 4 validation functions:
* validateJson: basic JSON structure validation
* formatTomlError: unified TOML error formatting with i18n
* validateTomlConfig: complete TOML validation with required fields
* validateJsonConfig: complete JSON validation with structure checks
- Update McpFormModal to use the hook instead of inline validation
- Simplify validation calls throughout the component
- Reduce code duplication while maintaining all functionality
Benefits:
- Validation logic can be reused in other MCP-related components
- Easier to test validation in isolation
- Better separation of concerns
- McpFormModal remains at 699 lines (original: 767), kept cohesive
The component stays as one piece since its 700 lines represent a
single, cohesive form feature rather than multiple unrelated concerns.
- Migrate all form components from ProviderForm/ to providers/forms/
- Create shared components to eliminate code duplication:
* ApiKeySection: unified API key input with "Get API Key" link
* EndpointField: unified endpoint URL input with manage button
- Refactor ClaudeFormFields (-31% lines) and CodexFormFields (-33% lines)
- Update all import paths to use new locations
- Reduce code duplication from ~12% to ~7%
This change improves maintainability and makes the codebase more DRY.
- Add smol-toml dependency for client-side TOML parsing
- Create useCodexTomlValidation hook with 500ms debounce
- Display validation errors below config.toml textarea
- Trigger validation on onChange for immediate user feedback
- Backend validation remains as fallback for data integrity
- Remove obsolete TODO comments for Codex Base URL handling
- Codex Base URL is already fully managed by useCodexConfigState hook
- useBaseUrlState is now only used for Claude mode
- Add clarifying comments about the architecture
- Import vscodeApi to access backend test_api_endpoints command
- Replace empty results array with actual API call
- Remove TODO comments for implemented API calls
- Enable all endpoint management features:
- Speed test with latency measurement
- Load custom endpoints from backend
- Add/remove custom endpoints
- Update endpoint last used time
- Fix issue where clicking test button immediately showed failure
- Create useSpeedTestEndpoints hook that collects endpoints from:
1. Current baseUrl/codexBaseUrl
2. Initial data URL (edit mode)
3. Preset's endpointCandidates array
- Pass speedTestEndpoints to ClaudeFormFields and CodexFormFields
- Update EndpointSpeedTest to use collected endpoints instead of just current URL
- Fix PackyCode preset endpoints not appearing in speed test modal
Fixed critical bug where CodexFormFields component was not rendered
in edit mode, preventing users from:
- Viewing and editing API base URL for custom/third-party Codex providers
- Accessing endpoint speed test modal in edit mode
- Updating API keys in edit mode
Changed line 477 from:
{appType === "codex" && !isEditMode && (
To:
{appType === "codex" && (
This aligns Codex behavior with Claude, where all form fields are
available in both create and edit modes for custom/third-party providers.
Fixed logic in useApiKeyState.ts to correctly show API Key input
when editing existing providers. Changed condition from
`!isEditMode && hasApiKeyField(config)` to
`isEditMode && hasApiKeyField(config)` to match the original
form's behavior.
This restores the ability to directly update API keys when
editing existing providers that have API key fields in their
configuration.
- Created ProviderPresetSelector component (80 lines)
- Created BasicFormFields component (60 lines)
- Created ClaudeFormFields component (272 lines)
- Created CodexFormFields component (131 lines)
- Reduced ProviderForm from 866 to 544 lines (37% reduction)
Each component now has a clear single responsibility:
- ProviderPresetSelector: Handles preset selection UI
- BasicFormFields: Name and website URL inputs
- ClaudeFormFields: All Claude-specific form fields
- CodexFormFields: All Codex-specific form fields
- ProviderForm: Orchestrates hooks and component composition
Benefits:
- Better code organization and maintainability
- Easier to test individual components
- Clearer separation of concerns
- More reusable components
- Created useCodexCommonConfig hook for managing Codex TOML common config
- Persists to localStorage with key 'cc-switch:codex-common-config-snippet'
- Added isCodexTemplateModalOpen state to ProviderForm
- Connected all CodexConfigEditor props:
- Common config snippet management (useCommonConfig, handlers)
- Template modal state (isTemplateModalOpen, setIsTemplateModalOpen)
- Form field callbacks (onWebsiteUrlChange, onNameChange)
- Custom mode detection (isCustomMode)
- Hook structure mirrors useCommonConfigSnippet for consistency
- Create useCommonConfigSnippet hook to manage common config state
- Create CommonConfigEditor component with modal for editing
- Support merging/removing common config snippets from provider configs
- Persist common config to localStorage for reuse across providers
- Auto-detect if provider config contains common snippet
- Replace JSON editor with CommonConfigEditor in ProviderForm
- Create useTemplateValues hook to manage template variable state
- Support dynamic placeholder replacement in provider configs
- Add template parameter input UI in provider form
- Validate required template values before submission
- Auto-update config when template values change
- Create useKimiModelSelector hook to manage Kimi-specific state
- Auto-detect Kimi providers by preset name or config content
- Support model initialization from existing config in edit mode
- Sync model selections with JSON configuration
- Maintain clean separation between UI and business logic
- Create useApiKeyLink hook to manage API Key retrieval link display and URL
- Create useCustomEndpoints hook to collect endpoints from multiple sources
- Simplify ProviderForm by using these new hooks
- Reduce code duplication and improve maintainability
- Fix TypeScript error with form.watch("websiteUrl") by providing default empty string
- Add draftCustomEndpoints state to collect custom endpoints from speed test modal
- Import CustomEndpoint type from @/types
- Update handleSubmit to collect and package endpoints into meta.custom_endpoints:
* User-added custom endpoints (from draftCustomEndpoints)
* Preset endpointCandidates (if any)
* Current Base URL (baseUrl/codexBaseUrl)
- Add onCustomEndpointsChange callback to both Claude and Codex EndpointSpeedTest instances
- Extend ProviderFormValues type to include meta.custom_endpoints field
- Only creates meta.custom_endpoints for new providers (not edit mode)
- Deduplicates URLs and creates CustomEndpoint entries with addedAt timestamp
- Add shouldShowClaudeApiKeyLink logic based on provider category
- Add shouldShowCodexApiKeyLink logic for Codex providers
- Add getCurrentClaudeWebsiteUrl() to get website URL with apiKeyUrl priority for third-party providers
- Add getCurrentCodexWebsiteUrl() with same logic for Codex
- Add link UI below API Key input for both Claude and Codex
- Links only show for cn_official, aggregator, and third_party categories
- Preserve original UI styling with -mt-1 pl-1 positioning
- Integrate useModelState hook for managing ANTHROPIC_MODEL and ANTHROPIC_SMALL_FAST_MODEL
- Add two model input fields in responsive grid layout
- Only show for non-official Claude providers
- Include helper text explaining optional nature
- Bidirectional sync between inputs and JSON config
- Integrate useBaseUrlState hook for managing Base URL
- Add Base URL input field for third-party and custom providers
- Add endpoint speed test modal with management button
- Show Base URL section only for non-official providers
- Add Zap icon button to open endpoint speed test modal
- Pass baseUrl to EndpointSpeedTest component
- Add helper text explaining API endpoint usage
All TypeScript type checks pass.
- Create custom hooks for state management:
- useProviderCategory: manages provider category state
- useApiKeyState: manages API key input with auto-sync to config
- useBaseUrlState: manages base URL for Claude and Codex
- useModelState: manages model selection state
- Integrate API key input into simplified ProviderForm:
- Add ApiKeyInput component for Claude mode
- Auto-populate API key into settings config
- Disable for official providers
- Fix EndpointSpeedTest type errors:
- Fix import paths to use @ alias
- Add temporary type definitions
- Format all TODO comments properly
- Remove incorrect type assertions
- Comment out unimplemented window.api checks
All TypeScript type checks now pass.