From 54a6083a4a499dc9a386223c6590781bc4ba4a6a Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Sun, 2 Nov 2025 03:54:01 -0600
Subject: [PATCH 1/2] fix: Update readme
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e0d99567..81af5534 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,7 @@ If you would like, you can support the project here!\
-Termix is an open-source, forever-free, self-hosted all-in-one server management platform. It provides a web-based
+Termix is an open-source, forever-free, self-hosted all-in-one server management platform. It provides a multi-platform
solution for managing your servers and infrastructure through a single, intuitive interface. Termix offers SSH terminal
access, SSH tunneling capabilities, and remote file management, with many more tools to come. Termix is the perfect
free and self-hosted alternative to Termius available for all platforms.
--
2.49.1
From 84cdb9d431a9b7366974fc8b96a07fe51803229a Mon Sep 17 00:00:00 2001
From: Robert Coroianu
Date: Sun, 2 Nov 2025 11:55:34 +0200
Subject: [PATCH 2/2] [FEATURE] Adjustable Left Menu Width in Web Interface
#234 Added to LeftSidebar.tsx functionality Update TopNavbar.tsx to use
sidebar dynamic width
---
src/ui/desktop/navigation/LeftSidebar.tsx | 88 +++++++++++++++++++++--
src/ui/desktop/navigation/TopNavbar.tsx | 3 +-
2 files changed, 86 insertions(+), 5 deletions(-)
diff --git a/src/ui/desktop/navigation/LeftSidebar.tsx b/src/ui/desktop/navigation/LeftSidebar.tsx
index 0021283e..2afa54a8 100644
--- a/src/ui/desktop/navigation/LeftSidebar.tsx
+++ b/src/ui/desktop/navigation/LeftSidebar.tsx
@@ -241,6 +241,63 @@ export function LeftSidebar({
localStorage.setItem("leftSidebarOpen", JSON.stringify(isSidebarOpen));
}, [isSidebarOpen]);
+ // Sidebar width state for resizing
+ const [sidebarWidth, setSidebarWidth] = useState(() => {
+ const saved = localStorage.getItem("leftSidebarWidth");
+ return saved !== null ? parseInt(saved, 10) : 320;
+ });
+
+ const [isResizing, setIsResizing] = useState(false);
+ const startXRef = React.useRef(null);
+ const startWidthRef = React.useRef(sidebarWidth);
+
+ React.useEffect(() => {
+ localStorage.setItem("leftSidebarWidth", String(sidebarWidth));
+ }, [sidebarWidth]);
+
+ const handleMouseDown = (e: React.MouseEvent) => {
+ e.preventDefault();
+ setIsResizing(true);
+ startXRef.current = e.clientX;
+ startWidthRef.current = sidebarWidth;
+ };
+
+ React.useEffect(() => {
+ if (!isResizing) return;
+
+ const handleMouseMove = (e: MouseEvent) => {
+ if (startXRef.current == null) return;
+ const dx = e.clientX - startXRef.current;
+ const newWidth = Math.round(startWidthRef.current + dx);
+ const minWidth = 200;
+ const maxWidth = Math.round(window.innerWidth * 0.5);
+ if (newWidth >= minWidth && newWidth <= maxWidth) {
+ setSidebarWidth(newWidth);
+ } else if (newWidth < minWidth) {
+ setSidebarWidth(minWidth);
+ } else if (newWidth > maxWidth) {
+ setSidebarWidth(maxWidth);
+ }
+ };
+
+ const handleMouseUp = () => {
+ setIsResizing(false);
+ startXRef.current = null;
+ };
+
+ document.addEventListener("mousemove", handleMouseMove);
+ document.addEventListener("mouseup", handleMouseUp);
+ document.body.style.cursor = "col-resize";
+ document.body.style.userSelect = "none";
+
+ return () => {
+ document.removeEventListener("mousemove", handleMouseMove);
+ document.removeEventListener("mouseup", handleMouseUp);
+ document.body.style.cursor = "";
+ document.body.style.userSelect = "";
+ };
+ }, [isResizing]);
+
const filteredHosts = React.useMemo(() => {
if (!debouncedSearch.trim()) return hosts;
const q = debouncedSearch.trim().toLowerCase();
@@ -293,8 +350,12 @@ export function LeftSidebar({
return (
-
-
+
+
+
Termix
@@ -416,8 +477,27 @@ export function LeftSidebar({
-
-
{children}
+
+
+ {/* Resizable divider */}
+ {isSidebarOpen && (
+
+ )}
+
+
{children}
+
{!isSidebarOpen && (
diff --git a/src/ui/desktop/navigation/TopNavbar.tsx b/src/ui/desktop/navigation/TopNavbar.tsx
index 7d7ad169..b5fa7700 100644
--- a/src/ui/desktop/navigation/TopNavbar.tsx
+++ b/src/ui/desktop/navigation/TopNavbar.tsx
@@ -50,7 +50,8 @@ export function TopNavbar({
allSplitScreenTab: number[];
reorderTabs: (fromIndex: number, toIndex: number) => void;
};
- const leftPosition = state === "collapsed" ? "26px" : "264px";
+ // Use CSS variable for dynamic sidebar width + divider width (4px) + some padding
+ const leftPosition = state === "collapsed" ? "26px" : "calc(var(--sidebar-width) + 20px)";
const { t } = useTranslation();
const [toolsSheetOpen, setToolsSheetOpen] = useState(false);
--
2.49.1