Skip to content

Commit 9d57f21

Browse files
feat(ui): redesign modified files section in session turn (anomalyco#20348)
Co-authored-by: David Hill <iamdavidhill@gmail.com>
1 parent 3deee3a commit 9d57f21

3 files changed

Lines changed: 134 additions & 143 deletions

File tree

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

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -92,62 +92,54 @@
9292
min-width: 0;
9393
}
9494

95-
[data-slot="session-turn-diffs"]
96-
> [data-component="collapsible"]
97-
> [data-slot="collapsible-trigger"][aria-expanded="true"] {
98-
position: sticky;
99-
top: var(--sticky-accordion-top, 0px);
100-
z-index: 20;
101-
height: 40px;
102-
padding-bottom: 8px;
103-
background-color: var(--background-stronger);
104-
}
105-
106-
[data-component="session-turn-diffs-trigger"] {
107-
width: 100%;
95+
[data-slot="session-turn-diffs-header"] {
10896
display: flex;
109-
align-items: center;
110-
justify-content: flex-start;
111-
gap: 8px;
112-
padding: 0;
113-
}
114-
115-
[data-slot="session-turn-diffs-title"] {
116-
display: inline-flex;
11797
align-items: baseline;
11898
gap: 8px;
99+
padding-bottom: 12px;
119100
}
120101

121102
[data-slot="session-turn-diffs-label"] {
103+
font-variant-numeric: tabular-nums;
122104
color: var(--text-strong);
123105
font-family: var(--font-family-sans);
124106
font-size: var(--font-size-base);
125107
font-weight: var(--font-weight-medium);
126108
line-height: var(--line-height-large);
127109
}
128110

129-
[data-slot="session-turn-diffs-count"] {
130-
color: var(--text-base);
111+
[data-slot="session-turn-diffs-toggle"] {
112+
color: var(--text-interactive-base);
131113
font-family: var(--font-family-sans);
132-
font-variant-numeric: tabular-nums;
133114
font-size: var(--font-size-base);
134115
font-weight: var(--font-weight-regular);
135-
line-height: var(--line-height-x-large);
116+
line-height: var(--line-height-large);
117+
cursor: pointer;
118+
opacity: 0;
119+
transition: opacity 0.15s ease;
120+
margin-left: 4px;
136121
}
137122

138-
[data-slot="session-turn-diffs-meta"] {
139-
display: inline-flex;
140-
align-items: center;
141-
gap: 8px;
142-
flex-shrink: 0;
123+
[data-component="session-turn-diffs-group"]:hover [data-slot="session-turn-diffs-toggle"] {
124+
opacity: 1;
125+
}
143126

144-
[data-slot="collapsible-arrow"] {
145-
margin-left: -6px;
146-
transform: translateY(2px);
147-
}
127+
[data-component="session-turn-diffs-group"][data-show-all] [data-slot="session-turn-diffs-toggle"] {
128+
opacity: 1;
129+
}
130+
131+
[data-slot="session-turn-diffs-more"] {
132+
color: var(--text-weak);
133+
font-family: var(--font-family-sans);
134+
font-size: var(--font-size-small);
135+
line-height: var(--line-height-large);
136+
margin-top: 12px;
137+
padding: 0 0 6px;
138+
cursor: pointer;
139+
transition: color 0.15s ease;
148140

149-
[data-component="diff-changes"][data-variant="bars"] {
150-
transform: translateY(1px);
141+
&:hover {
142+
color: var(--text-link-base);
151143
}
152144
}
153145

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

Lines changed: 102 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { AssistantParts, Message, MessageDivider, PART_MAPPING, type UserActions
1212
import { Card } from "./card"
1313
import { Accordion } from "./accordion"
1414
import { StickyAccordionHeader } from "./sticky-accordion-header"
15-
import { Collapsible } from "./collapsible"
1615
import { DiffChanges } from "./diff-changes"
1716
import { Icon } from "./icon"
1817
import { TextShimmer } from "./text-shimmer"
@@ -241,23 +240,20 @@ export function SessionTurn(
241240
}, [])
242241
.reverse()
243242
})
243+
const MAX_FILES = 10
244244
const edited = createMemo(() => diffs().length)
245245
const [state, setState] = createStore({
246-
open: false,
246+
showAll: false,
247247
expanded: [] as string[],
248248
})
249-
const open = () => state.open
249+
const showAll = () => state.showAll
250250
const expanded = () => state.expanded
251-
252-
createEffect(
253-
on(
254-
open,
255-
(value, prev) => {
256-
if (!value && prev) setState("expanded", [])
257-
},
258-
{ defer: true },
259-
),
260-
)
251+
const overflow = createMemo(() => Math.max(0, edited() - MAX_FILES))
252+
const visible = createMemo(() => (showAll() ? diffs() : diffs().slice(0, MAX_FILES)))
253+
const toggleAll = () => {
254+
autoScroll.pause()
255+
setState("showAll", !showAll())
256+
}
261257

262258
const assistantMessages = createMemo(
263259
() => {
@@ -425,101 +421,100 @@ export function SessionTurn(
425421
</Show>
426422
<SessionRetry status={status()} show={active()} />
427423
<Show when={edited() > 0 && !working()}>
428-
<div data-slot="session-turn-diffs">
429-
<Collapsible open={open()} onOpenChange={(value) => setState("open", value)} variant="ghost">
430-
<Collapsible.Trigger>
431-
<div data-component="session-turn-diffs-trigger">
432-
<div data-slot="session-turn-diffs-title">
433-
<span data-slot="session-turn-diffs-label">{i18n.t("ui.sessionReview.change.modified")}</span>
434-
<span data-slot="session-turn-diffs-count">
435-
{edited()} {i18n.t(edited() === 1 ? "ui.common.file.one" : "ui.common.file.other")}
436-
</span>
437-
<div data-slot="session-turn-diffs-meta">
438-
<DiffChanges changes={diffs()} variant="bars" />
439-
<Collapsible.Arrow />
440-
</div>
441-
</div>
442-
</div>
443-
</Collapsible.Trigger>
444-
<Collapsible.Content>
445-
<Show when={open()}>
446-
<div data-component="session-turn-diffs-content">
447-
<Accordion
448-
multiple
449-
style={{ "--sticky-accordion-offset": "40px" }}
450-
value={expanded()}
451-
onChange={(value) =>
452-
setState("expanded", Array.isArray(value) ? value : value ? [value] : [])
453-
}
454-
>
455-
<For each={diffs()}>
456-
{(diff) => {
457-
const active = createMemo(() => expanded().includes(diff.file))
458-
const [visible, setVisible] = createSignal(false)
459-
460-
createEffect(
461-
on(
462-
active,
463-
(value) => {
464-
if (!value) {
465-
setVisible(false)
466-
return
467-
}
468-
469-
requestAnimationFrame(() => {
470-
if (!active()) return
471-
setVisible(true)
472-
})
473-
},
474-
{ defer: true },
475-
),
476-
)
477-
478-
return (
479-
<Accordion.Item value={diff.file}>
480-
<StickyAccordionHeader>
481-
<Accordion.Trigger>
482-
<div data-slot="session-turn-diff-trigger">
483-
<span data-slot="session-turn-diff-path">
484-
<Show when={diff.file.includes("/")}>
485-
<span data-slot="session-turn-diff-directory">
486-
{`\u202A${getDirectory(diff.file)}\u202C`}
487-
</span>
488-
</Show>
489-
<span data-slot="session-turn-diff-filename">{getFilename(diff.file)}</span>
490-
</span>
491-
<div data-slot="session-turn-diff-meta">
492-
<span data-slot="session-turn-diff-changes">
493-
<DiffChanges changes={diff} />
494-
</span>
495-
<span data-slot="session-turn-diff-chevron">
496-
<Icon name="chevron-down" size="small" />
497-
</span>
498-
</div>
499-
</div>
500-
</Accordion.Trigger>
501-
</StickyAccordionHeader>
502-
<Accordion.Content>
503-
<Show when={visible()}>
504-
<div data-slot="session-turn-diff-view" data-scrollable>
505-
<Dynamic
506-
component={fileComponent}
507-
mode="diff"
508-
before={{ name: diff.file, contents: diff.before }}
509-
after={{ name: diff.file, contents: diff.after }}
510-
/>
511-
</div>
424+
<div
425+
data-slot="session-turn-diffs"
426+
data-component="session-turn-diffs-group"
427+
data-show-all={showAll() || undefined}
428+
>
429+
<div data-slot="session-turn-diffs-header">
430+
<span data-slot="session-turn-diffs-label">
431+
{edited()} {i18n.t("ui.sessionTurn.diffs.changed")}{" "}
432+
{i18n.t(edited() === 1 ? "ui.common.file.one" : "ui.common.file.other")}
433+
</span>
434+
<DiffChanges changes={diffs()} />
435+
<Show when={overflow() > 0}>
436+
<span data-slot="session-turn-diffs-toggle" onClick={toggleAll}>
437+
{showAll() ? i18n.t("ui.sessionTurn.diffs.showLess") : i18n.t("ui.sessionTurn.diffs.showAll")}
438+
</span>
439+
</Show>
440+
</div>
441+
<div data-component="session-turn-diffs-content">
442+
<Accordion
443+
multiple
444+
style={{ "--sticky-accordion-offset": "40px" }}
445+
value={expanded()}
446+
onChange={(value) => setState("expanded", Array.isArray(value) ? value : value ? [value] : [])}
447+
>
448+
<For each={visible()}>
449+
{(diff) => {
450+
const active = createMemo(() => expanded().includes(diff.file))
451+
const [shown, setShown] = createSignal(false)
452+
453+
createEffect(
454+
on(
455+
active,
456+
(value) => {
457+
if (!value) {
458+
setShown(false)
459+
return
460+
}
461+
462+
requestAnimationFrame(() => {
463+
if (!active()) return
464+
setShown(true)
465+
})
466+
},
467+
{ defer: true },
468+
),
469+
)
470+
471+
return (
472+
<Accordion.Item value={diff.file}>
473+
<StickyAccordionHeader>
474+
<Accordion.Trigger>
475+
<div data-slot="session-turn-diff-trigger">
476+
<span data-slot="session-turn-diff-path">
477+
<Show when={diff.file.includes("/")}>
478+
<span data-slot="session-turn-diff-directory">
479+
{`\u202A${getDirectory(diff.file)}\u202C`}
480+
</span>
512481
</Show>
513-
</Accordion.Content>
514-
</Accordion.Item>
515-
)
516-
}}
517-
</For>
518-
</Accordion>
519-
</div>
520-
</Show>
521-
</Collapsible.Content>
522-
</Collapsible>
482+
<span data-slot="session-turn-diff-filename">{getFilename(diff.file)}</span>
483+
</span>
484+
<div data-slot="session-turn-diff-meta">
485+
<span data-slot="session-turn-diff-changes">
486+
<DiffChanges changes={diff} />
487+
</span>
488+
<span data-slot="session-turn-diff-chevron">
489+
<Icon name="chevron-down" size="small" />
490+
</span>
491+
</div>
492+
</div>
493+
</Accordion.Trigger>
494+
</StickyAccordionHeader>
495+
<Accordion.Content>
496+
<Show when={shown()}>
497+
<div data-slot="session-turn-diff-view" data-scrollable>
498+
<Dynamic
499+
component={fileComponent}
500+
mode="diff"
501+
before={{ name: diff.file, contents: diff.before }}
502+
after={{ name: diff.file, contents: diff.after }}
503+
/>
504+
</div>
505+
</Show>
506+
</Accordion.Content>
507+
</Accordion.Item>
508+
)
509+
}}
510+
</For>
511+
</Accordion>
512+
<Show when={!showAll() && overflow() > 0}>
513+
<div data-slot="session-turn-diffs-more" onClick={toggleAll}>
514+
{i18n.t("ui.sessionTurn.diffs.more", { count: String(overflow()) })}
515+
</div>
516+
</Show>
517+
</div>
523518
</div>
524519
</Show>
525520
<Show when={error()}>

packages/ui/src/i18n/en.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ export const dict: Record<string, string> = {
3838
"ui.sessionTurn.steps.hide": "Hide steps",
3939
"ui.sessionTurn.summary.response": "Response",
4040
"ui.sessionTurn.diff.showMore": "Show more changes ({{count}})",
41+
"ui.sessionTurn.diffs.changed": "Changed",
42+
"ui.sessionTurn.diffs.showAll": "Show all",
43+
"ui.sessionTurn.diffs.showLess": "Show less",
44+
"ui.sessionTurn.diffs.more": "+{{count}} more files",
4145

4246
"ui.sessionTurn.retry.retrying": "retrying",
4347
"ui.sessionTurn.retry.inSeconds": "in {{seconds}}s",

0 commit comments

Comments
 (0)