mirror of
https://github.com/YuzuZensai/Termix.git
synced 2026-09-13 18:58:52 +00:00
v2.3.0
This commit is contained in:
@@ -13,19 +13,14 @@ import {
|
||||
Settings,
|
||||
Download,
|
||||
Upload,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
RefreshCw,
|
||||
ArrowUp,
|
||||
ArrowDown,
|
||||
FileSymlink,
|
||||
Move,
|
||||
GitCompare,
|
||||
Edit,
|
||||
} from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { FileItem } from "@/types/index";
|
||||
import { SimpleLoader } from "@/lib/SimpleLoader.tsx";
|
||||
|
||||
interface CreateIntent {
|
||||
id: string;
|
||||
@@ -70,7 +65,6 @@ interface FileManagerGridProps {
|
||||
onFileOpen: (file: FileItem) => void;
|
||||
onSelectionChange: (files: FileItem[]) => void;
|
||||
currentPath: string;
|
||||
isLoading?: boolean;
|
||||
onPathChange: (path: string) => void;
|
||||
onRefresh: () => void;
|
||||
onUpload?: (files: FileList) => void;
|
||||
@@ -194,7 +188,6 @@ export function FileManagerGrid({
|
||||
onFileOpen,
|
||||
onSelectionChange,
|
||||
currentPath,
|
||||
isLoading,
|
||||
onPathChange,
|
||||
onRefresh,
|
||||
onUpload,
|
||||
@@ -529,20 +522,30 @@ export function FileManagerGrid({
|
||||
e.stopPropagation();
|
||||
}, []);
|
||||
|
||||
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
||||
if (e.target === e.currentTarget && e.button === 0) {
|
||||
e.preventDefault();
|
||||
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
|
||||
const startX = e.clientX - rect.left;
|
||||
const startY = e.clientY - rect.top;
|
||||
const handleMouseDown = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
if (createIntent) {
|
||||
const target = e.target as HTMLElement;
|
||||
if (target.tagName !== "INPUT") {
|
||||
e.preventDefault();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (e.target === e.currentTarget && e.button === 0) {
|
||||
e.preventDefault();
|
||||
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
|
||||
const startX = e.clientX - rect.left;
|
||||
const startY = e.clientY - rect.top;
|
||||
|
||||
setIsSelecting(true);
|
||||
setSelectionStart({ x: startX, y: startY });
|
||||
setSelectionRect({ x: startX, y: startY, width: 0, height: 0 });
|
||||
setIsSelecting(true);
|
||||
setSelectionStart({ x: startX, y: startY });
|
||||
setSelectionRect({ x: startX, y: startY, width: 0, height: 0 });
|
||||
|
||||
setJustFinishedSelecting(false);
|
||||
}
|
||||
}, []);
|
||||
setJustFinishedSelecting(false);
|
||||
}
|
||||
},
|
||||
[createIntent],
|
||||
);
|
||||
|
||||
const handleMouseMove = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
@@ -699,7 +702,7 @@ export function FileManagerGrid({
|
||||
const handleFileClick = (file: FileItem, event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
|
||||
if (gridRef.current) {
|
||||
if (gridRef.current && !createIntent) {
|
||||
gridRef.current.focus();
|
||||
}
|
||||
|
||||
@@ -734,7 +737,7 @@ export function FileManagerGrid({
|
||||
};
|
||||
|
||||
const handleGridClick = (event: React.MouseEvent) => {
|
||||
if (gridRef.current) {
|
||||
if (gridRef.current && !createIntent) {
|
||||
gridRef.current.focus();
|
||||
}
|
||||
|
||||
@@ -978,6 +981,7 @@ export function FileManagerGrid({
|
||||
onBlur={handleEditConfirm}
|
||||
className="max-w-[120px] min-w-[60px] w-fit border border-accent-brand/60 bg-card px-2 py-1 text-xs rounded-none outline-none focus:ring-1 focus:ring-accent-brand/50 text-center pointer-events-auto"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
/>
|
||||
) : (
|
||||
<p
|
||||
@@ -1100,6 +1104,7 @@ export function FileManagerGrid({
|
||||
onBlur={handleEditConfirm}
|
||||
className="flex-1 min-w-0 max-w-[200px] border border-accent-brand/60 bg-card px-2 py-1 text-xs rounded-none outline-none focus:ring-1 focus:ring-accent-brand/50 pointer-events-auto"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
/>
|
||||
) : (
|
||||
<span
|
||||
@@ -1230,8 +1235,6 @@ export function FileManagerGrid({
|
||||
</div>,
|
||||
document.body,
|
||||
)}
|
||||
|
||||
<SimpleLoader visible={isLoading} message={t("common.connecting")} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1248,24 +1251,49 @@ function CreateIntentGridItem({
|
||||
const { t } = useTranslation();
|
||||
const [inputName, setInputName] = useState(intent.currentName);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const doneRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
inputRef.current?.focus();
|
||||
inputRef.current?.select();
|
||||
}, []);
|
||||
const timer = setTimeout(() => {
|
||||
if (inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
inputRef.current.select();
|
||||
}
|
||||
}, 50);
|
||||
return () => clearTimeout(timer);
|
||||
}, [intent.id]);
|
||||
|
||||
const commit = useCallback(
|
||||
(name: string) => {
|
||||
if (doneRef.current) return;
|
||||
doneRef.current = true;
|
||||
if (name) {
|
||||
onConfirm?.(name);
|
||||
} else {
|
||||
onCancel?.();
|
||||
}
|
||||
},
|
||||
[onConfirm, onCancel],
|
||||
);
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
onConfirm?.(inputName.trim());
|
||||
commit(inputName.trim());
|
||||
} else if (e.key === "Escape") {
|
||||
e.preventDefault();
|
||||
if (doneRef.current) return;
|
||||
doneRef.current = true;
|
||||
onCancel?.();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="group flex flex-col items-center p-3 rounded-none border-2 border-dashed border-accent-brand/60 bg-accent-brand/5">
|
||||
<div
|
||||
className="group flex flex-col items-center p-3 rounded-none border-2 border-dashed border-accent-brand/60 bg-accent-brand/5"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="mb-2">
|
||||
{intent.type === "directory" ? (
|
||||
<Folder className="size-10 text-accent-brand" />
|
||||
@@ -1279,7 +1307,7 @@ function CreateIntentGridItem({
|
||||
value={inputName}
|
||||
onChange={(e) => setInputName(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
onBlur={() => onConfirm?.(inputName.trim())}
|
||||
onBlur={() => commit(inputName.trim())}
|
||||
className="w-full max-w-[120px] border border-accent-brand/60 bg-card px-2 py-1 text-xs text-center rounded-none outline-none focus:ring-1 focus:ring-accent-brand/50"
|
||||
placeholder={
|
||||
intent.type === "directory"
|
||||
@@ -1303,24 +1331,49 @@ function CreateIntentListItem({
|
||||
const { t } = useTranslation();
|
||||
const [inputName, setInputName] = useState(intent.currentName);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const doneRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
inputRef.current?.focus();
|
||||
inputRef.current?.select();
|
||||
}, []);
|
||||
const timer = setTimeout(() => {
|
||||
if (inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
inputRef.current.select();
|
||||
}
|
||||
}, 50);
|
||||
return () => clearTimeout(timer);
|
||||
}, [intent.id]);
|
||||
|
||||
const commit = useCallback(
|
||||
(name: string) => {
|
||||
if (doneRef.current) return;
|
||||
doneRef.current = true;
|
||||
if (name) {
|
||||
onConfirm?.(name);
|
||||
} else {
|
||||
onCancel?.();
|
||||
}
|
||||
},
|
||||
[onConfirm, onCancel],
|
||||
);
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
onConfirm?.(inputName.trim());
|
||||
commit(inputName.trim());
|
||||
} else if (e.key === "Escape") {
|
||||
e.preventDefault();
|
||||
if (doneRef.current) return;
|
||||
doneRef.current = true;
|
||||
onCancel?.();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-[1fr_120px_150px_80px_90px] gap-2 px-4 py-2 items-center border-b border-accent-brand/30 bg-accent-brand/5 rounded-none">
|
||||
<div
|
||||
className="grid grid-cols-[1fr_120px_150px_80px_90px] gap-2 px-4 py-2 items-center border-b border-accent-brand/30 bg-accent-brand/5 rounded-none"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="shrink-0">
|
||||
{intent.type === "directory" ? (
|
||||
@@ -1335,7 +1388,7 @@ function CreateIntentListItem({
|
||||
value={inputName}
|
||||
onChange={(e) => setInputName(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
onBlur={() => onConfirm?.(inputName.trim())}
|
||||
onBlur={() => commit(inputName.trim())}
|
||||
className="flex-1 min-w-0 max-w-[200px] border border-accent-brand/60 bg-card px-2 py-1 text-xs rounded-none outline-none focus:ring-1 focus:ring-accent-brand/50"
|
||||
placeholder={
|
||||
intent.type === "directory"
|
||||
|
||||
Reference in New Issue
Block a user