From fd24525834e5c8b3b25c3f0031d2d3273f0e0ca9 Mon Sep 17 00:00:00 2001 From: Zhichao Zhang Date: Thu, 23 Jul 2026 08:06:29 +0800 Subject: [PATCH 1/2] Refine sidebar flyout and chat UI --- desktop/package-lock.json | 242 +-------- desktop/renderer/package-lock.json | 27 +- .../renderer/src/components/ChatWelcome.vue | 17 +- desktop/renderer/src/components/SidePanel.vue | 490 +++++++++++++----- desktop/renderer/src/i18n/en-US.ts | 4 +- desktop/renderer/src/i18n/zh-CN.ts | 4 +- desktop/renderer/src/views/ChatView.vue | 4 +- 7 files changed, 390 insertions(+), 398 deletions(-) diff --git a/desktop/package-lock.json b/desktop/package-lock.json index 62e134f..a306110 100644 --- a/desktop/package-lock.json +++ b/desktop/package-lock.json @@ -469,106 +469,6 @@ "node": ">= 10.0.0" } }, - "node_modules/@electron/windows-sign": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/@electron/windows-sign/-/windows-sign-1.2.2.tgz", - "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "dependencies": { - "cross-dirname": "^0.1.0", - "debug": "^4.3.4", - "fs-extra": "^11.1.1", - "minimist": "^1.2.8", - "postject": "^1.0.0-alpha.6" - }, - "bin": { - "electron-windows-sign": "bin/electron-windows-sign.js" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@electron/windows-sign/node_modules/fs-extra": { - "version": "11.3.4", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.4.tgz", - "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@electron/windows-sign/node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/windows-sign/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmmirror.com/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -1520,6 +1420,14 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": { + "dev": true, + "optional": true + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "dev": true, + "optional": true + }, "node_modules/@rolldown/binding-win32-arm64-msvc": { "version": "1.0.0-rc.17", "resolved": "https://registry.npmmirror.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", @@ -3089,15 +2997,6 @@ "buffer": "^5.1.0" } }, - "node_modules/cross-dirname": { - "version": "0.1.0", - "resolved": "https://registry.npmmirror.com/cross-dirname/-/cross-dirname-0.1.0.tgz", - "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3538,19 +3437,6 @@ "node": ">=14.0.0" } }, - "node_modules/electron-builder-squirrel-windows": { - "version": "26.8.1", - "resolved": "https://registry.npmmirror.com/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.8.1.tgz", - "integrity": "sha512-o288fIdgPLHA76eDrFADHPoo7VyGkDCYbLV1GzndaMSAVBoZrGvM9m2IehdcVMzdAZJ2eV9bgyissQXHv5tGzA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "app-builder-lib": "26.8.1", - "builder-util": "26.8.1", - "electron-winstaller": "5.4.0" - } - }, "node_modules/electron-builder/node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", @@ -3657,44 +3543,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/electron-winstaller": { - "version": "5.4.0", - "resolved": "https://registry.npmmirror.com/electron-winstaller/-/electron-winstaller-5.4.0.tgz", - "integrity": "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@electron/asar": "^3.2.1", - "debug": "^4.1.1", - "fs-extra": "^7.0.1", - "lodash": "^4.17.21", - "temp": "^0.9.0" - }, - "engines": { - "node": ">=8.0.0" - }, - "optionalDependencies": { - "@electron/windows-sign": "^1.1.2" - } - }, - "node_modules/electron-winstaller/node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, "node_modules/electron/node_modules/@types/node": { "version": "20.19.39", "resolved": "https://registry.npmmirror.com/@types/node/-/node-20.19.39.tgz", @@ -5571,20 +5419,6 @@ "node": ">= 18" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", @@ -6103,36 +5937,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postject": { - "version": "1.0.0-alpha.6", - "resolved": "https://registry.npmmirror.com/postject/-/postject-1.0.0-alpha.6.tgz", - "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "commander": "^9.4.0" - }, - "bin": { - "postject": "dist/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/postject/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmmirror.com/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": "^12.20.0 || >=14" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -6345,21 +6149,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/roarr": { "version": "2.15.4", "resolved": "https://registry.npmmirror.com/roarr/-/roarr-2.15.4.tgz", @@ -6787,21 +6576,6 @@ "node": ">=18" } }, - "node_modules/temp": { - "version": "0.9.4", - "resolved": "https://registry.npmmirror.com/temp/-/temp-0.9.4.tgz", - "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "mkdirp": "^0.5.1", - "rimraf": "~2.6.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/temp-file": { "version": "3.4.0", "resolved": "https://registry.npmmirror.com/temp-file/-/temp-file-3.4.0.tgz", diff --git a/desktop/renderer/package-lock.json b/desktop/renderer/package-lock.json index 3dd1bbb..6fda6ef 100644 --- a/desktop/renderer/package-lock.json +++ b/desktop/renderer/package-lock.json @@ -5169,7 +5169,7 @@ "version": "5.9.3", "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -5475,31 +5475,6 @@ } } }, - "node_modules/vue-eslint-parser": { - "version": "10.4.0", - "resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-10.4.0.tgz", - "integrity": "sha512-Vxi9pJdbN3ZnVGLODVtZ7y4Y2kzAAE2Cm0CZ3ZDRvydVYxZ6VrnBhLikBsRS+dpwj4Jv4UCv21PTEwF5rQ9WXg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "^4.4.0", - "eslint-scope": "^8.2.0 || ^9.0.0", - "eslint-visitor-keys": "^4.2.0 || ^5.0.0", - "espree": "^10.3.0 || ^11.0.0", - "esquery": "^1.6.0", - "semver": "^7.6.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0" - } - }, "node_modules/vue-router": { "version": "4.6.4", "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.6.4.tgz", diff --git a/desktop/renderer/src/components/ChatWelcome.vue b/desktop/renderer/src/components/ChatWelcome.vue index 3738668..f8c0a5d 100644 --- a/desktop/renderer/src/components/ChatWelcome.vue +++ b/desktop/renderer/src/components/ChatWelcome.vue @@ -78,7 +78,8 @@ const defaultCards = computed(() => { title: t("home.card.news.title"), desc: t("home.card.news.desc"), prompt: t("home.card.news.prompt"), - style: "--rot: 12deg; --dx: clamp(35px, 6vw, 75px); z-index: 3", + style: + "--rot: 12deg; --dx: clamp(35px, 6vw, 75px); --hover-dx: clamp(22px, 2.8vw, 38px); --hover-dy: -24px; z-index: 3", }, { id: "desktop", @@ -86,7 +87,7 @@ const defaultCards = computed(() => { title: t("home.card.desktop.title"), desc: t("home.card.desktop.desc"), prompt: t("home.card.desktop.prompt"), - style: "--rot: 0deg; z-index: 2", + style: "--rot: 0deg; --hover-dx: 0px; --hover-dy: -36px; z-index: 2", }, { id: "travel", @@ -94,7 +95,8 @@ const defaultCards = computed(() => { title: t("home.card.travel.title"), desc: t("home.card.travel.desc"), prompt: t("home.card.travel.prompt"), - style: "--rot: -12deg; --dx: clamp(-75px, -6vw, -35px); z-index: 1", + style: + "--rot: -12deg; --dx: clamp(-75px, -6vw, -35px); --hover-dx: clamp(-38px, -2.8vw, -22px); --hover-dy: -24px; z-index: 1", }, ]; }); @@ -169,7 +171,7 @@ function onSuggestionsScroll() { font-weight: 500; color: var(--text-secondary); text-align: center; - margin-bottom: clamp(16px, 4vh, 56px); + margin-bottom: clamp(28px, 6vh, 84px); position: relative; z-index: 10; } @@ -204,7 +206,12 @@ function onSuggestionsScroll() { } .fan-card:hover { - transform: translateX(var(--dx, 0px)) rotate(var(--rot)) translateY(-36px) translateZ(0); + transform: + translateX(calc(var(--dx, 0px) + var(--hover-dx, 0px))) + rotate(var(--rot)) + translateY(var(--hover-dy, -36px)) + translateZ(0); + z-index: 10 !important; box-shadow: var(--card-shadow-hover); } diff --git a/desktop/renderer/src/components/SidePanel.vue b/desktop/renderer/src/components/SidePanel.vue index c5fb22b..a5aca78 100644 --- a/desktop/renderer/src/components/SidePanel.vue +++ b/desktop/renderer/src/components/SidePanel.vue @@ -4,18 +4,82 @@
-
-
+
+
{{ currentAgent.name }}
{{ t("sidebar.tagline") }}
+
- -
-
@@ -151,7 +150,6 @@ import { ElMessage } from "element-plus"; import SidePanel from "@/components/SidePanel.vue"; import GatewayLoading from "@/components/GatewayLoading.vue"; import PermissionDialog from "@/components/PermissionDialog.vue"; -import UsagePanel from "@/components/UsagePanel.vue"; import { useAgentStore } from "@/stores/agents"; import { useGatewayStore } from "@/stores/gateway"; import { useChatStore } from "@/stores/chat"; diff --git a/desktop/renderer/src/components/SidePanel.vue b/desktop/renderer/src/components/SidePanel.vue index a5aca78..d24419d 100644 --- a/desktop/renderer/src/components/SidePanel.vue +++ b/desktop/renderer/src/components/SidePanel.vue @@ -151,25 +151,6 @@ {{ t("sidebar.phone") }} - - - + + + + + @@ -206,7 +238,6 @@ import { useChatStore } from "@/stores/chat"; import { useSessionStore } from "@/stores/sessions"; import { useAgentStore } from "@/stores/agents"; import { t } from "@/i18n"; -import { useUsagePanel } from "@/composables/useUsagePanel"; import IconPlus from "@/components/icons/IconPlus.vue"; import IconChevronDown from "@/components/icons/IconChevronDown.vue"; import IconClose from "@/components/icons/IconClose.vue"; @@ -218,7 +249,16 @@ const chatStore = useChatStore(); const sessionStore = useSessionStore(); const agentStore = useAgentStore(); -const { open: openUsage } = useUsagePanel(); +interface UsageSnapshot { + totalSpend: number; + totalTokens: number; +} + +const usageSnapshot = ref(null); +const usageLoading = ref(false); +const usageLastUpdated = ref(null); +const usageCollapsed = ref(false); +let usageRefreshTimer: ReturnType | null = null; const chatExpanded = ref(true); const isAgentFlyoutOpen = ref(false); @@ -234,6 +274,12 @@ const flyoutStyle = computed(() => ({ left: `${flyoutLeft.value}px`, })); +const gatewayOnline = computed(() => gateway.ready && gateway.status === "running"); +const lastUpdatedLabel = computed(() => { + if (!usageLastUpdated.value) return ""; + return usageLastUpdated.value.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }); +}); + const filteredAgents = computed(() => { const q = agentQuery.value.trim().toLowerCase(); if (!q) return agentStore.agents; @@ -252,10 +298,17 @@ const currentAgent = computed(() => { onMounted(() => { gateway.refreshWeixinStatus(); + try { + usageCollapsed.value = localStorage.getItem("microclaw:usageSnapshotCollapsed") === "1"; + } catch {} document.addEventListener("mousedown", handleDocumentPointerDown); document.addEventListener("keydown", handleDocumentKeyDown); window.addEventListener("resize", handleWindowResize); window.addEventListener("scroll", handleWindowScroll, true); + void loadUsageSnapshot(); + usageRefreshTimer = setInterval(() => { + void loadUsageSnapshot(); + }, 60_000); }); onUnmounted(() => { @@ -263,8 +316,73 @@ onUnmounted(() => { document.removeEventListener("keydown", handleDocumentKeyDown); window.removeEventListener("resize", handleWindowResize); window.removeEventListener("scroll", handleWindowScroll, true); + if (usageRefreshTimer) { + clearInterval(usageRefreshTimer); + usageRefreshTimer = null; + } }); +async function loadUsageSnapshot() { + if (usageLoading.value) return; + usageLoading.value = true; + try { + const usageApi = window.openclaw?.usage?.getStats; + if (!gatewayOnline.value || typeof usageApi !== "function") { + if (import.meta.env.DEV) { + applyMockSnapshot(); + } else { + usageSnapshot.value = null; + } + return; + } + + const stats = await usageApi(); + usageSnapshot.value = { + totalSpend: Number(stats?.totalSpend || 0), + totalTokens: Number(stats?.totalTokens || 0), + }; + usageLastUpdated.value = new Date(); + } catch { + if (import.meta.env.DEV) { + applyMockSnapshot(); + } else { + usageSnapshot.value = null; + } + } finally { + usageLoading.value = false; + } +} + +function applyMockSnapshot() { + usageSnapshot.value = { + totalSpend: 42.35, + totalTokens: 128400, + }; + usageLastUpdated.value = new Date(); +} + +function toggleUsageCollapsed() { + usageCollapsed.value = !usageCollapsed.value; + try { + localStorage.setItem("microclaw:usageSnapshotCollapsed", usageCollapsed.value ? "1" : "0"); + } catch {} +} + +function formatCompact(value: number) { + return new Intl.NumberFormat(undefined, { + notation: "compact", + maximumFractionDigits: 1, + }).format(value || 0); +} + +function formatUsd(value: number) { + return new Intl.NumberFormat(undefined, { + style: "currency", + currency: "USD", + maximumFractionDigits: 2, + }).format(value || 0); +} + /** * Ensure the active chat is a fresh session bound to the currently-selected agent. * Starts a new session when the current chat already has messages, OR when it @@ -695,6 +813,109 @@ html.dark .sp-create-btn:hover { min-height: 0; } +.sp-usage-snapshot { + padding: 10px clamp(8px, 1.5vw, 16px) 12px; + background: #fbfbf9; +} + +html.dark .sp-usage-snapshot { + background: var(--bg-secondary); +} + +.sp-usage-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin-bottom: 8px; +} + +.sp-usage-title { + font-size: 12px; + color: var(--text-secondary); + font-weight: 600; +} + +.sp-usage-toggle { + border: none; + background: transparent; + color: var(--text-secondary); + cursor: pointer; + width: 18px; + height: 18px; + padding: 0; + line-height: 1; + display: grid; + place-items: center; + border-radius: 4px; + font-size: 11px; +} + +.sp-usage-toggle-icon { + transition: transform 0.2s ease; +} + +.sp-usage-toggle-icon.collapsed { + transform: rotate(-90deg); +} + +.sp-usage-toggle:hover { + background: #f0ece7; + color: var(--text-primary); +} + +html.dark .sp-usage-toggle:hover { + background: var(--bg-tertiary); +} + +.sp-usage-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 6px; +} + +.sp-usage-card { + border: 1px solid #ece7e2; + border-radius: 8px; + padding: 6px; + background: #fff; + display: flex; + flex-direction: column; + gap: 4px; +} + +html.dark .sp-usage-card { + border-color: var(--border); + background: var(--bg-primary); +} + +.sp-usage-label { + font-size: 10px; + color: var(--text-muted); +} + +.sp-usage-value { + font-size: 12px; + color: var(--text-primary); + font-weight: 600; + line-height: 1.2; +} + +.sp-usage-state { + font-size: 12px; + color: var(--text-muted); + padding: 4px 0; +} + +.sp-usage-foot { + margin-top: 8px; + display: flex; + justify-content: space-between; + gap: 8px; + font-size: 10px; + color: var(--text-muted); +} + /* ── Chat section ── */ .sp-section { margin-bottom: 8px; diff --git a/desktop/renderer/src/i18n/en-US.ts b/desktop/renderer/src/i18n/en-US.ts index 4c7286b..6a683a7 100644 --- a/desktop/renderer/src/i18n/en-US.ts +++ b/desktop/renderer/src/i18n/en-US.ts @@ -47,6 +47,20 @@ export default { "sidebar.explorePopularAgents": "Explore more popular agents", "sidebar.phone": "Phone", "sidebar.tagline": "Weave the future through conversation", + "sidebar.usageSnapshotTitle": "Usage", + "sidebar.usageSnapshotViewDetails": "Details", + "sidebar.usageSnapshotSpend": "Spend", + "sidebar.usageSnapshotTokens": "Tokens", + "sidebar.usageSnapshotRequests": "Requests", + "sidebar.usageSnapshotHealth": "Health", + "sidebar.usageSnapshotOffline": "Gateway offline", + "sidebar.usageSnapshotNoData": "No usage data yet", + "sidebar.usageSnapshotPeriod": "Last 30 days", + "sidebar.usageSnapshotUpdated": "Updated {time}", + "sidebar.usageSnapshotExpand": "Expand usage snapshot", + "sidebar.usageSnapshotCollapse": "Collapse usage snapshot", + "sidebar.usageSnapshotMock": "Mock data", + "sidebar.usageSnapshotSimulated": "Simulated", // ── HomeView ── "home.heading": "Ready? Pick a task below to start exploring!", diff --git a/desktop/renderer/src/i18n/zh-CN.ts b/desktop/renderer/src/i18n/zh-CN.ts index 2347573..214f7ee 100644 --- a/desktop/renderer/src/i18n/zh-CN.ts +++ b/desktop/renderer/src/i18n/zh-CN.ts @@ -45,6 +45,20 @@ export default { "sidebar.explorePopularAgents": "探索更多热门 Agent", "sidebar.phone": "手机", "sidebar.tagline": "透过对话,编织万物未来", + "sidebar.usageSnapshotTitle": "使用情况", + "sidebar.usageSnapshotViewDetails": "查看详情", + "sidebar.usageSnapshotSpend": "花费", + "sidebar.usageSnapshotTokens": "Tokens", + "sidebar.usageSnapshotRequests": "请求", + "sidebar.usageSnapshotHealth": "状态", + "sidebar.usageSnapshotOffline": "网关未连接", + "sidebar.usageSnapshotNoData": "暂无用量数据", + "sidebar.usageSnapshotPeriod": "最近 30 天", + "sidebar.usageSnapshotUpdated": "更新于 {time}", + "sidebar.usageSnapshotExpand": "展开使用概览", + "sidebar.usageSnapshotCollapse": "收起使用概览", + "sidebar.usageSnapshotMock": "模拟数据", + "sidebar.usageSnapshotSimulated": "模拟", // ── HomeView ── "home.heading": "准备好了?从下面挑一个任务开始探索吧!",