diff --git a/frontend/src/components/server/TerminalDialog.tsx b/frontend/src/components/server/TerminalDialog.tsx index 649f5d6..e1f3d59 100644 --- a/frontend/src/components/server/TerminalDialog.tsx +++ b/frontend/src/components/server/TerminalDialog.tsx @@ -1,4 +1,4 @@ -import { useState, useRef, useEffect } from "react"; +import { useState, useRef, useEffect, useLayoutEffect } from "react"; import { useTranslation } from "react-i18next"; import { Dialog, @@ -173,11 +173,12 @@ export function TerminalDialog({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [open, serverId, authReady]); - // 容器尺寸变化时 fit 并同步远端 PTY // Logan.Li - useEffect(() => { + // 在浏览器绘制前完成 fit,避免最大化还原时短暂显示旧宽度画布。 // Logan.Li + useLayoutEffect(() => { if (!open || !authReady) return; let cleanup: (() => void) | undefined; + let fitFrame = 0; let retry = 0; const attach = () => { @@ -190,15 +191,23 @@ export function TerminalDialog({ return; } cleanup = attachTerminalResize(container, fit, term, ws); - try { - fitTerminal(fit, term, ws); - } catch { - /* noop */ - } + const applyFit = () => { + try { + fitTerminal(fit, term, ws); + } catch { + /* noop */ + } + }; + applyFit(); + // 下一帧再校准一次,兼容 Radix Dialog 全屏样式刚提交的场景。 // Logan.Li + fitFrame = requestAnimationFrame(applyFit); }; attach(); - return () => cleanup?.(); + return () => { + if (fitFrame) cancelAnimationFrame(fitFrame); + cleanup?.(); + }; }, [open, authReady, fullscreen]); return ( @@ -208,7 +217,7 @@ export function TerminalDialog({ // 禁用 Radix Dialog 默认的 ESC 关闭:终端内 vi/top 等会用到 ESC,关闭只能点头部 X 按钮 // Logan.Li onEscapeKeyDown={(e) => e.preventDefault()} className={cn( - "bg-[var(--dg-bg-secondary)] border-[var(--dg-border)] p-0 gap-0", + "min-w-0 overflow-hidden bg-[var(--dg-bg-secondary)] border-[var(--dg-border)] p-0 gap-0", // 禁用 CSS 过渡:终端窗口应该即时缩放,不需要动画 "!duration-0 !transition-none", fullscreen @@ -239,7 +248,7 @@ export function TerminalDialog({