From 5f7048090771a83babe1558e1038c8aadf4827c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Thu, 28 May 2026 19:24:16 -0400 Subject: [PATCH] Pin page actions to the fixed topbar Each page rendered its primary actions inside the scrolling body, so they drifted away on scroll and diverged from the design, which places them in the topbar next to the breadcrumbs. Introduce a TopbarSlotContext that the Shell publishes from its topbar action area, and a TopbarActions portal that Home, Team, Work, Files, Social and Approvals use to render their controls there. --- .../src/renderer/src/pages/ApprovalsPage.tsx | 21 ++++------ .../src/renderer/src/pages/FilesPage.tsx | 41 +++++++++---------- .../src/renderer/src/pages/HomePage.tsx | 17 ++++---- .../src/renderer/src/pages/SocialPage.tsx | 27 ++++++------ .../src/renderer/src/pages/TeamPage.tsx | 29 ++++++------- .../src/renderer/src/pages/WorkPage.tsx | 23 +++++------ .../src/renderer/src/shared/Shell.tsx | 10 +++-- .../src/renderer/src/shared/TopbarActions.tsx | 9 ++++ .../src/renderer/src/shared/topbar-context.ts | 9 ++++ AgentCompany-New/src/renderer/src/styles.css | 1 + 10 files changed, 95 insertions(+), 92 deletions(-) create mode 100644 AgentCompany-New/src/renderer/src/shared/TopbarActions.tsx create mode 100644 AgentCompany-New/src/renderer/src/shared/topbar-context.ts diff --git a/AgentCompany-New/src/renderer/src/pages/ApprovalsPage.tsx b/AgentCompany-New/src/renderer/src/pages/ApprovalsPage.tsx index 24f99adb..859470b2 100644 --- a/AgentCompany-New/src/renderer/src/pages/ApprovalsPage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/ApprovalsPage.tsx @@ -1,5 +1,6 @@ import { useMemo, useState } from "react"; import { Avatar, Button, Icon, Pill } from "../shared/ui"; +import { TopbarActions } from "../shared/TopbarActions"; import type { AgentRecord, ApprovalRecord, @@ -57,18 +58,14 @@ export function ApprovalsPage({ snapshot, actions }: PageProps) { return (
-
-
-

Approvals

-

- {pending.length} pending · {approved7d} approved this week -

-
-
- - -
-
+ + + + +

Approvals

+

+ {pending.length} pending · {approved7d} approved this week +

diff --git a/AgentCompany-New/src/renderer/src/pages/FilesPage.tsx b/AgentCompany-New/src/renderer/src/pages/FilesPage.tsx index baa35da8..e04c4273 100644 --- a/AgentCompany-New/src/renderer/src/pages/FilesPage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/FilesPage.tsx @@ -1,5 +1,6 @@ import { useMemo, useState } from "react"; import { Avatar, Button, Icon, IconButton, Pill, Segmented } from "../shared/ui"; +import { TopbarActions } from "../shared/TopbarActions"; import type { AgentRecord, EmployeeRecord, @@ -56,28 +57,24 @@ export function FilesPage({ snapshot, actions }: PageProps) { />
-
-
-

Files

-

- {visibleFiles.length} {visibleFiles.length === 1 ? "file" : "files"} · {formatBytes(totalBytes)} -

-
-
- - - value={view} - onChange={setView} - options={[ - { id: "grid", label: "Grid" }, - { id: "list", label: "List" }, - ]} - /> - -
-
+ + + + value={view} + onChange={setView} + options={[ + { id: "grid", label: "Grid" }, + { id: "list", label: "List" }, + ]} + /> + + +

Files

+

+ {visibleFiles.length} {visibleFiles.length === 1 ? "file" : "files"} · {formatBytes(totalBytes)} +

{pinnedFiles.length > 0 && section.kind === "all" && ( <> diff --git a/AgentCompany-New/src/renderer/src/pages/HomePage.tsx b/AgentCompany-New/src/renderer/src/pages/HomePage.tsx index dddf79e8..a5cc4269 100644 --- a/AgentCompany-New/src/renderer/src/pages/HomePage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/HomePage.tsx @@ -1,5 +1,6 @@ import { useMemo, useState } from "react"; import { Avatar, Button, Icon, Pill } from "../shared/ui"; +import { TopbarActions } from "../shared/TopbarActions"; import type { AgentRecord, ApprovalRecord, @@ -39,16 +40,12 @@ export function HomePage({ snapshot, actions }: PageProps) { return (
-
-
-

{greeting}, {firstName}

-

{summaryText}

-
-
- - -
-
+ + + + +

{greeting}, {firstName}

+

{summaryText}

diff --git a/AgentCompany-New/src/renderer/src/pages/SocialPage.tsx b/AgentCompany-New/src/renderer/src/pages/SocialPage.tsx index 3d46eda9..4c6fccc2 100644 --- a/AgentCompany-New/src/renderer/src/pages/SocialPage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/SocialPage.tsx @@ -1,5 +1,6 @@ import { useMemo, useState, type FormEvent } from "react"; import { Avatar, Button, Field, Icon, IconButton, Pill } from "../shared/ui"; +import { TopbarActions } from "../shared/TopbarActions"; import { Dialog } from "../shared/Dialog"; import { SOCIAL_PLATFORM, @@ -76,21 +77,17 @@ export function SocialPage({ snapshot, actions }: PageProps) { return (
-
-
-

Social

-

- {accounts.length} {accounts.length === 1 ? "account" : "accounts"} · {scheduled.length} scheduled - {operatorName ? ` · managed by ${operatorName}` : ""} -

-
-
- - -
-
+ + + + +

Social

+

+ {accounts.length} {accounts.length === 1 ? "account" : "accounts"} · {scheduled.length} scheduled + {operatorName ? ` · managed by ${operatorName}` : ""} +

{accounts.length > 0 && ( <> diff --git a/AgentCompany-New/src/renderer/src/pages/TeamPage.tsx b/AgentCompany-New/src/renderer/src/pages/TeamPage.tsx index 9437ce9f..e9315cf8 100644 --- a/AgentCompany-New/src/renderer/src/pages/TeamPage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/TeamPage.tsx @@ -1,5 +1,6 @@ import { useMemo, useState, type FormEvent } from "react"; import { Avatar, Button, Field, Icon, IconButton, Pill } from "../shared/ui"; +import { TopbarActions } from "../shared/TopbarActions"; import { Dialog } from "../shared/Dialog"; import type { AgentRecord, EmployeeRecord, ProviderRecord } from "../../../shared/domain"; import type { PageProps } from "./types"; @@ -49,22 +50,18 @@ export function TeamPage({ snapshot, actions }: PageProps) { return (
-
-
-

Team

-

- {employees.length + agents.length} {employees.length + agents.length === 1 ? "member" : "members"} · - {" "}{employees.length} {employees.length === 1 ? "human" : "humans"} · - {" "}{agents.length} {agents.length === 1 ? "agent" : "agents"} -

-
-
- - -
-
+ + + + +

Team

+

+ {employees.length + agents.length} {employees.length + agents.length === 1 ? "member" : "members"} · + {" "}{employees.length} {employees.length === 1 ? "human" : "humans"} · + {" "}{agents.length} {agents.length === 1 ? "agent" : "agents"} +

Org
diff --git a/AgentCompany-New/src/renderer/src/pages/WorkPage.tsx b/AgentCompany-New/src/renderer/src/pages/WorkPage.tsx index dfcbe461..7faeba27 100644 --- a/AgentCompany-New/src/renderer/src/pages/WorkPage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/WorkPage.tsx @@ -1,5 +1,6 @@ import { useMemo, useState } from "react"; import { Avatar, Button, Icon, IconButton, Pill, Segmented } from "../shared/ui"; +import { TopbarActions } from "../shared/TopbarActions"; import { TASK_STATUS, type AgentRecord, @@ -54,19 +55,15 @@ export function WorkPage({ snapshot, actions }: PageProps) { return (
-
-
-

Work

-

- {tasks.length} {tasks.length === 1 ? "task" : "tasks"} · {agents.length} {agents.length === 1 ? "assignee" : "assignees"} -

-
-
- - - -
-
+ + + + + +

Work

+

+ {tasks.length} {tasks.length === 1 ? "task" : "tasks"} · {agents.length} {agents.length === 1 ? "assignee" : "assignees"} +

{view === "board" && ( void; - actions?: ReactNode; onSwitchOrg: (orgId: string) => void; onDeleteOrg: (orgId: string) => void; onNewOrg: () => void; children: ReactNode; }) { const [searchOpen, setSearchOpen] = useState(false); + const [actionsSlot, setActionsSlot] = useState(null); useEffect(() => { const handler = (event: KeyboardEvent) => { if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") { @@ -123,7 +123,7 @@ export function Shell({ / {activeLabel}
- {actions} + {window.agentCompany.platform !== "darwin" && ( <> void window.agentCompany.windowMinimize()} /> @@ -132,7 +132,9 @@ export function Shell({ )}
-
{children}
+
+ {children} +
(null); diff --git a/AgentCompany-New/src/renderer/src/styles.css b/AgentCompany-New/src/renderer/src/styles.css index 0e8555d6..ed7a76ad 100644 --- a/AgentCompany-New/src/renderer/src/styles.css +++ b/AgentCompany-New/src/renderer/src/styles.css @@ -291,6 +291,7 @@ a { color: inherit; } .crumb-sub { font-size: 13px; color: var(--text-3); } .crumb-sep { color: var(--text-4); } .topbar-actions { margin-left: auto; display: flex; align-items: center; gap: 6px; } +.topbar-actions-slot { display: flex; align-items: center; gap: 6px; } .content { flex: 1;