Просмотр исходного кода

Merge pull request #4627 from weseek/feat/add-items-to-pt

feat: Add items to pt
Yuki Takei 4 лет назад
Родитель
Сommit
4c5a6c5f4c

+ 6 - 7
packages/app/src/components/Sidebar/PageTree.tsx

@@ -1,12 +1,10 @@
-import React, { FC } from 'react';
+import React, { FC, memo } from 'react';
 import { useTranslation } from 'react-i18next';
 
+import ItemsTree from './PageTree/ItemsTree';
 
-type Props = {
-}
-
-const PageTree:FC<Props> = (props: Props) => {
 
+const PageTree: FC = memo(() => {
   const { t } = useTranslation();
 
   return (
@@ -14,11 +12,12 @@ const PageTree:FC<Props> = (props: Props) => {
       <div className="grw-sidebar-content-header p-3 d-flex">
         <h3 className="mb-0">{t('Page Tree')}</h3>
       </div>
+
       <div className="grw-sidebar-content-body p-3">
-        TBD
+        <ItemsTree />
       </div>
     </>
   );
-};
+});
 
 export default PageTree;

+ 45 - 0
packages/app/src/components/Sidebar/PageTree/Item.tsx

@@ -0,0 +1,45 @@
+import React, { memo } from 'react';
+import { ItemNode } from './ItemNode';
+
+
+interface ItemProps {
+  itemNode: ItemNode
+  isOpen?: boolean
+}
+
+const Item = memo<ItemProps>((props: ItemProps) => {
+  const { itemNode, isOpen = false } = props;
+
+  const { page, children, isPartialChildren } = itemNode;
+
+  // TODO: fetch children if isPartialChildren
+
+  if (page == null) {
+    return null;
+  }
+
+  // TODO: improve style
+  const style = { margin: '10px', opacity: 1.0 };
+  if (page.isTarget) style.opacity = 0.7;
+
+  /*
+   * Normal render
+   */
+  return (
+    <div style={style}>
+      <p>{page.path}</p>
+      {
+        itemNode.hasChildren() && (children as ItemNode[]).map(node => (
+          <Item
+            key={node.page.path}
+            itemNode={node}
+            isOpen={false}
+          />
+        ))
+      }
+    </div>
+  );
+
+});
+
+export default Item;

+ 23 - 0
packages/app/src/components/Sidebar/PageTree/ItemNode.ts

@@ -0,0 +1,23 @@
+import { IPage } from '~/interfaces/page';
+
+type IPageForItem = Partial<IPage> & {isTarget?: boolean};
+
+export class ItemNode {
+
+  page: IPageForItem;
+
+  children?: ItemNode[];
+
+  isPartialChildren?: boolean;
+
+  constructor(page: IPageForItem, children: ItemNode[] = [], isPartialChildren = false) {
+    this.page = page;
+    this.children = children;
+    this.isPartialChildren = isPartialChildren;
+  }
+
+  hasChildren(): boolean {
+    return this.children != null && this.children?.length > 0;
+  }
+
+}

+ 70 - 0
packages/app/src/components/Sidebar/PageTree/ItemsTree.tsx

@@ -0,0 +1,70 @@
+import React, { FC } from 'react';
+
+import { IPage } from '../../../interfaces/page';
+import { ItemNode } from './ItemNode';
+import Item from './Item';
+
+/*
+ * Mock data
+ */
+const ancestors: (Partial<IPage> & {isTarget?: boolean})[] = [
+  {
+    path: '/A/B',
+    isEmpty: false,
+    grant: 1,
+  },
+  {
+    path: '/A',
+    isEmpty: false,
+    grant: 1,
+  },
+  {
+    path: '/',
+    isEmpty: false,
+    grant: 1,
+  },
+];
+
+
+/*
+ * Utility to generate node tree and return the root node
+ */
+const generateInitialTreeFromAncestors = (ancestors: Partial<IPage>[]): ItemNode => {
+  const rootPage = ancestors[ancestors.length - 1]; // the last item is the root
+  if (rootPage?.path !== '/') throw Error('/ not exist in ancestors');
+
+  const ancestorNodes = ancestors.map((page, i): ItemNode => {
+    // isPartialChildren will be false for the target page
+    const isPartialChildren = i !== 0;
+    return new ItemNode(page, [], isPartialChildren);
+  });
+
+  // update children for each node
+  const rootNode = ancestorNodes.reduce((child, parent) => {
+    parent.children = [child];
+    return parent;
+  });
+
+  return rootNode;
+};
+
+/*
+ * ItemsTree
+ */
+const ItemsTree: FC = () => {
+  // TODO: fetch ancestors using swr
+  if (ancestors == null) return null;
+
+  // create node tree
+  const rootNode = generateInitialTreeFromAncestors(ancestors);
+
+  const isOpen = true;
+
+  return (
+    <>
+      <Item key={rootNode.page.path} itemNode={rootNode} isOpen={isOpen} />
+    </>
+  );
+};
+
+export default ItemsTree;