mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-10 03:58:29 +00:00
feat(app): refine session UI styling (#33860)
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
This commit is contained in:
parent
219ba24d90
commit
78a5a030ce
21 changed files with 711 additions and 129 deletions
|
|
@ -16,6 +16,7 @@ import {
|
|||
type Component,
|
||||
createEffect,
|
||||
createMemo,
|
||||
createRenderEffect,
|
||||
createResource,
|
||||
createSignal,
|
||||
ErrorBoundary,
|
||||
|
|
@ -278,10 +279,11 @@ function QueryProvider(props: ParentProps) {
|
|||
function BodyDesignClass() {
|
||||
const settings = useSettings()
|
||||
|
||||
createEffect(() => {
|
||||
createRenderEffect(() => {
|
||||
if (typeof document === "undefined") return
|
||||
|
||||
const enabled = settings.general.newLayoutDesigns()
|
||||
document.body.toggleAttribute("data-new-layout", enabled)
|
||||
document.body.classList.toggle("text-12-regular", !enabled)
|
||||
document.body.classList.toggle("font-(family-name:--font-family-text)", enabled)
|
||||
document.body.classList.toggle("text-[13px]", enabled)
|
||||
|
|
|
|||
|
|
@ -908,7 +908,13 @@ export default function Page() {
|
|||
)
|
||||
|
||||
const reviewPanel = () => (
|
||||
<div class="flex flex-col h-full overflow-hidden bg-background-stronger contain-strict">
|
||||
<div
|
||||
classList={{
|
||||
"flex flex-col h-full overflow-hidden contain-strict": true,
|
||||
"bg-v2-background-bg-base": settings.general.newLayoutDesigns(),
|
||||
"bg-background-stronger": !settings.general.newLayoutDesigns(),
|
||||
}}
|
||||
>
|
||||
<div class="relative pt-2 flex-1 min-h-0 overflow-hidden">
|
||||
{reviewContent({
|
||||
diffStyle: layout.review.diffStyle(),
|
||||
|
|
@ -1713,7 +1719,9 @@ export default function Page() {
|
|||
>
|
||||
<div
|
||||
classList={{
|
||||
"flex-1 min-h-0 flex flex-col bg-background-stronger": true,
|
||||
"flex-1 min-h-0 flex flex-col": true,
|
||||
"bg-v2-background-bg-base": settings.general.newLayoutDesigns(),
|
||||
"bg-background-stronger": !settings.general.newLayoutDesigns(),
|
||||
"rounded-[10px] overflow-hidden": settings.general.newLayoutDesigns(),
|
||||
"shadow-[var(--v2-elevation-raised)]": settings.general.newLayoutDesigns() && !!params.id,
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Show, type JSX } from "solid-js"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { useSettings } from "@/context/settings"
|
||||
import { SessionPermissionDock } from "@/pages/session/composer/session-permission-dock"
|
||||
import { SessionQuestionDock } from "@/pages/session/composer/session-question-dock"
|
||||
import { SessionFollowupDock } from "@/pages/session/composer/session-followup-dock"
|
||||
|
|
@ -13,6 +14,7 @@ export function SessionComposerRegion(props: {
|
|||
}) {
|
||||
const language = useLanguage()
|
||||
const controller = props.controller
|
||||
const settings = useSettings()
|
||||
const rolled = () => {
|
||||
const revert = controller.revert()
|
||||
return revert?.items.length ? revert : undefined
|
||||
|
|
@ -22,7 +24,11 @@ export function SessionComposerRegion(props: {
|
|||
<div
|
||||
ref={controller.setDockRef}
|
||||
data-component="session-prompt-dock"
|
||||
class="w-full shrink-0 flex flex-col justify-center items-center pb-3 bg-background-stronger pointer-events-none"
|
||||
classList={{
|
||||
"w-full shrink-0 flex flex-col justify-center items-center pb-3 pointer-events-none": true,
|
||||
"bg-v2-background-bg-base": settings.general.newLayoutDesigns(),
|
||||
"bg-background-stronger": !settings.general.newLayoutDesigns(),
|
||||
}}
|
||||
>
|
||||
<div
|
||||
classList={{
|
||||
|
|
|
|||
|
|
@ -1019,7 +1019,13 @@ export function MessageTimeline(props: {
|
|||
<div class="flex w-max min-w-full justify-end gap-2">
|
||||
<Index each={comments()}>
|
||||
{(comment) => (
|
||||
<div class="shrink-0 max-w-[260px] rounded-[6px] border border-border-weak-base bg-background-stronger px-2.5 py-2">
|
||||
<div
|
||||
classList={{
|
||||
"shrink-0 max-w-[260px] rounded-[6px] border-border-weak-base bg-background-stronger px-2.5 py-2": true,
|
||||
"border-[0.5px]": settings.general.newLayoutDesigns(),
|
||||
border: !settings.general.newLayoutDesigns(),
|
||||
}}
|
||||
>
|
||||
<div class="flex items-center gap-1.5 min-w-0 text-11-medium text-text-strong">
|
||||
<FileIcon node={{ path: comment().path, type: "file" }} class="size-3.5 shrink-0" />
|
||||
<span class="truncate">{getFilename(comment().path)}</span>
|
||||
|
|
@ -1288,7 +1294,11 @@ export function MessageTimeline(props: {
|
|||
<div
|
||||
data-session-title
|
||||
classList={{
|
||||
"sticky top-0 z-30 bg-[linear-gradient(to_bottom,var(--background-stronger)_48px,transparent)]": true,
|
||||
"sticky top-0 z-30": true,
|
||||
"bg-[linear-gradient(to_bottom,var(--v2-background-bg-base)_48px,transparent)]":
|
||||
settings.general.newLayoutDesigns(),
|
||||
"bg-[linear-gradient(to_bottom,var(--background-stronger)_48px,transparent)]":
|
||||
!settings.general.newLayoutDesigns(),
|
||||
"w-full": true,
|
||||
"pb-4": true,
|
||||
"pr-3": true,
|
||||
|
|
@ -1509,7 +1519,11 @@ export function MessageTimeline(props: {
|
|||
<Button
|
||||
size="large"
|
||||
variant="secondary"
|
||||
class="w-full shadow-none border border-border-weak-base"
|
||||
class={
|
||||
settings.general.newLayoutDesigns()
|
||||
? "w-full shadow-none border-[0.5px] border-border-weak-base"
|
||||
: "w-full shadow-none border border-border-weak-base"
|
||||
}
|
||||
onClick={unshareSession}
|
||||
disabled={unshareMutation.isPending}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-faint);
|
||||
|
||||
[data-component="spinner"] {
|
||||
width: 16px;
|
||||
|
|
@ -89,14 +89,14 @@
|
|||
font-weight: var(--font-weight-medium);
|
||||
line-height: var(--line-height-large);
|
||||
letter-spacing: var(--letter-spacing-normal);
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
|
||||
&.capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
&.agent-title {
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
}
|
||||
|
|
@ -114,7 +114,7 @@
|
|||
font-weight: var(--font-weight-regular);
|
||||
line-height: var(--line-height-large);
|
||||
letter-spacing: var(--letter-spacing-normal);
|
||||
color: var(--text-base);
|
||||
color: var(--v2-text-text-muted);
|
||||
|
||||
&.clickable {
|
||||
cursor: pointer;
|
||||
|
|
@ -122,7 +122,7 @@
|
|||
transition: color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
color: var(--text-base);
|
||||
color: var(--v2-text-text-muted);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +160,7 @@
|
|||
font-weight: var(--font-weight-regular);
|
||||
line-height: var(--line-height-large);
|
||||
letter-spacing: var(--letter-spacing-normal);
|
||||
color: var(--text-base);
|
||||
color: var(--v2-text-text-muted);
|
||||
}
|
||||
|
||||
[data-slot="basic-tool-tool-action"] {
|
||||
|
|
@ -178,7 +178,7 @@
|
|||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--border-weak-base, rgba(255, 255, 255, 0.08));
|
||||
border: 0.5px solid var(--border-weak-base, rgba(255, 255, 255, 0.08));
|
||||
background: color-mix(in srgb, var(--background-base) 92%, transparent);
|
||||
transition:
|
||||
border-color 0.15s ease,
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
color: var(--icon-weak);
|
||||
color: var(--v2-text-text-faint);
|
||||
margin-left: auto;
|
||||
opacity: 0;
|
||||
transition:
|
||||
|
|
@ -233,7 +233,7 @@
|
|||
}
|
||||
|
||||
[data-slot="basic-tool-tool-subtitle"] {
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
|
|
@ -246,3 +246,34 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
body:not([data-new-layout]) {
|
||||
[data-component="tool-trigger"] {
|
||||
[data-slot="basic-tool-tool-spinner"] {
|
||||
color: var(--text-weak);
|
||||
}
|
||||
|
||||
[data-slot="basic-tool-tool-title"],
|
||||
[data-slot="basic-tool-tool-title"].agent-title {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
|
||||
[data-slot="basic-tool-tool-subtitle"],
|
||||
[data-slot="basic-tool-tool-subtitle"].clickable:hover,
|
||||
[data-slot="basic-tool-tool-arg"] {
|
||||
color: var(--text-base);
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="task-tool-card"] {
|
||||
border-width: 1px;
|
||||
|
||||
[data-component="task-tool-action"] {
|
||||
color: var(--icon-weak);
|
||||
}
|
||||
|
||||
[data-slot="basic-tool-tool-subtitle"] {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
import { describe, expect, test } from "bun:test"
|
||||
import { inlineCodeKind } from "./markdown-inline-code-kind"
|
||||
|
||||
describe("inlineCodeKind", () => {
|
||||
test("leaves code expressions as normal inline code", () => {
|
||||
expect(
|
||||
inlineCodeKind(`case "question.asked": ... input.setStore("question", question.sessionID, [question]) / splice/insert`),
|
||||
).toBeUndefined()
|
||||
expect(inlineCodeKind(`<SessionQuestionDock request={request} ... />`)).toBeUndefined()
|
||||
expect(inlineCodeKind(`from sync.data.question + sync.data.session.`)).toBeUndefined()
|
||||
expect(inlineCodeKind(`@opencode-ai/app <StatusPopover />)`)).toBeUndefined()
|
||||
expect(inlineCodeKind(`sync.data.session`)).toBeUndefined()
|
||||
expect(inlineCodeKind(`window.api`)).toBeUndefined()
|
||||
})
|
||||
|
||||
test("detects file and directory paths", () => {
|
||||
expect(inlineCodeKind(`app.tsx`)).toBe("path")
|
||||
expect(inlineCodeKind(`packages/desktop-electron`)).toBe("path")
|
||||
expect(inlineCodeKind(`~/.config/opencode`)).toBe("path")
|
||||
expect(inlineCodeKind(`@opencode-ai/app`)).toBe("path")
|
||||
expect(inlineCodeKind(`session/status`)).toBe("path")
|
||||
})
|
||||
|
||||
test("detects urls", () => {
|
||||
expect(inlineCodeKind(`https://opencode.ai/docs`)).toBe("url")
|
||||
expect(inlineCodeKind(`http://localhost:4444`)).toBe("url")
|
||||
expect(inlineCodeKind(`file:///tmp/opencode`)).toBeUndefined()
|
||||
expect(inlineCodeKind(`ftp://opencode.ai/docs`)).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
export function inlineCodeKind(text: string): "path" | "url" | undefined {
|
||||
if (/^https?:\/\//i.test(text)) return "url"
|
||||
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(text)) return
|
||||
if (/^\/[a-z][a-z0-9-]*$/i.test(text)) return
|
||||
if (/\s/.test(text)) return
|
||||
if (/[()\[\]{}*+=<>|&^"';]/.test(text)) return
|
||||
if (
|
||||
/[/\\]/.test(text) ||
|
||||
/^\.\.?[/\\]/.test(text) ||
|
||||
/\.(tsx?|jsx?|json|py|go|rs|rb|php|css|html|md|sh|ya?ml|toml|sql|c|cpp|h|java|kt|swift|scala|xml|png|jpe?g|gif|svg|ico)$/i.test(text)
|
||||
)
|
||||
return "path"
|
||||
}
|
||||
|
|
@ -1,9 +1,17 @@
|
|||
[data-component="markdown"] {
|
||||
--markdown-inline-code-path-color: var(--v2-text-text-code-accent);
|
||||
--markdown-inline-code-color: var(--v2-text-text-code-accent);
|
||||
--markdown-inline-code-bg-mix: 8%;
|
||||
--markdown-shell-code-background: var(--v2-background-bg-layer-02);
|
||||
--markdown-shell-code-border: var(--v2-border-border-muted);
|
||||
--markdown-shell-code-color: var(--v2-text-text-base);
|
||||
--markdown-shell-code-token-color: currentColor;
|
||||
|
||||
/* Reset & Base Typography */
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
overflow-wrap: break-word;
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
font-family: var(--font-family-sans);
|
||||
font-size: var(--font-size-base); /* 14px */
|
||||
line-height: 160%;
|
||||
|
|
@ -22,15 +30,31 @@
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Headings: Same size, distinguished by color and spacing */
|
||||
h1,
|
||||
h2,
|
||||
/* Headings: Sized by level, distinguished by color and spacing */
|
||||
h1 {
|
||||
font-size: 17px;
|
||||
color: var(--v2-text-text-base);
|
||||
font-weight: 600;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 24px;
|
||||
line-height: var(--line-height-large);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 15px;
|
||||
color: var(--v2-text-text-base);
|
||||
font-weight: 600;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 24px;
|
||||
line-height: var(--line-height-large);
|
||||
}
|
||||
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 14px;
|
||||
color: var(--text-strong);
|
||||
font-size: 13px;
|
||||
color: var(--v2-text-text-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
margin-top: 0px;
|
||||
margin-bottom: 24px;
|
||||
|
|
@ -40,7 +64,7 @@
|
|||
/* Emphasis & Strong: Neutral strong color */
|
||||
strong,
|
||||
b {
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +119,7 @@
|
|||
}
|
||||
|
||||
li::marker {
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-muted);
|
||||
}
|
||||
|
||||
/* Nested lists spacing */
|
||||
|
|
@ -112,10 +136,10 @@
|
|||
|
||||
/* Blockquotes */
|
||||
blockquote {
|
||||
border-left: 2px solid var(--border-weak-base);
|
||||
border-left: 0.5px solid var(--v2-border-border-base);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 0.5rem;
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-muted);
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
|
@ -132,13 +156,27 @@
|
|||
font-size: 13px;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
border: 0.5px solid var(--border-weak-base);
|
||||
border: 0.5px solid var(--v2-border-border-base);
|
||||
}
|
||||
|
||||
[data-component="markdown-code"] {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[data-component="markdown-code"][data-code-kind="shell"] .shiki {
|
||||
background: var(--markdown-shell-code-background);
|
||||
border-color: var(--markdown-shell-code-border);
|
||||
color: var(--markdown-shell-code-color);
|
||||
}
|
||||
|
||||
[data-component="markdown-code"][data-code-kind="shell"] code {
|
||||
color: var(--markdown-shell-code-color);
|
||||
}
|
||||
|
||||
[data-component="markdown-code"][data-code-kind="shell"] code span {
|
||||
color: var(--markdown-shell-code-token-color) !important;
|
||||
}
|
||||
|
||||
[data-slot="markdown-copy-button"] {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
|
|
@ -160,7 +198,7 @@
|
|||
background: var(--surface-float-base);
|
||||
color: var(--text-invert-strong);
|
||||
padding: 2px 8px;
|
||||
border: 1px solid var(--border-weak-base, rgba(0, 0, 0, 0.07));
|
||||
border: 0.5px solid var(--v2-border-border-base, rgba(0, 0, 0, 0.07));
|
||||
box-shadow: var(--shadow-md);
|
||||
|
||||
pointer-events: none;
|
||||
|
|
@ -185,11 +223,11 @@
|
|||
|
||||
[data-slot="markdown-copy-button"][data-variant="secondary"] {
|
||||
box-shadow: none;
|
||||
border: 1px solid var(--border-weak-base);
|
||||
border: 0.5px solid var(--v2-border-border-base);
|
||||
}
|
||||
|
||||
[data-slot="markdown-copy-button"][data-variant="secondary"] [data-slot="icon-svg"] {
|
||||
color: var(--icon-base);
|
||||
color: var(--v2-icon-icon-base);
|
||||
}
|
||||
|
||||
[data-component="markdown-code"]:hover [data-slot="markdown-copy-button"] {
|
||||
|
|
@ -222,15 +260,28 @@
|
|||
:not(pre) > code {
|
||||
font-family: var(--font-family-mono);
|
||||
font-feature-settings: var(--font-family-mono--font-feature-settings);
|
||||
color: var(--syntax-string);
|
||||
color: var(--v2-text-text-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
/* font-size: 13px; */
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
background: color-mix(in oklch, var(--v2-text-text-base) var(--markdown-inline-code-bg-mix), transparent);
|
||||
}
|
||||
|
||||
/* padding: 2px 2px; */
|
||||
/* margin: 0 1.5px; */
|
||||
/* border-radius: 2px; */
|
||||
/* background: var(--surface-base); */
|
||||
/* box-shadow: 0 0 0 0.5px var(--border-weak-base); */
|
||||
:not(pre) > code[data-inline-code-kind="path"] {
|
||||
color: var(--markdown-inline-code-path-color);
|
||||
background: color-mix(
|
||||
in oklch,
|
||||
var(--markdown-inline-code-path-color) var(--markdown-inline-code-bg-mix),
|
||||
transparent
|
||||
);
|
||||
}
|
||||
|
||||
a.external-link > code[data-inline-code-kind="url"] {
|
||||
color: var(--markdown-inline-code-color);
|
||||
background: none;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: color-mix(in oklch, var(--markdown-inline-code-color) 25%, transparent);
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
|
|
@ -246,16 +297,16 @@
|
|||
th,
|
||||
td {
|
||||
/* Minimal borders for structure, matching TUI "lines" roughly but keeping it web-clean */
|
||||
border-bottom: 1px solid var(--border-weaker-base);
|
||||
border-bottom: 0.5px solid var(--v2-border-border-muted);
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
th {
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
border-bottom: 1px solid var(--border-weak-base);
|
||||
border-bottom: 0.5px solid var(--v2-border-border-base);
|
||||
}
|
||||
|
||||
/* Images */
|
||||
|
|
@ -268,6 +319,68 @@
|
|||
}
|
||||
}
|
||||
|
||||
body:not([data-new-layout]) [data-component="markdown"] {
|
||||
color: var(--text-strong);
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 14px;
|
||||
color: var(--text-strong);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
strong,
|
||||
b {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
|
||||
li::marker {
|
||||
color: var(--text-weak);
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 2px solid var(--border-weak-base);
|
||||
color: var(--text-weak);
|
||||
}
|
||||
|
||||
.shiki {
|
||||
border-color: var(--border-weak-base);
|
||||
}
|
||||
|
||||
:not(pre) > code {
|
||||
color: var(--syntax-string);
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
background: none;
|
||||
}
|
||||
|
||||
[data-slot="markdown-copy-button"]::after {
|
||||
border: 1px solid var(--border-weak-base, rgba(0, 0, 0, 0.07));
|
||||
}
|
||||
|
||||
[data-slot="markdown-copy-button"][data-variant="secondary"] {
|
||||
border: 1px solid var(--border-weak-base);
|
||||
}
|
||||
|
||||
[data-slot="markdown-copy-button"][data-variant="secondary"] [data-slot="icon-svg"] {
|
||||
color: var(--icon-base);
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
border-bottom: 1px solid var(--border-weaker-base);
|
||||
}
|
||||
|
||||
th {
|
||||
color: var(--text-strong);
|
||||
border-bottom-color: var(--border-weak-base);
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="markdown"] a.external-link:hover > code {
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import {
|
|||
import { markdownBlockKey, type MarkdownToken } from "./markdown-worker-protocol"
|
||||
import { shouldResetCodeTokens, type RenderedCodeState } from "./markdown-code-state"
|
||||
import { getCachedMarkdown, sanitizeMarkdown, touchCachedMarkdown, type MarkdownCacheEntry } from "./markdown-cache"
|
||||
import { inlineCodeKind } from "./markdown-inline-code-kind"
|
||||
|
||||
type RenderedBlock =
|
||||
| (MarkdownCacheEntry & { key: string; mode: Exclude<Block["mode"], "code"> })
|
||||
|
|
@ -140,6 +141,35 @@ function setCopyState(button: HTMLButtonElement, labels: CopyLabels, copied: boo
|
|||
button.setAttribute("data-tooltip", labels.copy)
|
||||
}
|
||||
|
||||
const shellLanguages = new Set(["bash", "sh", "shell", "zsh", "fish", "console", "terminal"])
|
||||
|
||||
function codeKind(language: string | undefined) {
|
||||
const value = language?.toLowerCase()
|
||||
if (!value) return
|
||||
if (shellLanguages.has(value)) return "shell"
|
||||
}
|
||||
|
||||
function codeLanguage(block: HTMLPreElement) {
|
||||
const code = block.querySelector("code")
|
||||
if (!(code instanceof HTMLElement)) return
|
||||
return code.className.match(/(?:^|\s)language-([^\s]+)/)?.[1]
|
||||
}
|
||||
|
||||
function applyCodeMetadata(wrapper: HTMLElement, language: string | undefined) {
|
||||
if (!document.body.hasAttribute("data-new-layout")) {
|
||||
delete wrapper.dataset.language
|
||||
delete wrapper.dataset.codeKind
|
||||
return
|
||||
}
|
||||
|
||||
if (language) wrapper.dataset.language = language
|
||||
else delete wrapper.dataset.language
|
||||
|
||||
const kind = codeKind(language)
|
||||
if (kind) wrapper.dataset.codeKind = kind
|
||||
else delete wrapper.dataset.codeKind
|
||||
}
|
||||
|
||||
function ensureCodeWrapper(block: HTMLPreElement, labels: CopyLabels) {
|
||||
const parent = block.parentElement
|
||||
if (!parent) return
|
||||
|
|
@ -147,12 +177,15 @@ function ensureCodeWrapper(block: HTMLPreElement, labels: CopyLabels) {
|
|||
if (!wrapped) {
|
||||
const wrapper = document.createElement("div")
|
||||
wrapper.setAttribute("data-component", "markdown-code")
|
||||
applyCodeMetadata(wrapper, codeLanguage(block))
|
||||
parent.replaceChild(wrapper, block)
|
||||
wrapper.appendChild(block)
|
||||
wrapper.appendChild(createCopyButton(labels))
|
||||
return
|
||||
}
|
||||
|
||||
applyCodeMetadata(parent, codeLanguage(block))
|
||||
|
||||
const buttons = Array.from(parent.querySelectorAll('[data-slot="markdown-copy-button"]')).filter(
|
||||
(el): el is HTMLButtonElement => el instanceof HTMLButtonElement,
|
||||
)
|
||||
|
|
@ -196,11 +229,23 @@ function markCodeLinks(root: HTMLDivElement) {
|
|||
}
|
||||
}
|
||||
|
||||
function markInlineCode(root: HTMLDivElement) {
|
||||
const codeNodes = Array.from(root.querySelectorAll(":not(pre) > code"))
|
||||
for (const code of codeNodes) {
|
||||
if (!(code instanceof HTMLElement)) continue
|
||||
delete code.dataset.inlineCodeKind
|
||||
const kind = inlineCodeKind(code.textContent ?? "")
|
||||
if (kind) code.dataset.inlineCodeKind = kind
|
||||
}
|
||||
}
|
||||
|
||||
function decorate(root: HTMLDivElement, labels: CopyLabels) {
|
||||
const blocks = Array.from(root.querySelectorAll("pre"))
|
||||
for (const block of blocks) {
|
||||
ensureCodeWrapper(block, labels)
|
||||
}
|
||||
if (!document.body.hasAttribute("data-new-layout")) return
|
||||
markInlineCode(root)
|
||||
markCodeLinks(root)
|
||||
}
|
||||
|
||||
|
|
@ -522,6 +567,8 @@ function updateCodeBlock(
|
|||
|
||||
const code = existing?.querySelector("code")
|
||||
if (code instanceof HTMLElement) {
|
||||
const wrapper = code.closest('[data-component="markdown-code"]')
|
||||
if (wrapper instanceof HTMLElement) applyCodeMetadata(wrapper, block.language)
|
||||
code.className = `language-${block.language}`
|
||||
const previous = renderedCodeTokens.get(next)
|
||||
const reset = shouldResetCodeTokens(previous, {
|
||||
|
|
@ -552,6 +599,7 @@ function updateCodeBlock(
|
|||
|
||||
const wrapper = document.createElement("div")
|
||||
wrapper.setAttribute("data-component", "markdown-code")
|
||||
applyCodeMetadata(wrapper, block.language)
|
||||
const pre = document.createElement("pre")
|
||||
pre.className = "shiki OpenCode"
|
||||
const codeElement = document.createElement("code")
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
font-weight: var(--font-weight-regular);
|
||||
line-height: var(--line-height-large);
|
||||
letter-spacing: var(--letter-spacing-normal);
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
|
|
@ -41,15 +41,15 @@
|
|||
min-width: 0;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: var(--surface-weak);
|
||||
border: 1px solid var(--border-weak-base);
|
||||
background: var(--v2-background-bg-layer-02);
|
||||
border: 0.5px solid var(--v2-border-border-base);
|
||||
cursor: default;
|
||||
transition:
|
||||
border-color 0.15s ease,
|
||||
opacity 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--border-strong-base);
|
||||
border-color: var(--v2-border-border-strong);
|
||||
}
|
||||
|
||||
&[data-clickable] {
|
||||
|
|
@ -107,7 +107,7 @@
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: var(--text-base);
|
||||
color: var(--v2-text-text-muted);
|
||||
font-size: var(--font-size-small);
|
||||
line-height: var(--line-height-large);
|
||||
}
|
||||
|
|
@ -130,10 +130,10 @@
|
|||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
overflow: hidden;
|
||||
background: var(--surface-base);
|
||||
border: 1px solid var(--border-weak-base);
|
||||
background: var(--v2-background-bg-layer-02);
|
||||
border: none;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
border-radius: 10px;
|
||||
|
||||
[data-highlight="file"] {
|
||||
color: var(--syntax-property);
|
||||
|
|
@ -199,7 +199,7 @@
|
|||
}
|
||||
|
||||
.text-text-strong {
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
}
|
||||
|
||||
.font-medium {
|
||||
|
|
@ -267,7 +267,7 @@
|
|||
[data-slot="compaction-part-line"] {
|
||||
flex: 1 1 auto;
|
||||
height: 1px;
|
||||
background: var(--border-weak-base);
|
||||
background: var(--v2-border-border-base);
|
||||
}
|
||||
|
||||
[data-slot="compaction-part-label"] {
|
||||
|
|
@ -279,18 +279,18 @@
|
|||
|
||||
[data-component="reasoning-part"] {
|
||||
width: 100%;
|
||||
color: var(--text-base);
|
||||
color: var(--v2-text-text-muted);
|
||||
line-height: var(--line-height-normal);
|
||||
|
||||
[data-component="markdown"] {
|
||||
margin-top: 16px;
|
||||
font-style: normal;
|
||||
font-size: 13px;
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-muted);
|
||||
|
||||
strong,
|
||||
b {
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-muted);
|
||||
}
|
||||
|
||||
p:has(strong) {
|
||||
|
|
@ -357,7 +357,7 @@
|
|||
|
||||
[data-component="bash-output"] {
|
||||
width: 100%;
|
||||
border: 1px solid var(--border-weak-base);
|
||||
border: 0.5px solid var(--v2-border-border-base);
|
||||
border-radius: 6px;
|
||||
background: transparent;
|
||||
position: relative;
|
||||
|
|
@ -380,7 +380,7 @@
|
|||
|
||||
[data-slot="bash-copy"] [data-component="icon-button"][data-variant="secondary"] {
|
||||
box-shadow: none;
|
||||
border: 1px solid var(--border-weak-base);
|
||||
border: 0.5px solid var(--v2-border-border-base);
|
||||
}
|
||||
|
||||
[data-slot="bash-copy"] [data-component="icon-button"][data-variant="secondary"] [data-slot="icon-svg"] {
|
||||
|
|
@ -442,7 +442,7 @@
|
|||
font-weight: var(--font-weight-medium);
|
||||
line-height: var(--line-height-large);
|
||||
letter-spacing: var(--letter-spacing-normal);
|
||||
color: var(--text-base);
|
||||
color: var(--v2-text-text-muted);
|
||||
}
|
||||
|
||||
[data-slot="message-part-title-spinner"] {
|
||||
|
|
@ -453,7 +453,7 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-muted);
|
||||
|
||||
[data-component="spinner"] {
|
||||
width: 16px;
|
||||
|
|
@ -464,7 +464,7 @@
|
|||
[data-slot="message-part-title-text"] {
|
||||
flex-shrink: 0;
|
||||
text-transform: capitalize;
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
}
|
||||
|
||||
[data-slot="message-part-title-filename"] {
|
||||
|
|
@ -484,7 +484,7 @@
|
|||
}
|
||||
|
||||
[data-slot="message-part-directory"] {
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-muted);
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
|
@ -493,7 +493,7 @@
|
|||
}
|
||||
|
||||
[data-slot="message-part-filename"] {
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
|
|
@ -508,7 +508,7 @@
|
|||
|
||||
[data-component="edit-content"] {
|
||||
border-radius: inherit;
|
||||
border-top: 1px solid var(--border-weaker-base);
|
||||
border-top: 0.5px solid var(--v2-border-border-muted);
|
||||
overflow-x: hidden;
|
||||
overflow-y: visible;
|
||||
|
||||
|
|
@ -527,7 +527,7 @@
|
|||
|
||||
[data-component="write-content"] {
|
||||
border-radius: inherit;
|
||||
border-top: 1px solid var(--border-weaker-base);
|
||||
border-top: 0.5px solid var(--v2-border-border-muted);
|
||||
overflow-x: hidden;
|
||||
overflow-y: visible;
|
||||
|
||||
|
|
@ -561,7 +561,7 @@
|
|||
font-family: var(--font-family-sans);
|
||||
font-size: var(--font-size-base);
|
||||
line-height: var(--line-height-large);
|
||||
color: var(--text-base);
|
||||
color: var(--v2-text-text-muted);
|
||||
}
|
||||
|
||||
[data-slot="basic-tool-tool-subtitle"].exa-tool-query {
|
||||
|
|
@ -583,7 +583,7 @@
|
|||
max-width: 100%;
|
||||
font: inherit;
|
||||
line-height: inherit;
|
||||
color: var(--text-interactive-base);
|
||||
color: var(--v2-text-text-accent);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
overflow: hidden;
|
||||
|
|
@ -591,11 +591,11 @@
|
|||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
color: var(--text-interactive-base);
|
||||
color: var(--v2-text-text-accent);
|
||||
}
|
||||
|
||||
&:visited {
|
||||
color: var(--text-interactive-base);
|
||||
color: var(--v2-text-text-accent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -615,7 +615,7 @@
|
|||
|
||||
&[data-completed="completed"] {
|
||||
text-decoration: line-through;
|
||||
color: var(--text-weaker);
|
||||
color: var(--v2-text-text-faint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -660,8 +660,8 @@
|
|||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 8px 12px;
|
||||
background-color: var(--surface-critical-weak);
|
||||
border-top: 1px solid var(--border-critical-base);
|
||||
background-color: var(--v2-state-bg-danger);
|
||||
border-top: 0.5px solid var(--v2-state-border-danger);
|
||||
|
||||
[data-slot="diagnostic"] {
|
||||
display: flex;
|
||||
|
|
@ -673,7 +673,7 @@
|
|||
}
|
||||
|
||||
[data-slot="diagnostic-label"] {
|
||||
color: var(--text-on-critical-base);
|
||||
color: var(--v2-state-fg-danger);
|
||||
font-weight: var(--font-weight-medium);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: -0.5px;
|
||||
|
|
@ -681,12 +681,12 @@
|
|||
}
|
||||
|
||||
[data-slot="diagnostic-location"] {
|
||||
color: var(--text-on-critical-weak);
|
||||
color: var(--v2-state-fg-danger);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
[data-slot="diagnostic-message"] {
|
||||
color: var(--text-on-critical-base);
|
||||
color: var(--v2-state-fg-danger);
|
||||
word-break: break-word;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
|
|
@ -761,7 +761,7 @@
|
|||
font-size: 14px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
line-height: var(--line-height-large);
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
|
|
@ -778,7 +778,7 @@
|
|||
font-size: 14px;
|
||||
font-weight: var(--font-weight-regular);
|
||||
line-height: var(--line-height-large);
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-muted);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
|
@ -856,7 +856,7 @@
|
|||
font-size: 14px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
line-height: var(--line-height-large);
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
|
|
@ -916,7 +916,7 @@
|
|||
font-size: 14px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
line-height: var(--line-height-large);
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
padding: 0 10px;
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
|
|
@ -927,7 +927,7 @@
|
|||
font-size: 13px;
|
||||
font-weight: var(--font-weight-regular);
|
||||
line-height: var(--line-height-large);
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-muted);
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
|
|
@ -953,8 +953,8 @@
|
|||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 8px 8px 8px 10px;
|
||||
background-color: var(--surface-raised-stronger-non-alpha);
|
||||
border: 1px solid var(--border-weak-base);
|
||||
background-color: var(--v2-background-bg-layer-01);
|
||||
border: 0.5px solid var(--v2-border-border-base);
|
||||
border-radius: 6px;
|
||||
box-shadow: none;
|
||||
text-align: left;
|
||||
|
|
@ -966,11 +966,11 @@
|
|||
box-shadow 0.15s ease;
|
||||
|
||||
&:hover:not([data-picked="true"]) {
|
||||
background-color: var(--background-base);
|
||||
background-color: var(--v2-background-bg-base);
|
||||
}
|
||||
|
||||
&[data-picked="true"] {
|
||||
background-color: var(--surface-interactive-weak);
|
||||
background-color: var(--v2-state-bg-info);
|
||||
border-color: transparent;
|
||||
box-shadow: var(--shadow-xs-border-hover);
|
||||
}
|
||||
|
|
@ -991,7 +991,7 @@
|
|||
height: 16px;
|
||||
padding: 2px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border-weak-base);
|
||||
border: 0.5px solid var(--v2-border-border-base);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -1014,7 +1014,7 @@
|
|||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 999px;
|
||||
background-color: var(--background-stronger);
|
||||
background-color: var(--v2-background-bg-layer-01);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
|
@ -1052,7 +1052,7 @@
|
|||
font-size: 14px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
line-height: var(--line-height-large);
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
}
|
||||
|
||||
[data-slot="option-description"] {
|
||||
|
|
@ -1060,7 +1060,7 @@
|
|||
font-size: 14px;
|
||||
font-weight: var(--font-weight-regular);
|
||||
line-height: var(--line-height-large);
|
||||
color: var(--text-base);
|
||||
color: var(--v2-text-text-muted);
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
white-space: normal;
|
||||
|
|
@ -1088,7 +1088,7 @@
|
|||
font-size: 14px;
|
||||
font-weight: var(--font-weight-regular);
|
||||
line-height: var(--line-height-large);
|
||||
color: var(--text-base);
|
||||
color: var(--v2-text-text-muted);
|
||||
min-width: 0;
|
||||
cursor: text;
|
||||
resize: none;
|
||||
|
|
@ -1096,11 +1096,11 @@
|
|||
overflow-wrap: anywhere;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-muted);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 1px solid var(--border-interactive-base);
|
||||
outline: 0.5px solid var(--v2-border-border-focus);
|
||||
outline-offset: 2px;
|
||||
border-radius: var(--radius-xs);
|
||||
}
|
||||
|
|
@ -1139,11 +1139,11 @@
|
|||
font-size: 13px;
|
||||
|
||||
[data-slot="question-text"] {
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-muted);
|
||||
}
|
||||
|
||||
[data-slot="answer-text"] {
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1166,13 +1166,13 @@
|
|||
z-index: 20;
|
||||
height: calc(32px + var(--tool-content-gap));
|
||||
padding-bottom: var(--tool-content-gap);
|
||||
background-color: var(--background-stronger);
|
||||
background-color: var(--v2-background-bg-base);
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="accordion"][data-scope="apply-patch"] {
|
||||
[data-slot="accordion-trigger"] {
|
||||
background-color: var(--background-stronger) !important;
|
||||
background-color: var(--v2-background-bg-base) !important;
|
||||
}
|
||||
|
||||
[data-slot="apply-patch-trigger-content"] {
|
||||
|
|
@ -1199,7 +1199,7 @@
|
|||
}
|
||||
|
||||
[data-slot="apply-patch-directory"] {
|
||||
color: var(--text-base);
|
||||
color: var(--v2-text-text-muted);
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
|
@ -1208,7 +1208,7 @@
|
|||
}
|
||||
|
||||
[data-slot="apply-patch-filename"] {
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
|
@ -1268,10 +1268,199 @@
|
|||
font-size: var(--font-size-small);
|
||||
font-weight: var(--font-weight-regular);
|
||||
line-height: var(--line-height-large);
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-muted);
|
||||
|
||||
[data-component="icon"] {
|
||||
flex-shrink: 0;
|
||||
color: var(--icon-weak);
|
||||
}
|
||||
}
|
||||
|
||||
body:not([data-new-layout]) {
|
||||
[data-component="user-message"] {
|
||||
color: var(--text-strong);
|
||||
|
||||
[data-slot="user-message-attachment"] {
|
||||
background: var(--surface-weak);
|
||||
border: 1px solid var(--border-weak-base);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--border-strong-base);
|
||||
}
|
||||
}
|
||||
|
||||
[data-slot="user-message-attachment-name"] {
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
[data-slot="user-message-text"] {
|
||||
background: var(--surface-base);
|
||||
border: 1px solid var(--border-weak-base);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.text-text-strong {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
}
|
||||
|
||||
[data-slot="compaction-part-line"] {
|
||||
background: var(--border-weak-base);
|
||||
}
|
||||
|
||||
[data-component="reasoning-part"] {
|
||||
color: var(--text-base);
|
||||
|
||||
[data-component="markdown"],
|
||||
[data-component="markdown"] :is(strong, b) {
|
||||
color: var(--text-weak);
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="bash-output"] {
|
||||
border: 1px solid var(--border-weak-base);
|
||||
|
||||
[data-slot="bash-copy"] [data-component="icon-button"][data-variant="secondary"] {
|
||||
border: 1px solid var(--border-weak-base);
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="edit-trigger"],
|
||||
[data-component="write-trigger"] {
|
||||
[data-slot="message-part-title"] {
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
[data-slot="message-part-title-spinner"],
|
||||
[data-slot="message-part-directory"] {
|
||||
color: var(--text-weak);
|
||||
}
|
||||
|
||||
[data-slot="message-part-title-text"],
|
||||
[data-slot="message-part-filename"] {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="edit-content"],
|
||||
[data-component="write-content"] {
|
||||
border-top: 1px solid var(--border-weaker-base);
|
||||
}
|
||||
|
||||
[data-component="exa-tool-output"] {
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
[data-slot="exa-tool-link"],
|
||||
[data-slot="exa-tool-link"]:hover,
|
||||
[data-slot="exa-tool-link"]:visited {
|
||||
color: var(--text-interactive-base);
|
||||
}
|
||||
|
||||
[data-slot="message-part-todo-content"][data-completed="completed"] {
|
||||
color: var(--text-weaker);
|
||||
}
|
||||
|
||||
[data-component="diagnostics"] {
|
||||
background-color: var(--surface-critical-weak);
|
||||
border-top: 1px solid var(--border-critical-base);
|
||||
|
||||
[data-slot="diagnostic-label"],
|
||||
[data-slot="diagnostic-message"] {
|
||||
color: var(--text-on-critical-base);
|
||||
}
|
||||
|
||||
[data-slot="diagnostic-location"] {
|
||||
color: var(--text-on-critical-weak);
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="dock-prompt"][data-kind="permission"] {
|
||||
[data-slot="permission-header-title"] {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
|
||||
[data-slot="permission-hint"] {
|
||||
color: var(--text-weak);
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="dock-prompt"][data-kind="question"] {
|
||||
[data-slot="question-header-title"],
|
||||
[data-slot="question-text"],
|
||||
[data-slot="option-label"] {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
|
||||
[data-slot="question-hint"] {
|
||||
color: var(--text-weak);
|
||||
}
|
||||
|
||||
[data-slot="question-option"] {
|
||||
background-color: var(--surface-raised-stronger-non-alpha);
|
||||
border: 1px solid var(--border-weak-base);
|
||||
|
||||
&:hover:not([data-picked="true"]) {
|
||||
background-color: var(--background-base);
|
||||
}
|
||||
|
||||
&[data-picked="true"] {
|
||||
background-color: var(--surface-interactive-weak);
|
||||
}
|
||||
}
|
||||
|
||||
[data-slot="question-option-box"] {
|
||||
border: 1px solid var(--border-weak-base);
|
||||
|
||||
[data-slot="question-option-radio-dot"] {
|
||||
background-color: var(--background-stronger);
|
||||
}
|
||||
}
|
||||
|
||||
[data-slot="option-description"],
|
||||
[data-slot="question-custom-input"] {
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
[data-slot="question-custom-input"] {
|
||||
&::placeholder {
|
||||
color: var(--text-weak);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 1px solid var(--border-interactive-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="question-answers"] {
|
||||
[data-slot="question-text"] {
|
||||
color: var(--text-weak);
|
||||
}
|
||||
|
||||
[data-slot="answer-text"] {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
}
|
||||
|
||||
:is([data-component="edit-tool"], [data-component="write-tool"], [data-component="apply-patch-tool"])
|
||||
> [data-component="collapsible"]
|
||||
> [data-slot="collapsible-trigger"][aria-expanded="true"],
|
||||
[data-component="accordion"][data-scope="apply-patch"] [data-slot="accordion-trigger"] {
|
||||
background-color: var(--background-stronger) !important;
|
||||
}
|
||||
|
||||
[data-component="accordion"][data-scope="apply-patch"] {
|
||||
[data-slot="apply-patch-directory"] {
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
[data-slot="apply-patch-filename"] {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="tool-loaded-file"] {
|
||||
color: var(--text-weak);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
[data-slot="session-review-header"] {
|
||||
z-index: 120;
|
||||
background-color: var(--background-stronger);
|
||||
background-color: var(--v2-background-bg-base);
|
||||
height: 40px;
|
||||
padding-bottom: 8px;
|
||||
flex-shrink: 0;
|
||||
|
|
@ -211,7 +211,7 @@
|
|||
|
||||
[data-slot="session-review-large-diff"] {
|
||||
padding: 12px;
|
||||
background: var(--background-stronger);
|
||||
background: var(--v2-background-bg-base);
|
||||
}
|
||||
|
||||
[data-slot="session-review-large-diff-title"] {
|
||||
|
|
@ -235,3 +235,13 @@
|
|||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
body:not([data-new-layout]) [data-component="session-review"] {
|
||||
[data-slot="session-review-header"] {
|
||||
background-color: var(--background-stronger);
|
||||
}
|
||||
|
||||
[data-slot="session-review-large-diff"] {
|
||||
background: var(--background-stronger);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@
|
|||
}
|
||||
|
||||
.error-card {
|
||||
color: var(--text-on-critical-base);
|
||||
color: var(--v2-text-text-base);
|
||||
max-height: 240px;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
|
|
@ -102,7 +102,7 @@
|
|||
position: sticky;
|
||||
top: var(--sticky-accordion-top, 0px);
|
||||
z-index: 20;
|
||||
background-color: var(--background-stronger);
|
||||
background-color: var(--v2-background-bg-base);
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
|
|
@ -226,6 +226,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
body:not([data-new-layout]) [data-component="session-turn"] {
|
||||
.error-card {
|
||||
color: var(--text-on-critical-base);
|
||||
}
|
||||
|
||||
[data-slot="session-turn-diffs-header"] {
|
||||
background-color: var(--background-stronger);
|
||||
}
|
||||
}
|
||||
|
||||
[data-slot="session-turn-list"] {
|
||||
gap: 24px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,19 @@
|
|||
--card-pad-y: 8px;
|
||||
--card-line-pad: 12px;
|
||||
|
||||
[data-slot="basic-tool-tool-title"] {
|
||||
color: var(--v2-text-text-base);
|
||||
}
|
||||
|
||||
[data-slot="basic-tool-tool-subtitle"] {
|
||||
color: var(--v2-text-text-muted);
|
||||
}
|
||||
|
||||
[data-slot="collapsible-arrow"],
|
||||
[data-slot="collapsible-arrow-icon"] {
|
||||
color: var(--v2-text-text-faint);
|
||||
}
|
||||
|
||||
> [data-component="collapsible"].tool-collapsible {
|
||||
gap: 0px;
|
||||
}
|
||||
|
|
@ -43,10 +56,34 @@
|
|||
}
|
||||
|
||||
[data-slot="tool-error-card-content"] :where(*)::selection {
|
||||
background: var(--surface-critical-base);
|
||||
color: var(--text-on-critical-base);
|
||||
background: var(--v2-state-bg-danger);
|
||||
color: var(--v2-text-text-base);
|
||||
}
|
||||
|
||||
[data-slot="tool-error-card-content"] :where(*)::-moz-selection {
|
||||
background: var(--v2-state-bg-danger);
|
||||
color: var(--v2-text-text-base);
|
||||
}
|
||||
}
|
||||
|
||||
body:not([data-new-layout]) [data-component="card"][data-kind="tool-error-card"] {
|
||||
[data-slot="basic-tool-tool-title"] {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
|
||||
[data-slot="basic-tool-tool-subtitle"] {
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
[data-slot="collapsible-arrow"] {
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
[data-slot="collapsible-arrow-icon"] {
|
||||
color: var(--icon-weaker);
|
||||
}
|
||||
|
||||
[data-slot="tool-error-card-content"] :where(*)::selection,
|
||||
[data-slot="tool-error-card-content"] :where(*)::-moz-selection {
|
||||
background: var(--surface-critical-base);
|
||||
color: var(--text-on-critical-base);
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@
|
|||
--v2-text-text-contrast: var(--v2-grey-50);
|
||||
--v2-text-text-accent: var(--v2-blue-600);
|
||||
--v2-text-text-accent-hover: var(--v2-blue-700);
|
||||
--v2-text-text-code-accent: var(--v2-blue-900);
|
||||
|
||||
--v2-icon-icon-base: var(--v2-grey-800);
|
||||
--v2-icon-icon-muted: var(--v2-grey-600);
|
||||
|
|
|
|||
|
|
@ -35,12 +35,12 @@
|
|||
cursor: default;
|
||||
user-select: none;
|
||||
|
||||
background-color: var(--background-stronger);
|
||||
border: 1px solid var(--border-weak-base);
|
||||
background-color: var(--v2-background-bg-base);
|
||||
border: 0.5px solid var(--v2-border-border-base);
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
overflow: clip;
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
transition: background-color 0.15s ease;
|
||||
|
||||
/* text-12-regular */
|
||||
|
|
@ -52,10 +52,10 @@
|
|||
letter-spacing: var(--letter-spacing-normal);
|
||||
|
||||
&:hover:not([data-disabled]) {
|
||||
background-color: var(--surface-base-hover);
|
||||
background-color: var(--v2-overlay-simple-overlay-hover);
|
||||
}
|
||||
&:active:not([data-disabled]) {
|
||||
background-color: var(--surface-base-active);
|
||||
background-color: var(--v2-overlay-simple-overlay-pressed);
|
||||
}
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
|
|
@ -82,9 +82,9 @@
|
|||
|
||||
&[data-expanded] {
|
||||
[data-slot="accordion-content"] {
|
||||
border: 1px solid var(--border-weak-base);
|
||||
border: 0.5px solid var(--v2-border-border-base);
|
||||
border-top: 0;
|
||||
background-color: var(--background-stronger);
|
||||
background-color: var(--v2-background-bg-layer-01);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +104,30 @@
|
|||
}
|
||||
}
|
||||
|
||||
body:not([data-new-layout]) [data-component="accordion"] {
|
||||
[data-slot="accordion-item"] [data-slot="accordion-header"] [data-slot="accordion-trigger"] {
|
||||
background-color: var(--background-stronger);
|
||||
border-width: 1px;
|
||||
border-color: var(--border-weak-base);
|
||||
color: var(--text-strong);
|
||||
|
||||
&:hover:not([data-disabled]) {
|
||||
background-color: var(--surface-base-hover);
|
||||
}
|
||||
|
||||
&:active:not([data-disabled]) {
|
||||
background-color: var(--surface-base-active);
|
||||
}
|
||||
}
|
||||
|
||||
[data-slot="accordion-item"][data-expanded] [data-slot="accordion-content"] {
|
||||
border-width: 1px;
|
||||
border-color: var(--border-weak-base);
|
||||
border-top: 0;
|
||||
background-color: var(--background-stronger);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
height: 0;
|
||||
|
|
|
|||
|
|
@ -19,14 +19,14 @@
|
|||
font-weight: var(--font-weight-regular);
|
||||
line-height: var(--line-height-large);
|
||||
letter-spacing: var(--letter-spacing-normal);
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
|
||||
--card-gap: 8px;
|
||||
--card-icon: 16px;
|
||||
--card-indent: 0px;
|
||||
--card-line-pad: 8px;
|
||||
|
||||
--card-accent: var(--icon-active);
|
||||
--card-accent: var(--v2-icon-icon-base);
|
||||
|
||||
&:has([data-slot="card-title"]) {
|
||||
gap: 8px;
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
}
|
||||
|
||||
:where([data-card="title"], [data-slot="card-title"]) {
|
||||
color: var(--text-strong);
|
||||
color: var(--v2-text-text-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
}
|
||||
|
||||
:where([data-slot="card-title-icon"][data-placeholder]) [data-component="icon"] {
|
||||
color: var(--text-weak);
|
||||
color: var(--v2-text-text-faint);
|
||||
}
|
||||
|
||||
:where([data-slot="card-title-icon"])
|
||||
|
|
@ -82,7 +82,7 @@
|
|||
}
|
||||
|
||||
:where([data-card="description"], [data-slot="card-description"]) {
|
||||
color: var(--text-base);
|
||||
color: var(--v2-text-text-muted);
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
|
|
@ -92,3 +92,24 @@
|
|||
padding-left: var(--card-indent);
|
||||
}
|
||||
}
|
||||
|
||||
body:not([data-new-layout]) [data-component="card"] {
|
||||
color: var(--text-strong);
|
||||
--card-accent: var(--icon-active);
|
||||
|
||||
:where([data-card="title"], [data-slot="card-title"]) {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
|
||||
:where([data-slot="card-title-icon"][data-placeholder]) [data-component="icon"] {
|
||||
color: var(--text-weak);
|
||||
}
|
||||
|
||||
:where([data-card="description"], [data-slot="card-description"]) {
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
&[data-variant="error"] {
|
||||
--card-accent: var(--icon-critical-base) !important;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export function Card(props: CardProps) {
|
|||
const variant = () => split.variant ?? "normal"
|
||||
const accent = () => {
|
||||
const v = variant()
|
||||
if (v === "error") return "var(--icon-critical-base)"
|
||||
if (v === "error") return "var(--v2-state-fg-danger)"
|
||||
if (v === "warning") return "var(--icon-warning-active)"
|
||||
if (v === "success") return "var(--icon-success-active)"
|
||||
if (v === "info") return "var(--icon-info-active)"
|
||||
|
|
|
|||
|
|
@ -249,6 +249,7 @@
|
|||
--color-v2-text-text-contrast: var(--v2-text-text-contrast);
|
||||
--color-v2-text-text-accent: var(--v2-text-text-accent);
|
||||
--color-v2-text-text-accent-hover: var(--v2-text-text-accent-hover);
|
||||
--color-v2-text-text-code-accent: var(--v2-text-text-code-accent);
|
||||
--color-v2-icon-icon-base: var(--v2-icon-icon-base);
|
||||
--color-v2-icon-icon-muted: var(--v2-icon-icon-muted);
|
||||
--color-v2-icon-icon-inverse: var(--v2-icon-icon-inverse);
|
||||
|
|
@ -282,4 +283,4 @@
|
|||
--color-v2-state-bg-info: var(--v2-state-bg-info);
|
||||
--color-v2-state-fg-info: var(--v2-state-fg-info);
|
||||
--color-v2-state-border-info: var(--v2-state-border-info);
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,8 @@
|
|||
"text-base": "#6F6F6F",
|
||||
"text-weak": "#8F8F8F",
|
||||
"text-weaker": "#C7C7C7",
|
||||
"text-diff-add-base": "var(--v2-state-fg-success)",
|
||||
"text-diff-delete-base": "var(--v2-state-fg-danger)",
|
||||
"border-weak-base": "#DBDBDB",
|
||||
"border-weaker-base": "#E8E8E8",
|
||||
"icon-base": "#8F8F8F",
|
||||
|
|
@ -31,14 +33,14 @@
|
|||
"surface-interactive-weak": "#F5FAFF",
|
||||
"icon-success-base": "#0ABE00",
|
||||
"surface-success-base": "#E6FFE5",
|
||||
"syntax-comment": "#7a7a7a",
|
||||
"syntax-keyword": "#a753ae",
|
||||
"syntax-string": "#00ceb9",
|
||||
"syntax-primitive": "#034cff",
|
||||
"syntax-property": "#a753ae",
|
||||
"syntax-type": "#8a6f00",
|
||||
"syntax-comment": "var(--v2-text-text-muted)",
|
||||
"syntax-keyword": "var(--v2-pink-800)",
|
||||
"syntax-string": "var(--v2-green-800)",
|
||||
"syntax-primitive": "var(--v2-pink-800)",
|
||||
"syntax-property": "var(--v2-orange-800)",
|
||||
"syntax-type": "var(--v2-purple-800)",
|
||||
"syntax-constant": "#007b80",
|
||||
"syntax-critical": "#ff8c00",
|
||||
"syntax-critical": "var(--v2-red-800)",
|
||||
"syntax-diff-delete": "#ff8c00",
|
||||
"syntax-diff-unknown": "#a753ae",
|
||||
"surface-critical-base": "#FFF2F0"
|
||||
|
|
@ -170,6 +172,7 @@
|
|||
"v2-text-text-contrast": "var(--v2-grey-50)",
|
||||
"v2-text-text-accent": "var(--v2-blue-600)",
|
||||
"v2-text-text-accent-hover": "var(--v2-blue-700)",
|
||||
"v2-text-text-code-accent": "var(--v2-blue-900)",
|
||||
"v2-icon-icon-base": "var(--v2-grey-800)",
|
||||
"v2-icon-icon-muted": "var(--v2-grey-600)",
|
||||
"v2-icon-icon-inverse": "var(--v2-grey-50)",
|
||||
|
|
@ -252,6 +255,8 @@
|
|||
"text-base": "#A0A0A0",
|
||||
"text-weak": "#707070",
|
||||
"text-weaker": "#505050",
|
||||
"text-diff-add-base": "var(--v2-state-fg-success)",
|
||||
"text-diff-delete-base": "var(--v2-state-fg-danger)",
|
||||
"border-weak-base": "#282828",
|
||||
"border-weaker-base": "#232323",
|
||||
"icon-base": "#7E7E7E",
|
||||
|
|
@ -262,14 +267,14 @@
|
|||
"surface-base-hover": "#FFFFFF0D",
|
||||
"surface-interactive-weak": "#0D172B",
|
||||
"surface-success-base": "#022B00",
|
||||
"syntax-comment": "#8f8f8f",
|
||||
"syntax-keyword": "#edb2f1",
|
||||
"syntax-string": "#00ceb9",
|
||||
"syntax-primitive": "#8cb0ff",
|
||||
"syntax-property": "#fab283",
|
||||
"syntax-type": "#fcd53a",
|
||||
"syntax-comment": "var(--v2-text-text-muted)",
|
||||
"syntax-keyword": "var(--v2-pink-400)",
|
||||
"syntax-string": "var(--v2-green-400)",
|
||||
"syntax-primitive": "var(--v2-pink-400)",
|
||||
"syntax-property": "var(--v2-orange-400)",
|
||||
"syntax-type": "var(--v2-purple-400)",
|
||||
"syntax-constant": "#93e9f6",
|
||||
"syntax-critical": "#fab283",
|
||||
"syntax-critical": "var(--v2-red-400)",
|
||||
"syntax-diff-delete": "#fab283",
|
||||
"syntax-diff-unknown": "#edb2f1",
|
||||
"surface-critical-base": "#1F0603"
|
||||
|
|
@ -401,6 +406,7 @@
|
|||
"v2-text-text-contrast": "var(--v2-grey-50)",
|
||||
"v2-text-text-accent": "var(--v2-blue-400)",
|
||||
"v2-text-text-accent-hover": "var(--v2-blue-300)",
|
||||
"v2-text-text-code-accent": "var(--v2-blue-400)",
|
||||
"v2-icon-icon-base": "var(--v2-grey-400)",
|
||||
"v2-icon-icon-muted": "var(--v2-grey-600)",
|
||||
"v2-icon-icon-inverse": "var(--v2-grey-1100)",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ const light: Record<string, V2ColorValue> = {
|
|||
"v2-text-text-contrast": ref("v2-grey-100"),
|
||||
"v2-text-text-accent": ref("v2-blue-600"),
|
||||
"v2-text-text-accent-hover": ref("v2-blue-700"),
|
||||
"v2-text-text-code-accent": ref("v2-blue-900"),
|
||||
"v2-border-border-muted": ref("v2-alpha-dark-8"),
|
||||
"v2-border-border-base": ref("v2-alpha-dark-10"),
|
||||
"v2-border-border-strong": ref("v2-alpha-dark-20"),
|
||||
|
|
@ -81,6 +82,7 @@ const dark: Record<string, V2ColorValue> = {
|
|||
"v2-text-text-contrast": ref("v2-grey-100"),
|
||||
"v2-text-text-accent": ref("v2-blue-400"),
|
||||
"v2-text-text-accent-hover": ref("v2-blue-300"),
|
||||
"v2-text-text-code-accent": ref("v2-blue-400"),
|
||||
"v2-border-border-muted": ref("v2-alpha-light-8"),
|
||||
"v2-border-border-base": ref("v2-alpha-light-10"),
|
||||
"v2-border-border-strong": ref("v2-alpha-light-20"),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,16 @@
|
|||
@layer theme {
|
||||
html[data-theme="oc-2"] body:not([data-new-layout]) {
|
||||
--text-diff-add-base: light-dark(#167517, #c4ffc0);
|
||||
--text-diff-delete-base: light-dark(#fa3012, #ec2f14);
|
||||
--syntax-comment: light-dark(#7a7a7a, #8f8f8f);
|
||||
--syntax-keyword: light-dark(#a753ae, #edb2f1);
|
||||
--syntax-string: #00ceb9;
|
||||
--syntax-primitive: light-dark(#034cff, #8cb0ff);
|
||||
--syntax-property: light-dark(#a753ae, #fab283);
|
||||
--syntax-type: light-dark(#8a6f00, #fcd53a);
|
||||
--syntax-critical: light-dark(#ff8c00, #fab283);
|
||||
}
|
||||
|
||||
:root {
|
||||
color-scheme: light;
|
||||
|
||||
|
|
@ -22,6 +34,7 @@
|
|||
--v2-text-text-contrast: var(--v2-grey-50);
|
||||
--v2-text-text-accent: var(--v2-blue-600);
|
||||
--v2-text-text-accent-hover: var(--v2-blue-700);
|
||||
--v2-text-text-code-accent: var(--v2-blue-900);
|
||||
|
||||
/* ── Icon ── */
|
||||
--v2-icon-icon-base: var(--v2-grey-800);
|
||||
|
|
@ -141,6 +154,7 @@
|
|||
--v2-text-text-contrast: var(--v2-grey-100);
|
||||
--v2-text-text-accent: var(--v2-blue-400);
|
||||
--v2-text-text-accent-hover: var(--v2-blue-300);
|
||||
--v2-text-text-code-accent: var(--v2-blue-400);
|
||||
|
||||
--v2-icon-icon-base: var(--v2-grey-400);
|
||||
--v2-icon-icon-muted: var(--v2-grey-600);
|
||||
|
|
@ -243,6 +257,7 @@
|
|||
--v2-text-text-contrast: var(--v2-grey-50);
|
||||
--v2-text-text-accent: var(--v2-blue-600);
|
||||
--v2-text-text-accent-hover: var(--v2-blue-700);
|
||||
--v2-text-text-code-accent: var(--v2-blue-900);
|
||||
|
||||
--v2-icon-icon-base: var(--v2-grey-800);
|
||||
--v2-icon-icon-muted: var(--v2-grey-600);
|
||||
|
|
@ -352,6 +367,7 @@
|
|||
--v2-text-text-contrast: var(--v2-grey-50);
|
||||
--v2-text-text-accent: var(--v2-blue-400);
|
||||
--v2-text-text-accent-hover: var(--v2-blue-300);
|
||||
--v2-text-text-code-accent: var(--v2-blue-400);
|
||||
|
||||
--v2-icon-icon-base: var(--v2-grey-400);
|
||||
--v2-icon-icon-muted: var(--v2-grey-600);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue