summaryrefslogtreecommitdiffhomepage
path: root/packages/ui/src
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-12-12 14:44:04 -0600
committerAdam <[email protected]>2025-12-12 15:24:42 -0600
commitccdd77032aedf9ce9fdf48ad74e79a9e308a370c (patch)
treede4c1ec1f531476c1719c037b75b24928cfeb3e7 /packages/ui/src
parent41e234c6d0f7f0e8cfb137ef1a4d9c9c9eea7d06 (diff)
downloadopencode-ccdd77032aedf9ce9fdf48ad74e79a9e308a370c.tar.gz
opencode-ccdd77032aedf9ce9fdf48ad74e79a9e308a370c.zip
fix: desktop layout
Diffstat (limited to 'packages/ui/src')
-rw-r--r--packages/ui/src/components/session-turn.css24
-rw-r--r--packages/ui/src/components/session-turn.tsx121
2 files changed, 79 insertions, 66 deletions
diff --git a/packages/ui/src/components/session-turn.css b/packages/ui/src/components/session-turn.css
index 2203b6033..6bead9b57 100644
--- a/packages/ui/src/components/session-turn.css
+++ b/packages/ui/src/components/session-turn.css
@@ -29,20 +29,32 @@
gap: 32px;
}
+ [data-slot="session-turn-sticky-header"] {
+ position: sticky;
+ top: 0;
+ background-color: var(--background-stronger);
+ z-index: 20;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ padding-bottom: 8px;
+ }
+
[data-slot="session-turn-message-header"] {
display: flex;
align-items: center;
gap: 8px;
align-self: stretch;
- position: sticky;
- top: 0;
- background-color: var(--background-stronger);
- z-index: 20;
height: 32px;
}
- [data-slot="session-turn-message-content"] {
- margin-top: -24px;
+ /* [data-slot="session-turn-message-content"] { */
+ /* } */
+
+ [data-slot="session-turn-response-trigger"] {
+ width: calc(100% + 9px);
+ margin-left: -9px;
+ padding-left: 9px;
}
[data-slot="session-turn-message-title"] {
diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx
index f57a0509b..c09754a59 100644
--- a/packages/ui/src/components/session-turn.tsx
+++ b/packages/ui/src/components/session-turn.tsx
@@ -73,6 +73,12 @@ export function SessionTurn(
}
}
+ function handleInteraction() {
+ if (working()) {
+ setUserScrolled(true)
+ }
+ }
+
createEffect(() => {
if (!working()) {
setUserScrolled(false)
@@ -90,7 +96,7 @@ export function SessionTurn(
return (
<div data-component="session-turn" class={props.classes?.root}>
<div ref={scrollRef} onScroll={handleScroll} data-slot="session-turn-content" class={props.classes?.content}>
- <div ref={contentRef}>
+ <div ref={contentRef} onClick={handleInteraction}>
<Show when={message()}>
{(message) => {
const assistantMessages = createMemo(() => {
@@ -233,35 +239,29 @@ export function SessionTurn(
data-slot="session-turn-message-container"
class={props.classes?.container}
>
- {/* Title */}
- <div data-slot="session-turn-message-header">
- <div data-slot="session-turn-message-title">
- <Switch>
- <Match when={working()}>
- <Typewriter as="h1" text={message().summary?.title} data-slot="session-turn-typewriter" />
- </Match>
- <Match when={true}>
- <h1>{message().summary?.title}</h1>
- </Match>
- </Switch>
+ {/* Sticky Header */}
+ <div data-slot="session-turn-sticky-header">
+ <div data-slot="session-turn-message-header">
+ <div data-slot="session-turn-message-title">
+ <Switch>
+ <Match when={working()}>
+ <Typewriter as="h1" text={message().summary?.title} data-slot="session-turn-typewriter" />
+ </Match>
+ <Match when={true}>
+ <h1>{message().summary?.title}</h1>
+ </Match>
+ </Switch>
+ </div>
</div>
- </div>
- <div data-slot="session-turn-message-content">
- <Message message={message()} parts={parts()} />
- </div>
- {/* Response */}
- <div data-slot="session-turn-response-section">
- <Collapsible
- variant="ghost"
- open={store.detailsExpanded}
- onOpenChange={(open) => setStore("detailsExpanded", open)}
- data-slot="session-turn-collapsible"
- >
- <Collapsible.Trigger
- as={Button}
+ <div data-slot="session-turn-message-content">
+ <Message message={message()} parts={parts()} />
+ </div>
+ <div data-slot="session-turn-response-trigger">
+ <Button
data-slot="session-turn-collapsible-trigger-content"
variant="ghost"
size="small"
+ onClick={() => setStore("detailsExpanded", !store.detailsExpanded)}
>
<Show when={working()}>
<Spinner />
@@ -274,41 +274,42 @@ export function SessionTurn(
<span>ยท</span>
<span>{store.duration}</span>
<Icon name="chevron-grabber-vertical" size="small" />
- </Collapsible.Trigger>
- <Collapsible.Content>
- <div data-slot="session-turn-collapsible-content-inner">
- <For each={assistantMessages()}>
- {(assistantMessage) => {
- const parts = createMemo(() => data.store.part[assistantMessage.id] ?? [])
- const last = createMemo(() =>
- parts()
- .filter((p) => p?.type === "text")
- .at(-1),
- )
- return (
- <Switch>
- <Match when={lastTextPartShown() && lastTextPart()?.id === last()?.id}>
- <Message
- message={assistantMessage}
- parts={parts().filter((p) => p?.id !== last()?.id)}
- />
- </Match>
- <Match when={true}>
- <Message message={assistantMessage} parts={parts()} />
- </Match>
- </Switch>
- )
- }}
- </For>
- <Show when={error()}>
- <Card variant="error" class="error-card">
- {error()?.data?.message as string}
- </Card>
- </Show>
- </div>
- </Collapsible.Content>
- </Collapsible>
+ </Button>
+ </div>
</div>
+ {/* Response */}
+ <Show when={store.detailsExpanded}>
+ <div data-slot="session-turn-collapsible-content-inner">
+ <For each={assistantMessages()}>
+ {(assistantMessage) => {
+ const parts = createMemo(() => data.store.part[assistantMessage.id] ?? [])
+ const last = createMemo(() =>
+ parts()
+ .filter((p) => p?.type === "text")
+ .at(-1),
+ )
+ return (
+ <Switch>
+ <Match when={lastTextPartShown() && lastTextPart()?.id === last()?.id}>
+ <Message
+ message={assistantMessage}
+ parts={parts().filter((p) => p?.id !== last()?.id)}
+ />
+ </Match>
+ <Match when={true}>
+ <Message message={assistantMessage} parts={parts()} />
+ </Match>
+ </Switch>
+ )
+ }}
+ </For>
+ <Show when={error()}>
+ <Card variant="error" class="error-card">
+ {error()?.data?.message as string}
+ </Card>
+ </Show>
+ </div>
+ </Show>
{/* Summary */}
<Show when={!working()}>
<div data-slot="session-turn-summary-section">