Skip to content

Commit bbdd94c

Browse files
nficanoclaude
andcommitted
Scaffold ARCP console: Motif-themed Nuxt UI app + component gallery
Nuxt 4 + Nuxt UI v4 console for the Agent Runtime Control Protocol. - Motif (UniFi) theme: full Tailwind color scales mapped onto Nuxt UI aliases (blue primary, cool-gray neutral, green/aqua/amber/red status), Inter, 4px radius - ARCP client: createArcpClient()/arcpWsUrl() + useArcpClient composable, with a vitest suite exercising the client over an in-memory transport (7 passing) - Component gallery at /components: registry + index + dynamic [slug] pages, with a themed showcase SFC for every renderable Nuxt UI component (103), incl. dashboard shells bounded via GalleryFrame - Storybook installed (kept for structure; Nuxt UI v4's Tailwind v4 theme does not apply in its preview — the in-app gallery is the themed source of truth) - Docker Compose dev setup; Material Symbols icons; passing production build Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0 parents  commit bbdd94c

141 files changed

Lines changed: 28732 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
node_modules
2+
.nuxt
3+
.output
4+
.data
5+
.nitro
6+
.cache
7+
dist
8+
.git
9+
.env
10+
.env.*
11+
!.env.example
12+
*.log
13+
.DS_Store

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Base URL of the ARCP server this console controls.
2+
ARCP_SERVER_URL=http://localhost:8080

.gitignore

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Nuxt dev/build outputs
2+
.output
3+
.data
4+
.nuxt
5+
.nitro
6+
.cache
7+
dist
8+
9+
# Dependencies
10+
node_modules
11+
12+
# Logs
13+
logs
14+
*.log
15+
16+
# Env
17+
.env
18+
.env.*
19+
!.env.example
20+
21+
# Storybook
22+
storybook-static
23+
debug-storybook.log
24+
25+
# Local scratch / verification artifacts
26+
.sb-verify
27+
28+
# Misc
29+
.DS_Store
30+
.fleet
31+
.idea
32+
.vscode

.storybook/main.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { StorybookConfig } from '@storybook-vue/nuxt'
2+
3+
const config: StorybookConfig = {
4+
stories: ['../stories/**/*.stories.@(ts|js)'],
5+
addons: ['@storybook/addon-themes'],
6+
framework: {
7+
name: '@storybook-vue/nuxt',
8+
options: {},
9+
},
10+
}
11+
12+
export default config

.storybook/preview.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { Preview } from '@storybook/vue3'
2+
import { withThemeByClassName } from '@storybook/addon-themes'
3+
4+
const preview: Preview = {
5+
parameters: {
6+
layout: 'centered',
7+
backgrounds: { disable: true },
8+
controls: {
9+
matchers: { color: /(background|color)$/i, date: /Date$/i },
10+
},
11+
options: { storySort: { method: 'alphabetical' } },
12+
},
13+
decorators: [
14+
withThemeByClassName({
15+
themes: { light: '', dark: 'dark' },
16+
defaultTheme: 'light',
17+
}),
18+
],
19+
}
20+
21+
export default preview

Dockerfile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# syntax=docker/dockerfile:1
2+
3+
# Dev-oriented image: runs the Nuxt dev server with HMR.
4+
# docker-compose bind-mounts the source over /app for live reloads, while the
5+
# node_modules volume keeps the container's installed deps.
6+
FROM node:22-slim
7+
8+
# pnpm via corepack (version pinned by package.json "packageManager").
9+
RUN corepack enable
10+
11+
WORKDIR /app
12+
13+
# Install deps first for better layer caching. The "postinstall: nuxt prepare"
14+
# hook needs the project files, so copy everything before installing.
15+
COPY . .
16+
RUN pnpm install
17+
18+
ENV HOST=0.0.0.0 \
19+
PORT=3000 \
20+
NUXT_TELEMETRY_DISABLED=1
21+
22+
EXPOSE 3000
23+
24+
CMD ["pnpm", "dev"]

README.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# ARCP Console
2+
3+
A web UI for controlling and observing an [ARCP](https://github.com/agentruntimecontrolprotocol)
4+
(Agent Runtime Control Protocol) server — submit agent jobs, watch runs, and
5+
manage agents.
6+
7+
## Stack
8+
9+
- [Nuxt 4](https://nuxt.com) + [Nuxt UI](https://ui.nuxt.com) v4
10+
- [`@nuxt/icon`](https://github.com/nuxt/icon) with Google
11+
[Material Symbols](https://icones.js.org/collection/material-symbols)
12+
(`i-material-symbols-*`)
13+
- [`@agentruntimecontrolprotocol/sdk`](https://www.npmjs.com/package/@agentruntimecontrolprotocol/sdk)
14+
— the ARCP TypeScript SDK (client + transports)
15+
16+
## Theme — Motif
17+
18+
The console is themed with the **Motif** palette, reconstructed from the UniFi
19+
Network design system. The Tailwind color scales live in
20+
[`app/assets/css/main.css`](app/assets/css/main.css) and are mapped onto Nuxt UI's
21+
color aliases in [`app/theme/motif.ui.ts`](app/theme/motif.ui.ts):
22+
23+
| Alias | Scale | Hue |
24+
| -------------------------- | ------------- | -------------- |
25+
| `primary` | `motif-blue` | 214 (UniFi blue) |
26+
| `neutral` | `motif-gray` | 214 / 8% (cool gray) |
27+
| `success` | `motif-green` | 138 |
28+
| `info` / `secondary` | `motif-aqua` | 198 |
29+
| `warning` | `motif-amber` | 37 |
30+
| `error` | `motif-red` | 358 |
31+
32+
Body type is **Inter**; corner radius is 4px (UniFi default).
33+
34+
## Develop
35+
36+
```bash
37+
cp .env.example .env # point ARCP_SERVER_URL at your server
38+
docker compose up --build # http://localhost:3000
39+
40+
# or locally (Node 22+, pnpm):
41+
pnpm install
42+
pnpm dev
43+
```
44+
45+
## Component gallery
46+
47+
A themed, browsable gallery of every Nuxt UI component lives at **`/components`**
48+
(in the app sidebar). Each component has a showcase demonstrating its colors,
49+
variants, sizes, and states in the Motif theme, with ARCP-flavored examples.
50+
51+
- Registry: [`app/utils/gallery.ts`](app/utils/gallery.ts)
52+
- Showcases: [`app/components/showcase/`](app/components/showcase/) — one SFC per component
53+
- Pages: [`app/pages/components/`](app/pages/components/) (index + `[slug]`)
54+
55+
> **Why a gallery and not Storybook?** Storybook is installed (`pnpm storybook`)
56+
> and runs, but its preview build does not apply Nuxt UI v4's Tailwind-v4 theme
57+
> (components render unstyled there — a known upstream integration gap). The
58+
> in-app gallery renders every component **fully themed**, so it's the source of
59+
> truth for designing the console. The Storybook stories under
60+
> [`stories/`](stories/) remain for reference.
61+
62+
## ARCP client
63+
64+
- [`app/utils/arcp-client.ts`](app/utils/arcp-client.ts)`createArcpClient()` and
65+
`arcpWsUrl()` (maps the `http(s)` server URL to `ws(s)`)
66+
- [`app/composables/useArcpClient.ts`](app/composables/useArcpClient.ts) — browser-side
67+
connect/disconnect over a WebSocket transport
68+
- Tests: [`tests/arcp-client.test.ts`](tests/arcp-client.test.ts) (`pnpm test`) —
69+
exercises the client over an in-memory transport
70+
71+
## Scripts
72+
73+
| Script | Description |
74+
| --------------------- | ---------------------------------------- |
75+
| `pnpm dev` | Nuxt dev server (http://localhost:3000) |
76+
| `pnpm build` | Production build |
77+
| `pnpm test` | Run vitest |
78+
| `pnpm storybook` | Storybook dev server (http://localhost:6006) |
79+
| `pnpm build-storybook`| Build static Storybook |
80+
81+
## Configuration
82+
83+
| Env var | Default | Description |
84+
| ----------------------------- | ----------------------- | --------------------------------- |
85+
| `NUXT_PUBLIC_ARCP_SERVER_URL` | `http://localhost:8080` | ARCP server the console controls. |
86+
87+
(`docker-compose.yml` maps `ARCP_SERVER_URL``NUXT_PUBLIC_ARCP_SERVER_URL`.)

app/app.config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { motifUi } from './theme/motif.ui'
2+
3+
// Nuxt UI theme — Motif (UniFi) palette + Material Symbols icons.
4+
// The config lives in app/theme/motif.ui.ts so Storybook can share it.
5+
export default defineAppConfig({
6+
ui: motifUi,
7+
})

app/app.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<template>
2+
<UApp>
3+
<NuxtLayout>
4+
<NuxtPage />
5+
</NuxtLayout>
6+
</UApp>
7+
</template>

app/assets/css/main.css

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/* Inter — the Motif (UniFi) body typeface. */
2+
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap");
3+
4+
@import "tailwindcss";
5+
@import "@nuxt/ui";
6+
7+
/* -------------------------------------------------------------------------- *
8+
* Motif design tokens
9+
*
10+
* Color scales reconstructed from the UniFi Network design system
11+
* (extracted-styles/motif-theme.{css,json}). Nuxt UI's color aliases below
12+
* point at these, so every component's bg / text / border / ring derives from
13+
* the Motif palette automatically.
14+
*
15+
* motif-blue primary hue 214 — global-primary
16+
* motif-gray neutral hue 214 / 8% — the signature UniFi cool gray
17+
* motif-green success hue 138 — data-positive
18+
* motif-red error hue 358 — data-destructive
19+
* motif-amber warning hue 37 — data-notice
20+
* motif-aqua info hue 198 — data-down / aqua
21+
*
22+
* `static` forces Tailwind v4 to emit every token: Nuxt UI references these
23+
* via `var(--color-motif-*)` (not utility classes), so usage-based tree-shaking
24+
* would otherwise drop them and the theme would resolve to empty.
25+
* -------------------------------------------------------------------------- */
26+
@theme static {
27+
--font-sans: "Inter", "Lato", ui-sans-serif, system-ui, -apple-system,
28+
"Segoe UI", Arial, sans-serif;
29+
30+
/* primary — Motif blue (global-primary light=500, dark=400) */
31+
--color-motif-blue-50: hsl(214 100% 97%);
32+
--color-motif-blue-100: hsl(214 100% 92%);
33+
--color-motif-blue-200: hsl(214 100% 85%);
34+
--color-motif-blue-300: hsl(214 100% 75%);
35+
--color-motif-blue-400: hsl(214 100% 64%);
36+
--color-motif-blue-500: hsl(214 100% 50%);
37+
--color-motif-blue-600: hsl(214 100% 42%);
38+
--color-motif-blue-700: hsl(215 88% 36%);
39+
--color-motif-blue-800: hsl(213 88% 26%);
40+
--color-motif-blue-900: hsl(213 88% 16%);
41+
--color-motif-blue-950: hsl(213 88% 12%);
42+
43+
/* neutral — Motif cool gray (hue 214 / 8%) */
44+
--color-motif-gray-50: hsl(214 8% 98%);
45+
--color-motif-gray-100: hsl(214 8% 96%);
46+
--color-motif-gray-200: hsl(214 8% 88%);
47+
--color-motif-gray-300: hsl(214 8% 82%);
48+
--color-motif-gray-400: hsl(214 8% 65%);
49+
--color-motif-gray-500: hsl(214 8% 54%);
50+
--color-motif-gray-600: hsl(214 8% 44%);
51+
--color-motif-gray-700: hsl(214 8% 34%);
52+
--color-motif-gray-800: hsl(214 8% 20%);
53+
--color-motif-gray-900: hsl(214 8% 12%);
54+
--color-motif-gray-950: hsl(214 8% 8%);
55+
56+
/* success — Motif green (data-positive) */
57+
--color-motif-green-50: hsl(138 60% 95%);
58+
--color-motif-green-100: hsl(138 60% 90%);
59+
--color-motif-green-200: hsl(138 60% 81%);
60+
--color-motif-green-300: hsl(138 59% 71%);
61+
--color-motif-green-400: hsl(138 59% 61%);
62+
--color-motif-green-500: hsl(138 59% 51%);
63+
--color-motif-green-600: hsl(138 56% 41%);
64+
--color-motif-green-700: hsl(138 56% 33%);
65+
--color-motif-green-800: hsl(138 57% 25%);
66+
--color-motif-green-900: hsl(138 56% 18%);
67+
--color-motif-green-950: hsl(138 56% 12%);
68+
69+
/* error — Motif red (data-destructive) */
70+
--color-motif-red-50: hsl(357 82% 96%);
71+
--color-motif-red-100: hsl(359 86% 92%);
72+
--color-motif-red-200: hsl(358 86% 83%);
73+
--color-motif-red-300: hsl(359 86% 75%);
74+
--color-motif-red-400: hsl(358 86% 67%);
75+
--color-motif-red-500: hsl(359 86% 58%);
76+
--color-motif-red-600: hsl(358 61% 47%);
77+
--color-motif-red-700: hsl(359 61% 38%);
78+
--color-motif-red-800: hsl(359 61% 29%);
79+
--color-motif-red-900: hsl(358 62% 20%);
80+
--color-motif-red-950: hsl(358 62% 14%);
81+
82+
/* warning — Motif amber/orange (data-notice) */
83+
--color-motif-amber-50: hsl(37 91% 95%);
84+
--color-motif-amber-100: hsl(37 91% 91%);
85+
--color-motif-amber-200: hsl(37 91% 82%);
86+
--color-motif-amber-300: hsl(37 91% 73%);
87+
--color-motif-amber-400: hsl(37 91% 64%);
88+
--color-motif-amber-500: hsl(37 91% 55%);
89+
--color-motif-amber-600: hsl(37 75% 44%);
90+
--color-motif-amber-700: hsl(37 75% 36%);
91+
--color-motif-amber-800: hsl(37 74% 27%);
92+
--color-motif-amber-900: hsl(37 74% 20%);
93+
--color-motif-amber-950: hsl(37 74% 14%);
94+
95+
/* info — Motif aqua (data-down) */
96+
--color-motif-aqua-50: hsl(198 100% 96%);
97+
--color-motif-aqua-100: hsl(198 100% 93%);
98+
--color-motif-aqua-200: hsl(198 97% 85%);
99+
--color-motif-aqua-300: hsl(198 98% 78%);
100+
--color-motif-aqua-400: hsl(198 97% 71%);
101+
--color-motif-aqua-500: hsl(198 98% 63%);
102+
--color-motif-aqua-600: hsl(198 58% 51%);
103+
--color-motif-aqua-700: hsl(198 56% 41%);
104+
--color-motif-aqua-800: hsl(198 57% 32%);
105+
--color-motif-aqua-900: hsl(198 56% 22%);
106+
--color-motif-aqua-950: hsl(198 56% 16%);
107+
}
108+
109+
/* Motif uses a 4px corner radius across the board (radius-global / -btn). */
110+
:root {
111+
--ui-radius: 0.25rem;
112+
}
113+
114+
/* Match the UniFi canvas: a faint cool-gray page behind white surfaces. */
115+
body {
116+
background-color: var(--ui-bg-muted);
117+
}

0 commit comments

Comments
 (0)