Files
web-terminal/docs/mockups/project-manager.html
Yaojia Wang dc5d073374 chore(v0.6): checkpoint foundation — Amber theme, P1 types, P3 config, design docs
Prior-session prep for the v0.6 Project Manager, checkpointed on the
v0.6-projects branch as a clean base for the parallel builders:

- P1 (src/types.ts): ProjectInfo + ProjectSessionRef contracts; Config
  gains projectRoots/projectScanDepth/projectScanTtlMs/projectDirtyCheck.
- P3 (src/config.ts): parseBool + parseProjectRoots helpers; parse the
  4 PROJECT_* env vars with defaults ([homeDir]/4/10000/true).
- UI: public/style.css indigo -> Amber (#e3a64a) accent theme.
- Docs: FEATURE_PROJECT_MANAGER.md (1:N session design), THEME.md,
  docs/mockups/ (final-amber.png is the locked visual).

Typecheck (backend + web) green. No behavior change to runtime code yet;
P2/P4/P5/P6 implement the feature on top of this.
2026-06-30 10:05:40 +02:00

271 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Project Manager — UI Mockup</title>
<style>
:root{
/* warm near-neutral dark base — no blue/purple */
--bg:#100f0d; --panel:#181613; --card:#1b1916;
--border:rgba(255,255,255,.07); --border-strong:rgba(255,255,255,.14);
--text:#ece9e3; --text-dim:#a8a299; --text-faint:#6f6a61;
/* emerald accent */
--accent:#3ecf8e; --accent-2:#2bb377;
--accent-soft:rgba(62,207,142,.14); --accent-line:rgba(62,207,142,.35);
/* status */
--working:#3ecf8e; --waiting:#f5b14c; --idle:#8b8a86; --dirty:#e8a13c; --red:#ff6b6b;
--shadow:0 12px 44px rgba(0,0,0,.55); --radius:9px; --radius-lg:14px;
--ui-font:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
--mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
*{box-sizing:border-box}
body{margin:0;background:
radial-gradient(1100px 520px at 82% -12%, rgba(62,207,142,.10), transparent 62%),
var(--bg);
color:var(--text);font-family:var(--ui-font);min-height:100vh;-webkit-font-smoothing:antialiased}
/* top bar */
.topbar{height:50px;display:flex;align-items:center;gap:14px;padding:0 18px;
border-bottom:1px solid var(--border);background:rgba(24,22,19,.62);
backdrop-filter:blur(14px);position:sticky;top:0;z-index:5}
.brand{display:flex;align-items:center;gap:9px;font-weight:650;letter-spacing:.2px}
.brand .dot{width:11px;height:11px;border-radius:50%;
background:conic-gradient(from 200deg,var(--accent),var(--accent-2),var(--accent))}
.seg{display:flex;background:#0c0b09;border:1px solid var(--border);
border-radius:999px;padding:3px;gap:2px;margin-left:6px}
.seg button{all:unset;cursor:pointer;font-size:13px;color:var(--text-dim);
padding:5px 15px;border-radius:999px;transition:.15s;display:flex;align-items:center;gap:6px}
.seg button.active{background:var(--accent-soft);color:#bff3da;
box-shadow:inset 0 0 0 1px var(--accent-line)}
.seg .mini{font-size:10px;background:var(--accent);color:#08120c;border-radius:999px;
padding:1px 6px;font-weight:700}
.spacer{flex:1}
.icns{display:flex;gap:6px}
.icns button{all:unset;cursor:pointer;width:33px;height:33px;border-radius:8px;
display:grid;place-items:center;color:var(--text-dim);font-size:15px;transition:.15s}
.icns button:hover{background:var(--accent-soft);color:var(--text)}
/* content */
.wrap{max-width:1100px;margin:0 auto;padding:26px 22px 60px}
.head{display:flex;align-items:baseline;gap:12px;margin:4px 0 22px}
.head h1{font-size:20px;margin:0;font-weight:680;letter-spacing:.2px}
.head .sub{color:var(--text-faint);font-size:13px}
.head .grow{flex:1}
.search{display:flex;align-items:center;gap:8px;background:var(--panel);
border:1px solid var(--border);border-radius:999px;padding:8px 15px;width:260px;
color:var(--text-faint);font-size:13px;transition:.15s}
.search:focus-within{border-color:var(--accent-line)}
.search input{all:unset;flex:1;color:var(--text);font-size:13px}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(290px,1fr));gap:16px}
.card{background:linear-gradient(180deg,var(--card),#161410);
border:1px solid var(--border);border-radius:var(--radius-lg);
padding:15px;display:flex;flex-direction:column;gap:11px;
box-shadow:var(--shadow);transition:.18s;cursor:default;position:relative;overflow:hidden}
.card:hover{border-color:var(--border-strong);transform:translateY(-2px)}
.card.running{border-color:var(--accent-line)}
.card.running::before{content:"";position:absolute;left:0;right:0;top:0;height:2px;
background:linear-gradient(90deg,transparent,var(--accent),transparent);opacity:.8}
.crow{display:flex;align-items:center;gap:8px;min-width:0}
.name{font-weight:680;font-size:15px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.star{color:var(--waiting);font-size:13px}
.badge{margin-left:auto;font-size:11px;padding:3px 10px;border-radius:999px;
display:flex;align-items:center;gap:6px;white-space:nowrap}
.badge.idle{background:rgba(255,255,255,.05);color:var(--text-faint)}
.countbadge{margin-left:auto;font-size:11px;padding:3px 10px;border-radius:999px;
background:var(--accent-soft);color:#bff3da;display:flex;align-items:center;gap:6px;font-weight:600}
.countbadge .d{width:6px;height:6px;border-radius:50%;background:var(--accent);
box-shadow:0 0 9px var(--accent)}
.meta{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.chip{font-size:11px;padding:3px 9px;border-radius:999px;border:1px solid var(--border);
color:var(--text-dim);display:flex;align-items:center;gap:5px;font-family:var(--mono)}
.chip.dirty{color:var(--dirty);border-color:rgba(232,161,60,.32)}
.chip .gd{width:6px;height:6px;border-radius:50%;background:var(--dirty)}
.path{font-family:var(--mono);font-size:11px;color:var(--text-faint);
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:-2px}
/* session rows (1 project : N sessions) */
.sessions{display:flex;flex-direction:column;gap:7px}
.srow{display:flex;align-items:center;gap:10px;padding:9px 11px;border-radius:10px;
background:rgba(255,255,255,.025);border:1px solid var(--border);cursor:pointer;
transition:.15s;position:relative}
.srow::before{content:"";position:absolute;left:0;top:8px;bottom:8px;width:2px;border-radius:2px;
background:var(--rail,transparent)}
.srow:hover{background:var(--accent-soft);border-color:var(--accent-line)}
.srow.working{--rail:var(--working)} .srow.waiting{--rail:var(--waiting)} .srow.idle{--rail:var(--idle)}
.srow .st{width:8px;height:8px;border-radius:50%;flex:0 0 auto;margin-left:3px}
.st.working{background:var(--working);box-shadow:0 0 9px var(--working)}
.st.waiting{background:var(--waiting);box-shadow:0 0 9px var(--waiting);animation:blink 1.1s steps(2) infinite}
.st.idle{background:var(--idle)}
@keyframes blink{50%{opacity:.25}}
.srow .stitle{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.srow .smeta{font-size:11px;color:var(--text-faint);font-family:var(--mono);white-space:nowrap}
.srow .mir{font-size:10px;color:var(--text-dim);background:rgba(255,255,255,.06);
padding:2px 7px;border-radius:999px;white-space:nowrap}
.srow .x{color:var(--text-faint);font-size:13px;padding:2px 5px;border-radius:6px;transition:.12s}
.srow .x:hover{color:var(--red);background:rgba(255,107,107,.13)}
.spush{margin-left:auto}
/* empty project preview */
.thumb.empty{height:96px;border-radius:10px;border:1px dashed var(--border-strong);
background:rgba(255,255,255,.015);display:grid;place-items:center;color:var(--text-faint)}
.thumb.empty .plus{font-size:13px;color:var(--accent);
border:1px dashed var(--accent-line);padding:7px 16px;border-radius:999px}
.actions{display:flex;gap:8px;margin-top:2px}
.btn{all:unset;cursor:pointer;flex:1;text-align:center;font-size:12px;font-weight:680;
padding:9px;border-radius:10px;background:var(--accent);color:#08120c;transition:.15s}
.btn:hover{filter:brightness(1.07)}
.btn.new{background:var(--accent-soft);color:#bff3da;box-shadow:inset 0 0 0 1px var(--accent-line)}
.btn.shell{background:rgba(255,255,255,.07);color:var(--text)}
.btn.ghost{flex:0 0 auto;padding:9px 13px;background:transparent;color:var(--text-dim);
border:1px solid var(--border)}
.btn.ghost:hover{border-color:var(--border-strong);color:var(--text)}
.card.add{border-style:dashed;align-items:center;justify-content:center;
color:var(--text-faint);min-height:236px;gap:6px;cursor:pointer}
.card.add:hover{color:var(--text);border-color:var(--accent-line)}
.card.add .big{font-size:30px;color:var(--accent)}
.note{margin-top:28px;color:var(--text-faint);font-size:12px;text-align:center;line-height:1.7}
</style>
</head>
<body>
<div class="topbar">
<div class="brand"><span class="dot"></span> web-terminal</div>
<div class="seg">
<button>Sessions</button>
<button class="active">Projects <span class="mini">2</span></button>
</div>
<div class="spacer"></div>
<div class="icns"><button></button><button>🗂</button><button></button></div>
</div>
<div class="wrap">
<div class="head">
<h1>Projects</h1>
<span class="sub">5 found · 2 running · 4 sessions</span>
<span class="grow"></span>
<div class="search">🔍 <input placeholder="search projects…"></div>
</div>
<div class="grid">
<!-- project with MULTIPLE sessions (1:N) -->
<div class="card running">
<div class="crow">
<span class="star"></span>
<span class="name">web-terminal</span>
<span class="countbadge"><span class="d"></span>3 sessions</span>
</div>
<div class="meta">
<span class="chip">⎇ main</span>
<span class="chip dirty"><span class="gd"></span>dirty</span>
<span class="chip">2h ago</span>
</div>
<div class="path">~/Documents/git/web-terminal</div>
<div class="sessions">
<div class="srow working">
<span class="st working"></span>
<span class="stitle">claude</span>
<span class="smeta">⚙ working</span>
<span class="mir spush">👥 2</span>
<span class="x"></span>
</div>
<div class="srow waiting">
<span class="st waiting"></span>
<span class="stitle">claude #2</span>
<span class="smeta">⏳ waiting approval</span>
<span class="x spush"></span>
</div>
<div class="srow idle">
<span class="st idle"></span>
<span class="stitle">shell · npm test</span>
<span class="smeta">✓ idle</span>
<span class="x spush"></span>
</div>
</div>
<div class="actions">
<button class="btn new"> New claude</button>
<button class="btn ghost"></button>
</div>
</div>
<!-- project with ONE session -->
<div class="card running">
<div class="crow">
<span class="name">colacoder-api</span>
<span class="countbadge"><span class="d"></span>1 session</span>
</div>
<div class="meta">
<span class="chip">⎇ feat/auth</span>
<span class="chip">5d ago</span>
</div>
<div class="path">~/Documents/git/colacoder-api</div>
<div class="sessions">
<div class="srow idle">
<span class="st idle"></span>
<span class="stitle">claude</span>
<span class="smeta">✓ idle · 20m</span>
<span class="x spush"></span>
</div>
</div>
<div class="actions">
<button class="btn new"> New claude</button>
<button class="btn ghost"></button>
</div>
</div>
<!-- idle project (0 sessions) -->
<div class="card">
<div class="crow">
<span class="star"></span>
<span class="name">dotfiles</span>
<span class="badge idle">idle</span>
</div>
<div class="meta">
<span class="chip">⎇ main</span>
<span class="chip">12d ago</span>
</div>
<div class="path">~/.dotfiles</div>
<div class="thumb empty"><span class="plus"> start claude here</span></div>
<div class="actions">
<button class="btn">Open ▸ claude</button>
<button class="btn ghost"></button>
</div>
</div>
<!-- non-git folder (0 sessions) -->
<div class="card">
<div class="crow">
<span class="name">scratch</span>
<span class="badge idle">idle</span>
</div>
<div class="meta">
<span class="chip" style="opacity:.6">not a git repo</span>
</div>
<div class="path">~/scratch</div>
<div class="thumb empty"><span class="plus"> start shell here</span></div>
<div class="actions">
<button class="btn shell">Open ▸ shell</button>
<button class="btn ghost"></button>
</div>
</div>
<!-- add folder -->
<div class="card add">
<div class="big"></div>
<div>Add folder…</div>
<div style="font-size:11px;opacity:.7">browse a path to track</div>
</div>
</div>
<div class="note">UI mockup · 暖灰底 + 翡翠绿强调色(无蓝/紫)· 状态色working 绿 / waiting 琥珀 / idle 中性灰 · 一项目可挂多 session每行可单独进入或 ✕Kill。</div>
</div>
</body>
</html>