Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion docs/specs/layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ The user can navigate between all elements using the mouse, or by entering `comm

```
Pond
├── Context providers (Mode, SelectedId, PondActions, PanelElements, DoorElements, RenamingId, Zoomed)
├── Context providers (Mode, SelectedId, PondActions, PanelElements, DoorElements, RenamingId, Zoomed, WindowFocused)
│ └── div (h-screen, flex col)
│ ├── Dockview wrapper (flex-1, 6px padding around edges)
│ │ ├── DockviewReact (tiling layout engine, singleTabMode="fullwidth")
Expand Down
4 changes: 3 additions & 1 deletion lib/src/components/Baseboard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useRef, useState, useMemo, useLayoutEffect, useContext, useSyncExternalStore, type ReactNode } from 'react';
import { CaretLeftIcon, CaretRightIcon } from '@phosphor-icons/react';
import { Door } from './Door';
import { DoorElementsContext, type DetachedItem } from './Pond';
import { DoorElementsContext, WindowFocusedContext, type DetachedItem } from './Pond';
import { DEFAULT_SESSION_UI_STATE, getSessionStateSnapshot, subscribeToSessionStateChanges } from '../lib/terminal-registry';

export interface BaseboardProps {
Expand All @@ -13,6 +13,7 @@ export interface BaseboardProps {

export function Baseboard({ items, activeId, onReattach, notice }: BaseboardProps) {
const { elements: doorElements, bumpVersion } = useContext(DoorElementsContext);
const windowFocused = useContext(WindowFocusedContext);
const sessionStates = useSyncExternalStore(subscribeToSessionStateChanges, getSessionStateSnapshot);
const containerRef = useRef<HTMLDivElement>(null);
const [containerWidth, setContainerWidth] = useState(0);
Expand Down Expand Up @@ -176,6 +177,7 @@ export function Baseboard({ items, activeId, onReattach, notice }: BaseboardProp
doorId={item.id}
title={item.title}
isActive={activeId === item.id}
windowFocused={windowFocused}
status={sessionState.status}

todo={sessionState.todo}
Expand Down
6 changes: 4 additions & 2 deletions lib/src/components/Door.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface DoorProps {
doorId?: string;
title: string;
isActive?: boolean;
windowFocused?: boolean;
status?: SessionStatus;
todo?: TodoState;
onClick?: () => void;
Expand All @@ -14,6 +15,7 @@ export function Door({
doorId,
title,
isActive = false,
windowFocused = true,
status = 'ALARM_DISABLED',
todo = false,
onClick,
Expand Down Expand Up @@ -46,7 +48,7 @@ export function Door({
onClick={onClick}
title={title}
>
<span className={['min-w-0 flex-1 truncate', isActive ? 'text-foreground' : 'text-muted'].join(' ')}>
<span className={['min-w-0 flex-1 truncate', (isActive && windowFocused) ? 'text-foreground' : 'text-muted'].join(' ')}>
{title}
</span>
{(todo || alarmEnabled) && (
Expand All @@ -60,7 +62,7 @@ export function Door({
</span>
)}
{alarmEnabled && (
<span className={['relative', alarmRinging ? 'text-warning' : isActive ? 'text-foreground' : 'text-muted'].join(' ')}>
<span className={['relative', alarmRinging ? 'text-warning' : (isActive && windowFocused) ? 'text-foreground' : 'text-muted'].join(' ')}>
<BellIcon size={11} weight="fill" />
{(status === 'MIGHT_BE_BUSY' || status === 'BUSY' || status === 'MIGHT_NEED_ATTENTION') && (
<span className={[
Expand Down
10 changes: 8 additions & 2 deletions lib/src/components/Pond.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ export const PondActionsContext = createContext<PondActions>({

export const RenamingIdContext = createContext<string | null>(null);
export const ZoomedContext = createContext(false);
export const WindowFocusedContext = createContext(true);

const ARROW_OPPOSITES: Record<string, string> = {
ArrowLeft: 'ArrowRight', ArrowRight: 'ArrowLeft',
Expand Down Expand Up @@ -487,11 +488,12 @@ export function TerminalPaneHeader({ api }: IDockviewPanelHeaderProps) {
const selectedId = useContext(SelectedIdContext);
const renamingId = useContext(RenamingIdContext);
const zoomed = useContext(ZoomedContext);
const windowFocused = useContext(WindowFocusedContext);
const sessionStates = useSyncExternalStore(subscribeToSessionStateChanges, getSessionStateSnapshot);
const actions = useContext(PondActionsContext);
const sessionState = sessionStates.get(api.id) ?? DEFAULT_SESSION_UI_STATE;
const isSelected = selectedId === api.id;
const showSelectedHeader = mode === 'passthrough' && isSelected;
const showSelectedHeader = mode === 'passthrough' && isSelected && windowFocused;
const isRenaming = renamingId === api.id;
const tabRef = useRef<HTMLDivElement>(null);
const suppressAlarmClickRef = useRef(false);
Expand Down Expand Up @@ -812,7 +814,7 @@ function SelectionOverlay({ apiRef, selectedId, selectedType, mode }: {
const { elements: panelElements, version: panelVersion } = useContext(PanelElementsContext);
const { elements: doorElements, version: doorVersion } = useContext(DoorElementsContext);
const selectionColor = useSelectionColor();
const windowFocused = useWindowFocused();
const windowFocused = useContext(WindowFocusedContext);
const [rect, setRect] = useState<{ top: number; left: number; width: number; height: number } | null>(null);
const isDoor = selectedType === 'door';

Expand Down Expand Up @@ -998,6 +1000,8 @@ export function Pond({
const [selectedId, setSelectedId] = useState<string | null>(null);
const [selectedType, setSelectedType] = useState<'pane' | 'door'>('pane');

const windowFocused = useWindowFocused();

// UI state
const [confirmKill, setConfirmKill] = useState<ConfirmKill | null>(null);
useEffect(() => { if (!confirmKill) { clearTimeout(shakeTimerRef.current!); } }, [confirmKill]);
Expand Down Expand Up @@ -1816,6 +1820,7 @@ export function Pond({
<DoorElementsContext.Provider value={{ elements: doorElements, version: doorElementsVersion, bumpVersion: bumpDoorElementsVersion }}>
<RenamingIdContext.Provider value={renamingPaneId}>
<ZoomedContext.Provider value={zoomed}>
<WindowFocusedContext.Provider value={windowFocused}>
<div className="flex-1 min-h-0 flex flex-col bg-surface text-foreground font-sans overflow-hidden">
{/* Dockview */}
<div className="flex-1 min-h-0 relative p-1.5">
Expand Down Expand Up @@ -1844,6 +1849,7 @@ export function Pond({
)}

</div>
</WindowFocusedContext.Provider>
</ZoomedContext.Provider>
</RenamingIdContext.Provider>
</DoorElementsContext.Provider>
Expand Down
Loading