polish(v0.6): make "New session" a grid tile instead of a heavy header button
The big solid-amber "+ New session" button clashed with the refined segmented control. Replace it with a dashed "+" tile that leads the session grid (same size as the session cards, re-prepended each refresh), so it reads as a natural "create" cell. Header is now just the title + Sessions/Projects toggle; the redundant empty-state message is gone (the tile is the CTA). Frontend-only (launcher.ts + style.css). Verified: web typecheck + build clean, preview-grid tests green, in-browser the grid leads with the New-session tile followed by the session cards (Open/Kill).
This commit is contained in:
@@ -146,6 +146,14 @@
|
|||||||
- **commit**: <hash 或 N/A>
|
- **commit**: <hash 或 N/A>
|
||||||
======================================================= -->
|
======================================================= -->
|
||||||
|
|
||||||
|
### 2026-06-30 · v0.6 "New session" 改为网格卡片(去掉别扭的大按钮)
|
||||||
|
|
||||||
|
- **状态**: `[x]` DONE。web typecheck 干净 · `build:web` OK · 真浏览器验证通过。
|
||||||
|
- **需求**(用户): 头部那个大的实心琥珀 "+ New session" 按钮很别扭(与精致的分段 pill 不协调)。
|
||||||
|
- **改动**(纯前端 `public/launcher.ts` + style): 删头部 `.launcher-new` 按钮 + `.launcher-actions`;改为 grid 内的 **`.mg-new-card` 虚线"+ New session"瓦片**(与 session 卡同尺寸,始终排在网格第一格,每次 refresh 重新 prepend),hover 变琥珀。删冗余 `.mg-empty` 空态(瓦片即 CTA)。头部只剩标题 + 段控,更干净。
|
||||||
|
- **验证**: `npx tsc -p tsconfig.web.json` 干净;`build:web` OK;`preview-grid` 测试 14 全绿;真浏览器:Sessions 网格首格为虚线 New 瓦片 + 其后 session 卡(Open/Kill),无旧大按钮。
|
||||||
|
- **commit**: (本次提交)
|
||||||
|
|
||||||
### 2026-06-30 · v0.6 删除 manage 独立页 — Sessions 选择器即会话管理
|
### 2026-06-30 · v0.6 删除 manage 独立页 — Sessions 选择器即会话管理
|
||||||
|
|
||||||
- **状态**: `[x]` DONE。**453 测试全绿** · web typecheck 干净 · `build:web` OK(仅 main,无 manage 产物)· 真浏览器验证通过。
|
- **状态**: `[x]` DONE。**453 测试全绿** · web typecheck 干净 · `build:web` OK(仅 main,无 manage 产物)· 真浏览器验证通过。
|
||||||
|
|||||||
@@ -42,16 +42,20 @@ export function mountLauncher(host: HTMLElement, hooks: LauncherHooks): Launcher
|
|||||||
const head = el('div', 'launcher-head')
|
const head = el('div', 'launcher-head')
|
||||||
head.append(el('div', 'launcher-title', 'Your sessions'))
|
head.append(el('div', 'launcher-title', 'Your sessions'))
|
||||||
const sub = el('div', 'launcher-sub', '')
|
const sub = el('div', 'launcher-sub', '')
|
||||||
const actions = el('div', 'launcher-actions')
|
head.append(sub)
|
||||||
const newBtn = el('button', 'launcher-new', '+ New session')
|
|
||||||
newBtn.addEventListener('click', () => hooks.onNew())
|
|
||||||
actions.append(newBtn)
|
|
||||||
head.append(sub, actions)
|
|
||||||
root.append(head)
|
root.append(head)
|
||||||
|
|
||||||
const grid = el('div', 'mg-grid')
|
const grid = el('div', 'mg-grid')
|
||||||
root.append(grid)
|
root.append(grid)
|
||||||
|
|
||||||
|
// "New session" is a tile that leads the grid (matches the session cards),
|
||||||
|
// instead of a heavy header button. Re-prepended on every refresh.
|
||||||
|
const newTile = el('button', 'mg-new-card')
|
||||||
|
newTile.title = 'Start a new session'
|
||||||
|
newTile.setAttribute('aria-label', 'New session')
|
||||||
|
newTile.append(el('div', 'mg-new-plus', '+'), el('div', 'mg-new-label', 'New session'))
|
||||||
|
newTile.addEventListener('click', () => hooks.onNew())
|
||||||
|
|
||||||
const cards = new Map<string, PreviewCard>()
|
const cards = new Map<string, PreviewCard>()
|
||||||
let timer: ReturnType<typeof setInterval> | null = null
|
let timer: ReturnType<typeof setInterval> | null = null
|
||||||
|
|
||||||
@@ -78,6 +82,9 @@ export function mountLauncher(host: HTMLElement, hooks: LauncherHooks): Launcher
|
|||||||
? `${sessions.length} running on this host — pick one to open`
|
? `${sessions.length} running on this host — pick one to open`
|
||||||
: 'No sessions running yet'
|
: 'No sessions running yet'
|
||||||
|
|
||||||
|
// Keep the New-session tile as the first grid cell.
|
||||||
|
if (grid.firstChild !== newTile) grid.prepend(newTile)
|
||||||
|
|
||||||
const seen = new Set<string>()
|
const seen = new Set<string>()
|
||||||
for (const s of sessions) {
|
for (const s of sessions) {
|
||||||
seen.add(s.id)
|
seen.add(s.id)
|
||||||
@@ -99,10 +106,6 @@ export function mountLauncher(host: HTMLElement, hooks: LauncherHooks): Launcher
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
grid.querySelector('.mg-empty')?.remove()
|
|
||||||
if (sessions.length === 0) {
|
|
||||||
grid.append(el('div', 'mg-empty', 'No running sessions. Click “New session” to start one.'))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -711,18 +711,35 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
.launcher-new {
|
/* "New session" tile — leads the session grid, matching the session cards. */
|
||||||
background: var(--accent);
|
.mg-new-card {
|
||||||
color: var(--on-accent);
|
display: flex;
|
||||||
border: none;
|
flex-direction: column;
|
||||||
border-radius: 8px;
|
align-items: center;
|
||||||
padding: 9px 16px;
|
justify-content: center;
|
||||||
font: inherit;
|
gap: 8px;
|
||||||
font-weight: 600;
|
min-height: 200px;
|
||||||
|
background: none;
|
||||||
|
border: 2px dashed var(--border-strong);
|
||||||
|
border-radius: 12px;
|
||||||
|
color: var(--text-dim);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
transition: border-color 0.12s ease, color 0.12s ease, background 0.12s ease;
|
||||||
}
|
}
|
||||||
.launcher-new:hover {
|
.mg-new-card:hover {
|
||||||
background: var(--accent-2);
|
border-color: var(--accent);
|
||||||
|
color: var(--accent);
|
||||||
|
background: var(--accent-soft);
|
||||||
|
}
|
||||||
|
.mg-new-plus {
|
||||||
|
font-size: 34px;
|
||||||
|
font-weight: 300;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.mg-new-label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Session Manager page (manage.html) ──────────────────────────── */
|
/* ── Session Manager page (manage.html) ──────────────────────────── */
|
||||||
|
|||||||
Reference in New Issue
Block a user