Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(app): refine new session workspace controls
  • Loading branch information
Brendonovich committed Jun 26, 2026
commit 8e48355f8fe27276ad051e9715f46b8a7b5e4a0d
8 changes: 6 additions & 2 deletions packages/app/src/components/prompt-project-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,10 @@ export function createPromptProjectController(input: {

export type PromptProjectController = ReturnType<typeof createPromptProjectController>

export function PromptProjectSelector(props: { controller: PromptProjectController }) {
export function PromptProjectSelector(props: {
controller: PromptProjectController
placement?: "bottom" | "bottom-start"
}) {
let contentRef: HTMLDivElement | undefined
let restoreTrigger = true

Expand Down Expand Up @@ -229,7 +232,7 @@ export function PromptProjectSelector(props: { controller: PromptProjectControll
return (
<DropdownMenu
open={props.controller.open()}
placement="bottom"
placement={props.placement ?? "bottom"}
gutter={4}
modal={false}
onOpenChange={(open) => props.controller.setOpen(open)}
Expand Down Expand Up @@ -380,6 +383,7 @@ function ProjectTrigger(props: ComponentProps<"button"> & { controller: PromptPr
...local.classList,
"hover:bg-v2-overlay-simple-overlay-hover": !local.controller.open(),
"bg-v2-overlay-simple-overlay-pressed": local.controller.open(),
"text-v2-text-text-muted": local.controller.open(),
}}
onClick={local.onClick ?? (() => local.controller.setOpen(true))}
onKeyDown={(event) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function PromptWorkspaceSelector(props: {
<>
<span class="hidden select-none opacity-50 sm:inline mx-1">/</span>
<MenuV2 placement="bottom" gutter={4} onOpenChange={onOpenChange}>
<MenuV2.Trigger class="flex h-7 min-w-0 max-w-[203px] items-center gap-1.5 rounded-sm px-1.5 hover:bg-v2-overlay-simple-overlay-hover focus-visible:bg-v2-overlay-simple-overlay-hover focus-visible:outline-none data-[expanded]:bg-v2-overlay-simple-overlay-pressed">
<MenuV2.Trigger class="flex h-7 min-w-0 max-w-[203px] items-center gap-1.5 rounded-sm px-1.5 hover:bg-v2-overlay-simple-overlay-hover focus-visible:bg-v2-overlay-simple-overlay-hover focus-visible:outline-none data-[expanded]:bg-v2-overlay-simple-overlay-pressed data-[expanded]:text-v2-text-text-muted">
<IconV2 name={icon()} class="shrink-0 text-v2-icon-icon-muted" />
<span class="min-w-0 truncate">{label()}</span>
<Icon name="chevron-down" size="small" class="shrink-0 text-v2-icon-icon-muted" />
Expand Down
47 changes: 30 additions & 17 deletions packages/app/src/pages/new-session.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { useComposerCommands } from "@/pages/session/use-composer-commands"
import { NEW_SESSION_CONTENT_WIDTH } from "@/pages/session/new-session-layout"
import { PromptWorkspaceSelector } from "@/components/prompt-workspace-selector"

const showWorkspaceBar = import.meta.env.VITE_OPENCODE_CHANNEL !== "prod"

/**
* The `/new-session` draft page. Unlike `session.tsx`, this only renders the prompt
* composer for a brand-new session — no terminal, review pane, file tree, or message
Expand Down Expand Up @@ -103,7 +105,7 @@ export default function NewSessionPage() {
</div>
}
>
<div class="flex flex-col gap-8">
<div class="flex flex-col" classList={{ "gap-8": showWorkspaceBar, "gap-3": !showWorkspaceBar }}>
<PromptInput
controls={inputController()}
variant="new-session"
Expand All @@ -120,23 +122,34 @@ export default function NewSessionPage() {
}
/>
<Show when={projectController.selected()}>
<div class="flex min-h-7 min-w-0 flex-col items-center justify-center gap-0 px-2 text-v2-text-text-faint sm:flex-row">
<PromptProjectSelector controller={projectController} />
<PromptWorkspaceSelector
value={newSessionWorktree()}
projectRoot={projectRoot()}
workspaces={sync().project?.sandboxes ?? []}
branch={selectedBranch()}
onChange={(value) =>
setStore(
"worktree",
value === "main" && sync().project?.worktree !== sdk().directory
? sync().project?.worktree
: value,
)
}
onDone={() => inputRef?.focus()}
<div
class="flex min-h-7 min-w-0 items-center gap-0 text-v2-text-text-faint"
classList={{
"flex-col justify-center sm:flex-row": showWorkspaceBar,
"justify-start": !showWorkspaceBar,
}}
>
<PromptProjectSelector
controller={projectController}
placement={showWorkspaceBar ? "bottom" : "bottom-start"}
/>
<Show when={showWorkspaceBar}>
<PromptWorkspaceSelector
value={newSessionWorktree()}
projectRoot={projectRoot()}
workspaces={sync().project?.sandboxes ?? []}
branch={selectedBranch()}
onChange={(value) =>
setStore(
"worktree",
value === "main" && sync().project?.worktree !== sdk().directory
? sync().project?.worktree
: value,
)
}
onDone={() => inputRef?.focus()}
/>
</Show>
</div>
</Show>
</div>
Expand Down