renamed folder database to xoonips.
This commit is contained in:
		
							
								
								
									
										109
									
								
								src/xoonips/blocks/IndexTree.module.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/xoonips/blocks/IndexTree.module.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
			
		||||
.indexTree {
 | 
			
		||||
  border-top: 1px solid #999999;
 | 
			
		||||
  border-left: 1px solid #999999;
 | 
			
		||||
  border-bottom: 1px solid #404040;
 | 
			
		||||
  border-right: 1px solid #404040;
 | 
			
		||||
  background-color: white;
 | 
			
		||||
  height: 400px;
 | 
			
		||||
  width: calc(100% - 6px);
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
  margin: 0 auto;
 | 
			
		||||
  padding: 3px;
 | 
			
		||||
  line-height: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.formButton {
 | 
			
		||||
  margin: 3px 3px 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.indexTree div span {
 | 
			
		||||
  color: #333;
 | 
			
		||||
  font-size: 12px;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  line-height: 19px;
 | 
			
		||||
  vertical-align: bottom;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.indexTree div span:hover {
 | 
			
		||||
  color: #f60;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.indexTree:global(.rc-tree .rc-tree-treenode) {
 | 
			
		||||
  line-height: 20px;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent) {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent .rc-tree-indent-unit) {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  height: 20px;
 | 
			
		||||
  width: 9px;
 | 
			
		||||
  background: url(../assets/images/tree_line.png);
 | 
			
		||||
}
 | 
			
		||||
.indexTree:global(
 | 
			
		||||
    .rc-tree .rc-tree-treenode .rc-tree-indent .rc-tree-indent-unit:not(:last-child)
 | 
			
		||||
  ) {
 | 
			
		||||
  background-position: -9px 0;
 | 
			
		||||
}
 | 
			
		||||
.indexTree:global(
 | 
			
		||||
    .rc-tree
 | 
			
		||||
      .rc-tree-treenode
 | 
			
		||||
      .rc-tree-indent
 | 
			
		||||
      .rc-tree-indent-unit:not(:last-child).rc-tree-indent-unit-end
 | 
			
		||||
  ) {
 | 
			
		||||
  background-position: -18px 0;
 | 
			
		||||
}
 | 
			
		||||
.indexTree:global(
 | 
			
		||||
    .rc-tree
 | 
			
		||||
      .rc-tree-treenode
 | 
			
		||||
      .rc-tree-indent
 | 
			
		||||
      .rc-tree-indent-unit:last-child.rc-tree-indent-unit-end
 | 
			
		||||
  ) {
 | 
			
		||||
  background-position: -27px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-switcher) {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  height: 20px;
 | 
			
		||||
  width: 16px;
 | 
			
		||||
  margin-right: 2px;
 | 
			
		||||
  background: url(../assets/images/tree_node.png);
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
.indexTree:global(.rc-tree .rc-tree-treenode:first-child .rc-tree-switcher.rc-tree-switcher-noop) {
 | 
			
		||||
  background-position: 0 0;
 | 
			
		||||
  cursor: auto;
 | 
			
		||||
}
 | 
			
		||||
.indexTree:global(.rc-tree .rc-tree-treenode:first-child .rc-tree-switcher.rc-tree-switcher_open) {
 | 
			
		||||
  background-position: -16px 0;
 | 
			
		||||
}
 | 
			
		||||
.indexTree:global(.rc-tree .rc-tree-treenode:first-child .rc-tree-switcher.rc-tree-switcher_close) {
 | 
			
		||||
  background-position: -32px 0;
 | 
			
		||||
}
 | 
			
		||||
.indexTree:global(
 | 
			
		||||
    .rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher-noop
 | 
			
		||||
  ) {
 | 
			
		||||
  background-position: 0 -20px;
 | 
			
		||||
  cursor: auto;
 | 
			
		||||
}
 | 
			
		||||
.indexTree:global(
 | 
			
		||||
    .rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher_open
 | 
			
		||||
  ) {
 | 
			
		||||
  background-position: -16px -20px;
 | 
			
		||||
}
 | 
			
		||||
.indexTree:global(
 | 
			
		||||
    .rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher_close
 | 
			
		||||
  ) {
 | 
			
		||||
  background-position: -32px -20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-node-content-wrapper) {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  height: 20px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-node-content-wrapper .rc-tree-title) {
 | 
			
		||||
  vertical-align: middle;
 | 
			
		||||
  line-height: 20px;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										134
									
								
								src/xoonips/blocks/IndexTree.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								src/xoonips/blocks/IndexTree.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
import Tree from 'rc-tree';
 | 
			
		||||
import { DataNode, EventDataNode } from 'rc-tree/lib/interface';
 | 
			
		||||
import { useNavigate } from 'react-router';
 | 
			
		||||
import Loading from '../../common/lib/Loading';
 | 
			
		||||
import { BrainAtlasType, MultiLang } from '../../config';
 | 
			
		||||
import Functions from '../../functions';
 | 
			
		||||
import IndexUtil, { INDEX_ID_PUBLIC, Index } from '../lib/IndexUtil';
 | 
			
		||||
 | 
			
		||||
import styles from './IndexTree.module.css';
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  lang: MultiLang;
 | 
			
		||||
  type: BrainAtlasType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const IndexTree: React.FC<Props> = (props) => {
 | 
			
		||||
  const { lang, type } = props;
 | 
			
		||||
  const navigate = useNavigate();
 | 
			
		||||
 | 
			
		||||
  const [tree, setTree] = React.useState<DataNode[]>([]);
 | 
			
		||||
  const [keys, setKeys] = React.useState<string[]>([]);
 | 
			
		||||
  const [expandedKeys, setExpandedKeys] = React.useState<string[]>([]);
 | 
			
		||||
  const [selectedKeys, setSelectedKeys] = React.useState<number[]>([]);
 | 
			
		||||
 | 
			
		||||
  React.useEffect(() => {
 | 
			
		||||
    const tree: DataNode[] = [];
 | 
			
		||||
    const keys: string[] = [];
 | 
			
		||||
    const eKeys: string[] = [];
 | 
			
		||||
    const makeTreeNode = (index: Index, depth: number, func: (node: DataNode) => void): void => {
 | 
			
		||||
      const title =
 | 
			
		||||
        Functions.mlang(index.title, lang) +
 | 
			
		||||
        (index.numOfItems > 0 ? ' (' + index.numOfItems + ')' : '');
 | 
			
		||||
      IndexUtil.getChildren(type, index.id, (children) => {
 | 
			
		||||
        if (children.length === 0) {
 | 
			
		||||
          func({ key: String(index.id), title: title });
 | 
			
		||||
        } else {
 | 
			
		||||
          if (depth < 1) {
 | 
			
		||||
            eKeys.push(String(index.id));
 | 
			
		||||
          }
 | 
			
		||||
          keys.push(String(index.id));
 | 
			
		||||
          const childTreeNodes: DataNode[] = [];
 | 
			
		||||
          let called = 0;
 | 
			
		||||
          children.forEach((value: Index) => {
 | 
			
		||||
            makeTreeNode(value, depth + 1, (cNode) => {
 | 
			
		||||
              called++;
 | 
			
		||||
              childTreeNodes.push(cNode);
 | 
			
		||||
              if (called === children.length) {
 | 
			
		||||
                func({ key: String(index.id), title: title, children: childTreeNodes });
 | 
			
		||||
              }
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    };
 | 
			
		||||
    IndexUtil.get(type, INDEX_ID_PUBLIC, (index) => {
 | 
			
		||||
      if (index != null) {
 | 
			
		||||
        makeTreeNode(index, 0, (node) => {
 | 
			
		||||
          tree.push(node);
 | 
			
		||||
          setTree(tree);
 | 
			
		||||
          setKeys(keys);
 | 
			
		||||
          setExpandedKeys(eKeys);
 | 
			
		||||
          setSelectedKeys([]);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }, [lang, type]);
 | 
			
		||||
 | 
			
		||||
  const handleClickOpenAll = () => {
 | 
			
		||||
    setExpandedKeys(keys);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleClickCloseAll = () => {
 | 
			
		||||
    setExpandedKeys([]);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleExpand: (
 | 
			
		||||
    expandedKeys: React.Key[],
 | 
			
		||||
    info: {
 | 
			
		||||
      node: EventDataNode<DataNode>;
 | 
			
		||||
      expanded: boolean;
 | 
			
		||||
      nativeEvent: MouseEvent;
 | 
			
		||||
    },
 | 
			
		||||
  ) => void = (expandedKeys) => {
 | 
			
		||||
    const keys: string[] = expandedKeys.map((key) => {
 | 
			
		||||
      return typeof key === 'string' ? key : String(key);
 | 
			
		||||
    });
 | 
			
		||||
    setExpandedKeys(keys);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleSelect: (
 | 
			
		||||
    selectedKeys: React.Key[],
 | 
			
		||||
    info: {
 | 
			
		||||
      event: 'select';
 | 
			
		||||
      selected: boolean;
 | 
			
		||||
      node: EventDataNode<DataNode>;
 | 
			
		||||
      selectedNodes: DataNode[];
 | 
			
		||||
      nativeEvent: MouseEvent;
 | 
			
		||||
    },
 | 
			
		||||
  ) => void = (selectedKeys) => {
 | 
			
		||||
    const selectedKey = selectedKeys.shift() ?? 0;
 | 
			
		||||
    const key = typeof selectedKey === 'string' ? parseInt(selectedKey, 10) : selectedKey;
 | 
			
		||||
    const url = IndexUtil.getUrl(type, key);
 | 
			
		||||
    navigate(url);
 | 
			
		||||
    setSelectedKeys([]);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (tree.length === 0) {
 | 
			
		||||
    return <Loading />;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={styles.container}>
 | 
			
		||||
      <button className={styles.formButton} onClick={handleClickOpenAll}>
 | 
			
		||||
        open all
 | 
			
		||||
      </button>
 | 
			
		||||
      <button className={styles.formButton} onClick={handleClickCloseAll}>
 | 
			
		||||
        close all
 | 
			
		||||
      </button>
 | 
			
		||||
      <Tree
 | 
			
		||||
        className={styles.indexTree}
 | 
			
		||||
        expandedKeys={expandedKeys}
 | 
			
		||||
        selectedKeys={selectedKeys}
 | 
			
		||||
        onExpand={handleExpand}
 | 
			
		||||
        onSelect={handleSelect}
 | 
			
		||||
        showIcon={false}
 | 
			
		||||
        treeData={tree}
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default IndexTree;
 | 
			
		||||
		Reference in New Issue
	
	Block a user