diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx new file mode 100644 index 0000000..c7894f9 --- /dev/null +++ b/apps/web/src/app/page.tsx @@ -0,0 +1,5 @@ +import { AppShell } from "../components/app-shell.js"; + +export default function Page(): string { + return AppShell(); +} diff --git a/apps/web/src/components/app-shell-model.ts b/apps/web/src/components/app-shell-model.ts new file mode 100644 index 0000000..fd44e5b --- /dev/null +++ b/apps/web/src/components/app-shell-model.ts @@ -0,0 +1,36 @@ +import { APP_NAV_ITEMS, renderSidebarHtml } from "./sidebar.js"; +import { renderInspectorHtml } from "./inspector.js"; + +export { APP_NAV_ITEMS } from "./sidebar.js"; + +export const APP_SHELL_PANEL_WIDTHS = { + sidebar: "236px", + inspector: "320px", +} as const; + +export function renderAppShellHtml(): string { + return `
+
+
AgentDeck
+
Local workspace
+
+
+ ${renderSidebarHtml("chat")} +
+
+
+

Chat

+

Coordinate agents, workflows, runtime checks, and pending tasks from one dense workspace.

+
+ +
+
+ ${APP_NAV_ITEMS.slice(0, 5) + .map((item) => `

${item.label}

${item.id}

`) + .join("")} +
+
+ ${renderInspectorHtml()} +
+
`; +} diff --git a/apps/web/src/components/app-shell.test.ts b/apps/web/src/components/app-shell.test.ts new file mode 100644 index 0000000..a2d8c13 --- /dev/null +++ b/apps/web/src/components/app-shell.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from "vitest"; + +import { APP_NAV_ITEMS, APP_SHELL_PANEL_WIDTHS, renderAppShellHtml } from "./app-shell-model.js"; + +describe("app shell", () => { + it("renders top bar, sidebar, main work area, and contextual inspector", () => { + const html = renderAppShellHtml(); + + expect(html).toContain("AgentDeck"); + expect(html).toContain("agentdeck-sidebar"); + expect(html).toContain("agentdeck-work-area"); + expect(html).toContain("agentdeck-inspector"); + }); + + it("includes dense workspace navigation entries", () => { + expect(APP_NAV_ITEMS.map((item) => item.label)).toEqual([ + "Chat", + "Agents", + "Workflows", + "Tasks", + "Runtimes", + "Audit", + "Settings", + ]); + }); + + it("uses stable panel widths for desktop layout", () => { + expect(APP_SHELL_PANEL_WIDTHS).toEqual({ + sidebar: "236px", + inspector: "320px", + }); + expect(renderAppShellHtml()).toContain("grid-template-columns:236px minmax(0,1fr) 320px"); + }); +}); diff --git a/apps/web/src/components/app-shell.tsx b/apps/web/src/components/app-shell.tsx new file mode 100644 index 0000000..0780214 --- /dev/null +++ b/apps/web/src/components/app-shell.tsx @@ -0,0 +1,5 @@ +import { renderAppShellHtml } from "./app-shell-model.js"; + +export function AppShell(): string { + return renderAppShellHtml(); +} diff --git a/apps/web/src/components/inspector.tsx b/apps/web/src/components/inspector.tsx new file mode 100644 index 0000000..784bb5f --- /dev/null +++ b/apps/web/src/components/inspector.tsx @@ -0,0 +1,10 @@ +export function renderInspectorHtml(): string { + return ``; +} diff --git a/apps/web/src/components/sidebar.tsx b/apps/web/src/components/sidebar.tsx new file mode 100644 index 0000000..27b8d8d --- /dev/null +++ b/apps/web/src/components/sidebar.tsx @@ -0,0 +1,21 @@ +export interface NavItem { + readonly id: string; + readonly label: string; +} + +export const APP_NAV_ITEMS: readonly NavItem[] = [ + { id: "chat", label: "Chat" }, + { id: "agents", label: "Agents" }, + { id: "workflows", label: "Workflows" }, + { id: "tasks", label: "Tasks" }, + { id: "runtimes", label: "Runtimes" }, + { id: "audit", label: "Audit" }, + { id: "settings", label: "Settings" }, +]; + +export function renderSidebarHtml(activeItemId = "chat"): string { + return ``; +} diff --git a/apps/web/src/index.ts b/apps/web/src/index.ts index 81e1b23..8af70a2 100644 --- a/apps/web/src/index.ts +++ b/apps/web/src/index.ts @@ -1 +1,11 @@ export const webAppName = "@agentdeck/web"; + +export { AppShell } from "./components/app-shell.js"; +export { + APP_NAV_ITEMS, + APP_SHELL_PANEL_WIDTHS, + renderAppShellHtml, +} from "./components/app-shell-model.js"; +export { renderInspectorHtml } from "./components/inspector.js"; +export { renderSidebarHtml } from "./components/sidebar.js"; +export type { NavItem } from "./components/sidebar.js"; diff --git a/apps/web/src/styles/globals.css b/apps/web/src/styles/globals.css new file mode 100644 index 0000000..e20e91d --- /dev/null +++ b/apps/web/src/styles/globals.css @@ -0,0 +1,173 @@ +:root { + color: #172026; + background: #f4f6f7; + font-family: + Inter, + ui-sans-serif, + system-ui, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + sans-serif; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; +} + +.agentdeck-shell { + min-height: 100vh; + background: #f4f6f7; +} + +.agentdeck-topbar { + display: flex; + align-items: center; + justify-content: space-between; + height: 48px; + padding: 0 16px; + border-bottom: 1px solid #d9e0e4; + background: #ffffff; +} + +.agentdeck-brand { + font-size: 15px; + font-weight: 700; +} + +.agentdeck-topbar-meta { + color: #66747d; + font-size: 12px; +} + +.agentdeck-layout { + display: grid; + min-height: calc(100vh - 48px); +} + +.agentdeck-sidebar, +.agentdeck-inspector { + background: #ffffff; +} + +.agentdeck-sidebar { + display: flex; + flex-direction: column; + gap: 2px; + padding: 10px; + border-right: 1px solid #d9e0e4; +} + +.agentdeck-nav-item { + display: block; + padding: 8px 10px; + border-radius: 6px; + color: #28343b; + font-size: 13px; + text-decoration: none; +} + +.agentdeck-nav-item.is-active { + background: #e6f0ed; + color: #0e4f43; + font-weight: 700; +} + +.agentdeck-work-area { + min-width: 0; + padding: 16px; +} + +.agentdeck-work-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 16px; + padding-bottom: 14px; + border-bottom: 1px solid #d9e0e4; +} + +.agentdeck-work-header h1 { + margin: 0 0 4px; + font-size: 20px; +} + +.agentdeck-work-header p { + max-width: 720px; + margin: 0; + color: #5c6870; + font-size: 13px; +} + +.agentdeck-work-header button { + min-width: 88px; + height: 32px; + border: 1px solid #0e4f43; + border-radius: 6px; + background: #0e4f43; + color: #ffffff; + font-weight: 700; +} + +.agentdeck-work-grid { + display: grid; + grid-template-columns: repeat(5, minmax(120px, 1fr)); + gap: 10px; + margin-top: 14px; +} + +.agentdeck-work-grid article { + min-height: 84px; + padding: 10px; + border: 1px solid #d9e0e4; + border-radius: 8px; + background: #ffffff; +} + +.agentdeck-work-grid h2 { + margin: 0; + font-size: 13px; +} + +.agentdeck-work-grid p { + margin: 8px 0 0; + color: #66747d; + font-size: 12px; +} + +.agentdeck-inspector { + padding: 12px; + border-left: 1px solid #d9e0e4; +} + +.agentdeck-panel-title { + margin-bottom: 12px; + font-size: 12px; + font-weight: 700; + text-transform: uppercase; +} + +.agentdeck-inspector-list { + display: grid; + gap: 10px; + margin: 0; +} + +.agentdeck-inspector-list div { + padding-bottom: 10px; + border-bottom: 1px solid #edf1f3; +} + +.agentdeck-inspector-list dt { + color: #66747d; + font-size: 11px; +} + +.agentdeck-inspector-list dd { + margin: 3px 0 0; + font-size: 13px; +} diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index 1155e6e..75cd1aa 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -2,8 +2,9 @@ "extends": "../../tsconfig.base.json", "compilerOptions": { "rootDir": "src", - "outDir": "dist" + "outDir": "dist", + "jsx": "preserve" }, - "include": ["src/**/*.ts"], + "include": ["src/**/*.ts", "src/**/*.tsx"], "exclude": ["dist", "node_modules"] } diff --git a/docs/development/task-backlog.md b/docs/development/task-backlog.md index a46e4ff..e879e56 100644 --- a/docs/development/task-backlog.md +++ b/docs/development/task-backlog.md @@ -424,10 +424,10 @@ Status markers: **Tasks:** -- [ ] Implement top bar, left sidebar, main work area, and right inspector. -- [ ] Add navigation entries for Chat, Agents, Workflows, Tasks, Runtimes, Audit, and Settings. -- [ ] Use dense tool-style layout with stable panel widths. -- [ ] Commit with message `feat: add web app shell`. +- [x] Implement top bar, left sidebar, main work area, and right inspector. +- [x] Add navigation entries for Chat, Agents, Workflows, Tasks, Runtimes, Audit, and Settings. +- [x] Use dense tool-style layout with stable panel widths. +- [x] Commit with message `feat: add web app shell`. **Acceptance Criteria:**