Refactor Settings, FileTree, GitPanel, Shell, and CodeEditor components (#402)

This commit is contained in:
Haileyesus
2026-02-25 19:07:07 +03:00
committed by GitHub
parent 23801e9cc1
commit 5e3a7b69d7
149 changed files with 11627 additions and 8453 deletions

View File

@@ -0,0 +1,74 @@
import { useCallback, useState } from 'react';
import type { Project, ProjectSession } from '../../../types/app';
import Shell from '../../shell/view/Shell';
import StandaloneShellEmptyState from './subcomponents/StandaloneShellEmptyState';
import StandaloneShellHeader from './subcomponents/StandaloneShellHeader';
type StandaloneShellProps = {
project?: Project | null;
session?: ProjectSession | null;
command?: string | null;
isPlainShell?: boolean | null;
autoConnect?: boolean;
onComplete?: ((exitCode: number) => void) | null;
onClose?: (() => void) | null;
title?: string | null;
className?: string;
showHeader?: boolean;
compact?: boolean;
minimal?: boolean;
};
export default function StandaloneShell({
project = null,
session = null,
command = null,
isPlainShell = null,
autoConnect = true,
onComplete = null,
onClose = null,
title = null,
className = '',
showHeader = true,
compact = false,
minimal = false,
}: StandaloneShellProps) {
const [isCompleted, setIsCompleted] = useState(false);
// Keep `compact` in the public API for compatibility with existing callers.
void compact;
const shouldUsePlainShell = isPlainShell !== null ? isPlainShell : command !== null;
const handleProcessComplete = useCallback(
(exitCode: number) => {
setIsCompleted(true);
onComplete?.(exitCode);
},
[onComplete],
);
if (!project) {
return <StandaloneShellEmptyState className={className} />;
}
return (
<div className={`h-full w-full flex flex-col ${className}`}>
{!minimal && showHeader && title && (
<StandaloneShellHeader title={title} isCompleted={isCompleted} onClose={onClose} />
)}
<div className="flex-1 w-full min-h-0">
<Shell
selectedProject={project}
selectedSession={session}
initialCommand={command}
isPlainShell={shouldUsePlainShell}
onProcessComplete={handleProcessComplete}
minimal={minimal}
autoConnect={minimal ? true : autoConnect}
/>
</div>
</div>
);
}

View File

@@ -0,0 +1,24 @@
type StandaloneShellEmptyStateProps = {
className: string;
};
export default function StandaloneShellEmptyState({ className }: StandaloneShellEmptyStateProps) {
return (
<div className={`h-full flex items-center justify-center ${className}`}>
<div className="text-center text-gray-500 dark:text-gray-400">
<div className="w-16 h-16 mx-auto mb-4 bg-gray-100 dark:bg-gray-800 rounded-full flex items-center justify-center">
<svg className="w-8 h-8 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 002 2z"
/>
</svg>
</div>
<h3 className="text-lg font-semibold mb-2">No Project Selected</h3>
<p>A project is required to open a shell</p>
</div>
</div>
);
}

View File

@@ -0,0 +1,30 @@
type StandaloneShellHeaderProps = {
title: string;
isCompleted: boolean;
onClose?: (() => void) | null;
};
export default function StandaloneShellHeader({
title,
isCompleted,
onClose = null,
}: StandaloneShellHeaderProps) {
return (
<div className="flex-shrink-0 bg-gray-800 border-b border-gray-700 px-4 py-2">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<h3 className="text-sm font-medium text-gray-200">{title}</h3>
{isCompleted && <span className="text-xs text-green-400">(Completed)</span>}
</div>
{onClose && (
<button onClick={onClose} className="text-gray-400 hover:text-white" title="Close">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
)}
</div>
</div>
);
}