Procházet zdrojové kódy

Merge branch 'master' into imprv/refacter-recursively

itizawa před 5 roky
rodič
revize
114c3e0d02

+ 0 - 2
src/client/js/app.jsx

@@ -31,7 +31,6 @@ import BookmarkList from './components/PageList/BookmarkList';
 import LikerList from './components/User/LikerList';
 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';
 
@@ -114,7 +113,6 @@ if (pageContainer.state.pageId != null) {
 
     'recent-created-icon': <RecentlyCreatedIcon />,
     'user-bookmark-icon': <BookmarkIcon />,
-    'grw-user-contents-links': <UserContentsLinks />,
   });
 }
 if (pageContainer.state.creator != null) {

+ 89 - 0
src/client/js/components/ContentLinkButtons.jsx

@@ -0,0 +1,89 @@
+import React, { useMemo } from 'react';
+import PropTypes from 'prop-types';
+
+import NavigationContainer from '../services/NavigationContainer';
+import PageContainer from '../services/PageContainer';
+
+import { withUnstatedContainers } from './UnstatedUtils';
+
+import RecentlyCreatedIcon from './Icons/RecentlyCreatedIcon';
+
+const WIKI_HEADER_LINK = 120;
+
+/**
+ * @author Yuki Takei <yuki@weseek.co.jp>
+ *
+ */
+const ContentLinkButtons = (props) => {
+
+  const { navigationContainer, pageContainer } = props;
+  const { pageUser } = pageContainer.state;
+  const { isPageExist } = pageContainer.state;
+
+  // get element for smoothScroll
+  const getCommentListDom = useMemo(() => { return document.getElementById('page-comments-list') }, []);
+  const getBookMarkListHeaderDom = useMemo(() => { return document.getElementById('bookmarks-list') }, []);
+  const getRecentlyCreatedListHeaderDom = useMemo(() => { return document.getElementById('recently-created-list') }, []);
+
+
+  const CommentLinkButton = () => {
+    return (
+      <div className="mt-3">
+        <button
+          type="button"
+          className="btn btn-outline-secondary btn-sm btn-block"
+          onClick={() => navigationContainer.smoothScrollIntoView(getCommentListDom, WIKI_HEADER_LINK)}
+        >
+          <i className="mr-2 icon-fw icon-bubbles"></i>
+          <span>Comments</span>
+        </button>
+      </div>
+    );
+  };
+
+  const BookMarkLinkButton = () => {
+    return (
+      <button
+        type="button"
+        className="btn btn-outline-secondary btn-sm px-2"
+        onClick={() => navigationContainer.smoothScrollIntoView(getBookMarkListHeaderDom, WIKI_HEADER_LINK)}
+      >
+        <i className="mr-2 icon-star"></i>
+        <span>Bookmarks</span>
+      </button>
+
+    );
+  };
+
+  const RecentlyCreatedLinkButton = () => {
+    return (
+      <button
+        type="button"
+        className="btn btn-outline-secondary btn-sm px-3"
+        onClick={() => navigationContainer.smoothScrollIntoView(getRecentlyCreatedListHeaderDom, WIKI_HEADER_LINK)}
+      >
+        <i className="grw-icon-container-recently-created mr-2"><RecentlyCreatedIcon /></i>
+        <span>Recently Created</span>
+      </button>
+
+    );
+  };
+
+  return (
+    <>
+      {isPageExist && <CommentLinkButton />}
+
+      <div className="mt-3 d-flex justify-content-between">
+        {pageUser && <><BookMarkLinkButton /><RecentlyCreatedLinkButton /></>}
+      </div>
+    </>
+  );
+
+};
+
+ContentLinkButtons.propTypes = {
+  navigationContainer: PropTypes.instanceOf(NavigationContainer).isRequired,
+  pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
+};
+
+export default withUnstatedContainers(ContentLinkButtons, [NavigationContainer, PageContainer]);

+ 2 - 2
src/client/js/components/Page/DisplaySwitcher.jsx

@@ -8,7 +8,7 @@ import Editor from '../PageEditor';
 import Page from '../Page';
 import UserInfo from '../User/UserInfo';
 import TableOfContents from '../TableOfContents';
-import UserContentsLinks from '../UserContentsLinks';
+import ContentLinkButtons from '../ContentLinkButtons';
 import PageAccessories from '../PageAccessories';
 import PageEditorByHackmd from '../PageEditorByHackmd';
 import EditorNavbarBottom from '../PageEditor/EditorNavbarBottom';
@@ -37,7 +37,7 @@ const DisplaySwitcher = (props) => {
                   <div id="revision-toc" className="revision-toc">
                     <TableOfContents />
                   </div>
-                  {pageUser && <UserContentsLinks />}
+                  <ContentLinkButtons />
                 </div>
               </div>
             </div>

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

@@ -1,54 +0,0 @@
-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]);

+ 22 - 0
src/client/styles/scss/_mixins.scss

@@ -253,3 +253,25 @@
     }
   }
 }
+@mixin highlighted($color) {
+  @keyframes fadeout {
+    100% {
+      opacity: 0;
+    }
+  }
+  position: relative;
+  z-index: 1;
+
+  &::after {
+    position: absolute;
+    top: 15%;
+    left: 0;
+    z-index: -1;
+    width: 100%;
+    height: 70%;
+    content: '';
+    background-color: $color;
+    border-radius: 2px;
+    animation: fadeout 1s ease-in 1.5s forwards;
+  }
+}

+ 5 - 5
src/client/styles/scss/_toc.scss

@@ -25,11 +25,11 @@
       margin-left: 17px;
     }
   }
+}
 
-  .grw-icon-container-recently-created {
-    svg {
-      width: 14px;
-      height: 14px;
-    }
+.grw-icon-container-recently-created {
+  svg {
+    width: 14px;
+    height: 14px;
   }
 }

+ 1 - 4
src/client/styles/scss/_wiki.scss

@@ -34,6 +34,7 @@ div.body {
     border-bottom: solid 1px transparent;
   }
   h2 {
+    // padding-top: 0.5em;
     padding-bottom: 0.5em;
     font-size: 1.4em;
     font-weight: bold;
@@ -137,10 +138,6 @@ div.body {
     }
   }
 
-  .highlighted {
-    background-color: $warning;
-  }
-
   .revision-head {
     a {
       text-decoration: none;

+ 4 - 0
src/client/styles/scss/theme/_apply-colors.scss

@@ -389,6 +389,10 @@ ul.pagination {
  * GROWI wiki
  */
 .wiki {
+  .highlighted {
+    @include highlighted($bgcolor-highlighted);
+  }
+
   a {
     color: $color-link-wiki;
 

+ 1 - 0
src/client/styles/scss/theme/antarctic.scss

@@ -51,6 +51,7 @@ html[dark] {
   $bgcolor-global: $themelight;
   $bgcolor-inline-code: $gray-100; //optional
   $bgcolor-card: $gray-50;
+  $bgcolor-highlighted: rgba($primary, 0.15);
 
   // Font colors
   $color-global: black;

+ 1 - 11
src/client/styles/scss/theme/christmas.scss

@@ -43,6 +43,7 @@ html[dark] {
   // Background colors
   $bgcolor-card: $gray-50;
   $bgcolor-inline-code: $gray-100; //optional
+  $bgcolor-highlighted: rgba($primary, 0.5);
 
   // Font colors
   $color-global: #112744;
@@ -106,17 +107,6 @@ html[dark] {
   @import 'apply-colors-light';
 
   // change color of highlighted header in wiki (default: orange)
-  .wiki {
-    .code-line.revision-head.highlighted {
-      color: $themelight;
-      background-color: lighten($themecolor, 20%);
-
-      .icon-note,
-      .icon-link {
-        color: $themelight;
-      }
-    }
-  }
 
   .sidebar {
     background: $themecolor;

+ 2 - 0
src/client/styles/scss/theme/default.scss

@@ -22,6 +22,7 @@ html[light] {
   $bgcolor-global: white;
   $bgcolor-inline-code: $gray-100; //optional
   $bgcolor-card: $gray-50;
+  $bgcolor-highlighted: rgba($primary, 0.1);
 
   // Font colors
   $color-global: #112744;
@@ -122,6 +123,7 @@ html[dark] {
   $bgcolor-global: #131418;
   $bgcolor-inline-code: #1f1f22; //optional
   $bgcolor-card: darken($bgcolor-global, 5%);
+  $bgcolor-highlighted: rgba($primary, 0.4);
 
   // Font colors
   $color-global: $gray-400;

+ 1 - 0
src/client/styles/scss/theme/future.scss

@@ -11,6 +11,7 @@ html[dark] {
   $bgcolor-global: $themecolor;
   $bgcolor-inline-code: #1f1f22; //optional
   $bgcolor-card: darken($themecolor, 5%);
+  $bgcolor-highlighted: rgba($primary, 0.4);
 
   // Font colors
   $color-global: #95abba;

+ 1 - 0
src/client/styles/scss/theme/halloween.scss

@@ -39,6 +39,7 @@ html[dark] {
   $bgcolor-global: #050000;
   $bgcolor-inline-code: #1f1f22; //optional
   $bgcolor-card: $bgcolor-global;
+  $bgcolor-highlighted: rgba($primary, 0.4);
 
   // Font colors
   $color-global: #e9af2b;

+ 1 - 6
src/client/styles/scss/theme/island.scss

@@ -11,6 +11,7 @@ html[dark] {
   $bgcolor-card: $gray-50;
   $bgcolor-global: lighten($color-themelight, 10%);
   $bgcolor-inline-code: $gray-100; //optional
+  $bgcolor-highlighted: rgba($primary, 0.3);
 
   // Font colors
   $color-global: #112744;
@@ -84,12 +85,6 @@ html[dark] {
   @import 'apply-colors';
   @import 'apply-colors-light';
 
-  .wiki {
-    .highlighted {
-      background-color: lighten($primary, 20%);
-    }
-  }
-
   .rbt-menu {
     background: lighten($color-themelight, 5%);
   }

+ 3 - 0
src/client/styles/scss/theme/kibela.scss

@@ -45,6 +45,8 @@ html[dark] {
   $primary: $bgcolor-theme;
   $info: lighten($bgcolor-theme, 20%);
 
+  $bgcolor-highlighted: rgba($primary, 0.2);
+
   // List Group colors
   $color-list: $color-global;
   $bgcolor-list: $bgcolor-global;
@@ -98,6 +100,7 @@ html[dark] {
 
   @import 'apply-colors';
   @import 'apply-colors-light';
+
   //Button
   .grw-page-editor-mode-manager {
     .btn.btn-outline-primary {

+ 2 - 0
src/client/styles/scss/theme/mono-blue.scss

@@ -14,6 +14,7 @@ html[light] {
   $bgcolor-global: $themelight;
   $bgcolor-inline-code: $gray-100; //optional
   $bgcolor-card: darken($themelight, 5%);
+  $bgcolor-highlighted: rgba($primary, 0.1);
 
   // Font colors
   $color-global: $themecolor;
@@ -111,6 +112,7 @@ html[dark] {
   $bgcolor-navbar: #27343b;
   $bgcolor-inline-code: #1f1f22; //optional
   $bgcolor-card: darken($themedark, 5%);
+  $bgcolor-highlighted: rgba($primary, 0.5);
 
   // Font colors
   $color-global: #d3d4d4;

+ 1 - 0
src/client/styles/scss/theme/nature.scss

@@ -45,6 +45,7 @@ html[dark] {
   $bgcolor-inline-code: $gray-100; //optional
   $bgcolor-card: #f1ffe4;
   $bgcolor-subnav: #fafafa;
+  $bgcolor-highlighted: rgba($primary, 0.1);
 
   // Font colors
   $color-global: #460039;

+ 1 - 0
src/client/styles/scss/theme/spring.scss

@@ -34,6 +34,7 @@ html[dark] {
   $bgcolor-global: white;
   $bgcolor-inline-code: $gray-100; //optional
   $bgcolor-card: $gray-50;
+  $bgcolor-highlighted: rgba($primary, 0.5);
 
   // Font colors
   $color-global: black;

+ 1 - 0
src/client/styles/scss/theme/wood.scss

@@ -43,6 +43,7 @@ html[dark] {
   // Background colors
   $bgcolor-global: white;
   $bgcolor-card: #ece8de;
+  $bgcolor-highlighted: rgba($primary, 0.3);
 
   // Font colors
   // $color-global: black;

+ 68 - 0
src/migrations/20200827045151-remove-layout-setting.js

@@ -0,0 +1,68 @@
+require('module-alias/register');
+const logger = require('@alias/logger')('growi:migrate:remove-layout-setting');
+
+const mongoose = require('mongoose');
+const config = require('@root/config/migrate');
+
+const { getModelSafely } = require('@commons/util/mongoose-utils');
+
+module.exports = {
+  async up(db, client) {
+    logger.info('Apply migration');
+    mongoose.connect(config.mongoUri, config.mongodb.options);
+
+    const Config = getModelSafely('Config') || require('@server/models/config')();
+
+    const layoutType = await Config.findOne({ key: 'customize:layout' });
+
+    if (layoutType == null) {
+      return;
+    }
+
+    const promise = [
+      // remove layout
+      Config.findOneAndDelete({ key: 'customize:layout' }),
+    ];
+
+    if (layoutType.value === '"kibela"') {
+      promise.push(
+        Config.update(
+          { key: 'customize:theme' },
+          { value: JSON.stringify('kibela') },
+        ),
+      );
+    }
+
+    await Promise.all(promise);
+
+    logger.info('Migration has successfully applied');
+  },
+
+  async down(db, client) {
+    logger.info('Rollback migration');
+    mongoose.connect(config.mongoUri, config.mongodb.options);
+
+    const Config = getModelSafely('Config') || require('@server/models/config')();
+
+    const theme = await Config.findOne({ key: 'customize:theme' });
+    const insertLayoutType = (theme.value === '"kibela"') ? 'kibela' : 'growi';
+
+    const insertConfig = new Config({
+      ns: 'crowi',
+      key: 'customize:layout',
+      value: JSON.stringify(insertLayoutType),
+    });
+
+    const promise = [
+      insertConfig.save(),
+      Config.update(
+        { key: 'customize:theme', value: JSON.stringify('kibela') },
+        { value: JSON.stringify('default') },
+      ),
+    ];
+
+    await Promise.all(promise);
+
+    logger.info('Migration has been successfully rollbacked');
+  },
+};

+ 14 - 20
src/server/routes/page.js

@@ -143,16 +143,16 @@ module.exports = function(crowi, app) {
   const ApiResponse = require('../util/apiResponse');
   const getToday = require('../util/getToday');
 
-  const { slackNotificationService, configManager } = crowi;
+  const { slackNotificationService, configManager, xssService } = crowi;
   const interceptorManager = crowi.getInterceptorManager();
   const globalNotificationService = crowi.getGlobalNotificationService();
 
   const XssOption = require('../../lib/service/xss/xssOption');
   const Xss = require('../../lib/service/xss/index');
   const initializedConfig = {
-    isEnabledXssPrevention: crowi.configManager.getConfig('markdown', 'markdown:xss:isEnabledPrevention'),
-    tagWhiteList: crowi.xssService.getTagWhiteList(),
-    attrWhiteList: crowi.xssService.getAttrWhiteList(),
+    isEnabledXssPrevention: configManager.getConfig('markdown', 'markdown:xss:isEnabledPrevention'),
+    tagWhiteList: xssService.getTagWhiteList(),
+    attrWhiteList: xssService.getAttrWhiteList(),
   };
   const xssOption = new XssOption(initializedConfig);
   const xss = new Xss(xssOption);
@@ -330,9 +330,8 @@ module.exports = function(crowi, app) {
   async function showTopPage(req, res, next) {
     const portalPath = req.path;
     const revisionId = req.query.revision;
-    const layoutName = configManager.getConfig('crowi', 'customize:layout');
 
-    const view = `layout-${layoutName}/page_list`;
+    const view = 'layout-growi/page_list';
     const renderVars = { path: portalPath };
 
     let portalPage = await Page.findByPathAndViewer(portalPath, req.user);
@@ -364,7 +363,6 @@ module.exports = function(crowi, app) {
   async function showPageForGrowiBehavior(req, res, next) {
     const path = getPathFromRequest(req);
     const revisionId = req.query.revision;
-    const layoutName = configManager.getConfig('crowi', 'customize:layout');
 
     let page = await Page.findByPathAndViewer(path, req.user);
 
@@ -384,7 +382,7 @@ module.exports = function(crowi, app) {
     const offset = parseInt(req.query.offset) || 0;
     const renderVars = {};
 
-    let view = `layout-${layoutName}/page`;
+    let view = 'layout-growi/page';
 
     page.initLatestRevisionField(revisionId);
 
@@ -406,7 +404,7 @@ module.exports = function(crowi, app) {
 
     if (isUserPage(page.path)) {
       // change template
-      view = `layout-${layoutName}/user_page`;
+      view = 'layout-growi/user_page';
       await addRenderVarsForUserPage(renderVars, page, req.user);
     }
 
@@ -453,13 +451,11 @@ module.exports = function(crowi, app) {
     const { linkId } = req.params;
     const revisionId = req.query.revision;
 
-    const layoutName = configManager.getConfig('crowi', 'customize:layout');
-
     const shareLink = await ShareLink.findOne({ _id: linkId }).populate('relatedPage');
 
     if (shareLink == null || shareLink.relatedPage == null) {
       // page or sharelink are not found
-      return res.render(`layout-${layoutName}/not_found_shared_page`);
+      return res.render('layout-growi/not_found_shared_page');
     }
 
     const renderVars = {};
@@ -469,7 +465,7 @@ module.exports = function(crowi, app) {
     // check if share link is expired
     if (shareLink.isExpired()) {
       // page is not found
-      return res.render(`layout-${layoutName}/expired_shared_page`, renderVars);
+      return res.render('layout-growi/expired_shared_page', renderVars);
     }
 
     let page = shareLink.relatedPage;
@@ -491,7 +487,7 @@ module.exports = function(crowi, app) {
     addRenderVarsForScope(renderVars, page);
 
     await interceptorManager.process('beforeRenderPage', req, res, renderVars);
-    return res.render(`layout-${layoutName}/shared_page`, renderVars);
+    return res.render('layout-growi/shared_page', renderVars);
   };
 
   /**
@@ -528,19 +524,18 @@ module.exports = function(crowi, app) {
     const path = getPathFromRequest(req);
 
     const isCreatable = Page.isCreatableName(path);
-    const layoutName = configManager.getConfig('crowi', 'customize:layout');
 
     let view;
     const renderVars = { path };
 
     if (!isCreatable) {
-      view = `layout-${layoutName}/not_creatable`;
+      view = 'layout-growi/not_creatable';
     }
     else if (req.isForbidden) {
-      view = `layout-${layoutName}/forbidden`;
+      view = 'layout-growi/forbidden';
     }
     else {
-      view = `layout-${layoutName}/not_found`;
+      view = 'layout-growi/not_found';
 
       // retrieve templates
       if (req.user != null) {
@@ -571,7 +566,6 @@ module.exports = function(crowi, app) {
   actions.deletedPageListShow = async function(req, res) {
     // normalizePath makes '/trash/' -> '/trash'
     const path = pathUtils.normalizePath(`/trash${getPathFromRequest(req)}`);
-    const layoutName = configManager.getConfig('crowi', 'customize:layout');
 
     const limit = 50;
     const offset = parseInt(req.query.offset) || 0;
@@ -596,7 +590,7 @@ module.exports = function(crowi, app) {
 
     renderVars.pager = generatePager(result.offset, result.limit, result.totalCount);
     renderVars.pages = result.pages;
-    res.render(`layout-${layoutName}/page_list`, renderVars);
+    res.render('layout-growi/page_list', renderVars);
   };
 
   /**