feat(image): add native-read controls and autosave settings

- add per-profile native image preferences and native-capability detection
- redesign Settings -> Image around compact sections with Web-style autosave
- expose richer backend/profile status and update Gemini Flash defaults
This commit is contained in:
Tam Nhu Tran committed 2026-04-01 15:32:37 -04:00
1 parent 9d1d281e34
commit 982ffc5895
30 files changed
+1893 -708

No files matched your search

@@ -26,7 +26,7 @@ export function TabNavigation({ activeTab, onTabChange }: TabNavigationProps) {
const { t } = useTranslation();
const tabs = [
{ value: 'websearch' as const, label: t('settingsTabs.web'), icon: Globe },
{ value: 'imageanalysis' as const, label: 'Image Analysis', icon: ImageIcon },
{ value: 'image' as const, label: 'Image', icon: ImageIcon },
{ value: 'channels' as const, label: 'Channels', icon: MessageSquare },
{ value: 'globalenv' as const, label: t('settingsTabs.env'), icon: Settings2 },
{ value: 'thinking' as const, label: t('settingsTabs.think'), icon: Brain },
@@ -39,7 +39,7 @@ export function TabNavigation({ activeTab, onTabChange }: TabNavigationProps) {
<Tabs value={activeTab} onValueChange={(v) => onTabChange(v as SettingsTab)}>
<TabsList className="grid w-full grid-cols-8">
{tabs.map(({ value, label, icon: Icon }) => (
<TabsTrigger key={value} value={value} className="gap-1.5 px-1 text-xs">
<TabsTrigger key={value} value={value} className="gap-1.5 px-2 text-xs">
<Icon className="h-3.5 w-3.5 shrink-0" />
<span className="truncate">{label}</span>
</TabsTrigger>
@@ -11,8 +11,8 @@ export function useSettingsTab() {
// Normalize to lowercase for case-insensitive matching (fixes ?tab=Backups vs ?tab=backups)
const tabParam = searchParams.get('tab')?.toLowerCase();
const activeTab: SettingsTab =
tabParam === 'imageanalysis'
? 'imageanalysis'
tabParam === 'imageanalysis' || tabParam === 'image'
? 'image'
: tabParam === 'channels'
? 'channels'
: tabParam === 'globalenv'
+4 -4
View File
@@ -132,7 +132,7 @@ function SettingsPageInner() {
<SectionErrorBoundary>
<Suspense fallback={<SectionSkeleton />}>
{activeTab === 'websearch' && <WebSearchSection />}
{activeTab === 'imageanalysis' && <ImageAnalysisSection />}
{activeTab === 'image' && <ImageAnalysisSection />}
{activeTab === 'channels' && <ChannelsSection />}
{activeTab === 'globalenv' && <GlobalEnvSection />}
{activeTab === 'thinking' && <ThinkingSection />}
@@ -146,7 +146,7 @@ function SettingsPageInner() {
{/* Desktop View - Side-by-side panels */}
<PanelGroup direction="horizontal" className="h-full hidden md:flex">
{/* Left Panel - Settings Controls */}
<Panel defaultSize={40} minSize={30} maxSize={55}>
<Panel defaultSize={46} minSize={36} maxSize={62}>
<div className="h-full border-r flex flex-col bg-muted/30 relative">
{/* Header with Tabs */}
<div className="p-5 border-b bg-background">
@@ -157,7 +157,7 @@ function SettingsPageInner() {
<SectionErrorBoundary>
<Suspense fallback={<SectionSkeleton />}>
{activeTab === 'websearch' && <WebSearchSection />}
{activeTab === 'imageanalysis' && <ImageAnalysisSection />}
{activeTab === 'image' && <ImageAnalysisSection />}
{activeTab === 'channels' && <ChannelsSection />}
{activeTab === 'globalenv' && <GlobalEnvSection />}
{activeTab === 'thinking' && <ThinkingSection />}
@@ -175,7 +175,7 @@ function SettingsPageInner() {
</PanelResizeHandle>
{/* Right Panel - Config Viewer */}
<Panel defaultSize={60} minSize={35}>
<Panel defaultSize={54} minSize={35}>
<div className="h-full flex flex-col">
{/* Header */}
<div className="p-4 border-b bg-background flex items-center justify-between">
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -161,7 +161,7 @@ export interface OfficialChannelsStatus {
export type SettingsTab =
| 'websearch'
| 'imageanalysis'
| 'image'
| 'channels'
| 'globalenv'
| 'proxy'