From be9fe07c2770d190b86769abc8faa121b98d317a Mon Sep 17 00:00:00 2001 From: xiaoxixi Date: Fri, 24 Jul 2026 09:18:25 +0800 Subject: [PATCH] feat(webui): Signal Deck design tokens and base styles --- webui/src/styles.css | 171 ++++++++++++++++++++++++++++--------------- 1 file changed, 112 insertions(+), 59 deletions(-) diff --git a/webui/src/styles.css b/webui/src/styles.css index 1561350..eb2ab75 100644 --- a/webui/src/styles.css +++ b/webui/src/styles.css @@ -1,59 +1,101 @@ +@font-face { + font-family: "Space Grotesk"; + src: url("/fonts/space-grotesk-500.woff2") format("woff2"); + font-weight: 500; font-style: normal; font-display: swap; +} +@font-face { + font-family: "Space Grotesk"; + src: url("/fonts/space-grotesk-700.woff2") format("woff2"); + font-weight: 700; font-style: normal; font-display: swap; +} +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono-400.woff2") format("woff2"); + font-weight: 400; font-style: normal; font-display: swap; +} +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono-700.woff2") format("woff2"); + font-weight: 700; font-style: normal; font-display: swap; +} + :root { - font-family: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; - color: #e8edf2; - background: #0d1117; - font-synthesis: none; - --bg: #0d1117; - --panel: #151a21; - --panel-2: #1b222c; - --sidebar: #10151c; - --header: rgb(13 17 23 / 82%); - --line: #28313d; - --muted: #8b96a5; - --text: #e8edf2; - --text-soft: #c2cad4; - --accent: #8b72ff; - --accent-hover: #9e89ff; - --accent-contrast: #ffffff; - --accent-soft: #231f3d; - --accent-border: #4d4089; + --font-ui: "Space Grotesk", ui-sans-serif, system-ui, "PingFang SC", "Microsoft YaHei", "Noto Sans SC", sans-serif; + --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Consolas, monospace; + color-scheme: dark; + font-family: var(--font-ui); + color: #e7ecf3; + background: #0b1017; + --bg: #0b1017; + --panel: #0e1520; + --panel-2: #131c29; + --sidebar: #0d131c; + --header: rgb(11 16 23 / 84%); + --line: #1d2733; + --line-strong: #2c3a4c; + --muted: #8fa3b8; + --faint: #5b6b7e; + --text: #e7ecf3; + --text-soft: #b8c4d4; + --accent: #ffb454; + --accent-hover: #ffc370; + --accent-contrast: #1a1206; + --accent-soft: rgb(255 180 84 / 12%); + --accent-border: rgb(255 180 84 / 35%); + --signal: #2dd4bf; + --signal-soft: rgb(45 212 191 / 12%); + --signal-border: rgb(45 212 191 / 35%); + --info: #6aa6ff; + --info-soft: rgb(106 166 255 / 12%); --danger: #ff7b86; - --danger-soft: #321d23; - --warning: #f1c75b; - --warning-soft: #302a18; - --success-soft: #1d3029; - --overlay: #1d2530; - --code-bg: #0b0f14; - --user-bubble: #26213f; + --danger-soft: rgb(255 123 134 / 12%); + --danger-border: rgb(255 123 134 / 35%); + --warning: #ffb454; + --warning-soft: rgb(255 180 84 / 10%); + --success-soft: rgb(45 212 191 / 12%); + --overlay: #101826; + --code-bg: #080c12; + --user-bubble: #221d38; + --spine-bg: #0e1520; --shadow: 0 16px 45px rgb(0 0 0 / 35%); - --radius: 13px; + --radius: 11px; } :root[data-theme="light"] { - color: #1c2430; - background: #f6f7f9; - --bg: #f6f7f9; + color-scheme: light; + color: #1a2230; + background: #eef1f5; + --bg: #eef1f5; --panel: #ffffff; - --panel-2: #f1f3f6; - --sidebar: #fbfbfc; - --header: rgb(246 247 249 / 86%); - --line: #dde2e8; - --muted: #687386; - --text: #1c2430; - --text-soft: #4f5b6b; - --accent: #6748e8; - --accent-hover: #5739d4; + --panel-2: #f4f6f9; + --sidebar: #f7f9fc; + --header: rgb(238 241 245 / 86%); + --line: #d8dee8; + --line-strong: #c2ccd9; + --muted: #5b6b7e; + --faint: #8494a8; + --text: #1a2230; + --text-soft: #3d4b5e; + --accent: #c47400; + --accent-hover: #a86300; --accent-contrast: #ffffff; - --accent-soft: #eeeaff; - --accent-border: #c9befd; + --accent-soft: rgb(196 116 0 / 10%); + --accent-border: rgb(196 116 0 / 35%); + --signal: #0d9488; + --signal-soft: rgb(13 148 136 / 10%); + --signal-border: rgb(13 148 136 / 35%); + --info: #2f6fd0; + --info-soft: rgb(47 111 208 / 10%); --danger: #d94354; - --danger-soft: #fff0f2; - --warning: #9b6b00; - --warning-soft: #fff7df; - --success-soft: #e8f7ef; + --danger-soft: rgb(217 67 84 / 10%); + --danger-border: rgb(217 67 84 / 35%); + --warning: #c47400; + --warning-soft: rgb(196 116 0 / 8%); + --success-soft: rgb(13 148 136 / 10%); --overlay: #ffffff; - --code-bg: #f4f5f7; - --user-bubble: #eeeaff; + --code-bg: #f7f9fc; + --user-bubble: #ece7fb; + --spine-bg: #0e1520; --shadow: 0 16px 45px rgb(31 41 55 / 12%); } @@ -65,10 +107,10 @@ body { margin: 0; min-width: 320px; color: var(--text); background: var(--bg); t .pairing-icon { width: 52px; height: 52px; display: grid; place-items: center; margin-bottom: 18px; border-radius: 14px; color: var(--accent); background: var(--accent-soft); font-size: 24px; } .pairing-card h1 { margin: 0 0 9px; font-size: 24px; } .pairing-card > p { margin: 0 0 18px; color: var(--muted); font-size: 13px; line-height: 1.65; } -.pairing-command { display: block; margin-bottom: 22px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; color: var(--text); background: var(--code-bg); font: 12px/1.5 ui-monospace, SFMono-Regular, Consolas, monospace; } +.pairing-command { display: block; margin-bottom: 22px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; color: var(--text); background: var(--code-bg); font: 12px/1.5 var(--font-mono); } .pairing-card form { display: grid; gap: 10px; } .pairing-card label { color: var(--text-soft); font-size: 11px; font-weight: 650; } -.pairing-card input { width: 100%; padding: 12px 14px; border: 1px solid var(--line); border-radius: 10px; color: var(--text); background: var(--panel-2); font: 600 22px/1.2 ui-monospace, SFMono-Regular, Consolas, monospace; letter-spacing: .28em; text-align: center; } +.pairing-card input { width: 100%; padding: 12px 14px; border: 1px solid var(--line); border-radius: 10px; color: var(--text); background: var(--panel-2); font: 600 22px/1.2 var(--font-mono); letter-spacing: .28em; text-align: center; } .pairing-card form .primary { margin-top: 3px; padding: 11px 14px; } .pairing-card > small { display: block; margin-top: 17px; color: var(--muted); font-size: 10px; line-height: 1.5; } .pairing-error { padding: 8px 10px; border-radius: 8px; color: var(--danger); background: var(--danger-soft); font-size: 11px; } @@ -90,7 +132,7 @@ button:disabled { cursor: not-allowed; opacity: .45; } .sidebar nav button.active { color: var(--accent); } .gateway-status { margin-top: auto; border-top: 1px solid var(--line); padding: 18px 8px 2px; display: flex; gap: 10px; align-items: center; } .gateway-status i { width: 9px; height: 9px; border-radius: 50%; color: var(--warning); background: currentColor; box-shadow: 0 0 12px currentColor; } -.gateway-status i.online { color: #48b985; background: currentColor; } +.gateway-status i.online { color: var(--signal); background: currentColor; } .gateway-status b, .gateway-status small { display: block; font-size: 12px; } .gateway-status small { color: var(--muted); margin-top: 2px; } main { min-width: 0; height: 100vh; display: flex; flex-direction: column; } @@ -165,10 +207,10 @@ main { min-width: 0; height: 100vh; display: flex; flex-direction: column; } .reasoning-content { padding: 10px 13px; border-top: 1px solid var(--line); color: var(--muted); font-size: 12px; } .reasoning-block.historical { border-style: dashed; } .live-tool summary { display: grid; grid-template-columns: 24px 1fr auto; align-items: center; gap: 8px; } -.live-tool summary strong { color: var(--text); font: 600 12px/1.4 ui-monospace, SFMono-Regular, Consolas, monospace; } +.live-tool summary strong { color: var(--text); font: 600 12px/1.4 var(--font-mono); } .live-tool summary small { color: var(--muted); } .live-tool-details { display: grid; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--line); } -.live-tool-details pre { max-height: 260px; margin: 0; padding: 10px; overflow: auto; border-radius: 8px; color: var(--text-soft); background: var(--code-bg); font: 11px/1.5 ui-monospace, SFMono-Regular, Consolas, monospace; white-space: pre-wrap; } +.live-tool-details pre { max-height: 260px; margin: 0; padding: 10px; overflow: auto; border-radius: 8px; color: var(--text-soft); background: var(--code-bg); font: 11px/1.5 var(--font-mono); white-space: pre-wrap; } .turn-status, .completion-status { color: var(--muted); font-size: 10px; } .turn-status.failed, .turn-error { color: var(--danger); } .turn-error { padding: 8px 10px; border-radius: 8px; background: var(--danger-soft); font-size: 11px; } @@ -186,7 +228,7 @@ main { min-width: 0; height: 100vh; display: flex; flex-direction: column; } .markdown-body h3 { font-size: 1.1em; } .markdown-body a { color: var(--accent); text-underline-offset: 2px; } .markdown-body blockquote { padding-left: 12px; border-left: 3px solid var(--accent-border); color: var(--muted); } -.markdown-body code { padding: .14em .35em; border: 1px solid var(--line); border-radius: 5px; color: var(--text); background: var(--code-bg); font: .88em/1.5 ui-monospace, SFMono-Regular, Consolas, monospace; } +.markdown-body code { padding: .14em .35em; border: 1px solid var(--line); border-radius: 5px; color: var(--text); background: var(--code-bg); font: .88em/1.5 var(--font-mono); } .markdown-body pre { max-width: 100%; padding: 12px 13px; overflow-x: auto; border: 1px solid var(--line); border-radius: 9px; background: var(--code-bg); } .markdown-body pre code { padding: 0; border: 0; background: transparent; } .markdown-body table { display: block; max-width: 100%; border-collapse: collapse; overflow-x: auto; } @@ -202,13 +244,13 @@ main { min-width: 0; height: 100vh; display: flex; flex-direction: column; } .tool-call-icon { width: 28px; height: 28px; display: grid; place-items: center; border-radius: 8px; color: var(--accent); background: var(--accent-soft); font-size: 13px; } .tool-call-title small, .tool-call-title strong { display: block; } .tool-call-title small { margin-bottom: 1px; color: var(--muted); font-size: 9px; font-weight: 500; } -.tool-call-title strong { font: 600 12px/1.4 ui-monospace, SFMono-Regular, Consolas, monospace; } +.tool-call-title strong { font: 600 12px/1.4 var(--font-mono); } .tool-call-status { color: var(--muted); font-size: 10px; } .tool-call-chevron { color: var(--muted); transition: transform .18s; } .tool-call.open .tool-call-chevron { transform: rotate(180deg); } .tool-call-details { display: grid; gap: 12px; padding: 12px; border-top: 1px solid var(--line); background: color-mix(in srgb, var(--panel-2) 55%, transparent); } .tool-call-details > div > span { display: block; margin-bottom: 6px; color: var(--muted); font-size: 9px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; } -.tool-call-details pre, .tool-result { max-height: 300px; margin: 0; padding: 10px 11px; overflow: auto; border: 1px solid var(--line); border-radius: 8px; color: var(--text-soft); background: var(--code-bg); font: 11px/1.55 ui-monospace, SFMono-Regular, Consolas, monospace; white-space: pre-wrap; overflow-wrap: anywhere; } +.tool-call-details pre, .tool-result { max-height: 300px; margin: 0; padding: 10px 11px; overflow: auto; border: 1px solid var(--line); border-radius: 8px; color: var(--text-soft); background: var(--code-bg); font: 11px/1.55 var(--font-mono); white-space: pre-wrap; overflow-wrap: anywhere; } .tool-result .markdown-body { font: inherit; } .composer { position: relative; margin: 0 max(18px, calc((100% - 850px) / 2)) 18px; border: 1px solid var(--line); background: var(--panel); border-radius: 14px; padding: 10px 11px 6px; display: grid; grid-template-columns: 38px 1fr 38px; box-shadow: var(--shadow); } .composer textarea { resize: none; max-height: 180px; background: transparent; border: 0; outline: 0; color: var(--text); padding: 7px; line-height: 1.5; } @@ -248,7 +290,7 @@ main { min-width: 0; height: 100vh; display: flex; flex-direction: column; } .command-menu-heading kbd { color: var(--muted); font: inherit; } .command-menu button { display: grid; grid-template-columns: minmax(100px, auto) 1fr; gap: 14px; width: 100%; padding: 9px 10px; border: 0; border-radius: 8px; color: var(--text); background: transparent; text-align: left; cursor: pointer; } .command-menu button:hover, .command-menu button.selected { background: var(--accent-soft); } -.command-menu code { color: var(--accent); font: 600 12px/1.4 ui-monospace, SFMono-Regular, Consolas, monospace; } +.command-menu code { color: var(--accent); font: 600 12px/1.4 var(--font-mono); } .command-menu button span { color: var(--text-soft); font-size: 12px; line-height: 1.4; } .content-page { padding: 22px 26px; overflow: auto; } .toolbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px; gap: 10px; } @@ -264,7 +306,7 @@ main { min-width: 0; height: 100vh; display: flex; flex-direction: column; } .card p { color: var(--text-soft); font-size: 12px; line-height: 1.55; margin: 5px 0; white-space: pre-wrap; } .meta { display: flex; gap: 14px; flex-wrap: wrap; color: var(--muted); font-size: 11px; } .badge { border-radius: 99px; padding: 4px 8px; font-size: 10px; background: var(--panel-2); color: var(--text-soft); white-space: nowrap; } -.badge.ok { background: var(--success-soft); color: #38a877; } +.badge.ok { background: var(--success-soft); color: var(--signal); } .badge.fail { background: var(--danger-soft); color: var(--danger); } .badge.run { background: var(--warning-soft); color: var(--warning); } .details { margin-top: 12px; border-top: 1px solid var(--line); padding-top: 10px; } @@ -274,8 +316,8 @@ main { min-width: 0; height: 100vh; display: flex; flex-direction: column; } .metric b { font-size: 22px; display: block; } .metric small { color: var(--muted); } .memory-content { font-size: 13px !important; } -.memory-key { color: var(--accent); font-family: ui-monospace, monospace; } -.log-view { margin: 0; background: var(--code-bg); border: 1px solid var(--line); border-radius: 12px; padding: 16px; color: var(--text-soft); min-height: calc(100vh - 190px); font: 11px/1.65 ui-monospace, SFMono-Regular, Consolas, monospace; white-space: pre-wrap; overflow: auto; } +.memory-key { color: var(--accent); font-family: var(--font-mono); } +.log-view { margin: 0; background: var(--code-bg); border: 1px solid var(--line); border-radius: 12px; padding: 16px; color: var(--text-soft); min-height: calc(100vh - 190px); font: 11px/1.65 var(--font-mono); white-space: pre-wrap; overflow: auto; } .log-meta { color: var(--muted); font-size: 11px; margin: -8px 0 8px; } .switch-label { color: var(--muted); font-size: 12px; display: flex; gap: 7px; align-items: center; cursor: pointer; } .switch { width: 34px; height: 20px; padding: 2px; border: 1px solid var(--line); border-radius: 99px; background: var(--panel); cursor: pointer; } @@ -288,7 +330,7 @@ main { min-width: 0; height: 100vh; display: flex; flex-direction: column; } .editor-head { height: 62px; padding: 0 15px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--line); } .editor-head strong, .editor-head small { display: block; } .editor-head small { color: var(--muted); font-size: 10px; margin-top: 4px; } -.editor-card textarea { display: block; width: 100%; height: calc(100vh - 275px); min-height: 420px; resize: vertical; border: 0; outline: 0; padding: 18px; background: var(--code-bg); color: var(--text); font: 12px/1.6 ui-monospace, SFMono-Regular, Consolas, monospace; tab-size: 2; } +.editor-card textarea { display: block; width: 100%; height: calc(100vh - 275px); min-height: 420px; resize: vertical; border: 0; outline: 0; padding: 18px; background: var(--code-bg); color: var(--text); font: 12px/1.6 var(--font-mono); tab-size: 2; } .notice { padding: 11px 15px; color: var(--muted); font-size: 11px; border-top: 1px solid var(--line); } code { color: var(--accent); } #toast { position: fixed; z-index: 100; right: 22px; bottom: 22px; color: var(--text); background: var(--overlay); border: 1px solid var(--line); border-radius: 10px; padding: 11px 15px; font-size: 12px; opacity: 0; transform: translateY(8px); pointer-events: none; transition: .2s; box-shadow: var(--shadow); } @@ -297,6 +339,17 @@ code { color: var(--accent); } .loading, .empty-card { text-align: center; color: var(--muted); padding: 50px; } .empty-card.compact { padding: 24px 8px; } .error-text { color: var(--danger) !important; } +.mono { font-family: var(--font-mono); } +.label-caps { font-family: var(--font-mono); font-size: 9px; letter-spacing: .16em; color: var(--faint); } +.panel { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); } +.cap { display: inline-flex; align-items: center; gap: 4px; font-size: 9.5px; font-weight: 600; border-radius: 6px; padding: 2.5px 8px; } +.cap.signal { color: var(--signal); background: var(--signal-soft); border: 1px solid var(--signal-border); } +.cap.accent { color: var(--accent); background: var(--accent-soft); border: 1px solid var(--accent-border); } +.cap.danger { color: var(--danger); background: var(--danger-soft); border: 1px solid var(--danger-border); } +.cap.info { color: var(--info); background: var(--info-soft); border: 1px solid var(--line); } +@keyframes spine-pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } } +.pulse-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; animation: spine-pulse 1.6s ease-in-out infinite; } +@media (prefers-reduced-motion: reduce) { .pulse-dot { animation: none; } } @media (max-width: 800px) { .shell { grid-template-columns: 1fr; }