This commit is contained in:
@@ -5,20 +5,21 @@ import { useFilePickerStore } from "../store/useFilePickerStore";
|
||||
|
||||
interface FilePickerProps {
|
||||
files: FileNode;
|
||||
onRun?: (path: string) => void;
|
||||
}
|
||||
|
||||
const FilePickerTree: React.FC<{ node: FileNode; level: number }> = ({
|
||||
node,
|
||||
level,
|
||||
}) => {
|
||||
const FilePickerTree: React.FC<{
|
||||
node: FileNode;
|
||||
level: number;
|
||||
onRun?: (path: string) => void;
|
||||
}> = ({ node, level, onRun }) => {
|
||||
const expandedFolders = useFilePickerStore((s) => s.expandedFolders);
|
||||
const selectedPaths = useFilePickerStore((s) => s.selectedPaths);
|
||||
const toggleSelection = useFilePickerStore((s) => s.toggleSelection);
|
||||
const runningScripts = useFilePickerStore((s) => s.runningScripts);
|
||||
const toggleFolder = useFilePickerStore((s) => s.toggleFolder);
|
||||
|
||||
const nodePath = node.path || node.name;
|
||||
const isExpanded = expandedFolders.has(nodePath);
|
||||
const isSelected = node.type === "file" && selectedPaths.has(nodePath);
|
||||
const isRunning = node.type === "file" && runningScripts.has(nodePath);
|
||||
|
||||
if (node.type === "file") {
|
||||
return (
|
||||
@@ -26,9 +27,9 @@ const FilePickerTree: React.FC<{ node: FileNode; level: number }> = ({
|
||||
name={node.name}
|
||||
type="file"
|
||||
path={nodePath}
|
||||
isSelected={isSelected}
|
||||
isSelected={isRunning}
|
||||
level={level}
|
||||
onToggleSelect={toggleSelection}
|
||||
onRun={onRun}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -44,14 +45,19 @@ const FilePickerTree: React.FC<{ node: FileNode; level: number }> = ({
|
||||
onToggleFolder={toggleFolder}
|
||||
>
|
||||
{node.children?.map((child, idx) => (
|
||||
<FilePickerTree key={idx} node={child} level={level + 1} />
|
||||
<FilePickerTree
|
||||
key={idx}
|
||||
node={child}
|
||||
level={level + 1}
|
||||
onRun={onRun}
|
||||
/>
|
||||
))}
|
||||
</FilePickerItem>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const FilePicker: React.FC<FilePickerProps> = ({ files }) => {
|
||||
export const FilePicker: React.FC<FilePickerProps> = ({ files, onRun }) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@@ -61,7 +67,7 @@ export const FilePicker: React.FC<FilePickerProps> = ({ files }) => {
|
||||
}}
|
||||
>
|
||||
{(files.children || []).map((child, idx) => (
|
||||
<FilePickerTree key={idx} node={child} level={0} />
|
||||
<FilePickerTree key={idx} node={child} level={0} onRun={onRun} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
FiChevronDown,
|
||||
FiFile,
|
||||
FiFolder,
|
||||
FiPlay,
|
||||
} from "react-icons/fi";
|
||||
|
||||
interface FilePickerItemProps {
|
||||
@@ -16,6 +17,7 @@ interface FilePickerItemProps {
|
||||
level: number;
|
||||
onToggleSelect?: (path: string) => void;
|
||||
onToggleFolder?: (path: string) => void;
|
||||
onRun?: (path: string) => void;
|
||||
}
|
||||
|
||||
export const FilePickerItem: React.FC<FilePickerItemProps> = ({
|
||||
@@ -28,6 +30,7 @@ export const FilePickerItem: React.FC<FilePickerItemProps> = ({
|
||||
level,
|
||||
onToggleSelect,
|
||||
onToggleFolder,
|
||||
onRun,
|
||||
}) => {
|
||||
const isFolder = type === "folder";
|
||||
const extension = name.includes(".")
|
||||
@@ -120,40 +123,48 @@ export const FilePickerItem: React.FC<FilePickerItemProps> = ({
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* Checkbox — только у файлов */}
|
||||
{!isFolder && onToggleSelect && (
|
||||
<div
|
||||
{/* Run button — только у файлов */}
|
||||
{!isFolder && onRun && (
|
||||
<button
|
||||
style={{
|
||||
width: "18px",
|
||||
height: "18px",
|
||||
border: isSelected
|
||||
? "2px solid #0e639c"
|
||||
: "2px solid var(--border)",
|
||||
borderRadius: "3px",
|
||||
backgroundColor: isSelected ? "#0e639c" : "transparent",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
padding: "4px",
|
||||
backgroundColor: isSelected ? "#238636" : "transparent",
|
||||
border: isSelected
|
||||
? "1px solid #2ea043"
|
||||
: "1px solid transparent",
|
||||
borderRadius: "3px",
|
||||
color: isSelected ? "#ffffff" : "var(--text-secondary)",
|
||||
cursor: "pointer",
|
||||
flexShrink: 0,
|
||||
transition: "all 0.15s",
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onToggleSelect(path);
|
||||
onRun(path);
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.backgroundColor = "#238636";
|
||||
e.currentTarget.style.color = "#ffffff";
|
||||
e.currentTarget.style.borderColor = "#2ea043";
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.backgroundColor = isSelected
|
||||
? "#238636"
|
||||
: "transparent";
|
||||
e.currentTarget.style.color = isSelected
|
||||
? "#ffffff"
|
||||
: "var(--text-secondary)";
|
||||
e.currentTarget.style.borderColor = isSelected
|
||||
? "#2ea043"
|
||||
: "transparent";
|
||||
}}
|
||||
title="Run script"
|
||||
>
|
||||
{isSelected && (
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
|
||||
<path
|
||||
d="M2 6L5 9L10 3"
|
||||
stroke="white"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
</div>
|
||||
<FiPlay size={12} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user