Skip to content

Commit cc34084

Browse files
authored
feat(desktop): prevent overlapping composer borders (#37490)
1 parent b8142c7 commit cc34084

7 files changed

Lines changed: 60 additions & 11 deletions

File tree

packages/app/src/components/prompt-input-v2.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
export type PromptInputV2ComposerProps = {
3737
class?: string
3838
controller: PromptInputV2ComposerController
39+
borderUnderlay?: boolean
3940
edit?: PromptInputProps["edit"]
4041
onEditLoaded?: PromptInputProps["onEditLoaded"]
4142
}
@@ -57,6 +58,7 @@ export function PromptInputV2Composer(props: PromptInputV2ComposerProps) {
5758
<div class="flex flex-col gap-3">
5859
<PromptInputV2
5960
controller={props.controller}
61+
borderUnderlay={props.borderUnderlay}
6062
class={props.class}
6163
modelControl={
6264
<PromptInputV2ModelControl

packages/app/src/components/prompt-input.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1460,10 +1460,10 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
14601460
t={(key) => language.t(key as Parameters<typeof language.t>[0])}
14611461
/>
14621462
<DockShellForm
1463+
data-dock-border-underlay="legacy"
14631464
onSubmit={handleSubmit}
14641465
classList={{
14651466
"group/prompt-input": true,
1466-
"focus-within:shadow-xs-border": true,
14671467
"border-icon-info-active border-dashed": store.draggingType !== null,
14681468
[props.class ?? ""]: !!props.class,
14691469
}}

packages/app/src/pages/session.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2265,6 +2265,7 @@ export default function Page() {
22652265
return (
22662266
<PromptInputV2Composer
22672267
controller={controller}
2268+
borderUnderlay
22682269
edit={editingFollowup()}
22692270
onEditLoaded={clearFollowupEdit}
22702271
/>

packages/app/src/pages/session/composer/session-revert-dock.stories.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { For } from "solid-js"
22
import { createStore } from "solid-js/store"
3+
import { DockShell } from "@opencode-ai/ui/dock-surface"
34
import { SessionRevertDock } from "@/pages/session/composer/session-revert-dock"
45
import { SettingsProvider, useSettings } from "@/context/settings"
56

@@ -78,12 +79,17 @@ function Stage(props: { count: number }) {
7879
{/* Reproduce the real composer stack: dock + card overlapping the dock's bottom by lift() = 18px */}
7980
<div style={{ display: "flex", "flex-direction": "column" }}>
8081
<SessionRevertDock items={store.items} onRestore={restore} />
81-
<div
82+
<DockShell
83+
data-dock-border-underlay={v2() ? "v2" : "legacy"}
8284
style={{ position: "relative", "z-index": 70, "margin-top": "-18px" }}
83-
class="min-h-24 w-full rounded-[12px] border border-v2-border-border-base bg-v2-background-bg-base px-4 py-3 text-[13px] text-v2-text-text-faint"
85+
classList={{
86+
"min-h-24 w-full rounded-[12px] px-4 py-3 text-[13px]": true,
87+
"bg-v2-background-bg-base text-v2-text-text-faint": v2(),
88+
"text-text-weak": !v2(),
89+
}}
8490
>
8591
Ask anything...
86-
</div>
92+
</DockShell>
8793
</div>
8894

8995
<div class="text-[12px] text-v2-text-text-faint">

packages/app/src/pages/session/composer/session-todo-dock.tsx

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import { TextReveal } from "@opencode-ai/ui/text-reveal"
88
import { TextStrikethrough } from "@opencode-ai/ui/text-strikethrough"
99
import { createResizeObserver } from "@solid-primitives/resize-observer"
1010
import { Index, createEffect, createMemo } from "solid-js"
11+
import { Dynamic } from "solid-js/web"
1112
import { createStore } from "solid-js/store"
1213
import { useLanguage } from "@/context/language"
14+
import { useSettings } from "@/context/settings"
1315

1416
const doneToken = "\u0000done\u0000"
1517
const totalToken = "\u0000total\u0000"
@@ -48,6 +50,7 @@ export function SessionTodoDock(props: {
4850
dockProgress: number
4951
}) {
5052
const language = useLanguage()
53+
const settings = useSettings()
5154
const [store, setStore] = createStore({
5255
height: 78,
5356
})
@@ -91,8 +94,13 @@ export function SessionTodoDock(props: {
9194
})
9295

9396
return (
94-
<DockTray
97+
<Dynamic
98+
component={settings.general.newLayoutDesigns() ? "div" : DockTray}
9599
data-component="session-todo-dock"
100+
classList={{
101+
"w-full overflow-hidden rounded-xl border-[0.5px] border-v2-border-border-base bg-v2-background-bg-layer-01":
102+
settings.general.newLayoutDesigns(),
103+
}}
96104
style={{
97105
"overflow-x": "visible",
98106
"overflow-y": "hidden",
@@ -102,7 +110,11 @@ export function SessionTodoDock(props: {
102110
<div ref={contentRef}>
103111
<div
104112
data-action="session-todo-toggle"
105-
class="pl-3 pr-2 py-2 flex items-center gap-2 overflow-visible"
113+
classList={{
114+
"flex items-center gap-2 overflow-visible": true,
115+
"h-[42px] pl-4 pr-2": settings.general.newLayoutDesigns(),
116+
"pl-3 pr-2 py-2": !settings.general.newLayoutDesigns(),
117+
}}
106118
role="button"
107119
tabIndex={0}
108120
onClick={props.onToggle}
@@ -113,7 +125,12 @@ export function SessionTodoDock(props: {
113125
}}
114126
>
115127
<span
116-
class="text-14-regular text-text-strong cursor-default inline-flex items-baseline shrink-0 overflow-visible"
128+
classList={{
129+
"cursor-default inline-flex items-baseline shrink-0 overflow-visible": true,
130+
"font-[440] text-[13px] leading-5 tracking-[-0.04px] text-v2-text-text-muted":
131+
settings.general.newLayoutDesigns(),
132+
"text-14-regular text-text-strong": !settings.general.newLayoutDesigns(),
133+
}}
117134
aria-label={label()}
118135
style={{
119136
"--tool-motion-odometer-ms": "600ms",
@@ -145,7 +162,11 @@ export function SessionTodoDock(props: {
145162
}}
146163
>
147164
<TextReveal
148-
class="text-14-regular text-text-base cursor-default"
165+
class={
166+
settings.general.newLayoutDesigns()
167+
? "cursor-default text-[13px] font-[440] leading-5 tracking-[-0.04px] text-v2-text-text-faint"
168+
: "text-14-regular text-text-base cursor-default"
169+
}
149170
text={props.collapsed ? preview() : undefined}
150171
duration={600}
151172
travel={25}
@@ -191,7 +212,7 @@ export function SessionTodoDock(props: {
191212
<TodoList todos={props.todos} />
192213
</div>
193214
</div>
194-
</DockTray>
215+
</Dynamic>
195216
)
196217
}
197218

packages/session-ui/src/v2/components/prompt-input/index.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export type PromptInputV2Props = {
3636
controller: PromptInputV2Interaction
3737
disabled?: boolean
3838
readOnly?: boolean
39+
borderUnderlay?: boolean
3940
class?: string
4041
modelControl?: JSX.Element
4142
}
@@ -102,8 +103,12 @@ export function PromptInputV2(props: PromptInputV2Props) {
102103
</Show>
103104
<form
104105
data-component="prompt-input-v2"
105-
class="group/prompt-input relative min-h-[96px] w-full rounded-xl bg-v2-background-bg-base shadow-[var(--v2-elevation-raised)]"
106-
classList={{ "border border-v2-icon-icon-info border-dashed": state.drag === "active" }}
106+
data-dock-border-underlay={props.borderUnderlay ? "v2" : undefined}
107+
class="group/prompt-input relative min-h-[96px] w-full rounded-xl bg-v2-background-bg-base"
108+
classList={{
109+
"shadow-[var(--v2-elevation-raised)]": !props.borderUnderlay,
110+
"border border-v2-icon-icon-info border-dashed": state.drag === "active",
111+
}}
107112
onSubmit={(event) => {
108113
event.preventDefault()
109114
if (!props.disabled) props.controller.submit()

packages/ui/src/components/dock-surface.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@
77
overflow: clip;
88
}
99

10+
[data-dock-border-underlay] {
11+
/* Later shadows paint underneath, so this solid ring masks overlapping surfaces without changing border geometry. */
12+
box-shadow:
13+
var(--dock-shell-visual-shadow, var(--shadow-xs-border)),
14+
0 0 0 var(--dock-shell-border-underlay-width, 1px)
15+
var(--dock-shell-border-underlay-background, var(--surface-raised-stronger-non-alpha));
16+
}
17+
18+
[data-dock-border-underlay="v2"] {
19+
--dock-shell-visual-shadow: var(--v2-elevation-raised);
20+
--dock-shell-border-underlay-width: 0.5px;
21+
--dock-shell-border-underlay-background: var(--v2-background-bg-base);
22+
}
23+
1024
[data-dock-surface="tray"] {
1125
background-color: var(--background-base);
1226
border: 1px solid var(--border-weak-base);

0 commit comments

Comments
 (0)