From 5ea44f5916cb15f1a83e91dabac6bcf3e83fafc8 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 8 Aug 2026 22:22:32 -0700 Subject: [PATCH] refactor(ui): remove dead Control UI weight (#120870) * refactor(ui): remove dead Control UI weight * test(ui): trim redundant preview fixture * fix(ui): preserve agent file preview behavior --- package.json | 1 - pnpm-lock.yaml | 25 -- src/types/create-markdown-preview.d.ts | 10 - test/scripts/ci-node-test-plan.test.ts | 25 +- test/scripts/test-projects.test.ts | 24 +- test/vitest/vitest.shared.config.ts | 2 +- ui/package.json | 2 - .../markdown-assistant-transcript.ts | 3 +- ui/src/components/markdown-document.test.ts | 34 ++ ui/src/components/markdown-parser.ts | 5 +- ui/src/components/markdown-render-options.ts | 3 + ui/src/components/markdown.ts | 9 +- ui/src/pages/agents/panels-status-files.ts | 8 +- ui/src/pages/agents/view.test.ts | 14 +- ui/src/styles.css | 10 - ui/src/styles/base.css | 48 --- ui/src/styles/chat/layout.css | 309 +-------------- ui/src/styles/components.css | 374 ------------------ ui/src/styles/cron.css | 66 ---- ui/src/styles/layout.css | 179 +-------- ui/src/styles/layout.mobile.css | 47 +-- ui/src/styles/model-providers.css | 14 +- ui/src/styles/usage.css | 86 +--- ui/src/test-helpers/load-styles.ts | 1 - ui/src/types/create-markdown-preview.d.ts | 8 - 25 files changed, 92 insertions(+), 1215 deletions(-) delete mode 100644 src/types/create-markdown-preview.d.ts create mode 100644 ui/src/components/markdown-document.test.ts delete mode 100644 ui/src/types/create-markdown-preview.d.ts diff --git a/package.json b/package.json index f32a92e79673..012dad5a3317 100644 --- a/package.json +++ b/package.json @@ -2084,7 +2084,6 @@ "@typescript/native-preview": "7.0.0-dev.20260707.2", "@vitest/coverage-v8": "4.1.10", "esbuild": "0.28.1", - "fast-glob": "3.3.3", "ipaddr.js": "2.4.0", "jscpd": "5.0.12", "jsdom": "29.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a8923e8cb942..07c25c06c0f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -302,9 +302,6 @@ importers: esbuild: specifier: 0.28.1 version: 0.28.1 - fast-glob: - specifier: 3.3.3 - version: 3.3.3 ipaddr.js: specifier: 2.4.0 version: 2.4.0 @@ -2382,9 +2379,6 @@ importers: '@codemirror/view': specifier: 6.43.6 version: 6.43.6 - '@create-markdown/preview': - specifier: 2.0.3 - version: 2.0.3(shiki@4.3.1) '@lezer/highlight': specifier: 1.2.3 version: 1.2.3 @@ -2460,9 +2454,6 @@ importers: markdown-it-task-lists: specifier: 2.1.1 version: 2.1.1 - marked: - specifier: 18.0.7 - version: 18.0.7 remend: specifier: 1.3.0 version: 1.3.0 @@ -2969,18 +2960,6 @@ packages: vitest: optional: true - '@create-markdown/preview@2.0.3': - resolution: {integrity: sha512-Vrp8DyuiouryZ3E4NQ7tBgoYQdoekd0+DzN64mZ48QYCw3V+MCb/H2q10SW8KC8XPr931XOMDvKX4I83qpQh3g==} - engines: {node: '>=20.0.0'} - peerDependencies: - '@create-markdown/core': '>=2.0.3' - shiki: '>=1.0.0' - peerDependenciesMeta: - '@create-markdown/core': - optional: true - shiki: - optional: true - '@csstools/color-helpers@6.1.0': resolution: {integrity: sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==} engines: {node: '>=20.19.0'} @@ -10360,10 +10339,6 @@ snapshots: optionalDependencies: vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.2)(@vitest/browser-playwright@4.1.10)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1(@noble/hashes@2.2.0))(vite@8.1.5(@types/node@26.1.2)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.23.1)(yaml@2.9.0)) - '@create-markdown/preview@2.0.3(shiki@4.3.1)': - optionalDependencies: - shiki: 4.3.1 - '@csstools/color-helpers@6.1.0': {} '@csstools/css-calc@3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': diff --git a/src/types/create-markdown-preview.d.ts b/src/types/create-markdown-preview.d.ts deleted file mode 100644 index 99063224375a..000000000000 --- a/src/types/create-markdown-preview.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** Ambient types for the create-markdown preview package used by docs rendering. */ -declare module "@create-markdown/preview" { - /** Theme options accepted by the preview renderer. */ - export type PreviewThemeOptions = { - sanitize?: ((html: string) => string) | undefined; - }; - - /** Apply the package's preview theme to an HTML string. */ - export function applyPreviewTheme(html: string, options?: PreviewThemeOptions): string; -} diff --git a/test/scripts/ci-node-test-plan.test.ts b/test/scripts/ci-node-test-plan.test.ts index e35c8f8181b2..7c406160ee33 100644 --- a/test/scripts/ci-node-test-plan.test.ts +++ b/test/scripts/ci-node-test-plan.test.ts @@ -1,7 +1,6 @@ // Ci Node Test Plan tests cover ci node test plan script behavior. -import { existsSync, readdirSync } from "node:fs"; -import { join, relative, resolve } from "node:path"; -import fg from "fast-glob"; +import { existsSync, globSync, readdirSync } from "node:fs"; +import { isAbsolute, join, relative, resolve } from "node:path"; import { describe, expect, it } from "vitest"; import { assignVitestFsCacheWriter, @@ -65,13 +64,13 @@ function listTestFiles(rootDir: string): string[] { function listMatchedTestFiles(config: VitestConfig): string[] { const testConfig = config.test ?? {}; const cwd = testConfig.dir ? resolve(testConfig.dir) : process.cwd(); - return fg - .sync(testConfig.include ?? [], { - absolute: false, - cwd, - dot: false, - ignore: testConfig.exclude ?? [], - }) + const exclude = (testConfig.exclude ?? []).map((pattern) => + isAbsolute(pattern) ? toRepoPath(relative(cwd, pattern)) : toRepoPath(pattern), + ); + return globSync(testConfig.include ?? [], { + cwd, + exclude, + }) .map((file) => toRepoPath(relative(process.cwd(), resolve(cwd, file)))) .toSorted((a, b) => a.localeCompare(b)); } @@ -1133,12 +1132,12 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => { agentVitestProjectOwners.embeddedOverflowCompaction.include, ); const actual = [ - ...fg - .sync(agentVitestProjectOwners.embedded.include) + ...globSync(agentVitestProjectOwners.embedded.include) + .map(toRepoPath) .filter((file) => !incompleteTurnFiles.has(file) && !overflowCompactionFiles.has(file)), ...agentVitestProjectOwners.embeddedIncompleteTurn.include, ...agentVitestProjectOwners.embeddedOverflowCompaction.include, - ...fg.sync(agentVitestProjectOwners.embeddedRun.include), + ...globSync(agentVitestProjectOwners.embeddedRun.include).map(toRepoPath), ].toSorted((left, right) => left.localeCompare(right)); const expected = listTestFiles("src/agents/embedded-agent-runner").toSorted((left, right) => left.localeCompare(right), diff --git a/test/scripts/test-projects.test.ts b/test/scripts/test-projects.test.ts index 47728763cc0f..503d1aa53df3 100644 --- a/test/scripts/test-projects.test.ts +++ b/test/scripts/test-projects.test.ts @@ -1,9 +1,8 @@ // Test Projects tests cover test projects script behavior. import { spawnSync } from "node:child_process"; -import fs from "node:fs"; +import fs, { globSync } from "node:fs"; import os from "node:os"; import path from "node:path"; -import fg from "fast-glob"; import { beforeAll, describe, expect, it, vi } from "vitest"; import { listExtensionTestFilesForRoots } from "../../scripts/lib/extension-test-plan.mjs"; import { @@ -107,13 +106,10 @@ async function listMatchedTestFilesForConfig(configPath: string): Promise normalizeRepoPath(path.relative(process.cwd(), path.resolve(dir, file)))) .toSorted((left, right) => left.localeCompare(right)); } @@ -135,12 +131,10 @@ function listNormalFullSuiteTestFiles(): string[] { "src/gateway/server.startup-matrix-migration.integration.test.ts", "src/gateway/sessions-history-http.test.ts", ]); - return fg - .sync(["**/*.{test,spec}.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"], { - cwd: process.cwd(), - dot: false, - ignore: ["**/.*/**", "**/dist/**", "**/node_modules/**", "**/vendor/**"], - }) + return globSync(["**/*.{test,spec}.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"], { + cwd: process.cwd(), + exclude: ["**/.*/**", "**/dist/**", "**/node_modules/**", "**/vendor/**"], + }) .map(normalizeRepoPath) .filter( (file) => diff --git a/test/vitest/vitest.shared.config.ts b/test/vitest/vitest.shared.config.ts index 9c5342e34986..701cf01c3a58 100644 --- a/test/vitest/vitest.shared.config.ts +++ b/test/vitest/vitest.shared.config.ts @@ -32,7 +32,7 @@ export const jsdomOptimizedDeps = { optimizer: { web: { enabled: true, - include: ["lit", "lit-html", "@lit/reactive-element", "marked"] as string[], + include: ["lit", "lit-html", "@lit/reactive-element"] as string[], }, }, }; diff --git a/ui/package.json b/ui/package.json index 480cf2597027..1766fca4d225 100644 --- a/ui/package.json +++ b/ui/package.json @@ -15,7 +15,6 @@ "@codemirror/language-data": "6.5.2", "@codemirror/state": "6.7.1", "@codemirror/view": "6.43.6", - "@create-markdown/preview": "2.0.3", "@lezer/highlight": "1.2.3", "@lit/context": "1.1.6", "@lit/task": "1.0.3", @@ -41,7 +40,6 @@ "lit": "3.3.3", "markdown-it": "14.3.0", "markdown-it-task-lists": "2.1.1", - "marked": "18.0.7", "remend": "1.3.0" }, "devDependencies": { diff --git a/ui/src/components/markdown-assistant-transcript.ts b/ui/src/components/markdown-assistant-transcript.ts index 69d495e70615..31f8fba40fde 100644 --- a/ui/src/components/markdown-assistant-transcript.ts +++ b/ui/src/components/markdown-assistant-transcript.ts @@ -85,6 +85,7 @@ export function installAssistantTranscriptRoleImageRenderer( assistantLabel: () => string; openImageLabel: (alt: string, hasAlt: boolean) => string; interactiveImages: (env: unknown) => boolean; + allowRemoteImages: (env: unknown) => boolean; }, ): void { md.renderer.rules.image = (tokens, index, _rendererOptions, env) => { @@ -97,7 +98,7 @@ export function installAssistantTranscriptRoleImageRenderer( const alt = options.normalizeLabel(token.content); const roleMeta = (token.meta as AssistantTranscriptRoleImageMeta | undefined) ?.assistantTranscriptRoleImage; - if (!options.isInlineDataImage(src)) { + if (!options.isInlineDataImage(src) && !options.allowRemoteImages(env)) { return roleMeta ? renderAssistantTranscriptRoleImageLabel(roleMeta.text, roleMeta.spans, options.escapeHtml) : options.escapeHtml(alt); diff --git a/ui/src/components/markdown-document.test.ts b/ui/src/components/markdown-document.test.ts new file mode 100644 index 000000000000..85635c8b6f72 --- /dev/null +++ b/ui/src/components/markdown-document.test.ts @@ -0,0 +1,34 @@ +// Control UI tests cover full-document markdown behavior. +import { describe, expect, it } from "vitest"; +import { toSanitizedMarkdownHtml } from "./markdown.ts"; + +function htmlFragment(html: string): HTMLElement { + const container = document.createElement("div"); + container.innerHTML = html; + return container; +} + +describe("document markdown", () => { + it("preserves safe remote images while sanitizing unsafe sources", () => { + const safe = htmlFragment( + toSanitizedMarkdownHtml("![Alt text](https://example.com/img.png)", { + mode: "document", + }), + ); + const unsafe = htmlFragment( + toSanitizedMarkdownHtml("![Alt text](javascript:alert(1))", { mode: "document" }), + ); + + expect(safe.querySelector("img")?.getAttribute("src")).toBe("https://example.com/img.png"); + expect(unsafe.querySelector("img")?.hasAttribute("src")).toBe(false); + }); + + it("parses complete documents above message limits", () => { + const input = `# Start\n\n${"x".repeat(140_000)}\n\n## End`; + const fragment = htmlFragment(toSanitizedMarkdownHtml(input, { mode: "document" })); + + expect(fragment.querySelector("h1")?.textContent).toBe("Start"); + expect(fragment.querySelector("h2")?.textContent).toBe("End"); + expect(fragment.textContent).not.toContain("truncated"); + }); +}); diff --git a/ui/src/components/markdown-parser.ts b/ui/src/components/markdown-parser.ts index 9c1bb21abe34..d0ba8af041bf 100644 --- a/ui/src/components/markdown-parser.ts +++ b/ui/src/components/markdown-parser.ts @@ -393,7 +393,8 @@ export function createMarkdownParser(): MarkdownIt { return `${rendered}`; }; - // Override image to only allow base64 data URIs (#15437). + // Message rendering allows only inline data images (#15437). Document + // previews preserve authored image URLs and rely on DOMPurify's URI policy. installAssistantTranscriptRoleImageRenderer(markdownParser, { escapeHtml: escapeMarkdownHtml, isInlineDataImage: (src) => INLINE_DATA_IMAGE_RE.test(src), @@ -405,6 +406,8 @@ export function createMarkdownParser(): MarkdownIt { }), interactiveImages: (env) => (env as Partial | undefined)?.interactiveImages === true, + allowRemoteImages: (env) => + (env as Partial | undefined)?.mode === "document", }); // Override fenced code blocks with copy button + JSON collapse diff --git a/ui/src/components/markdown-render-options.ts b/ui/src/components/markdown-render-options.ts index f91c469d98a0..178213eebf45 100644 --- a/ui/src/components/markdown-render-options.ts +++ b/ui/src/components/markdown-render-options.ts @@ -1,10 +1,12 @@ type MarkdownCodeBlockChrome = "copy" | "none"; +type MarkdownRenderMode = "document" | "message"; export type MarkdownRenderOptions = { assistantTranscriptRoleHeaders?: boolean; codeBlockChrome?: MarkdownCodeBlockChrome; fileLinks?: boolean; interactiveImages?: boolean; + mode?: MarkdownRenderMode; }; export type MarkdownRenderEnv = Required; @@ -17,5 +19,6 @@ export function normalizeMarkdownRenderOptions( codeBlockChrome: options.codeBlockChrome ?? "copy", fileLinks: options.fileLinks ?? false, interactiveImages: options.interactiveImages ?? false, + mode: options.mode ?? "message", }; } diff --git a/ui/src/components/markdown.ts b/ui/src/components/markdown.ts index 90346c0f4543..1962ecb5f7ca 100644 --- a/ui/src/components/markdown.ts +++ b/ui/src/components/markdown.ts @@ -500,7 +500,10 @@ const markdownParser = createMarkdownParser(); // wrapper) keeps per-message churn out of the LRU cache. function renderSanitizedMarkdown(renderInput: string, renderOptions: MarkdownRenderEnv): string { installHooks(); - const truncated = truncateText(renderInput, MARKDOWN_CHAR_LIMIT); + const documentMode = renderOptions.mode === "document"; + const truncated = documentMode + ? { text: renderInput, truncated: false, total: renderInput.length } + : truncateText(renderInput, MARKDOWN_CHAR_LIMIT); const input = appendMarkdownTruncationNotice(truncated); if (isMarkdownBlockArtText(truncated.text)) { return DOMPurify.sanitize( @@ -508,7 +511,7 @@ function renderSanitizedMarkdown(renderInput: string, renderOptions: MarkdownRen sanitizeOptions, ); } - if (truncated.text.length > MARKDOWN_PARSE_LIMIT) { + if (!documentMode && truncated.text.length > MARKDOWN_PARSE_LIMIT) { // Large plain-text replies should stay readable without inheriting the // capped code-block chrome, while still preserving whitespace for logs // and other structured text that commonly trips the parse guard. @@ -539,7 +542,7 @@ export function toSanitizedMarkdownHtml( } const renderInput = isMarkdownBlockArtText(rawInput) ? rawInput : input; const cacheable = input.length <= MARKDOWN_CACHE_MAX_CHARS; - const cacheKey = `${i18n.getLocale()}\0${renderOptions.assistantTranscriptRoleHeaders}\0${renderOptions.codeBlockChrome}\0${renderOptions.fileLinks}\0${renderOptions.interactiveImages}\0${renderInput}`; + const cacheKey = `${i18n.getLocale()}\0${renderOptions.assistantTranscriptRoleHeaders}\0${renderOptions.codeBlockChrome}\0${renderOptions.fileLinks}\0${renderOptions.interactiveImages}\0${renderOptions.mode}\0${renderInput}`; if (cacheable) { const cached = getCachedMarkdown(cacheKey); if (cached !== null) { diff --git a/ui/src/pages/agents/panels-status-files.ts b/ui/src/pages/agents/panels-status-files.ts index 49f54542dda4..0a01419dd4e4 100644 --- a/ui/src/pages/agents/panels-status-files.ts +++ b/ui/src/pages/agents/panels-status-files.ts @@ -1,9 +1,6 @@ // Control UI view renders agents panels status files screen content. -import { applyPreviewTheme } from "@create-markdown/preview"; -import DOMPurify from "dompurify"; import { html, nothing } from "lit"; import { unsafeHTML } from "lit/directives/unsafe-html.js"; -import { marked } from "marked"; import type { AgentFileEntry, AgentsFilesListResult, @@ -15,6 +12,7 @@ import type { import { renderCronJobsPagination } from "../../components/cron-jobs-pagination.ts"; import { renderHubTabs } from "../../components/hub-tabs.ts"; import { icons } from "../../components/icons.ts"; +import { toSanitizedMarkdownHtml } from "../../components/markdown.ts"; import "../../components/modal-dialog.ts"; import type { OpenClawModalDialog } from "../../components/modal-dialog.ts"; import "../../components/tooltip.ts"; @@ -428,9 +426,7 @@ export function renderAgentFiles(params: { const draft = active ? (params.agentFileDrafts[active] ?? baseContent) : ""; const isDirty = active ? draft !== baseContent : false; const previewHtml = activeEntry - ? applyPreviewTheme(marked.parse(draft, { gfm: true, breaks: true }) as string, { - sanitize: (h: string) => DOMPurify.sanitize(h), - }) + ? toSanitizedMarkdownHtml(draft, { codeBlockChrome: "none", mode: "document" }) : ""; const draftByteSize = formatBytes(new TextEncoder().encode(draft).length); const draftWordCount = countWords(draft); diff --git a/ui/src/pages/agents/view.test.ts b/ui/src/pages/agents/view.test.ts index 33ed251c6be6..5d5bdf90e176 100644 --- a/ui/src/pages/agents/view.test.ts +++ b/ui/src/pages/agents/view.test.ts @@ -932,11 +932,10 @@ describe("renderAgentFiles", () => { agentFilesError: null, agentFileActive: "USER.md", agentFileContents: { - "USER.md": "# User Profile\n\nHello world", - }, - agentFileDrafts: { - "USER.md": "# User Profile\n\nHello world", + "USER.md": + "# User Profile\n\nHello world\n\n```ts\nconst answer = 42;\n```\n\n\n\n![Remote](https://e.co/i)", }, + agentFileDrafts: {}, agentFileSaving: false, onLoadFiles: () => undefined, onSelectFile: () => undefined, @@ -947,9 +946,6 @@ describe("renderAgentFiles", () => { container, ); - expect(container.querySelectorAll(".md-preview-dialog__reader.sidebar-markdown")).toHaveLength( - 1, - ); expect(container.querySelector(".md-preview-dialog__path")?.textContent?.trim()).toBe( "USER.md", ); @@ -959,6 +955,10 @@ describe("renderAgentFiles", () => { expect(container.querySelector(".md-preview-dialog__eyebrow span")?.textContent?.trim()).toBe( "Markdown Preview", ); + const reader = container.querySelector(".md-preview-dialog__reader.sidebar-markdown"); + expect(reader?.querySelector("img")?.getAttribute("src")).toBe("https://e.co/i"); + expect(reader?.querySelector("pre code")?.textContent).toBe("const answer = 42;\n"); + expect(reader?.querySelector(".code-block-copy, script")).toBeNull(); }); it("renders preview header controls as icon-only buttons with accessible labels", () => { diff --git a/ui/src/styles.css b/ui/src/styles.css index a2c77cf9a1b0..d5da3a5d4ea5 100644 --- a/ui/src/styles.css +++ b/ui/src/styles.css @@ -5,19 +5,9 @@ @import "./styles/components.css"; @import "./styles/approval-boot.css"; @import "./styles/settings.css"; -@import "@create-markdown/preview/themes/system.css"; /* Contract read by stale-chunk-reload.ts to detect a failed entry stylesheet load. * Removing it leaves a fully unstyled page undetected. */ :root { --openclaw-css-ok: 1; } - -.cm-preview { - --cm-mono: var(--mono); - --cm-link: var(--accent); - --cm-info: var(--info); - --cm-warning: var(--warn); - --cm-success: var(--ok); - --cm-danger: var(--danger); -} diff --git a/ui/src/styles/base.css b/ui/src/styles/base.css index 6881d2ad7bb5..4ceb7ce16d46 100644 --- a/ui/src/styles/base.css +++ b/ui/src/styles/base.css @@ -841,17 +841,6 @@ textarea, width: 85%; } -.skeleton-stat { - height: 28px; - width: 60px; - border-radius: var(--radius-sm); -} - -.skeleton-block { - height: 48px; - border-radius: var(--radius-md); -} - @keyframes pulse-subtle { 0%, 100% { @@ -862,43 +851,6 @@ textarea, } } -@keyframes glow-pulse { - 0%, - 100% { - box-shadow: 0 0 0 transparent; - } - 50% { - box-shadow: 0 0 20px var(--accent-glow); - } -} - -@media (prefers-reduced-motion: reduce) { - .glow-pulse, - [class*="glow-pulse"] { - animation: none !important; - } -} - -/* Stagger animation delays for grouped elements */ -.stagger-1 { - animation-delay: 0ms; -} -.stagger-2 { - animation-delay: 50ms; -} -.stagger-3 { - animation-delay: 100ms; -} -.stagger-4 { - animation-delay: 150ms; -} -.stagger-5 { - animation-delay: 200ms; -} -.stagger-6 { - animation-delay: 250ms; -} - @media (prefers-reduced-motion: reduce) { *, *::before, diff --git a/ui/src/styles/chat/layout.css b/ui/src/styles/chat/layout.css index 7b6da2791874..df01db621723 100644 --- a/ui/src/styles/chat/layout.css +++ b/ui/src/styles/chat/layout.css @@ -261,33 +261,6 @@ openclaw-chat-page { min-height: 0; } -/* Chat header - fixed at top, transparent */ -.chat-header { - display: flex; - justify-content: space-between; - align-items: flex-end; - gap: 16px; - flex-wrap: wrap; - flex-shrink: 0; - padding-bottom: 0; - margin-bottom: 0; - background: transparent; -} - -.chat-header__left { - display: flex; - align-items: flex-end; - gap: 12px; - flex-wrap: wrap; - min-width: 0; -} - -.chat-header__right { - display: flex; - align-items: center; - gap: 8px; -} - .chat-session { min-width: 240px; } @@ -947,87 +920,6 @@ openclaw-chat-page { color: color-mix(in srgb, var(--ok) 72%, var(--text)); } -/* Image attachments preview */ -.chat-attachments { - display: inline-flex; - flex-wrap: wrap; - gap: 8px; - padding: 8px; - background: var(--panel); - border-radius: var(--radius-md); - border: 1px solid var(--border); - width: fit-content; - max-width: 100%; - align-self: flex-start; - /* Don't stretch in flex column parent */ -} - -.chat-attachment { - position: relative; - width: 80px; - height: 80px; - border-radius: var(--radius-sm); - overflow: hidden; - border: 1px solid var(--border); - background: var(--bg); -} - -.chat-attachment__img { - width: 100%; - height: 100%; - object-fit: contain; -} - -.chat-attachment__remove { - position: absolute; - top: 4px; - right: 4px; - width: 24px; - height: 24px; - border-radius: 50%; - border: none; - background: rgba(0, 0, 0, 0.7); - color: #fff; - font-size: 12px; - line-height: 1; - display: flex; - align-items: center; - justify-content: center; - opacity: 0; - transition: opacity 150ms ease-out; -} - -.chat-attachment:hover .chat-attachment__remove { - opacity: 1; -} - -.chat-attachment__remove:hover { - background: color-mix(in srgb, var(--danger) 90%, black); -} - -.chat-attachment__remove svg { - width: 12px; - height: 12px; - stroke: currentColor; - fill: none; - stroke-width: 2px; -} - -/* Light theme attachment overrides */ -:root[data-theme-mode="light"] .chat-attachments { - background: #f8fafc; - border-color: rgba(16, 24, 40, 0.1); -} - -:root[data-theme-mode="light"] .chat-attachment { - border-color: rgba(16, 24, 40, 0.15); - background: #fff; -} - -:root[data-theme-mode="light"] .chat-attachment__remove { - background: rgba(0, 0, 0, 0.6); -} - /* Message images (sent images displayed in chat) */ .chat-message-images { display: flex; @@ -2411,14 +2303,11 @@ openclaw-chat-video-player { padding: 8px 10px 0; } -.agent-chat__composer-status-stack:not( - :has(.compaction-indicator, .fallback-indicator, .agent-chat__goal) -) { +.agent-chat__composer-status-stack:not(:has(.compaction-indicator, .agent-chat__goal)) { display: none; } .agent-chat__composer-status-stack .compaction-indicator, -.agent-chat__composer-status-stack .fallback-indicator, .agent-chat__composer-status-stack .agent-chat__goal { margin: 0; } @@ -2453,11 +2342,6 @@ openclaw-chat-video-player { max-width: min(240px, 30vw); } -.agent-chat__composer-session { - min-width: 0; - flex: 1 1 260px; -} - .agent-chat__composer-controls .chat-controls { display: flex; justify-content: flex-end; @@ -2470,11 +2354,6 @@ openclaw-chat-video-player { min-width: 0; } -.agent-chat__composer-controls .chat-controls__actions { - flex-wrap: wrap; - justify-content: flex-end; -} - .chat-view-menu-wrapper { position: relative; display: inline-flex; @@ -2551,23 +2430,6 @@ openclaw-chat-video-player { text-align: left; } -.chat-view-menu__check { - display: inline-flex; - align-items: center; - justify-content: center; - width: 16px; - height: 16px; - flex: 0 0 auto; -} - -.chat-view-menu__check svg { - width: 14px; - height: 14px; - stroke: currentColor; - fill: none; - stroke-width: 2px; -} - .chat-view-menu__text { min-width: 0; overflow: hidden; @@ -2634,8 +2496,7 @@ openclaw-chat-video-player { padding: calc(var(--chat-box-inset) / 2) var(--chat-box-inset); } -.agent-chat__composer-meta, -.agent-chat__toolbar-right { +.agent-chat__composer-meta { display: flex; align-items: center; gap: 4px; @@ -2653,8 +2514,7 @@ openclaw-chat-video-player { flex: 0 0 auto; } -.agent-chat__input-btn, -.agent-chat__toolbar-right .btn--ghost { +.agent-chat__input-btn { display: inline-flex; align-items: center; justify-content: center; @@ -2670,8 +2530,7 @@ openclaw-chat-video-player { transition: all var(--duration-fast) ease; } -.agent-chat__input-btn svg, -.agent-chat__toolbar-right .btn--ghost svg { +.agent-chat__input-btn svg { width: 18px; height: 18px; fill: none; @@ -2685,14 +2544,12 @@ openclaw-chat-video-player { display: none; } -.agent-chat__input-btn:hover:not(:disabled), -.agent-chat__toolbar-right .btn--ghost:hover:not(:disabled) { +.agent-chat__input-btn:hover:not(:disabled) { color: var(--text); background: var(--bg-hover); } -.agent-chat__input-btn:disabled, -.agent-chat__toolbar-right .btn--ghost:disabled { +.agent-chat__input-btn:disabled { opacity: 0.4; cursor: not-allowed; } @@ -2900,17 +2757,6 @@ openclaw-chat-video-player { /* Selected/open states stay a quiet neutral wash; only live recording gets a (soft) danger tint so "active" chrome never competes with the send button. */ -.agent-chat__input-btn--active, -.agent-chat__input-btn--open { - color: var(--text); - background: color-mix(in srgb, var(--text) 7%, transparent); -} - -.agent-chat__input-btn--talk { - color: var(--danger, #ef4444); - background: color-mix(in srgb, var(--danger, #ef4444) 9%, transparent); -} - .agent-chat__talk-status { display: flex; align-items: center; @@ -3080,13 +2926,6 @@ openclaw-chat-video-player { opacity: 0.7; } -.agent-chat__input-divider { - width: 1px; - height: 16px; - background: var(--border); - margin: 0 4px; -} - .agent-chat__run-status { display: inline-flex; align-items: center; @@ -3158,8 +2997,7 @@ openclaw-chat-video-player { } @media (max-width: 860px) { - .agent-chat__input-btn, - .agent-chat__toolbar-right .btn--ghost { + .agent-chat__input-btn { width: 36px; min-width: 36px; padding: 0; @@ -3692,12 +3530,6 @@ openclaw-chat-video-player { padding: 0; } - .agent-chat__toolbar-right { - flex-direction: column; - gap: 8px; - margin-bottom: calc(var(--chat-box-inset, 4px) + 1px); - } - .agent-chat__composer-shell { grid-template-columns: minmax(0, 1fr); gap: 0; @@ -4068,11 +3900,6 @@ openclaw-chat-video-player { gap: 4px; } -.chat-attachment-file__meta { - color: var(--muted); - font-size: 0.68rem; -} - .chat-attachment-text-action { display: inline-flex; width: fit-content; @@ -4154,103 +3981,10 @@ openclaw-chat-video-player { position: relative; } -.chat-controls__session-trigger { - display: flex; - align-items: center; - justify-content: space-between; - gap: 6px; - width: 100%; - min-height: 36px; - padding: 8px 10px 8px 12px; - border: 1px solid var(--input); - border-radius: var(--radius-md); - background: var(--bg-elevated); - color: var(--text); - font: inherit; - font-size: 14px; - line-height: 1.2; - min-width: 0; - transition: - background var(--duration-fast) ease-out, - border-color var(--duration-fast) ease-out; -} - -.chat-controls__session-trigger:hover:not(:disabled), -.chat-controls__session-trigger[aria-expanded="true"] { - border-color: color-mix(in srgb, var(--accent) 38%, var(--input)); - background: color-mix(in srgb, var(--bg-elevated) 90%, var(--accent-subtle) 10%); -} - -.chat-controls__session-trigger:disabled { - cursor: default; - opacity: 0.6; -} - -.chat-controls__session-trigger-label { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - min-width: 0; -} - -.chat-controls__session-trigger-icon { - display: inline-flex; - width: 16px; - height: 16px; - flex: 0 0 auto; - color: var(--muted); -} - -.chat-controls__session-trigger-icon svg { - width: 16px; - height: 16px; - stroke: currentColor; - fill: none; - stroke-width: 1.5px; -} - .chat-controls__agent { grid-area: agent; } -.chat-controls__session-row--flash .chat-controls__session-trigger { - animation: chat-session-switch-flash 0.2s ease-out; -} - -.chat-controls__session-notice { - width: 100%; - min-height: 16px; - font-size: 12px; - line-height: 16px; - color: var(--muted); -} - -@keyframes chat-session-switch-flash { - 0% { - border-color: color-mix(in srgb, var(--accent) 72%, var(--border)); - background: color-mix(in srgb, var(--accent-subtle) 62%, var(--card)); - box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent); - } - 100% { - border-color: var(--border); - background: var(--card); - box-shadow: none; - } -} - -@media (prefers-reduced-motion: reduce) { - .chat-controls__session-row--flash .chat-controls__session-trigger { - animation: none; - border-color: color-mix(in srgb, var(--accent) 70%, var(--border)); - box-shadow: var(--focus-ring); - } - - .agent-chat__talk-input-refresh:disabled svg, - .agent-chat__talk-input-spinner { - animation: none; - } -} - .chat-controls__model { grid-area: model; min-width: 0; @@ -4703,21 +4437,6 @@ openclaw-chat-video-player { font-size: 12px; } -.chat-controls__model-provenance-state { - display: inline-flex; - align-items: center; - gap: 4px; - min-width: 0; - padding-right: 6px; -} - -.chat-controls__model-provenance-value { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-size: 12px; -} - .chat-controls__model-provenance-value--inherit { color: var(--muted); } @@ -5179,10 +4898,6 @@ openclaw-chat-video-player { border: 1px solid var(--border); } -.chat-controls__auto-expand { - padding: 8px; -} - /* Light theme thinking indicator override */ :root[data-theme-mode="light"] .chat-controls__thinking { background: rgba(255, 255, 255, 0.9); @@ -5190,15 +4905,6 @@ openclaw-chat-video-player { } @media (max-width: 768px) { - .agent-chat__talk-options--settings .agent-chat__talk-options-primary, - .agent-chat__talk-options--settings .agent-chat__talk-options-grid { - grid-template-columns: minmax(0, 1fr); - } - - .agent-chat__talk-input-setting { - order: -1; - } - .chat-controls__session { min-width: 120px; max-width: none; @@ -5219,7 +4925,6 @@ openclaw-chat-video-player { } .agent-chat__input-btn, - .agent-chat__toolbar-right .btn--ghost, .chat-send-btn { width: 44px; min-width: 44px; diff --git a/ui/src/styles/components.css b/ui/src/styles/components.css index b8811e883818..bf267d529aab 100644 --- a/ui/src/styles/components.css +++ b/ui/src/styles/components.css @@ -162,13 +162,6 @@ openclaw-session-owner-chip { padding: 24px; } -.login-gate__theme { - position: fixed; - top: 16px; - right: 16px; - z-index: 10; -} - .login-gate__card { width: min(520px, 100%); margin-block: auto; @@ -380,64 +373,6 @@ openclaw-session-owner-chip { } } -/* =========================================== - Update Banner - =========================================== */ - -.update-banner { - position: sticky; - top: 0; - z-index: 10; - margin: 0 calc(-1 * var(--shell-pad)) 0; - border-radius: 0; - border-left: none; - border-right: none; - text-align: center; - font-weight: 500; - padding: 10px 16px; -} - -.update-banner .update-banner__btn { - margin-left: 8px; - border-color: currentColor; - color: currentColor; - font-size: 12px; - padding: 4px 12px; -} - -.update-banner .update-banner__btn:hover:not(:disabled) { - border-color: currentColor; - background: color-mix(in srgb, currentColor 14%, transparent); -} - -.update-banner__close { - display: inline-flex; - align-items: center; - justify-content: center; - margin-left: 8px; - padding: 4px; - min-width: 24px; - min-height: 24px; - background: none; - border: none; - color: currentColor; - opacity: 0.7; - transition: opacity 0.15s; -} - -.update-banner__close:hover { - opacity: 1; -} - -.update-banner__close svg { - width: 16px; - height: 16px; - fill: none; - stroke: currentColor; - stroke-width: 2; - stroke-linecap: round; -} - /* =========================================== Cards - Refined with depth =========================================== */ @@ -490,14 +425,6 @@ openclaw-session-owner-chip { border-color: var(--border-strong); } -.stat-label { - color: var(--muted); - font-size: 12px; /* was 11px */ - font-weight: 500; - text-transform: uppercase; - letter-spacing: 0.04em; -} - .stat-value { font-size: 24px; font-weight: 700; @@ -506,16 +433,6 @@ openclaw-session-owner-chip { line-height: 1.1; } -.stat-card { - display: grid; - gap: 6px; -} - -.note-title { - font-weight: 600; - letter-spacing: -0.01em; -} - /* =========================================== Labels & Pills =========================================== */ @@ -581,60 +498,6 @@ openclaw-session-owner-chip { opacity: 0.5; } -/* =========================================== - Skill Toggle Switch - =========================================== */ - -.skill-toggle-wrap { - display: inline-flex; - align-items: center; -} - -.skill-toggle { - appearance: none; - width: 36px; - height: 20px; - border-radius: var(--radius-full); - background: var(--border); - position: relative; - border: none; - outline: none; - transition: - background var(--duration-fast) var(--ease-out), - box-shadow var(--duration-fast) var(--ease-out); - flex-shrink: 0; -} - -.skill-toggle::after { - content: ""; - position: absolute; - top: 2px; - left: 2px; - width: 16px; - height: 16px; - border-radius: var(--radius-full); - background: white; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); - transition: transform var(--duration-fast) var(--ease-out); -} - -.skill-toggle:checked { - background: var(--accent); -} - -.skill-toggle:checked::after { - transform: translateX(16px); -} - -.skill-toggle:focus-visible { - box-shadow: var(--focus-ring); -} - -.skill-toggle:disabled { - opacity: 0.4; - cursor: not-allowed; -} - /* =========================================== Buttons - Tactile with personality =========================================== */ @@ -701,35 +564,6 @@ openclaw-session-owner-chip { background: var(--primary-hover); } -/* Keyboard shortcut badge (shadcn style) */ -.btn-kbd { - display: inline-flex; - align-items: center; - justify-content: center; - margin-left: 6px; - padding: 2px 5px; - font-family: var(--mono); - font-size: 12px; /* was 11px */ - font-weight: 500; - line-height: 1; - border-radius: var(--radius-sm); - background: rgba(255, 255, 255, 0.15); - color: inherit; - opacity: 0.8; -} - -.btn.primary .btn-kbd { - background: rgba(255, 255, 255, 0.2); -} - -:root[data-theme-mode="light"] .btn-kbd { - background: rgba(0, 0, 0, 0.08); -} - -:root[data-theme-mode="light"] .btn.primary .btn-kbd { - background: rgba(255, 255, 255, 0.25); -} - .btn.active { border-color: var(--accent); background: var(--accent-subtle); @@ -1290,12 +1124,6 @@ openclaw-session-owner-chip { height: 16px; } -.form-grid { - display: grid; - gap: 12px; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); -} - /* =========================================== Cron Form =========================================== */ @@ -1376,14 +1204,6 @@ openclaw-session-owner-chip { white-space: nowrap; } -.summary-strip__actions { - display: flex; - align-items: center; - justify-content: flex-end; - gap: 10px; - min-width: 0; -} - .field input[aria-invalid="true"], .field textarea[aria-invalid="true"], .field select[aria-invalid="true"] { @@ -1400,12 +1220,6 @@ openclaw-session-owner-chip { width: 100%; gap: 8px 18px; } - - .summary-strip__actions { - width: 100%; - justify-content: flex-start; - flex-wrap: wrap; - } } :root[data-theme-mode="light"] .field input, @@ -2168,7 +1982,6 @@ openclaw-chat-session-rail { :root[data-theme-mode="light"] .code-block, :root[data-theme-mode="light"] .list-item, -:root[data-theme-mode="light"] .table-row, :root[data-theme-mode="light"] .chip { background: var(--bg); } @@ -2468,34 +2281,12 @@ openclaw-chat-session-rail { border-color: var(--border-strong); } -.list-item-selected { - border-color: var(--accent); - box-shadow: var(--focus-ring); -} - .list-main { display: grid; gap: 4px; min-width: 0; } -.list-item__detail-button { - width: 100%; - border: 0; - border-radius: var(--radius-sm); - padding: 0; - background: transparent; - color: inherit; - font: inherit; - text-align: left; - cursor: pointer; -} - -.list-item__detail-button:focus-visible { - outline: none; - box-shadow: var(--focus-ring); -} - .list-title { font-weight: 500; } @@ -2844,42 +2635,6 @@ td.data-table-key-col { cursor: not-allowed; } -/* Inline form fields for filter bars */ -.field-inline { - display: inline-flex; - align-items: center; - gap: 6px; - font-size: 13px; - color: var(--text); -} - -.field-inline span { - color: var(--muted); - font-weight: 500; - white-space: nowrap; -} - -.field-inline input[type="text"], -.field-inline input:not([type]) { - padding: 6px 10px; - font-size: 13px; - color: var(--text); - background: var(--card); - border: 1px solid var(--border); - border-radius: var(--radius-sm); - outline: none; - transition: border-color var(--duration-fast) ease; -} - -.field-inline input:focus-visible { - border-color: var(--border-strong); - box-shadow: var(--focus-ring); -} - -.field-inline.checkbox { - gap: 4px; -} - /* =========================================== Log Stream =========================================== */ @@ -3479,12 +3234,6 @@ td.data-table-key-col { gap: 14px; } -.agents-sidebar { - display: grid; - gap: 12px; - align-self: start; -} - .agents-toolbar { display: flex; align-items: center; @@ -3749,85 +3498,6 @@ td.data-table-key-col { gap: 14px; } -.agent-list { - display: grid; - gap: 8px; -} - -.agent-row { - display: grid; - grid-template-columns: auto minmax(0, 1fr) auto; - align-items: center; - gap: 10px; - width: 100%; - text-align: left; - border: 1px solid var(--border); - border-radius: var(--radius-md); - background: var(--card); - padding: 8px 12px; - transition: border-color var(--duration-fast) ease; -} - -.agent-row:hover { - border-color: var(--border-strong); -} - -.agent-row.active { - border-color: var(--accent); - box-shadow: var(--focus-ring); -} - -.agent-avatar { - width: 32px; - height: 32px; - border-radius: 50%; - background: var(--secondary); - display: grid; - place-items: center; - font-weight: 600; -} - -.agent-avatar--lg { - width: 48px; - height: 48px; - font-size: 20px; -} - -.agent-info { - display: grid; - gap: 2px; - min-width: 0; -} - -.agent-title { - font-weight: 600; -} - -.agent-sub { - color: var(--muted); - font-size: 12px; -} - -.agent-header { - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - gap: 12px; - align-items: center; -} - -.agent-header-main { - display: flex; - gap: 12px; - align-items: center; -} - -.agent-header-meta { - display: grid; - justify-items: end; - gap: 6px; - color: var(--muted); -} - .agent-file-tabs { display: flex; align-items: flex-end; @@ -4234,10 +3904,6 @@ td.data-table-key-col { .md-preview-dialog__reader { --md-preview-serif: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia, serif; --md-preview-document-bg: color-mix(in srgb, var(--bg) 92%, var(--panel) 8%); - --cm-bg: transparent; - --cm-border: color-mix(in srgb, var(--border) 72%, white 10%); - --cm-code-bg: color-mix(in srgb, var(--bg-elevated) 72%, black 28%); - --cm-inline-code-bg: color-mix(in srgb, var(--secondary) 58%, transparent); position: relative; width: min(100%, 82ch); margin: 0 auto; @@ -4269,10 +3935,6 @@ td.data-table-key-col { z-index: 1; } -.md-preview-dialog__reader .cm-preview { - background: transparent; -} - .md-preview-dialog__reader.sidebar-markdown { font-size: 15px; line-height: 1.74; @@ -4958,14 +4620,6 @@ td.data-table-key-col { } @media (max-width: 980px) { - .agent-header { - grid-template-columns: 1fr; - } - - .agent-header-meta { - justify-items: start; - } - .agent-tools-list { grid-template-columns: 1fr; } @@ -5105,25 +4759,6 @@ td.data-table-key-col { } @media (max-width: 768px) { - .agent-row { - padding: 8px 10px; - gap: 8px; - } - - .agent-avatar--lg { - width: 40px; - height: 40px; - font-size: 18px; - } - - .agent-header { - gap: 8px; - } - - .agent-header-main { - gap: 8px; - } - .exec-approval-card { padding: 16px; display: flex; @@ -5145,15 +4780,6 @@ td.data-table-key-col { max-height: 40dvh; overflow-y: auto; } - - .table-head { - display: none; - } - - .table-row { - grid-template-columns: 1fr; - gap: 6px; - } } /* ── Shared collapse chevron ── */ diff --git a/ui/src/styles/cron.css b/ui/src/styles/cron.css index f79bc20ed3e1..cc1c6bf0583a 100644 --- a/ui/src/styles/cron.css +++ b/ui/src/styles/cron.css @@ -231,10 +231,6 @@ height: 32px; } -.cron-filter-popover__trigger::-webkit-details-marker { - display: none; -} - .cron-filter-popover__trigger svg { width: 14px; height: 14px; @@ -777,10 +773,6 @@ padding: 0; } -.cron-job-menu__trigger::-webkit-details-marker { - display: none; -} - /* Invisible full-viewport hit area so clicking anywhere outside closes the menu. */ .cron-job-menu[open] > .cron-job-menu__trigger::before { content: ""; @@ -790,21 +782,6 @@ cursor: default; } -.cron-job-menu__panel { - position: absolute; - z-index: 40; - top: calc(100% + 6px); - right: 0; - min-width: 170px; - border: 1px solid var(--border); - border-radius: var(--radius-md); - background: var(--bg-elevated); - padding: var(--space-1); - display: grid; - gap: 2px; - box-shadow: var(--shadow-lg); -} - .cron-job-menu__item { border: 0; background: transparent; @@ -880,14 +857,6 @@ position: relative; } -.cron-filter-dropdown__details > summary { - list-style: none; -} - -.cron-filter-dropdown__details > summary::-webkit-details-marker { - display: none; -} - .cron-filter-dropdown__trigger { justify-content: space-between; text-align: left; @@ -901,26 +870,6 @@ color: var(--muted); } -.cron-filter-dropdown__panel { - position: absolute; - z-index: 30; - top: calc(100% + 8px); - left: 0; - width: min(300px, calc(100vw - 48px)); - border: 1px solid var(--border); - border-radius: var(--radius-md); - background: var(--bg-elevated); - padding: var(--space-3); - display: grid; - gap: var(--space-3); - box-shadow: var(--shadow-lg); -} - -.cron-filter-dropdown__list { - display: grid; - gap: var(--space-1); -} - .cron-filter-dropdown__option { display: grid; grid-template-columns: 16px minmax(0, 1fr); @@ -930,12 +879,6 @@ font-size: 13px; } -.cron-filter-dropdown__option input[type="checkbox"] { - width: 16px; - height: 16px; - margin: 0; -} - /* Run entries: flat list separated by hairlines inside the group. */ .cron-run-entry { @@ -1046,15 +989,6 @@ /* ── Responsive ── */ -@media (max-width: 1100px) { - .cron-filter-dropdown__panel { - width: 100%; - max-width: none; - position: static; - margin-top: var(--space-2); - } -} - @media (max-width: 900px) { /* Stack table rows into label-free cards; hide the head and secondary cells. */ .cron-table__head { diff --git a/ui/src/styles/layout.css b/ui/src/styles/layout.css index 71b5e3ffb239..a5130cebd81a 100644 --- a/ui/src/styles/layout.css +++ b/ui/src/styles/layout.css @@ -1451,13 +1451,6 @@ html.openclaw-native-macos cursor: grabbing; } -.sidebar-recent-sessions__head--root { - position: sticky; - top: 0; - z-index: 2; - background: var(--sidebar-bg); -} - .sidebar-session-group-toggle { display: flex; align-items: center; @@ -2423,13 +2416,6 @@ html.openclaw-native-macos box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--accent) 75%, transparent); } -/* Button variant of .nav-item (e.g. the "More" menu row). */ -.nav-item--action { - width: 100%; - font: inherit; - text-align: left; -} - .sidebar-customize-menu:not(wa-dropdown) { position: fixed; z-index: 120; @@ -2686,8 +2672,7 @@ wa-dropdown.sidebar-session-sort-menu::part(menu) { } .session-menu__icon svg, -.session-menu__check svg, -.session-menu__chevron svg { +.session-menu__check svg { width: 14px; height: 14px; stroke: currentColor; @@ -2715,11 +2700,6 @@ wa-dropdown.sidebar-session-sort-menu::part(menu) { white-space: nowrap; } -.session-menu__chevron { - display: inline-flex; - color: var(--muted); -} - .session-menu__shortcut { flex: 0 0 auto; color: var(--muted); @@ -2739,23 +2719,6 @@ wa-dropdown.sidebar-session-sort-menu::part(menu) { border-top: 1px solid color-mix(in srgb, var(--border) 80%, transparent); } -.session-menu__submenu-host { - position: relative; -} - -.session-menu__submenu { - position: absolute; - top: -6px; - left: calc(100% + 4px); - max-height: min(360px, calc(100vh - 24px)); - overflow-y: auto; -} - -.session-menu__submenu--left { - right: calc(100% + 4px); - left: auto; -} - .session-menu__icon-picker { width: 184px; padding: 8px; @@ -3458,7 +3421,6 @@ openclaw-tooltip.sidebar-hover-tooltip { font-weight: 550; } -.sidebar-hover-card__you, .sidebar-hover-card__person-email { color: var(--muted); font-weight: 400; @@ -3684,23 +3646,6 @@ wa-dropdown.sidebar-identity-menu::part(menu) { white-space: nowrap; } -.sidebar-status__dot { - width: 8px; - height: 8px; - border-radius: var(--radius-full); - flex-shrink: 0; -} - -.sidebar-status__dot.sidebar-connection-status--online { - background: var(--ok); - box-shadow: 0 0 0 4px color-mix(in srgb, var(--ok) 14%, transparent); -} - -.sidebar-status__dot.sidebar-connection-status--offline { - background: var(--danger); - box-shadow: 0 0 0 4px color-mix(in srgb, var(--danger) 14%, transparent); -} - .sidebar-mode-switch { display: inline-flex; margin-left: 2px; @@ -3743,32 +3688,6 @@ wa-dropdown.sidebar-identity-menu::part(menu) { stroke-linejoin: round; } -.nav-item__external-icon { - width: 12px; - height: 12px; - display: inline-flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - margin-left: auto; - opacity: 0; - transition: opacity var(--duration-fast) ease; -} - -.nav-item__external-icon svg { - width: 12px; - height: 12px; - stroke: currentColor; - fill: none; - stroke-width: 1.5px; - stroke-linecap: round; - stroke-linejoin: round; -} - -.nav-item:hover .nav-item__external-icon { - opacity: 0.5; -} - /* =========================================== Content Area =========================================== */ @@ -3955,90 +3874,6 @@ html:not(.openclaw-native-macos):not(.openclaw-native-nav):not(.openclaw-native- gap: 8px; } -.dreaming-header-controls__modes { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 3px; - border: 1px solid var(--border); - border-radius: var(--radius-full); - background: color-mix(in srgb, var(--bg-elevated) 88%, transparent); -} - -.dreaming-header-controls__mode { - appearance: none; - border: 1px solid transparent; - border-radius: var(--radius-full); - padding: 4px 10px; - background: transparent; - color: var(--muted); - font-size: 12px; /* was 11px */ - line-height: 1.2; - letter-spacing: 0.08em; - text-transform: uppercase; - font-weight: 600; - display: inline-flex; - align-items: center; - gap: 0; - max-width: 90px; - overflow: hidden; - transition: - max-width var(--duration-fast) ease, - border-color var(--duration-fast) ease, - background var(--duration-fast) ease, - color var(--duration-fast) ease; -} - -.dreaming-header-controls__mode:hover:not(:disabled) { - border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); - color: var(--text); - max-width: 290px; -} - -.dreaming-header-controls__mode:focus-visible:not(:disabled) { - max-width: 290px; -} - -.dreaming-header-controls__mode:disabled { - opacity: 0.55; - cursor: default; -} - -.dreaming-header-controls__mode--active { - border-color: color-mix(in srgb, var(--accent) 62%, var(--border)); - background: color-mix(in srgb, var(--accent-subtle) 70%, var(--bg-elevated)); - color: var(--text-strong); -} - -.dreaming-header-controls__mode-label { - flex-shrink: 0; -} - -.dreaming-header-controls__mode-detail { - max-width: 0; - opacity: 0; - margin-left: 0; - overflow: hidden; - white-space: nowrap; - text-transform: none; - letter-spacing: normal; - font-size: 12px; /* was 10px */ - font-weight: 500; - color: color-mix(in srgb, var(--muted) 86%, var(--text) 14%); - transition: - max-width var(--duration-fast) ease, - margin-left var(--duration-fast) ease, - opacity var(--duration-fast) ease; -} - -.dreaming-header-controls__mode:hover:not(:disabled) .dreaming-header-controls__mode-detail, -.dreaming-header-controls__mode:focus-visible:not(:disabled) - .dreaming-header-controls__mode-detail { - max-width: 220px; - margin-left: 6px; - opacity: 0.95; -} - /* Chat view header adjustments */ .content--chat .content-header { display: grid; @@ -4075,18 +3910,6 @@ html:not(.openclaw-native-macos):not(.openclaw-native-nav):not(.openclaw-native- gap: 6px; } -.content--chat .content-header .chat-controls__session-notice { - position: absolute; - top: calc(100% + 2px); - left: 0; - width: min(100%, 680px); - min-height: 0; - overflow: hidden; - pointer-events: none; - text-overflow: ellipsis; - white-space: nowrap; -} - /* =========================================== Grid Utilities =========================================== */ diff --git a/ui/src/styles/layout.mobile.css b/ui/src/styles/layout.mobile.css index db5df80d880b..bc01624498f7 100644 --- a/ui/src/styles/layout.mobile.css +++ b/ui/src/styles/layout.mobile.css @@ -416,12 +416,6 @@ html.openclaw-native-macos body .shell--mobile-nav .topnav-shell__actions { grid-area: session; } - .chat-mobile-controls-wrapper .chat-controls-dropdown .chat-controls__session-trigger { - min-height: 44px; - padding: 10px 12px; - font-size: 14px; - } - .chat-mobile-controls-wrapper .chat-controls-dropdown .chat-controls__model { grid-area: model; } @@ -440,8 +434,7 @@ html.openclaw-native-macos body .shell--mobile-nav .topnav-shell__actions { width: 100%; } - .chat-mobile-controls-wrapper .chat-controls-dropdown .chat-controls__session select, - .chat-mobile-controls-wrapper .chat-controls-dropdown .chat-controls__session-trigger { + .chat-mobile-controls-wrapper .chat-controls-dropdown .chat-controls__session select { width: 100%; font-size: 14px; min-height: 44px; @@ -492,20 +485,11 @@ html.openclaw-native-macos body .shell--mobile-nav .topnav-shell__actions { border-radius: var(--radius-md); } - .stat-label { - font-size: 12px; /* was 11px */ - } - .stat-value { font-size: 18px; } /* Forms */ - .form-grid { - grid-template-columns: 1fr; - gap: 10px; - } - .field input, .field textarea, .field select { @@ -527,21 +511,6 @@ html.openclaw-native-macos body .shell--mobile-nav .topnav-shell__actions { } /* Chat */ - .chat-header { - flex-direction: column; - align-items: stretch; - gap: 8px; - } - - .chat-header__left { - flex-direction: column; - align-items: stretch; - } - - .chat-header__right { - justify-content: space-between; - } - .chat-session { min-width: unset; width: 100%; @@ -571,20 +540,7 @@ html.openclaw-native-macos body .shell--mobile-nav .topnav-shell__actions { margin: 0 8px calc(10px + var(--safe-area-bottom)); } - .agent-chat__toolbar { - align-items: stretch; - gap: 8px; - padding: 6px 8px; - } - - .agent-chat__toolbar-left, - .agent-chat__toolbar-right { - flex-wrap: wrap; - gap: 6px; - } - .agent-chat__input-btn, - .agent-chat__toolbar .btn--ghost, .chat-send-btn { width: 44px; min-width: 44px; @@ -592,7 +548,6 @@ html.openclaw-native-macos body .shell--mobile-nav .topnav-shell__actions { } .agent-chat__input-btn svg, - .agent-chat__toolbar .btn--ghost svg, .chat-send-btn svg { width: 16px; height: 16px; diff --git a/ui/src/styles/model-providers.css b/ui/src/styles/model-providers.css index f44a5c98e4f2..977686953f72 100644 --- a/ui/src/styles/model-providers.css +++ b/ui/src/styles/model-providers.css @@ -53,7 +53,6 @@ letter-spacing: 0.04em; } -.model-providers__layout, .model-providers__fallbacks, .model-providers__inline-form, .model-providers__probe { @@ -135,9 +134,7 @@ .model-providers__probe-summary, .model-providers__probe-target, .model-providers__fallback-heading, -.model-providers__fallback-row, -.model-providers__defaults-heading, -.model-providers__add-heading { +.model-providers__fallback-row { display: flex; align-items: center; justify-content: space-between; @@ -194,11 +191,6 @@ grid-template-columns: minmax(160px, 0.8fr) minmax(220px, 1.4fr) auto; } -.model-providers__card .callout, -.model-providers__add .callout { - margin-top: 10px; -} - @media (max-width: 700px) { .model-providers__head { align-items: flex-start; @@ -221,9 +213,7 @@ } .model-providers__credentials, - .model-providers__confirm, - .model-providers__defaults-heading, - .model-providers__add-heading { + .model-providers__confirm { align-items: flex-start; flex-direction: column; } diff --git a/ui/src/styles/usage.css b/ui/src/styles/usage.css index 6082ddbe105a..7f0847da49b2 100644 --- a/ui/src/styles/usage.css +++ b/ui/src/styles/usage.css @@ -340,8 +340,7 @@ .usage-presets, .usage-date-range, .chart-toggle, -.usage-query-actions, -.usage-filter-actions { +.usage-query-actions { display: inline-flex; align-items: center; gap: 6px; @@ -479,12 +478,6 @@ font-weight: 600; } -.usage-export-item:disabled { - opacity: 0.45; - cursor: not-allowed; - box-shadow: none; -} - .usage-query-section { display: grid; gap: 10px; @@ -536,16 +529,6 @@ position: relative; } -details.usage-filter-select summary, -.usage-export-menu summary { - list-style: none; -} - -details.usage-filter-select summary::-webkit-details-marker, -.usage-export-menu summary::-webkit-details-marker { - display: none; -} - .usage-filter-trigger { display: inline-flex; align-items: center; @@ -580,35 +563,6 @@ details.usage-filter-select summary::-webkit-details-marker, max-width: min(320px, calc(100vw - 48px)); } -.usage-filter-popover, -.usage-export-popover { - position: absolute; - top: calc(100% + 8px); - width: min(320px, calc(100vw - 48px)); - padding: 12px; - border: 1px solid var(--border-strong); - border-radius: var(--radius-lg); - background: var(--popover); - color: var(--popover-foreground); - box-shadow: var(--shadow-lg); - z-index: 12; -} - -.usage-filter-popover { - left: 0; -} - -.usage-export-popover { - right: 0; - width: 220px; -} - -.usage-filter-options, -.usage-export-list { - display: grid; - gap: 8px; -} - .usage-filter-option { display: grid; grid-template-columns: auto minmax(0, 1fr); @@ -625,29 +579,6 @@ details.usage-filter-select summary::-webkit-details-marker, background: var(--bg-hover); } -.usage-export-item { - width: 100%; - min-height: 32px; - padding: 7px 10px; - border: 1px solid var(--border); - border-radius: var(--radius-md); - background: var(--bg-elevated); - color: var(--text); - text-align: left; - font: inherit; - font-size: 12px; - transition: - border-color 0.18s var(--ease-out), - background 0.18s var(--ease-out), - color 0.18s var(--ease-out); -} - -.usage-export-item:hover:not(:disabled) { - border-color: var(--border-strong); - background: var(--bg-hover); - color: var(--text-strong); -} - .usage-query-chips, .usage-query-suggestions, .usage-badges, @@ -1920,11 +1851,6 @@ details.usage-filter-select summary::-webkit-details-marker, box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 8%, transparent); } -:root[data-theme-mode="light"] .usage-filter-popover, -:root[data-theme-mode="light"] .usage-export-popover { - box-shadow: var(--shadow-md); -} - :root[data-theme-mode="light"] .session-bar-row, :root[data-theme-mode="light"] .usage-insight-card, :root[data-theme-mode="light"] .session-timeseries-compact, @@ -2024,16 +1950,6 @@ details.usage-filter-select summary::-webkit-details-marker, justify-content: flex-start; } - .usage-filter-popover, - .usage-export-popover { - width: min(320px, calc(100vw - 40px)); - } - - .usage-export-popover { - right: auto; - left: 0; - } - .usage-daypart-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } diff --git a/ui/src/test-helpers/load-styles.ts b/ui/src/test-helpers/load-styles.ts index 5ba29d9c7a69..36d419325302 100644 --- a/ui/src/test-helpers/load-styles.ts +++ b/ui/src/test-helpers/load-styles.ts @@ -8,4 +8,3 @@ import "../styles/config.css"; import "../styles/usage.css"; import "../styles/dreams.css"; import "../styles/memory-overview.css"; -import "@create-markdown/preview/themes/system.css"; diff --git a/ui/src/types/create-markdown-preview.d.ts b/ui/src/types/create-markdown-preview.d.ts deleted file mode 100644 index 9778ae9bdc68..000000000000 --- a/ui/src/types/create-markdown-preview.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Control UI type declarations define create markdown preview contracts. -declare module "@create-markdown/preview" { - export type PreviewThemeOptions = { - sanitize?: ((html: string) => string) | undefined; - }; - - export function applyPreviewTheme(html: string, options?: PreviewThemeOptions): string; -}