mirror of
https://github.com/xuquan-nikkkki/FolderFile-Splitter-Plugin.git
synced 2026-07-22 05:37:28 +00:00
173 lines
4.3 KiB
TypeScript
173 lines
4.3 KiB
TypeScript
import { useDraggable, useDroppable } from "@dnd-kit/core";
|
|
import classNames from "classnames";
|
|
import { useEffect } from "react";
|
|
import { useShallow } from "zustand/react/shallow";
|
|
|
|
import { FFS_DRAG_FILE, FFS_DRAG_FOLDER } from "src/assets/constants";
|
|
import { useExplorer } from "src/hooks/useExplorer";
|
|
import { ExplorerStore } from "src/store";
|
|
import { pluralize } from "src/utils";
|
|
|
|
import FolderContent, { FolderProps } from "./Content";
|
|
import FolderExpandIcon from "./ExpandIcon";
|
|
|
|
|
|
type Props = FolderProps & {
|
|
onOpenFilesPane: () => void;
|
|
disableDrag?: boolean;
|
|
hideExpandIcon?: boolean;
|
|
disableHoverIndent?: boolean;
|
|
};
|
|
const Folder = ({
|
|
folder,
|
|
onOpenFilesPane,
|
|
hideExpandIcon = false,
|
|
disableDrag = false,
|
|
disableHoverIndent = false,
|
|
}: Props) => {
|
|
const { useExplorerStore, plugin } = useExplorer();
|
|
const { language } = plugin;
|
|
|
|
const {
|
|
setFocusedFolder,
|
|
expandFolder,
|
|
collapseFolder,
|
|
expandedFolderPaths,
|
|
focusedFolder,
|
|
hasFolderChildren,
|
|
getFilesinFolder,
|
|
getFoldersByParent,
|
|
changeViewMode,
|
|
} = useExplorerStore(
|
|
useShallow((store: ExplorerStore) => ({
|
|
setFocusedFolder: store.setFocusedFolder,
|
|
hasFolderChildren: store.hasFolderChildren,
|
|
expandedFolderPaths: store.expandedFolderPaths,
|
|
expandFolder: store.expandFolder,
|
|
collapseFolder: store.collapseFolder,
|
|
focusedFolder: store.focusedFolder,
|
|
getFilesinFolder: store.getFilesInFolder,
|
|
getFoldersByParent: store.getFoldersByParent,
|
|
changeViewMode: store.changeViewMode,
|
|
}))
|
|
);
|
|
|
|
const isFocused = folder.path == focusedFolder?.path;
|
|
const isRoot = folder.isRoot();
|
|
|
|
const {
|
|
setNodeRef: setDragRef,
|
|
attributes,
|
|
listeners,
|
|
isDragging,
|
|
} = useDraggable({
|
|
id: folder.path,
|
|
data: { type: FFS_DRAG_FOLDER, item: folder },
|
|
disabled: disableDrag,
|
|
});
|
|
|
|
const { setNodeRef: setDropRef, isOver } = useDroppable({
|
|
id: `drop-${folder.path}`,
|
|
data: {
|
|
accepts: [FFS_DRAG_FILE, FFS_DRAG_FOLDER],
|
|
item: folder,
|
|
},
|
|
disabled: disableDrag,
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (!isOver) return;
|
|
const timer = setTimeout(() => {
|
|
if (!expandedFolderPaths.includes(folder.path)) {
|
|
expandFolder(folder);
|
|
}
|
|
}, 800);
|
|
return () => clearTimeout(timer);
|
|
}, [isOver]);
|
|
|
|
useEffect(() => {
|
|
window.addEventListener("dblclick", onOpenFilesPane);
|
|
return () => {
|
|
window.removeEventListener("dblclick", onOpenFilesPane);
|
|
};
|
|
}, [onOpenFilesPane]);
|
|
|
|
const onToggleExpandState = (): void => {
|
|
const isFolderExpanded = expandedFolderPaths.includes(folder.path);
|
|
if (isFolderExpanded) {
|
|
collapseFolder(folder);
|
|
} else {
|
|
expandFolder(folder);
|
|
}
|
|
};
|
|
|
|
const maybeRenderExpandIcon = () => {
|
|
if (isRoot || hideExpandIcon) return null;
|
|
return <FolderExpandIcon folder={folder} />;
|
|
};
|
|
|
|
const getAriaLabel = () => {
|
|
const { name } = folder;
|
|
const filesCount = getFilesinFolder(folder).length;
|
|
const foldersCount = getFoldersByParent(folder).length;
|
|
|
|
const filesCountInfo = pluralize(filesCount, "file");
|
|
const foldersCountInfo = pluralize(foldersCount, "folder");
|
|
|
|
if (language === "zh") {
|
|
return `${name}\n${filesCount} 条笔记,${foldersCount} 个文件夹`;
|
|
}
|
|
return `${name}\n${filesCountInfo}, ${foldersCountInfo}`;
|
|
};
|
|
|
|
const getIndentStyle = () => {
|
|
if (disableHoverIndent) return undefined;
|
|
const folderLevel = isRoot ? 0 : folder.path.split("/").length - 1;
|
|
return {
|
|
marginInlineStart: -17 * folderLevel,
|
|
paddingInlineStart: 24 + 17 * folderLevel,
|
|
};
|
|
};
|
|
|
|
const getClassNames = () => {
|
|
return classNames(
|
|
"ffs__folder-container tree-item-self nav-folder-title is-clickable",
|
|
{
|
|
"mod-collapsible": hasFolderChildren(folder),
|
|
"is-active": isFocused,
|
|
"ffs__is-over": isOver && !disableDrag,
|
|
}
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className={getClassNames()}
|
|
ref={setDropRef}
|
|
onClick={async () => {
|
|
onToggleExpandState();
|
|
setFocusedFolder(folder);
|
|
await changeViewMode("folder");
|
|
}}
|
|
style={getIndentStyle()}
|
|
data-tooltip-position="right"
|
|
aria-label={getAriaLabel()}
|
|
>
|
|
{maybeRenderExpandIcon()}
|
|
<div
|
|
className="ffs__draggable-container tree-item-inner nav-folder-title-content"
|
|
style={{ opacity: isDragging ? 0.5 : 1 }}
|
|
ref={setDragRef}
|
|
{...attributes}
|
|
{...listeners}
|
|
>
|
|
<FolderContent
|
|
folder={folder}
|
|
onToggleExpandState={onToggleExpandState}
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Folder;
|