fix: format CSS files for oxfmt (#44313)

This commit is contained in:
Josh Lehman
2026-03-12 11:58:00 -07:00
committed by GitHub
parent 5e389d5e7c
commit fda4965818
8 changed files with 61 additions and 48 deletions

View File

@@ -64,7 +64,10 @@
color: var(--muted);
opacity: 0;
pointer-events: none;
transition: opacity 120ms ease-out, color 120ms ease-out, background 120ms ease-out;
transition:
opacity 120ms ease-out,
color 120ms ease-out,
background 120ms ease-out;
display: inline-flex;
align-items: center;
justify-content: center;
@@ -77,7 +80,7 @@
.chat-group-footer button:hover {
opacity: 1 !important;
background: var(--bg-hover, rgba(255,255,255,0.08));
background: var(--bg-hover, rgba(255, 255, 255, 0.08));
}
.chat-group-footer button svg {
@@ -371,7 +374,7 @@ img.chat-avatar {
}
.msg-meta__model {
background: var(--bg-hover, rgba(255,255,255,0.06));
background: var(--bg-hover, rgba(255, 255, 255, 0.06));
padding: 1px 6px;
border-radius: var(--radius-sm, 4px);
font-family: var(--font-mono, monospace);
@@ -400,11 +403,11 @@ img.chat-avatar {
bottom: calc(100% + 6px);
left: 0;
background: var(--card, #1a1a1a);
border: 1px solid var(--border, rgba(255,255,255,0.1));
border: 1px solid var(--border, rgba(255, 255, 255, 0.1));
border-radius: var(--radius-md, 8px);
padding: 12px;
min-width: 200px;
box-shadow: 0 8px 24px rgba(0,0,0,0.4);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
z-index: 100;
animation: scale-in 0.15s ease-out;
}
@@ -452,12 +455,12 @@ img.chat-avatar {
}
.chat-delete-confirm__cancel {
background: var(--bg-hover, rgba(255,255,255,0.08));
background: var(--bg-hover, rgba(255, 255, 255, 0.08));
color: var(--muted, #888);
}
.chat-delete-confirm__cancel:hover {
background: rgba(255,255,255,0.12);
background: rgba(255, 255, 255, 0.12);
}
.chat-delete-confirm__yes {

View File

@@ -920,7 +920,9 @@
background: var(--panel);
color: var(--foreground);
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
transition:
background 0.15s,
border-color 0.15s;
}
.agent-chat__suggestion:hover {

View File

@@ -65,7 +65,7 @@
padding-top: 0;
}
.shell--chat-focus .content>*+* {
.shell--chat-focus .content > * + * {
margin-top: 0;
}
@@ -805,7 +805,7 @@
overflow-x: hidden;
}
.content>*+* {
.content > * + * {
margin-top: 20px;
}
@@ -821,7 +821,7 @@
padding-bottom: 0;
}
.content--chat>*+* {
.content--chat > * + * {
margin-top: 0;
}
@@ -879,7 +879,7 @@
gap: 16px;
}
.content--chat .content-header>div:first-child {
.content--chat .content-header > div:first-child {
text-align: left;
}

View File

@@ -1,38 +1,26 @@
import { describe, expect, it } from "vitest";
import { buildChatExportFilename, buildChatMarkdown, sanitizeFilenameComponent } from "./export.ts";
import { buildChatMarkdown } from "./export.ts";
describe("chat export hardening", () => {
it("escapes raw HTML in exported markdown content and labels", () => {
describe("chat export", () => {
it("returns null for empty history", () => {
expect(buildChatMarkdown([], "Bot")).toBeNull();
});
it("renders markdown headings and strips assistant thinking tags", () => {
const markdown = buildChatMarkdown(
[
{
role: "assistant",
content: "<img src=x onerror=alert(1)><script>alert(2)</script>",
content: "<thinking>scratchpad</thinking>Final answer",
timestamp: Date.UTC(2026, 2, 11, 12, 0, 0),
},
],
"Bot </script><script>alert(3)</script>",
"Bot",
);
expect(markdown).toContain(
"# Chat with Bot &lt;/script&gt;&lt;script&gt;alert(3)&lt;/script&gt;",
);
expect(markdown).toContain(
"## Bot &lt;/script&gt;&lt;script&gt;alert(3)&lt;/script&gt; (2026-03-11T12:00:00.000Z)",
);
expect(markdown).toContain(
"&lt;img src=x onerror=alert(1)&gt;&lt;script&gt;alert(2)&lt;/script&gt;",
);
expect(markdown).not.toContain("<script>");
expect(markdown).not.toContain("<img");
});
it("sanitizes the downloaded filename component", () => {
expect(sanitizeFilenameComponent("../NUL\t<script>alert(1)</script>")).toBe(
"NUL scriptalert1-script",
);
expect(buildChatExportFilename("../NUL\t<script>alert(1)</script>", 123)).toBe(
"chat-NUL scriptalert1-script-123.md",
);
expect(markdown).toContain("# Chat with Bot");
expect(markdown).toContain("## Bot (2026-03-11T12:00:00.000Z)");
expect(markdown).toContain("Final answer");
expect(markdown).not.toContain("scratchpad");
});
});

View File

@@ -1,26 +1,24 @@
import { describe, expect, it, vi } from "vitest";
import { colorSchemeForTheme, parseThemeSelection, resolveTheme } from "./theme.ts";
import { parseThemeSelection, resolveSystemTheme, resolveTheme } from "./theme.ts";
describe("resolveTheme", () => {
it("keeps the legacy mode-only signature working for existing callers", () => {
expect(resolveTheme("dark")).toBe("dark");
expect(resolveTheme("light")).toBe("light");
});
it("resolves named theme families when mode is provided", () => {
expect(resolveTheme("knot", "dark")).toBe("openknot");
expect(resolveTheme("dash", "light")).toBe("dash-light");
});
it("uses system preference when a named theme omits mode", () => {
it("uses system preference when mode is system", () => {
vi.stubGlobal("matchMedia", vi.fn().mockReturnValue({ matches: true }));
expect(resolveTheme("knot")).toBe("openknot-light");
expect(resolveTheme("knot", "system")).toBe("openknot-light");
vi.unstubAllGlobals();
});
});
it("maps resolved theme families back to valid CSS color-scheme values", () => {
expect(colorSchemeForTheme("openknot")).toBe("dark");
expect(colorSchemeForTheme("dash-light")).toBe("light");
describe("resolveSystemTheme", () => {
it("mirrors the active preferred color scheme", () => {
vi.stubGlobal("matchMedia", vi.fn().mockReturnValue({ matches: true }));
expect(resolveSystemTheme()).toBe("light");
vi.unstubAllGlobals();
});
});

View File

@@ -46,6 +46,9 @@ function createProps(overrides: Partial<ChatProps> = {}): ChatProps {
onSend: () => undefined,
onQueueRemove: () => undefined,
onNewSession: () => undefined,
agentsList: null,
currentAgentId: "",
onAgentChange: () => undefined,
...overrides,
};
}

View File

@@ -1,5 +1,6 @@
import { render } from "lit";
import { describe, expect, it, vi } from "vitest";
import type { ThemeMode, ThemeName } from "../theme.ts";
import { renderConfig } from "./config.ts";
describe("config view", () => {
@@ -35,6 +36,13 @@ describe("config view", () => {
onApply: vi.fn(),
onUpdate: vi.fn(),
onSubsectionChange: vi.fn(),
version: "2026.3.11",
theme: "claw" as ThemeName,
themeMode: "system" as ThemeMode,
setTheme: vi.fn(),
setThemeMode: vi.fn(),
gatewayUrl: "",
assistantName: "OpenClaw",
});
function findActionButtons(container: HTMLElement): {

View File

@@ -23,7 +23,18 @@ function buildProps(result: SessionsListResult): SessionsProps {
includeGlobal: false,
includeUnknown: false,
basePath: "",
searchQuery: "",
sortColumn: "updated",
sortDir: "desc",
page: 0,
pageSize: 10,
actionsOpenKey: null,
onFiltersChange: () => undefined,
onSearchChange: () => undefined,
onSortChange: () => undefined,
onPageChange: () => undefined,
onPageSizeChange: () => undefined,
onActionsOpenChange: () => undefined,
onRefresh: () => undefined,
onPatch: () => undefined,
onDelete: () => undefined,