From e364e4a70fc979aa16cda1c71b424f4eb5057a81 Mon Sep 17 00:00:00 2001 From: zipg Date: Mon, 21 Sep 2026 11:37:24 +0800 Subject: [PATCH] fix(objects): collapse toolbar controls when object view is narrow --- .../src/components/objects/ObjectBrowser.vue | 13 +++++-- ...ObjectBrowser.toolbarOverflowFloor.spec.ts | 34 ++++++++++++++++++ .../issue-9200-after-narrow-fixed-full.png | Bin 0 -> 107166 bytes ...issue-9200-after-narrow-search-visible.png | Bin 0 -> 24524 bytes .../issue-9200-before-narrow-overlap-full.png | Bin 0 -> 106821 bytes ...ssue-9200-before-narrow-search-overlap.png | Bin 0 -> 22760 bytes 6 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 apps/desktop/src/components/objects/__tests__/ObjectBrowser.toolbarOverflowFloor.spec.ts create mode 100644 docs/screenshots/issue-9200-after-narrow-fixed-full.png create mode 100644 docs/screenshots/issue-9200-after-narrow-search-visible.png create mode 100644 docs/screenshots/issue-9200-before-narrow-overlap-full.png create mode 100644 docs/screenshots/issue-9200-before-narrow-search-overlap.png diff --git a/apps/desktop/src/components/objects/ObjectBrowser.vue b/apps/desktop/src/components/objects/ObjectBrowser.vue index 815fce5cfe..69fb44eed9 100644 --- a/apps/desktop/src/components/objects/ObjectBrowser.vue +++ b/apps/desktop/src/components/objects/ObjectBrowser.vue @@ -3393,8 +3393,8 @@ function getObjectBrowserMenuItems(item: ObjectBrowserRow): ContextMenuItem[] { {{ props.database }} -
-
+
+
-
diff --git a/apps/desktop/src/components/objects/__tests__/ObjectBrowser.toolbarOverflowFloor.spec.ts b/apps/desktop/src/components/objects/__tests__/ObjectBrowser.toolbarOverflowFloor.spec.ts new file mode 100644 index 0000000000..297de5a31f --- /dev/null +++ b/apps/desktop/src/components/objects/__tests__/ObjectBrowser.toolbarOverflowFloor.spec.ts @@ -0,0 +1,34 @@ +import { readFileSync } from "node:fs"; +import { describe, expect, it } from "vitest"; + +// Issue #9200: when the "Browse Objects" pane is narrow, the keyword search box +// collapsed to a sliver and the "全部/表/视图" chips were painted on top of it, +// instead of the toolbar condensing its controls into the overflow menu. +// +// useToolbarOverflow only condenses while the row reports real overflow, and its +// contract requires "non-shrinking (shrink-0) or floored (min-w-*) children": +// 1. the collapsed search wrapper was `min-w-0`, so the wrapper dropped to 0 +// width while the input inside still painted at its padding width (58px), +// drawing on top of the neighbouring filter chips; +// 2. the search + filter group carried `min-w-24`, which overrode the +// content-based minimum and let the group shrink below its own content, so +// its children spilled into the sort control instead of overflowing the row; +// 3. the filter chips allowed their labels to wrap, so the group's min-content +// (longest word) was far below the width the chips actually occupy. +// Each of the three is load-bearing; removing any one of them brings the overlap +// back at some pane width. + +const objectBrowserSource = readFileSync(new URL("../ObjectBrowser.vue", import.meta.url), "utf8"); + +describe("ObjectBrowser toolbar condenses instead of overlapping when narrow", () => { + it("floors the search box and lets the search + filter group keep its content minimum", () => { + // The floored wrapper keeps the input from painting over its neighbours, and + // dropping `min-w-24` lets the group's content-based minimum stop the spill + // into the sort control, so the row reports overflow instead. + expect(objectBrowserSource).toMatch(/
\s*
/); + }); + + it("pins the filter chips to their single-line width so the row reports overflow", () => { + expect(objectBrowserSource).toMatch(/