فهرست منبع

Merge branch 'dev/4.0.x' into support/apply-bootstrap4

Yuki Takei 6 سال پیش
والد
کامیت
125b6d70fa

+ 1 - 2
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "growi",
   "name": "growi",
-  "version": "3.7.3-RC",
+  "version": "4.0.0-RC",
   "description": "Team collaboration software using markdown",
   "description": "Team collaboration software using markdown",
   "tags": [
   "tags": [
     "wiki",
     "wiki",
@@ -208,7 +208,6 @@
     "markdown-it-task-checkbox": "^1.0.6",
     "markdown-it-task-checkbox": "^1.0.6",
     "markdown-it-toc-and-anchor-with-slugid": "^1.1.4",
     "markdown-it-toc-and-anchor-with-slugid": "^1.1.4",
     "markdown-table": "^1.1.1",
     "markdown-table": "^1.1.1",
-    "metismenu": "^3.0.3",
     "mini-css-extract-plugin": "^0.9.0",
     "mini-css-extract-plugin": "^0.9.0",
     "morgan": "^1.9.0",
     "morgan": "^1.9.0",
     "node-dev": "^4.0.0",
     "node-dev": "^4.0.0",

+ 71 - 59
src/client/js/components/Sidebar.jsx

@@ -1,74 +1,83 @@
 import React from 'react';
 import React from 'react';
-// import PropTypes from 'prop-types';
+import PropTypes from 'prop-types';
 
 
 import { withTranslation } from 'react-i18next';
 import { withTranslation } from 'react-i18next';
 
 
-import BacklogIcon from '@atlaskit/icon/glyph/backlog';
-import BoardIcon from '@atlaskit/icon/glyph/board';
-import GraphLineIcon from '@atlaskit/icon/glyph/graph-line';
-import ShortcutIcon from '@atlaskit/icon/glyph/shortcut';
-import { JiraWordmark } from '@atlaskit/logo';
-
 import {
 import {
-  GroupHeading,
-  HeaderSection,
-  Item,
+  withNavigationUIController,
   LayoutManager,
   LayoutManager,
-  MenuSection,
   NavigationProvider,
   NavigationProvider,
-  Separator,
-  Wordmark,
   ThemeProvider, modeGenerator,
   ThemeProvider, modeGenerator,
 } from '@atlaskit/navigation-next';
 } from '@atlaskit/navigation-next';
 
 
+import Drawer from '@atlaskit/drawer';
+
 import { createSubscribedElement } from './UnstatedUtils';
 import { createSubscribedElement } from './UnstatedUtils';
 import AppContainer from '../services/AppContainer';
 import AppContainer from '../services/AppContainer';
 
 
+import GrowiLogo from './GrowiLogo';
 import SidebarNav from './Sidebar/SidebarNav';
 import SidebarNav from './Sidebar/SidebarNav';
+import History from './Sidebar/History';
+import CustomSidebar from './Sidebar/CustomSidebar';
 
 
 class Sidebar extends React.Component {
 class Sidebar extends React.Component {
 
 
   static propTypes = {
   static propTypes = {
+    navigationUIController: PropTypes.any.isRequired,
   };
   };
 
 
   state = {
   state = {
+    currentContentsId: 'custom',
+    isDrawerOpen: false,
   };
   };
 
 
-  renderSidebarContents = () => (
+  openDrawer = () => this.setState({ isDrawerOpen: true });
+
+  closeDrawer = () => this.setState({ isDrawerOpen: false });
+
+  itemSelectedHandler = (contentsId) => {
+    const { navigationUIController } = this.props;
+    const { currentContentsId } = this.state;
+
+    // already selected
+    if (currentContentsId === contentsId) {
+      navigationUIController.toggleCollapse();
+    }
+    // switch and expand
+    else {
+      this.setState({ currentContentsId: contentsId });
+      navigationUIController.expand();
+    }
+
+    // if (contentsId === 'drawer') {
+    //   this.openDrawer();
+    // }
+  }
+
+  renderGlobalNavigation = () => (
     <>
     <>
-      <HeaderSection>
-        { () => (
-          <div className="grw-product-nav-header">
-            <Wordmark wordmark={JiraWordmark} />
-          </div>
-        ) }
-      </HeaderSection>
-      <MenuSection>
-        { () => (
-          <div className="grw-product-nav-menu">
-            <Item
-              before={BacklogIcon}
-              text="Backlog"
-              isSelected
-            />
-            <Item
-              before={BoardIcon}
-              text="Active sprints"
-            />
-            <Item
-              before={GraphLineIcon}
-              text="Reports"
-            />
-            <Separator />
-            <GroupHeading>Shortcuts</GroupHeading>
-            <Item before={ShortcutIcon} text="Project space" />
-            <Item before={ShortcutIcon} text="Looooooooooooooooooooooooooooooong Menu" />
-          </div>
-        ) }
-      </MenuSection>
+      <div className="grw-logo">
+        <a href="/"><GrowiLogo /></a>
+      </div>
+      <SidebarNav currentContentsId={this.state.currentContentsId} onItemSelected={this.itemSelectedHandler} />
+      <Drawer onClose={this.closeDrawer} isOpen={this.state.isDrawerOpen} width="wide">
+        <code>Drawer contents</code>
+      </Drawer>
     </>
     </>
   );
   );
 
 
+  renderSidebarContents = () => {
+    let contents = <CustomSidebar></CustomSidebar>;
+
+    switch (this.state.currentContentsId) {
+      case 'history':
+        contents = <History></History>;
+        break;
+    }
+
+    return contents;
+  }
+
   render() {
   render() {
     return (
     return (
       <ThemeProvider
       <ThemeProvider
@@ -80,31 +89,34 @@ class Sidebar extends React.Component {
           }),
           }),
         })}
         })}
       >
       >
-        <NavigationProvider>
-          <LayoutManager
-            globalNavigation={SidebarNav}
-            productNavigation={() => null}
-            containerNavigation={this.renderSidebarContents}
-            experimental_flyoutOnHover
-            experimental_alternateFlyoutBehaviour
-            // experimental_fullWidthFlyout
-            shouldHideGlobalNavShadow
-            showContextualNavigation
-          >
-          </LayoutManager>
-        </NavigationProvider>
+        <LayoutManager
+          globalNavigation={this.renderGlobalNavigation}
+          productNavigation={() => null}
+          containerNavigation={this.renderSidebarContents}
+          experimental_hideNavVisuallyOnCollapse
+          experimental_flyoutOnHover
+          experimental_alternateFlyoutBehaviour
+          // experimental_fullWidthFlyout
+          shouldHideGlobalNavShadow
+          showContextualNavigation
+        >
+        </LayoutManager>
       </ThemeProvider>
       </ThemeProvider>
     );
     );
   }
   }
 
 
 }
 }
 
 
+const SidebarWithNavigationUI = withNavigationUIController(Sidebar);
+const SidebarWithNavigationUIAndTranslation = withTranslation()(SidebarWithNavigationUI);
 
 
 /**
 /**
  * Wrapper component for using unstated
  * Wrapper component for using unstated
  */
  */
 const SidebarWrapper = (props) => {
 const SidebarWrapper = (props) => {
-  return createSubscribedElement(Sidebar, props, [AppContainer]);
+  return createSubscribedElement(SidebarWithNavigationUIAndTranslation, props, [AppContainer]);
 };
 };
 
 
-export default withTranslation()(SidebarWrapper);
+export default () => (
+  <NavigationProvider><SidebarWrapper /></NavigationProvider>
+);

+ 53 - 0
src/client/js/components/Sidebar/CustomSidebar.jsx

@@ -0,0 +1,53 @@
+import React from 'react';
+// import PropTypes from 'prop-types';
+
+import { withTranslation } from 'react-i18next';
+
+import { JiraWordmark } from '@atlaskit/logo';
+
+import {
+  HeaderSection,
+  MenuSection,
+  Wordmark,
+} from '@atlaskit/navigation-next';
+
+import { createSubscribedElement } from '../UnstatedUtils';
+import AppContainer from '../../services/AppContainer';
+
+class CustomSidebar extends React.Component {
+
+  static propTypes = {
+  };
+
+  state = {
+  };
+
+  render() {
+    return (
+      <>
+        <HeaderSection>
+          { () => (
+            <div className="grw-product-nav-header">
+              <Wordmark wordmark={JiraWordmark} />
+            </div>
+          ) }
+        </HeaderSection>
+        <MenuSection>
+          { () => (
+            <span>(TBD) CustomSidebar Contents</span>
+          ) }
+        </MenuSection>
+      </>
+    );
+  }
+
+}
+
+/**
+ * Wrapper component for using unstated
+ */
+const CustomSidebarWrapper = (props) => {
+  return createSubscribedElement(CustomSidebar, props, [AppContainer]);
+};
+
+export default withTranslation()(CustomSidebarWrapper);

+ 53 - 0
src/client/js/components/Sidebar/History.jsx

@@ -0,0 +1,53 @@
+import React from 'react';
+// import PropTypes from 'prop-types';
+
+import { withTranslation } from 'react-i18next';
+
+import { JiraWordmark } from '@atlaskit/logo';
+
+import {
+  HeaderSection,
+  MenuSection,
+  Wordmark,
+} from '@atlaskit/navigation-next';
+
+import { createSubscribedElement } from '../UnstatedUtils';
+import AppContainer from '../../services/AppContainer';
+
+class History extends React.Component {
+
+  static propTypes = {
+  };
+
+  state = {
+  };
+
+  render() {
+    return (
+      <>
+        <HeaderSection>
+          { () => (
+            <div className="grw-product-nav-header">
+              <Wordmark wordmark={JiraWordmark} />
+            </div>
+          ) }
+        </HeaderSection>
+        <MenuSection>
+          { () => (
+            <span>(TBD) History Contents</span>
+          ) }
+        </MenuSection>
+      </>
+    );
+  }
+
+}
+
+/**
+ * Wrapper component for using unstated
+ */
+const HistoryWrapper = (props) => {
+  return createSubscribedElement(History, props, [AppContainer]);
+};
+
+export default withTranslation()(HistoryWrapper);

+ 26 - 25
src/client/js/components/Sidebar/SidebarNav.jsx

@@ -1,5 +1,5 @@
 import React from 'react';
 import React from 'react';
-// import PropTypes from 'prop-types';
+import PropTypes from 'prop-types';
 
 
 import { withTranslation } from 'react-i18next';
 import { withTranslation } from 'react-i18next';
 
 
@@ -9,46 +9,47 @@ import TrayIcon from '@atlaskit/icon/glyph/tray';
 import {
 import {
   GlobalNav,
   GlobalNav,
 } from '@atlaskit/navigation-next';
 } from '@atlaskit/navigation-next';
-import Drawer from '@atlaskit/drawer';
 
 
 import { createSubscribedElement } from '../UnstatedUtils';
 import { createSubscribedElement } from '../UnstatedUtils';
 import AppContainer from '../../services/AppContainer';
 import AppContainer from '../../services/AppContainer';
 
 
-import GrowiLogo from '../GrowiLogo';
 
 
 class SidebarNav extends React.Component {
 class SidebarNav extends React.Component {
 
 
-  propTypes = {
+  static propTypes = {
+    currentContentsId: PropTypes.string,
+    onItemSelected: PropTypes.func,
   };
   };
 
 
   state = {
   state = {
-    isDrawerOpen: false,
   };
   };
 
 
-  openDrawer = () => this.setState({ isDrawerOpen: true });
+  itemSelectedHandler = (contentsId) => {
+    const { onItemSelected } = this.props;
+    if (onItemSelected != null) {
+      onItemSelected(contentsId);
+    }
+  }
 
 
-  closeDrawer = () => this.setState({ isDrawerOpen: false });
+  generateSidebarItemObj(id, icon, label) {
+    return {
+      id,
+      icon,
+      label,
+      isSelected: this.props.currentContentsId === id,
+      onClick: () => this.itemSelectedHandler(id),
+    };
+  }
 
 
   render() {
   render() {
-    const { isDrawerOpen } = this.state;
     return (
     return (
-      <>
-        <div className="grw-logo">
-          <GrowiLogo />
-        </div>
-        <GlobalNav
-          primaryItems={[
-            { id: 'create', icon: EditIcon, label: 'Create' },
-            {
-              id: 'drawer', icon: TrayIcon, label: 'Drawer', onClick: this.openDrawer,
-            },
-          ]}
-          secondaryItems={[]}
-        />
-        <Drawer onClose={this.closeDrawer} isOpen={isDrawerOpen} width="wide">
-          <code>Drawer contents</code>
-        </Drawer>
-      </>
+      <GlobalNav
+        primaryItems={[
+          this.generateSidebarItemObj('custom', EditIcon, 'Custom Sidebar'),
+          this.generateSidebarItemObj('history', TrayIcon, 'History'),
+        ]}
+        secondaryItems={[]}
+      />
     );
     );
   }
   }
 
 

+ 0 - 3
src/client/styles/scss/_vendor.scss

@@ -7,9 +7,6 @@
 // import toastr styles
 // import toastr styles
 @import '~toastr/build/toastr';
 @import '~toastr/build/toastr';
 
 
-// import metismenu styles
-@import '~metismenu/dist/metisMenu';
-
 // import CodeMirror styles
 // import CodeMirror styles
 @import '~codemirror/lib/codemirror.css';
 @import '~codemirror/lib/codemirror.css';
 @import '~codemirror/theme/elegant.css';
 @import '~codemirror/theme/elegant.css';

+ 7 - 11
yarn.lock

@@ -9112,10 +9112,6 @@ methods@~1.1.1, methods@~1.1.2:
   version "1.1.2"
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
   resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
 
 
-metismenu@^3.0.3:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/metismenu/-/metismenu-3.0.3.tgz#961e4c9469144d5078f6228b6e049e58f3137140"
-
 micromatch@2.3.11:
 micromatch@2.3.11:
   version "2.3.11"
   version "2.3.11"
   resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
   resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
@@ -11752,13 +11748,6 @@ react-i18next@^11.1.0:
     "@babel/runtime" "^7.3.1"
     "@babel/runtime" "^7.3.1"
     html-parse-stringify2 "2.0.1"
     html-parse-stringify2 "2.0.1"
 
 
-react-input-autosize@^2.2.2:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.2.tgz#fcaa7020568ec206bc04be36f4eb68e647c4d8c2"
-  integrity sha512-jQJgYCA3S0j+cuOwzuCd1OjmBmnZLdqQdiLKRYrsMMzbjUrVDS5RvJUDwJqA7sKuksDuzFtm6hZGKFu7Mjk5aw==
-  dependencies:
-    prop-types "^15.5.8"
-
 react-image-crop@^8.3.0:
 react-image-crop@^8.3.0:
   version "8.3.0"
   version "8.3.0"
   resolved "https://registry.yarnpkg.com/react-image-crop/-/react-image-crop-8.3.0.tgz#a0642dd3daafd77f142bac01887628cb967876b7"
   resolved "https://registry.yarnpkg.com/react-image-crop/-/react-image-crop-8.3.0.tgz#a0642dd3daafd77f142bac01887628cb967876b7"
@@ -11768,6 +11757,13 @@ react-image-crop@^8.3.0:
     core-js "^3.2.1"
     core-js "^3.2.1"
     prop-types "^15.7.2"
     prop-types "^15.7.2"
 
 
+react-input-autosize@^2.2.2:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.2.tgz#fcaa7020568ec206bc04be36f4eb68e647c4d8c2"
+  integrity sha512-jQJgYCA3S0j+cuOwzuCd1OjmBmnZLdqQdiLKRYrsMMzbjUrVDS5RvJUDwJqA7sKuksDuzFtm6hZGKFu7Mjk5aw==
+  dependencies:
+    prop-types "^15.5.8"
+
 react-is@^16.12.0:
 react-is@^16.12.0:
   version "16.12.0"
   version "16.12.0"
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c"
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c"