From d81690efb5867a02c8f4d67c4e27e8420be89694 Mon Sep 17 00:00:00 2001 From: ciregenz Date: Wed, 5 Aug 2026 10:06:15 -0700 Subject: [PATCH] [eric] marketplace: its own dock app via a shell-global Directory host, dialogs grouped under Directory/dialogs --- .../src/app/components/Layout/AppShell.tsx | 3 +++ .../Dashboard/desktop/DockActionTiles.tsx | 6 +++-- .../pages/Directory/DirectorySkillsTab.tsx | 2 +- .../app/pages/Directory/MarketplaceHost.tsx | 22 +++++++++++++++++++ .../app/pages/Tools/dialogs/ToolsAddMenu.tsx | 2 +- 5 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 frontend/src/app/pages/Directory/MarketplaceHost.tsx diff --git a/frontend/src/app/components/Layout/AppShell.tsx b/frontend/src/app/components/Layout/AppShell.tsx index 3159f6e6..43533e1d 100644 --- a/frontend/src/app/components/Layout/AppShell.tsx +++ b/frontend/src/app/components/Layout/AppShell.tsx @@ -28,6 +28,7 @@ import { fetchOutputs } from '@/shared/state/outputsSlice'; import UpdateReadyPill from '@/app/components/Layout/UpdateReadyPill'; import ShareRequestHost from '@/app/components/share/ShareRequestHost'; import CardContextMenu from '@/app/pages/Dashboard/desktop/CardContextMenu'; +import MarketplaceHost from '@/app/pages/Directory/MarketplaceHost'; import { findBrowserByWebContentsId } from '@/shared/browserRegistry'; import { byPreviewRecency } from '@/shared/previewOrder'; import { useClaudeTokens, useThemeAccent, useThemeWash } from '@/shared/styles/ThemeContext'; @@ -581,6 +582,8 @@ const AppShell: React.FC = () => { {/* Shell-global right-click host (portals to body): chat surfaces render on non-dashboard routes too, so the menu can't live inside DashboardCanvas. */} + + ); }; diff --git a/frontend/src/app/pages/Dashboard/desktop/DockActionTiles.tsx b/frontend/src/app/pages/Dashboard/desktop/DockActionTiles.tsx index cea69f8b..626f2b06 100644 --- a/frontend/src/app/pages/Dashboard/desktop/DockActionTiles.tsx +++ b/frontend/src/app/pages/Dashboard/desktop/DockActionTiles.tsx @@ -1,12 +1,13 @@ import React from 'react'; import Box from '@mui/material/Box'; import Tooltip from '@mui/material/Tooltip'; -import { Globe, CalendarClock, Settings, LayoutGrid } from 'lucide-react'; +import { Globe, CalendarClock, Settings, LayoutGrid, Store } from 'lucide-react'; import { useAppDispatch } from '@/shared/hooks'; import { openSettingsCard, openWorkflowsApp } from '@/shared/state/dashboardLayoutSlice'; +import { openMarketplace } from '@/app/pages/Directory/MarketplaceHost'; // The dock reserves room for these before it knows what they are, so the count lives with the list. -export const DOCK_ACTION_COUNT = 4; +export const DOCK_ACTION_COUNT = 5; interface DockActionTilesProps { tile: number; @@ -21,6 +22,7 @@ function DockActionTiles({ tile, onAddBrowser, onApplications, onHoverAway }: Do const actions: { label: string; Icon: typeof Globe; act: () => void; divider?: boolean }[] = [ { label: 'New browser', Icon: Globe, act: onAddBrowser }, { label: 'Workflows', Icon: CalendarClock, act: () => dispatch(openWorkflowsApp()) }, + { label: 'Marketplace', Icon: Store, act: () => openMarketplace() }, { label: 'Settings', Icon: Settings, act: () => dispatch(openSettingsCard()), divider: true }, { label: 'Applications', Icon: LayoutGrid, act: onApplications }, ]; diff --git a/frontend/src/app/pages/Directory/DirectorySkillsTab.tsx b/frontend/src/app/pages/Directory/DirectorySkillsTab.tsx index b1d479f3..371c4d67 100644 --- a/frontend/src/app/pages/Directory/DirectorySkillsTab.tsx +++ b/frontend/src/app/pages/Directory/DirectorySkillsTab.tsx @@ -19,7 +19,7 @@ import { RegistrySkill, } from '@/shared/state/skillRegistrySlice'; import DirectoryFilterBar from './DirectoryFilterBar'; -import CommunityInstallConfirm from './CommunityInstallConfirm'; +import CommunityInstallConfirm from './dialogs/CommunityInstallConfirm'; interface Props { onOpenInstalled?: (skillId: string) => void; diff --git a/frontend/src/app/pages/Directory/MarketplaceHost.tsx b/frontend/src/app/pages/Directory/MarketplaceHost.tsx new file mode 100644 index 00000000..a617e9c9 --- /dev/null +++ b/frontend/src/app/pages/Directory/MarketplaceHost.tsx @@ -0,0 +1,22 @@ +import React, { useEffect, useState } from 'react'; +import DirectoryDialog, { DirectoryTab } from './DirectoryDialog'; + +export const MARKETPLACE_OPEN_EVENT = 'openswarm:open-marketplace'; + +export function openMarketplace(tab: DirectoryTab = 'skills'): void { + window.dispatchEvent(new CustomEvent(MARKETPLACE_OPEN_EVENT, { detail: { tab } })); +} + +// Shell-global Directory mount: the marketplace is its own surface (dock tile, launcher), not just a settings drill-down. +const MarketplaceHost: React.FC = () => { + const [openTab, setOpenTab] = useState(null); + useEffect(() => { + const onOpen = (e: Event): void => setOpenTab(((e as CustomEvent).detail?.tab as DirectoryTab) ?? 'skills'); + window.addEventListener(MARKETPLACE_OPEN_EVENT, onOpen); + return () => window.removeEventListener(MARKETPLACE_OPEN_EVENT, onOpen); + }, []); + if (!openTab) return null; + return setOpenTab(null)} />; +}; + +export default MarketplaceHost; diff --git a/frontend/src/app/pages/Tools/dialogs/ToolsAddMenu.tsx b/frontend/src/app/pages/Tools/dialogs/ToolsAddMenu.tsx index 6f974566..c39194b3 100644 --- a/frontend/src/app/pages/Tools/dialogs/ToolsAddMenu.tsx +++ b/frontend/src/app/pages/Tools/dialogs/ToolsAddMenu.tsx @@ -9,7 +9,7 @@ import StorefrontIcon from '@mui/icons-material/Storefront'; import AddLinkIcon from '@mui/icons-material/AddLink'; import { useClaudeTokens } from '@/shared/styles/ThemeContext'; import DirectoryDialog from '../../Directory/DirectoryDialog'; -import AddCustomConnectorDialog from '../../Directory/AddCustomConnectorDialog'; +import AddCustomConnectorDialog from '../../Directory/dialogs/AddCustomConnectorDialog'; interface Props { devMode: boolean;