polish(my-deepagent): rebuild Web GUI visual design — cards, pill badges, 8px grid

The first cut of static/*.html + style.css was functional but visually
bare. Rewriting with a modern dev-tool dashboard aesthetic (Linear /
Vercel / Resend palette), still vanilla CSS — no framework, no build
system (DR-3 / plan.md D3 constraint kept).

Changes
- `static/style.css`: full rewrite (192 → ~580 lines). Adds:
  - CSS custom-property design tokens: surface 0/1/2/3, accent/success/
    warning/danger/info each with a matching `*-bg` rgba.
  - Type system: Inter / Pretendard / Apple SD Gothic Neo / Noto Sans KR
    stack with tabular-nums + system features cv05/ss01.
  - 8 px spacing grid, refined border-radius scale (sm/md/lg).
  - `.card` surface with subtle inner highlight + low shadow.
  - `.badge` pill component with state-* modifiers and an animated dot
    for in-progress states (running / executing / validating /
    awaiting_artifact).
  - `.meta-panel` + `.meta-row` for key/value run detail.
  - `.budget-card` with embedded usage bar (ok/warn/over color states).
  - `.events` log with monospace, hover background, per-event-type
    accent color (run.completed green, run.failed red, etc.) and themed
    scrollbar.
  - `.chips` row for per-role persona override input.
  - Buttons with `primary` / `danger` variants and subtle press animation.
  - Compact responsive break at 720 px (single-column meta rows /
    form-grid / chips).
- `static/index.html`: page-title row + `.card` wrapper for runs table +
  `.budget-grid` for budget cards. Active nav highlight.
- `static/new.html`: form rebuilt inside a card with form-grid layout
  (repo path / branch side-by-side), `.chips` rows for per-role override.
- `static/run.html`: page-title with state badge + `.meta-panel` for
  Run ID / Repo / Worktree / Final report + action bar + cards for
  phases and live events.
- `static/app.js`: redesigned rendering helpers to match new markup:
  - New `badge(state)` helper returning a pill element.
  - `emptyCell(colspan, text, ctaHref, ctaText)` for empty-state tables.
  - Runs list: short hash + arrow link, basename for repo with full path
    in `title`, ISO timestamps trimmed to `YYYY-MM-DD HH:MM:SS`.
  - Budget cards: usage bar fill % computed from spent/cap, status class
    (ok / warn / over) flows to both the amount color and the bar color.
  - New event line uses two-column grid (`.ts` + `.body`), event-line
    class derived from event type for per-type accent coloring.
  - EventSource singleton to prevent stacking on re-renders.

XSS policy unchanged: textContent only, innerHTML/insertAdjacentHTML/
outerHTML still forbidden. The hardcoded comment at the top of `app.js`
is preserved (and the static test that asserts it).

Gates
- ruff check + mypy --strict: PASS (120 source files)
- pytest 16 API tests (read+write+sse+static): all PASS

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
chungyeong
2026-05-16 22:30:51 +09:00
parent 0630142c34
commit 4b0b07c8d4
5 changed files with 991 additions and 281 deletions

View File

@@ -3,47 +3,55 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>my-deepagent · 새 run</title>
<title>my-deepagent · 새 Run</title>
<link rel="stylesheet" href="/static/style.css" />
</head>
<body data-page="new">
<header>
<h1>my-deepagent · 새 run 시작</h1>
<h1>my-deepagent</h1>
<nav>
<a href="/">runs</a>
<a href="/new.html">run</a>
<a href="/">Runs</a>
<a href="/new.html" class="active">Run</a>
</nav>
</header>
<main>
<div id="error" class="error-banner" style="display:none"></div>
<form id="start-form">
<div class="form-row">
<label for="template">워크플로우 템플릿</label>
<select id="template" required></select>
<div class="page-title">
<h2>새 Run 시작</h2>
<span class="page-subtitle">워크플로우 + repo + 요구사항</span>
</div>
<form id="start-form" autocomplete="off">
<div class="card" style="padding: 20px;">
<div class="form-row">
<label for="template">워크플로우 템플릿</label>
<select id="template" required></select>
</div>
<div class="form-grid">
<div class="form-row">
<label for="repo-path">repo 절대경로</label>
<input id="repo-path" type="text" placeholder="/Users/me/projects/my-thing" required />
</div>
<div class="form-row">
<label for="base-branch">base branch</label>
<input id="base-branch" type="text" value="main" />
</div>
</div>
<div class="form-row">
<label for="requirements">requirements <span class="hint">— 자유 텍스트, 마크다운 OK</span></label>
<textarea id="requirements" rows="6" placeholder="이 workflow가 다룰 요구사항을 적어주세요."></textarea>
</div>
</div>
<div class="form-row">
<label for="repo-path">repo 절대경로</label>
<input id="repo-path" type="text" placeholder="/Users/me/projects/my-thing" required />
</div>
<div class="form-row">
<label for="base-branch">base branch</label>
<input id="base-branch" type="text" value="main" />
</div>
<div class="form-row">
<label for="requirements">requirements (markdown 가능)</label>
<textarea id="requirements" rows="6" placeholder="이 workflow가 다룰 요구사항을 자유롭게 적어주세요."></textarea>
</div>
<h2>persona override (선택)</h2>
<p class="empty" style="padding:0">비워두면 자동 선택. 값은 <code>persona-name@버전</code> 형식.</p>
<div id="override-fields"></div>
<h2 class="section-title">Persona 오버라이드 <span class="hint" style="text-transform: none; letter-spacing: 0; font-weight: 400;">(선택, 비우면 자동 선택)</span></h2>
<div id="override-fields" class="card"></div>
<div class="action-bar">
<button type="submit">▶︎ 시작</button>
<button type="submit" class="primary">▶︎ 시작</button>
<a class="button" href="/">취소</a>
</div>
</form>