add: tree / search

This commit is contained in:
h z
2025-03-05 01:23:09 +00:00
parent 39a69ca5b8
commit 2911f8722e
4 changed files with 96 additions and 93 deletions

View File

@@ -3,23 +3,15 @@ import PathNode from "./PathNode";
import "./SideNavigation.css";
import {useDeletePath, usePaths, useUpdatePath} from "../../utils/path-queries";
import React from 'react';
import {useSearchMarkdown} from "../../utils/markdown-queries";
import MarkdownNode from "./MarkdownNode";
import {useTree} from "../../utils/tree-queries";
const SideNavigation = () => {
const {data: paths, isLoading, error } = usePaths(1);
const {data: tree, isLoading, error} = useTree();
const deletePath = useDeletePath();
const updatePath = useUpdatePath();
const [searchTerm, setSearchTerm] = React.useState("");
const [keyword, setKeyword] = React.useState("");
const [searchMode, setSearchMode] = React.useState(false);
const {data: searchResults, isLoading: isSearching} = useSearchMarkdown(keyword, {
enabled: searchMode && !!searchMode,
});
const sortedPaths = paths
? paths.slice().sort((a, b) => a.order.localeCompare(b.order))
: [];
const handleDelete = (id) => {
if (window.confirm("Are you sure you want to delete this path?")){
deletePath.mutate(id, {
@@ -30,13 +22,30 @@ const SideNavigation = () => {
}
};
const handleSearch = () => {
setSearchMode(true);
setKeyword(searchTerm);
}
const exitSearch = () => {
setSearchMode(false);
}
const filterTree = (t, k) => {
if(t === undefined)
return undefined;
if (t.type === "path") {
if (t.name.includes(k)) {
return { ...t };
}
const filteredChildren = (t.children || [])
.map(c => filterTree(c, k))
.filter(Boolean);
if (filteredChildren.length > 0) {
return { ...t, children: filteredChildren };
}
} else if (t.type === "markdown") {
if (t.title.includes(k)) {
return { ...t };
}
}
return undefined;
};
const filteredTree = filterTree(tree, keyword);
const handleSave = (id, newName) => {
updatePath.mutate({ id, data: {name: newName }} , {
@@ -45,55 +54,17 @@ const SideNavigation = () => {
}
});
};
if(!searchMode && isLoading){
return <aside className="menu"><p>Loading...</p></aside>;
}
if(searchMode && isSearching){
return <aside className="menu"><p>Loading...</p></aside>;
}
if(error){
return <aside className="menu"><p>Error...</p></aside>;
}
if (isLoading) return <aside className="menu"><p>Loading...</p></aside>;
if (error) return <aside className="menu"><p>Error loading tree</p></aside>;
return (
<aside className="menu">
<div className="field has-addons mb-2">
<div className="control is-expanded">
<input
className="input is-small"
type="text"
placeholder="Search..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</div>
<div className="control">
<button
className="button is-small is-info"
onClick={handleSearch}
disabled={!searchTerm.trim()}
type="button"
>
<span className="icon">
<i className="fa fa-search"></i>
</span>
</button>
</div>
{searchMode && (
<div className="control">
<button
className="button is-small is-danger"
onClick={exitSearch}
type="button"
>
<span className="icon">
<i className={"fa fa-window-close"}></i>
</span>
</button>
</div>
)}
<div className="control is-expanded">
<input
className="input is-small"
type="text"
placeholder="Search..."
onChange={(e) => setKeyword(e.target.value)}
/>
</div>
<PermissionGuard rolesRequired={["admin", "creator"]}>
<a
@@ -103,29 +74,17 @@ const SideNavigation = () => {
Create New Markdown
</a>
</PermissionGuard>
{searchMode ? (
<ul>
{searchResults.map((markdown, i) => (
<MarkdownNode
markdown={markdown}
handleMoveMarkdown={() => {}}
/>
))}
</ul>
) : (
<ul className="menu-list">
{isLoading && <p>Loading...</p>}
{sortedPaths.map((path) => (
<PathNode
key={path.id}
path={path}
isRoot={false}
onSave={handleSave}
onDelete={handleDelete}
/>
))}
</ul>
)}
{!filteredTree || filteredTree.length === 0 ?
<p>No Result</p> :
<PathNode
key={1}
path={filteredTree}
isRoot={true}
onSave={handleSave}
onDelete={handleDelete}
/>
}
</aside>
);