Fixed up split screen a little. Still buggy. Made some UI changes too.

This commit is contained in:
Karmaa
2025-03-02 00:04:21 -06:00
parent cf8fff572a
commit 2038a84c15
2 changed files with 63 additions and 40 deletions

View File

@@ -22,6 +22,7 @@ function App() {
port: 22, port: 22,
}); });
const [isLaunchpadOpen, setIsLaunchpadOpen] = useState(false); const [isLaunchpadOpen, setIsLaunchpadOpen] = useState(false);
const [splitTabIds, setSplitTabIds] = useState([]);
// Handle keypress for opening launchpad // Handle keypress for opening launchpad
useEffect(() => { useEffect(() => {
@@ -50,8 +51,7 @@ function App() {
password: form.password, password: form.password,
port: Number(form.port), port: Number(form.port),
}, },
isSplit: false, terminalRef: null,
terminalRef: null, // Reference to the terminal instance
}; };
setTerminals([...terminals, newTerminal]); setTerminals([...terminals, newTerminal]);
setActiveTab(nextId); setActiveTab(nextId);
@@ -67,6 +67,7 @@ function App() {
const closeTab = (id) => { const closeTab = (id) => {
const newTerminals = terminals.filter((t) => t.id !== id); const newTerminals = terminals.filter((t) => t.id !== id);
setTerminals(newTerminals); setTerminals(newTerminals);
setSplitTabIds(prev => prev.filter(tabId => tabId !== id));
if (activeTab === id) { if (activeTab === id) {
setActiveTab(newTerminals[0]?.id || null); setActiveTab(newTerminals[0]?.id || null);
} }
@@ -74,21 +75,29 @@ function App() {
// Toggle split for a specific tab // Toggle split for a specific tab
const toggleSplit = (id) => { const toggleSplit = (id) => {
setTerminals(terminals.map(t => setSplitTabIds(prev => {
t.id === id ? { ...t, isSplit: !t.isSplit } : t if (prev.includes(id)) {
)); return prev.filter(tabId => tabId !== id);
} else {
if (prev.length >= 1) return prev; // Limit to 1 split
return [...prev, id, activeTab].filter((tabId, index, self) => self.indexOf(tabId) === index);
}
});
}; };
// Get the split terminals // Get grid layout class based on split count
const splitTerminals = terminals.filter(t => t.isSplit); const getGridLayout = (count) => {
const mainTerminal = terminals.find(t => t.id === activeTab); if (count === 1) return 'grid-cols-1';
if (count === 2) return 'grid-cols-2';
return 'grid-cols-1';
};
return ( return (
<CssVarsProvider theme={theme}> <CssVarsProvider theme={theme}>
<div className="flex h-screen bg-neutral-900 overflow-hidden"> <div className="flex h-screen bg-neutral-900 overflow-hidden">
<div className="flex-1 flex flex-col overflow-hidden"> <div className="flex-1 flex flex-col overflow-hidden">
{/* Topbar */} {/* Topbar */}
<div className="bg-neutral-800 text-white p-4 flex items-center justify-between gap-4 min-h-[75px] max-h-[75px]"> <div className="bg-neutral-800 text-white p-4 flex items-center justify-between gap-4 min-h-[75px] max-h-[75px] shadow-xl border-b-5 border-neutral-700">
<div className="bg-neutral-700 flex justify-center items-center gap-2 p-3 rounded-lg h-[52px]"> <div className="bg-neutral-700 flex justify-center items-center gap-2 p-3 rounded-lg h-[52px]">
<img src={TermixIcon} alt="Termix Icon" className="w-[30px] h-[30px]" /> <img src={TermixIcon} alt="Termix Icon" className="w-[30px] h-[30px]" />
<h2 className="text-lg font-bold ml-[-2px]">Termix</h2> <h2 className="text-lg font-bold ml-[-2px]">Termix</h2>
@@ -102,6 +111,7 @@ function App() {
setActiveTab={setActiveTab} setActiveTab={setActiveTab}
closeTab={closeTab} closeTab={closeTab}
toggleSplit={toggleSplit} toggleSplit={toggleSplit}
splitTabIds={splitTabIds}
theme={theme} theme={theme}
/> />
</div> </div>
@@ -144,15 +154,17 @@ function App() {
{/* Terminal Views */} {/* Terminal Views */}
<div className="flex-1 relative p-4"> <div className="flex-1 relative p-4">
{splitTerminals.length > 0 ? ( {splitTabIds.length > 0 ? (
<div className={`grid ${splitTerminals.length === 1 ? 'grid-cols-1' : 'grid-cols-2'} gap-4 h-full`}> <div className={`grid gap-4 h-full ${getGridLayout(splitTabIds.length)}`}>
{splitTerminals.map((terminal) => ( {splitTabIds.map(id => {
const terminal = terminals.find(t => t.id === id);
return terminal ? (
<div key={terminal.id} className="bg-neutral-800 rounded-lg overflow-hidden shadow-xl border-5 border-neutral-700 h-full"> <div key={terminal.id} className="bg-neutral-800 rounded-lg overflow-hidden shadow-xl border-5 border-neutral-700 h-full">
<NewTerminal <NewTerminal
key={terminal.id}
hostConfig={terminal.hostConfig} hostConfig={terminal.hostConfig}
ref={(ref) => { ref={(ref) => {
if (ref && !terminal.terminalRef) { if (ref && !terminal.terminalRef) {
// Store the terminal instance reference
setTerminals(prev => prev.map(t => setTerminals(prev => prev.map(t =>
t.id === terminal.id ? { ...t, terminalRef: ref } : t t.id === terminal.id ? { ...t, terminalRef: ref } : t
)); ));
@@ -160,19 +172,21 @@ function App() {
}} }}
/> />
</div> </div>
))} ) : null;
})}
</div> </div>
) : ( ) : (
<div className="absolute top-4 left-4 right-4 bottom-4"> <div className="absolute top-4 left-4 right-4 bottom-4">
{mainTerminal && ( {terminals.find(t => t.id === activeTab) && (
<div className="bg-neutral-800 rounded-lg overflow-hidden shadow-xl border-5 border-neutral-700 h-full"> <div className="bg-neutral-800 rounded-lg overflow-hidden shadow-xl border-5 border-neutral-700 h-full">
<NewTerminal <NewTerminal
hostConfig={mainTerminal.hostConfig} key={activeTab}
hostConfig={terminals.find(t => t.id === activeTab).hostConfig}
ref={(ref) => { ref={(ref) => {
if (ref && !mainTerminal.terminalRef) { const terminal = terminals.find(t => t.id === activeTab);
// Store the terminal instance reference if (ref && terminal && !terminal.terminalRef) {
setTerminals(prev => prev.map(t => setTerminals(prev => prev.map(t =>
t.id === mainTerminal.id ? { ...t, terminalRef: ref } : t t.id === activeTab ? { ...t, terminalRef: ref } : t
)); ));
} }
}} }}
@@ -184,7 +198,7 @@ function App() {
</div> </div>
</div> </div>
{/* Modal for adding a host */} {/* Modals */}
<AddHostModal <AddHostModal
isHidden={isAddHostHidden} isHidden={isAddHostHidden}
form={form} form={form}
@@ -192,8 +206,6 @@ function App() {
handleAddHost={handleAddHost} handleAddHost={handleAddHost}
setIsAddHostHidden={setIsAddHostHidden} setIsAddHostHidden={setIsAddHostHidden}
/> />
{/* Launchpad Component */}
{isLaunchpadOpen && <Launchpad onClose={() => setIsLaunchpadOpen(false)} />} {isLaunchpadOpen && <Launchpad onClose={() => setIsLaunchpadOpen(false)} />}
</div> </div>
</CssVarsProvider> </CssVarsProvider>

View File

@@ -1,14 +1,15 @@
import { Button, ButtonGroup } from "@mui/joy"; import { Button, ButtonGroup } from "@mui/joy";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
function TabList({ terminals, activeTab, setActiveTab, closeTab, toggleSplit, theme }) { function TabList({ terminals, activeTab, setActiveTab, closeTab, toggleSplit, splitTabIds, theme }) {
return ( return (
<div className="inline-flex items-center h-full px-[0.5rem]"> <div className="inline-flex items-center h-full px-[0.5rem]">
{terminals.map((terminal, index) => ( {terminals.map((terminal, index) => (
<div key={terminal.id} className={index < terminals.length - 1 ? "mr-[0.5rem]" : ""}> <div key={terminal.id} className={index < terminals.length - 1 ? "mr-[0.5rem]" : ""}>
<ButtonGroup> <ButtonGroup>
<Button <Button
onClick={() => setActiveTab(terminal.id)} onClick={() => splitTabIds.length === 0 && setActiveTab(terminal.id)}
disabled={splitTabIds.length > 0}
sx={{ sx={{
backgroundColor: backgroundColor:
terminal.id === activeTab terminal.id === activeTab
@@ -28,17 +29,26 @@ function TabList({ terminals, activeTab, setActiveTab, closeTab, toggleSplit, th
</Button> </Button>
<Button <Button
onClick={() => toggleSplit(terminal.id)} onClick={() => toggleSplit(terminal.id)}
disabled={terminal.id === activeTab} disabled={
(splitTabIds.length >= 1 && !splitTabIds.includes(terminal.id)) ||
(splitTabIds.length === 0 && terminal.id === activeTab)
}
sx={{ sx={{
backgroundColor: theme.palette.neutral[700], backgroundColor: splitTabIds.includes(terminal.id)
? theme.palette.neutral[500]
: theme.palette.neutral[700],
color: theme.palette.text.primary, color: theme.palette.text.primary,
"&:hover": { backgroundColor: theme.palette.neutral[300] }, "&:hover": { backgroundColor: theme.palette.neutral[300] },
borderTopRightRadius: "4px", borderTopRightRadius: "4px",
borderBottomRightRadius: "4px", borderBottomRightRadius: "4px",
height: "40px", height: "40px",
fontSize: "1rem", fontSize: "1rem",
opacity: terminal.id === activeTab ? 0.5 : 1, opacity: (splitTabIds.length >= 1 && !splitTabIds.includes(terminal.id)) ||
cursor: terminal.id === activeTab ? "not-allowed" : "pointer", (splitTabIds.length === 0 && terminal.id === activeTab) ? 0.5 : 1,
cursor: (splitTabIds.length >= 1 && !splitTabIds.includes(terminal.id)) ||
(splitTabIds.length === 0 && terminal.id === activeTab)
? "not-allowed"
: "pointer",
}} }}
> >
/ /
@@ -70,6 +80,7 @@ TabList.propTypes = {
setActiveTab: PropTypes.func.isRequired, setActiveTab: PropTypes.func.isRequired,
closeTab: PropTypes.func.isRequired, closeTab: PropTypes.func.isRequired,
toggleSplit: PropTypes.func.isRequired, toggleSplit: PropTypes.func.isRequired,
splitTabIds: PropTypes.array.isRequired,
theme: PropTypes.object.isRequired, theme: PropTypes.object.isRequired,
}; };