diff --git a/apps/ai-game-creator-shell/src/view/project-development/ResourceClassificationPanel.tsx b/apps/ai-game-creator-shell/src/view/project-development/ResourceClassificationPanel.tsx index 6dc83a914..3a70afbdd 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/ResourceClassificationPanel.tsx +++ b/apps/ai-game-creator-shell/src/view/project-development/ResourceClassificationPanel.tsx @@ -214,8 +214,10 @@ export function ResourceClassificationPanel({ items={RESOURCE_CLASSIFICATION_CATEGORY_OPTIONS} activeId={category} onChange={setCategory} - columns="threeToSix" + layout="scroll" gap="sm" + frame="bare" + surface="transparent" size="compact" /> { test('renders a controlled search box, category tabs and tag chips', () => { render( @@ -93,4 +109,45 @@ describe('PlatformResourceFilterBar', () => { expect(screen.queryByRole('group', { name: '素材筛选标签' })).toBeNull(); expect(screen.getByRole('button', { name: '全部' })).toBeTruthy(); }); + + test('never lets a category chip shrink below its label width', () => { + const { container } = render( + {}} + />, + ); + + // 分类条是 scroll 布局:容器横向可滚,标签不换行。 + const row = container.querySelector('.platform-segmented-tabs'); + expect(row).not.toBeNull(); + expect(row?.className).toContain('overflow-x-auto'); + for (const button of row?.querySelectorAll('button') ?? []) { + expect(button.className).toContain('whitespace-nowrap'); + } + + // 单靠 nowrap 不够:子项必须有不低于内容宽度的下限,否则文字会画出盒子压到相邻项。 + expect(segmentedTabsStylesheet()).toMatch( + /\.platform-segmented-tabs\s*>\s*button\s*\{[^}]*min-width:\s*max-content/s, + ); + }); + + test('grid 布局的分段页签同样带宽度下限钩子', () => { + render( + {}} + columns="two" + />, + ); + + const row = screen + .getByRole('button', { name: '角色与对象' }) + .closest('div'); + expect(row?.className).toContain('platform-segmented-tabs'); + expect(row?.className).toContain('grid-cols-2'); + }); }); diff --git a/packages/shared/src/components/PlatformSegmentedTabs.tsx b/packages/shared/src/components/PlatformSegmentedTabs.tsx index 34852d475..cd2eadb1f 100644 --- a/packages/shared/src/components/PlatformSegmentedTabs.tsx +++ b/packages/shared/src/components/PlatformSegmentedTabs.tsx @@ -191,6 +191,7 @@ export function PlatformSegmentedTabs({ role={semantics === 'tabs' ? 'tablist' : undefined} aria-label={semantics === 'tabs' ? ariaLabel : undefined} className={[ + 'platform-segmented-tabs', layout === 'scroll' ? 'flex min-w-0 items-center overflow-x-auto scrollbar-hide' : 'grid', diff --git a/packages/shared/src/components/styles.css b/packages/shared/src/components/styles.css index a3c7bcc59..9b1cd337a 100644 --- a/packages/shared/src/components/styles.css +++ b/packages/shared/src/components/styles.css @@ -519,6 +519,16 @@ display: none; } +/* 分段页签的子项不得被压到内容宽度以下。中文标签(例如「角色与对象」需要一个 + `1.5rem 内边距 + 4 个字`的宽度)在窄容器里一旦被压扁,标签虽然 `nowrap`,文字仍会 + 画出自己的盒子压到相邻项上——现场表现就是「后几项挤成一团、文字互相重叠」。 + `min-width: max-content` 给每个子项一个「内容宽度」下限:放得下就照原样排,放不下 + 就由容器横向滚动兜底,任何情况下都不叠字。grid 与 scroll 两条 layout 都需要它: + grid 的轨道按容器等分,scroll 的 flex 子项默认可收缩,两者都会压到内容宽度以下。 */ +.platform-segmented-tabs > button { + min-width: max-content; +} + .platform-category-chip { display: inline-flex; min-height: 2.25rem;