fix(ui): refine instance drawer layout and controls
This commit is contained in:
@@ -20,7 +20,6 @@ import IconButton from "@suid/material/IconButton"
|
|||||||
import Toolbar from "@suid/material/Toolbar"
|
import Toolbar from "@suid/material/Toolbar"
|
||||||
import Typography from "@suid/material/Typography"
|
import Typography from "@suid/material/Typography"
|
||||||
import useMediaQuery from "@suid/material/useMediaQuery"
|
import useMediaQuery from "@suid/material/useMediaQuery"
|
||||||
import CloseIcon from "@suid/icons-material/Close"
|
|
||||||
import MenuIcon from "@suid/icons-material/Menu"
|
import MenuIcon from "@suid/icons-material/Menu"
|
||||||
import MenuOpenIcon from "@suid/icons-material/MenuOpen"
|
import MenuOpenIcon from "@suid/icons-material/MenuOpen"
|
||||||
import PushPinIcon from "@suid/icons-material/PushPin"
|
import PushPinIcon from "@suid/icons-material/PushPin"
|
||||||
@@ -94,7 +93,6 @@ const RIGHT_DRAWER_WIDTH = 260
|
|||||||
const MIN_RIGHT_DRAWER_WIDTH = 200
|
const MIN_RIGHT_DRAWER_WIDTH = 200
|
||||||
const MAX_RIGHT_DRAWER_WIDTH = 380
|
const MAX_RIGHT_DRAWER_WIDTH = 380
|
||||||
const SESSION_CACHE_LIMIT = 5
|
const SESSION_CACHE_LIMIT = 5
|
||||||
const APP_BAR_HEIGHT = 56
|
|
||||||
const LEFT_DRAWER_STORAGE_KEY = "opencode-session-sidebar-width-v8"
|
const LEFT_DRAWER_STORAGE_KEY = "opencode-session-sidebar-width-v8"
|
||||||
const RIGHT_DRAWER_STORAGE_KEY = "opencode-session-right-drawer-width-v1"
|
const RIGHT_DRAWER_STORAGE_KEY = "opencode-session-right-drawer-width-v1"
|
||||||
const LEFT_PIN_STORAGE_KEY = "opencode-session-left-drawer-pinned-v1"
|
const LEFT_PIN_STORAGE_KEY = "opencode-session-left-drawer-pinned-v1"
|
||||||
@@ -214,10 +212,8 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
const host = drawerHost()
|
const host = drawerHost()
|
||||||
if (!host) return
|
if (!host) return
|
||||||
const rect = host.getBoundingClientRect()
|
const rect = host.getBoundingClientRect()
|
||||||
const toolbar = host.querySelector<HTMLElement>(".session-toolbar")
|
setFloatingDrawerTop(rect.top)
|
||||||
const toolbarHeight = toolbar?.offsetHeight ?? APP_BAR_HEIGHT
|
setFloatingDrawerHeight(Math.max(0, rect.height))
|
||||||
setFloatingDrawerTop(rect.top + toolbarHeight)
|
|
||||||
setFloatingDrawerHeight(Math.max(0, rect.height - toolbarHeight))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@@ -617,7 +613,7 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const fallbackDrawerTop = () => APP_BAR_HEIGHT + props.tabBarOffset
|
const fallbackDrawerTop = () => props.tabBarOffset
|
||||||
const floatingTop = () => {
|
const floatingTop = () => {
|
||||||
const measured = floatingDrawerTop()
|
const measured = floatingDrawerTop()
|
||||||
if (measured > 0) return measured
|
if (measured > 0) return measured
|
||||||
@@ -727,27 +723,21 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
const leftAppBarButtonLabel = () => {
|
const leftAppBarButtonLabel = () => {
|
||||||
const state = leftDrawerState()
|
const state = leftDrawerState()
|
||||||
if (state === "pinned") return t("instanceShell.leftDrawer.toggle.pinned")
|
if (state === "pinned") return t("instanceShell.leftDrawer.toggle.pinned")
|
||||||
if (state === "floating-closed") return t("instanceShell.leftDrawer.toggle.open")
|
return t("instanceShell.leftDrawer.toggle.open")
|
||||||
return t("instanceShell.leftDrawer.toggle.close")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const rightAppBarButtonLabel = () => {
|
const rightAppBarButtonLabel = () => {
|
||||||
const state = rightDrawerState()
|
const state = rightDrawerState()
|
||||||
if (state === "pinned") return t("instanceShell.rightDrawer.toggle.pinned")
|
if (state === "pinned") return t("instanceShell.rightDrawer.toggle.pinned")
|
||||||
if (state === "floating-closed") return t("instanceShell.rightDrawer.toggle.open")
|
return t("instanceShell.rightDrawer.toggle.open")
|
||||||
return t("instanceShell.rightDrawer.toggle.close")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const leftAppBarButtonIcon = () => {
|
const leftAppBarButtonIcon = () => {
|
||||||
const state = leftDrawerState()
|
return <MenuIcon fontSize="small" />
|
||||||
if (state === "floating-closed") return <MenuIcon fontSize="small" />
|
|
||||||
return <MenuOpenIcon fontSize="small" />
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const rightAppBarButtonIcon = () => {
|
const rightAppBarButtonIcon = () => {
|
||||||
const state = rightDrawerState()
|
return <MenuIcon fontSize="small" sx={{ transform: "scaleX(-1)" }} />
|
||||||
if (state === "floating-closed") return <MenuIcon fontSize="small" sx={{ transform: "scaleX(-1)" }} />
|
|
||||||
return <MenuOpenIcon fontSize="small" sx={{ transform: "scaleX(-1)" }} />
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -795,29 +785,15 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
|
|
||||||
const handleLeftAppBarButtonClick = () => {
|
const handleLeftAppBarButtonClick = () => {
|
||||||
const state = leftDrawerState()
|
const state = leftDrawerState()
|
||||||
if (state === "pinned") return
|
if (state !== "floating-closed") return
|
||||||
if (state === "floating-closed") {
|
setLeftOpen(true)
|
||||||
setLeftOpen(true)
|
|
||||||
measureDrawerHost()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
blurIfInside(leftDrawerContentEl())
|
|
||||||
setLeftOpen(false)
|
|
||||||
focusTarget(leftToggleButtonEl())
|
|
||||||
measureDrawerHost()
|
measureDrawerHost()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRightAppBarButtonClick = () => {
|
const handleRightAppBarButtonClick = () => {
|
||||||
const state = rightDrawerState()
|
const state = rightDrawerState()
|
||||||
if (state === "pinned") return
|
if (state !== "floating-closed") return
|
||||||
if (state === "floating-closed") {
|
setRightOpen(true)
|
||||||
setRightOpen(true)
|
|
||||||
measureDrawerHost()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
blurIfInside(rightDrawerContentEl())
|
|
||||||
setRightOpen(false)
|
|
||||||
focusTarget(rightToggleButtonEl())
|
|
||||||
measureDrawerHost()
|
measureDrawerHost()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -894,6 +870,17 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
{leftPinned() ? <PushPinIcon fontSize="small" /> : <PushPinOutlinedIcon fontSize="small" />}
|
{leftPinned() ? <PushPinIcon fontSize="small" /> : <PushPinOutlinedIcon fontSize="small" />}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Show>
|
</Show>
|
||||||
|
<Show when={leftDrawerState() === "floating-open"}>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
color="inherit"
|
||||||
|
aria-label={t("instanceShell.leftDrawer.toggle.close")}
|
||||||
|
title={t("instanceShell.leftDrawer.toggle.close")}
|
||||||
|
onClick={closeLeftDrawer}
|
||||||
|
>
|
||||||
|
<MenuOpenIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -1087,11 +1074,19 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="flex flex-col h-full" ref={setRightDrawerContentEl}>
|
<div class="flex flex-col h-full" ref={setRightDrawerContentEl}>
|
||||||
<div class="flex items-center justify-between px-4 py-2 border-b border-base text-primary">
|
<div class="relative flex items-center px-4 py-2 border-b border-base text-primary">
|
||||||
<Typography variant="subtitle2" class="uppercase tracking-wide text-xs font-semibold text-primary">
|
|
||||||
{t("instanceShell.rightPanel.title")}
|
|
||||||
</Typography>
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
|
<Show when={rightDrawerState() === "floating-open"}>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
color="inherit"
|
||||||
|
aria-label={t("instanceShell.rightDrawer.toggle.close")}
|
||||||
|
title={t("instanceShell.rightDrawer.toggle.close")}
|
||||||
|
onClick={closeRightDrawer}
|
||||||
|
>
|
||||||
|
<MenuOpenIcon fontSize="small" sx={{ transform: "scaleX(-1)" }} />
|
||||||
|
</IconButton>
|
||||||
|
</Show>
|
||||||
<Show when={!isPhoneLayout()}>
|
<Show when={!isPhoneLayout()}>
|
||||||
<IconButton
|
<IconButton
|
||||||
size="small"
|
size="small"
|
||||||
@@ -1103,6 +1098,11 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="pointer-events-none absolute inset-0 flex items-center justify-center">
|
||||||
|
<Typography variant="subtitle2" class="uppercase tracking-wide text-xs font-semibold text-primary">
|
||||||
|
{t("instanceShell.rightPanel.title")}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1 overflow-y-auto">
|
<div class="flex-1 overflow-y-auto">
|
||||||
<Accordion.Root
|
<Accordion.Root
|
||||||
@@ -1263,19 +1263,93 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
|
|
||||||
const sessionLayout = (
|
const sessionLayout = (
|
||||||
<div
|
<div
|
||||||
class="session-shell-panels flex flex-col flex-1 min-h-0 overflow-x-hidden"
|
class="session-shell-panels flex flex-1 min-h-0 overflow-x-hidden"
|
||||||
ref={(element) => {
|
ref={(element) => {
|
||||||
setDrawerHost(element)
|
setDrawerHost(element)
|
||||||
measureDrawerHost()
|
measureDrawerHost()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AppBar position="sticky" color="default" elevation={0} class="border-b border-base">
|
{renderLeftPanel()}
|
||||||
<Toolbar variant="dense" class="session-toolbar flex flex-wrap items-center gap-2 py-0 min-h-[40px]">
|
|
||||||
<Show
|
<Box sx={{ display: "flex", flexDirection: "column", flex: 1, minWidth: 0, minHeight: 0, overflowX: "hidden" }}>
|
||||||
when={!isPhoneLayout()}
|
<AppBar position="sticky" color="default" elevation={0} class="border-b border-base">
|
||||||
fallback={
|
<Toolbar variant="dense" class="session-toolbar flex flex-wrap items-center gap-2 py-0 min-h-[40px]">
|
||||||
<div class="flex flex-col w-full gap-1.5">
|
<Show
|
||||||
<div class="flex flex-wrap items-center justify-between gap-2 w-full">
|
when={!isPhoneLayout()}
|
||||||
|
fallback={
|
||||||
|
<div class="flex flex-col w-full gap-1.5">
|
||||||
|
<div class="flex flex-wrap items-center justify-between gap-2 w-full">
|
||||||
|
<Show when={leftDrawerState() === "floating-closed"}>
|
||||||
|
<IconButton
|
||||||
|
ref={setLeftToggleButtonEl}
|
||||||
|
color="inherit"
|
||||||
|
onClick={handleLeftAppBarButtonClick}
|
||||||
|
aria-label={leftAppBarButtonLabel()}
|
||||||
|
size="small"
|
||||||
|
aria-expanded={leftDrawerState() !== "floating-closed"}
|
||||||
|
>
|
||||||
|
{leftAppBarButtonIcon()}
|
||||||
|
</IconButton>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap items-center gap-1 justify-center">
|
||||||
|
<PermissionNotificationBanner
|
||||||
|
instanceId={props.instance.id}
|
||||||
|
onClick={() => setPermissionModalOpen(true)}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="connection-status-button px-2 py-0.5 text-xs"
|
||||||
|
onClick={handleCommandPaletteClick}
|
||||||
|
aria-label={t("instanceShell.commandPalette.openAriaLabel")}
|
||||||
|
style={{ flex: "0 0 auto", width: "auto" }}
|
||||||
|
>
|
||||||
|
{t("instanceShell.commandPalette.button")}
|
||||||
|
</button>
|
||||||
|
<span class="connection-status-shortcut-hint">
|
||||||
|
<Kbd shortcut="cmd+shift+p" />
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class={`status-indicator ${connectionStatusClass()}`}
|
||||||
|
aria-label={t("instanceShell.connection.ariaLabel", { status: connectionStatusLabel() })}
|
||||||
|
>
|
||||||
|
<span class="status-dot" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Show when={rightDrawerState() === "floating-closed"}>
|
||||||
|
<IconButton
|
||||||
|
ref={setRightToggleButtonEl}
|
||||||
|
color="inherit"
|
||||||
|
onClick={handleRightAppBarButtonClick}
|
||||||
|
aria-label={rightAppBarButtonLabel()}
|
||||||
|
size="small"
|
||||||
|
aria-expanded={rightDrawerState() !== "floating-closed"}
|
||||||
|
>
|
||||||
|
{rightAppBarButtonIcon()}
|
||||||
|
</IconButton>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap items-center justify-center gap-2 pb-1">
|
||||||
|
<div class="inline-flex items-center gap-1 rounded-full border border-base px-2 py-0.5 text-xs text-primary">
|
||||||
|
<span class="uppercase text-[10px] tracking-wide text-muted">
|
||||||
|
{t("instanceShell.metrics.usedLabel")}
|
||||||
|
</span>
|
||||||
|
<span class="font-semibold text-primary">{formattedUsedTokens()}</span>
|
||||||
|
</div>
|
||||||
|
<div class="inline-flex items-center gap-1 rounded-full border border-base px-2 py-0.5 text-xs text-primary">
|
||||||
|
<span class="uppercase text-[10px] tracking-wide text-muted">
|
||||||
|
{t("instanceShell.metrics.availableLabel")}
|
||||||
|
</span>
|
||||||
|
<span class="font-semibold text-primary">{formattedAvailableTokens()}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div class="session-toolbar-left flex items-center gap-3 min-w-0">
|
||||||
|
<Show when={leftDrawerState() === "floating-closed"}>
|
||||||
<IconButton
|
<IconButton
|
||||||
ref={setLeftToggleButtonEl}
|
ref={setLeftToggleButtonEl}
|
||||||
color="inherit"
|
color="inherit"
|
||||||
@@ -1283,52 +1357,12 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
aria-label={leftAppBarButtonLabel()}
|
aria-label={leftAppBarButtonLabel()}
|
||||||
size="small"
|
size="small"
|
||||||
aria-expanded={leftDrawerState() !== "floating-closed"}
|
aria-expanded={leftDrawerState() !== "floating-closed"}
|
||||||
disabled={leftDrawerState() === "pinned"}
|
|
||||||
>
|
>
|
||||||
{leftAppBarButtonIcon()}
|
{leftAppBarButtonIcon()}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
</Show>
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center gap-1 justify-center">
|
<Show when={!showingInfoView()}>
|
||||||
<PermissionNotificationBanner
|
|
||||||
instanceId={props.instance.id}
|
|
||||||
onClick={() => setPermissionModalOpen(true)}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="connection-status-button px-2 py-0.5 text-xs"
|
|
||||||
onClick={handleCommandPaletteClick}
|
|
||||||
aria-label={t("instanceShell.commandPalette.openAriaLabel")}
|
|
||||||
style={{ flex: "0 0 auto", width: "auto" }}
|
|
||||||
>
|
|
||||||
{t("instanceShell.commandPalette.button")}
|
|
||||||
</button>
|
|
||||||
<span class="connection-status-shortcut-hint">
|
|
||||||
<Kbd shortcut="cmd+shift+p" />
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
class={`status-indicator ${connectionStatusClass()}`}
|
|
||||||
aria-label={t("instanceShell.connection.ariaLabel", { status: connectionStatusLabel() })}
|
|
||||||
>
|
|
||||||
<span class="status-dot" />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<IconButton
|
|
||||||
ref={setRightToggleButtonEl}
|
|
||||||
color="inherit"
|
|
||||||
onClick={handleRightAppBarButtonClick}
|
|
||||||
aria-label={rightAppBarButtonLabel()}
|
|
||||||
size="small"
|
|
||||||
aria-expanded={rightDrawerState() !== "floating-closed"}
|
|
||||||
disabled={rightDrawerState() === "pinned"}
|
|
||||||
>
|
|
||||||
{rightAppBarButtonIcon()}
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center justify-center gap-2 pb-1">
|
|
||||||
<div class="inline-flex items-center gap-1 rounded-full border border-base px-2 py-0.5 text-xs text-primary">
|
<div class="inline-flex items-center gap-1 rounded-full border border-base px-2 py-0.5 text-xs text-primary">
|
||||||
<span class="uppercase text-[10px] tracking-wide text-muted">
|
<span class="uppercase text-[10px] tracking-wide text-muted">
|
||||||
{t("instanceShell.metrics.usedLabel")}
|
{t("instanceShell.metrics.usedLabel")}
|
||||||
@@ -1341,101 +1375,65 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
</span>
|
</span>
|
||||||
<span class="font-semibold text-primary">{formattedAvailableTokens()}</span>
|
<span class="font-semibold text-primary">{formattedAvailableTokens()}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div class="session-toolbar-left flex items-center gap-3 min-w-0">
|
|
||||||
<IconButton
|
|
||||||
ref={setLeftToggleButtonEl}
|
|
||||||
color="inherit"
|
|
||||||
onClick={handleLeftAppBarButtonClick}
|
|
||||||
aria-label={leftAppBarButtonLabel()}
|
|
||||||
size="small"
|
|
||||||
aria-expanded={leftDrawerState() !== "floating-closed"}
|
|
||||||
disabled={leftDrawerState() === "pinned"}
|
|
||||||
>
|
|
||||||
{leftAppBarButtonIcon()}
|
|
||||||
</IconButton>
|
|
||||||
|
|
||||||
<Show when={!showingInfoView()}>
|
|
||||||
<div class="inline-flex items-center gap-1 rounded-full border border-base px-2 py-0.5 text-xs text-primary">
|
|
||||||
<span class="uppercase text-[10px] tracking-wide text-muted">
|
|
||||||
{t("instanceShell.metrics.usedLabel")}
|
|
||||||
</span>
|
|
||||||
<span class="font-semibold text-primary">{formattedUsedTokens()}</span>
|
|
||||||
</div>
|
|
||||||
<div class="inline-flex items-center gap-1 rounded-full border border-base px-2 py-0.5 text-xs text-primary">
|
|
||||||
<span class="uppercase text-[10px] tracking-wide text-muted">
|
|
||||||
{t("instanceShell.metrics.availableLabel")}
|
|
||||||
</span>
|
|
||||||
<span class="font-semibold text-primary">{formattedAvailableTokens()}</span>
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="session-toolbar-center flex-1 flex items-center justify-center gap-2 min-w-[160px]">
|
|
||||||
<PermissionNotificationBanner
|
|
||||||
instanceId={props.instance.id}
|
|
||||||
onClick={() => setPermissionModalOpen(true)}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="connection-status-button px-2 py-0.5 text-xs"
|
|
||||||
onClick={handleCommandPaletteClick}
|
|
||||||
aria-label={t("instanceShell.commandPalette.openAriaLabel")}
|
|
||||||
style={{ flex: "0 0 auto", width: "auto" }}
|
|
||||||
>
|
|
||||||
{t("instanceShell.commandPalette.button")}
|
|
||||||
</button>
|
|
||||||
<span class="connection-status-shortcut-hint">
|
|
||||||
<Kbd shortcut="cmd+shift+p" />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="session-toolbar-right flex items-center gap-3">
|
|
||||||
<div class="connection-status-meta flex items-center gap-3">
|
|
||||||
<Show when={connectionStatus() === "connected"}>
|
|
||||||
<span class="status-indicator connected">
|
|
||||||
<span class="status-dot" />
|
|
||||||
<span class="status-text">{t("instanceShell.connection.connected")}</span>
|
|
||||||
</span>
|
|
||||||
</Show>
|
|
||||||
<Show when={connectionStatus() === "connecting"}>
|
|
||||||
<span class="status-indicator connecting">
|
|
||||||
<span class="status-dot" />
|
|
||||||
<span class="status-text">{t("instanceShell.connection.connecting")}</span>
|
|
||||||
</span>
|
|
||||||
</Show>
|
|
||||||
<Show when={connectionStatus() === "error" || connectionStatus() === "disconnected"}>
|
|
||||||
<span class="status-indicator disconnected">
|
|
||||||
<span class="status-dot" />
|
|
||||||
<span class="status-text">{t("instanceShell.connection.disconnected")}</span>
|
|
||||||
</span>
|
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<IconButton
|
|
||||||
ref={setRightToggleButtonEl}
|
|
||||||
color="inherit"
|
|
||||||
onClick={handleRightAppBarButtonClick}
|
|
||||||
aria-label={rightAppBarButtonLabel()}
|
|
||||||
size="small"
|
|
||||||
aria-expanded={rightDrawerState() !== "floating-closed"}
|
|
||||||
disabled={rightDrawerState() === "pinned"}
|
|
||||||
>
|
|
||||||
{rightAppBarButtonIcon()}
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
</Toolbar>
|
|
||||||
</AppBar>
|
|
||||||
|
|
||||||
<Box sx={{ display: "flex", flex: 1, minHeight: 0, overflowX: "hidden" }}>
|
<div class="session-toolbar-center flex-1 flex items-center justify-center gap-2 min-w-[160px]">
|
||||||
{renderLeftPanel()}
|
<PermissionNotificationBanner
|
||||||
|
instanceId={props.instance.id}
|
||||||
|
onClick={() => setPermissionModalOpen(true)}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="connection-status-button px-2 py-0.5 text-xs"
|
||||||
|
onClick={handleCommandPaletteClick}
|
||||||
|
aria-label={t("instanceShell.commandPalette.openAriaLabel")}
|
||||||
|
style={{ flex: "0 0 auto", width: "auto" }}
|
||||||
|
>
|
||||||
|
{t("instanceShell.commandPalette.button")}
|
||||||
|
</button>
|
||||||
|
<span class="connection-status-shortcut-hint">
|
||||||
|
<Kbd shortcut="cmd+shift+p" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="session-toolbar-right flex items-center gap-3">
|
||||||
|
<div class="connection-status-meta flex items-center gap-3">
|
||||||
|
<Show when={connectionStatus() === "connected"}>
|
||||||
|
<span class="status-indicator connected">
|
||||||
|
<span class="status-dot" />
|
||||||
|
<span class="status-text">{t("instanceShell.connection.connected")}</span>
|
||||||
|
</span>
|
||||||
|
</Show>
|
||||||
|
<Show when={connectionStatus() === "connecting"}>
|
||||||
|
<span class="status-indicator connecting">
|
||||||
|
<span class="status-dot" />
|
||||||
|
<span class="status-text">{t("instanceShell.connection.connecting")}</span>
|
||||||
|
</span>
|
||||||
|
</Show>
|
||||||
|
<Show when={connectionStatus() === "error" || connectionStatus() === "disconnected"}>
|
||||||
|
<span class="status-indicator disconnected">
|
||||||
|
<span class="status-dot" />
|
||||||
|
<span class="status-text">{t("instanceShell.connection.disconnected")}</span>
|
||||||
|
</span>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
<Show when={rightDrawerState() === "floating-closed"}>
|
||||||
|
<IconButton
|
||||||
|
ref={setRightToggleButtonEl}
|
||||||
|
color="inherit"
|
||||||
|
onClick={handleRightAppBarButtonClick}
|
||||||
|
aria-label={rightAppBarButtonLabel()}
|
||||||
|
size="small"
|
||||||
|
aria-expanded={rightDrawerState() !== "floating-closed"}
|
||||||
|
>
|
||||||
|
{rightAppBarButtonIcon()}
|
||||||
|
</IconButton>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
</Toolbar>
|
||||||
|
</AppBar>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
component="main"
|
component="main"
|
||||||
@@ -1489,9 +1487,9 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{renderRightPanel()}
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{renderRightPanel()}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user