mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-16 05:13:36 +00:00
feat: continued improvements
This commit is contained in:
@@ -688,9 +688,28 @@ const TerminalInner = forwardRef<TerminalHandle, SSHTerminalProps>(
|
||||
}
|
||||
},
|
||||
fit: () => {
|
||||
fitAddonRef.current?.fit();
|
||||
if (terminal) scheduleNotify(terminal.cols, terminal.rows);
|
||||
hardRefresh();
|
||||
if (!fitAddonRef.current || !terminal || isFittingRef.current) return;
|
||||
isFittingRef.current = true;
|
||||
try {
|
||||
fitAddonRef.current.fit();
|
||||
if (terminal.cols > 0 && terminal.rows > 0) {
|
||||
const lastSize = lastFittedSizeRef.current;
|
||||
if (
|
||||
!lastSize ||
|
||||
lastSize.cols !== terminal.cols ||
|
||||
lastSize.rows !== terminal.rows
|
||||
) {
|
||||
scheduleNotify(terminal.cols, terminal.rows);
|
||||
lastFittedSizeRef.current = {
|
||||
cols: terminal.cols,
|
||||
rows: terminal.rows,
|
||||
};
|
||||
}
|
||||
}
|
||||
setIsFitted(true);
|
||||
} finally {
|
||||
isFittingRef.current = false;
|
||||
}
|
||||
},
|
||||
sendInput: (data: string) => {
|
||||
if (webSocketRef.current?.readyState === 1) {
|
||||
@@ -2448,7 +2467,13 @@ const TerminalInner = forwardRef<TerminalHandle, SSHTerminalProps>(
|
||||
}, [terminal, hostConfig.id, isVisible, isConnected, isConnecting]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!terminal || !fitAddonRef.current || !isVisible) return;
|
||||
if (!terminal || !fitAddonRef.current) return;
|
||||
|
||||
if (!isVisible) {
|
||||
lastFittedSizeRef.current = null;
|
||||
lastSentSizeRef.current = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const fitTimeoutId = setTimeout(() => {
|
||||
if (!isFittingRef.current && terminal.cols > 0 && terminal.rows > 0) {
|
||||
@@ -2457,7 +2482,7 @@ const TerminalInner = forwardRef<TerminalHandle, SSHTerminalProps>(
|
||||
requestAnimationFrame(() => terminal.focus());
|
||||
}
|
||||
}
|
||||
}, 0);
|
||||
}, 50);
|
||||
|
||||
return () => clearTimeout(fitTimeoutId);
|
||||
}, [terminal, isVisible, splitScreen, isConnecting]);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Terminal } from "@/features/terminal/Terminal.tsx";
|
||||
import { FullScreenAppWrapper } from "@/features/FullScreenAppWrapper.tsx";
|
||||
|
||||
@@ -7,6 +8,7 @@ interface TerminalAppProps {
|
||||
}
|
||||
|
||||
const TerminalApp: React.FC<TerminalAppProps> = ({ hostId }) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<FullScreenAppWrapper hostId={hostId}>
|
||||
{(hostConfig, loading) => {
|
||||
@@ -15,7 +17,9 @@ const TerminalApp: React.FC<TerminalAppProps> = ({ hostId }) => {
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-white mx-auto mb-2"></div>
|
||||
<p className="text-muted-foreground">Loading host...</p>
|
||||
<p className="text-muted-foreground">
|
||||
{t("hosts.loadingHost")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -25,7 +29,7 @@ const TerminalApp: React.FC<TerminalAppProps> = ({ hostId }) => {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="text-center">
|
||||
<p className="text-red-500 mb-4">Host not found</p>
|
||||
<p className="text-red-500 mb-4">{t("hosts.hostNotFound")}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
import { TERMINAL_THEMES, TERMINAL_FONTS } from "@/lib/terminal-themes.ts";
|
||||
import { useTheme } from "@/components/theme-provider.tsx";
|
||||
|
||||
interface TerminalPreviewProps {
|
||||
theme: string;
|
||||
fontSize?: number;
|
||||
fontFamily?: string;
|
||||
cursorStyle?: "block" | "underline" | "bar";
|
||||
cursorBlink?: boolean;
|
||||
letterSpacing?: number;
|
||||
lineHeight?: number;
|
||||
}
|
||||
|
||||
export function TerminalPreview({
|
||||
theme = "termix",
|
||||
fontSize = 14,
|
||||
fontFamily = "Caskaydia Cove Nerd Font Mono",
|
||||
cursorStyle = "bar",
|
||||
cursorBlink = true,
|
||||
letterSpacing = 0,
|
||||
lineHeight = 1.2,
|
||||
}: TerminalPreviewProps) {
|
||||
const { theme: appTheme } = useTheme();
|
||||
|
||||
const resolvedTheme =
|
||||
theme === "termix"
|
||||
? appTheme === "dark" ||
|
||||
(appTheme === "system" &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
? "termixDark"
|
||||
: "termixLight"
|
||||
: theme;
|
||||
|
||||
return (
|
||||
<div className="border border-input rounded-md overflow-hidden">
|
||||
<div
|
||||
className="p-4 font-mono text-sm"
|
||||
style={{
|
||||
fontSize: `${fontSize}px`,
|
||||
fontFamily:
|
||||
TERMINAL_FONTS.find((f) => f.value === fontFamily)?.fallback ||
|
||||
TERMINAL_FONTS[0].fallback,
|
||||
letterSpacing: `${letterSpacing}px`,
|
||||
lineHeight,
|
||||
background:
|
||||
TERMINAL_THEMES[resolvedTheme]?.colors.background ||
|
||||
"var(--bg-base)",
|
||||
color:
|
||||
TERMINAL_THEMES[resolvedTheme]?.colors.foreground ||
|
||||
"var(--foreground)",
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<span style={{ color: TERMINAL_THEMES[resolvedTheme]?.colors.green }}>
|
||||
user@termix
|
||||
</span>
|
||||
<span>:</span>
|
||||
<span style={{ color: TERMINAL_THEMES[resolvedTheme]?.colors.blue }}>
|
||||
~
|
||||
</span>
|
||||
<span>$ ls -la</span>
|
||||
</div>
|
||||
<div>
|
||||
<span style={{ color: TERMINAL_THEMES[resolvedTheme]?.colors.blue }}>
|
||||
drwxr-xr-x
|
||||
</span>
|
||||
<span> 5 user </span>
|
||||
<span style={{ color: TERMINAL_THEMES[resolvedTheme]?.colors.cyan }}>
|
||||
docs
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span style={{ color: TERMINAL_THEMES[resolvedTheme]?.colors.green }}>
|
||||
-rwxr-xr-x
|
||||
</span>
|
||||
<span> 1 user </span>
|
||||
<span style={{ color: TERMINAL_THEMES[resolvedTheme]?.colors.green }}>
|
||||
script.sh
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>-rw-r--r--</span>
|
||||
<span> 1 user </span>
|
||||
<span>README.md</span>
|
||||
</div>
|
||||
<div>
|
||||
<span style={{ color: TERMINAL_THEMES[resolvedTheme]?.colors.green }}>
|
||||
user@termix
|
||||
</span>
|
||||
<span>:</span>
|
||||
<span style={{ color: TERMINAL_THEMES[resolvedTheme]?.colors.blue }}>
|
||||
~
|
||||
</span>
|
||||
<span>$ </span>
|
||||
<span
|
||||
className="inline-block"
|
||||
style={{
|
||||
width: cursorStyle === "block" ? "0.6em" : "0.1em",
|
||||
height:
|
||||
cursorStyle === "underline"
|
||||
? "0.15em"
|
||||
: cursorStyle === "bar"
|
||||
? `${fontSize}px`
|
||||
: `${fontSize}px`,
|
||||
background:
|
||||
TERMINAL_THEMES[resolvedTheme]?.colors.cursor || "#f7f7f7",
|
||||
animation: cursorBlink ? "blink 1s step-end infinite" : "none",
|
||||
verticalAlign:
|
||||
cursorStyle === "underline" ? "bottom" : "text-bottom",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<style>{`
|
||||
@keyframes blink {
|
||||
0%, 49% { opacity: 1; }
|
||||
50%, 100% { opacity: 0; }
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user