fix: restore Flash/Pro buttons, add GPT-5.4 label in topbar

- Restore Flash/Pro dual model buttons in GeminiInput (they control
  speed/quality mode sent to backend, not model name)
- Restore selectedModel/onSelectedModelChange props in GeminiInput
- Reset default model back to "pro" in GeminiChat
- Replace Gemini model dropdown in GeminiTopbar with static "GPT-5.4"
  label to show current model name

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gongzhiyong
2026-04-08 18:08:10 +08:00
co-authored by Claude Sonnet 4.6
parent b9465f4c5a
commit 8c7fe84a3d
3 changed files with 39 additions and 71 deletions
+3 -1
View File
@@ -72,7 +72,7 @@ export function GeminiChat() {
const [extensions, setExtensions] = useState<Extension[]>(INITIAL_EXTENSIONS);
const [ticketSummary, setTicketSummary] = useState<TicketSummaryData | null>(null);
const [activeTools, setActiveTools] = useState<Set<string>>(new Set());
const [selectedModel, setSelectedModel] = useState<"flash" | "pro">("flash");
const [selectedModel, setSelectedModel] = useState<"flash" | "pro">("pro");
const messagesEndRef = useRef<HTMLDivElement>(null);
const abortRef = useRef<AbortController | null>(null);
@@ -383,6 +383,8 @@ export function GeminiChat() {
isLoading={isLoading}
activeTools={activeTools}
onActiveToolsChange={setActiveTools}
selectedModel={selectedModel}
onSelectedModelChange={setSelectedModel}
/>
</div>
+28 -5
View File
@@ -27,6 +27,8 @@ interface GeminiInputProps {
isLoading?: boolean;
activeTools: Set<string>;
onActiveToolsChange: (tools: Set<string>) => void;
selectedModel: "flash" | "pro";
onSelectedModelChange: (model: "flash" | "pro") => void;
}
const TOOLS: Tool[] = [
@@ -43,6 +45,8 @@ export function GeminiInput({
isLoading,
activeTools,
onActiveToolsChange,
selectedModel,
onSelectedModelChange,
}: GeminiInputProps) {
const textareaRef = useRef<HTMLTextAreaElement>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
@@ -200,13 +204,32 @@ export function GeminiInput({
</div>
</div>
{/* Bottom row: Model indicator */}
{/* Bottom row: Model selector */}
<div className="flex items-center justify-end px-4 pb-3 pt-0 gap-2">
<span
className="px-3 py-1.5 rounded-full text-xs font-medium bg-[var(--gem-blue)] text-white"
<button
onClick={() => onSelectedModelChange("flash")}
className={cn(
"px-3 py-1.5 rounded-full text-xs font-medium transition-all duration-150 cursor-pointer",
selectedModel === "flash"
? "bg-[var(--gem-blue)] text-white"
: "bg-[var(--gem-surface-2)] text-[var(--gem-text-muted)] hover:bg-[var(--gem-surface-3)] hover:text-[var(--gem-text)]"
)}
aria-pressed={selectedModel === "flash"}
>
gpt-5.4
</span>
Flash
</button>
<button
onClick={() => onSelectedModelChange("pro")}
className={cn(
"px-3 py-1.5 rounded-full text-xs font-medium transition-all duration-150 cursor-pointer",
selectedModel === "pro"
? "bg-[var(--gem-purple)] text-white"
: "bg-[var(--gem-surface-2)] text-[var(--gem-text-muted)] hover:bg-[var(--gem-surface-3)] hover:text-[var(--gem-text)]"
)}
aria-pressed={selectedModel === "pro"}
>
Pro
</button>
</div>
{/* Tools panel (collapsible, below input) */}
+8 -65
View File
@@ -1,7 +1,6 @@
"use client";
import { useState } from "react";
import { Menu, ChevronDown, Settings, Sun, Moon } from "lucide-react";
import { Menu, Settings, Sun, Moon } from "lucide-react";
import { useTheme } from "next-themes";
import { cn } from "@/lib/utils";
@@ -10,16 +9,7 @@ interface GeminiTopbarProps {
onToggleSidebar: () => void;
}
const models = [
"Gemini 2.0 Flash",
"Gemini 1.5 Pro",
"Gemini 1.5 Flash",
"Gemini Advanced",
];
export function GeminiTopbar({ sidebarOpen, onToggleSidebar }: GeminiTopbarProps) {
const [selectedModel, setSelectedModel] = useState("Gemini 2.0 Flash");
const [modelDropdownOpen, setModelDropdownOpen] = useState(false);
const { theme, setTheme } = useTheme();
return (
@@ -42,60 +32,13 @@ export function GeminiTopbar({ sidebarOpen, onToggleSidebar }: GeminiTopbarProps
<Menu size={20} />
</button>
{/* Center: model selector */}
<div className="relative">
<button
onClick={() => setModelDropdownOpen((prev) => !prev)}
className="flex items-center gap-1.5 px-4 py-1.5 rounded-full border border-[var(--gem-border)] text-[var(--gem-text)] text-sm font-medium hover:bg-[var(--gem-surface-2)] transition-colors duration-150 cursor-pointer"
aria-haspopup="listbox"
aria-expanded={modelDropdownOpen}
aria-label="选择模型"
>
<span>{selectedModel}</span>
<ChevronDown
size={14}
className={cn(
"text-[var(--gem-text-muted)] transition-transform duration-200",
modelDropdownOpen && "rotate-180"
)}
/>
</button>
{/* Dropdown */}
{modelDropdownOpen && (
<>
<div
className="fixed inset-0 z-10"
onClick={() => setModelDropdownOpen(false)}
aria-hidden="true"
/>
<ul
role="listbox"
className="absolute top-full left-1/2 -translate-x-1/2 mt-2 w-52 bg-[var(--gem-surface-2)] border border-[var(--gem-border)] rounded-2xl shadow-2xl overflow-hidden z-20 py-1.5"
aria-label="可用的模型"
>
{models.map((model) => (
<li key={model} role="option" aria-selected={selectedModel === model}>
<button
onClick={() => {
setSelectedModel(model);
setModelDropdownOpen(false);
}}
className={cn(
"w-full text-left px-4 py-2.5 text-sm transition-colors duration-150 cursor-pointer",
selectedModel === model
? "text-[var(--gem-blue)] bg-[var(--gem-surface)]"
: "text-[var(--gem-text)] hover:bg-[var(--gem-surface-3)]"
)}
>
{model}
</button>
</li>
))}
</ul>
</>
)}
</div>
{/* Center: model label */}
<span
className="px-4 py-1.5 rounded-full border border-[var(--gem-border)] text-[var(--gem-text)] text-sm font-medium"
aria-label="当前模型"
>
GPT-5.4
</span>
{/* Right: theme toggle + settings + avatar */}
<div className="flex items-center gap-1">