From f7ed1822c73879dcda2cdff12e54ebeb80bd48ae Mon Sep 17 00:00:00 2001 From: EthanHealy01 <80844253+EthanHealy01@users.noreply.github.com> Date: Thu, 20 Aug 2026 09:33:26 +0000 Subject: [PATCH] Float the editor search when no file is open (#7575) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What The super-search work pinned the editor's `WorkbenchBar` visible on every view except My Files, even with no file open. That left an empty workbench showing a fully painted bar whose only live control was the search — download / close / print / save were all disabled, because those actions only make sense with a file open. This stops forcing the bar. When nothing is open, only the global search floats (unpainted, centered), mirroring how the Processor already works. When a file **is** open, the `WorkbenchBar` renders exactly as before. Also fixes a smaller Processor issue: its floating search strip was shorter than the sidebar logo row, so the search sat higher than the brand. Its height now matches the logo row (51px) so they line up. ## Changes - **`Workbench.tsx`** — render the `WorkbenchBar` only when a file is open (or a custom view supplies content); otherwise render the new floating search. My Files and `hideTopControls` custom views are unchanged. - **`WorkbenchFloatingSearch.tsx` / `.css`** (new) — the editor's `SuperSearch` floated in an unpainted strip, mirroring `PortalSearchBar`. Its vertical band matches the bar's so opening a file swaps in the bar without a shift. - **`PortalSearchBar.css`** — strip height matched to `.portal-sidebar__logo` (51px) so the Processor search aligns with the logo. The notification bell is intentionally out of scope — it ships in a separate PR. ## Before / after (ignore the bell icon in the after that’s not live yet) Screenshot 2026-08-20 at 2 28
17 AM Screenshot 2026-08-20 at 2 28
31 AM - **Editor, no file:** painted bar with disabled buttons → just a floating search. - **Editor, file open:** unchanged. - **Processor:** search now vertically aligned with the logo. ## Testing - `task frontend:check` — lint (incl. colour linters) + typecheck + tests (247 files / 2137 tests) all pass. - Processor alignment verified in Storybook (`Portal/Shell/AppShell`): logo row, search strip, and search pill share the same vertical center. - Editor float not verified in-browser (local backend is behind a login gate); covered by types/tests and reuses the verified Processor pattern. --- .../src/core/components/layout/Workbench.tsx | 77 +++++++++++-------- .../shared/WorkbenchFloatingSearch.css | 31 ++++++++ .../shared/WorkbenchFloatingSearch.tsx | 15 ++++ .../src/portal/components/PortalSearchBar.css | 7 +- 4 files changed, 94 insertions(+), 36 deletions(-) create mode 100644 frontend/editor/src/core/components/shared/WorkbenchFloatingSearch.css create mode 100644 frontend/editor/src/core/components/shared/WorkbenchFloatingSearch.tsx diff --git a/frontend/editor/src/core/components/layout/Workbench.tsx b/frontend/editor/src/core/components/layout/Workbench.tsx index 7dbc6f75be..8bc0794140 100644 --- a/frontend/editor/src/core/components/layout/Workbench.tsx +++ b/frontend/editor/src/core/components/layout/Workbench.tsx @@ -18,6 +18,7 @@ import { useCookieConsent } from "@app/hooks/useCookieConsent"; import styles from "@app/components/layout/Workbench.module.css"; import WorkbenchBar from "@app/components/shared/WorkbenchBar"; +import WorkbenchFloatingSearch from "@app/components/shared/WorkbenchFloatingSearch"; import LandingPage from "@app/components/shared/LandingPage"; import DismissAllErrorsButton from "@app/components/shared/DismissAllErrorsButton"; import { ChatFAB } from "@app/components/chat/ChatFAB"; @@ -77,6 +78,22 @@ export default function Workbench() { const [viewerToolbarCollapsed, setViewerToolbarCollapsed] = useState(false); const showReopenTab = currentView === "viewer" && viewerToolbarCollapsed; + // The WorkbenchBar carries file-scoped actions, so it only shows once a file + // is open or a custom view supplies content; otherwise the search floats. + const activeCustomView = customWorkbenchViews.find( + (v) => v.workbenchId === currentView, + ); + const topControlsAvailable = + currentView !== "myFiles" && !activeCustomView?.hideTopControls; + const hasWorkbenchContent = + hasFiles || + fileIds.length > 0 || + !isBaseWorkbench(currentView) || + // Shared signing drives the viewer from the sidebar with no file in context. + (currentView === "viewer" && !!signingOverlay?.file); + const showWorkbenchBar = topControlsAvailable && hasWorkbenchContent; + const showFloatingSearch = topControlsAvailable && !hasWorkbenchContent; + const handlePreviewClose = () => { setPreviewFile(null); const previousMode = sessionStorage.getItem("previousMode"); @@ -231,41 +248,35 @@ export default function Workbench() { data-tour="workbench" style={{ backgroundColor: "var(--c-bg)", minWidth: 0 }} > - {/* Workbench Bar — always visible outside My Files (it hosts the - global search), even with no files loaded. */} - {currentView !== "myFiles" && - !customWorkbenchViews.find((v) => v.workbenchId === currentView) - ?.hideTopControls && ( -
-
-
- -
-
- {/* Reopen tab: a little handle hanging off the bar's bottom-right - while the viewer tool row is retracted. */} - {showReopenTab && ( -
+ )} + {showFloatingSearch && } {/* Dismiss All Errors Button */} diff --git a/frontend/editor/src/core/components/shared/WorkbenchFloatingSearch.css b/frontend/editor/src/core/components/shared/WorkbenchFloatingSearch.css new file mode 100644 index 0000000000..47c7e9eed4 --- /dev/null +++ b/frontend/editor/src/core/components/shared/WorkbenchFloatingSearch.css @@ -0,0 +1,31 @@ +/* Unpainted floating search for the empty workbench. Height + top margin match + the WorkbenchBar's band so opening a file swaps it in without a shift. */ +.workbench-floating-search { + display: flex; + align-items: center; + justify-content: center; + min-height: 38px; + margin-top: var(--nav-gutter); + padding: 0 1rem; + flex-shrink: 0; +} + +.workbench-floating-search .super-search { + flex: 0 1 24rem; + width: min(100%, 24rem); + max-width: 24rem; +} + +.workbench-floating-search .super-search input { + background-color: transparent; + padding-top: 4px; + padding-bottom: 4px; + font-size: 12.5px; +} + +[data-mantine-color-scheme="dark"] + .workbench-floating-search + .super-search + input { + background-color: transparent; +} diff --git a/frontend/editor/src/core/components/shared/WorkbenchFloatingSearch.tsx b/frontend/editor/src/core/components/shared/WorkbenchFloatingSearch.tsx new file mode 100644 index 0000000000..37e858adff --- /dev/null +++ b/frontend/editor/src/core/components/shared/WorkbenchFloatingSearch.tsx @@ -0,0 +1,15 @@ +import SuperSearch from "@app/components/shared/superSearch/SuperSearch"; +import { useEditorSearchScopes } from "@app/hooks/useSuperSearch"; +import "@app/components/shared/WorkbenchFloatingSearch.css"; + +// The editor's global search, floated while no file is open (mirrors the +// processor's PortalSearchBar). Renders only when the WorkbenchBar doesn't, so +// reusing the default input id is safe. +export default function WorkbenchFloatingSearch() { + const scopes = useEditorSearchScopes(); + return ( +
+ +
+ ); +} diff --git a/frontend/editor/src/portal/components/PortalSearchBar.css b/frontend/editor/src/portal/components/PortalSearchBar.css index cf1d9971c7..8e253b6136 100644 --- a/frontend/editor/src/portal/components/PortalSearchBar.css +++ b/frontend/editor/src/portal/components/PortalSearchBar.css @@ -1,10 +1,11 @@ -/* Slim strip at the top of the main column hosting the shared search bar. - Deliberately unpainted: only the input itself shows, on the page ground. */ +/* Unpainted strip at the top of the main column. Height matches the sidebar's + logo row (.portal-sidebar__logo, 51px) so the search lines up with the brand. */ .portal-searchbar { display: flex; align-items: center; justify-content: center; - padding: 0.22rem 1rem; + min-height: 3.1875rem; + padding: 0 1rem; flex-shrink: 0; }