From 9be3aa82354a28ff03a5313ac18806137ea120aa Mon Sep 17 00:00:00 2001 From: qihang ma <116867131+skyqingname@users.noreply.github.com> Date: Thu, 8 Oct 2026 14:28:40 +0800 Subject: [PATCH] =?UTF-8?q?fix(model-picker):=20=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E9=80=89=E6=8B=A9=20-=20=E4=BF=AE=E5=A4=8D=E9=95=BF=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E6=BA=A2=E5=87=BA=E4=B8=8E=E6=B8=A0=E9=81=93=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=E9=9A=8F=E5=8A=A8=20(#706)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 天道酬秦 --- web/src/components/model-picker.tsx | 23 +++++++++++++++++--- web/src/styles/shared/model-picker.css | 30 ++++++++++++++------------ web/src/styles/workspace-product.css | 2 +- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/web/src/components/model-picker.tsx b/web/src/components/model-picker.tsx index af94cdbc6..d8f5ca001 100644 --- a/web/src/components/model-picker.tsx +++ b/web/src/components/model-picker.tsx @@ -1,4 +1,4 @@ -import { useEffect, useId, useMemo, useRef, useState, type KeyboardEvent } from "react"; +import { useEffect, useId, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type KeyboardEvent } from "react"; import { Check, ChevronDown, Coins } from "lucide-react"; import { Popover } from "antd"; @@ -54,6 +54,7 @@ export function ModelPicker({ const rawTheme = useActiveTheme(); const theme = (canvasThemes[rawTheme as keyof typeof canvasThemes] ?? canvasThemes.dark) as CanvasTheme; const [open, setOpen] = useState(false); + const [availableHeight, setAvailableHeight] = useState(0); const [activeGroupKey, setActiveGroupKey] = useState(null); const menuRef = useRef(null); const triggerRef = useRef(null); @@ -70,6 +71,21 @@ export function ModelPicker({ const [routeQuote, setRouteQuote] = useState(); const creationVariant = variant === "creation"; + useLayoutEffect(() => { + if (!open) return; + const updateAvailableHeight = () => { + const { top, bottom } = triggerRef.current!.getBoundingClientRect(); + setAvailableHeight(Math.max(top, window.innerHeight - bottom)); + }; + updateAvailableHeight(); + window.addEventListener("resize", updateAvailableHeight); + window.addEventListener("scroll", updateAvailableHeight, true); + return () => { + window.removeEventListener("resize", updateAvailableHeight); + window.removeEventListener("scroll", updateAvailableHeight, true); + }; + }, [open]); + useEffect(() => { if (!showSelectedPrice || !creditsEnabled || !quoteRequest) { setRouteQuote(undefined); @@ -156,7 +172,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 }} + style={{ background: theme.node.panel, color: theme.node.text, "--canvas-model-picker-available-height": `${availableHeight}px` } as CSSProperties} role="listbox" aria-label={placeholder} onKeyDown={handleMenuKeyDown} @@ -185,7 +201,7 @@ export function ModelPicker({ ; })} - {optionGroups.filter((group) => group.key === activeGroupKey).map((group) =>
+ {optionGroups.filter((group) => group.key === activeGroupKey).map((group) =>
{group.models.map((modelGroup) => { const selected = modelGroup.models.includes(current); @@ -243,6 +259,7 @@ export function ModelPicker({ onOpenChange={setPickerOpen} trigger="click" placement="bottomLeft" + align={{ overflow: { adjustY: true, shiftX: true } }} arrow={false} content={content} classNames={{ diff --git a/web/src/styles/shared/model-picker.css b/web/src/styles/shared/model-picker.css index 989a021b1..6711ba101 100644 --- a/web/src/styles/shared/model-picker.css +++ b/web/src/styles/shared/model-picker.css @@ -66,7 +66,6 @@ } .creation-model-picker-menu { - max-height: min(460px, calc(100vh - 24px)); overflow-x: hidden; overflow-y: auto; padding: 8px !important; @@ -305,9 +304,11 @@ html:not(.dark) .creation-model-picker.canvas-composer-model-picker[aria-expande .canvas-model-picker-menu { box-sizing: border-box; + display: flex; + flex-direction: column; min-width: 0; max-width: calc(100vw - 24px); - max-height: min(420px, calc(100vh - 32px)); + max-height: min(460px, calc(100dvh - 24px), calc(var(--canvas-model-picker-available-height) - 24px)); overflow-x: hidden; overflow-y: auto; padding: 4px; @@ -522,7 +523,7 @@ html:not(.dark) .creation-chat-composer .creation-model-picker.canvas-composer-m .creation-model-picker-surface .ant-popover-inner-content { padding: 0 !important; } -.creation-model-picker-menu { max-height: min(420px, calc(100vh - 24px)); padding: 7px !important; background: transparent !important; color: #f0f1f2 !important; } +.creation-model-picker-menu { padding: 7px !important; background: transparent !important; color: #f0f1f2 !important; } .creation-model-picker-heading { display: flex; align-items: center; gap: 6px; padding: 4px 7px 7px; color: #8e949d; font-size: 10px; } .creation-model-picker-heading strong { color: #e6e8eb; font-weight: 500; } .creation-model-picker-menu .canvas-model-picker-group-label { padding: 6px 7px 5px; font-size: 10px; } @@ -632,19 +633,26 @@ html:not(.dark) .creation-home .creation-chat-composer .creation-model-picker.ca } .canvas-model-picker-menu.is-model-list { width: min(800px, calc(100vw - 24px)); + overflow: hidden; } .canvas-model-picker-two-pane { display: grid; + flex: 1 1 auto; width: 100%; grid-template-columns: 250px minmax(0, 1fr); + grid-template-rows: minmax(0, 1fr); gap: 14px; min-width: 0; - align-items: start; + min-height: 0; + overflow: hidden; } .canvas-model-picker-menu.is-model-list .canvas-model-picker-brand-rail { display: grid; + min-height: 0; align-content: start; gap: 5px; + overflow-x: hidden; + overflow-y: auto; border-right: 1px solid var(--workspace-border); padding-right: 14px; } @@ -653,6 +661,9 @@ html:not(.dark) .creation-home .creation-chat-composer .creation-model-picker.ca } .canvas-model-picker-model-pane { min-width: 0; + min-height: 0; + overflow-x: hidden; + overflow-y: auto; } @media (max-width: 720px) { .canvas-model-picker-menu:is(.is-brand-list, .is-model-list) { @@ -893,10 +904,8 @@ html:not(.dark) .creation-home .creation-chat-composer .creation-model-picker.ca .app-user-workspace .creation-launchpad .creation-model-picker.canvas-composer-model-picker { width: min(232px, 60cqw) !important; } -/* 模型选择器:先选品牌,再选模型;品牌列表保持完整可见,不用内部滚动条。 */ +/* 模型与渠道共用菜单高度约束,长列表在各自区域滚动。 */ .app-user-workspace .creation-model-picker-menu.is-brand-list { - max-height: none !important; - overflow: visible !important; padding: 10px !important; } .app-user-workspace .creation-model-picker-menu .canvas-model-picker-brands { display: grid; gap: 5px; } @@ -928,14 +937,7 @@ html:not(.dark) .creation-home .creation-chat-composer .creation-model-picker.ca min-height: 32px !important; height: 32px !important; } -.creation-model-picker-surface .creation-model-picker-menu.is-model-list { - max-height: min(460px, calc(100vh - 24px)) !important; - overflow-x: hidden !important; - overflow-y: auto !important; -} .creation-model-picker-surface .creation-model-picker-menu.is-brand-list { - max-height: none !important; - overflow: visible !important; padding: 10px !important; } .creation-model-picker-surface .canvas-model-picker-brands { display: grid; gap: 5px; } diff --git a/web/src/styles/workspace-product.css b/web/src/styles/workspace-product.css index 2e939fcec..483e13a72 100644 --- a/web/src/styles/workspace-product.css +++ b/web/src/styles/workspace-product.css @@ -659,7 +659,7 @@ .app-user-workspace .creation-composer-stage .creation-empty-composer { min-width: 0; flex: 1 1 auto; } .app-user-workspace .creation-composer-stage.is-agent-mode .creation-agent-entry { min-width: 0; flex: 1 1 auto; } -.creation-model-picker-surface .creation-model-picker-menu.is-model-list .canvas-model-picker-two-pane { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: 14px; min-height: 0; align-items: start; } +.creation-model-picker-surface .creation-model-picker-menu.is-model-list .canvas-model-picker-two-pane { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: 14px; min-height: 0; } .creation-model-picker-surface .creation-model-picker-menu.is-model-list .canvas-model-picker-brand-rail { display: grid; align-content: start; gap: 5px; border-right: 1px solid var(--workspace-border); padding-right: 14px; } .creation-model-picker-surface .creation-model-picker-menu.is-model-list .canvas-model-picker-brand { width: 100%; } .creation-model-picker-surface .creation-model-picker-menu.is-model-list .canvas-model-picker-model-pane { border: 0; margin: 0; padding: 0; }