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

Merge pull request #1989 from weseek/feat/switch-sidebar-content

Feat/switch sidebar content
Yuki Takei 6 лет назад
Родитель
Сommit
7eea837529

+ 8 - 0
resource/cdn-manifests.js

@@ -138,6 +138,14 @@ module.exports = {
         integrity: '',
       },
     },
+    {
+      name: 'animate.css',
+      url: 'https://cdn.jsdelivr.net/npm/animate.css@3.7.2/animate.min.css',
+      groups: ['basis'],
+      args: {
+        integrity: '',
+      },
+    },
     {
       name: 'jquery-ui',
       url: 'https://cdn.jsdelivr.net/jquery.ui/1.11.4/jquery-ui.min.css',

+ 3 - 0
src/client/js/bootstrap.jsx

@@ -4,6 +4,7 @@ import loggerFactory from '@alias/logger';
 import Xss from '@commons/service/xss';
 
 import HeaderSearchBox from './components/HeaderSearchBox';
+import NavbarToggler from './components/Navbar/NavbarToggler';
 import PersonalDropdown from './components/Navbar/PersonalDropdown';
 import Sidebar from './components/Sidebar';
 import StaffCredit from './components/StaffCredit/StaffCredit';
@@ -37,6 +38,8 @@ appContainer.injectToWindow();
  *  value: React Element
  */
 const componentMappings = {
+  'grw-navbar-toggler': <NavbarToggler />,
+
   'search-top': <HeaderSearchBox />,
   'search-sidebar': <HeaderSearchBox crowi={appContainer} />,
   'personal-dropdown': <PersonalDropdown />,

+ 35 - 0
src/client/js/components/Navbar/NavbarToggler.jsx

@@ -0,0 +1,35 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { withTranslation } from 'react-i18next';
+
+import { createSubscribedElement } from '../UnstatedUtils';
+import AppContainer from '../../services/AppContainer';
+
+const NavbarToggler = (props) => {
+
+  // eslint-disable-next-line no-unused-vars
+  const { appContainer } = props;
+
+  return (
+    <button className="navbar-toggler grw-navbar-toggler border-0" type="button" aria-expanded="false" aria-label="Toggle navigation">
+      <i className="icon-menu"></i>
+    </button>
+  );
+
+};
+
+/**
+ * Wrapper component for using unstated
+ */
+const NavbarTogglerWrapper = (props) => {
+  return createSubscribedElement(NavbarToggler, props, [AppContainer]);
+};
+
+
+NavbarToggler.propTypes = {
+  t: PropTypes.func.isRequired, //  i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+};
+
+export default withTranslation()(NavbarTogglerWrapper);

+ 1 - 1
src/client/js/components/Navbar/PersonalDropdown.jsx

@@ -59,7 +59,7 @@ const PersonalDropdown = (props) => {
       {/* remove .dropdown-toggle for hide caret */}
       {/* See https://stackoverflow.com/a/44577512/13183572 */}
       <a className="nav-link waves-effect waves-light" data-toggle="dropdown">
-        <UserPicture user={user} withoutLink />&nbsp;{user.name}
+        <UserPicture user={user} withoutLink /><span className="d-none d-sm-inline-block">&nbsp;{user.name}</span>
       </a>
 
       {/* Menu */}

+ 23 - 4
src/client/js/components/Sidebar/SidebarNav.jsx

@@ -29,7 +29,7 @@ class SidebarNav extends React.Component {
     }
   }
 
-  generateSidebarItemObj(id, label, icon) {
+  generatePrimaryItemObj(id, label, icon) {
     const isSelected = this.props.currentContentsId === id;
 
     return {
@@ -47,6 +47,22 @@ class SidebarNav extends React.Component {
     };
   }
 
+  generateSecondaryItemObj(id, label, icon, href) {
+    return {
+      id,
+      component: ({ className }) => (
+        <div className={`${className} grw-global-item-container d-block d-md-none`}>
+          <a href={href}>
+            <GlobalItem
+              icon={icon}
+              label={label}
+            />
+          </a>
+        </div>
+      ),
+    };
+  }
+
   generateIconFactory(classNames) {
     return () => <i className={classNames}></i>;
   }
@@ -55,10 +71,13 @@ class SidebarNav extends React.Component {
     return (
       <GlobalNav
         primaryItems={[
-          this.generateSidebarItemObj('custom', 'Custom Sidebar', this.generateIconFactory('fa fa-2x fa-code')),
-          this.generateSidebarItemObj('history', 'History', this.generateIconFactory('icon-clock fa-2x')),
+          this.generatePrimaryItemObj('custom', 'Custom Sidebar', this.generateIconFactory('fa fa-code')),
+          this.generatePrimaryItemObj('history', 'History', this.generateIconFactory('icon-clock')),
+        ]}
+        secondaryItems={[
+          this.generateSecondaryItemObj('admin', 'Admin', this.generateIconFactory('icon-settings'), '/admin'),
+          this.generateSecondaryItemObj('help', 'Help', this.generateIconFactory('icon-question'), 'https://docs.growi.org'),
         ]}
-        secondaryItems={[]}
       />
     );
   }

+ 34 - 3
src/client/styles/scss/_layout.scss

@@ -68,9 +68,28 @@
     }
   }
 
-  .grw-global-item-container.active {
-    button {
-      @extend %fukidashi-for-active;
+  .grw-global-item-container {
+    i {
+      font-size: 1.5em;
+    }
+
+    // icon opacity
+    &:not(.active) {
+      i {
+        opacity: 0.4;
+      }
+      &:hover,
+      &:focus {
+        i {
+          opacity: 0.7;
+        }
+      }
+    }
+
+    &.active {
+      button {
+        @extend %fukidashi-for-active;
+      }
     }
   }
 }
@@ -143,6 +162,18 @@
   }
 }
 
+.grw-fixed-controls-container {
+  position: fixed;
+  right: 1em;
+  bottom: 3em;
+
+  transition: all 200ms linear;
+
+  .grw-fixed-controls-button-container {
+    box-shadow: 0 3px 4px rgba($black, 0.3);
+  }
+}
+
 // printable style
 @media print {
   padding: 30px;

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

@@ -1,4 +1,9 @@
 .grw-navbar {
+  .grw-navbar-toggler {
+    padding: 0.5rem;
+    font-size: 1.5em;
+  }
+
   .nav-link,
   .nav-item.confidential {
     display: flex;

+ 23 - 13
src/server/views/layout/layout.html

@@ -74,44 +74,46 @@
 <div id="wrapper">
 
   {% block layout_head_nav %}
-  <nav class="navbar grw-navbar navbar-expand-sm navbar-dark fixed-top mb-0 p-0">
+  <nav class="navbar grw-navbar navbar-expand-sm navbar-dark fixed-top mb-0 p-sm-0">
+    <div id="grw-navbar-toggler" class="d-sm-none mr-auto"></div>
+
     {# Brand Logo #}
-    <div class="navbar-brand">
+    <div class="navbar-brand mr-sm-auto">
       <a class="grw-logo d-block" href="/">
         {% include '../widget/logo.html' %}
       </a>
     </div>
 
-    {# Navbar Left #}
-    <ul class="navbar-nav ml-auto mr-auto">
+    {# Navbar Center #}
+    <ul class="navbar-nav d-none d-md-block">
       <li>
         {% if isSearchServiceConfigured() %}
-        <div class="navbar-form navbar-left search-top" role="search" id="search-top"></div>
+        <div class="search-top" role="search" id="search-top"></div>
         {% endif %}
       </li>
     </ul>
 
     {# Navbar Right #}
-    <ul class="navbar-nav">
+    <ul class="navbar-nav ml-auto">
       {% if user and user.admin %}
-      <li class="nav-item">
+      <li class="nav-item d-none d-md-block">
         <a class="nav-link" href="/admin">
           <i class="icon-settings mr-2"></i>
-          <span class="d-none d-md-inline-block">{{ t('Admin') }}</span>
+          {{ t('Admin') }}
         </a>
       </li>
       {% endif %}
 
       {% if user %}
-      <li class="nav-item">
+      <li class="nav-item d-none d-md-block">
         <a class="nav-link create-page" href="#" data-target="#create-page" data-toggle="modal">
           <i class="icon-pencil mr-2"></i>
-          <span class="d-none d-md-inline-block">{{ t('New') }}</span>
+          {{ t('New') }}
         </a>
       </li>
-      <li class="nav-item">
+      <li class="nav-item d-none d-md-block">
         <a class="nav-link" href="https://docs.growi.org/" target="_blank">
-          <i class="icon-question mr-2"></i><span class="d-none d-md-inline-block mr-2">{{ t('Help') }}</span><span class="text-muted small"><i class="icon-share-alt"></i></span>
+          <i class="icon-question mr-2"></i><span class="mr-2">{{ t('Help') }}</span><span class="small"><i class="icon-share-alt"></i></span>
         </a>
       </li>
       <li id="personal-dropdown" class="nav-item dropdown dropdown-toggle"></li>
@@ -132,7 +134,7 @@
 
   <div class="d-flex">
     {# Sidebar #}
-    <nav>
+    <nav class="d-none d-sm-block">
       <div id="grw-sidebar" class="grw-sidebar"></div>
     </nav>
     <div id="page-wrapper" class="flex-grow-1">
@@ -143,6 +145,14 @@
 
 </div><!-- /#wrapper -->
 
+<div class="grw-fixed-controls-container d-md-none animated fadeInUp faster">
+  <div class="grw-fixed-controls-button-container rounded-circle">
+    <button class="btn btn-lg btn-primary rounded-circle waves-effect waves-light" type="button" data-target="#create-page" data-toggle="modal">
+      <i class="icon-pencil"></i>
+    </button>
+  </div>
+</div>
+
 <!-- /#staff-credit -->
 <div id="staff-credit"></div>