Răsfoiți Sursa

Merge branch 'master' into feat/export-single-page-for-merge

yusuketk 5 ani în urmă
părinte
comite
dc282c8509
54 a modificat fișierele cu 334 adăugiri și 259 ștergeri
  1. 2 2
      CHANGES.md
  2. BIN
      public/images/agile-admin/tooltip/Euclid.png
  3. 0 8
      public/images/agile-admin/tooltip/shape1.svg
  4. 0 18
      public/images/agile-admin/tooltip/shape2.svg
  5. 0 5
      public/images/agile-admin/tooltip/shape3.svg
  6. 0 8
      public/images/agile-admin/tooltip/tooltip1.svg
  7. 0 6
      public/images/agile-admin/tooltip/tooltip2.svg
  8. 0 6
      public/images/agile-admin/tooltip/tooltip3.svg
  9. 2 1
      resource/locales/en_US/translation.json
  10. 2 1
      resource/locales/ja_JP/translation.json
  11. 2 1
      resource/locales/zh_CN/translation.json
  12. 29 67
      src/client/js/components/Admin/App/AppSettingsPage.jsx
  13. 62 0
      src/client/js/components/Admin/App/AppSettingsPageContents.jsx
  14. 1 1
      src/client/js/components/BookmarkButton.jsx
  15. 1 1
      src/client/js/components/LikeButton.jsx
  16. 5 6
      src/client/js/components/Page/ShareLinkAlert.jsx
  17. 3 1
      src/client/js/services/AdminAppContainer.js
  18. 3 3
      src/client/styles/scss/_admin.scss
  19. 1 1
      src/client/styles/scss/_comment.scss
  20. 2 2
      src/client/styles/scss/_comment_kibela.scss
  21. 4 4
      src/client/styles/scss/_editor-attachment.scss
  22. 1 1
      src/client/styles/scss/_editor-overlay.scss
  23. 4 4
      src/client/styles/scss/_hljs.scss
  24. 5 5
      src/client/styles/scss/_layout.scss
  25. 7 7
      src/client/styles/scss/_login.scss
  26. 1 1
      src/client/styles/scss/_navbar_kibela.scss
  27. 7 6
      src/client/styles/scss/_on-edit.scss
  28. 1 1
      src/client/styles/scss/_override-bootstrap-variables.scss
  29. 4 4
      src/client/styles/scss/_page.scss
  30. 3 3
      src/client/styles/scss/_page_list.scss
  31. 5 5
      src/client/styles/scss/_search.scss
  32. 3 3
      src/client/styles/scss/_shortcuts.scss
  33. 1 1
      src/client/styles/scss/_subnav.scss
  34. 2 2
      src/client/styles/scss/_user.scss
  35. 1 0
      src/client/styles/scss/_wiki.scss
  36. 16 9
      src/client/styles/scss/atoms/_buttons.scss
  37. 5 5
      src/client/styles/scss/style-presentation.scss
  38. 5 5
      src/client/styles/scss/theme/_apply-colors-dark.scss
  39. 2 2
      src/client/styles/scss/theme/_apply-colors-kibela.scss
  40. 7 7
      src/client/styles/scss/theme/antarctic.scss
  41. 9 9
      src/client/styles/scss/theme/christmas.scss
  42. 5 5
      src/client/styles/scss/theme/default.scss
  43. 1 1
      src/client/styles/scss/theme/future.scss
  44. 3 3
      src/client/styles/scss/theme/halloween.scss
  45. 5 5
      src/client/styles/scss/theme/island.scss
  46. 1 1
      src/client/styles/scss/theme/kibela.scss
  47. 4 4
      src/client/styles/scss/theme/mono-blue.scss
  48. 4 4
      src/client/styles/scss/theme/nature.scss
  49. 3 3
      src/client/styles/scss/theme/spring.scss
  50. 4 4
      src/client/styles/scss/theme/wood.scss
  51. 5 5
      src/linter-checker/test.scss
  52. 7 1
      src/server/middlewares/access-token-parser.js
  53. 1 1
      src/server/views/admin/customize.html
  54. 83 0
      src/test/middlewares/access-token-parser.test.js

+ 2 - 2
CHANGES.md

@@ -8,8 +8,8 @@
     * Page history
     * Renaming pages
     * Deleting pages
-* Fix: "Append params" switch of CopyDropdown does not work when multiple CopyDropdown instance exists\
-
+* Fix: "Append params" switch of CopyDropdown does not work when multiple CopyDropdown instance exists
+* Fix: Access token parser
 
 ## v4.1.0
 

BIN
public/images/agile-admin/tooltip/Euclid.png


+ 0 - 8
public/images/agile-admin/tooltip/shape1.svg

@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="none">
-<path fill="#00AEEF" d="M174.209,28.162C154.645,8.88,124.289,2.08,100.06,2.08c-0.074,0-0.06-0.079-0.06-0.079
-	s0.015,0.079-0.06,0.079c-24.229,0-54.584,6.8-74.149,26.082C5.417,48.242,3,75,3,100s2.418,51.758,22.792,71.838
-	c19.564,19.281,49.92,26.082,74.149,26.082c0.074,0,0.06,0.079,0.06,0.079s-0.015-0.079,0.06-0.079
-	c24.229,0,54.585-6.801,74.149-26.082C194.582,151.758,197,125,197,100S194.582,48.242,174.209,28.162z"/>
-</svg>

+ 0 - 18
public/images/agile-admin/tooltip/shape2.svg

@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200px" height="150px" viewBox="0 0 200 150">
-<g>
-	<path id="path1" fill="#010101" d="M159.599,137.909c0.975,3.397,4.717,5.548,8.161,4.988c3.489-0.443,6.558-3.466,6.685-7.043
-		c0.217-3.19-1.805-6.34-5.113-7.118c-3.417-1.079-7.469,0.508-9.138,3.701c-0.91,1.636-1.166,3.624-0.612,5.414"/>
-	<path id="path2" fill="#010101" d="M130.646,125.253c1.368,4.656,6.393,7.288,10.806,6.718c4.763-0.451,9.26-4.276,9.71-9.394
-		c0.369-3.779-1.902-7.583-5.244-9.144c-5.404-2.732-12.557-0.222-14.908,5.448c-0.841,1.945-1.018,4.214-0.388,6.294"/>
-	<path id="path3" fill="#010101" d="M184.112,144.325c0.704,2.461,3.412,4.016,5.905,3.611c2.526-0.318,4.746-2.509,4.841-5.093
-		c0.153-2.315-1.483-4.54-3.703-5.155c-2.474-0.781-5.405,0.37-6.612,2.681c-0.657,1.181-0.845,2.619-0.442,3.917"/>
-	<path id="path4" fill="#010101" d="M53.149,10.686c12.101-3.695,24.478-1.625,33.84,4.571c3.187-5.687,8.381-10.144,14.943-12.148
-		c10.427-3.185,21.37,0.699,28.159,8.982c15.606-3.76,31.369,4.398,35.804,18.915c3.269,10.699-0.488,21.956-8.71,29.388
-		c0.395,0.934,0.762,1.882,1.064,2.873c4.73,15.485-3.992,31.889-19.473,36.617c-5.073,1.551-10.251,1.625-15.076,0.518
-		c-3.58,10.605-12.407,19.55-24.386,23.211c-15.015,4.586-30.547-0.521-39.226-11.624c-2.861,1.991-6.077,3.564-9.583,4.636
-		c-18.43,5.631-38.04-5.068-43.785-23.874l-0.083-0.272C1.564,75.375,9.696,57.543,25.083,50.302
-		C23.349,33.157,34.85,16.276,53.149,10.686L53.149,10.686z"/>
-</g>
-</svg>

+ 0 - 5
public/images/agile-admin/tooltip/shape3.svg

@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200px" height="150px" viewBox="0 0 200 150" enable-background="new 0 0 200 150" xml:space="preserve">
-<polygon fill="#FFFFFF" stroke="#000000" points="29.857,3.324 171.111,3.324 196.75,37.671 184.334,107.653 104.355,136.679 100,146.676 96.292,136.355 16.312,107.653 3.25,37.671 "/>
-</svg>

+ 0 - 8
public/images/agile-admin/tooltip/tooltip1.svg

@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="30px" height="20px" viewBox="0 0 30 20">
-	<g>
-		<path fill="#fb9678" d="M7.065,7.067C13.462,10.339,15,19.137,15,19.137V0H0C0,0,1.865,4.407,7.065,7.067z"/>
-		<path fill="#fb9678" d="M15,0v19.137c0,0,1.537-8.797,7.936-12.07C28.135,4.407,30,0,30,0H15z"/>
-	</g>
-</svg>

+ 0 - 6
public/images/agile-admin/tooltip/tooltip2.svg

@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="80px" height="80px" viewBox="0 0 80 80">
-<path fill="#e35583" d="M80,0c0,0-5.631,14.445-25.715,27.213C29.946,42.688,12.79,33.997,3.752,30.417
-	c-3.956-1.567-4.265,1.021-2.966,3.814C16.45,67.934,80,79.614,80,79.614l0,0V0z"/>
-</svg>

+ 0 - 6
public/images/agile-admin/tooltip/tooltip3.svg

@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="60px" height="120px" preserveAspectRatio="none" viewBox="0 0 60 120">
-<path fill="#ffffff" d="M55.451-0.043C55.451-0.043,66.059-41.066,55.451-0.043C51.069,16.9,0.332,119.498,0.332,119.498
-	S43.365,18.315,39.532-0.043c-4.099-19.616,0,0,0,0"/>
-</svg>

+ 2 - 1
resource/locales/en_US/translation.json

@@ -274,7 +274,8 @@
       "restricted": "Access to this page is restricted",
       "stale": "More than {{count}} year has passed since last update.",
       "stale_plural": "More than {{count}} years has passed since last update.",
-      "expiration": "This share link will expire <strong>{{expiredAt}}</strong>."
+      "expiration": "This share link will expire at <strong>{{expiredAt}}</strong>.",
+      "no_deadline":"This page has no expiration date"
     }
   },
   "page_edit": {

+ 2 - 1
resource/locales/ja_JP/translation.json

@@ -276,7 +276,8 @@
       "unlinked": "このページへのリダイレクトは削除されました。",
       "restricted": "このページの閲覧は制限されています",
       "stale": "このページは最終更新日から{{count}}年以上が経過しています。",
-      "expiration": "この共有パーマリンクの有効期限は <strong>{{expiredAt}}</strong> です。"
+      "expiration": "この共有パーマリンクの有効期限は <strong>{{expiredAt}}</strong> です。",
+      "no_deadline": "このページに有効期限は設定されていません。"
     }
   },
   "page_edit": {

+ 2 - 1
resource/locales/zh_CN/translation.json

@@ -249,7 +249,8 @@
 			"unlinked": "将网页重定向到此网页已被删除。",
 			"restricted": "访问此页受到限制",
 			"stale": "自上次更新以来,已超过{{count}年。",
-			"stale_plural": "自上次更新以来已过去{{count}年以上。"
+      "stale_plural": "自上次更新以来已过去{{count}年以上。",
+      "no_deadline": "This page has no expiration date"
 		}
 	},
 	"page_edit": {

+ 29 - 67
src/client/js/components/Admin/App/AppSettingsPage.jsx

@@ -1,92 +1,54 @@
-import React, { Fragment } from 'react';
-import { withTranslation } from 'react-i18next';
+import React, { Suspense } from 'react';
 import PropTypes from 'prop-types';
 import loggerFactory from '@alias/logger';
 
 import { withUnstatedContainers } from '../../UnstatedUtils';
 import { toastError } from '../../../util/apiNotification';
 
-import AppContainer from '../../../services/AppContainer';
 import AdminAppContainer from '../../../services/AdminAppContainer';
 
-import AppSetting from './AppSetting';
-import SiteUrlSetting from './SiteUrlSetting';
-import MailSetting from './MailSetting';
-import AwsSetting from './AwsSetting';
-import PluginSetting from './PluginSetting';
+import AppSettingsPageContents from './AppSettingsPageContents';
 
 const logger = loggerFactory('growi:appSettings');
 
-class AppSettingsPage extends React.Component {
-
-  async componentDidMount() {
-    const { adminAppContainer } = this.props;
-
-    try {
-      await adminAppContainer.retrieveAppSettingsData();
-    }
-    catch (err) {
-      toastError(err);
-      adminAppContainer.setState({ retrieveError: err.message });
-      logger.error(err);
-    }
-  }
-
-  render() {
-    const { t } = this.props;
-
-    return (
-      <Fragment>
+function AppSettingsPage(props) {
+  return (
+    <Suspense
+      fallback={(
         <div className="row">
-          <div className="col-lg-12">
-            <h2 className="admin-setting-header">{t('App Settings')}</h2>
-            <AppSetting />
-          </div>
-        </div>
-
-        <div className="row mt-5">
-          <div className="col-lg-12">
-            <h2 className="admin-setting-header">{t('Site URL settings')}</h2>
-            <SiteUrlSetting />
-          </div>
-        </div>
-
-        <div className="row mt-5">
-          <div className="col-lg-12">
-            <h2 className="admin-setting-header">{t('admin:app_setting.mail_settings')}</h2>
-            <MailSetting />
-          </div>
-        </div>
-
-        <div className="row mt-5">
-          <div className="col-lg-12">
-            <h2 className="admin-setting-header">{t('admin:app_setting.aws_settings')}</h2>
-            <AwsSetting />
-          </div>
+          <i className="fa fa-5x fa-spinner fa-pulse mx-auto text-muted"></i>
         </div>
+)}
+    >
+      <RenderAppSettingsPageWrapper />
+    </Suspense>
+  );
+}
 
-        <div className="row mt-5">
-          <div className="col-lg-12">
-            <h2 className="admin-setting-header">{t('admin:app_setting.plugin_settings')}</h2>
-            <PluginSetting />
-          </div>
-        </div>
-      </Fragment>
-    );
+function RenderAppSettingsPage(props) {
+  if (props.adminAppContainer.state.title === props.adminAppContainer.dummyTitle) {
+    throw new Promise(async() => {
+      try {
+        await props.adminAppContainer.retrieveAppSettingsData();
+      }
+      catch (err) {
+        toastError(err);
+        props.adminAppContainer.setState({ retrieveError: err.message });
+        logger.error(err);
+      }
+    });
   }
 
+  return <AppSettingsPageContents />;
 }
 
-AppSettingsPage.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+RenderAppSettingsPage.propTypes = {
   adminAppContainer: PropTypes.instanceOf(AdminAppContainer).isRequired,
 };
 
 /**
  * Wrapper component for using unstated
  */
-const AppSettingsPageWrapper = withUnstatedContainers(AppSettingsPage, [AppContainer, AdminAppContainer]);
-
+const RenderAppSettingsPageWrapper = withUnstatedContainers(RenderAppSettingsPage, [AdminAppContainer]);
 
-export default withTranslation()(AppSettingsPageWrapper);
+export default AppSettingsPage;

+ 62 - 0
src/client/js/components/Admin/App/AppSettingsPageContents.jsx

@@ -0,0 +1,62 @@
+import React, { Fragment } from 'react';
+import { withTranslation } from 'react-i18next';
+import PropTypes from 'prop-types';
+
+import AppSetting from './AppSetting';
+import SiteUrlSetting from './SiteUrlSetting';
+import MailSetting from './MailSetting';
+import AwsSetting from './AwsSetting';
+import PluginSetting from './PluginSetting';
+
+class AppSettingsPageContents extends React.Component {
+
+  render() {
+    const { t } = this.props;
+
+    return (
+      <Fragment>
+        <div className="row">
+          <div className="col-lg-12">
+            <h2 className="admin-setting-header">{t('App Settings')}</h2>
+            <AppSetting />
+          </div>
+        </div>
+
+        <div className="row mt-5">
+          <div className="col-lg-12">
+            <h2 className="admin-setting-header">{t('Site URL settings')}</h2>
+            <SiteUrlSetting />
+          </div>
+        </div>
+
+        <div className="row mt-5">
+          <div className="col-lg-12">
+            <h2 className="admin-setting-header">{t('admin:app_setting.mail_settings')}</h2>
+            <MailSetting />
+          </div>
+        </div>
+
+        <div className="row mt-5">
+          <div className="col-lg-12">
+            <h2 className="admin-setting-header">{t('admin:app_setting.aws_settings')}</h2>
+            <AwsSetting />
+          </div>
+        </div>
+
+        <div className="row mt-5">
+          <div className="col-lg-12">
+            <h2 className="admin-setting-header">{t('admin:app_setting.plugin_settings')}</h2>
+            <PluginSetting />
+          </div>
+        </div>
+      </Fragment>
+    );
+  }
+
+}
+
+AppSettingsPageContents.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+};
+
+export default withTranslation()(AppSettingsPageContents);

+ 1 - 1
src/client/js/components/BookmarkButton.jsx

@@ -66,7 +66,7 @@ class BookmarkButton extends React.Component {
         onClick={this.handleClick}
         className={`btn rounded-circle btn-bookmark border-0 d-edit-none
           ${`btn-${this.props.size}`}
-          ${this.state.isBookmarked ? 'btn-warning active' : 'btn-outline-warning'}`}
+          ${this.state.isBookmarked ? 'active' : ''}`}
       >
         <i className="icon-star"></i>
       </button>

+ 1 - 1
src/client/js/components/LikeButton.jsx

@@ -44,7 +44,7 @@ class LikeButton extends React.Component {
         type="button"
         onClick={this.handleClick}
         className={`btn rounded-circle btn-like border-0 d-edit-none
-        ${this.state.isLiked ? 'btn-info active' : 'btn-outline-info'}`}
+        ${this.state.isLiked ? 'active' : ''}`}
       >
         <i className="icon-like"></i>
       </button>

+ 5 - 6
src/client/js/components/Page/ShareLinkAlert.jsx

@@ -8,7 +8,7 @@ const ShareLinkAlert = (props) => {
 
 
   const shareContent = document.getElementById('is-shared-page');
-  let expiredAt = shareContent.getAttribute('data-share-link-expired-at');
+  const expiredAt = shareContent.getAttribute('data-share-link-expired-at');
   const createdAt = shareContent.getAttribute('data-share-link-created-at');
 
   function generateRatio() {
@@ -22,9 +22,6 @@ const ShareLinkAlert = (props) => {
   if (expiredAt !== '') {
     ratio = generateRatio();
   }
-  else {
-    expiredAt = t('share_links.Unlimited');
-  }
 
   function specifyColor() {
     let color;
@@ -46,8 +43,10 @@ const ShareLinkAlert = (props) => {
   return (
     <p className={`alert alert-${specifyColor()} py-3 px-4`}>
       <i className="icon-fw icon-link"></i>
-      {/* eslint-disable-next-line react/no-danger */}
-      <span dangerouslySetInnerHTML={{ __html: t('page_page.notice.expiration', { expiredAt }) }} />
+      {(expiredAt === '' ? <span>{t('page_page.notice.no_deadline')}</span>
+      // eslint-disable-next-line react/no-danger
+      : <span dangerouslySetInnerHTML={{ __html: t('page_page.notice.expiration', { expiredAt }) }} />
+      )}
     </p>
   );
 };

+ 3 - 1
src/client/js/services/AdminAppContainer.js

@@ -16,10 +16,12 @@ export default class AdminAppContainer extends Container {
     super();
 
     this.appContainer = appContainer;
+    this.dummyTitle = 0;
 
     this.state = {
       retrieveError: null,
-      title: '',
+      // set dummy value tile for using suspense
+      title: this.dummyTitle,
       confidential: '',
       globalLang: '',
       fileUpload: '',

+ 3 - 3
src/client/styles/scss/_admin.scss

@@ -28,7 +28,7 @@
 
     .ss-container img {
       padding: 0.5em;
-      background-color: #ddd;
+      background-color: $gray-300;
     }
 
     .table-user-list {
@@ -140,8 +140,8 @@
 
     // style
     .theme-option-container a {
-      background-color: #f5f5f5;
-      border: 1px solid #ccc;
+      background-color: $gray-50;
+      border: 1px solid $gray-300;
     }
     .theme-option-name {
       opacity: 0.3;

+ 1 - 1
src/client/styles/scss/_comment.scss

@@ -38,7 +38,7 @@
       justify-content: flex-end;
 
       font-size: 0.9em;
-      color: #999;
+      color: $gray-400;
     }
   }
 

+ 2 - 2
src/client/styles/scss/_comment_kibela.scss

@@ -14,7 +14,7 @@
       height: 0;
       content: '';
       border-top: 20px solid transparent;
-      border-right: 20px solid #e6e9ec;
+      border-right: 20px solid $gray-200;
       border-bottom: 20px solid transparent;
       border-left: 20px solid transparent;
       border-left-width: 0;
@@ -65,7 +65,7 @@
     .page-comment-main {
       @extend %comment-section;
       margin-left: 4.5em;
-      background: #e6e9ec;
+      background: $gray-200;
       border-radius: 0.35em;
     }
 

+ 4 - 4
src/client/styles/scss/_editor-attachment.scss

@@ -22,7 +22,7 @@
         background: rgba(200, 200, 200, 0.8);
 
         .overlay-content {
-          color: #444;
+          color: $gray-700;
         }
       }
     }
@@ -51,7 +51,7 @@
       // accepted
       &.dropzone-accepted:not(.dropzone-rejected) {
         .overlay.overlay-dropzone-active {
-          border: 4px dashed #ccc;
+          border: 4px dashed $gray-300;
 
           .overlay-content {
             // insert content
@@ -62,7 +62,7 @@
             }
 
             // style
-            color: #666;
+            color: $secondary;
             background: rgba(200, 200, 200, 0.8);
           }
         }
@@ -106,7 +106,7 @@
     padding-bottom: 3px;
     font-size: small;
     border: none;
-    border-top: 1px dotted #ccc;
+    border-top: 1px dotted $gray-300;
     border-bottom: none;
 
     &:active {

+ 1 - 1
src/client/styles/scss/_editor-overlay.scss

@@ -4,7 +4,7 @@
     .overlay-content {
       padding: $contentPadding;
       font-size: $contentFontSize;
-      color: #444;
+      color: $gray-700;
       background: rgba(200, 200, 200, 0.5);
     }
   }

+ 4 - 4
src/client/styles/scss/_hljs.scss

@@ -15,8 +15,8 @@ pre.hljs {
     padding: 0 4px;
     font-style: normal;
     font-weight: bold;
-    color: #333;
-    background: #ccc;
+    color: $gray-900;
+    background: $gray-300;
     opacity: 0.6;
   }
 }
@@ -24,12 +24,12 @@ pre.hljs {
 // styles for highlightjs-line-numbers
 .hljs-ln td.hljs-ln-numbers {
   padding-right: 5px;
-  color: #ccc;
+  color: $gray-300;
 
   text-align: center;
   vertical-align: top;
   user-select: none;
-  border-right: 1px solid #ccc;
+  border-right: 1px solid $gray-300;
 }
 
 .hljs-ln td.hljs-ln-code {

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

@@ -94,10 +94,10 @@ body {
   }
   .main {
     header {
-      border-bottom: solid 1px #666;
+      border-bottom: solid 1px $secondary;
       h1 {
         font-size: 2em;
-        color: #000;
+        color: black;
       }
     }
 
@@ -110,7 +110,7 @@ body {
       max-width: 100%;
       margin-bottom: 20px;
       font-size: 0.9em;
-      border: solid 1px #aaa;
+      border: solid 1px $gray-400;
 
       .revision-toc-head {
         display: inline-block;
@@ -125,8 +125,8 @@ body {
 
     .meta {
       margin-top: 32px;
-      color: #666;
-      border-top: solid 1px #ccc;
+      color: $secondary;
+      border-top: solid 1px $gray-300;
     }
   }
 }

+ 7 - 7
src/client/styles/scss/_login.scss

@@ -101,31 +101,31 @@
     ),
     'google': (
       rgba(#24292e, 0.4),
-      #444,
+      $gray-700,
     ),
     'github': (
       rgba(lighten(black, 20%), 0.4),
-      #444,
+      $gray-700,
     ),
     'facebook': (
       rgba(#29487d, 0.4),
-      #444,
+      $gray-700,
     ),
     'twitter': (
       rgba(#1da1f2, 0.4),
-      #444,
+      $gray-700,
     ),
     'oidc': (
       rgba(#24292e, 0.4),
-      #444,
+      $gray-700,
     ),
     'saml': (
       rgba(#55a79a, 0.4),
-      #444,
+      $gray-700,
     ),
     'basic': (
       rgba(#24292e, 0.4),
-      #444,
+      $gray-700,
     ),
   );
 

+ 1 - 1
src/client/styles/scss/_navbar_kibela.scss

@@ -4,7 +4,7 @@
   .grw-navbar {
     height: 60px;
     background: white;
-    border-bottom: solid 1px #e6e9ec;
+    border-bottom: solid 1px $gray-200;
     .navbar-nav {
       .confidential {
         color: white;

+ 7 - 6
src/client/styles/scss/_on-edit.scss

@@ -187,7 +187,8 @@ body.on-edit {
       }
 
       // add icon on cursor
-      .markdown-table-activated, .markdown-link-activated {
+      .markdown-table-activated,
+      .markdown-link-activated {
         .CodeMirror-cursor {
           &:after {
             position: relative;
@@ -197,7 +198,7 @@ body.on-edit {
             width: 1em;
             height: 1em;
             content: ' ';
-  
+
             background-repeat: no-repeat;
             background-size: 1em;
           }
@@ -310,12 +311,12 @@ body.on-edit {
 
 #tag-edit-button-tooltip {
   .tooltip-inner {
-    color: #000;
-    background-color: #fff;
-    border: 1px solid #ccc;
+    color: black;
+    background-color: white;
+    border: 1px solid $gray-300;
   }
 
   .tooltip-arrow {
-    border-bottom: 5px solid #ccc;
+    border-bottom: 5px solid $gray-300;
   }
 }

+ 1 - 1
src/client/styles/scss/_override-bootstrap-variables.scss

@@ -79,7 +79,7 @@ $alert-color-level: -10;
 //== Progress bar
 $progress-height: 4px;
 $progress-border-radius: $border-radius-sm;
-$progress-bg: #f0f0f0;
+$progress-bg: $gray-100;
 $progress-box-shadow: none;
 
 //== Code

+ 4 - 4
src/client/styles/scss/_page.scss

@@ -4,7 +4,7 @@
 .main-container {
   .url-line {
     font-size: 1rem;
-    color: #999;
+    color: $gray-400;
   }
 
   h1.title {
@@ -17,7 +17,7 @@
 
     // crowi layout only
     a.last-path {
-      color: #ccc;
+      color: $gray-300;
 
       &:hover {
         color: inherit;
@@ -65,7 +65,7 @@
 
       .revision-history-diff {
         padding-left: 40px;
-        color: #333;
+        color: $gray-900;
         table-layout: fixed;
       }
     }
@@ -171,7 +171,7 @@
   left: 5%;
   width: 90%;
   height: 90%;
-  background: #000;
+  background: black;
 
   iframe {
     width: 100%;

+ 3 - 3
src/client/styles/scss/_page_list.scss

@@ -54,7 +54,7 @@ body .page-list {
 .popular-page-high {
   font-size: 1.1em;
   font-weight: bold;
-  color: #e80000;
+  color: darken($red, 5%);
 }
 
 .popular-page-mid {
@@ -67,8 +67,8 @@ body .page-list {
 }
 
 .card-timeline {
-  border: 1px solid #ccc;
+  border: 1px solid $gray-300;
   > .card-header {
-    background-color: #ccc;
+    background-color: $gray-300;
   }
 }

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

@@ -1,6 +1,6 @@
 .search-listpage-icon {
   font-size: 16px;
-  color: #999;
+  color: $gray-400;
 }
 
 .search-listpage-clear {
@@ -11,7 +11,7 @@
   height: 22px;
   padding: 8px;
   font-size: 0.6em;
-  color: #ccc;
+  color: $gray-300;
 }
 
 .search-typeahead {
@@ -26,7 +26,7 @@
     width: 24px;
     height: 24px;
     padding: 0;
-    color: #999;
+    color: $gray-400;
   }
 
   .rbt-menu {
@@ -48,7 +48,7 @@
 
       .page-list-meta {
         font-size: 0.9em;
-        color: #999;
+        color: $gray-400;
 
         > span {
           margin-right: 0.3rem;
@@ -213,7 +213,7 @@
       .wiki {
         padding: 16px;
         font-size: 13px;
-        border: solid 1px #ccc;
+        border: solid 1px $gray-300;
       }
     }
   }

+ 3 - 3
src/client/styles/scss/_shortcuts.scss

@@ -30,15 +30,15 @@
     margin: 0px 4px;
     /*Text Properties*/
     font: 18px/36px Helvetica, serif;
-    color: #666;
+    color: $secondary;
     text-align: center;
     text-transform: uppercase;
-    background: #fff;
+    background: white;
     border-radius: 4px;
     box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.5);
     /* SVG Properties*/
     polygon {
-      fill: #666;
+      fill: $secondary;
     }
 
     &.key-longer {

+ 1 - 1
src/client/styles/scss/_subnav.scss

@@ -56,7 +56,7 @@
     .picture {
       width: 22px;
       height: 22px;
-      border: 1px solid #ccc;
+      border: 1px solid $gray-300;
 
       &.picture-xs {
         width: 14px;

+ 2 - 2
src/client/styles/scss/_user.scss

@@ -16,7 +16,7 @@ $easeInOutCubic: cubic-bezier(0.65, 0, 0.35, 1);
   .user-page-name {
     margin: 0;
     font-size: 2.5em;
-    color: #666;
+    color: $secondary;
   }
 
   .picture {
@@ -26,7 +26,7 @@ $easeInOutCubic: cubic-bezier(0.65, 0, 0.35, 1);
 
   div.user-page-meta {
     padding-left: 0;
-    color: #999;
+    color: $gray-400;
 
     .user-page-username {
       font-weight: bold;

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

@@ -67,6 +67,7 @@ div.body {
     margin: 0 0 30px 0;
     font-size: 0.9em;
     color: lighten($gray-800, 35%);
+    border-left: 0.3rem solid #ddd;
   }
 
   img {

+ 16 - 9
src/client/styles/scss/atoms/_buttons.scss

@@ -1,14 +1,21 @@
-.btn.btn-outline-info.btn-like,
-.btn.btn-outline-warning.btn-bookmark {
-  color: $secondary;
-
-  &.active,
-  &:hover {
-    // header buttons are always white for active
-    color: white !important;
+.btn.btn-like {
+  @include button-outline-variant($secondary, lighten($info, 15%), rgba(lighten($info, 10%), 0.5), rgba(lighten($info, 10%), 0.5));
+  &:not(:disabled):not(.disabled):active,
+  &:not(:disabled):not(.disabled).active {
+    color: lighten($info, 15%);
+  }
+  &:not(:disabled):not(.disabled):not(:hover) {
+    background-color: transparent;
   }
+}
 
-  &:not(:hover):not(.active) {
+.btn.btn-bookmark {
+  @include button-outline-variant($secondary, $warning, rgba(lighten($warning, 20%), 0.5), rgba(lighten($warning, 20%), 0.5));
+  &:not(:disabled):not(.disabled):active,
+  &:not(:disabled):not(.disabled).active {
+    color: $warning;
+  }
+  &:not(:disabled):not(.disabled):not(:hover) {
     background-color: transparent;
   }
 }

+ 5 - 5
src/client/styles/scss/style-presentation.scss

@@ -94,14 +94,14 @@
           > td {
             padding: 1em;
             vertical-align: top;
-            border-top: 1px solid #999;
+            border-top: 1px solid $gray-400;
           }
         }
       }
       // Bottom align for column headings
       > thead > tr > th {
         vertical-align: bottom;
-        border-bottom: 2px solid #888;
+        border-bottom: 2px solid $gray-500;
       }
       // Remove top border from thead by default
       > caption + thead,
@@ -116,18 +116,18 @@
       }
       // Account for multiple tbody instances
       > tbody + tbody {
-        border-top: 2px solid #888;
+        border-top: 2px solid $gray-500;
       }
 
       // .table-bordered
-      border: 1px solid #999;
+      border: 1px solid $gray-400;
       > thead,
       > tbody,
       > tfoot {
         > tr {
           > th,
           > td {
-            border: 1px solid #999;
+            border: 1px solid $gray-400;
           }
         }
       }

+ 5 - 5
src/client/styles/scss/theme/_apply-colors-dark.scss

@@ -16,7 +16,7 @@ $color-tags: #949494 !default;
 $bgcolor-tags: $dark !default;
 
 // override bootstrap variables
-$border-color: #444;
+$border-color: $gray-700;
 $table-dark-color: $color-table;
 $table-dark-bg: $bgcolor-table;
 $table-dark-border-color: $border-color-table;
@@ -125,7 +125,7 @@ ul.pagination {
   .input-group {
     .input-group-text {
       color: darken(white, 30%);
-      background-color: rgba(#444, 0.7);
+      background-color: rgba($gray-700, 0.7);
     }
 
     .form-control {
@@ -141,10 +141,10 @@ ul.pagination {
 
   .btn-fill {
     .btn-label {
-      color: #ccc;
+      color: $gray-300;
     }
     .btn-label-text {
-      color: #aaa;
+      color: $gray-400;
     }
   }
 
@@ -180,7 +180,7 @@ ul.pagination {
  */
 .grw-drawer-toggler {
   @extend .btn-dark;
-  color: #999;
+  color: $gray-400;
 }
 
 /*

+ 2 - 2
src/client/styles/scss/theme/_apply-colors-kibela.scss

@@ -60,7 +60,7 @@ body.kibela {
         background-color: transparent;
 
         &:hover {
-          background: #eee;
+          background: $gray-100;
         }
       }
 
@@ -124,7 +124,7 @@ body.kibela {
 
     /* Modal */
     .modal-title {
-      color: #ffffff; // override header colors
+      color: white; // override header colors
     }
     .modal-content {
       background-color: $themelight;

+ 7 - 7
src/client/styles/scss/theme/antarctic.scss

@@ -49,8 +49,8 @@ html[dark] {
 
   // Background colors
   $bgcolor-global: $themelight;
-  $bgcolor-inline-code: #f0f0f0; //optional
-  $bgcolor-card: #f5f5f5;
+  $bgcolor-inline-code: $gray-100; //optional
+  $bgcolor-card: $gray-50;
 
   // Font colors
   $color-global: black;
@@ -81,7 +81,7 @@ html[dark] {
 
   // Sidebar
   $bgcolor-sidebar: $themecolor;
-  $bgcolor-sidebar-nav-item-active: rgba(#000000, 0.37); // optional
+  $bgcolor-sidebar-nav-item-active: rgba(black, 0.37); // optional
   $text-shadow-sidebar-nav-item-active: 0px 0px 10px #0099ff; // optional
   // Sidebar resize button
   $color-resize-button: $color-reversal;
@@ -98,7 +98,7 @@ html[dark] {
   $color-editor-icons: $color-global;
 
   // Border colors
-  $border-color-theme: #ccc; // former: `$navbar-border: #ccc;`
+  $border-color-theme: $gray-300; // former: `$navbar-border: $gray-300;`
   $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors
@@ -151,7 +151,7 @@ html[dark] {
 
 //   // Font colors
 //   $color-global: #eeeeee;
-//   $color-reversal: #333333;
+//   $color-reversal: $gray-900;
 //   // $color-header: desaturate($primary, 20%);
 //   $color-link: $primary;
 //   $color-link-hover: lighten($color-link, 10%);
@@ -169,13 +169,13 @@ html[dark] {
 
 //   // Logo colors
 //   $bgcolor-logo: $bgcolor-navbar;
-//   $fillcolor-logo-mark: #444;
+//   $fillcolor-logo-mark: $gray-700;
 
 //   // Icon colors
 //   $color-editor-icons: darken($accentcolor, 15%);
 
 //   // Border colors
-//   $border-color-theme: black; // former: `$navbar-border: #ccc;`
+//   $border-color-theme: black; // former: `$navbar-border: $gray-300;`
 
 //   // Dropdown colors
 //   $bgcolor-dropdown-link-active: $primary;

+ 9 - 9
src/client/styles/scss/theme/christmas.scss

@@ -19,7 +19,7 @@ $subthemecolor: #30882c;
 $bgcolor-global: $themelight;
 $linktext: $subthemecolor;
 $linktext-hover: lighten($subthemecolor, 15%);
-$sidebar-text: #ffffff;
+$sidebar-text: white;
 $fillcolor-logo-mark: lighten(desaturate($themecolor, 50%), 50%);
 $color-link-wiki: lighten($subthemecolor, 5%);
 $color-link-wiki-hover: lighten($color-link-wiki, 15%);
@@ -41,19 +41,19 @@ html[light],
 html[dark] {
   $primary: #d3c665;
   // Background colors
-  $bgcolor-card: #f5f5f5;
-  $bgcolor-inline-code: #f0f0f0; //optional
+  $bgcolor-card: $gray-50;
+  $bgcolor-inline-code: $gray-100; //optional
 
   // Font colors
   $color-global: #112744;
-  $color-reversal: #eee;
+  $color-reversal: $gray-100;
   $color-link: $subthemecolor;
   $color-link-hover: lighten($color-link, 10%);
   $color-link-nabvar: $color-reversal;
   $color-inline-code: #c7254e; // optional
 
   // Table colors
-  $border-color-table: #aaa; // optional
+  $border-color-table: $gray-400; // optional
 
   // List Group colors
   // $color-list: $color-global;
@@ -74,7 +74,7 @@ html[dark] {
 
   // Sidebar
   $bgcolor-sidebar: $subthemecolor;
-  $bgcolor-sidebar-nav-item-active: rgba(#000000, 0.37); // optional
+  $bgcolor-sidebar-nav-item-active: rgba(black, 0.37); // optional
   $text-shadow-sidebar-nav-item-active: 0px 0px 10px $primary; // optional
   // Sidebar resize button
   $color-resize-button: $color-reversal;
@@ -90,7 +90,7 @@ html[dark] {
   $color-editor-icons: $color-global;
 
   // Border colors
-  $border-color-theme: #ccc; // former: `$navbar-border: #ccc;`
+  $border-color-theme: $gray-300; // former: `$navbar-border: $gray-300;`
   $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors
@@ -136,11 +136,11 @@ html[dark] {
   .nologin {
     .input-group {
       .input-group-text {
-        color: #444;
+        color: $gray-700;
         background-color: rgba(darken(white, 20%), 0.6);
       }
       .form-control {
-        color: #444;
+        color: $gray-700;
         background-color: rgba(white, 0.6);
       }
     }

+ 5 - 5
src/client/styles/scss/theme/default.scss

@@ -117,7 +117,7 @@ html[dark] {
 
   // Font colors
   $color-global: #a8a8a8;
-  $color-reversal: #333333;
+  $color-reversal: $gray-900;
   // $color-header: desaturate($primary, 20%);
   $color-link: #7b9ad5;
   $color-link-hover: lighten($color-link, 10%);
@@ -148,7 +148,7 @@ html[dark] {
 
   // Logo colors
   $bgcolor-logo: $bgcolor-navbar;
-  $fillcolor-logo-mark: #444;
+  $fillcolor-logo-mark: $gray-700;
 
   // Sidebar
   $bgcolor-sidebar: #122c55;
@@ -169,7 +169,7 @@ html[dark] {
   $bgcolor-subnav: lighten($bgcolor-global, 4%); // optional
 
   // Tabs
-  $bordercolor-nav-tabs: #444; // optional
+  $bordercolor-nav-tabs: $gray-700; // optional
   // $color-nav-tabs-link-active: #; //optional
   $bordercolor-nav-tabs-hover: #666 #666 $bordercolor-nav-tabs; // optional
   // $bordercolor-nav-tabs-active: # # $bgcolor-global; // optional
@@ -182,8 +182,8 @@ html[dark] {
   $color-editor-icons: $color-global;
 
   // Border colors
-  $border-color-theme: #444;
-  $bordercolor-inline-code: #666; // optional
+  $border-color-theme: $gray-700;
+  $bordercolor-inline-code: $secondary; // optional
 
   // Dropdown colors
   $bgcolor-dropdown-link-active: $primary;

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

@@ -14,7 +14,7 @@ html[dark] {
 
   // Font colors
   $color-global: #95abba;
-  $color-reversal: #222;
+  $color-reversal: $gray-900;
   $color-header: #95abba;
   $color-link: $accentcolor;
   $color-link-hover: lighten($color-link, 20%);

+ 3 - 3
src/client/styles/scss/theme/halloween.scss

@@ -38,7 +38,7 @@ html[dark] {
   // Background colors
   $bgcolor-global: #050000;
   $bgcolor-inline-code: #1f1f22; //optional
-  $bgcolor-card: #f5f5f5;
+  $bgcolor-card: $gray-50;
 
   // Font colors
   $color-global: #e9af2b;
@@ -93,7 +93,7 @@ html[dark] {
   $color-editor-icons: $color-global;
 
   // Border colors
-  $border-color-theme: #ccc; // former: `$navbar-border: #ccc;`
+  $border-color-theme: $gray-300; // former: `$navbar-border: $gray-300;`
   $bordercolor-inline-code: #4d4d4d; // optional
 
   // Dropdown colors
@@ -114,6 +114,6 @@ html[dark] {
 
   pre {
     color: #edba4a;
-    background: #000000;
+    background: black;
   }
 }

+ 5 - 5
src/client/styles/scss/theme/island.scss

@@ -8,9 +8,9 @@ html[light],
 html[dark] {
   $primary: $color-primary;
   // Background colors
-  $bgcolor-card: #f5f5f5;
+  $bgcolor-card: $gray-50;
   $bgcolor-global: lighten($color-themelight, 10%);
-  $bgcolor-inline-code: #f0f0f0; //optional
+  $bgcolor-inline-code: $gray-100; //optional
 
   // Font colors
   $color-global: #112744;
@@ -49,7 +49,7 @@ html[dark] {
 
   // Sidebar
   $bgcolor-sidebar: #0d3955;
-  $bgcolor-sidebar-nav-item-active: rgba(#000000, 0.37);
+  $bgcolor-sidebar-nav-item-active: rgba(black, 0.37);
   // $bgcolor-sidebar-nav-item-active: rgba(#969494, 0.3); // optional
   $text-shadow-sidebar-nav-item-active: 0px 0px 10px #0099ff; // optional
   // Sidebar resize button
@@ -64,13 +64,13 @@ html[dark] {
   $bgcolor-sidebar-list-group: #eff8f7; // optional
 
   // Tabs
-  $bordercolor-nav-tabs: #ccc; // optional
+  $bordercolor-nav-tabs: $gray-300; // optional
 
   // Icon colors
   $color-editor-icons: $color-global;
 
   // Border colors
-  $border-color-theme: #ccc;
+  $border-color-theme: $gray-300;
   $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors

+ 1 - 1
src/client/styles/scss/theme/kibela.scss

@@ -20,7 +20,7 @@ html[dark] {
   $color-link: rgb(74, 109, 204);
   $color-link-hover: lighten($color-link, 12%);
   $sidebar-text: $bgcolor-theme;
-  $color-reversal: #eee;
+  $color-reversal: $gray-100;
 
   $primary: $bgcolor-theme;
   $info: lighten($bgcolor-theme, 20%);

+ 4 - 4
src/client/styles/scss/theme/mono-blue.scss

@@ -12,12 +12,12 @@ html[light] {
 
   // Background colors
   $bgcolor-global: $themelight;
-  $bgcolor-inline-code: #f0f0f0; //optional
+  $bgcolor-inline-code: $gray-100; //optional
   $bgcolor-card: darken($themelight, 5%);
 
   // Font colors
   $color-global: $themecolor;
-  $color-reversal: #eee;
+  $color-reversal: $gray-100;
   $color-link: lighten($primary, 5%);
   $color-link-hover: lighten($color-link, 12%);
   $color-link-wiki: lighten($primary, 20%);
@@ -62,7 +62,7 @@ html[light] {
   $color-editor-icons: $color-global;
 
   // Border colors
-  $border-color-theme: #ccc;
+  $border-color-theme: $gray-300;
   $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors
@@ -108,7 +108,7 @@ html[dark] {
 
   // Font colors
   $color-global: #d3d4d4;
-  $color-reversal: #eee;
+  $color-reversal: $gray-100;
   $color-link: #97d1f0;
   $color-link-hover: darken($color-link, 12%);
   $color-link-wiki: lighten($primary, 20%);

+ 4 - 4
src/client/styles/scss/theme/nature.scss

@@ -38,11 +38,11 @@ $themecolor: #12b105;
 html[light],
 html[dark] {
   $primary: #460039;
-  $light: #f0f0f0;
+  $light: $gray-100;
 
   // Background colors
   $bgcolor-global: #fdfdfd;
-  $bgcolor-inline-code: #f0f0f0; //optional
+  $bgcolor-inline-code: $gray-100; //optional
   $bgcolor-card: #f1ffe4;
   $bgcolor-subnav: #fafafa;
 
@@ -79,7 +79,7 @@ html[dark] {
   $color-editor-icons: $color-global;
 
   // Border colors
-  $border-color-theme: #ccc;
+  $border-color-theme: $gray-300;
   $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors
@@ -88,7 +88,7 @@ html[dark] {
   $color-dropdown-link-hover: $color-global;
 
   // Table colors
-  $border-color-table: #aaa; // optional
+  $border-color-table: $gray-400; // optional
 
   // admin theme box
   $color-theme-color-box: lighten($primary, 20%);

+ 3 - 3
src/client/styles/scss/theme/spring.scss

@@ -32,8 +32,8 @@ html[dark] {
 
   // Background colors
   $bgcolor-global: white;
-  $bgcolor-inline-code: #f0f0f0; //optional
-  $bgcolor-card: #f5f5f5;
+  $bgcolor-inline-code: $gray-100; //optional
+  $bgcolor-card: $gray-50;
 
   // Font colors
   $color-global: black;
@@ -79,7 +79,7 @@ html[dark] {
   $color-editor-icons: $color-global;
 
   // Border colors
-  $border-color-theme: #ccc; // former: `$navbar-border: #ccc;`
+  $border-color-theme: $gray-300; // former: `$navbar-border: $gray-300;`
   $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors

+ 4 - 4
src/client/styles/scss/theme/wood.scss

@@ -41,7 +41,7 @@ html[dark] {
   $primary: #aaa45f;
 
   // Background colors
-  $bgcolor-global: #ffffff;
+  $bgcolor-global: white;
   $bgcolor-card: #ece8de;
 
   // Font colors
@@ -63,7 +63,7 @@ html[dark] {
   // List Group colors
   // $color-list: $color-global;
   $bgcolor-list: transparent;
-  $color-list-hover: #eee;
+  $color-list-hover: $gray-100;
   $bgcolor-list-hover: darken($bgcolor-global, 3%);
   // $color-list-active: $color-reversal;
   // $bgcolor-list-active: $primary;
@@ -71,7 +71,7 @@ html[dark] {
   // Table colors
   // $color-table: #; // optional
   // $bgcolor-table: #; // optional
-  $border-color-table: #aaa; // optional
+  $border-color-table: $gray-400; // optional
   // $color-table-hover: #; // optional
   // $bgcolor-table-hover: #; // optional
 
@@ -97,7 +97,7 @@ html[dark] {
   $bgcolor-resize-button: $themecolor;
 
   // Border colors
-  $border-color-theme: #ccc; // former: `$navbar-border: #ccc;`
+  $border-color-theme: $gray-300; // former: `$navbar-border: $gray-300;`
   $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors

+ 5 - 5
src/linter-checker/test.scss

@@ -2,7 +2,7 @@
  * VSCode の Stylelint 設定チェック方法
  *
  * 1. .stylelintrc.json ファイル中の `src/linter-checker/test.scss` 行を削除
- * 
+ *
  * 2. VSCode で以下のエラーが表示されていることを確認
  *   - color で stylelint(order/properties-order)
  *   - ul で stylelint(selector-combinator-space-after)
@@ -16,10 +16,10 @@
  */
 
 .test {
-  background: #ccc;
-  color: #333;
+  background: $gray-300;
+  color: $gray-900;
 
-  ul>li {
+  ul > li {
     margin-left: 0;
   }
-}
+}

+ 7 - 1
src/server/middlewares/access-token-parser.js

@@ -16,6 +16,12 @@ module.exports = (crowi) => {
     logger.debug('accessToken is', accessToken);
 
     const user = await User.findUserByApiToken(accessToken);
+
+    if (user == null) {
+      logger.debug('The access token is invalid');
+      return next();
+    }
+
     // transforming attributes
     // see User model
     req.user = user.toObject();
@@ -23,7 +29,7 @@ module.exports = (crowi) => {
 
     logger.debug('Access token parsed: skipCsrfVerify');
 
-    next();
+    return next();
   };
 
 };

+ 1 - 1
src/server/views/admin/customize.html

@@ -7,7 +7,7 @@
 {{ cdnStyleTag('jquery-ui') }}
 <style>
   .CodeMirror {
-    border: 1px solid #eee;
+    border: 1px solid $gray-100;
   }
 </style>
 {% endblock %}

+ 83 - 0
src/test/middlewares/access-token-parser.test.js

@@ -0,0 +1,83 @@
+const mongoose = require('mongoose');
+
+const { getInstance } = require('../setup-crowi');
+
+describe('accessTokenParser', () => {
+  let crowi;
+  let accessTokenParser;
+
+  let User;
+  let targetUser;
+
+  beforeAll(async(done) => {
+    crowi = await getInstance();
+    User = mongoose.model('User');
+    accessTokenParser = require('@server/middlewares/access-token-parser')(crowi);
+
+    targetUser = await User.create({
+      name: 'Example for access token parser',
+      username: 'targetUser',
+      password: 'usertestpass',
+      lang: 'en_US',
+      apiToken: 'N4xPDjh48TBsC7ahUN+ajjL5asnGpwtA5VAR+EhIDeg=',
+    });
+
+
+    done();
+  });
+
+  crowi = {
+    model: jest.fn().mockReturnValue(User),
+  };
+  const req = {
+    skipCsrfVerify: false,
+    query: {},
+    body: {},
+    user: {},
+  };
+
+  const res = {};
+  const next = jest.fn().mockReturnValue('next');
+
+  test('without accessToken', async() => {
+    const result = await accessTokenParser(req, res, next);
+
+    expect(next).toHaveBeenCalled();
+    expect(result).toBe('next');
+    expect(req.skipCsrfVerify).toBe(false);
+  });
+
+  test('with invalid accessToken', async() => {
+    req.query.access_token = 'invalidAccessToken';
+
+    const result = await accessTokenParser(req, res, next);
+
+    expect(next).toHaveBeenCalled();
+    expect(result).toBe('next');
+    expect(req.skipCsrfVerify).toBe(false);
+  });
+
+  test('with accessToken in query', async() => {
+    req.query.access_token = 'N4xPDjh48TBsC7ahUN+ajjL5asnGpwtA5VAR+EhIDeg=';
+
+    const result = await accessTokenParser(req, res, next);
+
+    expect(next).toHaveBeenCalled();
+    expect(result).toBe('next');
+    expect(req.skipCsrfVerify).toBe(true);
+    expect(req.user._id).toStrictEqual(targetUser._id);
+  });
+
+  test('with accessToken in body', async() => {
+    req.body.access_token = 'N4xPDjh48TBsC7ahUN+ajjL5asnGpwtA5VAR+EhIDeg=';
+
+    const result = await accessTokenParser(req, res, next);
+
+    expect(next).toHaveBeenCalled();
+    expect(result).toBe('next');
+    expect(req.skipCsrfVerify).toBe(true);
+    expect(req.user._id).toStrictEqual(targetUser._id);
+  });
+
+
+});