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)
- **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 && (
-