diff --git a/apps/web/src/app/App.svelte b/apps/web/src/app/App.svelte index a5d8dce..e7170ef 100644 --- a/apps/web/src/app/App.svelte +++ b/apps/web/src/app/App.svelte @@ -1,4 +1,5 @@ {#if currentUser} - - SenlinAI Workbench - Signed in as {currentUser.account} - + {:else} {/if} diff --git a/apps/web/src/features/workbench/ProjectChannelSidebar.svelte b/apps/web/src/features/workbench/ProjectChannelSidebar.svelte new file mode 100644 index 0000000..40cb1a0 --- /dev/null +++ b/apps/web/src/features/workbench/ProjectChannelSidebar.svelte @@ -0,0 +1,52 @@ + + + diff --git a/apps/web/src/features/workbench/ProjectRail.svelte b/apps/web/src/features/workbench/ProjectRail.svelte new file mode 100644 index 0000000..d1be341 --- /dev/null +++ b/apps/web/src/features/workbench/ProjectRail.svelte @@ -0,0 +1,26 @@ + + + + SA + {#each projects as project} + onSelectProject(project.id)} + > + {project.initials} + {#if project.unreadCount} + {project.unreadCount} + {/if} + + {/each} + + + diff --git a/apps/web/src/features/workbench/ProjectWorkbench.svelte b/apps/web/src/features/workbench/ProjectWorkbench.svelte new file mode 100644 index 0000000..4ab9ffd --- /dev/null +++ b/apps/web/src/features/workbench/ProjectWorkbench.svelte @@ -0,0 +1,41 @@ + + + + + + + + + {workspace.channels.find((channel) => channel.id === selectedChannelID)?.title} + + + + diff --git a/apps/web/src/features/workbench/ProjectWorkbench.test.ts b/apps/web/src/features/workbench/ProjectWorkbench.test.ts new file mode 100644 index 0000000..cf251b3 --- /dev/null +++ b/apps/web/src/features/workbench/ProjectWorkbench.test.ts @@ -0,0 +1,26 @@ +import '@testing-library/jest-dom/vitest'; +import { fireEvent, render, screen } from '@testing-library/svelte'; +import { describe, expect, it } from 'vitest'; +import ProjectWorkbench from './ProjectWorkbench.svelte'; + +describe('ProjectWorkbench', () => { + it('renders project rail, channel sidebar, topbar, and inspector', () => { + render(ProjectWorkbench, { props: { currentUser: { account: 'david@example.com' } } }); + + expect(screen.getByLabelText('Project list')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Project A1' })).toHaveAttribute('aria-pressed', 'true'); + expect(screen.getByLabelText('Project channels')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Message Flow 36' })).toBeInTheDocument(); + expect(screen.getByLabelText('Global search')).toBeInTheDocument(); + expect(screen.getByLabelText('Object inspector')).toBeInTheDocument(); + }); + + it('refreshes channels when switching projects', async () => { + render(ProjectWorkbench, { props: { currentUser: { account: 'david@example.com' } } }); + + await fireEvent.click(screen.getByRole('button', { name: 'Project A2' })); + + expect(screen.getByRole('button', { name: 'Project A2' })).toHaveAttribute('aria-pressed', 'true'); + expect(screen.getByText('Ops Dashboard')).toBeInTheDocument(); + }); +}); diff --git a/apps/web/src/features/workbench/WorkspaceTopbar.svelte b/apps/web/src/features/workbench/WorkspaceTopbar.svelte new file mode 100644 index 0000000..c828fcf --- /dev/null +++ b/apps/web/src/features/workbench/WorkspaceTopbar.svelte @@ -0,0 +1,16 @@ + + + + SenlinAI + + Search + + + + ← + → + {account.slice(0, 2).toUpperCase()} + +
Signed in as {currentUser.account}