Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/web/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { AppShell } from "../components/app-shell.js";

export default function Page(): string {
return AppShell();
}
36 changes: 36 additions & 0 deletions apps/web/src/components/app-shell-model.ts
Original file line number Diff line number Diff line change
@@ -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 `<div class="agentdeck-shell">
<header class="agentdeck-topbar">
<div class="agentdeck-brand">AgentDeck</div>
<div class="agentdeck-topbar-meta">Local workspace</div>
</header>
<div class="agentdeck-layout" style="grid-template-columns:${APP_SHELL_PANEL_WIDTHS.sidebar} minmax(0,1fr) ${APP_SHELL_PANEL_WIDTHS.inspector}">
${renderSidebarHtml("chat")}
<main class="agentdeck-work-area" aria-label="Primary work area">
<section class="agentdeck-work-header">
<div>
<h1>Chat</h1>
<p>Coordinate agents, workflows, runtime checks, and pending tasks from one dense workspace.</p>
</div>
<button type="button">New task</button>
</section>
<section class="agentdeck-work-grid" aria-label="Workspace summary">
${APP_NAV_ITEMS.slice(0, 5)
.map((item) => `<article><h2>${item.label}</h2><p>${item.id}</p></article>`)
.join("")}
</section>
</main>
${renderInspectorHtml()}
</div>
</div>`;
}
34 changes: 34 additions & 0 deletions apps/web/src/components/app-shell.test.ts
Original file line number Diff line number Diff line change
@@ -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");
});
});
5 changes: 5 additions & 0 deletions apps/web/src/components/app-shell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { renderAppShellHtml } from "./app-shell-model.js";

export function AppShell(): string {
return renderAppShellHtml();
}
10 changes: 10 additions & 0 deletions apps/web/src/components/inspector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export function renderInspectorHtml(): string {
return `<aside class="agentdeck-inspector" aria-label="Context inspector">
<div class="agentdeck-panel-title">Inspector</div>
<dl class="agentdeck-inspector-list">
<div><dt>Selection</dt><dd>Workspace overview</dd></div>
<div><dt>Status</dt><dd>Ready</dd></div>
<div><dt>Scope</dt><dd>Local project</dd></div>
</dl>
</aside>`;
}
21 changes: 21 additions & 0 deletions apps/web/src/components/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -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 `<nav class="agentdeck-sidebar" aria-label="Workspace navigation">${APP_NAV_ITEMS.map(
(item) =>
`<a class="agentdeck-nav-item${item.id === activeItemId ? " is-active" : ""}" href="#${item.id}">${item.label}</a>`,
).join("")}</nav>`;
}
10 changes: 10 additions & 0 deletions apps/web/src/index.ts
Original file line number Diff line number Diff line change
@@ -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";
173 changes: 173 additions & 0 deletions apps/web/src/styles/globals.css
Original file line number Diff line number Diff line change
@@ -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;
}
5 changes: 3 additions & 2 deletions apps/web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
}
8 changes: 4 additions & 4 deletions docs/development/task-backlog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:**

Expand Down