flow: resource tree

This commit is contained in:
cha0s 2020-06-28 10:43:26 -05:00
parent b6b715dc87
commit 36fd1184f6
3 changed files with 124 additions and 18 deletions

View File

@ -49,6 +49,7 @@ html {
background-color: #212121; background-color: #212121;
color: #FFFFFF; color: #FFFFFF;
--active-color: rgb(0, 180, 204); --active-color: rgb(0, 180, 204);
--title-font-family: Ubuntu, "Droid Sans", sans-serif;
} }
body { body {
scrollbar-width: thin; scrollbar-width: thin;
@ -152,7 +153,7 @@ select {
.react-tabs__tab-list { .react-tabs__tab-list {
background-color: #272727; background-color: #272727;
font-family: Ubuntu, "Droid Sans", sans-serif; font-family: var(--title-font-family);
font-size: 0.9em; font-size: 0.9em;
overflow-x: hidden; overflow-x: hidden;
scrollbar-width: thin; scrollbar-width: thin;

View File

@ -1,8 +1,9 @@
import {compose} from '@avocado/core'; import {compose} from '@avocado/core';
import classnames from 'classnames';
import contempo from 'contempo'; import contempo from 'contempo';
import React, {useState} from 'react'; import React, {useState} from 'react';
import {useDispatch} from 'react-redux'; import {useDispatch} from 'react-redux';
import SortableTree, {changeNodeAtPath, getTreeFromFlatData} from 'react-sortable-tree'; import SortableTree, {changeNodeAtPath, getTreeFromFlatData, toggleExpandedForAll} from 'react-sortable-tree';
import ResourcesPacket from '~/common/packets/resources.packet'; import ResourcesPacket from '~/common/packets/resources.packet';
@ -18,18 +19,56 @@ const decorate = compose(
const rootUri = '/resources/cha0s/initial'; const rootUri = '/resources/cha0s/initial';
const sortTree = (tree) => { const sortTree = (tree) => tree
tree.sort((l, r) => l.title.localeCompare(r.title)); .sort((l, r) => l.title.localeCompare(r.title))
if (tree.children) { .map((node) => {
// eslint-disable-next-line no-param-reassign if (node.children) {
tree.children = sortTree(tree.children); // eslint-disable-next-line no-param-reassign
} node.children = sortTree(node.children);
return tree; }
}; return node;
});
const mapComponents = (tree) => tree.map((node) => ({
...node,
children: node.children ? mapComponents(node.children) : [],
rawTitle: node.title,
title: (
<span
className={classnames(
'title',
node.uri ? 'resource' : 'directory',
)}
>
{node.uri && (
<svg
height="1em"
viewBox="0 0 512 512"
width="1em"
>
<path
d="M 511.867188 247.648438 C 511.859375 247.4375 511.832031 247.230469 511.816406 247.015625 C 509.542969 181.140625 482.460938 119.558594 435.269531 73.253906 C 387.125 26.015625 323.460938 0 256 0 C 187.621094 0 123.332031 26.628906 74.980469 74.980469 C 26.628906 123.332031 0 187.621094 0 256 C 0 290.847656 28.351562 319.199219 63.199219 319.199219 C 98.050781 319.199219 126.398438 290.847656 126.398438 256 C 126.398438 157.960938 206.160156 78.199219 304.199219 78.199219 C 401.40625 78.199219 479.480469 154.28125 481.941406 251.402344 C 481.941406 251.449219 481.949219 251.496094 481.953125 251.542969 C 481.980469 253.027344 482 254.519531 482 256 C 482 380.617188 380.617188 482 256 482 C 247.714844 482 241 488.714844 241 497 C 241 505.285156 247.714844 512 256 512 C 324.378906 512 388.667969 485.371094 437.019531 437.019531 C 485.371094 388.667969 512 324.378906 512 256 C 512 253.21875 511.957031 250.410156 511.867188 247.648438 Z M 511.867188 247.648438 "
/>
</svg>
)}
<span className="text">{node.title}</span>
</span>
),
}));
const unmapComponents = (tree) => tree.map((node) => ({
...node,
children: node.children ? unmapComponents(node.children) : [],
title: node.rawTitle || node.title,
}));
const Sidebar = () => { const Sidebar = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [treeData, setTreeData] = useState([]); const [treeData, setTreeDataInternal] = useState([]);
// eslint-disable-next-line no-shadow
const setTreeData = (treeData) => {
setTreeDataInternal(sortTree(unmapComponents(treeData)));
};
useSocket((socket) => socket.send(new ResourcesPacket(), (uris) => { useSocket((socket) => socket.send(new ResourcesPacket(), (uris) => {
const visited = {}; const visited = {};
const nodes = uris const nodes = uris
@ -60,17 +99,17 @@ const Sidebar = () => {
visited[node.id] = true; visited[node.id] = true;
return true; return true;
}); });
setTreeData(sortTree(getTreeFromFlatData({ setTreeData(getTreeFromFlatData({
flatData: nodes, flatData: nodes,
rootKey: '', rootKey: '',
}))); }));
})); }));
return ( return (
<div className="sidebar"> <div className="sidebar">
<SortableTree <SortableTree
canNodeHaveChildren={(node) => !node.uri} canNodeHaveChildren={(node) => !node.uri}
generateNodeProps={({node}) => ({ generateNodeProps={({node}) => ({
onClick: () => { onClick: (event) => {
if (node.uri) { if (node.uri) {
dispatch(setActiveResourceUri(node.uri)); dispatch(setActiveResourceUri(node.uri));
} }
@ -81,17 +120,21 @@ const Sidebar = () => {
path: node.id.split('/'), path: node.id.split('/'),
newNode: { newNode: {
...node, ...node,
children: (event.ctrlKey && event.altKey)
? toggleExpandedForAll({treeData: node.children, expanded: !isExpanded})
: node.children,
expanded: !isExpanded, expanded: !isExpanded,
}, },
getNodeKey: ({node: {id}}) => id, getNodeKey: ({node: {title}}) => title,
})); }));
} }
}, },
})} })}
// eslint-disable-next-line no-shadow // eslint-disable-next-line no-shadow
onChange={(treeData) => setTreeData(sortTree(treeData))} onChange={(treeData) => setTreeData(treeData)}
scaffoldBlockPxWidth={20}
theme={FileExplorerTheme} theme={FileExplorerTheme}
treeData={treeData} treeData={mapComponents(treeData)}
/> />
</div> </div>
); );

View File

@ -1,6 +1,6 @@
:scope { :scope {
background-color: #242424; background-color: #242424;
padding: 1em; padding: 0.5em;
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
@ -9,6 +9,68 @@
box-shadow: none; box-shadow: none;
} }
.rstcustom__lineBlock {
border-left: 1px solid #666666;
height: 1.6em;
left: 2px;
}
.rstcustom__row {
left: -1.5em;
padding: 0.25em 0;
}
.rstcustom__rowWrapper { .rstcustom__rowWrapper {
cursor: pointer; cursor: pointer;
padding-left: 0.5em;
&:hover {
opacity: 1;
}
> div > .rstcustom__lineBlock:nth-last-of-type(2) {
border-left: none;
}
}
.rstcustom__rowLabel {
font-size: 0.9em;
.title {
align-items: center;
color: #ffffff;
display: flex;
font-family: var(--title-font-family);
padding: 0.25em 0 0;
svg {
fill: #aaaaaa;
}
&.directory {
left: 1.5em;
position: relative;
}
}
.resource .text {
margin-left: 0.5em;
}
}
.rstcustom__node {
&:hover {
background-color: rgba(0, 0, 0, 0.05);
}
button {
top: 0.75em;
transform: translate3d(-33%, -50%, 0) scale(0.75);
}
}
.rstcustom__collapseButton,
.rstcustom__expandButton {
&:focus {
box-shadow: none;
}
&::after {
border-top-color: #999999;
&:hover {
border-top-color: #999999;
}
}
} }