From e39eb8e34aba6655ea550c94254c1459e60bcf91 Mon Sep 17 00:00:00 2001 From: Rami Djebari <238472321+ramioca@users.noreply.github.com> Date: Tue, 8 Sep 2026 14:54:42 +0200 Subject: [PATCH 1/3] desktop: visual refresh of the control plane Sidebar sections, a data-driven hero, tinted capability chips, a live usage chart with axis and tooltips, a Settings page with a theme picker and copyable endpoints, redesigned wallet cards, and a Deposit tab in the funding dialog that exposes both wallet addresses. Review fixes folded in: copy buttons only show "Copied" once the clipboard write resolves and report failures; the usage chart pads the router's traffic-only days into a continuous UTC window; light-theme chip text clears 4.5:1; SVG gradient ids are per instance; the demo stats match the router's /stats shape. Co-Authored-By: Claude Fable 5.1 --- apps/desktop/src/App.tsx | 758 ++++++++++++++++++++++++------ apps/desktop/src/api.ts | 32 +- apps/desktop/src/styles.css | 907 ++++++++++++++++++++++++++++++------ 3 files changed, 1410 insertions(+), 287 deletions(-) diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index 026b2505..57d788e8 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useId, useMemo, useRef, useState } from "react"; import type { AgentId, @@ -15,8 +15,23 @@ import OPENCLAW_ICON from "./openclaw-x-avatar.jpg"; type Page = "overview" | "models" | "usage" | "wallet" | "settings"; type Theme = "dark" | "light"; type IconName = - "home" | "models" | "usage" | "settings" | "refresh" | "sun" | "moon" | "external" | "wallet"; + | "home" + | "models" + | "usage" + | "settings" + | "refresh" + | "sun" + | "moon" + | "external" + | "wallet" + | "copy" + | "plus" + | "check"; type CatalogModel = ModelInfo & { aliases: string[] }; +type UsageDay = { date: string; label: string; short: string; requests: number; cost: number }; + +/** Widest calendar window the activity chart pads out to. */ +const MAX_CHART_DAYS = 14; const CLAWROUTER_REPO = "https://github.com/BlockRunAI/ClawRouter"; const AGENT_REPOS: Record = { @@ -38,12 +53,15 @@ export function App() { const [fundingAmount, setFundingAmount] = useState(50); const [fundingBusy, setFundingBusy] = useState(false); const [notice, setNotice] = useState<{ kind: "ok" | "error"; text: string } | null>(null); + const [refreshSpin, setRefreshSpin] = useState(false); const [theme, setTheme] = useState(() => { const saved = window.localStorage.getItem("clawrouter-theme"); if (saved === "light" || saved === "dark") return saved; return window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark"; }); + const reportError = (text: string) => setNotice({ kind: "error", text }); + async function refresh() { await Promise.allSettled([ api.statuses().then(setAgents), @@ -155,6 +173,7 @@ export function App() {