console: GitHub 风格(Primer)
保持一页式控制台排版与全部功能、API 不变,只换视觉: 深色顶栏 #24292f、Primer 浅色配色(边框 #d0d7de、链接蓝 #0969da、绿主按钮 #2da44e)、6px 圆角方框、系统字体与 等宽 ID/trace;任务列表改 issues 式(状态圆点 + 标题 + 灰色元信息);对话改评论时间线(白框 + 头部 + 正文, 竖线连接),灰/蓝气泡已移除;自动选项目与继续消息历史 不受影响。console 标记单测本地 53 项通过。
This commit is contained in:
1 parent
bbe02efc14
commit
e90c885290
6 files changed
+171
-158
No files matched your search
@@ -19,17 +19,13 @@ import SkillsToolsPanel from "./sections/SkillsToolsPanel";
|
||||
import AutomationsSection from "./sections/AutomationsSection";
|
||||
import TriageSection from "./sections/TriageSection";
|
||||
|
||||
// Layout only: ONE scrollable console page, Muse web/desktop tokens
|
||||
// (white, hairlines, grey/blue bubbles) but console ordering — no
|
||||
// icon-rail column, no left list column, no right panel column, no
|
||||
// view switching. Everything is on the page: a slim sticky top bar
|
||||
// (name + real connection status + health + quota + refresh stamp +
|
||||
// anchor nav), a data-cards row, then every module as a section in
|
||||
// order. The old right panel's content moved here: its profile/status
|
||||
// line is the top bar, its 今天 list is redundant with the full task
|
||||
// list section, and its detail/context panels sit under their own
|
||||
// sections below (detail under 对话, members under 项目, and so on).
|
||||
// The old icon rail's module switching is the anchor nav.
|
||||
// Layout only: ONE scrollable console page in GitHub Primer style —
|
||||
// a dark header bar (name + real connection status + health + quota
|
||||
// + refresh stamp + anchor nav as header links), a data-cards row,
|
||||
// then every module as a bordered section in order. No icon-rail
|
||||
// column, no left list column, no right panel column, no view
|
||||
// switching. Detail/context panels sit under their own sections
|
||||
// below (detail under 对话, members under 项目, and so on).
|
||||
const NAV: Array<[string, string]> = [
|
||||
["#sec-dispatch", "派发"], ["#sec-tasks", "任务"], ["#sec-conv", "对话"],
|
||||
["#sec-projects", "项目"], ["#sec-env", "环境"], ["#sec-workers", "Workers"],
|
||||
|
||||
@@ -18,16 +18,19 @@ export function useAutoFollow(dep: unknown) {
|
||||
return { ref, following, onScroll };
|
||||
}
|
||||
|
||||
// GitHub-style comment box, not a chat bubble: full-width white box
|
||||
// with a subtle header row (role label only — no timestamp or sender
|
||||
// is invented; the backend provides neither) and the body below.
|
||||
// Status entries are plain muted timeline text on the timeline line.
|
||||
export function ChatBubble({ msg }: { msg: ChatMessage }) {
|
||||
if (msg.role === "status") {
|
||||
return <div className="chat-status">{msg.text}</div>;
|
||||
}
|
||||
const author = msg.label || (msg.role === "user" ? "用户" : msg.role === "assistant" ? "助手" : "工具");
|
||||
return (
|
||||
<div className={"chat-row " + msg.role}>
|
||||
<div className={"chat-bubble " + msg.role}>
|
||||
{msg.label ? <div className="chat-label">{msg.label}</div> : null}
|
||||
<div className="chat-text">{msg.text}</div>
|
||||
</div>
|
||||
<div className={"gh-comment " + msg.role}>
|
||||
<div className="gh-comment-header"><span className="gh-comment-author">{author}</span></div>
|
||||
<div className="gh-comment-body">{msg.text}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -54,25 +57,24 @@ export function ChatInput({ onSend, disabled, placeholder }: {
|
||||
onSend(v);
|
||||
setText("");
|
||||
};
|
||||
// Pill input bar, Muse screenshot style: the textarea is the pill
|
||||
// itself, and send is a light-blue circular arrow. No mic or
|
||||
// attachment button here: the continue chat has no voice or
|
||||
// attachment API (attachments live in Dispatch), so a mic/+ icon
|
||||
// would be a dead button; the left list header's + is the new-task
|
||||
// entry instead.
|
||||
// GitHub comment box: textarea on top, a subtle footer row with the
|
||||
// green primary send button. No mic or attachment button here: the
|
||||
// continue chat has no voice or attachment API (attachments live in
|
||||
// Dispatch), so a mic/+ icon would be a dead button.
|
||||
return (
|
||||
<div className="chat-input-bar">
|
||||
<div className="gh-comment-box">
|
||||
<textarea
|
||||
aria-label="会话输入"
|
||||
className="chat-input"
|
||||
rows={1}
|
||||
rows={3}
|
||||
placeholder={placeholder || "消息"}
|
||||
value={text}
|
||||
disabled={disabled}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); send(); } }}
|
||||
/>
|
||||
<button type="button" className="chat-send" aria-label="发送" disabled={disabled || !text.trim()} onClick={send}>↑</button>
|
||||
<div className="gh-comment-footer">
|
||||
<button type="button" className="primary" aria-label="发送" disabled={disabled || !text.trim()} onClick={send}>发送</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
import { useConsole } from "../context";
|
||||
import { shortId } from "../api/client";
|
||||
|
||||
// Left list panel, Muse screenshot style: rounded search on top, a
|
||||
// 主要聊天 section header with a + button, then the task list. The
|
||||
// search input IS the existing task search (id/prompt); the status and
|
||||
// executor filters are kept as a compact row below it — the screenshot
|
||||
// has no filters, but dropping them would cut functionality, so they
|
||||
// stay, just compact. List rows show the prompt truncated on one line
|
||||
// with a status dot, short id, status and executor below it; the
|
||||
// selected row is highlighted grey, as in the screenshot.
|
||||
// GitHub issues-style task list: search on top, the project selector
|
||||
// (the auto-project fix — do not remove it), a 主要聊天 header with a
|
||||
// + button, then hairline rows with a Primer status dot at the left,
|
||||
// a 14px title and a 12px muted meta line. The search input IS the
|
||||
// existing task search (id/prompt); status and executor filters stay
|
||||
// as a compact row below it. The selected row gets the light
|
||||
// blue-grey background (#ddf4ff), not a bubble.
|
||||
export default function TaskListSection({ onNew }: { onNew: () => void }) {
|
||||
const ctx = useConsole();
|
||||
return (
|
||||
@@ -46,18 +45,18 @@ export default function TaskListSection({ onNew }: { onNew: () => void }) {
|
||||
: !ctx.projectId ? <div className="muted">先选项目</div>
|
||||
: ctx.filteredTasks.length === 0 ? <div className="muted">{ctx.tasks.length ? "没有符合筛选条件的任务" : "该项目暂无任务"}</div>
|
||||
: (
|
||||
<ul className="muse-list">
|
||||
<ul className="issue-list">
|
||||
{ctx.filteredTasks.slice().reverse().map((t) => (
|
||||
<li key={t.id} className={"muse-item" + (ctx.currentTask?.id === t.id ? " selected" : "")} onClick={() => ctx.showDetail(t.id)}>
|
||||
<div className="muse-item-title">
|
||||
{t.plan ? "[计划] " : ""}{t.forked_from ? "[分支] " : ""}{t.coordinator_parts ? "[协调] " : ""}{t.parent_task_id ? "[协调子任务] " : ""}{String(t.prompt || shortId(t.id)).slice(0, 60)}
|
||||
</div>
|
||||
<div className="muse-item-sub">
|
||||
<span className={"task-dot st-" + t.status} />
|
||||
<span>{shortId(t.id)}</span>
|
||||
<span className={"st-" + t.status}>{t.status}</span>
|
||||
<span>{t.executor || ""}</span>
|
||||
</div>
|
||||
<li key={t.id} className={"issue-item" + (ctx.currentTask?.id === t.id ? " selected" : "")} onClick={() => ctx.showDetail(t.id)}>
|
||||
<span className={"issue-state st-" + t.status} aria-hidden="true" />
|
||||
<span>
|
||||
<div className="issue-title">
|
||||
{t.plan ? "[计划] " : ""}{t.forked_from ? "[分支] " : ""}{t.coordinator_parts ? "[协调] " : ""}{t.parent_task_id ? "[协调子任务] " : ""}{String(t.prompt || shortId(t.id)).slice(0, 60)}
|
||||
</div>
|
||||
<div className="issue-meta">
|
||||
{shortId(t.id)} · <span className={"st-" + t.status}>{t.status}</span> · {t.executor || ""}{t.updated_at ? " · " + new Date(t.updated_at * 1000).toLocaleString() : ""}
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function TracePanel() {
|
||||
<div className="chat-column">
|
||||
<ChatList messages={messages} empty="(暂无链路条目)" />
|
||||
</div>
|
||||
<div className="muted">对话时间线:首条是本任务 prompt(用户);助手回复来自 message 条目,命令/文件/工具/调用是工具气泡,计划/思考/子代理开始结束是居中状态提示。流式进行中时新条目实时追加;你在底部时自动跟随,往上翻时暂停跟随,点“回到最新”恢复。</div>
|
||||
<div className="muted">对话时间线:首条是本任务 prompt(用户);助手回复来自 message 条目,命令/文件/工具/调用是工具评论框,计划/思考/子代理开始结束是时间线上的状态文字。流式进行中时新条目实时追加;你在底部时自动跟随,往上翻时暂停跟随,点“回到最新”恢复。</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,135 +1,151 @@
|
||||
/* Single token source — Muse web/desktop palette (2026-10-29 redesign).
|
||||
This supersedes the previous v3 porcelain/ink/seal palette: white page,
|
||||
light-grey hairlines, grey assistant bubbles, light-blue user bubbles,
|
||||
blue accent, green only for 已连接. The old pine/seal colours are gone;
|
||||
the button class name "seal" is retained only so Dispatch/DetailActions
|
||||
need no change — it now renders in screenshot blue. No coloured page
|
||||
backgrounds, no big header bar, no shadows. Sans-serif only. */
|
||||
/* Single token source — GitHub Primer (light) visual language.
|
||||
This supersedes the Muse web/desktop palette: Primer canvas,
|
||||
borders, foregrounds and accents only. No grey/blue chat bubbles,
|
||||
no pill shapes, no coloured page backgrounds, no shadows beyond
|
||||
GitHub's hairline button shadow. Layout is unchanged (one
|
||||
scrollable console page: dark header + data cards + stacked
|
||||
sections); only the visual system moved to Primer. */
|
||||
:root{
|
||||
--text:#1d2129; --muted:#667085; --line:#e4e7ec; --line-strong:#d0d5dd;
|
||||
--paper:#ffffff; --card:#ffffff;
|
||||
--bubble-assistant:#f2f2f2; --bubble-user:#bfe0ff;
|
||||
--accent:#3b82f6; --accent-dark:#2563eb; --accent-soft:#eef4ff;
|
||||
--green:#22c55e; --success:#16a34a; --danger:#b42318; --danger-soft:#fef3f2;
|
||||
--amber:#b54708; --purple:#6941c6;
|
||||
--radius:12px; --radius-sm:10px; --shadow:none;
|
||||
--sans:-apple-system,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
|
||||
--mono:"IBM Plex Mono",Menlo,Consolas,monospace;
|
||||
--ctl:40px;
|
||||
--text:#1f2328; --muted:#656d76; --subtle:#6e7781;
|
||||
--line:#d0d7de; --line-muted:#d8dee4;
|
||||
--paper:#ffffff; --card:#ffffff; --subtle-bg:#f6f8fa; --inset-bg:#f6f8fa;
|
||||
--accent:#0969da; --accent-emphasis:#0969da;
|
||||
--green:#2da44e; --green-hover:#2c974b; --success:#1a7f37;
|
||||
--danger:#d1242f; --danger-bg:#ffebe9;
|
||||
--attention:#9a6700; --done:#8250df; --selected-bg:#ddf4ff;
|
||||
--radius:6px; --shadow:0 1px 0 rgba(27,31,36,.04);
|
||||
--sans:-apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif;
|
||||
--mono:ui-monospace,SFMono-Regular,SFMono-Regular,Menlo,Consolas,"Liberation Mono",monospace;
|
||||
--ctl:32px;
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
html,body,#root{height:100%}
|
||||
body{font-family:var(--sans);margin:0;color:var(--text);background:#fff;line-height:1.6;font-size:14px}
|
||||
body{font-family:var(--sans);margin:0;color:var(--text);background:#fff;line-height:1.5;font-size:14px}
|
||||
a{color:var(--accent);text-underline-offset:3px}
|
||||
:focus-visible{outline:3px solid var(--accent);outline-offset:2px}
|
||||
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
|
||||
@media (prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;transition:none!important}}
|
||||
.muted{color:var(--muted);font-size:13px;line-height:1.6}
|
||||
.muted{color:var(--muted);font-size:12px;line-height:1.5}
|
||||
.err{color:var(--danger)} .ok{color:var(--success)}
|
||||
button{cursor:pointer;font-weight:600;border-radius:999px}
|
||||
/* GitHub buttons: secondary by default, 6px radius, 5px 16px padding.
|
||||
"primary" and the legacy "seal" name are the green primary action
|
||||
(dispatch / submit), exactly like GitHub's primary button. */
|
||||
button{cursor:pointer;font-weight:500;border-radius:var(--radius);border:1px solid var(--line);background:#fff;color:var(--text);box-shadow:var(--shadow)}
|
||||
button:hover{background:var(--subtle-bg)}
|
||||
button:disabled{opacity:.45;cursor:not-allowed;box-shadow:none}
|
||||
button.primary{background:var(--accent);border-color:var(--accent);color:#fff}
|
||||
button.primary:hover{background:var(--accent-dark)}
|
||||
/* "seal" is a legacy class name only; its colour is screenshot blue now. */
|
||||
button.seal{background:var(--accent);border-color:var(--accent);color:#fff}
|
||||
button.seal:hover{background:var(--accent-dark)}
|
||||
button.danger{color:var(--danger);border-color:#fecdca;background:var(--danger-soft)}
|
||||
button.danger:hover{background:#fee4e2}
|
||||
.icon-btn{width:32px;height:32px;padding:0;display:grid;place-items:center;border:1px solid var(--line);border-radius:50%;background:#fff;color:var(--text);font-size:16px;line-height:1}
|
||||
.icon-btn:hover{background:#f9fafb}
|
||||
button.primary,button.seal{background:var(--green);border-color:rgba(27,31,36,.15);color:#fff}
|
||||
button.primary:hover,button.seal:hover{background:var(--green-hover)}
|
||||
button.danger{color:var(--danger);border-color:var(--line);background:#fff}
|
||||
button.danger:hover{background:var(--danger-bg);color:var(--danger)}
|
||||
.icon-btn{width:32px;height:32px;padding:0;display:grid;place-items:center;border:1px solid var(--line);border-radius:var(--radius);background:#fff;color:var(--text);font-size:16px;line-height:1}
|
||||
.icon-btn:hover{background:var(--subtle-bg)}
|
||||
|
||||
/* Dashboard shell: ONE scrollable console page, same Muse tokens.
|
||||
Slim sticky top bar (name + status + health + quota + refresh
|
||||
stamp + anchor nav), a data-cards row, then every module as a
|
||||
section. No icon-rail column, no left list column, no right
|
||||
panel column — the old shell classes are gone with them. */
|
||||
.dash-topbar{position:sticky;top:0;z-index:10;background:#fff;border-bottom:1px solid var(--line);padding:10px 20px 8px}
|
||||
/* Dashboard shell: ONE scrollable console page.
|
||||
Dark GitHub-style header (#24292f, white text) with the anchor nav
|
||||
inside it, a data-cards row, then every module as a section. */
|
||||
.dash-topbar{position:sticky;top:0;z-index:10;background:#24292f;color:#fff;border-bottom:1px solid rgba(255,255,255,.15);padding:10px 20px 8px}
|
||||
.dash-topbar .muted{color:rgba(255,255,255,.75)}
|
||||
.dash-topbar-row{display:flex;gap:14px;align-items:center;flex-wrap:wrap}
|
||||
.dash-brand{font-weight:700;font-size:17px}
|
||||
.dash-status{font-size:13px;font-weight:600;color:var(--muted)}
|
||||
.dash-status.ok{color:var(--green)}
|
||||
.dash-brand{font-weight:600;font-size:16px;color:#fff}
|
||||
.dash-status{font-size:13px;font-weight:600;color:rgba(255,255,255,.75)}
|
||||
.dash-status.ok{color:#2da44e}
|
||||
.dash-stamp{margin-left:auto}
|
||||
.dash-nav{display:flex;gap:4px;flex-wrap:wrap;margin-top:8px}
|
||||
.dash-nav a{color:var(--text);text-decoration:none;font-size:13px;font-weight:600;padding:6px 12px;border-radius:999px}
|
||||
.dash-nav a:hover{background:#f2f2f2}
|
||||
.dash-nav a{color:#fff;text-decoration:none;font-size:13px;font-weight:600;padding:6px 12px;border-radius:var(--radius)}
|
||||
.dash-nav a:hover{background:rgba(255,255,255,.12);text-decoration:none}
|
||||
.dash-page{max-width:1180px;margin:0 auto;padding:20px;display:flex;flex-direction:column;gap:20px}
|
||||
.dash-section{scroll-margin-top:130px;display:flex;flex-direction:column;gap:20px}
|
||||
.dash-section.card{padding:20px}
|
||||
.dash-section{scroll-margin-top:130px;display:flex;flex-direction:column;gap:16px}
|
||||
.dash-section.card{padding:16px}
|
||||
.dash-cards{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
|
||||
.dash-card{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:16px 18px;min-width:0}
|
||||
.dash-card-label{color:var(--muted);font-size:13px;font-weight:600}
|
||||
.dash-card-value{font-size:28px;font-weight:700;line-height:1.3;overflow-wrap:anywhere}
|
||||
.dash-card{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:16px;min-width:0}
|
||||
.dash-card-label{color:var(--muted);font-size:12px;font-weight:600}
|
||||
.dash-card-value{font-size:24px;font-weight:600;line-height:1.3;overflow-wrap:anywhere}
|
||||
|
||||
|
||||
/* Cards: flat white sections with a hairline border, no shadow. */
|
||||
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);box-shadow:none;padding:20px}
|
||||
.card h2{font-size:17px;margin:0 0 12px;font-weight:600}
|
||||
.card h3{font-size:15px;margin:24px 0 12px;padding-top:20px;border-top:1px solid var(--line);font-weight:600}
|
||||
/* Boxes: bordered, 6px radius, white body, subtle header row. */
|
||||
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);box-shadow:none;padding:16px}
|
||||
.card h2{font-size:14px;margin:0 0 12px;font-weight:600}
|
||||
.card h3{font-size:14px;margin:24px 0 12px;padding-top:16px;border-top:1px solid var(--line);font-weight:600}
|
||||
.card h3:first-of-type{border-top:0;padding-top:0}
|
||||
.composer h2{font-size:20px}
|
||||
.composer textarea.prompt{min-height:148px;font-size:16px;padding:16px 18px;border-radius:12px}
|
||||
.composer h2{font-size:16px}
|
||||
.composer textarea.prompt{min-height:148px;font-size:14px;padding:12px;border-radius:var(--radius)}
|
||||
.composer textarea.coord{font-family:var(--mono);font-size:13px}
|
||||
/* Unified controls: same-row controls are all 40px */
|
||||
/* Unified controls: same-row controls are all 32px (GitHub height) */
|
||||
.bar{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:12px 0}
|
||||
.bar > button,.bar > label{display:inline-flex;align-items:center;height:var(--ctl);min-height:var(--ctl);padding:0 16px;box-sizing:border-box;white-space:nowrap}
|
||||
.bar > input,.bar > select{height:var(--ctl);min-height:var(--ctl)}
|
||||
input,select,textarea,button{font:inherit;font-size:14px;padding:10px 13px;border-radius:var(--radius-sm);border:1px solid var(--line-strong);background:#fff;color:var(--text)}
|
||||
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(59,130,246,.15)}
|
||||
button:hover{box-shadow:none}
|
||||
select{appearance:none;-webkit-appearance:none;cursor:pointer;padding-right:34px;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%23667085' stroke-width='1.5' stroke-linecap='round'/></svg>");background-repeat:no-repeat;background-position:right 12px center}
|
||||
input,select,textarea,button{font:inherit;font-size:14px;padding:5px 12px;border-radius:var(--radius);border:1px solid var(--line);background:#fff;color:var(--text)}
|
||||
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(9,105,218,.3)}
|
||||
select{appearance:none;-webkit-appearance:none;cursor:pointer;padding-right:34px;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%23656d76' stroke-width='1.5' stroke-linecap='round'/></svg>");background-repeat:no-repeat;background-position:right 12px center}
|
||||
select::-ms-expand{display:none}
|
||||
select:disabled,input:disabled{color:var(--muted);background:#f9fafb;cursor:not-allowed}
|
||||
select:disabled,input:disabled{color:var(--muted);background:var(--subtle-bg);cursor:not-allowed}
|
||||
input[type="checkbox"]{width:16px;height:16px;accent-color:var(--accent)}
|
||||
input[type="file"]{height:var(--ctl);display:inline-flex;align-items:center;padding:0 12px;border:1px dashed var(--line-strong);border-radius:999px;background:#fff}
|
||||
input[type="file"]::file-selector-button{height:28px;padding:0 12px;margin-right:10px;border:0;border-radius:999px;background:#f2f2f2;color:var(--text);font:inherit;font-size:13px;cursor:pointer}
|
||||
textarea{width:100%;min-height:84px;resize:vertical;line-height:1.65;padding:12px 14px;border-radius:12px}
|
||||
.composer .bar label{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--line-strong);border-radius:999px;padding:7px 13px;background:#fff;cursor:pointer;font-size:13px;font-weight:600}
|
||||
input[type="file"]{height:var(--ctl);display:inline-flex;align-items:center;padding:0 12px;border:1px dashed var(--line);border-radius:var(--radius);background:#fff}
|
||||
input[type="file"]::file-selector-button{height:24px;padding:0 12px;margin-right:10px;border:1px solid var(--line);border-radius:var(--radius);background:var(--subtle-bg);color:var(--text);font:inherit;font-size:13px;cursor:pointer}
|
||||
textarea{width:100%;min-height:84px;resize:vertical;line-height:1.5;padding:12px;border-radius:var(--radius)}
|
||||
.composer .bar label{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--line);border-radius:var(--radius);padding:5px 12px;background:#fff;cursor:pointer;font-size:13px;font-weight:500}
|
||||
.composer .bar label:has(input:checked){background:var(--text);color:#fff;border-color:var(--text)}
|
||||
.stacked{margin-bottom:12px}
|
||||
.stacked + .bar{margin-top:0}
|
||||
/* Data lists: one shared list style, no per-section inline styles */
|
||||
/* Data lists: bordered rows, no coloured backgrounds */
|
||||
.data-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
|
||||
.data-list li{position:relative;margin:0;padding:10px 12px;background:#f9fafb;border:1px solid var(--line);border-radius:12px;line-height:1.6;display:flex;flex-wrap:wrap;align-items:center;gap:8px;overflow-wrap:anywhere}
|
||||
.data-list li{position:relative;margin:0;padding:8px 12px;background:#fff;border:1px solid var(--line);border-radius:var(--radius);line-height:1.5;display:flex;flex-wrap:wrap;align-items:center;gap:8px;overflow-wrap:anywhere}
|
||||
.data-list li .row-main{flex:1 1 200px;min-width:0}
|
||||
.data-list li button{flex:none}
|
||||
.data-list li.is-online,.data-list li.is-offline{padding-left:26px}
|
||||
.data-list li.is-online::before,.data-list li.is-offline::before{content:"";position:absolute;left:12px;top:17px;width:8px;height:8px;border-radius:50%}
|
||||
.data-list li.is-online::before{background:var(--green)}
|
||||
.data-list li.is-online::before,.data-list li.is-offline::before{content:"";position:absolute;left:12px;top:15px;width:8px;height:8px;border-radius:50%}
|
||||
.data-list li.is-online::before{background:var(--success)}
|
||||
.data-list li.is-offline::before{background:var(--danger)}
|
||||
.data-group{margin-bottom:12px}.data-group:last-child{margin-bottom:0}.data-group > b{display:block;margin-bottom:8px}
|
||||
/* Status colours (text only; dots use currentColor) */
|
||||
.st-queued{color:var(--muted)}.st-running{color:var(--amber);font-weight:700}.st-completed{color:var(--success)}.st-failed,.st-merge-failed{color:var(--danger)}.st-merged{color:var(--purple)}.st-interrupted{color:var(--amber)}
|
||||
/* Task table (kept for any table view; the left list is the primary list) */
|
||||
/* Status colours (Primer text; issue dots use the same classes) */
|
||||
.st-queued{color:var(--muted)}.st-running{color:var(--success);font-weight:600}.st-completed{color:var(--done)}.st-failed,.st-merge-failed{color:var(--danger)}.st-merged{color:var(--done)}.st-interrupted{color:var(--attention)}
|
||||
/* Task table */
|
||||
.table-wrap{border:0;border-top:1px solid var(--line);overflow:auto;background:var(--card)}
|
||||
table{border-collapse:collapse;width:100%;font-size:13px}
|
||||
th,td{padding:12px 16px;text-align:left;vertical-align:top;border-bottom:1px solid var(--line)}
|
||||
th{background:#f9fafb;color:var(--muted);font-size:12px;font-weight:600;white-space:nowrap;letter-spacing:.3px}
|
||||
th,td{padding:8px 16px;text-align:left;vertical-align:top;border-bottom:1px solid var(--line)}
|
||||
th{background:var(--subtle-bg);color:var(--muted);font-size:12px;font-weight:600;white-space:nowrap}
|
||||
tbody tr{cursor:pointer}
|
||||
tbody tr:hover{background:#f9fafb}
|
||||
tr.selected{background:#f2f2f2}
|
||||
td.prompt-col{font-size:15px;line-height:1.55}
|
||||
/* Result / error blocks: light, not dark — the screenshot has no dark log block */
|
||||
pre{background:#f9fafb;color:var(--text);border:1px solid var(--line);border-radius:12px;padding:16px 18px;overflow:auto;max-height:420px;white-space:pre-wrap;word-break:break-word;font-size:13px;font-family:var(--mono);line-height:1.7}
|
||||
.trace-box{background:#f9fafb;color:var(--text);border:1px solid var(--line);border-radius:12px;padding:16px 18px;max-height:520px;overflow:auto;font-size:13px;line-height:1.9;font-family:var(--mono)}
|
||||
tbody tr:hover{background:var(--subtle-bg)}
|
||||
tr.selected{background:var(--selected-bg)}
|
||||
td.prompt-col{font-size:14px;line-height:1.5}
|
||||
/* Result / error blocks and trace: subtle inset, monospace */
|
||||
pre{background:var(--inset-bg);color:var(--text);border:1px solid var(--line);border-radius:var(--radius);padding:16px;overflow:auto;max-height:420px;white-space:pre-wrap;word-break:break-word;font-size:13px;font-family:var(--mono);line-height:1.5}
|
||||
.trace-box{background:var(--inset-bg);color:var(--text);border:1px solid var(--line);border-radius:var(--radius);padding:16px;max-height:520px;overflow:auto;font-size:13px;line-height:1.5;font-family:var(--mono)}
|
||||
.trace-box .muted{color:var(--muted)}
|
||||
/* Chat: Muse screenshot bubbles. Assistant grey left, user light-blue
|
||||
right, dark text on both, rounded ~16px, max-width ~75%. One shared
|
||||
style for the trace timeline and the continue chat. */
|
||||
.conversation{display:flex;flex-direction:column;gap:20px}
|
||||
/* GitHub issues-style task list: hairline rows, status dot at left,
|
||||
14px title, 12px muted meta, selected row light blue-grey. */
|
||||
.search-box{display:flex;align-items:center;gap:8px;border:1px solid var(--line);border-radius:var(--radius);background:#fff;padding:0 12px;color:var(--muted)}
|
||||
.search-box input{flex:1;border:0;padding:5px 0}
|
||||
.search-box input:focus{box-shadow:none}
|
||||
.list-section-head{display:flex;align-items:center;justify-content:space-between;font-size:14px;font-weight:600;margin:12px 0 4px}
|
||||
.issue-list{list-style:none;margin:0;padding:0;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}
|
||||
.issue-item{padding:8px 16px;border-bottom:1px solid var(--line);cursor:pointer;display:flex;gap:10px;align-items:flex-start;background:#fff}
|
||||
.issue-item:last-child{border-bottom:0}
|
||||
.issue-item:hover{background:var(--subtle-bg)}
|
||||
.issue-item.selected{background:var(--selected-bg)}
|
||||
.issue-state{flex:none;width:16px;height:16px;margin-top:2px;border-radius:50%;background:var(--muted)}
|
||||
.issue-state.st-running,.issue-state.st-queued{background:var(--success)}
|
||||
.issue-state.st-completed,.issue-state.st-merged{background:var(--done)}
|
||||
.issue-state.st-failed,.issue-state.st-merge-failed{background:var(--danger)}
|
||||
.issue-state.st-interrupted{background:var(--attention)}
|
||||
.issue-title{font-size:14px;line-height:1.5;overflow-wrap:anywhere}
|
||||
.issue-meta{font-size:12px;color:var(--muted);line-height:1.5}
|
||||
/* Conversation as a GitHub timeline / comments: white comment boxes
|
||||
with a subtle header row, connected by a muted vertical line.
|
||||
No bubbles, no left/right alignment by role — every entry is a
|
||||
full-width comment. Status entries are plain muted timeline text. */
|
||||
.conversation{display:flex;flex-direction:column;gap:16px}
|
||||
.chat-column{max-width:100%;margin:0 auto;width:100%}
|
||||
.chat-list{position:relative;display:flex;flex-direction:column;gap:12px;max-height:none;overflow:visible;padding:8px 0}
|
||||
.chat-row{display:flex}.chat-row.user{justify-content:flex-end}.chat-row.assistant,.chat-row.tool{justify-content:flex-start}
|
||||
.chat-bubble{max-width:75%;padding:10px 14px;border-radius:16px;line-height:1.65;white-space:pre-wrap;word-break:break-word;color:var(--text)}
|
||||
.chat-bubble.user{background:var(--bubble-user);border-bottom-right-radius:4px}
|
||||
.chat-bubble.assistant{background:var(--bubble-assistant);border-bottom-left-radius:4px}
|
||||
.chat-bubble.tool{background:var(--bubble-assistant);font-family:var(--mono);font-size:13px;border-bottom-left-radius:4px}
|
||||
.chat-label{font-size:12px;color:var(--muted);margin-bottom:4px}
|
||||
.chat-status{text-align:center;font-size:12px;color:var(--muted)}
|
||||
.chat-follow{position:sticky;bottom:8px;align-self:center;background:var(--accent);border-color:var(--accent);color:#fff;z-index:2}
|
||||
.chat-input-bar{position:sticky;bottom:0;display:flex;gap:8px;align-items:center;background:#fff;border:1px solid var(--line);border-radius:999px;padding:6px 6px 6px 16px;box-shadow:0 1px 4px rgba(0,0,0,.06);z-index:2}
|
||||
.chat-input{flex:1;height:var(--ctl);min-height:var(--ctl);resize:none;border:0;background:transparent;padding:8px 0}
|
||||
.chat-input:focus{box-shadow:none;outline:none}
|
||||
.chat-send{width:36px;height:36px;border-radius:50%;background:var(--bubble-user);border:0;color:var(--accent-dark);padding:0;display:grid;place-items:center;font-size:18px;line-height:1;flex:none}
|
||||
.chat-send:disabled{opacity:.45;background:#f2f2f2;color:var(--muted)}
|
||||
.chat-list{position:relative;display:flex;flex-direction:column;gap:12px;max-height:none;overflow:visible;padding:4px 0 4px 20px;border-left:2px solid var(--line);margin-left:8px}
|
||||
.gh-comment{border:1px solid var(--line);border-radius:var(--radius);background:#fff;overflow:hidden}
|
||||
.gh-comment-header{background:var(--subtle-bg);border-bottom:1px solid var(--line);padding:8px 16px;font-size:13px}
|
||||
.gh-comment-author{font-weight:600;color:var(--text)}
|
||||
.gh-comment-body{padding:16px;white-space:pre-wrap;word-break:break-word;line-height:1.5}
|
||||
.gh-comment.tool .gh-comment-body{font-family:var(--mono);font-size:13px}
|
||||
.chat-status{font-size:12px;color:var(--muted);line-height:1.5}
|
||||
.chat-follow{position:sticky;bottom:8px;align-self:center;background:#fff;border:1px solid var(--line);color:var(--text);z-index:2}
|
||||
.gh-comment-box{border:1px solid var(--line);border-radius:var(--radius);background:#fff;overflow:hidden}
|
||||
.gh-comment-box textarea{border:0;border-radius:0;min-height:84px}
|
||||
.gh-comment-box textarea:focus{box-shadow:none}
|
||||
.gh-comment-footer{display:flex;justify-content:flex-end;gap:8px;padding:8px;border-top:1px solid var(--line);background:var(--subtle-bg)}
|
||||
.conv-divider{border-top:1px solid var(--line);margin:4px 0}
|
||||
@media (max-width:900px){
|
||||
.dash-cards{grid-template-columns:repeat(2,1fr)}
|
||||
@@ -145,5 +161,5 @@ pre{background:#f9fafb;color:var(--text);border:1px solid var(--line);border-rad
|
||||
.card{padding:16px}
|
||||
th:nth-child(6),td:nth-child(6),th:nth-child(9),td:nth-child(9){display:none}
|
||||
.bar > input[type="text"],.bar > input[type="password"],.bar > select{flex:1 1 100%}
|
||||
th,td{padding:10px 12px}
|
||||
th,td{padding:8px 12px}
|
||||
}
|
||||
Reference in new issue
Block a user