From f4a47a035a86d785b952e2b977cb9610b53c4412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Wed, 29 Jul 2026 21:27:30 +0000 Subject: [PATCH] soulseek: wire sections into the view, default to dashboard, persist zoom - render dashboard/uploads/rooms/chat/users/system from the section channel - nav + view both default to the dashboard section - register the view panel's zoom header; read the persisted zoom via useDashboardState Co-Authored-By: Claude Opus 4.8 --- .../src/apps/Soulseek/SoulseekNav.tsx | 2 +- .../src/apps/Soulseek/SoulseekView.tsx | 51 ++++++++++++++++--- .../officerdev/src/apps/Soulseek/index.ts | 10 +++- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/workspaces/officerdev/src/apps/Soulseek/SoulseekNav.tsx b/src/workspaces/officerdev/src/apps/Soulseek/SoulseekNav.tsx index 36b64a1d..1834649e 100644 --- a/src/workspaces/officerdev/src/apps/Soulseek/SoulseekNav.tsx +++ b/src/workspaces/officerdev/src/apps/Soulseek/SoulseekNav.tsx @@ -18,7 +18,7 @@ const ICONS: Record = { }; export const SoulseekNav = () => { - const [section, setSection] = usePanelChannel(SOULSEEK_SECTION_CHANNEL, 'search'); + const [section, setSection] = usePanelChannel(SOULSEEK_SECTION_CHANNEL, 'dashboard'); return (
diff --git a/src/workspaces/officerdev/src/apps/Soulseek/SoulseekView.tsx b/src/workspaces/officerdev/src/apps/Soulseek/SoulseekView.tsx index beba6e6a..5c582569 100644 --- a/src/workspaces/officerdev/src/apps/Soulseek/SoulseekView.tsx +++ b/src/workspaces/officerdev/src/apps/Soulseek/SoulseekView.tsx @@ -1,11 +1,20 @@ import { Construction } from 'lucide-react'; import { usePanelChannel } from 'hooks/usePanelChannel'; -import { SOULSEEK_SECTION_CHANNEL, SOULSEEK_SECTIONS, type SoulseekSectionId } from './shared'; +import { useDashboardState } from 'state/useDashboardState'; +import { SOULSEEK_SECTION_CHANNEL, SOULSEEK_SECTIONS, soulseekZoomKey, type SoulseekSectionId } from './shared'; import { SearchView } from './SearchView'; import { SoulseekTransfers } from './SoulseekTransfers'; +import { SoulseekUploads } from './SoulseekUploads'; +import { SoulseekRooms } from './SoulseekRooms'; +import { SoulseekDashboard } from './SoulseekDashboard'; +import { SoulseekChat } from './SoulseekChat'; +import { SoulseekUsers } from './SoulseekUsers'; +import { SoulseekSystem } from './SoulseekSystem'; -// Right panel of the /soulseek workspace — renders the UI for the section the nav selected. Only Search -// (history + input) and Downloads (transfers) are built so far; the rest are placeholders. +// Right panel of the /soulseek workspace — renders the UI for the section the nav selected. The panel +// header's +/- controls set a per-panel zoom factor, persisted via useDashboardState (same store as the +// layout config); we read it here and apply it as a CSS scale, with a compensating width/height so the +// scaled content still fills the panel and inner scroll keeps working. const Placeholder = ({ id }: { id: SoulseekSectionId }) => { const label = SOULSEEK_SECTIONS.find((s) => s.id === id)?.label ?? id; @@ -22,15 +31,45 @@ const Placeholder = ({ id }: { id: SoulseekSectionId }) => { ); }; -export const SoulseekView = () => { - const [section] = usePanelChannel(SOULSEEK_SECTION_CHANNEL, 'search'); - +const sectionView = (section: SoulseekSectionId) => { switch (section) { + case 'dashboard': + return ; case 'search': return ; case 'downloads': return ; + case 'uploads': + return ; + case 'rooms': + return ; + case 'chat': + return ; + case 'users': + return ; + case 'system': + return ; default: return ; } }; + +type SoulseekViewProps = { panelId: string }; + +export const SoulseekView = ({ panelId }: SoulseekViewProps) => { + const [section] = usePanelChannel(SOULSEEK_SECTION_CHANNEL, 'dashboard'); + const { value: zoom } = useDashboardState(soulseekZoomKey(panelId), 1); + const z = zoom ?? 1; + + if (z === 1) return
{sectionView(section)}
; + + // transform: scale doesn't reflow, so size the box to 1/z and let the scale bring it back to 100%. + const inv = `${100 / z}%`; + return ( +
+
+ {sectionView(section)} +
+
+ ); +}; diff --git a/src/workspaces/officerdev/src/apps/Soulseek/index.ts b/src/workspaces/officerdev/src/apps/Soulseek/index.ts index 147d607d..2cfdc74e 100644 --- a/src/workspaces/officerdev/src/apps/Soulseek/index.ts +++ b/src/workspaces/officerdev/src/apps/Soulseek/index.ts @@ -2,10 +2,18 @@ import type { AppRegistryMeta } from '../../AppRegistry'; import { PanelLeft, LayoutGrid } from 'lucide-react'; import { SoulseekNav } from './SoulseekNav'; import { SoulseekView } from './SoulseekView'; +import { SoulseekViewHeader } from './SoulseekViewHeader'; export { SoulseekNav, SoulseekView }; export const appRegistryMetas: AppRegistryMeta[] = [ { key: 'soulseek-nav', name: 'Soulseek', icon: PanelLeft, component: SoulseekNav, availableOnPanel: false }, - { key: 'soulseek-view', name: 'Soulseek', icon: LayoutGrid, component: SoulseekView, availableOnPanel: false }, + { + key: 'soulseek-view', + name: 'Soulseek', + icon: LayoutGrid, + component: SoulseekView, + header: SoulseekViewHeader, + availableOnPanel: false, + }, ];