Skip to content

Commit 3394402

Browse files
committed
chore: cleanup
1 parent 6cd3a59 commit 3394402

5 files changed

Lines changed: 274 additions & 110 deletions

File tree

packages/ui/src/components/basic-tool.tsx

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createEffect, createSignal, For, Match, Show, Switch, type JSX } from "solid-js"
1+
import { createEffect, createSignal, For, Match, on, onCleanup, Show, Switch, type JSX } from "solid-js"
22
import { Collapsible } from "./collapsible"
33
import type { IconProps } from "./icon"
44
import { TextShimmer } from "./text-shimmer"
@@ -27,18 +27,52 @@ export interface BasicToolProps {
2727
hideDetails?: boolean
2828
defaultOpen?: boolean
2929
forceOpen?: boolean
30+
defer?: boolean
3031
locked?: boolean
3132
onSubtitleClick?: () => void
3233
}
3334

3435
export function BasicTool(props: BasicToolProps) {
3536
const [open, setOpen] = createSignal(props.defaultOpen ?? false)
37+
const [ready, setReady] = createSignal(open())
3638
const pending = () => props.status === "pending" || props.status === "running"
3739

40+
let frame: number | undefined
41+
42+
const cancel = () => {
43+
if (frame === undefined) return
44+
cancelAnimationFrame(frame)
45+
frame = undefined
46+
}
47+
48+
onCleanup(cancel)
49+
3850
createEffect(() => {
3951
if (props.forceOpen) setOpen(true)
4052
})
4153

54+
createEffect(
55+
on(
56+
open,
57+
(value) => {
58+
if (!props.defer) return
59+
if (!value) {
60+
cancel()
61+
setReady(false)
62+
return
63+
}
64+
65+
cancel()
66+
frame = requestAnimationFrame(() => {
67+
frame = undefined
68+
if (!open()) return
69+
setReady(true)
70+
})
71+
},
72+
{ defer: true },
73+
),
74+
)
75+
4276
const handleOpenChange = (value: boolean) => {
4377
if (pending()) return
4478
if (props.locked && !value) return
@@ -114,7 +148,9 @@ export function BasicTool(props: BasicToolProps) {
114148
</div>
115149
</Collapsible.Trigger>
116150
<Show when={props.children && !props.hideDetails}>
117-
<Collapsible.Content>{props.children}</Collapsible.Content>
151+
<Collapsible.Content>
152+
<Show when={!props.defer || ready()}>{props.children}</Show>
153+
</Collapsible.Content>
118154
</Show>
119155
</Collapsible>
120156
)

packages/ui/src/components/message-part.css

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,7 @@
326326
}
327327

328328
[data-slot="collapsible-content"]:has([data-component="edit-content"]),
329-
[data-slot="collapsible-content"]:has([data-component="write-content"]),
330-
[data-slot="collapsible-content"]:has([data-component="apply-patch-files"]) {
329+
[data-slot="collapsible-content"]:has([data-component="write-content"]) {
331330
border: 1px solid var(--border-weak-base);
332331
border-radius: 6px;
333332
background: transparent;
@@ -1219,21 +1218,31 @@
12191218
}
12201219
}
12211220

1222-
[data-component="apply-patch-files"] {
1223-
display: flex;
1224-
flex-direction: column;
1225-
}
1221+
[data-component="accordion"][data-scope="apply-patch"] {
1222+
[data-slot="apply-patch-trigger-content"] {
1223+
display: flex;
1224+
align-items: center;
1225+
justify-content: space-between;
1226+
width: 100%;
1227+
min-width: 0;
1228+
gap: 12px;
1229+
}
12261230

1227-
[data-component="apply-patch-file"] {
1228-
display: flex;
1229-
flex-direction: column;
1231+
[data-slot="apply-patch-file-path"] {
1232+
font-family: var(--font-family-mono);
1233+
font-size: var(--font-size-small);
1234+
color: var(--text-weak);
1235+
overflow: hidden;
1236+
text-overflow: ellipsis;
1237+
white-space: nowrap;
1238+
flex-grow: 1;
1239+
}
12301240

1231-
[data-slot="apply-patch-file-header"] {
1232-
display: flex;
1241+
[data-slot="apply-patch-trigger-actions"] {
1242+
flex-shrink: 0;
1243+
display: inline-flex;
12331244
align-items: center;
1234-
gap: 8px;
1235-
padding: 8px 12px;
1236-
background-color: transparent;
1245+
gap: 10px;
12371246
}
12381247

12391248
[data-slot="apply-patch-file-action"] {
@@ -1257,26 +1266,23 @@
12571266
}
12581267
}
12591268

1260-
[data-slot="apply-patch-file-path"] {
1261-
font-family: var(--font-family-mono);
1262-
font-size: var(--font-size-small);
1263-
color: var(--text-weak);
1264-
overflow: hidden;
1265-
text-overflow: ellipsis;
1266-
white-space: nowrap;
1267-
flex-grow: 1;
1268-
}
1269-
12701269
[data-slot="apply-patch-deletion-count"] {
12711270
font-family: var(--font-family-mono);
12721271
font-size: var(--font-size-small);
12731272
color: var(--text-critical-base);
12741273
flex-shrink: 0;
12751274
}
1276-
}
12771275

1278-
[data-component="apply-patch-file"] + [data-component="apply-patch-file"] {
1279-
border-top: 1px solid var(--border-weaker-base);
1276+
[data-slot="apply-patch-file-chevron"] {
1277+
display: inline-flex;
1278+
color: var(--icon-weaker);
1279+
transform: rotate(-90deg);
1280+
transition: transform 0.15s ease;
1281+
}
1282+
1283+
[data-slot="accordion-item"][data-expanded] [data-slot="apply-patch-file-chevron"] {
1284+
transform: rotate(0deg);
1285+
}
12801286
}
12811287

12821288
[data-component="apply-patch-file-diff"] {

packages/ui/src/components/message-part.tsx

Lines changed: 88 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { useDialog } from "../context/dialog"
3535
import { useI18n } from "../context/i18n"
3636
import { BasicTool } from "./basic-tool"
3737
import { GenericTool } from "./basic-tool"
38+
import { Accordion } from "./accordion"
3839
import { Button } from "./button"
3940
import { Card } from "./card"
4041
import { Collapsible } from "./collapsible"
@@ -1482,6 +1483,7 @@ ToolRegistry.register({
14821483
<BasicTool
14831484
{...props}
14841485
icon="code-lines"
1486+
defer
14851487
trigger={
14861488
<div data-component="edit-trigger">
14871489
<div data-slot="message-part-title-area">
@@ -1542,6 +1544,7 @@ ToolRegistry.register({
15421544
<BasicTool
15431545
{...props}
15441546
icon="code-lines"
1547+
defer
15451548
trigger={
15461549
<div data-component="write-trigger">
15471550
<div data-slot="message-part-title-area">
@@ -1602,6 +1605,16 @@ ToolRegistry.register({
16021605
const i18n = useI18n()
16031606
const diffComponent = useDiffComponent()
16041607
const files = createMemo(() => (props.metadata.files ?? []) as ApplyPatchFile[])
1608+
const [expanded, setExpanded] = createSignal<string[]>([])
1609+
let seeded = false
1610+
1611+
createEffect(() => {
1612+
const list = files()
1613+
if (list.length === 0) return
1614+
if (seeded) return
1615+
seeded = true
1616+
setExpanded(list.filter((f) => f.type !== "delete").map((f) => f.filePath))
1617+
})
16051618

16061619
const subtitle = createMemo(() => {
16071620
const count = files().length
@@ -1613,60 +1626,89 @@ ToolRegistry.register({
16131626
<BasicTool
16141627
{...props}
16151628
icon="code-lines"
1629+
defer
16161630
trigger={{
16171631
title: i18n.t("ui.tool.patch"),
16181632
subtitle: subtitle(),
16191633
}}
16201634
>
16211635
<Show when={files().length > 0}>
1622-
<div data-component="apply-patch-files">
1636+
<Accordion
1637+
multiple
1638+
data-scope="apply-patch"
1639+
value={expanded()}
1640+
onChange={(value) => setExpanded(Array.isArray(value) ? value : value ? [value] : [])}
1641+
>
16231642
<For each={files()}>
1624-
{(file) => (
1625-
<div data-component="apply-patch-file">
1626-
<div data-slot="apply-patch-file-header">
1627-
<Switch>
1628-
<Match when={file.type === "delete"}>
1629-
<span data-slot="apply-patch-file-action" data-type="delete">
1630-
{i18n.t("ui.patch.action.deleted")}
1631-
</span>
1632-
</Match>
1633-
<Match when={file.type === "add"}>
1634-
<span data-slot="apply-patch-file-action" data-type="add">
1635-
{i18n.t("ui.patch.action.created")}
1636-
</span>
1637-
</Match>
1638-
<Match when={file.type === "move"}>
1639-
<span data-slot="apply-patch-file-action" data-type="move">
1640-
{i18n.t("ui.patch.action.moved")}
1641-
</span>
1642-
</Match>
1643-
<Match when={file.type === "update"}>
1644-
<span data-slot="apply-patch-file-action" data-type="update">
1645-
{i18n.t("ui.patch.action.patched")}
1646-
</span>
1647-
</Match>
1648-
</Switch>
1649-
<span data-slot="apply-patch-file-path">{file.relativePath}</span>
1650-
<Show when={file.type !== "delete"}>
1651-
<DiffChanges changes={{ additions: file.additions, deletions: file.deletions }} />
1652-
</Show>
1653-
<Show when={file.type === "delete"}>
1654-
<span data-slot="apply-patch-deletion-count">-{file.deletions}</span>
1655-
</Show>
1656-
</div>
1657-
<Show when={file.type !== "delete"}>
1658-
<div data-component="apply-patch-file-diff">
1659-
<Dynamic
1660-
component={diffComponent}
1661-
before={{ name: file.filePath, contents: file.before }}
1662-
after={{ name: file.filePath, contents: file.after }}
1663-
/>
1664-
</div>
1665-
</Show>
1666-
</div>
1667-
)}
1643+
{(file) => {
1644+
const active = createMemo(() => expanded().includes(file.filePath))
1645+
const [visible, setVisible] = createSignal(false)
1646+
1647+
createEffect(() => {
1648+
if (!active()) {
1649+
setVisible(false)
1650+
return
1651+
}
1652+
1653+
requestAnimationFrame(() => {
1654+
if (!active()) return
1655+
setVisible(true)
1656+
})
1657+
})
1658+
1659+
return (
1660+
<Accordion.Item value={file.filePath} data-type={file.type}>
1661+
<Accordion.Header>
1662+
<Accordion.Trigger>
1663+
<div data-slot="apply-patch-trigger-content">
1664+
<span data-slot="apply-patch-file-path">{file.relativePath}</span>
1665+
<div data-slot="apply-patch-trigger-actions">
1666+
<Switch>
1667+
<Match when={file.type === "delete"}>
1668+
<span data-slot="apply-patch-file-action" data-type="delete">
1669+
{i18n.t("ui.patch.action.deleted")}
1670+
</span>
1671+
</Match>
1672+
<Match when={file.type === "add"}>
1673+
<span data-slot="apply-patch-file-action" data-type="add">
1674+
{i18n.t("ui.patch.action.created")}
1675+
</span>
1676+
</Match>
1677+
<Match when={file.type === "move"}>
1678+
<span data-slot="apply-patch-file-action" data-type="move">
1679+
{i18n.t("ui.patch.action.moved")}
1680+
</span>
1681+
</Match>
1682+
</Switch>
1683+
<Show when={file.type !== "delete"}>
1684+
<DiffChanges changes={{ additions: file.additions, deletions: file.deletions }} />
1685+
</Show>
1686+
<Show when={file.type === "delete"}>
1687+
<span data-slot="apply-patch-deletion-count">-{file.deletions}</span>
1688+
</Show>
1689+
<span data-slot="apply-patch-file-chevron">
1690+
<Icon name="chevron-down" size="small" />
1691+
</span>
1692+
</div>
1693+
</div>
1694+
</Accordion.Trigger>
1695+
</Accordion.Header>
1696+
<Accordion.Content>
1697+
<Show when={visible()}>
1698+
<div data-component="apply-patch-file-diff">
1699+
<Dynamic
1700+
component={diffComponent}
1701+
before={{ name: file.filePath, contents: file.before }}
1702+
after={{ name: file.movePath ?? file.filePath, contents: file.after }}
1703+
/>
1704+
</div>
1705+
</Show>
1706+
</Accordion.Content>
1707+
</Accordion.Item>
1708+
)
1709+
}}
16681710
</For>
1669-
</div>
1711+
</Accordion>
16701712
</Show>
16711713
</BasicTool>
16721714
)

packages/ui/src/components/session-turn.css

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,19 +130,13 @@
130130
gap: 12px;
131131
}
132132

133-
[data-component="session-turn-diff"] {
134-
border: 1px solid var(--border-weaker-base);
135-
border-radius: var(--radius-md);
136-
overflow: clip;
137-
}
138-
139-
[data-slot="session-turn-diff-header"] {
133+
[data-slot="session-turn-diff-trigger"] {
140134
display: flex;
141135
align-items: center;
142136
justify-content: space-between;
143137
gap: 12px;
144-
padding: 6px 10px;
145-
border-bottom: 1px solid var(--border-weaker-base);
138+
width: 100%;
139+
min-width: 0;
146140
}
147141

148142
[data-slot="session-turn-diff-path"] {
@@ -166,9 +160,36 @@
166160
font-weight: var(--font-weight-medium);
167161
}
168162

163+
[data-slot="session-turn-diff-meta"] {
164+
flex-shrink: 0;
165+
display: inline-flex;
166+
align-items: center;
167+
gap: 10px;
168+
}
169+
170+
[data-slot="session-turn-diff-chevron"] {
171+
display: inline-flex;
172+
color: var(--icon-weaker);
173+
transform: rotate(-90deg);
174+
transition: transform 0.15s ease;
175+
}
176+
177+
[data-slot="accordion-item"][data-expanded] [data-slot="session-turn-diff-chevron"] {
178+
transform: rotate(0deg);
179+
}
180+
169181
[data-slot="session-turn-diff-view"] {
170182
background-color: var(--surface-inset-base);
171183
width: 100%;
172184
min-width: 0;
185+
max-height: 420px;
186+
overflow-y: auto;
187+
overflow-x: hidden;
188+
scrollbar-width: none;
189+
-ms-overflow-style: none;
190+
}
191+
192+
[data-slot="session-turn-diff-view"]::-webkit-scrollbar {
193+
display: none;
173194
}
174195
}

0 commit comments

Comments
 (0)