fix(model-picker): 模型选择 - 限制弹窗宽度并改善描述可读性

This commit is contained in:
medivh
2026-09-29 18:52:02 +08:00
parent eaff2f03e8
commit 7e4688e4d1
4 changed files with 57 additions and 62 deletions

View File

@@ -1,4 +1,4 @@
import { useEffect, useId, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type KeyboardEvent } from "react";
import { useEffect, useId, useMemo, useRef, useState, type KeyboardEvent } from "react";
import { Check, ChevronDown, Coins } from "lucide-react";
import { Popover } from "antd";
@@ -55,7 +55,6 @@ export function ModelPicker({
const theme = (canvasThemes[rawTheme as keyof typeof canvasThemes] ?? canvasThemes.dark) as CanvasTheme;
const [open, setOpen] = useState(false);
const [activeGroupKey, setActiveGroupKey] = useState<string | null>(null);
const [triggerWidth, setTriggerWidth] = useState<number | null>(null);
const menuRef = useRef<HTMLDivElement>(null);
const triggerRef = useRef<HTMLButtonElement>(null);
const options = useMemo(() => Array.from(new Set(selectableModelsByCapability(config, capability).filter(Boolean))), [capability, config]);
@@ -71,16 +70,6 @@ export function ModelPicker({
const [routeQuote, setRouteQuote] = useState<LogicalModelQuote | undefined>();
const creationVariant = variant === "creation";
useLayoutEffect(() => {
const trigger = triggerRef.current;
if (!trigger) return;
const updateTriggerWidth = () => setTriggerWidth(Math.ceil(trigger.getBoundingClientRect().width));
updateTriggerWidth();
const observer = new ResizeObserver(updateTriggerWidth);
observer.observe(trigger);
return () => observer.disconnect();
}, [className, fullWidth, showSelectedPrice, variant, value]);
useEffect(() => {
if (!showSelectedPrice || !creditsEnabled || !quoteRequest) {
setRouteQuote(undefined);
@@ -167,13 +156,7 @@ export function ModelPicker({
"canvas-model-picker-menu creation-model-picker-menu max-w-[calc(100vw-24px)]",
activeGroupKey === null ? "is-brand-list" : "is-model-list",
)}
style={
{
background: theme.node.panel,
color: theme.node.text,
"--canvas-model-picker-trigger-width": triggerWidth ? String(triggerWidth) + "px" : undefined,
} as CSSProperties
}
style={{ background: theme.node.panel, color: theme.node.text }}
role="listbox"
aria-label={placeholder}
onKeyDown={handleMenuKeyDown}
@@ -337,19 +320,21 @@ export function ModelLabel({
<span className="grid size-6 shrink-0 place-items-center rounded-md" style={{ background: theme.toolbar.itemHover }}>
<ModelIcon config={config} model={model} />
</span>
<span className="min-w-44 flex-1 overflow-hidden">
<span className="block min-w-0 truncate text-[var(--fs-label)] font-medium leading-none">{label || pickerModelDisplayName(config, model, showConfiguredModelName)}</span>
<span className={cn("canvas-model-picker-description mt-1 block truncate text-[var(--fs-tiny)]", showDescription && "is-visible")} style={{ color: theme.node.muted }}>
<span className="min-w-0 flex-1 overflow-hidden">
<span className="canvas-model-picker-option-heading">
<span className="canvas-model-picker-option-name text-[var(--fs-label)] font-medium leading-none" title={label || pickerModelDisplayName(config, model, showConfiguredModelName)}>{label || pickerModelDisplayName(config, model, showConfiguredModelName)}</span>
{showPrice ? (
<span className="canvas-model-picker-option-price">
{/* 候选模型展示自身价目;当前参数的精确报价只在选中后的触发器显示。 */}
<ModelPrice price={modelMenuPrice(config, model, capability, true, requirements)} />
</span>
) : null}
</span>
<span className={cn("canvas-model-picker-description mt-1 block", showDescription && "is-visible")} style={{ color: theme.node.muted }}>
{capabilitySummary}
</span>
<ModelTags tags={logicalCost?.tags} />
</span>
{showPrice ? (
<span className="ml-auto shrink-0 pl-2">
{/* 候选模型展示自身价目;当前参数的精确报价只在选中后的触发器显示。 */}
<ModelPrice price={modelMenuPrice(config, model, capability, true, requirements)} />
</span>
) : null}
{!creationVariant && meta.time ? (
<span className="shrink-0 rounded-full px-1.5 py-0.5 text-[var(--fs-tiny)] tabular-nums" style={{ background: theme.toolbar.itemHover, color: theme.node.muted }}>
{meta.time}