feat: add profile ui and request telemetry

This commit is contained in:
2026-06-29 04:40:32 +08:00
parent 7f7f7e5147
commit 4605885262
15 changed files with 7273 additions and 1684 deletions
+1291
View File
File diff suppressed because it is too large Load Diff
+11
View File
@@ -0,0 +1,11 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import "./styles.css";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>,
);
+922
View File
@@ -0,0 +1,922 @@
:root {
color-scheme: light;
--bg: #ebe4d6;
--surface: rgba(255, 251, 242, 0.88);
--surface-strong: #fffaf0;
--ink: #1e211d;
--muted: #716a5f;
--faint: #9b9284;
--line: rgba(30, 33, 29, 0.12);
--accent: #166b5c;
--accent-strong: #0f5045;
--accent-soft: #d7eee6;
--amber: #ba7130;
--red: #a43a2d;
--blue: #315f80;
--shadow: 0 24px 70px rgba(71, 48, 15, 0.16);
--mono: "Cascadia Code", "SFMono-Regular", Consolas, monospace;
--sans: "Aptos", "Segoe UI Variable", "Segoe UI", sans-serif;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
font-family: var(--sans);
color: var(--ink);
background:
radial-gradient(circle at 12% 10%, rgba(22, 107, 92, 0.26), transparent 28%),
radial-gradient(circle at 88% 0%, rgba(186, 113, 48, 0.22), transparent 24%),
linear-gradient(140deg, #f7f1e5 0%, var(--bg) 56%, #e1d4bf 100%);
}
button,
input,
textarea,
select {
font: inherit;
}
button {
border: 0;
border-radius: 999px;
padding: 10px 14px;
font-weight: 760;
cursor: pointer;
transition:
transform 140ms ease,
box-shadow 140ms ease,
opacity 140ms ease;
}
button:hover:not(:disabled) {
transform: translateY(-1px);
}
button:disabled {
cursor: not-allowed;
opacity: 0.58;
}
input,
textarea,
select {
width: 100%;
border: 1px solid var(--line);
border-radius: 15px;
padding: 9px 11px;
color: var(--ink);
background: rgba(255, 253, 248, 0.92);
outline: none;
}
textarea {
min-height: 88px;
resize: vertical;
}
code {
font-family: var(--mono);
font-size: 0.92em;
}
a {
color: inherit;
text-decoration: none;
}
.app-shell {
display: grid;
grid-template-columns: 270px minmax(0, 1fr);
gap: 20px;
max-width: 1500px;
margin: 0 auto;
padding: 22px;
}
.sidebar {
position: sticky;
top: 22px;
align-self: start;
min-height: calc(100vh - 44px);
border: 1px solid var(--line);
border-radius: 30px;
padding: 18px;
background: rgba(255, 250, 240, 0.78);
box-shadow: var(--shadow);
backdrop-filter: blur(18px);
}
.brand {
padding: 12px 10px 18px;
}
.eyebrow {
display: inline-flex;
align-items: center;
width: fit-content;
border-radius: 999px;
padding: 6px 10px;
color: var(--accent);
background: var(--accent-soft);
font-size: 12px;
font-weight: 800;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.brand h1 {
margin: 15px 0 8px;
font-size: 28px;
line-height: 1.04;
}
.brand p {
margin: 0;
color: var(--muted);
font-size: 13px;
line-height: 1.65;
}
.nav {
display: grid;
gap: 8px;
margin-top: 10px;
}
.nav button {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
border: 1px solid transparent;
color: var(--ink);
background: transparent;
text-align: left;
}
.nav button span {
color: var(--faint);
font-size: 12px;
font-weight: 700;
}
.nav button[data-active="true"] {
color: #fffdf6;
background: linear-gradient(135deg, var(--accent), var(--accent-strong));
box-shadow: 0 14px 30px rgba(22, 107, 92, 0.22);
}
.nav button[data-active="true"] span {
color: rgba(255, 255, 255, 0.72);
}
.side-card {
margin-top: 18px;
padding: 14px;
border: 1px solid var(--line);
border-radius: 22px;
background: rgba(255, 253, 247, 0.64);
}
.side-card label {
display: block;
color: var(--muted);
font-size: 11px;
font-weight: 800;
letter-spacing: 0.07em;
text-transform: uppercase;
}
.side-card strong,
.side-card span {
display: block;
margin-top: 7px;
word-break: break-word;
}
.content {
min-width: 0;
}
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
margin-bottom: 18px;
padding: 17px 18px;
border: 1px solid var(--line);
border-radius: 26px;
background: rgba(255, 250, 240, 0.72);
box-shadow: var(--shadow);
backdrop-filter: blur(18px);
}
.topbar h2 {
margin: 0;
font-size: 20px;
}
.topbar p {
margin: 3px 0 0;
color: var(--muted);
font-size: 13px;
}
.primary {
color: #fffdf6;
background: linear-gradient(135deg, var(--accent), var(--accent-strong));
box-shadow: 0 12px 24px rgba(22, 107, 92, 0.18);
}
.secondary {
color: var(--accent);
border: 1px solid rgba(22, 107, 92, 0.2);
background: var(--accent-soft);
}
.danger {
color: var(--red);
border: 1px solid rgba(164, 58, 45, 0.22);
background: #fff0ea;
}
.ghost {
color: var(--ink);
border: 1px solid var(--line);
background: rgba(255, 253, 248, 0.75);
}
.page {
animation: liftIn 280ms ease both;
}
@keyframes liftIn {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.grid {
display: grid;
gap: 16px;
}
.grid.two {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid.profile-layout {
grid-template-columns: minmax(0, 1.15fr) minmax(360px, 0.85fr);
}
.card {
border: 1px solid var(--line);
border-radius: 26px;
background: var(--surface);
box-shadow: var(--shadow);
backdrop-filter: blur(18px);
overflow: hidden;
}
.card-inner {
padding: 16px;
}
.card-head {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 14px;
margin-bottom: 10px;
}
.card h3 {
margin: 0;
font-size: 17px;
}
.muted {
color: var(--muted);
}
.hint {
color: var(--muted);
font-size: 12px;
line-height: 1.55;
}
.stat-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px;
}
.stat {
min-height: 110px;
padding: 15px;
border: 1px solid rgba(30, 33, 29, 0.08);
border-radius: 22px;
background: var(--surface-strong);
}
.stat label {
display: block;
margin-bottom: 10px;
color: var(--muted);
font-size: 11px;
font-weight: 850;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.stat strong {
display: block;
font-size: clamp(20px, 3vw, 30px);
line-height: 1.08;
}
.token-strip {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 10px;
}
.token-card {
padding: 16px;
border-radius: 22px;
color: #fffdf6;
background:
linear-gradient(135deg, rgba(255, 255, 255, 0.12), transparent),
#1f5e53;
}
.token-card:nth-child(2) {
background:
linear-gradient(135deg, rgba(255, 255, 255, 0.12), transparent),
#805b2a;
}
.token-card:nth-child(3) {
background:
linear-gradient(135deg, rgba(255, 255, 255, 0.12), transparent),
#315f80;
}
.token-card:nth-child(4) {
background:
linear-gradient(135deg, rgba(255, 255, 255, 0.12), transparent),
#773f33;
}
.token-card:nth-child(5) {
background:
linear-gradient(135deg, rgba(255, 255, 255, 0.12), transparent),
#425268;
}
.token-card label {
display: block;
opacity: 0.78;
font-size: 12px;
font-weight: 800;
}
.token-card strong {
display: block;
margin-top: 10px;
font-size: clamp(22px, 4vw, 34px);
}
.info-list {
display: grid;
gap: 10px;
}
.info-row {
display: grid;
grid-template-columns: 155px minmax(0, 1fr);
gap: 12px;
padding: 11px 0;
border-bottom: 1px solid rgba(30, 33, 29, 0.08);
}
.info-row:last-child {
border-bottom: 0;
}
.info-row label {
color: var(--muted);
font-size: 12px;
font-weight: 800;
}
.info-row span {
min-width: 0;
word-break: break-word;
}
.chips {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 12px;
}
.chip,
.badge {
display: inline-flex;
align-items: center;
width: fit-content;
border-radius: 999px;
padding: 4px 8px;
color: var(--accent);
background: var(--accent-soft);
font-size: 12px;
font-weight: 800;
}
.badge.warn {
color: var(--amber);
background: #fff0d9;
}
.badge.error {
color: var(--red);
background: #ffece7;
}
.badge.pending {
color: #6e5b2e;
background: #f4ead0;
}
.toolbar {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
}
.compact-toolbar {
gap: 8px;
}
.toolbar input,
.toolbar select {
max-width: 270px;
}
.table-wrap {
overflow: auto;
border: 1px solid rgba(30, 33, 29, 0.08);
border-radius: 22px;
background: var(--surface-strong);
}
.request-list {
display: grid;
gap: 8px;
}
.empty-state {
padding: 20px;
border: 1px dashed rgba(30, 33, 29, 0.12);
border-radius: 18px;
color: var(--muted);
background: rgba(255, 250, 240, 0.56);
}
.request-card {
display: grid;
gap: 8px;
padding: 10px 12px;
border: 1px solid rgba(30, 33, 29, 0.08);
border-radius: 20px;
background: var(--surface-strong);
}
.request-head {
display: flex;
justify-content: space-between;
gap: 8px;
align-items: flex-start;
}
.request-title,
.request-subtitle,
.request-token-row,
.request-badges {
display: flex;
flex-wrap: wrap;
gap: 6px;
align-items: center;
}
.token-pill {
display: inline-flex;
align-items: center;
border-radius: 999px;
padding: 4px 8px;
font-size: 11px;
font-weight: 780;
line-height: 1.2;
}
.token-in {
color: #155f53;
background: #d9efe8;
}
.token-out {
color: #2b5675;
background: #dcecf7;
}
.token-cached {
color: #91591f;
background: #fbe8cb;
}
.token-reasoning {
color: #8f4333;
background: #f8ddd5;
}
.token-total {
color: #3e4b5a;
background: #e5eaef;
}
.request-title strong {
font-size: 12px;
line-height: 1.2;
}
.request-subtitle {
margin-top: 2px;
}
.meta-pill {
display: inline-flex;
align-items: center;
border-radius: 999px;
padding: 4px 8px;
color: #4e5560;
background: #eceff3;
font-size: 11px;
font-weight: 760;
line-height: 1.2;
}
.meta-key {
margin-right: 5px;
color: #66707c;
font-size: 10px;
font-weight: 820;
letter-spacing: 0.04em;
}
.request-grid {
display: grid;
grid-template-columns: 1.05fr 1.35fr 1.6fr;
gap: 8px;
}
.request-block {
display: grid;
gap: 4px;
min-width: 0;
padding: 8px 9px;
border: 1px solid rgba(30, 33, 29, 0.08);
border-radius: 16px;
background: rgba(255, 250, 240, 0.74);
}
.request-block label {
color: var(--muted);
font-size: 10px;
font-weight: 820;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.request-block code,
.request-block span {
min-width: 0;
word-break: break-word;
font-size: 12px;
}
table {
width: 100%;
min-width: 960px;
border-collapse: collapse;
font-size: 12px;
}
th,
td {
padding: 8px 10px;
border-bottom: 1px solid rgba(30, 33, 29, 0.08);
text-align: left;
vertical-align: top;
white-space: nowrap;
}
th {
position: sticky;
top: 0;
z-index: 1;
color: var(--muted);
background: #f2eadb;
font-size: 11px;
font-weight: 850;
letter-spacing: 0.06em;
text-transform: uppercase;
}
tr:last-child td {
border-bottom: 0;
}
.path-cell {
max-width: 260px;
white-space: normal;
}
.profile-card {
display: grid;
gap: 14px;
padding: 11px 12px;
border: 1px solid rgba(30, 33, 29, 0.08);
border-radius: 20px;
background: var(--surface-strong);
}
.profile-list-grid {
gap: 10px;
}
.compact-profile-card {
gap: 8px;
}
.profile-card[data-active-profile="true"] {
border-color: rgba(22, 107, 92, 0.34);
box-shadow: inset 0 0 0 1px rgba(22, 107, 92, 0.12);
}
.profile-meta {
min-width: 0;
}
.profile-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 10px;
}
.profile-head h3 {
margin: 0 0 2px;
font-size: 14px;
line-height: 1.2;
}
.profile-path {
font-size: 11px;
line-height: 1.35;
word-break: break-all;
}
.profile-actions {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
gap: 5px;
}
.profile-actions button {
padding: 5px 9px;
font-size: 11px;
}
.profile-actions .badge {
padding: 3px 7px;
font-size: 11px;
}
.mini-stats {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 6px;
}
.mini-stat {
padding: 7px 8px;
border: 1px solid rgba(30, 33, 29, 0.08);
border-radius: 14px;
background: rgba(255, 250, 240, 0.76);
}
.mini-stat label {
display: block;
color: var(--muted);
font-size: 10px;
font-weight: 830;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.mini-stat span {
display: block;
margin-top: 3px;
word-break: break-word;
font-size: 11px;
line-height: 1.35;
}
form {
display: grid;
gap: 12px;
}
.field {
display: grid;
gap: 6px;
}
.field span:first-child {
font-size: 13px;
font-weight: 820;
}
.field-row {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
.inline-toggle {
display: flex;
align-items: center;
gap: 10px;
padding: 12px 13px;
border: 1px solid rgba(30, 33, 29, 0.08);
border-radius: 16px;
background: var(--surface-strong);
}
.inline-toggle input {
width: auto;
}
.message {
min-height: 22px;
color: var(--muted);
font-size: 13px;
line-height: 1.55;
}
.message[data-tone="success"] {
color: var(--accent);
}
.message[data-tone="error"] {
color: var(--red);
}
.log-output {
margin: 0;
min-height: 300px;
max-height: 68vh;
overflow: auto;
padding: 14px;
border-radius: 22px;
color: #f7efe2;
background:
radial-gradient(circle at 0% 0%, rgba(22, 107, 92, 0.22), transparent 36%),
#1f211d;
font-family: var(--mono);
font-size: 12px;
line-height: 1.5;
white-space: pre-wrap;
word-break: break-word;
}
.switch-overlay {
position: fixed;
inset: 0;
z-index: 20;
display: none;
align-items: center;
justify-content: center;
padding: 24px;
background: rgba(34, 30, 24, 0.36);
backdrop-filter: blur(9px);
}
.switch-overlay[data-active="true"] {
display: flex;
}
.switch-dialog {
width: min(520px, 100%);
border: 1px solid rgba(255, 255, 255, 0.38);
border-radius: 28px;
padding: 24px;
background: #fffaf0;
box-shadow: 0 28px 80px rgba(20, 16, 8, 0.28);
}
.progress-line {
height: 9px;
margin-top: 18px;
overflow: hidden;
border-radius: 999px;
background: #e8dcc7;
}
.progress-line span {
display: block;
width: 42%;
height: 100%;
border-radius: inherit;
background: linear-gradient(90deg, var(--accent), var(--amber));
animation: drift 1300ms ease-in-out infinite alternate;
}
@keyframes drift {
from {
transform: translateX(-18%);
}
to {
transform: translateX(150%);
}
}
@media (max-width: 1120px) {
.app-shell,
.grid.profile-layout {
grid-template-columns: 1fr;
}
.sidebar {
position: static;
min-height: auto;
}
.nav {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
.nav button {
justify-content: center;
}
.nav button span {
display: none;
}
}
@media (max-width: 820px) {
.app-shell {
padding: 12px;
}
.topbar,
.card-head,
.profile-head {
display: grid;
}
.grid.two,
.stat-grid,
.token-strip,
.mini-stats,
.field-row,
.nav {
grid-template-columns: 1fr;
}
.request-head,
.request-grid {
display: grid;
grid-template-columns: 1fr;
}
.info-row {
grid-template-columns: 1fr;
gap: 4px;
}
}