mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 05:50:35 +00:00
✨ Move the dashboard MCP menu to the page headers
Show the MCP menu next to the layout toggle in the header of the projects, files and deleted pages, instead of in the sidebar. It uses the secondary button style there and a visible dot colour while disconnected. Clicking the MCP button now toggles the menu instead of only opening it. Dashboard events report "dashboard:header" as their origin.
This commit is contained in:
parent
036f59266b
commit
c4d2ca9cd1
@ -81,7 +81,7 @@ Some important concepts for users:
|
||||
|
||||
Connect the tabs you want to use:
|
||||
|
||||
* **Remote MCP**: choose **MCP → Connect** in the dashboard sidebar or a file's toolbar. Use **Disconnect** in the same place to disconnect that tab.
|
||||
* **Remote MCP**: choose **MCP → Connect** in the dashboard header or a file's toolbar. Use **Disconnect** in the same place to disconnect that tab.
|
||||
* **Local MCP**: run the plugin in each file and connect it to your local server. Each plugin connection has its own session ID.
|
||||
* Connecting or disconnecting one tab does not disconnect the others.
|
||||
* A connected tab stays connected while navigating between the dashboard and files. Its session ID stays the same; requests operate on the currently open file.
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
(ns app.main.ui.components.mcp-menu
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.config :as cf]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.workspace.mcp :as mcp]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown-menu :refer [dropdown-menu* dropdown-menu-item*]]
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
@ -36,13 +38,13 @@
|
||||
open-timer* (mf/use-ref nil)
|
||||
close-timer* (mf/use-ref nil)
|
||||
|
||||
on-open-menu
|
||||
on-toggle-menu
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(cancel-timer! open-timer*)
|
||||
(cancel-timer! close-timer*)
|
||||
(reset! menu-open* true)))
|
||||
(swap! menu-open* not)))
|
||||
|
||||
on-close-menu
|
||||
(mf/use-fn
|
||||
@ -80,7 +82,7 @@
|
||||
(mf/deps dashboard)
|
||||
#(st/emit! (mcp/connect-mcp)
|
||||
(ev/event {::ev/name "connect-mcp-plugin"
|
||||
::ev/origin (if dashboard "dashboard:sidebar" "workspace:toolbar")})))
|
||||
::ev/origin (if dashboard "dashboard:header" "workspace:toolbar")})))
|
||||
|
||||
on-disconnect
|
||||
(mf/use-fn
|
||||
@ -102,8 +104,8 @@
|
||||
[:div {:class (stl/css-case :mcp-tool true :dashboard dashboard)
|
||||
:on-pointer-enter on-display-menu
|
||||
:on-pointer-leave on-hide-menu}
|
||||
[:> button* {:variant "ghost"
|
||||
:on-click on-open-menu
|
||||
[:> button* {:variant (if dashboard "secondary" "ghost")
|
||||
:on-click on-toggle-menu
|
||||
:aria-haspopup true
|
||||
:aria-expanded menu-open?
|
||||
:aria-pressed menu-open?
|
||||
@ -115,9 +117,7 @@
|
||||
:connected is-mcp-connected)}]
|
||||
[:span {:class (stl/css-case :toolbar-mcp-button-label true
|
||||
:connected is-mcp-connected)}
|
||||
(if (and dashboard is-mcp-connected)
|
||||
(tr "workspace.toolbar.mcp-connected")
|
||||
(tr "workspace.toolbar.mcp"))]]]
|
||||
(tr "workspace.toolbar.mcp")]]]
|
||||
|
||||
[:div {:class (stl/css :toolbar-mcp-menu)}
|
||||
[:> dropdown-menu* {:show menu-open?
|
||||
@ -139,3 +139,14 @@
|
||||
(if is-connection-requested
|
||||
(tr "workspace.header.menu.mcp.plugin.status.disconnect")
|
||||
(tr "workspace.header.menu.mcp.plugin.status.connect"))]]]]))
|
||||
|
||||
(mf/defc dashboard-mcp-menu*
|
||||
[]
|
||||
(let [mcp-state (mf/deref refs/mcp)]
|
||||
(when (and (contains? cf/flags :mcp)
|
||||
(:enabled mcp-state)
|
||||
(:token-valid mcp-state))
|
||||
[:> mcp-menu* {:dashboard true
|
||||
:is-mcp-connected (= "connected" (:connection-status mcp-state))
|
||||
:is-connection-requested (:connection-requested mcp-state)
|
||||
:session-id (:session-id mcp-state)}])))
|
||||
|
||||
@ -13,10 +13,10 @@
|
||||
|
||||
.mcp-tool {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
margin-inline: var(--sp-l);
|
||||
&.dashboard {
|
||||
--mcp-disconnected-dot-color: var(--color-foreground-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar-mcp-button {
|
||||
@ -38,7 +38,7 @@
|
||||
inline-size: px2rem(6);
|
||||
block-size: px2rem(6);
|
||||
border-radius: 50%;
|
||||
background-color: var(--color-background-disabled);
|
||||
background-color: var(--mcp-disconnected-dot-color, var(--color-background-disabled));
|
||||
|
||||
&.connected {
|
||||
background-color: var(--color-accent-primary);
|
||||
@ -72,6 +72,7 @@
|
||||
|
||||
.toolbar-mcp-menu {
|
||||
position: absolute;
|
||||
z-index: var(--z-index-dropdown);
|
||||
left: 0;
|
||||
top: $sz-36;
|
||||
}
|
||||
@ -85,7 +86,6 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sp-xs);
|
||||
z-index: var(--z-index-dropdown);
|
||||
margin: 0;
|
||||
padding: var(--sp-xs);
|
||||
border: $b-2 solid var(--panel-border-color);
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.context-menu-a11y :refer [context-menu*]]
|
||||
[app.main.ui.components.mcp-menu :refer [dashboard-mcp-menu*]]
|
||||
[app.main.ui.dashboard.grid :refer [grid*]]
|
||||
[app.main.ui.dashboard.layout-toggle :as lt :refer [layout-toggle*]]
|
||||
[app.main.ui.dashboard.subscription :refer [get-subscription-type]]
|
||||
@ -64,6 +65,7 @@
|
||||
[:div#dashboard-deleted-title {:class (stl/css :dashboard-title)}
|
||||
[:h1 (tr "dashboard.projects-title")]]
|
||||
[:div {:class (stl/css :dashboard-header-actions)}
|
||||
[:> dashboard-mcp-menu*]
|
||||
[:> layout-toggle* {:layout layout :on-change on-change}]]])
|
||||
|
||||
(mf/defc project-context-menu*
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
[app.main.data.project :as dpj]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.mcp-menu :refer [dashboard-mcp-menu*]]
|
||||
[app.main.ui.dashboard.grid :refer [grid*]]
|
||||
[app.main.ui.dashboard.import :as udi]
|
||||
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
|
||||
@ -102,6 +103,7 @@
|
||||
(:name project)]]))
|
||||
|
||||
[:div {:class (stl/css :dashboard-header-actions)}
|
||||
[:> dashboard-mcp-menu*]
|
||||
[:> layout-toggle* {:layout layout
|
||||
:on-change on-change}]
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
[app.main.data.team :as dtm]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.mcp-menu :refer [dashboard-mcp-menu*]]
|
||||
[app.main.ui.dashboard.deleted :as deleted]
|
||||
[app.main.ui.dashboard.grid :refer [line-grid*]]
|
||||
[app.main.ui.dashboard.import :as udi]
|
||||
@ -50,6 +51,7 @@
|
||||
(tr "dashboard.personal-projects")
|
||||
(tr "dashboard.projects-title"))]]
|
||||
[:div {:class (stl/css :dashboard-header-actions)}
|
||||
[:> dashboard-mcp-menu*]
|
||||
[:> layout-toggle* {:layout layout
|
||||
:on-change on-change}]
|
||||
(when can-edit
|
||||
|
||||
@ -23,7 +23,6 @@
|
||||
[app.main.ui.components.dropdown-menu :refer [dropdown-menu*
|
||||
dropdown-menu-item*]]
|
||||
[app.main.ui.components.link :refer [link*]]
|
||||
[app.main.ui.components.mcp-menu :refer [mcp-menu*]]
|
||||
[app.main.ui.dashboard.check-updates :as dcu]
|
||||
[app.main.ui.dashboard.comments :refer [comments-icon* comments-section]]
|
||||
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
|
||||
@ -256,7 +255,6 @@
|
||||
(get default-project :id)
|
||||
|
||||
team-id (get team :id)
|
||||
mcp-state (mf/deref refs/mcp)
|
||||
|
||||
projects? (= section :dashboard-recent)
|
||||
fonts? (= section :dashboard-fonts)
|
||||
@ -384,15 +382,6 @@
|
||||
[:span {:class (stl/css :element-title)} (tr "labels.shared-libraries")]]]]]
|
||||
|
||||
|
||||
(when (and (contains? cf/flags :mcp)
|
||||
(:enabled mcp-state)
|
||||
(:token-valid mcp-state))
|
||||
[:div {:class (stl/css :sidebar-content-section)}
|
||||
[:> mcp-menu* {:dashboard true
|
||||
:is-mcp-connected (= "connected" (:connection-status mcp-state))
|
||||
:is-connection-requested (:connection-requested mcp-state)
|
||||
:session-id (:session-id mcp-state)}]])
|
||||
|
||||
[:div {:class (stl/css :sidebar-content-section)
|
||||
:data-testid "pinned-projects"}
|
||||
[:div {:class (stl/css :sidebar-section-title)}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user