mirror of
https://github.com/xuquan-nikkkki/FolderFile-Splitter-Plugin.git
synced 2026-07-22 12:00:27 +00:00
feat: simplify click to expand folder/tag logic
This commit is contained in:
parent
0080382154
commit
949b0b351b
15 changed files with 64 additions and 161 deletions
|
|
@ -136,7 +136,6 @@ export class SettingTab extends PluginSettingTab {
|
|||
|
||||
initFolderAndFileBehaviorSettings() {
|
||||
this.createHeader2(this.headersCopy.folderAndFileBehavior);
|
||||
this._initDropdownSetting("expandFolderByClickingOn");
|
||||
this._initToggleSetting("hideRootFolder");
|
||||
this._initToggleSetting("showFolderHierarchyLines");
|
||||
this._initToggleSetting("openDestinationFolderAfterMove");
|
||||
|
|
|
|||
|
|
@ -6,9 +6,8 @@ import { ChevronRight } from "src/assets/icons";
|
|||
type Props = {
|
||||
isExpanded: boolean;
|
||||
hideIcon: boolean;
|
||||
onClickExpandIcon: (e: React.MouseEvent<HTMLDivElement>) => void;
|
||||
};
|
||||
const ExpandIcon = ({ isExpanded, hideIcon, onClickExpandIcon }: Props) => {
|
||||
const ExpandIcon = ({ isExpanded, hideIcon }: Props) => {
|
||||
let content: ReactNode;
|
||||
if (hideIcon) {
|
||||
content = null;
|
||||
|
|
@ -23,7 +22,6 @@ const ExpandIcon = ({ isExpanded, hideIcon, onClickExpandIcon }: Props) => {
|
|||
className={classNames("tree-item-icon collapse-icon", {
|
||||
"is-collapsed": !isExpanded,
|
||||
})}
|
||||
onClick={onClickExpandIcon}
|
||||
>
|
||||
{content}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@ import { useEffect, useRef, useState } from "react";
|
|||
|
||||
import { ExplorerStore } from "src/store";
|
||||
import { FolderListModal } from "../FolderListModal";
|
||||
import {
|
||||
useShowFolderIcon,
|
||||
useExpandFolderByClickingOnElement,
|
||||
} from "src/hooks/useSettingsHandler";
|
||||
import { useShowFolderIcon } from "src/hooks/useSettingsHandler";
|
||||
import FilesCount from "./FilesCount";
|
||||
import useRenderEditableName from "src/hooks/useRenderEditableName";
|
||||
import { FOLDER_OPERATION_COPY } from "src/locales";
|
||||
|
|
@ -38,7 +35,7 @@ const FolderContent = ({ folder, onToggleExpandState }: Props) => {
|
|||
renameFolder,
|
||||
latestCreatedFolder,
|
||||
latestFolderCreatedTime,
|
||||
getNameOfFolder
|
||||
getNameOfFolder,
|
||||
} = useExplorerStore(
|
||||
useShallow((store: ExplorerStore) => ({
|
||||
focusedFolder: store.focusedFolder,
|
||||
|
|
@ -53,7 +50,7 @@ const FolderContent = ({ folder, onToggleExpandState }: Props) => {
|
|||
renameFolder: store.renameFolder,
|
||||
latestCreatedFolder: store.latestCreatedFolder,
|
||||
latestFolderCreatedTime: store.latestFolderCreatedTime,
|
||||
getNameOfFolder: store.getNameOfFolder
|
||||
getNameOfFolder: store.getNameOfFolder,
|
||||
}))
|
||||
);
|
||||
|
||||
|
|
@ -62,9 +59,7 @@ const FolderContent = ({ folder, onToggleExpandState }: Props) => {
|
|||
|
||||
const { settings } = plugin;
|
||||
const { showFolderIcon } = useShowFolderIcon(settings.showFolderIcon);
|
||||
const { expandFolderByClickingOn } = useExpandFolderByClickingOnElement(
|
||||
settings.expandFolderByClickingOn
|
||||
);
|
||||
|
||||
const isFocused = folder.path == focusedFolder?.path;
|
||||
|
||||
const onSaveName = (name: string) => renameFolder(folder, name);
|
||||
|
|
@ -210,15 +205,6 @@ const FolderContent = ({ folder, onToggleExpandState }: Props) => {
|
|||
menu.showAtPosition({ x: e.clientX, y: e.clientY });
|
||||
};
|
||||
|
||||
const onClickFolderName = (e: React.MouseEvent<HTMLDivElement>): void => {
|
||||
e.stopPropagation();
|
||||
if (focusedFolder?.path !== folder.path) {
|
||||
setFocusedFolder(folder);
|
||||
} else if (expandFolderByClickingOn === "folder") {
|
||||
onToggleExpandState();
|
||||
}
|
||||
};
|
||||
|
||||
const maybeRenderFolderIcon = () => {
|
||||
if (!showFolderIcon) return null;
|
||||
const className = classNames("ffs__folder-icon", {
|
||||
|
|
@ -237,11 +223,7 @@ const FolderContent = ({ folder, onToggleExpandState }: Props) => {
|
|||
};
|
||||
|
||||
const renderTitleContent = () => (
|
||||
<div
|
||||
ref={folderRef}
|
||||
className="ffs__folder-content--main"
|
||||
onClick={onClickFolderName}
|
||||
>
|
||||
<div ref={folderRef} className="ffs__folder-content--main">
|
||||
{maybeRenderFolderIcon()}
|
||||
{renderFolderName()}
|
||||
<FilesCount folder={folder} />
|
||||
|
|
@ -254,7 +236,6 @@ const FolderContent = ({ folder, onToggleExpandState }: Props) => {
|
|||
onContextMenu={onShowContextMenu}
|
||||
onClick={(e) => {
|
||||
if (isFocused) {
|
||||
e.stopPropagation();
|
||||
folderRef.current?.focus();
|
||||
setIsFocusing(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,56 +2,28 @@ import { TFolder } from "obsidian";
|
|||
import { useShallow } from "zustand/react/shallow";
|
||||
|
||||
import { ExplorerStore } from "src/store";
|
||||
import { useExpandFolderByClickingOnElement } from "src/hooks/useSettingsHandler";
|
||||
import { useExplorer } from "src/hooks/useExplorer";
|
||||
import ExpandIcon from "../ExpandIcon";
|
||||
import { uniq } from "src/utils";
|
||||
|
||||
type Props = {
|
||||
folder: TFolder;
|
||||
};
|
||||
const FolderExpandIcon = ({ folder }: Props) => {
|
||||
const { useExplorerStore, plugin } = useExplorer();
|
||||
const { settings } = plugin;
|
||||
const { useExplorerStore } = useExplorer();
|
||||
|
||||
const {
|
||||
hasFolderChildren,
|
||||
expandedFolderPaths,
|
||||
changeExpandedFolderPaths,
|
||||
} = useExplorerStore(
|
||||
const { hasFolderChildren, expandedFolderPaths } = useExplorerStore(
|
||||
useShallow((store: ExplorerStore) => ({
|
||||
hasFolderChildren: store.hasFolderChildren,
|
||||
expandedFolderPaths: store.expandedFolderPaths,
|
||||
changeExpandedFolderPaths: store.changeExpandedFolderPaths,
|
||||
}))
|
||||
);
|
||||
|
||||
const { expandFolderByClickingOn } = useExpandFolderByClickingOnElement(
|
||||
settings.expandFolderByClickingOn
|
||||
);
|
||||
|
||||
const isFolderExpanded = expandedFolderPaths.includes(folder.path);
|
||||
|
||||
const onToggleExpandState = (): void => {
|
||||
if (hasFolderChildren(folder)) {
|
||||
const folderPaths = isFolderExpanded
|
||||
? expandedFolderPaths.filter((path) => path !== folder.path)
|
||||
: uniq([...expandedFolderPaths, folder.path]);
|
||||
changeExpandedFolderPaths(folderPaths);
|
||||
}
|
||||
};
|
||||
|
||||
const onClickExpandIcon = (e: React.MouseEvent<HTMLDivElement>): void => {
|
||||
if (expandFolderByClickingOn !== "icon") return;
|
||||
e.stopPropagation();
|
||||
onToggleExpandState();
|
||||
};
|
||||
|
||||
return (
|
||||
<ExpandIcon
|
||||
isExpanded={isFolderExpanded}
|
||||
hideIcon={!hasFolderChildren(folder)}
|
||||
onClickExpandIcon={onClickExpandIcon}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -140,7 +140,10 @@ const Folder = ({
|
|||
<div
|
||||
className={getClassNames()}
|
||||
ref={setDropRef}
|
||||
onClick={() => setFocusedFolder(folder)}
|
||||
onClick={() => {
|
||||
onToggleExpandState();
|
||||
setFocusedFolder(folder);
|
||||
}}
|
||||
style={getIndentStyle()}
|
||||
data-tooltip-position="right"
|
||||
aria-label={getAriaLabel()}
|
||||
|
|
|
|||
|
|
@ -132,7 +132,6 @@ const TagContent = ({ tag }: Props) => {
|
|||
onContextMenu={onShowContextMenu}
|
||||
onClick={(e) => {
|
||||
if (isFocused) {
|
||||
e.stopPropagation();
|
||||
tagRef.current?.focus();
|
||||
setIsFocusing(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,54 +1,29 @@
|
|||
import { useShallow } from "zustand/react/shallow";
|
||||
|
||||
import { ExplorerStore } from "src/store";
|
||||
import { useExpandFolderByClickingOnElement } from "src/hooks/useSettingsHandler";
|
||||
import { useExplorer } from "src/hooks/useExplorer";
|
||||
import ExpandIcon from "../ExpandIcon";
|
||||
import { TagNode } from "src/store/tag";
|
||||
import { uniq } from "src/utils";
|
||||
|
||||
type Props = {
|
||||
tag: TagNode;
|
||||
};
|
||||
const TagExpandIcon = ({ tag }: Props) => {
|
||||
const { useExplorerStore, plugin } = useExplorer();
|
||||
const { settings } = plugin;
|
||||
const { useExplorerStore } = useExplorer();
|
||||
|
||||
const { hasTagChildren, expandedTagPaths, changeExpandedTagPaths } =
|
||||
useExplorerStore(
|
||||
useShallow((store: ExplorerStore) => ({
|
||||
hasTagChildren: store.hasTagChildren,
|
||||
expandedTagPaths: store.expandedTagPaths,
|
||||
changeExpandedTagPaths: store.changeExpandedTagPaths,
|
||||
}))
|
||||
);
|
||||
|
||||
const { expandFolderByClickingOn } = useExpandFolderByClickingOnElement(
|
||||
settings.expandFolderByClickingOn
|
||||
const { hasTagChildren, expandedTagPaths } = useExplorerStore(
|
||||
useShallow((store: ExplorerStore) => ({
|
||||
hasTagChildren: store.hasTagChildren,
|
||||
expandedTagPaths: store.expandedTagPaths,
|
||||
}))
|
||||
);
|
||||
|
||||
const isTagExpanded = expandedTagPaths.includes(tag.fullPath);
|
||||
|
||||
const onToggleExpandState = (): void => {
|
||||
if (hasTagChildren(tag)) {
|
||||
const tagPaths = isTagExpanded
|
||||
? expandedTagPaths.filter((path) => path !== tag.fullPath)
|
||||
: uniq([...expandedTagPaths, tag.fullPath]);
|
||||
changeExpandedTagPaths(tagPaths);
|
||||
}
|
||||
};
|
||||
|
||||
const onClickExpandIcon = (e: React.MouseEvent<HTMLDivElement>): void => {
|
||||
if (expandFolderByClickingOn !== "icon") return;
|
||||
e.stopPropagation();
|
||||
onToggleExpandState();
|
||||
};
|
||||
|
||||
return (
|
||||
<ExpandIcon
|
||||
isExpanded={isTagExpanded}
|
||||
hideIcon={!hasTagChildren(tag)}
|
||||
onClickExpandIcon={onClickExpandIcon}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ const Tag = ({
|
|||
focusedTag,
|
||||
getFilesInTag,
|
||||
getTagsByParent,
|
||||
expandedTagPaths,
|
||||
collapseTag,
|
||||
expandTag,
|
||||
} = useExplorerStore(
|
||||
useShallow((store: ExplorerStore) => ({
|
||||
hasTagChildren: store.hasTagChildren,
|
||||
|
|
@ -34,8 +37,21 @@ const Tag = ({
|
|||
focusedTag: store.focusedTag,
|
||||
getTagsByParent: store.getTagsByParent,
|
||||
getFilesInTag: store.getFilesInTag,
|
||||
expandedTagPaths: store.expandedTagPaths,
|
||||
collapseTag: store.collapseTag,
|
||||
expandTag: store.expandTag,
|
||||
}))
|
||||
);
|
||||
|
||||
const onToggleExpandState = (): void => {
|
||||
const isFolderExpanded = expandedTagPaths.includes(tag.fullPath);
|
||||
if (isFolderExpanded) {
|
||||
collapseTag(tag);
|
||||
} else {
|
||||
expandTag(tag);
|
||||
}
|
||||
};
|
||||
|
||||
const isFocused = tag.fullPath == focusedTag?.fullPath;
|
||||
|
||||
const getAriaLabel = () => {
|
||||
|
|
@ -75,7 +91,10 @@ const Tag = ({
|
|||
<div
|
||||
className={getClassNames()}
|
||||
style={getIndentStyle()}
|
||||
onClick={() => setFocusedTag(tag)}
|
||||
onClick={() => {
|
||||
setFocusedTag(tag);
|
||||
onToggleExpandState();
|
||||
}}
|
||||
data-tooltip-position="right"
|
||||
aria-label={getAriaLabel()}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { useShowFolderIcon } from "./useShowFolderIcon";
|
||||
import { useExpandFolderByClickingOnElement } from "./useExpandFolderByClickingOnEle";
|
||||
import { useIncludeSubfolderFiles } from "./useIncludeSubfolderFiles";
|
||||
import { useShowFileDetail } from "./useShowFileDetail";
|
||||
import { useShowHierarchyLines } from "./useShowHierarchyLines";
|
||||
|
|
@ -22,7 +21,6 @@ import { useShowTagIcon } from "./useShowTagIcon";
|
|||
|
||||
export {
|
||||
useShowFolderIcon,
|
||||
useExpandFolderByClickingOnElement,
|
||||
useIncludeSubfolderFiles,
|
||||
useShowFileDetail,
|
||||
useShowHierarchyLines,
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
import { useState } from "react";
|
||||
|
||||
import { ExpandFolderByClickingOnElement } from "src/settings";
|
||||
import { useWatchSettingsChange } from "./useWatchSettingsChange";
|
||||
|
||||
export const useExpandFolderByClickingOnElement = (
|
||||
defaultClickingOnElement: ExpandFolderByClickingOnElement
|
||||
): { expandFolderByClickingOn: ExpandFolderByClickingOnElement } => {
|
||||
const [expandFolderByClickingOn, setExpandFolderByClickingOn] = useState(
|
||||
defaultClickingOnElement
|
||||
);
|
||||
|
||||
const onChangeShowFolderIcon = (event: CustomEvent) => {
|
||||
const { changeKey, changeValue } = event.detail;
|
||||
if (changeKey == "expandFolderByClickingOn") {
|
||||
setExpandFolderByClickingOn(changeValue);
|
||||
}
|
||||
};
|
||||
|
||||
useWatchSettingsChange(onChangeShowFolderIcon);
|
||||
|
||||
return { expandFolderByClickingOn };
|
||||
};
|
||||
|
|
@ -123,20 +123,6 @@ export const EN_SETTINGS: SettingsLocaleResource = {
|
|||
name: "Auto-hide action bar",
|
||||
desc: "When enabled, the top action bar will be hidden by default and only appear when hovering over it.",
|
||||
},
|
||||
expandFolderByClickingOn: {
|
||||
name: "Expand folder/tag on click",
|
||||
desc: "Choose whether to expand a folder/tag by clicking on the toggle icon (▶/▼) or the folder/tag name.",
|
||||
options: [
|
||||
{
|
||||
value: EXPAND_FOLDER_BY_CLICKING_ELEMENT.ICON,
|
||||
text: "Toggle Icon",
|
||||
},
|
||||
{
|
||||
value: EXPAND_FOLDER_BY_CLICKING_ELEMENT.FOLDER,
|
||||
text: "Folder/Tag Name",
|
||||
},
|
||||
],
|
||||
},
|
||||
includeSubfolderFiles: {
|
||||
name: "Include subfolder files",
|
||||
desc: "When enabled, files inside subfolders will be included in the file list and their count will be reflected in the folder’s file count.",
|
||||
|
|
@ -293,20 +279,6 @@ export const ZH_SETTINGS: SettingsLocaleResource = {
|
|||
name: "自动隐藏操作栏",
|
||||
desc: "启用后,顶部操作栏默认隐藏,鼠标悬停时才会显示。",
|
||||
},
|
||||
expandFolderByClickingOn: {
|
||||
name: "点击展开文件夹/标签",
|
||||
desc: "选择通过点击切换图标(▶/▼)或文件夹/标签名称来展开文件夹/标签。",
|
||||
options: [
|
||||
{
|
||||
value: EXPAND_FOLDER_BY_CLICKING_ELEMENT.ICON,
|
||||
text: "切换图标",
|
||||
},
|
||||
{
|
||||
value: EXPAND_FOLDER_BY_CLICKING_ELEMENT.FOLDER,
|
||||
text: "文件夹/标签名称",
|
||||
},
|
||||
],
|
||||
},
|
||||
includeSubfolderFiles: {
|
||||
name: "包含子文件夹文件",
|
||||
desc: "启用后,子文件夹中的文件将会显示在文件列表中,并计入所属文件夹的文件数量。",
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ export default class FolderFileSplitterPlugin extends Plugin {
|
|||
);
|
||||
|
||||
await this.loadSettings();
|
||||
console.log("settings", this.settings.expandFolderByClickingOn)
|
||||
|
||||
this.addCommand({
|
||||
id: "open-file-tree-view",
|
||||
|
|
|
|||
|
|
@ -1,13 +1,5 @@
|
|||
type ValueOf<T> = T[keyof T];
|
||||
|
||||
export const EXPAND_FOLDER_BY_CLICKING_ELEMENT = {
|
||||
ICON: "icon",
|
||||
FOLDER: "folder",
|
||||
} as const;
|
||||
export type ExpandFolderByClickingOnElement = ValueOf<
|
||||
typeof EXPAND_FOLDER_BY_CLICKING_ELEMENT
|
||||
>;
|
||||
|
||||
export const LAYOUT_MODE = {
|
||||
HORIZONTAL_SPLIT: "Horizontal split",
|
||||
VERTICAL_SPLIT: "Vertical split",
|
||||
|
|
@ -40,7 +32,6 @@ export type FolderNoteMissingBehavior = ValueOf<
|
|||
export const DEFAULT_FILE_CREATION_DATE_FORMAT = "YYYY/MM/DD";
|
||||
|
||||
export interface FolderFileSplitterPluginSettings {
|
||||
expandFolderByClickingOn: ExpandFolderByClickingOnElement;
|
||||
includeSubfolderFiles: boolean;
|
||||
showFolderHierarchyLines: boolean;
|
||||
showFolderIcon: boolean;
|
||||
|
|
@ -70,7 +61,6 @@ export interface FolderFileSplitterPluginSettings {
|
|||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: FolderFileSplitterPluginSettings = {
|
||||
expandFolderByClickingOn: EXPAND_FOLDER_BY_CLICKING_ELEMENT.FOLDER,
|
||||
includeSubfolderFiles: false,
|
||||
showFolderHierarchyLines: false,
|
||||
showFolderIcon: true,
|
||||
|
|
|
|||
|
|
@ -95,8 +95,8 @@ export type FolderExplorerStore = {
|
|||
) => Promise<void>;
|
||||
moveFolder: (folder: TFolder, newPath: string) => Promise<void>;
|
||||
renameFolder: (folder: TFolder, newName: string) => Promise<void>;
|
||||
expandFolder: (folder: TFolder) => void;
|
||||
collapseFolder: (folder: TFolder) => void;
|
||||
expandFolder: (folder: TFolder) => Promise<void>;
|
||||
collapseFolder: (folder: TFolder) => Promise<void>;
|
||||
updateFolderPinState: (oldPath: string, newPath: string) => Promise<void>;
|
||||
getNameOfFolder: (folder: TFolder) => string;
|
||||
};
|
||||
|
|
@ -609,25 +609,25 @@ export const createFolderExplorerStore =
|
|||
const newPath = folder.path.replace(folder.name, newName);
|
||||
await moveFolder(folder, newPath);
|
||||
},
|
||||
expandFolder: (folder: TFolder) => {
|
||||
expandFolder: async (folder: TFolder) => {
|
||||
const {
|
||||
changeExpandedFolderPaths,
|
||||
expandedFolderPaths,
|
||||
hasFolderChildren,
|
||||
} = get();
|
||||
if (!hasFolderChildren(folder) || folder.isRoot()) return;
|
||||
changeExpandedFolderPaths(
|
||||
await changeExpandedFolderPaths(
|
||||
uniq([...expandedFolderPaths, folder.path])
|
||||
);
|
||||
},
|
||||
collapseFolder: (folder: TFolder) => {
|
||||
collapseFolder: async(folder: TFolder) => {
|
||||
const {
|
||||
changeExpandedFolderPaths,
|
||||
hasFolderChildren,
|
||||
expandedFolderPaths,
|
||||
} = get();
|
||||
if (!hasFolderChildren(folder) || folder.isRoot()) return;
|
||||
changeExpandedFolderPaths(
|
||||
await changeExpandedFolderPaths(
|
||||
expandedFolderPaths.filter((path) => path !== folder.path)
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
FFS_FOCUSED_TAG_PATH_KEY,
|
||||
FFS_PINNED_TAG_PATHS_KEY,
|
||||
} from "src/assets/constants";
|
||||
import { uniq } from "src/utils";
|
||||
|
||||
type FolderPath = string;
|
||||
type ChildrenPaths = string[];
|
||||
|
|
@ -50,6 +51,8 @@ export type TagExplorerStore = {
|
|||
|
||||
changeExpandedTagPaths: (paths: string[]) => Promise<void>;
|
||||
restoreExpandedTagPaths: () => Promise<void>;
|
||||
expandTag: (tag: TagNode) => Promise<void>;
|
||||
collapseTag: (tag: TagNode) => Promise<void>;
|
||||
|
||||
_setFocusedTag: (tag: TagNode | null) => void;
|
||||
setFocusedTag: (folder: TagNode | null) => Promise<void>;
|
||||
|
|
@ -230,6 +233,22 @@ export const createTagExplorerStore =
|
|||
);
|
||||
},
|
||||
|
||||
expandTag: async (tag: TagNode) => {
|
||||
const { changeExpandedTagPaths, expandedTagPaths, hasTagChildren } =
|
||||
get();
|
||||
if (!hasTagChildren(tag)) return;
|
||||
await changeExpandedTagPaths(uniq([...expandedTagPaths, tag.fullPath]));
|
||||
},
|
||||
|
||||
collapseTag: async (tag: TagNode) => {
|
||||
const { changeExpandedTagPaths, hasTagChildren, expandedTagPaths } =
|
||||
get();
|
||||
if (!hasTagChildren(tag)) return;
|
||||
await changeExpandedTagPaths(
|
||||
expandedTagPaths.filter((path) => path !== tag.fullPath)
|
||||
);
|
||||
},
|
||||
|
||||
restoreExpandedTagPaths: async () => {
|
||||
const { getDataFromLocalStorage, hasTagChildren, tagTree } = get();
|
||||
const lastExpandedTagPaths = getDataFromLocalStorage(
|
||||
|
|
|
|||
Loading…
Reference in a new issue