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, + }, ];