mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-06 16:04:23 +00:00
Migrate FileTree
This commit is contained in:
32
frontend/package-lock.json
generated
32
frontend/package-lock.json
generated
@@ -21,6 +21,7 @@
|
|||||||
"@mantine/hooks": "^7.13.2",
|
"@mantine/hooks": "^7.13.2",
|
||||||
"@mantine/modals": "^7.13.2",
|
"@mantine/modals": "^7.13.2",
|
||||||
"@mantine/notifications": "^7.13.2",
|
"@mantine/notifications": "^7.13.2",
|
||||||
|
"@react-hook/resize-observer": "^2.0.2",
|
||||||
"@tabler/icons-react": "^3.19.0",
|
"@tabler/icons-react": "^3.19.0",
|
||||||
"codemirror": "^6.0.1",
|
"codemirror": "^6.0.1",
|
||||||
"katex": "^0.16.11",
|
"katex": "^0.16.11",
|
||||||
@@ -2568,6 +2569,37 @@
|
|||||||
"integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==",
|
"integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-hook/latest": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-hook/latest/-/latest-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-hook/passive-layout-effect": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-hook/passive-layout-effect/-/passive-layout-effect-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-hook/resize-observer": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-hook/resize-observer/-/resize-observer-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-tzKKzxNpfE5TWmxuv+5Ae3IF58n0FQgQaWJmcbYkjXTRZATXxClnTprQ2uuYygYTpu1pqbBskpwMpj6jpT1djA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-hook/latest": "^1.0.2",
|
||||||
|
"@react-hook/passive-layout-effect": "^1.2.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tabler/icons": {
|
"node_modules/@tabler/icons": {
|
||||||
"version": "3.19.0",
|
"version": "3.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.19.0.tgz",
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
"@mantine/hooks": "^7.13.2",
|
"@mantine/hooks": "^7.13.2",
|
||||||
"@mantine/modals": "^7.13.2",
|
"@mantine/modals": "^7.13.2",
|
||||||
"@mantine/notifications": "^7.13.2",
|
"@mantine/notifications": "^7.13.2",
|
||||||
|
"@react-hook/resize-observer": "^2.0.2",
|
||||||
"@tabler/icons-react": "^3.19.0",
|
"@tabler/icons-react": "^3.19.0",
|
||||||
"codemirror": "^6.0.1",
|
"codemirror": "^6.0.1",
|
||||||
"katex": "^0.16.11",
|
"katex": "^0.16.11",
|
||||||
|
|||||||
@@ -1,65 +1,102 @@
|
|||||||
import React from 'react';
|
import React, { useRef, useState, useLayoutEffect } from 'react';
|
||||||
import { Tree } from 'react-arborist';
|
import { Tree } from 'react-arborist';
|
||||||
import { Group, Text } from '@mantine/core';
|
|
||||||
import { IconFile, IconFolder, IconFolderOpen } from '@tabler/icons-react';
|
import { IconFile, IconFolder, IconFolderOpen } from '@tabler/icons-react';
|
||||||
import { isImageFile } from '../utils/fileHelpers';
|
import { Tooltip } from '@mantine/core';
|
||||||
|
import useResizeObserver from '@react-hook/resize-observer';
|
||||||
|
|
||||||
const FileIcon = ({ isFolder, isOpen }) => {
|
const useSize = (target) => {
|
||||||
if (isFolder) {
|
const [size, setSize] = useState();
|
||||||
return isOpen ? (
|
|
||||||
<IconFolderOpen size={16} color="var(--mantine-color-yellow-filled)" />
|
useLayoutEffect(() => {
|
||||||
) : (
|
setSize(target.current.getBoundingClientRect());
|
||||||
<IconFolder size={16} color="var(--mantine-color-yellow-filled)" />
|
}, [target]);
|
||||||
);
|
|
||||||
|
useResizeObserver(target, (entry) => setSize(entry.contentRect));
|
||||||
|
return size;
|
||||||
|
};
|
||||||
|
|
||||||
|
const FileIcon = ({ node }) => {
|
||||||
|
if (node.isLeaf) {
|
||||||
|
return <IconFile size={16} />;
|
||||||
}
|
}
|
||||||
return <IconFile size={16} />;
|
return node.isOpen ? (
|
||||||
|
<IconFolderOpen size={16} color="var(--mantine-color-yellow-filled)" />
|
||||||
|
) : (
|
||||||
|
<IconFolder size={16} color="var(--mantine-color-yellow-filled)" />
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Node = ({ node, style, dragHandle }) => {
|
const Node = ({ node, style, dragHandle }) => {
|
||||||
const isFolder = Array.isArray(node.data.children);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Group
|
<Tooltip label={node.data.name} openDelay={500}>
|
||||||
ref={dragHandle}
|
<div
|
||||||
style={style}
|
ref={dragHandle}
|
||||||
pl={node.level * 20}
|
style={{
|
||||||
py={4}
|
...style,
|
||||||
onClick={() => node.toggle()}
|
paddingLeft: `${node.level * 20}px`,
|
||||||
sx={(theme) => ({
|
display: 'flex',
|
||||||
cursor: 'pointer',
|
alignItems: 'center',
|
||||||
'&:hover': {
|
cursor: 'pointer',
|
||||||
backgroundColor:
|
whiteSpace: 'nowrap',
|
||||||
theme.colorScheme === 'dark'
|
overflow: 'hidden',
|
||||||
? theme.colors.dark[6]
|
}}
|
||||||
: theme.colors.gray[0],
|
onClick={() => {
|
||||||
},
|
if (node.isInternal) {
|
||||||
})}
|
node.toggle();
|
||||||
>
|
} else {
|
||||||
<FileIcon isFolder={isFolder} isOpen={node.isOpen} />
|
node.tree.props.onNodeClick(node);
|
||||||
<Text size="sm">{node.data.name}</Text>
|
}
|
||||||
</Group>
|
}}
|
||||||
|
>
|
||||||
|
<FileIcon node={node} />
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
marginLeft: '8px',
|
||||||
|
fontSize: '14px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
flexGrow: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{node.data.name}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const FileTree = ({ files, handleFileSelect }) => {
|
const FileTree = ({ files, handleFileSelect }) => {
|
||||||
const handleNodeClick = (node) => {
|
const target = useRef(null);
|
||||||
if (!node.isInternal) {
|
const size = useSize(target);
|
||||||
handleFileSelect(node.data.path);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tree
|
<div
|
||||||
data={files}
|
ref={target}
|
||||||
openByDefault={false}
|
style={{ height: 'calc(100vh - 140px)', marginTop: '20px' }}
|
||||||
width="100%"
|
|
||||||
height={400} // Adjust this value as needed
|
|
||||||
indent={24}
|
|
||||||
rowHeight={28}
|
|
||||||
onActivate={handleNodeClick}
|
|
||||||
>
|
>
|
||||||
{Node}
|
{size && (
|
||||||
</Tree>
|
<Tree
|
||||||
|
data={files}
|
||||||
|
openByDefault={false}
|
||||||
|
width={size.width}
|
||||||
|
height={size.height}
|
||||||
|
indent={24}
|
||||||
|
rowHeight={28}
|
||||||
|
onActivate={(node) => {
|
||||||
|
if (!node.isInternal) {
|
||||||
|
handleFileSelect(node.data.path);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onNodeClick={(node) => {
|
||||||
|
if (!node.isInternal) {
|
||||||
|
handleFileSelect(node.data.path);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Node}
|
||||||
|
</Tree>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user