fix(multirun): adjust layout for multirun launcher view
This commit is contained in:
@@ -22,6 +22,7 @@ import { useConfigStore } from '@/stores/useConfigStore';
|
|||||||
import { useDirectoryStore } from '@/stores/useDirectoryStore';
|
import { useDirectoryStore } from '@/stores/useDirectoryStore';
|
||||||
import { useMultiRunStore } from '@/stores/useMultiRunStore';
|
import { useMultiRunStore } from '@/stores/useMultiRunStore';
|
||||||
import { useSessionStore } from '@/stores/useSessionStore';
|
import { useSessionStore } from '@/stores/useSessionStore';
|
||||||
|
import { useUIStore } from '@/stores/useUIStore';
|
||||||
import type { CreateMultiRunParams, MultiRunModelSelection } from '@/types/multirun';
|
import type { CreateMultiRunParams, MultiRunModelSelection } from '@/types/multirun';
|
||||||
|
|
||||||
interface MultiRunLauncherProps {
|
interface MultiRunLauncherProps {
|
||||||
@@ -248,6 +249,36 @@ export const MultiRunLauncher: React.FC<MultiRunLauncherProps> = ({
|
|||||||
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
||||||
|
|
||||||
const currentDirectory = useDirectoryStore((state) => state.currentDirectory ?? null);
|
const currentDirectory = useDirectoryStore((state) => state.currentDirectory ?? null);
|
||||||
|
const isSidebarOpen = useUIStore((state) => state.isSidebarOpen);
|
||||||
|
|
||||||
|
const [isDesktopApp, setIsDesktopApp] = React.useState<boolean>(() => {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return typeof (window as typeof window & { opencodeDesktop?: unknown }).opencodeDesktop !== 'undefined';
|
||||||
|
});
|
||||||
|
|
||||||
|
const isMacPlatform = React.useMemo(() => {
|
||||||
|
if (typeof navigator === 'undefined') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return /Macintosh|Mac OS X/.test(navigator.userAgent || '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const detected = typeof (window as typeof window & { opencodeDesktop?: unknown }).opencodeDesktop !== 'undefined';
|
||||||
|
setIsDesktopApp(detected);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const desktopHeaderPaddingClass = React.useMemo(() => {
|
||||||
|
if (isDesktopApp && isMacPlatform) {
|
||||||
|
return isSidebarOpen ? 'pl-0' : 'pl-[8.0rem]';
|
||||||
|
}
|
||||||
|
return 'pl-3';
|
||||||
|
}, [isDesktopApp, isMacPlatform, isSidebarOpen]);
|
||||||
|
|
||||||
const [worktreeBaseBranch, setWorktreeBaseBranch] = React.useState<string>('HEAD');
|
const [worktreeBaseBranch, setWorktreeBaseBranch] = React.useState<string>('HEAD');
|
||||||
const [availableWorktreeBaseBranches, setAvailableWorktreeBaseBranches] = React.useState<WorktreeBaseOption[]>([
|
const [availableWorktreeBaseBranches, setAvailableWorktreeBaseBranches] = React.useState<WorktreeBaseOption[]>([
|
||||||
@@ -392,10 +423,18 @@ export const MultiRunLauncher: React.FC<MultiRunLauncherProps> = ({
|
|||||||
<div className="flex flex-col h-full bg-background">
|
<div className="flex flex-col h-full bg-background">
|
||||||
{/* Header - same height as app header (h-12 = 48px) */}
|
{/* Header - same height as app header (h-12 = 48px) */}
|
||||||
<header
|
<header
|
||||||
className="flex h-12 items-center justify-between border-b app-region-drag"
|
className={cn(
|
||||||
|
'flex h-12 items-center justify-between border-b app-region-drag',
|
||||||
|
desktopHeaderPaddingClass
|
||||||
|
)}
|
||||||
style={{ borderColor: 'var(--interactive-border)' }}
|
style={{ borderColor: 'var(--interactive-border)' }}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3 pl-4">
|
<div
|
||||||
|
className={cn(
|
||||||
|
'flex items-center gap-3',
|
||||||
|
isDesktopApp && isMacPlatform && isSidebarOpen && 'pl-4'
|
||||||
|
)}
|
||||||
|
>
|
||||||
<h1 className="typography-ui-label font-medium">New Multi-Run</h1>
|
<h1 className="typography-ui-label font-medium">New Multi-Run</h1>
|
||||||
</div>
|
</div>
|
||||||
{onCancel && (
|
{onCancel && (
|
||||||
@@ -433,7 +472,7 @@ export const MultiRunLauncher: React.FC<MultiRunLauncherProps> = ({
|
|||||||
value={name}
|
value={name}
|
||||||
onChange={(e) => setName(e.target.value)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
placeholder="e.g. feature-auth, bugfix-login"
|
placeholder="e.g. feature-auth, bugfix-login"
|
||||||
className="typography-body"
|
className="typography-body max-w-full sm:max-w-xs"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<p className="typography-micro text-muted-foreground">
|
<p className="typography-micro text-muted-foreground">
|
||||||
@@ -465,19 +504,19 @@ export const MultiRunLauncher: React.FC<MultiRunLauncherProps> = ({
|
|||||||
<SelectTrigger
|
<SelectTrigger
|
||||||
id="multirun-worktree-base-branch"
|
id="multirun-worktree-base-branch"
|
||||||
size="lg"
|
size="lg"
|
||||||
className="w-full typography-meta text-foreground"
|
className="max-w-full typography-meta text-foreground"
|
||||||
>
|
>
|
||||||
<SelectValue
|
<SelectValue
|
||||||
placeholder={isLoadingWorktreeBaseBranches ? 'Loading branches…' : 'Select a branch'}
|
placeholder={isLoadingWorktreeBaseBranches ? 'Loading branches…' : 'Select a branch'}
|
||||||
/>
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent fitContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectLabel>Default</SelectLabel>
|
<SelectLabel>Default</SelectLabel>
|
||||||
{availableWorktreeBaseBranches
|
{availableWorktreeBaseBranches
|
||||||
.filter((option) => option.group === 'special')
|
.filter((option) => option.group === 'special')
|
||||||
.map((option) => (
|
.map((option) => (
|
||||||
<SelectItem key={option.value} value={option.value}>
|
<SelectItem key={option.value} value={option.value} className="w-auto whitespace-nowrap">
|
||||||
{option.label}
|
{option.label}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
@@ -491,7 +530,7 @@ export const MultiRunLauncher: React.FC<MultiRunLauncherProps> = ({
|
|||||||
{availableWorktreeBaseBranches
|
{availableWorktreeBaseBranches
|
||||||
.filter((option) => option.group === 'local')
|
.filter((option) => option.group === 'local')
|
||||||
.map((option) => (
|
.map((option) => (
|
||||||
<SelectItem key={option.value} value={option.value}>
|
<SelectItem key={option.value} value={option.value} className="w-auto whitespace-nowrap">
|
||||||
{option.label}
|
{option.label}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
@@ -507,7 +546,7 @@ export const MultiRunLauncher: React.FC<MultiRunLauncherProps> = ({
|
|||||||
{availableWorktreeBaseBranches
|
{availableWorktreeBaseBranches
|
||||||
.filter((option) => option.group === 'remote')
|
.filter((option) => option.group === 'remote')
|
||||||
.map((option) => (
|
.map((option) => (
|
||||||
<SelectItem key={option.value} value={option.value}>
|
<SelectItem key={option.value} value={option.value} className="w-auto whitespace-nowrap">
|
||||||
{option.label}
|
{option.label}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -55,8 +55,11 @@ function SelectContent({
|
|||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
position = "popper",
|
position = "popper",
|
||||||
|
fitContent = false,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
}: React.ComponentProps<typeof SelectPrimitive.Content> & {
|
||||||
|
fitContent?: boolean;
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<SelectPrimitive.Portal>
|
<SelectPrimitive.Portal>
|
||||||
<SelectPrimitive.Content
|
<SelectPrimitive.Content
|
||||||
@@ -65,6 +68,7 @@ function SelectContent({
|
|||||||
"bg-background text-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden rounded-xl border shadow-none transform-gpu will-change-transform",
|
"bg-background text-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden rounded-xl border shadow-none transform-gpu will-change-transform",
|
||||||
position === "popper" &&
|
position === "popper" &&
|
||||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||||
|
fitContent && "w-max min-w-0",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
position={position}
|
position={position}
|
||||||
@@ -72,11 +76,16 @@ function SelectContent({
|
|||||||
>
|
>
|
||||||
<ScrollableOverlay
|
<ScrollableOverlay
|
||||||
as={SelectPrimitive.Viewport}
|
as={SelectPrimitive.Viewport}
|
||||||
outerClassName="max-h-[var(--radix-select-content-available-height)] w-full"
|
outerClassName={cn(
|
||||||
|
"max-h-[var(--radix-select-content-available-height)]",
|
||||||
|
fitContent ? "w-max" : "w-full"
|
||||||
|
)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"p-1",
|
"p-1",
|
||||||
position === "popper" &&
|
position === "popper" &&
|
||||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
(fitContent
|
||||||
|
? "h-[var(--radix-select-trigger-height)] w-max min-w-0 scroll-my-1"
|
||||||
|
: "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1")
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
Reference in New Issue
Block a user