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

Merge pull request #3020 from weseek/imprv/page-accessories-layout

Imprv/page accessories layout
Yuki Takei 5 лет назад
Родитель
Сommit
9da1824c09

+ 5 - 3
src/client/js/app.jsx

@@ -31,16 +31,17 @@ import TableOfContents from './components/TableOfContents';
 import PageAccessories from './components/PageAccessories';
 import UserInfo from './components/User/UserInfo';
 import Fab from './components/Fab';
-
 import PersonalSettings from './components/Me/PersonalSettings';
+import UserContentsLinks from './components/UserContentsLinks';
+import GrowiSubNavigation from './components/Navbar/GrowiSubNavigation';
+import GrowiSubNavigationSwitcher from './components/Navbar/GrowiSubNavigationSwitcher';
+
 import NavigationContainer from './services/NavigationContainer';
 import PageContainer from './services/PageContainer';
 import PageHistoryContainer from './services/PageHistoryContainer';
 import CommentContainer from './services/CommentContainer';
 import EditorContainer from './services/EditorContainer';
 import TagContainer from './services/TagContainer';
-import GrowiSubNavigation from './components/Navbar/GrowiSubNavigation';
-import GrowiSubNavigationSwitcher from './components/Navbar/GrowiSubNavigationSwitcher';
 import PersonalContainer from './services/PersonalContainer';
 
 import { appContainer, componentMappings } from './base';
@@ -113,6 +114,7 @@ if (pageContainer.state.pageId != null) {
 
     'recent-created-icon': <RecentlyCreatedIcon />,
     'user-bookmark-icon': <BookmarkIcon />,
+    'grw-user-contents-links': <UserContentsLinks />,
   });
 }
 if (pageContainer.state.creator != null) {

+ 6 - 6
src/client/js/components/PageAccessoriesModalControl.jsx

@@ -19,10 +19,10 @@ const PageAccessoriesModalControl = (props) => {
   const { t, pageAccessoriesContainer, isGuestUserMode } = props;
 
   return (
-    <div className="top-of-table-contents d-flex align-items-end pb-1">
+    <div className="grw-page-accessories-control d-flex align-items-end pb-1">
       <button
         type="button"
-        className="btn btn-link grw-btn-top-of-table"
+        className="btn btn-link grw-btn-page-accessories"
         onClick={() => pageAccessoriesContainer.openPageAccessoriesModal('pagelist')}
       >
         <PageListIcon />
@@ -30,7 +30,7 @@ const PageAccessoriesModalControl = (props) => {
 
       <button
         type="button"
-        className="btn btn-link grw-btn-top-of-table"
+        className="btn btn-link grw-btn-page-accessories"
         onClick={() => pageAccessoriesContainer.openPageAccessoriesModal('timeline')}
       >
         <TimeLineIcon />
@@ -38,7 +38,7 @@ const PageAccessoriesModalControl = (props) => {
 
       <button
         type="button"
-        className="btn btn-link grw-btn-top-of-table"
+        className="btn btn-link grw-btn-page-accessories"
         onClick={() => pageAccessoriesContainer.openPageAccessoriesModal('pageHistory')}
       >
         <HistoryIcon />
@@ -46,7 +46,7 @@ const PageAccessoriesModalControl = (props) => {
 
       <button
         type="button"
-        className="btn btn-link grw-btn-top-of-table"
+        className="btn btn-link grw-btn-page-accessories"
         onClick={() => pageAccessoriesContainer.openPageAccessoriesModal('attachment')}
       >
         <AttachmentIcon />
@@ -55,7 +55,7 @@ const PageAccessoriesModalControl = (props) => {
       <div id="shareLink-btn-wrapper-for-tooltip">
         <button
           type="button"
-          className={`btn btn-link grw-btn-top-of-table ${isGuestUserMode && 'disabled'}`}
+          className={`btn btn-link grw-btn-page-accessories ${isGuestUserMode && 'disabled'}`}
           onClick={() => pageAccessoriesContainer.openPageAccessoriesModal('shareLink')}
         >
           <ShareLinkIcon />

+ 7 - 1
src/client/js/components/PageList.jsx

@@ -50,8 +50,9 @@ const PageList = (props) => {
     );
   }
 
+  const liClasses = props.liClasses.join(' ');
   const pageList = pages.map(page => (
-    <li key={page._id} className="mb-3">
+    <li key={page._id} className={liClasses}>
       <Page page={page} />
     </li>
   ));
@@ -91,6 +92,11 @@ PageList.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   appContainer: PropTypes.instanceOf(AppContainer),
   pageContainer: PropTypes.instanceOf(PageContainer),
+
+  liClasses: PropTypes.arrayOf(PropTypes.string),
+};
+PageList.defaultProps = {
+  liClasses: ['mb-3'],
 };
 
 export default PageListTranslation;

+ 26 - 48
src/client/js/components/TableOfContents.jsx

@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useMemo } from 'react';
+import React, { useCallback, useEffect } from 'react';
 import PropTypes from 'prop-types';
 import loggerFactory from '@alias/logger';
 
@@ -11,11 +11,8 @@ import { withUnstatedContainers } from './UnstatedUtils';
 
 import StickyStretchableScroller from './StickyStretchableScroller';
 
-import RecentlyCreatedIcon from './Icons/RecentlyCreatedIcon';
-
 // eslint-disable-next-line no-unused-vars
 const logger = loggerFactory('growi:TableOfContents');
-const WIKI_HEADER_LINK = 120;
 
 /**
  * @author Yuki Takei <yuki@weseek.co.jp>
@@ -29,14 +26,22 @@ const TableOfContents = (props) => {
 
   const calcViewHeight = useCallback(() => {
     // calculate absolute top of '#revision-toc' element
+    const parentElem = document.querySelector('.grw-side-contents-container');
+    const parentBottom = parentElem.getBoundingClientRect().bottom;
     const containerElem = document.querySelector('#revision-toc');
     const containerTop = containerElem.getBoundingClientRect().top;
+    const containerComputedStyle = getComputedStyle(containerElem);
+    const containerPaddingTop = parseFloat(containerComputedStyle['padding-top']);
+
+    // get smaller bottom line of window height - .system-version height) and containerTop
+    let bottom = Math.min(window.innerHeight - 20, parentBottom);
 
-    // window height - revisionToc top - .system-version - .grw-fab-container height - top-of-table-contents height
     if (isUserPage) {
-      return window.innerHeight - containerTop - 20 - 155 - 26 - 40;
+      // raise the bottom line by the height and margin-top of UserContentLinks
+      bottom -= 45;
     }
-    return window.innerHeight - containerTop - 20 - 155 - 26;
+    // bottom - revisionToc top
+    return bottom - (containerTop + containerPaddingTop);
   }, [isUserPage]);
 
   const { tocHtml } = pageContainer.state;
@@ -48,48 +53,21 @@ const TableOfContents = (props) => {
     navigationContainer.addSmoothScrollEvent(anchorsInToc);
   }, [tocHtml, navigationContainer]);
 
-  // get element for smoothScroll
-  const getBookMarkListHeaderDom = useMemo(() => { return document.getElementById('bookmarks-list') }, []);
-  const getRecentlyCreatedListHeaderDom = useMemo(() => { return document.getElementById('recently-created-list') }, []);
-
   return (
-    <>
-      <StickyStretchableScroller
-        contentsElemSelector=".revision-toc .markdownIt-TOC"
-        stickyElemSelector="#revision-toc"
-        calcViewHeightFunc={calcViewHeight}
-      >
-        <div
-          id="revision-toc-content"
-          className="revision-toc-content top-of-table-contents"
-         // eslint-disable-next-line react/no-danger
-          dangerouslySetInnerHTML={{
-          __html: tocHtml,
-        }}
-        />
-      </StickyStretchableScroller>
-
-      { isUserPage && (
-      <div className="mt-3 d-flex justify-content-around">
-        <button
-          type="button"
-          className="btn btn-outline-secondary btn-sm"
-          onClick={() => navigationContainer.smoothScrollIntoView(getBookMarkListHeaderDom, WIKI_HEADER_LINK)}
-        >
-          <i className="mr-2 icon-star"></i>
-          <span>Bookmarks</span>
-        </button>
-        <button
-          type="button"
-          className="btn btn-outline-secondary btn-sm"
-          onClick={() => navigationContainer.smoothScrollIntoView(getRecentlyCreatedListHeaderDom, WIKI_HEADER_LINK)}
-        >
-          <i className="grw-icon-container-recently-created mr-2"><RecentlyCreatedIcon /></i>
-          <span>Recently Created</span>
-        </button>
-      </div>
-      )}
-    </>
+    <StickyStretchableScroller
+      contentsElemSelector=".revision-toc .markdownIt-TOC"
+      stickyElemSelector=".grw-side-contents-sticky-container"
+      calcViewHeightFunc={calcViewHeight}
+    >
+      <div
+        id="revision-toc-content"
+        className="revision-toc-content"
+        // eslint-disable-next-line react/no-danger
+        dangerouslySetInnerHTML={{
+        __html: tocHtml,
+      }}
+      />
+    </StickyStretchableScroller>
   );
 
 };

+ 54 - 0
src/client/js/components/UserContentsLinks.jsx

@@ -0,0 +1,54 @@
+import React, { useMemo } from 'react';
+import PropTypes from 'prop-types';
+import loggerFactory from '@alias/logger';
+
+import NavigationContainer from '../services/NavigationContainer';
+
+import { withUnstatedContainers } from './UnstatedUtils';
+
+import RecentlyCreatedIcon from './Icons/RecentlyCreatedIcon';
+
+// eslint-disable-next-line no-unused-vars
+const logger = loggerFactory('growi:cli:UserContentsLinks');
+const WIKI_HEADER_LINK = 120;
+
+/**
+ * @author Yuki Takei <yuki@weseek.co.jp>
+ *
+ */
+const UserContentsLinks = (props) => {
+
+  const { navigationContainer } = props;
+
+  // get element for smoothScroll
+  const getBookMarkListHeaderDom = useMemo(() => { return document.getElementById('bookmarks-list') }, []);
+  const getRecentlyCreatedListHeaderDom = useMemo(() => { return document.getElementById('recently-created-list') }, []);
+
+  return (
+    <div className="mt-3 d-flex justify-content-around">
+      <button
+        type="button"
+        className="btn btn-outline-secondary btn-sm"
+        onClick={() => navigationContainer.smoothScrollIntoView(getBookMarkListHeaderDom, WIKI_HEADER_LINK)}
+      >
+        <i className="mr-2 icon-star"></i>
+        <span>Bookmarks</span>
+      </button>
+      <button
+        type="button"
+        className="btn btn-outline-secondary btn-sm"
+        onClick={() => navigationContainer.smoothScrollIntoView(getRecentlyCreatedListHeaderDom, WIKI_HEADER_LINK)}
+      >
+        <i className="grw-icon-container-recently-created mr-2"><RecentlyCreatedIcon /></i>
+        <span>Recently Created</span>
+      </button>
+    </div>
+  );
+
+};
+
+UserContentsLinks.propTypes = {
+  navigationContainer: PropTypes.instanceOf(NavigationContainer).isRequired,
+};
+
+export default withUnstatedContainers(UserContentsLinks, [NavigationContainer]);

+ 2 - 23
src/client/styles/scss/_layout.scss

@@ -36,34 +36,13 @@ body {
   }
 }
 
-.top-of-table-contents {
-  line-height: 1.25;
-  border-bottom: 1px solid transparent;
-
-  .user-list-content {
-    direction: rtl;
-
-    .liker-user-count,
-    .seen-user-count {
-      font-size: 12px;
-      font-weight: bolder;
-    }
-  }
-  .cls-1 {
-    isolation: isolate;
-  }
-}
-
-.revision-toc {
+.grw-side-contents-sticky-container {
   position: sticky;
   // growisubnavigation + grw-navbar-boder
   top: calc(100px + 4px);
   width: 250px;
+  min-width: 250px;
   margin-top: 5px;
-
-  .revision-toc-content {
-    padding: 0;
-  }
 }
 
 .grw-fab {

+ 0 - 5
src/client/styles/scss/_on-edit.scss

@@ -71,11 +71,6 @@ body.on-edit {
     display: none;
   }
 
-  // hide unnecessary elements for growi layout
-  .side-contents-container {
-    display: none !important;
-  }
-
   // show only either Edit button or HackMD button
   &.hackmd .nav-tab-edit {
     display: none;

+ 40 - 0
src/client/styles/scss/_page-accessories-control.scss

@@ -0,0 +1,40 @@
+.grw-page-accessories-control {
+  flex-wrap: wrap;
+  line-height: 1.25;
+
+  .grw-btn-page-accessories {
+    width: 35px;
+    height: 35px;
+    svg {
+      width: 16px;
+      height: 16px;
+    }
+  }
+
+  .seen-user-count {
+    font-size: 12px;
+    font-weight: bolder;
+  }
+  .grw-seen-user-info {
+    .btn {
+      white-space: nowrap;
+    }
+  }
+
+  .seen-user-popover {
+    max-width: 200px;
+
+    .user-list-content {
+      direction: rtl;
+
+      .liker-user-count,
+      .seen-user-count {
+        font-size: 12px;
+        font-weight: bolder;
+      }
+    }
+    .cls-1 {
+      isolation: isolate;
+    }
+  }
+}

+ 4 - 28
src/client/styles/scss/_toc.scss

@@ -1,37 +1,13 @@
-.top-of-table-contents {
-  flex-wrap: wrap;
-
-  .grw-btn-top-of-table {
-    width: 35px;
-    height: 35px;
-    svg {
-      width: 16px;
-      height: 16px;
-    }
-  }
-
-  .seen-user-count {
-    font-size: 12px;
-    font-weight: bolder;
-  }
-  .grw-seen-user-info {
-    .btn {
-      white-space: nowrap;
-    }
-  }
-
-  .seen-user-popover {
-    max-width: 200px;
-  }
-}
-
 .revision-toc {
   // to get on the Attachment row
   z-index: 1;
+  padding: 5px;
   font-size: 0.9em;
 
+  border-top: 1px solid transparent;
+  border-bottom: 1px solid transparent;
+
   .revision-toc-content {
-    padding: 10px;
     li {
       margin: 6px;
     }

+ 1 - 0
src/client/styles/scss/style-app.scss

@@ -44,6 +44,7 @@
 @import 'navbar';
 @import 'on-edit';
 @import 'page_list';
+@import 'page-accessories-control';
 @import 'page-path';
 @import 'page';
 @import 'page-presentation';

+ 6 - 6
src/client/styles/scss/theme/_apply-colors.scss

@@ -306,15 +306,11 @@ ul.pagination {
   }
 }
 
-.top-of-table-contents {
-  border-color: $bordercolor-toc;
-
-  .grw-btn-top-of-table {
+.grw-page-accessories-control {
+  .grw-btn-page-accessories {
     fill: $color-link;
   }
   .grw-seen-user-info {
-    @include border-vertical('before', $bordercolor-toc, 70%);
-
     .btn {
       color: $color-seen-user;
       &:active {
@@ -327,6 +323,10 @@ ul.pagination {
   }
 }
 
+.revision-toc {
+  border-color: $bordercolor-toc;
+}
+
 .grw-custom-navigation {
   .nav-title {
     color: $color-link;

+ 9 - 4
src/server/views/widget/page_content.html

@@ -54,10 +54,15 @@
   <div id="page-editor-navbar-bottom-container" class="d-none d-edit-block"></div>
 </div>
 
-<div class="d-none d-lg-block side-contents-container ml-4">
-  <div id="page-accessories" class="page-accessories"></div>
-  <div id="revision-toc" class="revision-toc sps sps--abv" data-sps-offset="123">
-    <div id="revision-toc-content" class="revision-toc-content"></div>
+<div class="d-none d-lg-block d-editor-none grw-side-contents-container ml-4">
+  <div class="grw-side-contents-sticky-container">
+    <div id="page-accessories" class="page-accessories"></div>
+    <div id="revision-toc" class="revision-toc sps sps--abv" data-sps-offset="123">
+      <div id="revision-toc-content" class="revision-toc-content"></div>
+    </div>
+    {% if pageUser %}
+      <div id="grw-user-contents-links"></div>
+    {% endif %}
   </div>
 </div>