diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx
index fd854eb182e..6f34b34bd8e 100644
--- a/src/renderer/src/App.tsx
+++ b/src/renderer/src/App.tsx
@@ -72,7 +72,7 @@ function App(): React.JSX.Element {
+
{activeView === 'settings' ? : activeWorktreeId ? : }
diff --git a/src/renderer/src/assets/main.css b/src/renderer/src/assets/main.css
index c5af5caa4f4..87396c067f8 100644
--- a/src/renderer/src/assets/main.css
+++ b/src/renderer/src/assets/main.css
@@ -330,6 +330,12 @@
position: relative;
}
+/* Ensure Restty pane root fills its absolutely-positioned container */
+.restty-pane-root {
+ width: 100% !important;
+ height: 100% !important;
+}
+
/* ── Landing ─────────────────────────────────────────── */
.landing {
diff --git a/src/renderer/src/components/Terminal.tsx b/src/renderer/src/components/Terminal.tsx
index 844297ff648..5dbda7c0ce5 100644
--- a/src/renderer/src/components/Terminal.tsx
+++ b/src/renderer/src/components/Terminal.tsx
@@ -128,7 +128,7 @@ export default function Terminal(): React.JSX.Element | null {
}, [activeWorktreeId, handleNewTab, handleCloseTab, setActiveTab])
return (
-
+
{/* Animated tab bar container using CSS grid for smooth height animation */}
{/* Terminal panes container */}
-
+
{tabs.map((tab) => (
(null)
const resttyRef = useRef(null)
- const wasActiveRef = useRef(isActive)
+ const wasActiveRef = useRef(false)
const updateTabTitle = useAppStore((s) => s.updateTabTitle)
const updateTabPtyId = useAppStore((s) => s.updateTabPtyId)
@@ -162,6 +162,24 @@ export default function TerminalPane({
useEffect(() => {
const container = containerRef.current
if (!container) return
+ let resizeRaf: number | null = null
+
+ const queueResizeAll = (focusActive: boolean): void => {
+ if (resizeRaf !== null) cancelAnimationFrame(resizeRaf)
+ resizeRaf = requestAnimationFrame(() => {
+ resizeRaf = null
+ const restty = resttyRef.current
+ if (!restty) return
+ const panes = restty.getPanes()
+ for (const p of panes) {
+ p.app.updateSize(true)
+ }
+ if (focusActive) {
+ const active = restty.getActivePane() ?? panes[0]
+ active?.canvas.focus({ preventScroll: true })
+ }
+ })
+ }
const onTitleChange = (title: string): void => {
updateTabTitle(tabId, title)
@@ -214,15 +232,21 @@ export default function TerminalPane({
pane.app.updateSize(true)
pane.app.connectPty('')
pane.canvas.focus({ preventScroll: true })
+ queueResizeAll(true)
},
onPaneClosed: () => {},
- onActivePaneChange: () => {}
+ onActivePaneChange: () => {},
+ onLayoutChanged: () => {
+ queueResizeAll(false)
+ }
})
restty.createInitialPane({ focus: isActive })
resttyRef.current = restty
+ queueResizeAll(isActive)
return () => {
+ if (resizeRaf !== null) cancelAnimationFrame(resizeRaf)
restty.destroy()
resttyRef.current = null
}
@@ -234,8 +258,8 @@ export default function TerminalPane({
const restty = resttyRef.current
if (!restty) return
- if (isActive && !wasActiveRef.current) {
- // Tab just became active - focus and resize
+ if (isActive) {
+ // Ensure size/focus is correct both on initial mount and tab activation.
requestAnimationFrame(() => {
const panes = restty.getPanes()
for (const p of panes) {
@@ -250,6 +274,23 @@ export default function TerminalPane({
wasActiveRef.current = isActive
}, [isActive])
+ // ResizeObserver to keep terminal sized to container
+ useEffect(() => {
+ const container = containerRef.current
+ if (!container) return
+
+ const ro = new ResizeObserver(() => {
+ const restty = resttyRef.current
+ if (!restty || !isActive) return
+ const panes = restty.getPanes()
+ for (const p of panes) {
+ p.app.updateSize(true)
+ }
+ })
+ ro.observe(container)
+ return () => ro.disconnect()
+ }, [isActive])
+
// Terminal pane shortcuts handled at window capture phase so they remain
// reliable even when focus is inside the canvas/IME internals.
useEffect(() => {
@@ -299,8 +340,8 @@ export default function TerminalPane({
return (
)
}