Przeglądaj źródła

add PagePathHierarchicalLink component

Yuki Takei 6 lat temu
rodzic
commit
57702d2798

+ 75 - 62
src/client/js/components/Page/RevisionPath.jsx

@@ -5,6 +5,9 @@ import { withTranslation } from 'react-i18next';
 
 import urljoin from 'url-join';
 
+import LinkedPagePath from '../../models/LinkedPagePath';
+import PagePathHierarchicalLink from '../PageList/PagePathHierarchicalLink';
+
 import CopyDropdown from './CopyDropdown';
 
 class RevisionPath extends React.Component {
@@ -91,72 +94,82 @@ class RevisionPath extends React.Component {
     /* eslint-enable no-else-return */
   }
 
-  render() {
-    // define styles
-    const separatorStyle = {
-      marginLeft: '0.2em',
-      marginRight: '0.2em',
-    };
-    const buttonStyle = {
-      marginLeft: '0.5em',
-      padding: '0 2px',
-    };
+  // render() {
+  //   // define styles
+  //   const separatorStyle = {
+  //     marginLeft: '0.2em',
+  //     marginRight: '0.2em',
+  //   };
+  //   const buttonStyle = {
+  //     marginLeft: '0.5em',
+  //     padding: '0 2px',
+  //   };
+
+  //   const { isPageInTrash, isPageForbidden } = this.props;
+  //   const pageLength = this.state.pages.length;
+
+  //   const rootElement = isPageInTrash
+  //     ? (
+  //       <>
+  //         <span className="path-segment">
+  //           <a href="/trash"><i className="icon-trash"></i></a>
+  //         </span>
+  //         <span className="separator" style={separatorStyle}><a href="/">/</a></span>
+  //       </>
+  //     )
+  //     : (
+  //       <>
+  //         <span className="path-segment">
+  //           <a href="/">
+  //             <i className="icon-home"></i>
+  //             <span className="separator" style={separatorStyle}>/</span>
+  //           </a>
+  //         </span>
+  //       </>
+  //     );
+
+  //   const afterElements = [];
+  //   this.state.pages.forEach((page, index) => {
+  //     const isLastElement = (index === pageLength - 1);
+
+  //     // add elements for page
+  //     afterElements.push(
+  //       <span key={page.pagePath} className="path-segment">
+  //         <a href={page.pagePath}>{page.pageName}</a>
+  //       </span>,
+  //     );
+
+  //     // add elements for '/'
+  //     afterElements.push(
+  //       <span key={`${page.pagePath}/`} className="separator" style={separatorStyle}>
+  //         {this.generateLinkElementToListPage(page.pagePath, this.state.isLinkToListPage, isLastElement)}
+  //       </span>,
+  //     );
+  //   });
+
+  //   return (
+  //     <span className="d-flex align-items-center flex-wrap">
+
+  //       {rootElement}
+  //       {afterElements}
+
+  //       <CopyDropdown t={this.props.t} pagePath={this.props.pagePath} pageId={this.props.pageId} buttonStyle={buttonStyle}></CopyDropdown>
+
+  //       { !isPageInTrash && !isPageForbidden && (
+  //         <a href="#edit" className="d-block d-edit-none text-muted btn btn-secondary bg-transparent btn-edit border-0" style={buttonStyle}>
+  //           <i className="icon-note" />
+  //         </a>
+  //       ) }
+  //     </span>
+  //   );
+  // }
 
-    const { isPageInTrash, isPageForbidden } = this.props;
-    const pageLength = this.state.pages.length;
-
-    const rootElement = isPageInTrash
-      ? (
-        <>
-          <span className="path-segment">
-            <a href="/trash"><i className="icon-trash"></i></a>
-          </span>
-          <span className="separator" style={separatorStyle}><a href="/">/</a></span>
-        </>
-      )
-      : (
-        <>
-          <span className="path-segment">
-            <a href="/">
-              <i className="icon-home"></i>
-              <span className="separator" style={separatorStyle}>/</span>
-            </a>
-          </span>
-        </>
-      );
-
-    const afterElements = [];
-    this.state.pages.forEach((page, index) => {
-      const isLastElement = (index === pageLength - 1);
-
-      // add elements for page
-      afterElements.push(
-        <span key={page.pagePath} className="path-segment">
-          <a href={page.pagePath}>{page.pageName}</a>
-        </span>,
-      );
-
-      // add elements for '/'
-      afterElements.push(
-        <span key={`${page.pagePath}/`} className="separator" style={separatorStyle}>
-          {this.generateLinkElementToListPage(page.pagePath, this.state.isLinkToListPage, isLastElement)}
-        </span>,
-      );
-    });
+  render() {
+    const linkedPagePath = new LinkedPagePath(this.props.pagePath);
 
     return (
       <span className="d-flex align-items-center flex-wrap">
-
-        {rootElement}
-        {afterElements}
-
-        <CopyDropdown t={this.props.t} pagePath={this.props.pagePath} pageId={this.props.pageId} buttonStyle={buttonStyle}></CopyDropdown>
-
-        { !isPageInTrash && !isPageForbidden && (
-          <a href="#edit" className="d-block d-edit-none text-muted btn btn-secondary bg-transparent btn-edit border-0" style={buttonStyle}>
-            <i className="icon-note" />
-          </a>
-        ) }
+        <PagePathHierarchicalLink linkedPagePath={linkedPagePath} />
       </span>
     );
   }

+ 63 - 0
src/client/js/components/PageList/PagePathHierarchicalLink.jsx

@@ -0,0 +1,63 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import LinkedPagePath from '../../models/LinkedPagePath';
+
+
+const PagePathHierarchicalLink = (props) => {
+  const { linkedPagePath, additionalClassNames } = props;
+
+  let classNames = ['page-segment'];
+  classNames = classNames.concat(additionalClassNames);
+
+  const RootLink = () => {
+    return props.isPageInTrash
+      ? (
+        <>
+          <span className="path-segment">
+            <a href="/trash"><i className="icon-trash"></i></a>
+          </span>
+          <span className="separator"><a href="/">/</a></span>
+        </>
+      )
+      : (
+        <>
+          <span className="path-segment">
+            <a href="/">
+              <i className="icon-home"></i>
+              <span className="separator">/</span>
+            </a>
+          </span>
+        </>
+      );
+  };
+
+  const isParentExists = linkedPagePath.parent != null;
+  const isParentRoot = isParentExists && linkedPagePath.parent.parent == null;
+  return (
+    <>
+      { isParentExists && (
+        <PagePathHierarchicalLink linkedPagePath={linkedPagePath.parent} />
+      ) }
+      { isParentExists && !isParentRoot && (
+        <span className="separator">/</span>
+      ) }
+
+      { !isParentExists && <RootLink /> }
+      <a classNames={classNames} href={encodeURI(linkedPagePath.href)}>{linkedPagePath.pathName}</a>
+    </>
+  );
+};
+
+PagePathHierarchicalLink.propTypes = {
+  linkedPagePath: PropTypes.instanceOf(LinkedPagePath).isRequired,
+  additionalClassNames: PropTypes.array,
+
+  isPageInTrash: PropTypes.bool,
+};
+
+PagePathHierarchicalLink.defaultProps = {
+  additionalClassNames: [],
+};
+
+export default PagePathHierarchicalLink;

+ 31 - 0
src/client/js/models/LinkedPagePath.js

@@ -0,0 +1,31 @@
+import { pathUtils } from 'growi-commons';
+
+import PagePath from './PagePath';
+
+export default class LinkedPagePath {
+
+  constructor(path, skipNormalize = false) {
+
+    const pagePath = new PagePath(path, false, skipNormalize);
+
+    this.pathName = pagePath.latter;
+    this.parent = pagePath.former != null
+      ? new LinkedPagePath(pagePath.former, true)
+      : null;
+
+  }
+
+  get href() {
+    if (this.parent == null) {
+      return '/';
+    }
+
+    return pathUtils.normalizePath(`${this.parent.href}/${this.pathName}`);
+  }
+
+  get escapedPathName() {
+    // TODO: impl
+    return this.pathName;
+  }
+
+}

+ 5 - 0
src/client/styles/scss/_subnav.scss

@@ -75,6 +75,11 @@ header.grw-header {
   h1 {
     @include variable-font-size(28px);
     line-height: 1.1em;
+
+    .separator {
+      margin-right: 0.2em;
+      margin-left: 0.2em;
+    }
   }
 
   ul.authors {