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

Merge branch 'imprv/update-cache-bulk' into imprv/update-cache-bulk-with-comments

yusuketk 5 лет назад
Родитель
Сommit
bbc3c57df5
100 измененных файлов с 1025 добавлено и 836 удалено
  1. 4 1
      resource/locales/en-US/admin/admin.json
  2. 132 43
      resource/locales/en-US/sandbox-bootstrap4.md
  3. 5 5
      resource/locales/en-US/sandbox.md
  4. 4 6
      resource/locales/en-US/welcome.md
  5. 4 1
      resource/locales/ja/admin/admin.json
  6. 132 43
      resource/locales/ja/sandbox-bootstrap4.md
  7. 5 5
      resource/locales/ja/sandbox.md
  8. 1 1
      resource/locales/ja/translation.json
  9. 5 7
      resource/locales/ja/welcome.md
  10. 0 2
      src/client/js/app.jsx
  11. 2 0
      src/client/js/bootstrap.jsx
  12. 16 6
      src/client/js/components/Admin/Customize/CustomizeTitle.jsx
  13. 1 1
      src/client/js/components/Admin/ExportArchiveData/ArchiveFilesTable.jsx
  14. 7 11
      src/client/js/components/Admin/ExportArchiveData/ArchiveFilesTableMenu.jsx
  15. 1 1
      src/client/js/components/Admin/ImportData/GrowiArchive/ImportCollectionItem.jsx
  16. 2 2
      src/client/js/components/Admin/MarkdownSetting/XssForm.jsx
  17. 2 2
      src/client/js/components/Admin/Notification/GlobalNotificationList.jsx
  18. 3 3
      src/client/js/components/Admin/Notification/ManageGlobalNotification.jsx
  19. 1 1
      src/client/js/components/Admin/Security/SecurityManagement.jsx
  20. 4 3
      src/client/js/components/Admin/UserManagement.jsx
  21. 3 5
      src/client/js/components/Admin/Users/ExternalAccountTable.jsx
  22. 1 1
      src/client/js/components/Admin/Users/RemoveAdminButton.jsx
  23. 1 1
      src/client/js/components/Admin/Users/StatusActivateButton.jsx
  24. 1 1
      src/client/js/components/Admin/Users/StatusSuspendedButton.jsx
  25. 1 1
      src/client/js/components/Admin/Users/UserRemoveButton.jsx
  26. 3 7
      src/client/js/components/CreateTemplateModal.jsx
  27. 17 17
      src/client/js/components/LoginForm.jsx
  28. 1 1
      src/client/js/components/Me/PasswordSettings.jsx
  29. 30 32
      src/client/js/components/Me/PersonalSettings.jsx
  30. 0 5
      src/client/js/components/Navbar/PersonalDropdown.jsx
  31. 6 8
      src/client/js/components/PageCreateModal.jsx
  32. 1 1
      src/client/js/components/PageDeleteModal.jsx
  33. 13 16
      src/client/js/components/PageEditor/CodeMirrorEditor.jsx
  34. 1 1
      src/client/js/components/PageEditor/OptionsSelector.jsx
  35. 9 7
      src/client/js/components/PageHistory/Revision.jsx
  36. 1 1
      src/client/js/components/RecentCreated/RecentCreated.jsx
  37. 15 9
      src/client/js/components/SavePageControls/GrantSelector.jsx
  38. 13 8
      src/client/js/components/Sidebar/SidebarNav.jsx
  39. 1 1
      src/client/js/components/User/UserPictureList.jsx
  40. 17 5
      src/client/js/services/PageContainer.js
  41. 0 78
      src/client/styles/agile-admin/inverse/variables.scss
  42. 0 1
      src/client/styles/scss/_editor-attachment.scss
  43. 2 1
      src/client/styles/scss/_hljs.scss
  44. 1 24
      src/client/styles/scss/_layout.scss
  45. 1 2
      src/client/styles/scss/_layout_growi.scss
  46. 0 8
      src/client/styles/scss/_layout_variable.scss
  47. 0 2
      src/client/styles/scss/_mixins.scss
  48. 0 1
      src/client/styles/scss/_on-edit.scss
  49. 13 27
      src/client/styles/scss/_override-bootstrap-variables.scss
  50. 0 9
      src/client/styles/scss/_override-bootstrap.scss
  51. 1 9
      src/client/styles/scss/_search.scss
  52. 13 0
      src/client/styles/scss/_vendor-presentation.scss
  53. 1 12
      src/client/styles/scss/_wiki.scss
  54. 11 0
      src/client/styles/scss/atoms/_code.scss
  55. 4 0
      src/client/styles/scss/atoms/_pre.scss
  56. 2 2
      src/client/styles/scss/style-app.scss
  57. 4 7
      src/client/styles/scss/style-presentation.scss
  58. 21 59
      src/client/styles/scss/theme/_apply-colors-dark.scss
  59. 5 0
      src/client/styles/scss/theme/_apply-colors-kibela.scss
  60. 14 0
      src/client/styles/scss/theme/_apply-colors-light.scss
  61. 35 9
      src/client/styles/scss/theme/_apply-colors.scss
  62. 0 34
      src/client/styles/scss/theme/_mixins-for-tables.scss
  63. 0 2
      src/client/styles/scss/theme/_reboot-bootstrap-colors.scss
  64. 41 0
      src/client/styles/scss/theme/_reboot-bootstrap-nav.scss
  65. 72 0
      src/client/styles/scss/theme/_reboot-bootstrap-tables.scss
  66. 10 4
      src/client/styles/scss/theme/_reboot-bootstrap-theme-colors.scss
  67. 28 11
      src/client/styles/scss/theme/antarctic.scss
  68. 30 54
      src/client/styles/scss/theme/christmas.scss
  69. 34 6
      src/client/styles/scss/theme/default.scss
  70. 35 47
      src/client/styles/scss/theme/future.scss
  71. 35 32
      src/client/styles/scss/theme/halloween.scss
  72. 3 0
      src/client/styles/scss/theme/island.scss
  73. 16 67
      src/client/styles/scss/theme/kibela.scss
  74. 34 0
      src/client/styles/scss/theme/mixins/_tables.scss
  75. 6 3
      src/client/styles/scss/theme/mono-blue.scss
  76. 7 6
      src/client/styles/scss/theme/nature.scss
  77. 21 12
      src/client/styles/scss/theme/spring.scss
  78. 4 3
      src/client/styles/scss/theme/wood.scss
  79. 4 2
      src/lib/models/devided-page-path.js
  80. 6 4
      src/lib/models/linked-page-path.js
  81. 2 2
      src/server/models/user.js
  82. 1 3
      src/server/routes/apiv3/users.js
  83. 1 1
      src/server/routes/installer.js
  84. 22 4
      src/server/service/customize.js
  85. 1 1
      src/server/service/passport.js
  86. 1 1
      src/server/views/admin/app.html
  87. 4 1
      src/server/views/admin/customize.html
  88. 1 1
      src/server/views/admin/export.html
  89. 1 1
      src/server/views/admin/external-accounts.html
  90. 1 1
      src/server/views/admin/global-notification-detail.html
  91. 1 1
      src/server/views/admin/importer.html
  92. 1 1
      src/server/views/admin/index.html
  93. 1 1
      src/server/views/admin/markdown.html
  94. 1 1
      src/server/views/admin/notification.html
  95. 1 1
      src/server/views/admin/search.html
  96. 1 1
      src/server/views/admin/security.html
  97. 1 1
      src/server/views/admin/user-group-detail.html
  98. 1 1
      src/server/views/admin/user-groups.html
  99. 1 1
      src/server/views/admin/users.html
  100. 1 1
      src/server/views/installer.html

+ 4 - 1
resource/locales/en-US/admin/admin.json

@@ -125,7 +125,10 @@
     "code_highlight": "Code highlight",
     "nocdn_desc": "This function is disabled when the environment variable <code>NO_CDN=true</code>.<br>Github style has been forcibly applied.",
     "custom_title": "Custom title",
-    "custom_title_detail": "You can customize <code>&lt;title&gt;</code> tag.<br><code>&#123;&#123;sitename&#125;&#125;</code> will be automatically replaced with the app name, and <code>&#123;&#123;page&#125;&#125;</code> will be replaced with the page name/path.",
+    "custom_title_detail": "You can customize <code>&lt;title&gt;</code> tag. Following placeholders will be automatically replaced:",
+    "custom_title_detail_placeholder1": "<code>&#123;&#123;sitename&#125;&#125;</code> - The site name of this wiki.",
+    "custom_title_detail_placeholder2": "<code>&#123;&#123;pagename&#125;&#125;</code> - The page name of the current page.",
+    "custom_title_detail_placeholder3": "<code>&#123;&#123;pagepath&#125;&#125;</code> - The page path of the current page.",
     "custom_header": "Custom HTML header",
     "custom_header_detail": "You can customize HTML header that applies all pages. Your custom script will be inserted in <code>&lt;header&gt;</code> but above other <code>&lt;script&gt;</code> tags.<br>Relaod page to see changes.",
     "custom_css": "Custom CSS",

+ 132 - 43
resource/locales/en-US/sandbox-bootstrap4.md

@@ -6,92 +6,181 @@
 <span class="badge badge-info">Info</span>
 <span class="badge badge-warning">Warning</span>
 <span class="badge badge-danger">Danger</span>
-<span class="badge badge-light">Light</span>
+<span class="badge badge-light text-dark">Light</span>
 <span class="badge badge-dark">Dark</span>
 
+<span class="badge badge-blue">Blue</span>
+<span class="badge badge-indigo">Indigo</span>
+<span class="badge badge-purple">Purple</span>
+<span class="badge badge-pink">Pink</span>
+<span class="badge badge-red">Red</span>
+<span class="badge badge-orange">Orange</span>
+<span class="badge badge-yellow">Yellow</span>
+<span class="badge badge-green">Green</span>
+<span class="badge badge-teal">Teal</span>
+<span class="badge badge-cyan">Cyan</span>
+
+
 # Alerts
 
-<div class="alert alert-success" role="alert"><b>Well done!</b> You successfully read this important alert message. </div>
-<div class="alert alert-info" role="alert"><b>Heads up!</b> This alert needs your attention, but it's not super important. </div>
-<div class="alert alert-warning" role="alert"><b>Warning!</b> Better check yourself, you're not looking too good. </div>
-<div class="alert alert-danger" role="alert"><b>Oh snap!</b> Change a few things up and try submitting again. </div>
+<div class="alert alert-primary" role="alert">
+  This is a primary alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-secondary" role="alert">
+  This is a secondary alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-success" role="alert">
+  This is a success alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-danger" role="alert">
+  This is a danger alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-warning" role="alert">
+  This is a warning alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-info" role="alert">
+  This is a info alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-light text-dark" role="alert">
+  This is a light alert with <a href="#" class="alert-link text-dark">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-dark" role="alert">
+  This is a dark alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
 
 # Cards
 
-<div class="card">
-  <div class="card-header">Card header without title</div>
+<div class="d-flex">
+
+<div class="mr-3">
+<div class="card text-white bg-primary mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Primary card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-light">
-  <div class="card-header">Card header without title</div>
+<div class="card text-white bg-secondary mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Secondary card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-secondary text-white">
-  <div class="card-header">Card header without title</div>
+<div class="card text-white bg-success mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Success card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-dark text-white">
-  <div class="card-header">Card header without title</div>
+<div class="card text-white bg-danger mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Danger card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-primary text-white">
-  <div class="card-header">Card header without title</div>
+<div class="card text-white bg-warning mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Warning card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-success text-white">
-  <div class="card-header">Card header without title</div>
+<div class="card text-white bg-info mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Info card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-info text-white">
-  <div class="card-header">Card header without title</div>
+<div class="card bg-light mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Light card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-warning text-white">
-  <div class="card-header">Card header without title</div>
+<div class="card text-white bg-dark mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Dark card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
+</div>
 
-<div class="card bg-danger text-white">
-  <div class="card-header">Card header without title</div>
+<div>
+<div class="card border-primary mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-primary">
+    <h5 class="card-title">Primary card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-secondary mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-secondary">
+    <h5 class="card-title">Secondary card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-success mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-success">
+    <h5 class="card-title">Success card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-danger mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-danger">
+    <h5 class="card-title">Danger card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-warning mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-warning">
+    <h5 class="card-title">Warning card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-info mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-info">
+    <h5 class="card-title">Info card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-light mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Light card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-dark mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-dark">
+    <h5 class="card-title">Dark card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
+</div>
+
+</div>
 
 # Wells
 
 ## Default well
 
-<div class="card card-body bg-light">Look, I'm in a well! </div>
+<div class="card card-body">Look, I'm in a well! </div>
 
 ## Optional classes
 
-<div class="card card-body bg-light p-5">Look, I'm in a well! </div>
-
-<div class="card card-body bg-light p-2">Look, I'm in a well! </div>
+<div class="card card-body bg-primary text-light p-2">Look, I'm in a well! </div>
 
 # Typography
 

+ 5 - 5
resource/locales/en-US/sandbox.md

@@ -252,12 +252,12 @@ This is the most flexible linker.
 Both the page description and link address can be displayed on the page.
 
 ```
-[[./Bootstrap3]]
-Example of Bootstrap3 is[[here>./Bootstrap3]]
+[[./Bootstrap4]]
+Example of Bootstrap4 is[[here>./Bootstrap4]]
 ```
 
 [[../user]]
-Example of Bootstrap3 is[[here>./Bootstrap3]]
+Example of Bootstrap4 is[[here>./Bootstrap4]]
 
 # :pencil: Lists
 
@@ -449,8 +449,8 @@ See [emojione](https://www.emojione.com/)
 
 # :heavy_plus_sign: More..
 
-- Try to attach Bootstrap3 Tags?
-    - :arrow_right: [/Sandbox/Bootstrap3]
+- Try to attach Bootstrap4 Tags?
+    - :arrow_right: [/Sandbox/Bootstrap4]
 - Try to draw Diagrams?
     - :arrow_right: [/Sandbox/Diagrams]
 - Try to write Math Formulas?

+ 4 - 6
resource/locales/en-US/welcome.md

@@ -3,16 +3,14 @@
 [![GitHub Releases](https://img.shields.io/github/release/weseek/growi.svg)](https://github.com/weseek/growi/releases/latest)
 [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
 
-<div class="card">
-  <div class="card-header">Tips</div>
+<div class="card border-primary">
+  <div class="card-header bg-primary text-light">Tips</div>
   <div class="card-body"><ul>
-    <li>Ctrl(⌘)-/ to show quick help</li>
-    <li>You can write HTML with <a href="https://getbootstrap.com/docs/3.3/css/">Bootstrap 3</a>.</li>
+    <li>Ctrl(⌘) + "/" to show quick help</li>
+    <li>You can write HTML with <a href="https://getbootstrap.com/docs/4.5/components/">Bootstrap 4</a>.</li>
   </ul></div>
 </div>
 
-<div class="clearfix"></div>
-
 Contents
 =========
 

+ 4 - 1
resource/locales/ja/admin/admin.json

@@ -125,7 +125,10 @@
     "code_highlight": "コードハイライト",
     "nocdn_desc": "この機能は、環境変数 <code>NO_CDN=true</code> の時は無効化されます。<br>GitHub スタイルが適用されています。",
     "custom_title": "カスタム Title",
-    "custom_title_detail": "<code>&lt;title&gt;</code>タグのコンテンツをカスタマイズできます。<br><code>&#123;&#123;sitename&#125;&#125;</code>がサイト名、<code>&#123;&#123;page&#125;&#125;</code>がページ名またはページパスに置換されます。",
+    "custom_title_detail": "<code>&lt;title&gt;</code>タグのコンテンツをカスタマイズできます。以下のプレースホルダーは自動的に置換されます:",
+    "custom_title_detail_placeholder1": "<code>&#123;&#123;sitename&#125;&#125;</code> - この Wiki のサイト名",
+    "custom_title_detail_placeholder2": "<code>&#123;&#123;pagename&#125;&#125;</code> - 現在表示中のページ名",
+    "custom_title_detail_placeholder3": "<code>&#123;&#123;pagepath&#125;&#125;</code> - 現在表示中のページパス",
     "custom_header": "カスタム HTML Header",
     "custom_header_detail": "システム全体に適用される HTML を記述できます。<code>&lt;header&gt;</code> タグ内の他の <code>&lt;script&gt;</code> タグ読み込み前に展開されます。<br>変更の反映はページの更新が必要です。",
     "custom_css": "カスタム CSS",

+ 132 - 43
resource/locales/ja/sandbox-bootstrap4.md

@@ -6,92 +6,181 @@
 <span class="badge badge-info">Info</span>
 <span class="badge badge-warning">Warning</span>
 <span class="badge badge-danger">Danger</span>
-<span class="badge badge-light">Light</span>
+<span class="badge badge-light text-dark">Light</span>
 <span class="badge badge-dark">Dark</span>
 
+<span class="badge badge-blue">Blue</span>
+<span class="badge badge-indigo">Indigo</span>
+<span class="badge badge-purple">Purple</span>
+<span class="badge badge-pink">Pink</span>
+<span class="badge badge-red">Red</span>
+<span class="badge badge-orange">Orange</span>
+<span class="badge badge-yellow">Yellow</span>
+<span class="badge badge-green">Green</span>
+<span class="badge badge-teal">Teal</span>
+<span class="badge badge-cyan">Cyan</span>
+
+
 # Alerts
 
-<div class="alert alert-success" role="alert"><b>Well done!</b> You successfully read this important alert message. </div>
-<div class="alert alert-info" role="alert"><b>Heads up!</b> This alert needs your attention, but it's not super important. </div>
-<div class="alert alert-warning" role="alert"><b>Warning!</b> Better check yourself, you're not looking too good. </div>
-<div class="alert alert-danger" role="alert"><b>Oh snap!</b> Change a few things up and try submitting again. </div>
+<div class="alert alert-primary" role="alert">
+  This is a primary alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-secondary" role="alert">
+  This is a secondary alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-success" role="alert">
+  This is a success alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-danger" role="alert">
+  This is a danger alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-warning" role="alert">
+  This is a warning alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-info" role="alert">
+  This is a info alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-light text-dark" role="alert">
+  This is a light alert with <a href="#" class="alert-link text-dark">an example link</a>. Give it a click if you like.
+</div>
+<div class="alert alert-dark" role="alert">
+  This is a dark alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
+</div>
 
 # Cards
 
-<div class="card">
-  <div class="card-header">Card header without title</div>
+<div class="d-flex">
+
+<div class="mr-3">
+<div class="card text-white bg-primary mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Primary card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-light">
-  <div class="card-header">Card header without title</div>
+<div class="card text-white bg-secondary mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Secondary card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-secondary text-white">
-  <div class="card-header">Card header without title</div>
+<div class="card text-white bg-success mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Success card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-dark text-white">
-  <div class="card-header">Card header without title</div>
+<div class="card text-white bg-danger mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Danger card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-primary text-white">
-  <div class="card-header">Card header without title</div>
+<div class="card text-white bg-warning mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Warning card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-success text-white">
-  <div class="card-header">Card header without title</div>
+<div class="card text-white bg-info mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Info card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-info text-white">
-  <div class="card-header">Card header without title</div>
+<div class="card bg-light mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Light card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
-
-<div class="card bg-warning text-white">
-  <div class="card-header">Card header without title</div>
+<div class="card text-white bg-dark mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Dark card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
+</div>
 
-<div class="card bg-danger text-white">
-  <div class="card-header">Card header without title</div>
+<div>
+<div class="card border-primary mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-primary">
+    <h5 class="card-title">Primary card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-secondary mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-secondary">
+    <h5 class="card-title">Secondary card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-success mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-success">
+    <h5 class="card-title">Success card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-danger mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-danger">
+    <h5 class="card-title">Danger card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-warning mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-warning">
+    <h5 class="card-title">Warning card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-info mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-info">
+    <h5 class="card-title">Info card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-light mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
   <div class="card-body">
-    Card body content
+    <h5 class="card-title">Light card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
+  </div>
+</div>
+<div class="card border-dark mb-3" style="max-width: 18rem;">
+  <div class="card-header">Header</div>
+  <div class="card-body text-dark">
+    <h5 class="card-title">Dark card title</h5>
+    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
   </div>
 </div>
+</div>
+
+</div>
 
 # Wells
 
 ## Default well
 
-<div class="card card-body bg-light">Look, I'm in a well! </div>
+<div class="card card-body">Look, I'm in a well! </div>
 
 ## Optional classes
 
-<div class="card card-body bg-light p-5">Look, I'm in a well! </div>
-
-<div class="card card-body bg-light p-2">Look, I'm in a well! </div>
+<div class="card card-body bg-primary text-light p-2">Look, I'm in a well! </div>
 
 # Typography
 

+ 5 - 5
resource/locales/ja/sandbox.md

@@ -251,12 +251,12 @@ ___
 記述中のページを基点とした相対リンクと、表示テキストに対するリンクを同時に実現できます。
 
 ```
-[[./Bootstrap3]]
-Bootstrap3のExampleは[[こちら>./Bootstrap3]]
+[[./Bootstrap4]]
+Bootstrap4のExampleは[[こちら>./Bootstrap4]]
 ```
 
 [[../user]]
-Bootstrap3のExampleは[[こちら>./Bootstrap3]]
+Bootstrap4のExampleは[[こちら>./Bootstrap4]]
 
 # :pencil: Lists
 
@@ -449,8 +449,8 @@ See [emojione](https://www.emojione.com/)
 
 # :heavy_plus_sign: 更に…
 
-- Bootstrap3 のタグを使う
-    - :arrow_right: [/Sandbox/Bootstrap3]
+- Bootstrap4 のタグを使う
+    - :arrow_right: [/Sandbox/Bootstrap4]
 - 図表を書く
     - :arrow_right: [/Sandbox/Diagrams]
 - 数式を書く

+ 1 - 1
resource/locales/ja/translation.json

@@ -315,7 +315,7 @@
       "konami_code_url": "https://ja.wikipedia.org/wiki/コナミコマンド"
     },
     "editor": {
-      "titile": "エディターショートカット",
+      "title": "エディターショートカット",
       "Indent": "インデント",
       "Outdent": "左インデント",
       "Save Page": "保存",

+ 5 - 7
resource/locales/ja/welcome.md

@@ -3,16 +3,14 @@
 [![GitHub Releases](https://img.shields.io/github/release/weseek/growi.svg)](https://github.com/weseek/growi/releases/latest)
 [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
 
-<div class="card">
-  <div class="card-header">Tips</div>
+<div class="card border-primary">
+  <div class="card-header bg-primary text-light">Tips</div>
   <div class="card-body"><ul>
-    <li>Ctrl(⌘)-/ でショートカットヘルプを表示します</li>
-      <li>HTML/CSS の記述時は、<a href="https://getbootstrap.com/docs/3.3/css/">Bootstrap 3</a> を利用できます</li>
+    <li>Ctrl(⌘) + "/" でショートカットヘルプを表示します</li>
+    <li>HTML/CSS の記述には、<a href="https://getbootstrap.com/docs/4.5/components/">Bootstrap 4</a> を利用できます</li>
   </ul></div>
 </div>
 
-<div class="clearfix"></div>
-
 Contents
 =========
 
@@ -26,4 +24,4 @@ Slack
 <a href="https://growi-slackin.weseek.co.jp/"><img src="https://growi-slackin.weseek.co.jp/badge.svg"></a>
 
 GROWI をより良いものにするために、是非 Slack に参加してください。  
-開発に関する議論を行っている他、導入時の質問等も受け付けています。
+開発に関する議論を行っている他、導入時の質問等も受け付けています。

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

@@ -31,7 +31,6 @@ import MyDraftList from './components/MyDraftList/MyDraftList';
 import SeenUserPictureList from './components/User/SeenUserPictureList';
 import LikerPictureList from './components/User/LikerPictureList';
 import TableOfContents from './components/TableOfContents';
-import PageCreateModal from './components/PageCreateModal';
 
 import PersonalSettings from './components/Me/PersonalSettings';
 import PageContainer from './services/PageContainer';
@@ -98,7 +97,6 @@ if (pageContainer.state.pageId != null) {
     'seen-user-list': <SeenUserPictureList />,
     'liker-list': <LikerPictureList />,
     'rename-page-name-input': <PagePathAutoComplete crowi={appContainer} initializedPath={pageContainer.state.path} />,
-    'page-create-modal': <PageCreateModal />,
 
     'user-created-list': <RecentCreated />,
     'user-draft-list': <MyDraftList />,

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

@@ -12,6 +12,7 @@ import StaffCredit from './components/StaffCredit/StaffCredit';
 import AppContainer from './services/AppContainer';
 import WebsocketContainer from './services/WebsocketContainer';
 import PageCreateButton from './components/Navbar/PageCreateButton';
+import PageCreateModal from './components/PageCreateModal';
 
 const logger = loggerFactory('growi:app');
 
@@ -46,6 +47,7 @@ const componentMappings = {
 
   'create-page-button': <PageCreateButton />,
   'create-page-button-icon': <PageCreateButton isIcon />,
+  'page-create-modal': <PageCreateModal />,
 
   'grw-sidebar-wrapper': <Sidebar />,
 

+ 16 - 6
src/client/js/components/Admin/Customize/CustomizeTitle.jsx

@@ -44,19 +44,29 @@ class CustomizeTitle extends React.Component {
           <div className="col-12">
             <Card className="card well">
               <CardBody className="px-0 py-2">
-                <span
-                  // eslint-disable-next-line react/no-danger
-                  dangerouslySetInnerHTML={{ __html: t('admin:customize_setting.custom_title_detail') }}
-                />
+                {/* eslint-disable react/no-danger */}
+                <p dangerouslySetInnerHTML={{ __html: t('admin:customize_setting.custom_title_detail') }} />
+                <ul>
+                  <li>
+                    <span dangerouslySetInnerHTML={{ __html: t('admin:customize_setting.custom_title_detail_placeholder1') }} />
+                  </li>
+                  <li>
+                    <span dangerouslySetInnerHTML={{ __html: t('admin:customize_setting.custom_title_detail_placeholder2') }} />
+                  </li>
+                  <li>
+                    <span dangerouslySetInnerHTML={{ __html: t('admin:customize_setting.custom_title_detail_placeholder3') }} />
+                  </li>
+                </ul>
+                {/* eslint-enable react/no-danger */}
               </CardBody>
             </Card>
           </div>
 
           {/* TODO i18n */}
           <div className="form-text text-muted col-12">
-            Default Value: <code>&#123;&#123;page&#125;&#125; - &#123;&#123;sitename&#125;&#125;</code>
+            Default Value: <code>&#123;&#123;pagename&#125;&#125; - &#123;&#123;sitename&#125;&#125;</code>
             <br />
-            Default Output: <code className="xml">&lt;title&gt;/Somewhere/Page - {'GROWI'}&lt;&#047;title&gt;</code>
+            Default Output Example: <code className="xml">&lt;title&gt;Page name - My GROWI&lt;&#047;title&gt;</code>
           </div>
           <div className="form-group col-12">
             <input

+ 1 - 1
src/client/js/components/Admin/ExportArchiveData/ArchiveFilesTable.jsx

@@ -14,7 +14,7 @@ class ArchiveFilesTable extends React.Component {
     const { t } = this.props;
 
     return (
-      <div className="table-responsive text-nowrap">
+      <div className="table-responsive">
         <table className="table table-bordered">
           <thead>
             <tr>

+ 7 - 11
src/client/js/components/Admin/ExportArchiveData/ArchiveFilesTableMenu.jsx

@@ -12,22 +12,18 @@ class ArchiveFilesTableMenu extends React.Component {
     const { t } = this.props;
 
     return (
-      <div className="btn-group admin-user-menu">
+      <div className="btn-group admin-user-menu dropdown">
         <button type="button" className="btn btn-sm btn-outline-secondary dropdown-toggle" data-toggle="dropdown">
           <i className="icon-settings"></i> <span className="caret"></span>
         </button>
         <ul className="dropdown-menu" role="menu">
           <li className="dropdown-header">{t('admin:export_management.export_menu')}</li>
-          <li>
-            <a type="button" href={`/admin/export/${this.props.fileName}`}>
-              <i className="icon-cloud-download" /> {t('admin:export_management.download')}
-            </a>
-          </li>
-          <li>
-            <a type="button" role="button" onClick={() => this.props.onZipFileStatRemove(this.props.fileName)}>
-              <span className="text-danger"><i className="icon-trash" /> {t('admin:export_management.delete')}</span>
-            </a>
-          </li>
+          <a type="button" className="dropdown-item" href={`/admin/export/${this.props.fileName}`}>
+            <i className="icon-cloud-download" /> {t('admin:export_management.download')}
+          </a>
+          <a type="button" className="dropdown-item" role="button" onClick={() => this.props.onZipFileStatRemove(this.props.fileName)}>
+            <span className="text-danger"><i className="icon-trash" /> {t('admin:export_management.delete')}</span>
+          </a>
         </ul>
       </div>
     );

+ 1 - 1
src/client/js/components/Admin/ImportData/GrowiArchive/ImportCollectionItem.jsx

@@ -131,7 +131,7 @@ export default class ImportCollectionItem extends React.Component {
             { modes.map((mode) => {
               return (
                 <li key={`buttonMode_${mode}`}>
-                  <a type="button" role="button" onClick={() => this.modeSelectedHandler(mode)}>
+                  <a type="button" className="dropdown-item" role="button" onClick={() => this.modeSelectedHandler(mode)}>
                     {this.renderModeLabel(mode, true)}
                   </a>
                 </li>

+ 2 - 2
src/client/js/components/Admin/MarkdownSetting/XssForm.jsx

@@ -75,7 +75,7 @@ class XssForm extends React.Component {
               />
               <label className="custom-control-label w-100" htmlFor="xssOption2">
                 <p className="font-weight-bold">{t('admin:markdown_setting.xss_options.recommended_setting')}</p>
-                <div className="m-t-15">
+                <div className="mt-4">
                   <div className="d-flex justify-content-between">
                     {t('admin:markdown_setting.xss_options.tag_names')}
                   </div>
@@ -88,7 +88,7 @@ class XssForm extends React.Component {
                     defaultValue={tags}
                   />
                 </div>
-                <div className="m-t-15">
+                <div className="mt-4">
                   <div className="d-flex justify-content-between">
                     {t('admin:markdown_setting.xss_options.tag_attributes')}
                   </div>

+ 2 - 2
src/client/js/components/Admin/Notification/GlobalNotificationList.jsx

@@ -103,7 +103,7 @@ class GlobalNotificationList extends React.Component {
                   </li>
                 )}
                   {notification.triggerEvents.includes('pageMove') && (
-                  <li className="list-inline-item badge badge-pill badge-warning" data-toggle="tooltip" data-placement="top" title="Page Move">
+                  <li className="list-inline-item badge badge-pill badge-pink" data-toggle="tooltip" data-placement="top" title="Page Move">
                     <i className="icon-action-redo"></i> MOVE
                   </li>
                 )}
@@ -118,7 +118,7 @@ class GlobalNotificationList extends React.Component {
                   </li>
                 )}
                   {notification.triggerEvents.includes('comment') && (
-                  <li className="list-inline-item badge badge-pill badge-light" data-toggle="tooltip" data-placement="top" title="New Comment">
+                  <li className="list-inline-item badge badge-pill badge-secondary" data-toggle="tooltip" data-placement="top" title="New Comment">
                     <i className="icon-fw icon-bubble"></i> POST
                   </li>
                 )}

+ 3 - 3
src/client/js/components/Admin/Notification/ManageGlobalNotification.jsx

@@ -111,7 +111,7 @@ class ManageGlobalNotification extends React.Component {
 
 
         <div className="row">
-          <div className="m-t-20 form-box col-md-12">
+          <div className="form-box col-md-12">
             <h2 className="border-bottom mb-5">{t('notification_setting.notification_detail')}</h2>
           </div>
 
@@ -242,12 +242,12 @@ class ManageGlobalNotification extends React.Component {
               </div>
               <div className="my-1">
                 <TriggerEventCheckBox
-                  checkbox="warning"
+                  checkbox="pink"
                   event="pageMove"
                   checked={this.state.triggerEvents.has('pageMove')}
                   onChange={() => this.onChangeTriggerEvents('pageMove')}
                 >
-                  <span className="badge badge-pill badge-warning">
+                  <span className="badge badge-pill badge-pink">
                     <i className="icon-action-redo mr-1" />MOVE
                   </span>
                 </TriggerEventCheckBox>

+ 1 - 1
src/client/js/components/Admin/Security/SecurityManagement.jsx

@@ -58,7 +58,7 @@ class SecurityManagement extends React.Component {
           </div>
         </div>
 
-        <div className="auth-mechanism-configurations m-t-10">
+        <div className="auth-mechanism-configurations">
           <h2 className="border-bottom">{t('security_setting.Authentication mechanism settings')}</h2>
           <Nav tabs>
             <NavItem>

+ 4 - 3
src/client/js/components/Admin/UserManagement.jsx

@@ -99,7 +99,7 @@ class UserManagement extends React.Component {
           type="checkbox"
           id={`c_${status}`}
           checked={this.props.adminUsersContainer.isSelected(status)}
-          onClick={() => { this.handleClick(status) }}
+          onChange={() => { this.handleClick(status) }}
         />
         <label className="custom-control-label" htmlFor={`c_${status}`}>
           <span className={`badge badge-pill badge-${statusColor} d-inline-block vt mt-1`}>
@@ -160,10 +160,11 @@ class UserManagement extends React.Component {
         <div className="border-top border-bottom">
 
           <div className="row d-flex justify-content-start align-items-center my-2">
-            <div className="col-md-4 d-flex align-items-center my-2">
+            <div className="col-md-3 d-flex align-items-center my-2">
               <i className="icon-magnifier mr-1"></i>
               <span className="search-typeahead">
                 <input
+                  className="w-100"
                   type="text"
                   ref={(searchUserElement) => { this.searchUserElement = searchUserElement }}
                   onChange={this.handleChangeSearchText}
@@ -172,7 +173,7 @@ class UserManagement extends React.Component {
               </span>
             </div>
 
-            <div className="col-md-6 my-2">
+            <div className="offset-md-1 col-md-6 my-2">
               <div className="form-inline">
                 {this.renderCheckbox('all', 'All', 'secondary')}
                 {this.renderCheckbox('registered', 'Approval Pending', 'info')}

+ 3 - 5
src/client/js/components/Admin/Users/ExternalAccountTable.jsx

@@ -99,11 +99,9 @@ class ExternalAccountTable extends React.Component {
                       </button>
                       <ul className="dropdown-menu" role="menu">
                         <li className="dropdown-header">{t('admin:user_management.user_table.edit_menu')}</li>
-                        <li>
-                          <a role="button" onClick={() => { return this.removeExtenalAccount(ea._id) }}>
-                            <i className="icon-fw icon-fire text-danger"></i> {t('Delete')}
-                          </a>
-                        </li>
+                        <a className="dropdown-item" role="button" onClick={() => { return this.removeExtenalAccount(ea._id) }}>
+                          <i className="icon-fw icon-fire text-danger"></i> {t('Delete')}
+                        </a>
                       </ul>
                     </div>
                   </td>

+ 1 - 1
src/client/js/components/Admin/Users/RemoveAdminButton.jsx

@@ -32,7 +32,7 @@ class RemoveAdminButton extends React.Component {
     const { t } = this.props;
 
     return (
-      <a className="dropdown-item" href="" onClick={() => { this.onClickRemoveAdminBtn() }}>
+      <a className="dropdown-item" onClick={() => { this.onClickRemoveAdminBtn() }}>
         <i className="icon-fw icon-user-unfollow"></i> {t('admin:user_management.user_table.remove_admin_access')}
       </a>
     );

+ 1 - 1
src/client/js/components/Admin/Users/StatusActivateButton.jsx

@@ -31,7 +31,7 @@ class StatusActivateButton extends React.Component {
     const { t } = this.props;
 
     return (
-      <a className="dropdown-item" href="" onClick={() => { this.onClickAcceptBtn() }}>
+      <a className="dropdown-item" onClick={() => { this.onClickAcceptBtn() }}>
         <i className="icon-fw icon-user-following"></i> {t('admin:user_management.user_table.accept')}
       </a>
     );

+ 1 - 1
src/client/js/components/Admin/Users/StatusSuspendedButton.jsx

@@ -31,7 +31,7 @@ class StatusSuspendedButton extends React.Component {
     const { t } = this.props;
 
     return (
-      <a className="dropdown-item" href="" onClick={() => { this.onClickDeactiveBtn() }}>
+      <a className="dropdown-item" onClick={() => { this.onClickDeactiveBtn() }}>
         <i className="icon-fw icon-ban"></i> {t('admin:user_management.user_table.deactivate_account')}
       </a>
     );

+ 1 - 1
src/client/js/components/Admin/Users/UserRemoveButton.jsx

@@ -32,7 +32,7 @@ class UserRemoveButton extends React.Component {
     const { t } = this.props;
 
     return (
-      <a className="dropdown-item" href="" onClick={() => { this.onClickDeleteBtn() }}>
+      <a className="dropdown-item" onClick={() => { this.onClickDeleteBtn() }}>
         <i className="icon-fw icon-fire text-danger"></i> {t('Delete')}
       </a>
     );

+ 3 - 7
src/client/js/components/CreateTemplateModal.jsx

@@ -55,13 +55,9 @@ const CreateTemplateModal = (props) => {
             <code>{parentPath}</code><br />
             { t('template.modal_label.Create template under') }
           </label>
-          <div className="row">
-            <div className="col-md-6">
-              {renderTemplateCard('children', '_template')}
-            </div>
-            <div className="col-md-6">
-              {renderTemplateCard('decendants', '__template')}
-            </div>
+          <div className="card-deck">
+            {renderTemplateCard('children', '_template')}
+            {renderTemplateCard('decendants', '__template')}
           </div>
         </div>
       </ModalBody>

+ 17 - 17
src/client/js/components/LoginForm.jsx

@@ -44,13 +44,13 @@ class LoginForm extends React.Component {
 
     return (
       <form role="form" action="/login" method="post">
-        <div className="input-group mb-3">
+        <div className="input-group">
           <div className="input-group-prepend">
             <span className="input-group-text">
               <i className="icon-user"></i>
             </span>
           </div>
-          <input type="text" className="form-control" placeholder="Username or E-mail" name="loginForm[username]" />
+          <input type="text" className="form-control rounded-0" placeholder="Username or E-mail" name="loginForm[username]" />
           {isLdapStrategySetup && (
             <div className="input-group-append">
               <small className="input-group-text text-success">
@@ -60,18 +60,18 @@ class LoginForm extends React.Component {
           )}
         </div>
 
-        <div className="input-group mb-3">
+        <div className="input-group">
           <div className="input-group-prepend">
             <span className="input-group-text">
               <i className="icon-lock"></i>
             </span>
           </div>
-          <input type="password" className="form-control" placeholder="Password" name="loginForm[password]" />
+          <input type="password" className="form-control rounded-0" placeholder="Password" name="loginForm[password]" />
         </div>
 
-        <div className="input-group mt-5">
+        <div className="input-group my-4">
           <input type="hidden" name="_csrf" value={noLoginContainer.csrfToken} />
-          <button type="submit" id="login" className="btn btn-fill login mx-auto">
+          <button type="submit" id="login" className="btn btn-fill rounded-0 login mx-auto">
             <div className="eff"></div>
             <span className="btn-label">
               <i className="icon-login"></i>
@@ -96,8 +96,8 @@ class LoginForm extends React.Component {
     };
 
     return (
-      <div key={auth} className="col-6 mb-2">
-        <button type="button" className="btn btn-fill" id={auth} onClick={this.handleLoginWithExternalAuth}>
+      <div key={auth} className="col-6 my-2">
+        <button type="button" className="btn btn-fill rounded-0" id={auth} onClick={this.handleLoginWithExternalAuth}>
           <div className="eff"></div>
           <span className="btn-label">
             <i className={`fa fa-${authIconNames[auth]}`}></i>
@@ -131,7 +131,7 @@ class LoginForm extends React.Component {
         <div className="text-center">
           <button
             type="button"
-            className="btn btn-secondary btn-sm mb-3"
+            className="btn btn-secondary btn-sm rounded-0 mb-3"
             data-toggle={isExternalAuthCollapsible ? 'collapse' : ''}
             data-target="#external-auth"
             aria-expanded="false"
@@ -171,7 +171,7 @@ class LoginForm extends React.Component {
                 <i className="icon-user"></i>
               </span>
             </div>
-            <input type="text" className="form-control" placeholder={t('User ID')} name="registerForm[username]" defaultValue={username} required />
+            <input type="text" className="form-control rounded-0" placeholder={t('User ID')} name="registerForm[username]" defaultValue={username} required />
           </div>
           <p className="form-text text-danger">
             <span id="help-block-username"></span>
@@ -183,7 +183,7 @@ class LoginForm extends React.Component {
                 <i className="icon-tag"></i>
               </span>
             </div>
-            <input type="text" className="form-control" placeholder={t('Name')} name="registerForm[name]" defaultValue={name} required />
+            <input type="text" className="form-control rounded-0" placeholder={t('Name')} name="registerForm[name]" defaultValue={name} required />
           </div>
 
           <div className="input-group">
@@ -192,7 +192,7 @@ class LoginForm extends React.Component {
                 <i className="icon-envelope"></i>
               </span>
             </div>
-            <input type="email" className="form-control" placeholder={t('Email')} name="registerForm[email]" defaultValue={email} required />
+            <input type="email" className="form-control rounded-0" placeholder={t('Email')} name="registerForm[email]" defaultValue={email} required />
           </div>
 
           {registrationWhiteList.length > 0 && (
@@ -216,12 +216,12 @@ class LoginForm extends React.Component {
                 <i className="icon-lock"></i>
               </span>
             </div>
-            <input type="password" className="form-control" placeholder={t('Password')} name="registerForm[password]" required />
+            <input type="password" className="form-control rounded-0" placeholder={t('Password')} name="registerForm[password]" required />
           </div>
 
-          <div className="input-group justify-content-center mt-5">
+          <div className="input-group justify-content-center my-4">
             <input type="hidden" name="_csrf" value={noLoginContainer.csrfToken} />
-            <button type="submit" className="btn btn-fill" id="register">
+            <button type="submit" className="btn btn-fill rounded-0" id="register">
               <div className="eff"></div>
               <span className="btn-label">
                 <i className="icon-user-follow"></i>
@@ -231,10 +231,10 @@ class LoginForm extends React.Component {
           </div>
         </form>
 
-        <div className="border-bottom mb-3"></div>
+        <div className="border-bottom"></div>
 
         <div className="row">
-          <div className="text-right col-12 py-1">
+          <div className="text-right col-12 mt-2 py-2">
             <a href="#login" id="login" className="link-switch" onClick={this.switchForm}>
               <i className="icon-fw icon-login"></i>
               {t('Sign in is here')}

+ 1 - 1
src/client/js/components/Me/PasswordSettings.jsx

@@ -67,7 +67,7 @@ class PasswordSettings extends React.Component {
 
     return (
       <React.Fragment>
-        {(!personalContainer.state.isPasswordSet) && <div className="alert alert-warning m-t-10">{ t('Password is not set') }</div>}
+        {(!personalContainer.state.isPasswordSet) && <div className="alert alert-warning">{ t('Password is not set') }</div>}
         <div className="container-fluid my-4">
           {(personalContainer.state.isPasswordSet)
             ? <h2 className="border-bottom">{t('personal_settings.update_password')}</h2>

+ 30 - 32
src/client/js/components/Me/PersonalSettings.jsx

@@ -15,38 +15,36 @@ class PersonalSettings extends React.Component {
 
     return (
       <Fragment>
-        <div className="m-t-10">
-          <div className="personal-settings">
-            <ul className="nav nav-tabs" role="tablist">
-              <li className="nav-item">
-                <a className="nav-link active" href="#user-settings" data-toggle="tab" role="tab"><i className="icon-user"></i> { t('User Information') }</a>
-              </li>
-              <li className="nav-item">
-                <a className="nav-link" href="#external-accounts" data-toggle="tab" role="tab">
-                  <i className="icon-share-alt mr-1"></i>
-                  { t('admin:user_management.external_accounts') }
-                </a>
-              </li>
-              <li className="nav-item">
-                <a className="nav-link" href="#password-settings" data-toggle="tab" role="tab"><i className="icon-lock"></i> { t('Password Settings') }</a>
-              </li>
-              <li className="nav-item">
-                <a className="nav-link" href="#apiToken" data-toggle="tab" role="tab"><i className="icon-paper-plane"></i> { t('API Settings') }</a>
-              </li>
-            </ul>
-            <div className="tab-content p-t-10">
-              <div id="user-settings" className="tab-pane active" role="tabpanel">
-                <UserSettings />
-              </div>
-              <div id="external-accounts" className="tab-pane" role="tabpanel">
-                <ExternalAccountLinkedMe />
-              </div>
-              <div id="password-settings" className="tab-pane" role="tabpanel">
-                <PasswordSettings />
-              </div>
-              <div id="apiToken" className="tab-pane" role="tabpanel">
-                <ApiSettings />
-              </div>
+        <div className="personal-settings">
+          <ul className="nav nav-tabs" role="tablist">
+            <li className="nav-item">
+              <a className="nav-link active" href="#user-settings" data-toggle="tab" role="tab"><i className="icon-user"></i> { t('User Information') }</a>
+            </li>
+            <li className="nav-item">
+              <a className="nav-link" href="#external-accounts" data-toggle="tab" role="tab">
+                <i className="icon-share-alt mr-1"></i>
+                { t('admin:user_management.external_accounts') }
+              </a>
+            </li>
+            <li className="nav-item">
+              <a className="nav-link" href="#password-settings" data-toggle="tab" role="tab"><i className="icon-lock"></i> { t('Password Settings') }</a>
+            </li>
+            <li className="nav-item">
+              <a className="nav-link" href="#apiToken" data-toggle="tab" role="tab"><i className="icon-paper-plane"></i> { t('API Settings') }</a>
+            </li>
+          </ul>
+          <div className="tab-content p-t-10">
+            <div id="user-settings" className="tab-pane active" role="tabpanel">
+              <UserSettings />
+            </div>
+            <div id="external-accounts" className="tab-pane" role="tabpanel">
+              <ExternalAccountLinkedMe />
+            </div>
+            <div id="password-settings" className="tab-pane" role="tabpanel">
+              <PasswordSettings />
+            </div>
+            <div id="apiToken" className="tab-pane" role="tabpanel">
+              <ApiSettings />
             </div>
           </div>
         </div>

+ 0 - 5
src/client/js/components/Navbar/PersonalDropdown.jsx

@@ -70,11 +70,6 @@ const PersonalDropdown = (props) => {
 
         <div className="dropdown-divider"></div>
 
-        <a className="dropdown-item" href={`/user/${user.username}#user-draft-list`}><i className="icon-fw icon-docs"></i>{ t('List Drafts') }</a>
-        <a className="dropdown-item" href="/trash"><i className="icon-fw icon-trash"></i>{ t('Deleted Pages') }</a>
-
-        <div className="dropdown-divider"></div>
-
         <h6 className="dropdown-header">Color Scheme</h6>
         <form className="px-4">
           <div className="form-row align-items-center">

+ 6 - 8
src/client/js/components/PageCreateModal.jsx

@@ -13,17 +13,16 @@ import { pathUtils } from 'growi-commons';
 import { createSubscribedElement } from './UnstatedUtils';
 
 import AppContainer from '../services/AppContainer';
-import PageContainer from '../services/PageContainer';
 import PagePathAutoComplete from './PagePathAutoComplete';
 
 const PageCreateModal = (props) => {
-  const { t, appContainer, pageContainer } = props;
+  const { t, appContainer } = props;
 
   const config = appContainer.getConfig();
   const isReachable = config.isSearchServiceReachable;
-  const { path } = pageContainer.state;
+  const { pathname } = window.location;
   const userPageRootPath = userPageRoot(appContainer.currentUser);
-  const parentPath = pathUtils.addTrailingSlash(path);
+  const parentPath = pathUtils.addTrailingSlash(pathname);
   const now = format(new Date(), 'yyyy/MM/dd');
 
   const [todayInput1, setTodayInput1] = useState(t('Memo'));
@@ -152,7 +151,7 @@ const PageCreateModal = (props) => {
                 ? (
                   <PagePathAutoComplete
                     crowi={appContainer}
-                    initializedPath={path}
+                    initializedPath={decodeURI(pathname)}
                     addTrailingSlash
                     onSubmit={ppacSubmitHandler}
                     onInputChange={ppacInputChangeHandler}
@@ -189,7 +188,7 @@ const PageCreateModal = (props) => {
         <fieldset className="col-12">
 
           <h3 className="grw-modal-head pb-2">{ t('template.modal_label.Create template under')}<br />
-            <code>{path}</code>
+            <code>{decodeURI(pathname)}</code>
           </h3>
 
           <div className="d-sm-flex align-items-center justify-items-between">
@@ -248,14 +247,13 @@ const PageCreateModal = (props) => {
  * Wrapper component for using unstated
  */
 const ModalControlWrapper = (props) => {
-  return createSubscribedElement(PageCreateModal, props, [AppContainer, PageContainer]);
+  return createSubscribedElement(PageCreateModal, props, [AppContainer]);
 };
 
 
 PageCreateModal.propTypes = {
   t: PropTypes.func.isRequired, //  i18next
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-  pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
 };
 
 export default withTranslation()(ModalControlWrapper);

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

@@ -125,7 +125,7 @@ const PageDeleteModal = (props) => {
       </ModalBody>
       <ModalFooter>
         <ApiErrorMessage errorCode={errorCode} errorMessage={errorMessage} linkPath={path} />
-        <button type="button" className={`m-l-10 btn btn-${deleteIconAndKey[deleteMode].color}`} onClick={deleteButtonHandler}>
+        <button type="button" className={`btn btn-${deleteIconAndKey[deleteMode].color}`} onClick={deleteButtonHandler}>
           <i className={`icon-${deleteIconAndKey[deleteMode].icon}`} aria-hidden="true"></i>
           { t(`modal_delete.delete_${deleteIconAndKey[deleteMode].translationKey}`) }
         </button>

+ 13 - 16
src/client/js/components/PageEditor/CodeMirrorEditor.jsx

@@ -658,12 +658,10 @@ export default class CodeMirrorEditor extends AbstractEditor {
   }
 
   getNavbarItems() {
-    const buttonColor = '';
     return [
-      /* eslint-disable max-len */
       <Button
         key="nav-item-bold"
-        color={buttonColor}
+        color={null}
         size="sm"
         title="Bold"
         onClick={this.createReplaceSelectionHandler('**', '**')}
@@ -672,7 +670,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
       </Button>,
       <Button
         key="nav-item-italic"
-        color={buttonColor}
+        color={null}
         size="sm"
         title="Italic"
         onClick={this.createReplaceSelectionHandler('*', '*')}
@@ -681,7 +679,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
       </Button>,
       <Button
         key="nav-item-strikethrough"
-        color={buttonColor}
+        color={null}
         size="sm"
         title="Strikethrough"
         onClick={this.createReplaceSelectionHandler('~~', '~~')}
@@ -690,7 +688,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
       </Button>,
       <Button
         key="nav-item-header"
-        color={buttonColor}
+        color={null}
         size="sm"
         title="Heading"
         onClick={this.makeHeaderHandler}
@@ -699,7 +697,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
       </Button>,
       <Button
         key="nav-item-code"
-        color={buttonColor}
+        color={null}
         size="sm"
         title="Inline Code"
         onClick={this.createReplaceSelectionHandler('`', '`')}
@@ -708,7 +706,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
       </Button>,
       <Button
         key="nav-item-quote"
-        color={buttonColor}
+        color={null}
         size="sm"
         title="Quote"
         onClick={this.createAddPrefixToEachLinesHandler('> ')}
@@ -717,7 +715,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
       </Button>,
       <Button
         key="nav-item-ul"
-        color={buttonColor}
+        color={null}
         size="sm"
         title="List"
         onClick={this.createAddPrefixToEachLinesHandler('- ')}
@@ -726,7 +724,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
       </Button>,
       <Button
         key="nav-item-ol"
-        color={buttonColor}
+        color={null}
         size="sm"
         title="Numbered List"
         onClick={this.createAddPrefixToEachLinesHandler('1. ')}
@@ -735,7 +733,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
       </Button>,
       <Button
         key="nav-item-checkbox"
-        color={buttonColor}
+        color={null}
         size="sm"
         title="Check List"
         onClick={this.createAddPrefixToEachLinesHandler('- [ ] ')}
@@ -744,7 +742,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
       </Button>,
       <Button
         key="nav-item-link"
-        color={buttonColor}
+        color={null}
         size="sm"
         title="Link"
         onClick={this.createReplaceSelectionHandler('[', ']()')}
@@ -753,7 +751,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
       </Button>,
       <Button
         key="nav-item-image"
-        color={buttonColor}
+        color={null}
         size="sm"
         title="Image"
         onClick={this.createReplaceSelectionHandler('![', ']()')}
@@ -762,7 +760,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
       </Button>,
       <Button
         key="nav-item-table"
-        color={buttonColor}
+        color={null}
         size="sm"
         title="Table"
         onClick={this.showHandsonTableHandler}
@@ -771,14 +769,13 @@ export default class CodeMirrorEditor extends AbstractEditor {
       </Button>,
       <Button
         key="nav-item-drawio"
-        color={buttonColor}
+        color={null}
         bssize="small"
         title="draw.io"
         onClick={this.showDrawioHandler}
       >
         <EditorIcon icon="Drawio" />
       </Button>,
-      /* eslint-able max-len */
     ];
   }
 

+ 1 - 1
src/client/js/components/PageEditor/OptionsSelector.jsx

@@ -162,7 +162,7 @@ class OptionsSelector extends React.Component {
           toggle={this.onToggleConfigurationDropdown}
         >
 
-          <DropdownToggle color="light" caret>
+          <DropdownToggle color="outline-secondary" caret>
             <i className="icon-settings"></i>
           </DropdownToggle>
 

+ 9 - 7
src/client/js/components/PageHistory/Revision.jsx

@@ -16,7 +16,8 @@ export default class Revision extends React.Component {
   componentDidMount() {
   }
 
-  _onDiffOpenClicked() {
+  _onDiffOpenClicked(e) {
+    e.preventDefault();
     this.props.onDiffOpenClicked(this.props.revision);
   }
 
@@ -35,7 +36,7 @@ export default class Revision extends React.Component {
         <div className="picture-container">
           {pic}
         </div>
-        <div className="m-l-10">
+        <div className="ml-3">
           <div className="revision-history-meta">
             <span className="text-muted small">
               <UserDate dateTime={revision.createdAt} /> ({ t('No diff') })
@@ -56,13 +57,13 @@ export default class Revision extends React.Component {
       pic = <UserPicture user={author} size="lg" />;
     }
 
-    const iconClass = this.props.revisionDiffOpened ? 'caret caret-opened' : 'caret';
+    const iconClass = this.props.revisionDiffOpened ? 'fa fa-caret-down caret caret-opened' : 'fa fa-caret-down caret';
     return (
       <div className="revision-history-main d-flex mt-3">
         <div className="mt-2">
           {pic}
         </div>
-        <div className="m-l-10">
+        <div className="ml-2">
           <div className="revision-history-author">
             <strong><Username user={author}></Username></strong>
           </div>
@@ -77,13 +78,14 @@ export default class Revision extends React.Component {
                 }
                 { this.props.hasDiff
                   && (
-                  <a className="diff-view" onClick={this._onDiffOpenClicked}>
-                    <i className={iconClass}></i> { t('View diff') }
+                  // use dummy href attr (with preventDefault()), because don't apply style by a:not([href])
+                  <a className="diff-view" href="" onClick={this._onDiffOpenClicked}>
+                    <i className={iconClass}></i> {t('View diff')}
                   </a>
                   )
                 }
               </span>
-              <a href={`?revision=${revision._id}`} className="m-l-10">
+              <a href={`?revision=${revision._id}`} className="ml-2">
                 <i className="icon-login"></i> { t('Go to this version') }
               </a>
             </p>

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

@@ -77,7 +77,7 @@ class RecentCreated extends React.Component {
 
     return (
       <div className="page-list-container-create">
-        <ul className="page-list-ul page-list-ul-flat">
+        <ul className="page-list-ul page-list-ul-flat mb-3">
           {pageList}
         </ul>
         <PaginationWrapper

+ 15 - 9
src/client/js/components/SavePageControls/GrantSelector.jsx

@@ -30,17 +30,17 @@ class GrantSelector extends React.Component {
 
     this.availableGrants = [
       {
-        grant: 1, iconClass: 'icon-people', styleClass: '', label: 'Public',
+        grant: 1, iconClass: 'icon-people', btnStyleClass: 'outline-info', label: 'Public',
       },
       {
-        grant: 2, iconClass: 'icon-link', styleClass: 'text-info', label: 'Anyone with the link',
+        grant: 2, iconClass: 'icon-link', btnStyleClass: 'outline-teal', label: 'Anyone with the link',
       },
       // { grant: 3, iconClass: '', label: 'Specified users only' },
       {
-        grant: 4, iconClass: 'icon-lock', styleClass: 'text-danger', label: 'Only me',
+        grant: 4, iconClass: 'icon-lock', btnStyleClass: 'outline-danger', label: 'Only me',
       },
       {
-        grant: 5, iconClass: 'icon-options', styleClass: '', label: 'Only inside the group', reselectLabel: 'Reselect the group',
+        grant: 5, iconClass: 'icon-options', btnStyleClass: 'outline-purple', label: 'Only inside the group', reselectLabel: 'Reselect the group',
       },
     ];
 
@@ -136,6 +136,7 @@ class GrantSelector extends React.Component {
     const { t } = this.props;
     const { grant: currentGrant, grantGroup } = this.state;
 
+    let dropdownToggleBtnColor = null;
     let dropdownToggleLabelElm = null;
 
     const dropdownMenuElems = this.availableGrants.map((opt) => {
@@ -143,10 +144,15 @@ class GrantSelector extends React.Component {
         ? opt.reselectLabel // when grantGroup is selected
         : opt.label;
 
-      const labelElm = <span><i className={`icon icon-fw ${opt.iconClass} ${opt.styleClass}`}></i> <span className={opt.styleClass}>{t(label)}</span></span>;
+      const labelElm = (
+        <span>
+          <i className={`icon icon-fw ${opt.iconClass}`}></i> {t(label)}
+        </span>
+      );
 
-      // set dropdownToggleLabelElm
+      // set dropdownToggleBtnColor, dropdownToggleLabelElm
       if (opt.grant === 1 || opt.grant === currentGrant) {
+        dropdownToggleBtnColor = opt.btnStyleClass;
         dropdownToggleLabelElm = labelElm;
       }
 
@@ -155,7 +161,7 @@ class GrantSelector extends React.Component {
 
     // add specified group option
     if (grantGroup != null) {
-      const labelElm = <span><i className="icon icon-fw icon-organization text-success"></i> <span className="text-success">{this.getGroupName()}</span></span>;
+      const labelElm = <span><i className="icon icon-fw icon-organization"></i> {this.getGroupName()}</span>;
 
       // set dropdownToggleLabelElm
       dropdownToggleLabelElm = labelElm;
@@ -166,7 +172,7 @@ class GrantSelector extends React.Component {
     return (
       <div className="form-group grw-grant-selector mb-0">
         <UncontrolledDropdown direction="up" size="sm">
-          <DropdownToggle color="light" caret className="d-flex justify-content-between align-items-center" disabled={this.props.disabled}>
+          <DropdownToggle color={dropdownToggleBtnColor} caret className="d-flex justify-content-between align-items-center" disabled={this.props.disabled}>
             {dropdownToggleLabelElm}
           </DropdownToggle>
           <DropdownMenu>
@@ -217,7 +223,7 @@ class GrantSelector extends React.Component {
         isOpen={this.state.isSelectGroupModalShown}
         toggle={this.hideSelectGroupModal}
       >
-        <ModalHeader tag="h4" toggle={this.hideSelectGroupModal} className="bg-info text-light">
+        <ModalHeader tag="h4" toggle={this.hideSelectGroupModal} className="bg-purple text-light">
           Select a Group
         </ModalHeader>
         <ModalBody>

+ 13 - 8
src/client/js/components/Sidebar/SidebarNav.jsx

@@ -66,6 +66,7 @@ class SidebarNav extends React.Component {
 
   render() {
     const { isAdmin, currentUsername } = this.props.appContainer;
+    const isLoggedIn = currentUsername != null;
 
     const primaryItems = [
       this.generatePrimaryItemObj('custom', 'Custom Sidebar', 'code'),
@@ -74,16 +75,20 @@ class SidebarNav extends React.Component {
       // this.generatePrimaryItemObj('favorite', 'Favorite', 'icon-star'),
     ];
 
-    const secondaryItems = [
-      this.generateSecondaryItemObj('draft', 'Draft', 'file_copy', `/user/${currentUsername}#user-draft-list`),
+    let secondaryItems = [
+      isAdmin && (
+        this.generateSecondaryItemObj('admin', 'Admin', 'settings', '/admin')
+      ),
+      isLoggedIn && (
+        this.generateSecondaryItemObj('draft', 'Draft', 'file_copy', `/user/${currentUsername}#user-draft-list`)
+      ),
       this.generateSecondaryItemObj('help', 'Help', 'help', 'https://docs.growi.org', true),
-      this.generateSecondaryItemObj('trash', 'Trash', 'delete', '/trash'),
+      isLoggedIn && (
+        this.generateSecondaryItemObj('trash', 'Trash', 'delete', '/trash')
+      ),
     ];
-    if (isAdmin) {
-      secondaryItems.unshift( // add to the beginning
-        this.generateSecondaryItemObj('admin', 'Admin', 'settings', '/admin'),
-      );
-    }
+    // remove 'false' items
+    secondaryItems = secondaryItems.filter(item => item !== false);
 
     return (
       <GlobalNav

+ 1 - 1
src/client/js/components/User/UserPictureList.jsx

@@ -6,7 +6,7 @@ import UserPicture from './UserPicture';
 export default class UserPictureList extends React.Component {
 
   render() {
-    return this.state.users.map(user => (
+    return this.props.users.map(user => (
       <span key={user._id}>
         <UserPicture user={user} size="xs" />
       </span>

+ 17 - 5
src/client/js/services/PageContainer.js

@@ -130,7 +130,6 @@ export default class PageContainer extends Container {
 
     const seenUserListElem = document.getElementById('seen-user-list');
     if (seenUserListElem != null) {
-
       const userIdsStr = seenUserListElem.dataset.userIds;
       if (userIdsStr === '') {
         return;
@@ -146,13 +145,11 @@ export default class PageContainer extends Container {
 
       const noImageCacheUserIds = noImageCacheUsers.map((user) => { return user.id });
       try {
-        const res = await this.appContainer.apiv3Put('/users/update.imageUrlCache', { userIds: noImageCacheUserIds });
-        const usersUpdated = users.filter((user) => { return user.imageUrlCached }).concat(res.data.updatedUsers);
-        this.setState({ seenUsers: usersUpdated });
+        await this.appContainer.apiv3Put('/users/update.imageUrlCache', { userIds: noImageCacheUserIds });
       }
       catch (err) {
+        // Error alert doesn't apear, because user don't need to notice this error.
         logger.error(err);
-        throw new Error(err);
       }
     }
 
@@ -163,8 +160,23 @@ export default class PageContainer extends Container {
       if (userIdsStr === '') {
         return;
       }
+
       const { users } = await this.appContainer.apiGet('/users.list', { user_ids: userIdsStr });
       this.setState({ likerUsers: users });
+
+      const noImageCacheUsers = users.filter((user) => { return !user.imageUrlCached });
+      if (noImageCacheUsers.length === 0) {
+        return;
+      }
+
+      const noImageCacheUserIds = noImageCacheUsers.map((user) => { return user.id });
+      try {
+        await this.appContainer.apiv3Put('/users/update.imageUrlCache', { userIds: noImageCacheUserIds });
+      }
+      catch (err) {
+        // Error alert doesn't apear, because user don't need to notice this error.
+        logger.error(err);
+      }
     }
   }
 

+ 0 - 78
src/client/styles/agile-admin/inverse/variables.scss

@@ -1,78 +0,0 @@
-// Variables
-
-// @import 'https://fonts.googleapis.com/css?family=Rubik:300,400,500,700,900';
-
-// $basefont1:'Rubik', sans-serif;
-// $basefont2:'Rubik', sans-serif;
-// $basefont1: Lato, -apple-system, BlinkMacSystemFont, 'Hiragino Kaku Gothic ProN', Meiryo, sans-serif !default;
-// $basefont2: Lato, -apple-system, BlinkMacSystemFont, 'Hiragino Kaku Gothic ProN', Meiryo, sans-serif !default;
-
-/* GROWI Color */
-// $growi-green: #74bc46;
-// $growi-blue: #175fa5;
-
-/*bootstrap Color*/
-// $danger: #ff0a54 !default;
-// $success: #00bb83 !default;
-// $warning: #ffa32b !default;
-// $primary: $growi-blue !default;
-// $info: #009fbb !default;
-// $muted: #98a6ad !default;
-// $dark: #3e4d6c !default;
-// $inverse: #3e4d6c !default;
-// $light: #e4e7ea !default;
-// $extralight: #f7fafc !default;
-
-/*Normal Color*/
-// $white: #ffffff !default;
-// $red: #ff0000 !default;
-// $purple: #7b00ce !default;
-// $blue: #0d00c5 !default;
-// $yellow: #cccf0e !default;
-// $border: #f0f0f0 !default;
-// $megna: #00b5c2 !default;
-
-/*Theme Colors*/
-// $topbar: #3c4451 !default;
-// $sidebar: #4f5467 !default;
-// $bodycolor: #fff !default;
-// $headingtext: #2b2b2b !default;
-// $bodytext: #686868 !default;
-// $linktext: $inverse !default;
-// $linktext-hover: lighten($inverse, 20%) !default;
-// $sidebar-text: #54667a !default;
-// $themecolor: #ff6849 !default;
-// $dark-themecolor: #4f5467 !default;
-
-// $rgt: right !default;
-// $lft: left !default;
-
-// $dark-text: #848a96 !default;
-// $navbar-border: #ccc !default;
-// $active-navbar-border: lighten($navbar-border, 10%) !default;
-// $btn-default-bgcolor: darken(#fff, 10%) !default;
-// $color-inline-code: #c7254e !default;
-// $bgcolor-inline-code: #f9f2f4 !default;
-
-/*Border radius*/
-// $radius: 0 !default;
-
-/*Preloader*/
-/*
-.preloader{
-    width: 100%;
-    height: 100%;
-    top:0px;
-    position: fixed;
-    z-index: 99999;
-    background: #fff;
-    .cssload-speeding-wheel{
-        position: absolute;
-        top: "calc(50% - 3.5px)";
-        left: "calc(50% - 3.5px)";
-    }
-}
-*/
-
-/*Font weight*/
-// $font-bold: 700 !default;

+ 0 - 1
src/client/styles/scss/_editor-attachment.scss

@@ -108,7 +108,6 @@
     border: none;
     border-top: 1px dotted #ccc;
     border-bottom: none;
-    border-radius: 0;
 
     &:active {
       box-shadow: none;

+ 2 - 1
src/client/styles/scss/_hljs.scss

@@ -2,7 +2,8 @@ pre.hljs {
   position: relative;
 
   // override Highlight Js Style Border
-  border-radius: 3px;
+  border: 1px solid $gray-500;
+  border-radius: $border-radius;
   &.hljs-no-border {
     border: none;
   }

+ 1 - 24
src/client/styles/scss/_layout.scss

@@ -1,5 +1,3 @@
-@import 'layout_variable';
-
 // FIXME: replace with mt-2 or mt-3
 .grw-mt-10px {
   margin-top: 10px !important;
@@ -29,33 +27,13 @@
 
 .grw-modal-head {
   font-size: 1em;
-  border-bottom: 1px solid $grw-line-gray;
+  border-bottom: 1px solid $gray-500;
 }
 
 .main {
   margin-top: 1rem;
 }
 
-.layout-control {
-  position: fixed;
-  right: 25%;
-  bottom: 25px;
-  z-index: 1;
-  display: block;
-  padding: 5px 8px;
-  font-size: 0.8em;
-  text-align: center;
-  border: solid 1px #ccc;
-  border-right: none;
-  border-radius: 5px 0 0 5px;
-  transition: 0.3s ease;
-
-  &:hover {
-    text-decoration: none;
-    cursor: pointer;
-  }
-}
-
 .revision-toc {
   // to get on the Attachment row
   z-index: 1;
@@ -114,7 +92,6 @@
       margin-bottom: 20px;
       font-size: 0.9em;
       border: solid 1px #aaa;
-      border-radius: 5px;
 
       .revision-toc-head {
         display: inline-block;

+ 1 - 2
src/client/styles/scss/_layout_growi.scss

@@ -1,4 +1,3 @@
-@import 'layout_variable';
 @import 'layout';
 
 .growi {
@@ -10,7 +9,7 @@
     // adjusting position with negative margin
     height: $grw-nav-main-tab-height;
     line-height: 1.25;
-    border-bottom: 1px solid $grw-line-gray;
+    border-bottom: 1px solid transparent;
 
     .liker-user-count,
     .seen-user-count {

+ 0 - 8
src/client/styles/scss/_layout_variable.scss

@@ -1,8 +0,0 @@
-/* color variables */
-
-/* blue */
-$grw-alice-blue: aliceblue;
-
-/* gray */
-$grw-line-gray: #dee2e6;
-$grw-line-light-gray: #ddd;

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

@@ -1,5 +1,3 @@
-@import 'layout_variable';
-
 @mixin variable-font-size($basesize) {
   font-size: $basesize * 0.6;
 

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

@@ -1,5 +1,4 @@
 @import 'editor-overlay';
-@import 'layout_variable';
 
 body:not(.on-edit) {
   // hide .page-editor-footer

+ 13 - 27
src/client/styles/scss/_override-bootstrap-variables.scss

@@ -11,7 +11,7 @@ $success: #00bb83 !default;
 $warning: #ffa32b !default;
 $danger: #ff0a54 !default;
 $light: #e4e7ea !default;
-$dark: #3e4d6c !default;
+$dark: #343a40 !default;
 
 //== Typography
 //
@@ -26,33 +26,21 @@ $line-height-base: 1.42857;
 
 //== Components
 //
-//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
-$border-radius-base: 0;
-$border-radius-large: 0;
-$border-radius-small: 0;
-
-
-//== Buttons
-//
-//## For each of Bootstrap's buttons, define text, background and border color.
-
-$btn-border-radius: 0;
-$btn-border-radius-lg: 0;
-$btn-border-radius-sm: 0;
-
+$border-radius:               .15rem;
+$border-radius-sm:            .1rem;
+$border-radius-lg:            .25rem;
+$border-radius-xl:            .35rem;
 
 
 //== Forms
 //
-$input-border-radius: 0;
-$input-border-radius-lg: 0;
-$input-border-radius-sm: 0;
+$input-border-radius: $border-radius-sm;
+$input-border-radius-sm: $border-radius-sm;
+$input-border-radius-lg: $border-radius;
 
 //== Navs
-
 $nav-link-padding-y: 0.75rem;
 $nav-link-padding-x: 1rem;
-$nav-tabs-border-radius: 0;
 
 //== Navbar
 $navbar-padding-y: 0;
@@ -60,28 +48,26 @@ $navbar-brand-padding-y: 0;
 $navbar-nav-link-padding-x: 1rem;
 
 //== Dropdowns
-$dropdown-border-radius: 0;
+$dropdown-border-radius: $border-radius-sm;
 
 //== card
-$card-border-radius: 0;
 $card-spacer-y: 7px;
 $card-spacer-x: 15px;
 
 //== Modals
 $modal-content-border-width: 0;
-$modal-content-border-radius: 0;
 $modal-header-padding-y: 0.75rem;
 $modal-header-padding-x: 1rem;
 
-//== Alerts
-$alert-border-radius: 0;
-
 //== Progress bar
 $progress-height: 4px;
-$progress-border-radius: 0;
+$progress-border-radius: $border-radius-sm;
 $progress-bg: #f0f0f0;
 $progress-box-shadow: none;
 
+//== Code
+$pre-color: dummyinvalildcolor; // disable pre color specification with invalid value
+
 //== Custom Checkbox
 $custom-checkbox-indicator-border-radius: 0px;
 $custom-control-indicator-focus-box-shadow: none;

+ 0 - 9
src/client/styles/scss/_override-bootstrap.scss

@@ -39,11 +39,6 @@
     line-height: 14px;
   }
 
-  code {
-    padding: 2px 4px;
-    font-size: 90%;
-  }
-
   // Navs
   .nav-tabs {
     .nav-item {
@@ -65,24 +60,20 @@
   // card (substitute panel of bootstrap3)
   .card {
     margin-bottom: 20px;
-    border-radius: $card-border-radius;
   }
 
   .card-header {
     font-weight: 700;
     text-transform: none;
-    border-radius: $card-border-radius;
   }
 
   .card-header:first-child {
-    border-radius: $card-border-radius;
   }
 
   // Well (substitute Well of bootstrap3)
   .card.well {
     min-height: 20px;
     padding: $card-spacer-y $card-spacer-x;
-    border-radius: 3px;
   }
 
   // Dropdowns

+ 1 - 9
src/client/styles/scss/_search.scss

@@ -1,5 +1,3 @@
-@import 'layout_variable';
-
 .search-listpage-icon {
   font-size: 16px;
   color: #999;
@@ -22,7 +20,7 @@
 
   .search-clear {
     position: absolute;
-    top: 4px;
+    top: 5px;
     right: 4px;
     z-index: 3;
     width: 24px;
@@ -187,7 +185,6 @@
         padding: 16px;
         font-size: 13px;
         border: solid 1px #ccc;
-        border-radius: 3px;
       }
     }
   }
@@ -212,9 +209,4 @@
   caption {
     display: table-header-group;
   }
-
-  code {
-    padding: 0.25em;
-    background: $grw-alice-blue;
-  }
 }

+ 13 - 0
src/client/styles/scss/_vendor-presentation.scss

@@ -0,0 +1,13 @@
+// import bootstrap configurations
+@import '~bootstrap/scss/functions';
+@import '~bootstrap/scss/variables';
+@import '~bootstrap/scss/mixins';
+@import '~bootstrap/scss/utilities';
+
+@import '~reveal.js/css/reveal.css';
+@import '~reveal.js/css/theme/black.css';
+
+// hljs
+.reveal {
+  @import 'hljs';
+}

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

@@ -1,5 +1,3 @@
-@import 'layout_variable';
-
 div.body {
   padding: 10px;
 }
@@ -36,7 +34,7 @@ div.body {
     margin-top: 2em;
     font-size: 1.8em;
     line-height: 1.1em;
-    border-bottom: solid 1px $grw-line-light-gray;
+    border-bottom: solid 1px transparent;
   }
   h2 {
     padding-bottom: 0.5em;
@@ -127,15 +125,6 @@ div.body {
     }
   }
 
-  pre {
-    white-space: pre-line;
-  }
-
-  // only inline code blocks
-  p code {
-    font-family: $font-family-monospace-not-strictly;
-  }
-
   .page-template-builder {
     position: relative;
 

+ 11 - 0
src/client/styles/scss/atoms/_code.scss

@@ -0,0 +1,11 @@
+/*
+ * style of inline-code
+ */
+:not(pre) {
+  > code {
+    padding: 2px 4px;
+    font-family: $font-family-monospace-not-strictly;
+    border: 1px solid;
+    border-radius: $border-radius;
+  }
+}

+ 4 - 0
src/client/styles/scss/atoms/_pre.scss

@@ -0,0 +1,4 @@
+pre {
+  padding: 0.5em;
+  border-radius: $border-radius;
+}

+ 2 - 2
src/client/styles/scss/style-app.scss

@@ -1,5 +1,4 @@
 // import variables
-@import '../agile-admin/inverse/variables';
 @import 'variables';
 
 @import 'mixins';
@@ -16,7 +15,9 @@
 
 // atoms
 @import 'atoms/buttons';
+@import 'atoms/code';
 @import 'atoms/nav';
+@import 'atoms/pre';
 @import 'atoms/spinners';
 @import 'atoms/custom_control';
 
@@ -39,7 +40,6 @@
 @import 'layout';
 @import 'layout_growi';
 @import 'layout_kibela';
-@import 'layout_variable';
 @import 'login';
 @import 'me';
 @import 'navbar';

+ 4 - 7
src/client/styles/scss/style-presentation.scss

@@ -1,13 +1,10 @@
-// import Growi variable
+// import variable
 @import 'variables';
 
-@import '~reveal.js/css/reveal.css';
-@import '~reveal.js/css/theme/black.css';
+@import 'mixins';
+@import 'override-bootstrap-variables';
 
-// hljs
-.reveal {
-  @import 'hljs';
-}
+@import 'vendor-presentation';
 
 .reveal {
   font-size: 32px;

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

@@ -1,5 +1,19 @@
 // determine optional variables
 $bgcolor-subnabvar: lighten($bgcolor-global, 3%) !default;
+$color-table: white !default;
+$bgcolor-table: #343a40 !default;
+$border-color-table: lighten($bgcolor-table, 7.5%) !default;
+$color-table-hover: rgba(white, 0.075) !default;
+$bgcolor-table-hover: lighten($bgcolor-table, 7.5%) !default;
+
+// override bootstrap variables
+$table-dark-color: $color-table;
+$table-dark-bg: $bgcolor-table;
+$table-dark-border-color: $border-color-table;
+$table-dark-hover-color: $color-table-hover;
+$table-dark-hover-bg: $bgcolor-table-hover;
+
+@import 'reboot-bootstrap-tables';
 
 /*
   * Form
@@ -39,20 +53,6 @@ textarea.form-control {
   }
 }
 
-/*
- * Panel
- */
-.panel {
-  &,
-  &.panel-white,
-  &.panel-default {
-    .panel-heading,
-    .panel-body {
-      color: theme-color('light');
-    }
-  }
-}
-
 /*
  * Table
  */
@@ -83,38 +83,6 @@ ul.pagination {
   }
 }
 
-.table > thead > tr > th,
-.table > tbody > tr > th,
-.table > tfoot > tr > th,
-.table > thead > tr > td,
-.table > tbody > tr > td,
-.table > tfoot > tr > td,
-.table > thead > tr > th,
-.table-bordered {
-  // FIXME: use $table-dark-*
-  // border-top: 1px solid $border;
-}
-
-.table-bordered > thead > tr > th,
-.table-bordered > tbody > tr > th,
-.table-bordered > tfoot > tr > th,
-.table-bordered > thead > tr > td,
-.table-bordered > tbody > tr > td,
-.table-bordered > tfoot > tr > td {
-  // FIXME: use $table-dark-*
-  // border: 1px solid $border;
-}
-
-.table > thead > tr > th {
-  // FIXME: use $table-dark-*
-  // border-bottom: 1px solid $border;
-}
-
-.table-bordered {
-  // FIXME: use $table-dark-*
-  // border: 1px solid $border;
-}
-
 /*
  * GROWI page list
  */
@@ -138,15 +106,11 @@ ul.pagination {
   background-color: $bgcolor-subnabvar;
 }
 
-/*
- * GROWI search page
- */
-.search-page {
-  .input-group-btn {
-    .btn-light {
-      // FIXME:
-      // border: 1px solid darken($border, 30%); // fit to input.form-control
-    }
+// Search drop down
+#search-typeahead-asynctypeahead {
+  background-color: $bgcolor-global;
+  .table {
+    background-color: transparent;
   }
 }
 
@@ -161,12 +125,10 @@ ul.pagination {
 
 .wiki {
   h1 {
-    // FIXME:
-    // border-color: lighten($border, 10%);
+    border-color: lighten($border-color-theme, 10%);
   }
   h2 {
-    // FIXME:
-    // border-color: $border;
+    border-color: $border-color-theme;
   }
 }
 

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

@@ -123,6 +123,9 @@ body.kibela {
   }
 
   /* Modal */
+  .modal-title {
+    color: #ffffff; // override header colors
+  }
   .modal-content {
     background-color: $themelight;
   }
@@ -131,6 +134,8 @@ body.kibela {
   :not(.hljs) > code:not(.hljs) {
     color: $color-inline-code;
     background-color: $bgcolor-inline-code;
+    border: solid 1px $bordercolor-inline-code;
+    border-radius: 0.35em;
   }
 
   /* button */

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

@@ -1,5 +1,19 @@
 // determine optional variables
 $bgcolor-subnabvar: darken($bgcolor-global, 3%) !default;
+$color-table: $color-global !default;
+$bgcolor-table: null !default;
+$border-color-table: #dee2e6 !default;
+$color-table-hover: $color-table !default;
+$bgcolor-table-hover: rgba(black, 0.075) !default;
+
+// override bootstrap variables
+$table-color: $color-table;
+$table-bg: $bgcolor-table;
+$table-border-color: $border-color-table;
+$table-hover-color: $color-table-hover;
+$table-hover-bg: $bgcolor-table-hover;
+
+@import 'reboot-bootstrap-tables';
 
 /*
  * Form

+ 35 - 9
src/client/styles/scss/theme/_apply-colors.scss

@@ -13,6 +13,13 @@ $bgcolor-search-top-dropdown: $secondary !default;
 $bgcolor-sidebar-nav-item-active: darken($bgcolor-sidebar, 10%) !default;
 $text-shadow-sidebar-nav-item-active: 1px 1px 2px $primary !default;
 $bgcolor-sidebar-list-group: $bgcolor-list !default;
+$bgcolor-inline-code: #f0f0f0 !default;
+$color-inline-code: #c7254e !default;
+$bordercolor-inline-code: #ccc8c8 !default;
+$bordercolor-nav-tabs: #dee2e6 !default;
+$bordercolor-nav-tabs-hover: #e9ecef #e9ecef $bordercolor-nav-tabs !default;
+$color-nav-tabs-link-active: #495057 !default;
+$bordercolor-nav-tabs-active: $bordercolor-nav-tabs $bordercolor-nav-tabs $bgcolor-global !default;
 
 // override bootstrap variables
 $body-bg: $bgcolor-global;
@@ -20,17 +27,40 @@ $body-color: $color-global;
 $link-color: $color-link;
 $link-hover-color: $color-link-hover;
 $input-focus-color: $color-global;
+$nav-tabs-border-color: $bordercolor-nav-tabs;
+$nav-tabs-link-hover-border-color: $bordercolor-nav-tabs-hover;
+$nav-tabs-link-active-color: $color-nav-tabs-link-active;
+$nav-tabs-link-active-bg: $bgcolor-global;
+$nav-tabs-link-active-border-color: $bordercolor-nav-tabs-active;
 
 @import '~bootstrap/scss/functions';
 @import '~bootstrap/scss/variables';
 @import '~bootstrap/scss/mixins';
 @import '../mixins';
-@import 'mixins-for-tables';
 @import 'mixins/list-group';
+@import 'mixins/tables'; // comment out and use _reboot-bootstrap-tables instead -- 2020.05.28 Yuki Takei
 @import 'reboot-bootstrap-colors';
 @import 'reboot-bootstrap-theme-colors';
+@import 'reboot-bootstrap-nav';
 @import 'reboot-toastr-colors';
 
+:not(pre) {
+  > code {
+    color: $color-inline-code;
+    background-color: $bgcolor-inline-code;
+    border-color: $bordercolor-inline-code;
+  }
+}
+
+pre:not(.hljs):not(.CodeMirror-line) {
+  background-color: $bgcolor-inline-code;
+  border-color: $bordercolor-inline-code;
+}
+
+//
+//== Apply to Bootstrap Elements
+//
+
 // Link buttons
 .btn-link {
   color: $link-color;
@@ -176,14 +206,6 @@ $input-focus-color: $color-global;
   fill: $color-editor-icons;
 }
 
-/*
- * code color of inline-code
- */
-:not(.hljs) > code:not(.hljs) {
-  color: $color-inline-code;
-  background-color: $bgcolor-inline-code;
-}
-
 /*
  * Modal
  */
@@ -208,6 +230,10 @@ $input-focus-color: $color-global;
   }
 }
 
+.liker-and-seenusers {
+  border-bottom-color: $bordercolor-nav-tabs;
+}
+
 /*
  * cards
  */

+ 0 - 34
src/client/styles/scss/theme/_mixins-for-tables.scss

@@ -1,34 +0,0 @@
-//== Table
-$table-variants: (
-  'light': $light,
-  'dark': $dark,
-);
-
-// remove when master version is released
-// show https://github.com/twbs/bootstrap/blob/28cb1ff2b23253293601c51aff434c39b461025e/scss/mixins/_table-variants.scss
-@mixin table-variant($state, $background) {
-  .table-#{$state} {
-    $table-hover-bg-factor: 0.075 !default;
-    $table-striped-bg-factor: 0.05 !default;
-    $body-bg: $white !default;
-    $table-active-bg-factor: 0.1 !default;
-    $table-border-factor: 0.1 !default;
-
-    $color: color-contrast(mix(rgba($background, 1), $body-bg, opacity($background) * 100));
-    $color: gray;
-    $hover-bg: mix($color, $background, percentage($table-hover-bg-factor));
-    $striped-bg: mix($color, $background, percentage($table-striped-bg-factor));
-    $active-bg: mix($color, $background, percentage($table-active-bg-factor));
-
-    --bs-table-bg: #{$background};
-    --bs-table-striped-bg: #{$striped-bg};
-    --bs-table-striped-color: #{color-contrast($striped-bg)};
-    --bs-table-active-bg: #{$active-bg};
-    --bs-table-active-color: #{color-contrast($active-bg)};
-    --bs-table-hover-bg: #{$hover-bg};
-    --bs-table-hover-color: #{color-contrast($hover-bg)};
-
-    color: $color;
-    border-color: mix($color, $background, percentage($table-border-factor));
-  }
-}

+ 0 - 2
src/client/styles/scss/theme/_reboot-bootstrap-colors.scss

@@ -25,9 +25,7 @@ body {
   background-color: $body-bg; // 2
 }
 
-//
 // Links
-//
 
 a {
   color: $link-color;

+ 41 - 0
src/client/styles/scss/theme/_reboot-bootstrap-nav.scss

@@ -0,0 +1,41 @@
+//
+//
+// Apply partially
+//   https://github.com/twbs/bootstrap/blob/v4.5.0/scss/_nav.scss
+//
+//
+
+//
+// Tabs
+//
+
+.nav-tabs {
+  border-bottom: $nav-tabs-border-width solid $nav-tabs-border-color;
+
+  .nav-link {
+    border: $nav-tabs-border-width solid transparent;
+    @include border-top-radius($nav-tabs-border-radius);
+
+    @include hover-focus() {
+      border-color: $nav-tabs-link-hover-border-color;
+    }
+
+    &.disabled {
+      color: $nav-link-disabled-color;
+      background-color: transparent;
+      border-color: transparent;
+    }
+  }
+
+  .nav-link.active,
+  .nav-item.show .nav-link {
+    color: $nav-tabs-link-active-color;
+    background-color: $nav-tabs-link-active-bg;
+    border-color: $nav-tabs-link-active-border-color;
+  }
+
+  .dropdown-menu {
+    // Remove the top rounded corners here since there is a hard edge above the menu
+    @include border-top-radius(0);
+  }
+}

+ 72 - 0
src/client/styles/scss/theme/_reboot-bootstrap-tables.scss

@@ -0,0 +1,72 @@
+//
+//
+// Apply partially
+//   https://github.com/twbs/bootstrap/blob/v4.5.0/scss/_tables.scss
+//
+//
+
+.table {
+  color: $table-color;
+  background-color: $table-bg; // Reset for nesting within parents with `background-color`.
+
+  th,
+  td {
+    border-top-color: $table-border-color;
+  }
+
+  thead th {
+    border-bottom-color: $table-border-color;
+  }
+
+  tbody + tbody {
+    border-top-color: $table-border-color;
+  }
+}
+
+.table-bordered {
+  border-color: $table-border-color;
+
+  th,
+  td {
+    border-color: $table-border-color;
+  }
+}
+
+.table-hover {
+  tbody tr {
+    @include hover() {
+      color: $table-hover-color;
+      background-color: $table-hover-bg;
+    }
+  }
+}
+
+.table-dark {
+  color: $table-dark-color;
+  background-color: $table-dark-bg;
+
+  th,
+  td,
+  thead th {
+    border-color: $table-dark-border-color;
+  }
+
+  &.table-bordered {
+    border: 0;
+  }
+
+  &.table-striped {
+    tbody tr:nth-of-type(#{$table-striped-order}) {
+      background-color: $table-dark-accent-bg;
+    }
+  }
+
+  &.table-hover {
+    tbody tr {
+      @include hover() {
+        color: $table-dark-hover-color;
+        background-color: $table-dark-hover-bg;
+      }
+    }
+  }
+}

+ 10 - 4
src/client/styles/scss/theme/_reboot-bootstrap-theme-colors.scss

@@ -4,6 +4,16 @@ $theme-colors: map-merge($theme-colors, $colors);
   @include bg-variant('.bg-#{$color}', $value);
 }
 
+@each $color, $value in $theme-colors {
+  .border-#{$color} {
+    border-color: $value !important;
+  }
+}
+
+@each $color, $value in $theme-colors {
+  @include text-emphasis-variant('.text-#{$color}', $value, true);
+}
+
 @each $color, $value in $theme-colors {
   .btn-#{$color} {
     @include button-variant($value, $value);
@@ -65,7 +75,3 @@ $theme-colors: map-merge($theme-colors, $colors);
     background: $color;
   }
 }
-
-@each $color, $value in $table-variants {
-  @include table-variant($color, $value);
-}

+ 28 - 11
src/client/styles/scss/theme/antarctic.scss

@@ -49,19 +49,19 @@ html[dark] {
 
   // Background colors
   $bgcolor-global: $themelight;
-  $bgcolor-inline-code: #f9f2f4;
+  $bgcolor-inline-code: #f0f0f0; //optional
   $bgcolor-card: #f5f5f5;
 
   // Font colors
   $color-global: black;
   $color-reversal: #eeeeee;
   // $color-header: #2b2b2b;
-  $color-link: lighten($color-global, 20%);
+  $color-link: lighten($themecolor, 20%);
   $color-link-hover: lighten($color-link, 20%);
   $color-link-wiki: lighten($primary, 20%);
   $color-link-wiki-hover: lighten($color-link-wiki, 20%);
   $color-link-nabvar: $color-reversal;
-  $color-inline-code: #c7254e;
+  $color-inline-code: #c7254e; // optional
 
   // List Group colors
   $color-list: $color-global;
@@ -71,24 +71,34 @@ html[dark] {
   $color-list-hover: $color-reversal;
 
   // Navbar
-  $bgcolor-navbar: $themecolor;
-  $border-color-navbar-gradient-left: #545fff;
-  $border-color-navbar-gradient-right: #00a6e5;
-
+  $bgcolor-navbar: #35393f;
+  $bgcolor-search-top-dropdown: #fa9913;
+  $border-image-navbar: linear-gradient(to right, #f6d02e 0%, #f87c00 47%, #f6d02e 100%);
   // Logo colors
   $bgcolor-logo: $bgcolor-navbar;
   $fillcolor-logo-mark: lighten(desaturate($bgcolor-inline-code, 10%), 15%);
 
   // Sidebar
-  $bgcolor-sidebar: $bgcolor-navbar;
-  $color-sidebar-context: $color-reversal;
-  $bgcolor-sidebar-context: lighten($bgcolor-navbar, 10%);
+  $bgcolor-sidebar: $themecolor;
+  $bgcolor-sidebar-nav-item-active: rgba(#000000, 0.37); // optional
+  $text-shadow-sidebar-nav-item-active: 0px 0px 10px #0099ff; // optional
+  // Sidebar resize button
+  $color-resize-button: $color-reversal;
+  $bgcolor-resize-button: #fa9913;
+  $color-resize-button-hover: $color-reversal;
+  $bgcolor-resize-button-hover: lighten($bgcolor-resize-button, 5%);
+  // Sidebar contents
+  $color-sidebar-context: $themecolor;
+  $bgcolor-sidebar-context: #f4f6fc;
+  // Sidebar list group
+  $bgcolor-sidebar-list-group: #fafbff; // optional
 
   // Icon colors
   $color-editor-icons: $color-global;
 
   // Border colors
   $border-color-theme: #ccc; // former: `$navbar-border: #ccc;`
+  $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors
   $bgcolor-dropdown-link-active: $growi-blue;
@@ -110,6 +120,13 @@ html[dark] {
   .table {
     background-color: $themelight;
   }
+
+  #search-typeahead-asynctypeahead {
+    background-color: $bgcolor-global;
+    .table {
+      background-color: transparent;
+    }
+  }
 }
 
 //== Dark Mode
@@ -134,7 +151,7 @@ html[dark] {
 //   $color-link-wiki: lighten($basecolor, 50%);
 //   $color-link-wiki-hover: darken($color-link-wiki, 5%);
 //   $color-link-nabvar: $color-global;
-//   $color-inline-code: #c7254e;
+//   $color-inline-code: #c7254e; // optional
 
 //   // List Group colors
 //   $color-list: $color-global;

+ 30 - 54
src/client/styles/scss/theme/christmas.scss

@@ -12,20 +12,17 @@
 // $danger: #;
 // $light: #;
 // $dark: #;
+
 $themecolor: #b3000c;
 $themelight: white;
-
-$subthemecolor: #017e20;
+$subthemecolor: #30882c;
 $bgcolor-global: $themelight;
-$linktext: lighten(#0d5901, 5%);
-$linktext-hover: lighten($linktext, 12%);
+$linktext: $subthemecolor;
+$linktext-hover: lighten($subthemecolor, 15%);
 $sidebar-text: #ffffff;
 $fillcolor-logo-mark: lighten(desaturate($themecolor, 50%), 50%);
-$color-link-wiki: lighten($themecolor, 5%);
+$color-link-wiki: lighten($subthemecolor, 5%);
 $color-link-wiki-hover: lighten($color-link-wiki, 15%);
-$color-inline-code: darken($subthemecolor, 5%);
-$bgcolor-inline-code: lighten($subthemecolor, 70%);
-$active-nav-tabs-bgcolor: white;
 
 .growi:not(.login-page) {
   // add background-image
@@ -42,15 +39,18 @@ $active-nav-tabs-bgcolor: white;
 //
 html[light],
 html[dark] {
+  $primary: #d3c665;
   // Background colors
   $bgcolor-card: #f5f5f5;
+  $bgcolor-inline-code: #f0f0f0; //optional
 
   // Font colors
-  $color-global: $subthemecolor;
-  $color-reversal: #eeeeee;
-  $color-link: lighten($color-global, 2%);
-  $color-link-hover: lighten($color-link, 20%);
+  $color-global: #112744;
+  $color-reversal: #eee;
+  $color-link: $subthemecolor;
+  $color-link-hover: lighten($color-link, 10%);
   $color-link-nabvar: $color-reversal;
+  $color-inline-code: #c7254e; // optional
 
   // List Group colors
   $color-list: $color-global;
@@ -61,27 +61,39 @@ html[dark] {
 
   // Navbar
   $bgcolor-navbar: $themecolor;
+  $bgcolor-search-top-dropdown: $primary;
   $border-color-navbar-gradient-left: #545fff;
   $border-color-navbar-gradient-right: #00a6e5;
+  $border-image-navbar: linear-gradient(to right, #6458bc 33%, #5cb4ff 66%, #85d800 100%);
 
   // Logo colors
   $bgcolor-logo: $themecolor;
 
   // Sidebar
-  $bgcolor-sidebar: $themecolor;
-  $color-sidebar-context: $color-reversal;
-  $bgcolor-sidebar-context: lighten($themecolor, 10%);
+  $bgcolor-sidebar: $subthemecolor;
+  $bgcolor-sidebar-nav-item-active: rgba(#000000, 0.37); // optional
+  $text-shadow-sidebar-nav-item-active: 0px 0px 10px #0099ff; // optional
+  // Sidebar resize button
+  $color-resize-button: $color-reversal;
+  $bgcolor-resize-button: $primary;
+  $color-resize-button-hover: $color-reversal;
+  $bgcolor-resize-button-hover: lighten($bgcolor-resize-button, 5%);
+  $color-sidebar-context: $linktext;
+  $bgcolor-sidebar-context: #f4f6fc;
+  // Sidebar list group
+  $bgcolor-sidebar-list-group: #fafbff; // optional
 
   // Icon colors
   $color-editor-icons: $color-global;
 
   // Border colors
   $border-color-theme: #ccc; // former: `$navbar-border: #ccc;`
+  $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors
-  $bgcolor-dropdown-link-active: $growi-blue;
-  $color-dropdown-link-active: $color-reversal;
-  $color-dropdown-link-hover: $color-global;
+  $bgcolor-dropdown-link-active: $primary;
+  $color-dropdown-link-active: $color-global;
+  $color-dropdown-link-hover: $color-reversal;
 
   // admin theme box
   $color-theme-color-box: lighten($themecolor, 20%);
@@ -123,19 +135,6 @@ html[dark] {
     background-size: cover;
   }
 
-  /*
-  * Tabs
-  */
-  body:not(.on-edit) .nav.nav-tabs {
-    > li.active > a {
-      background: linear-gradient(
-        rgba($active-nav-tabs-bgcolor, 0) 0%,
-        rgba($active-nav-tabs-bgcolor, 0) 90%,
-        $active-nav-tabs-bgcolor 100%
-      ); // overwrite only the bottom pixel
-    }
-  }
-
   // login page
   .nologin {
     .input-group {
@@ -192,28 +191,5 @@ html[dark] {
 
   .grw-navbar {
     background-image: url('/images/themes/christmas/christmas-navbar.jpg');
-    border-bottom: 4px solid $subthemecolor;
-  }
-
-  .grw-subnav {
-    background-color: #ffffff;
-  }
-
-  .nav-tabs {
-    border-bottom-color: $themecolor;
-  }
-
-  .nav-link {
-    border-color: $themecolor;
-  }
-
-  .nav-tabs .nav-link.active {
-    background: none;
-    border-color: $themecolor;
-  }
-
-  .search-top .dropdown-toggle {
-    color: black;
-    background-color: hsla(0, 0%, 100%, 0.8);
   }
 }

+ 34 - 6
src/client/styles/scss/theme/default.scss

@@ -19,7 +19,7 @@ html[light] {
 
   // Background colors
   $bgcolor-global: white;
-  $bgcolor-inline-code: #f9f2f4;
+  $bgcolor-inline-code: #f0f0f0; //optional
   $bgcolor-card: #f5f5f5;
 
   // Font colors
@@ -31,7 +31,7 @@ html[light] {
   $color-link-wiki: $color-link;
   $color-link-wiki-hover: lighten($color-link-wiki, 20%);
   $color-link-nabvar: #a7a7a7;
-  $color-inline-code: #c7254e;
+  $color-inline-code: #c7254e; // optional
 
   // List Group colors
   // $color-list: $color-global; // optional
@@ -40,6 +40,14 @@ html[light] {
   // $color-list-active: $color-reversal; // optional
   // $bgcolor-list-active: $primary; // optional
 
+  // Table colors
+  // $bgcolor-subnabvar: #; // optional
+  // $color-table: #; // optional
+  // $bgcolor-table: #; // optional
+  // $border-color-table: #; // optional
+  // $color-table-hover: #; // optional
+  // $bgcolor-table-hover: #; // optional
+
   // Navbar
   $bgcolor-navbar: #2a2929;
   $bgcolor-search-top-dropdown: #209fd8;
@@ -67,11 +75,17 @@ html[light] {
   // Subnavigation
   // $bgcolor-subnabvar: #fafafa; // optional
 
+  // Tabs
+  // $color-nav-tabs-link-active: #; //optional
+  // $bordercolor-nav-tabs-hover: # # $bordercolor-nav-tabs; // optional
+  // $bordercolor-nav-tabs-active: # # $bgcolor-global; // optional
+
   // Icon colors
   $color-editor-icons: $color-global;
 
   // Border colors
-  $border-color-theme: #ccc; // former: `$navbar-border: #ccc;`
+  $border-color-theme: #ccc;
+  $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors
   $bgcolor-dropdown-link-active: $growi-blue;
@@ -98,7 +112,7 @@ html[dark] {
 
   // Background colors
   $bgcolor-global: #131418;
-  $bgcolor-inline-code: darken($bgcolor-global, 5%);
+  $bgcolor-inline-code: #1f1f22; //optional
   $bgcolor-card: darken($bgcolor-global, 5%);
 
   // Font colors
@@ -110,7 +124,7 @@ html[dark] {
   $color-link-wiki: $color-link;
   $color-link-wiki-hover: lighten($color-link-wiki, 10%);
   $color-link-nabvar: #a7a7a7;
-  $color-inline-code: #c7254e;
+  $color-inline-code: #c7254e; // optional
 
   // List Group colors
   // $color-list: $color-global; // optional
@@ -119,6 +133,13 @@ html[dark] {
   $color-list-active: white; // optional
   // $bgcolor-list-active: $primary; // optional
 
+  // Table colors
+  // $color-table: #; // optional
+  // $bgcolor-table: #; // optional
+  // $border-color-table: #; // optional
+  // $color-table-hover: #; // optional
+  // $bgcolor-table-hover: #; // optional
+
   // Navbar
   $bgcolor-navbar: #2a2929;
   $bgcolor-search-top-dropdown: $primary;
@@ -146,11 +167,18 @@ html[dark] {
   // Subnavigation
   $bgcolor-subnabvar: lighten($bgcolor-global, 4%); // optional
 
+  // Tabs
+  $bordercolor-nav-tabs: #444; // optional
+  // $color-nav-tabs-link-active: #; //optional
+  $bordercolor-nav-tabs-hover: #666 #666 $bordercolor-nav-tabs; // optional
+  // $bordercolor-nav-tabs-active: # # $bgcolor-global; // optional
+
   // Icon colors
   $color-editor-icons: $color-global;
 
   // Border colors
-  $border-color-theme: black; // former: `$navbar-border: #ccc;`
+  $border-color-theme: #444;
+  $bordercolor-inline-code: #666; // optional
 
   // Dropdown colors
   $bgcolor-dropdown-link-active: $primary;

+ 35 - 47
src/client/styles/scss/theme/future.scss

@@ -1,31 +1,28 @@
 @import '../variables';
 @import '../override-bootstrap-variables';
 
+$primary: #00b5b7;
 $themecolor: #16282d;
-$themelight: rgba(11, 79, 104, 0.616);
-$accentcolor: #66eddf;
-
-$primary: $themelight;
-$dark: darken($themecolor, 5%);
+$accentcolor: #00fff5;
 
 html[light],
 html[dark] {
   // Background colors
   $bgcolor-global: $themecolor;
-  $bgcolor-inline-code: darken($themecolor, 5%);
+  $bgcolor-inline-code: #1f1f22; //optional
   $bgcolor-card: darken($themecolor, 5%);
 
   // Font colors
-  $color-global: lighten($themecolor, 35%);
-  $color-reversal: #eeeeee;
-  $color-header: #d9a364;
-  $color-link: lighten($primary, 20%);
+  $color-global: #95abba;
+  $color-reversal: $accentcolor;
+  $color-header: #95abba;
+  $color-link: $accentcolor;
   $color-link-hover: lighten($color-link, 20%);
-  $color-link-wiki: darken($themecolor, 5%);
+  $color-link-wiki: $accentcolor;
   $color-link-wiki-hover: darken($color-link-wiki, 5%);
-  $color-link-nabvar: $color-reversal;
-  $color-inline-code: #c7254e;
-  $color-search: #050a0b;
+  $color-link-nabvar: #a7a7a7;
+  $color-inline-code: #c7254e; // optional
+  $color-search: $primary;
 
   // List Group colors
   $color-list: $color-global;
@@ -35,24 +32,38 @@ html[dark] {
   $color-list-hover: $color-reversal;
 
   // Navbar
-  $bgcolor-navbar: #011414;
-  $border-color-navbar-gradient-left: #545fff;
-  $border-color-navbar-gradient-right: #00a6e5;
+  $bgcolor-navbar: #01181a;
+  $bgcolor-search-top-dropdown: #00c2c4;
+  $border-image-navbar: linear-gradient(90deg, #6cfff9 0%, #0034c1 45%, #6cfff9 100%);
 
   // Logo colors
   $bgcolor-logo: darken($themecolor, 10%);
-  $fillcolor-logo-mark: lighten($accentcolor, 15%);
+  $fillcolor-logo-mark: #dedede;
 
   // Sidebar
-  $bgcolor-sidebar: $bgcolor-navbar;
-  $color-sidebar-context: $color-reversal;
-  $bgcolor-sidebar-context: lighten($bgcolor-navbar, 10%);
+  $bgcolor-sidebar: #052e2f;
+  $bgcolor-sidebar-nav-item-active: rgba(#969494, 0.3); // optional
+  $text-shadow-sidebar-nav-item-active: 0px 0px 10px #969494; // optional
+
+  // Sidebar contents
+  $color-sidebar-context: #00c2c4;
+  $bgcolor-sidebar-context: #020b0b;
+
+  // Sidebar list group
+  $bgcolor-sidebar-list-group: #162126; // optional
+
+  // Sidebar resize button
+  $color-resize-button: #0E2329;
+  $bgcolor-resize-button: #00C2C4;
+  $color-resize-button-hover: #0E2329;
+  $bgcolor-resize-button-hover: lighten($bgcolor-resize-button, 5%);
 
   // Icon colors
   $color-editor-icons: $color-global;
 
   // Border colors
   $border-color-theme: #407483;
+  $bordercolor-inline-code: #4d4d4d; // optional
 
   // Dropdown colors
   $bgcolor-dropdown-link-active: $primary;
@@ -78,31 +89,8 @@ html[dark] {
     }
   }
 
-  // Navs {
-  .nav-tabs {
-    border-bottom: $border-color-theme 1px solid;
-    .nav-link {
-      &:hover {
-        border-color: darken($border-color-theme, 10%);
-        border-bottom: none;
-      }
-      &.active {
-        color: $color-link;
-        background-color: transparent;
-        border-color: $border-color-theme;
-      }
-    }
-  }
-
-  // Search Top
-  .search-top {
-    .input-group-prepend .dropdown-toggle {
-      color: #5193a5;
-      background-color: $color-search;
-      border-color: $color-search;
-      &:hover {
-        background-color: darken($color-search, 10%);
-      }
-    }
+  pre {
+    color: #95abba;
+    background-color: #1f1f22;
   }
 }

+ 35 - 32
src/client/styles/scss/theme/halloween.scss

@@ -23,6 +23,7 @@ $light: lighten($secondary, 10%);
   #wrapper > .navbar {
     background-image: url(/images/themes/halloween/halloween-navbar.jpg);
   }
+
   // add background-image
   #page-wrapper,
   .page-editor-preview-container {
@@ -36,46 +37,63 @@ html[light],
 html[dark] {
   // Background colors
   $bgcolor-global: #050000;
-  $bgcolor-inline-code: #f9f2f4;
+  $bgcolor-inline-code: #1f1f22; //optional
   $bgcolor-card: #f5f5f5;
 
   // Font colors
   $color-global: #e9af2b;
   $color-reversal: #eeeeee;
   // $color-header: #2b2b2b;
-  $color-link: lighten($primary, 20%);
+  $color-link: #aa97cb;
   $color-link-hover: lighten($color-link, 20%);
-  $color-link-wiki: lighten($primary, 20%);
+  $color-link-wiki: #aa97cb;
   $color-link-wiki-hover: lighten($color-link-wiki, 20%);
-  $color-link-nabvar: $color-reversal;
-  $color-inline-code: #c7254e;
+  $color-link-nabvar: #a7a7a7;
+  $color-inline-code: #c7254e; // optional
 
   // List Group colors
-  $color-list: $color-global;
+  $color-list: #979797;
   $bgcolor-list: transparent;
   $color-list-active: $color-reversal;
   $bgcolor-list-active: $primary;
   $color-list-hover: $themecolor;
 
+  // Search Top
+  $color-search: $primary;
+
   // Navbar
-  $bgcolor-navbar: #223344;
-  $border-color-navbar-gradient-left: #545fff;
-  $border-color-navbar-gradient-right: #00a6e5;
+  $bgcolor-navbar: #eceded;
+  $bgcolor-search-top-dropdown: $primary;
+  $border-image-navbar: linear-gradient(90deg, #e3b7ff 0%, #134774 100%);
 
   // Logo colors
   $bgcolor-logo: darken($themecolor, 10%);
-  $fillcolor-logo-mark: lighten($accentcolor, 15%);
+  $fillcolor-logo-mark: #dedede;
 
   // Sidebar
-  $bgcolor-sidebar: $bgcolor-navbar;
-  $color-sidebar-context: $color-reversal;
-  $bgcolor-sidebar-context: lighten($bgcolor-navbar, 10%);
+  $bgcolor-sidebar: #162b33;
+  $bgcolor-sidebar-nav-item-active: rgba(#969494, 0.3); // optional
+  $text-shadow-sidebar-nav-item-active: 0px 0px 10px #969494; // optional
+
+  // Sidebar contents
+  $color-sidebar-context: #aa97cb;
+  $bgcolor-sidebar-context: #1d2126;
+
+  // Sidebar list group
+  $bgcolor-sidebar-list-group: #2c2926; // optional
+
+  // Sidebar resize button
+  $color-resize-button: #effcfa;
+  $bgcolor-resize-button: $primary;
+  $color-resize-button-hover: #effcfa;
+  $bgcolor-resize-button-hover: lighten($bgcolor-resize-button, 5%);
 
   // Icon colors
   $color-editor-icons: $color-global;
 
   // Border colors
   $border-color-theme: #ccc; // former: `$navbar-border: #ccc;`
+  $bordercolor-inline-code: #4d4d4d; // optional
 
   // Dropdown colors
   $bgcolor-dropdown-link-active: $primary;
@@ -98,25 +116,10 @@ html[dark] {
   .table {
     color: $color-global;
   }
-  .table-bordered {
-    th,
-    td {
-      border: 1px solid $themecolor;
-    }
-  }
 
-  // Nav
-  .nav-tabs {
-    border-bottom: $bordercolor 1px solid;
-    .nav-link {
-      &:hover {
-        border: $bordercolor 1px solid;
-      }
-      &.active {
-        color: lighten($themecolor, 5%);
-        background-color: transparent;
-        border: $bordercolor 1px solid;
-      }
-    }
+  pre {
+    color: #edba4a;
+    background: #000000;
   }
+
 }

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

@@ -19,12 +19,14 @@ html[dark] {
   // Background colors
   $bgcolor-card: #f5f5f5;
   $bgcolor-global: lighten($color-themelight, 10%);
+  $bgcolor-inline-code: #f0f0f0; //optional
 
   // Font colors
   $color-reversal: #eeeeee;
   $color-link: lighten($color-global, 20%);
   $color-link-hover: lighten($color-link, 20%);
   $color-link-nabvar: $color-reversal;
+  $color-inline-code: #c7254e; // optional
 
   // List Group colors
   $color-list: $color-global;
@@ -52,6 +54,7 @@ html[dark] {
 
   // Border colors
   $border-color-theme: #ccc;
+  $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors
   $bgcolor-dropdown-link-active: $growi-blue;

+ 16 - 67
src/client/styles/scss/theme/kibela.scss

@@ -7,7 +7,8 @@ $subthemecolor: rgb(88, 130, 250);
 $lightthemecolor: rgba(181, 203, 247, 0.61);
 
 // Light Mode
-html[light] {
+html[light],
+html[dark] {
   // Background colors
   $bgcolor-navbar: white;
   $bgcolor-navbar-active: $bgcolor-theme;
@@ -31,71 +32,8 @@ html[light] {
   $bgcolor-list-active: $primary;
   $color-list-hover: $color-reversal;
 
-  // Logo colors
-  $bgcolor-logo: transparent;
-  $fillcolor-logo-mark: lighten($bgcolor-theme, 20%);
-
-  // Icon colors
-  $color-editor-icons: $color-global;
-
-  $color-link-wiki: lighten($bgcolor-theme, 20%);
-  $color-link-wiki-hover: lighten($color-link-wiki, 20%);
-  $color-link-nabvar: $color-global;
-  $color-link-nabvar-hover: $color-global;
-  $color-inline-code: $subthemecolor;
-
-  // border colors
-  $border-color-theme: $lightthemecolor;
-  $thickborder: #5584e1;
-
-  // dropdown colors
-  $bgcolor-dropdown-link-active: $growi-blue;
-  $color-dropdown-link-active: $color-reversal;
-  $color-dropdown-link-hover: $color-global;
-
-  // admin theme box
-  $color-theme-color-box: lighten($bgcolor-theme, 20%);
-
-  // alert
-  $color-alert: $color-reversal;
-
-  // badge
-  $color-badge: $color-reversal;
-
-  // Sidebar
-  $bgcolor-sidebar: $bgcolor-theme;
-  $color-sidebar-context: $color-reversal;
-  $bgcolor-sidebar-context: lighten($bgcolor-theme, 10%);
-
-  @import 'apply-colors';
-  @import 'apply-colors-light';
-  @import 'apply-colors-kibela';
-}
-
-// Dark Mode ( same as Light Mode )
-html[dark] {
-  // Background colors
-  $bgcolor-navbar: white;
-  $bgcolor-navbar-active: $bgcolor-theme;
-  $bgcolor-global: $themelight;
-  $bgcolor-card: $lightthemecolor;
-  $bgcolor-inline-code: lighten($subthemecolor, 70%);
-  $color-header: $bgcolor-theme;
-  $color-global: #3c4a60;
-  $color-link: rgb(74, 109, 204);
-  $color-link-hover: lighten($color-link, 12%);
-  $sidebar-text: $bgcolor-theme;
-  $color-reversal: #eee;
-
-  $primary: $bgcolor-theme;
-  $info: lighten($bgcolor-theme, 20%);
-
-  // List Group colors
-  $color-list: $color-global;
-  $bgcolor-list: $bgcolor-global;
-  $color-list-active: $color-reversal;
-  $bgcolor-list-active: $primary;
-  $color-list-hover: $color-reversal;
+  // navbar
+  $bgcolor-search-top-dropdown: $primary;
 
   // Logo colors
   $bgcolor-logo: transparent;
@@ -113,6 +51,7 @@ html[dark] {
   // border colors
   $border-color-theme: $lightthemecolor;
   $thickborder: #5584e1;
+  $bordercolor-inline-code: $lightthemecolor;
 
   // dropdown colors
   $bgcolor-dropdown-link-active: $growi-blue;
@@ -131,7 +70,17 @@ html[dark] {
   // Sidebar
   $bgcolor-sidebar: $bgcolor-theme;
   $color-sidebar-context: $color-reversal;
-  $bgcolor-sidebar-context: lighten($bgcolor-theme, 5%);
+  $bgcolor-sidebar-context: lighten($bgcolor-theme, 10%);
+  // Sidebar resize button
+  $color-resize-button: $color-reversal;
+  $bgcolor-resize-button: #209fd8;
+  $color-resize-button-hover: $color-reversal;
+  $bgcolor-resize-button-hover: lighten($bgcolor-resize-button, 5%);
+  // Sidebar contents
+  $color-sidebar-context: $color-global;
+  $bgcolor-sidebar-context: #f4f6fc;
+  // Sidebar list group
+  $bgcolor-sidebar-list-group: #fafbff; // optional
 
   @import 'apply-colors';
   @import 'apply-colors-light';

+ 34 - 0
src/client/styles/scss/theme/mixins/_tables.scss

@@ -0,0 +1,34 @@
+//== Table
+// $table-variants: (
+//   'light': $light,
+//   'dark': $dark,
+// );
+
+// remove when master version is released
+// show https://github.com/twbs/bootstrap/blob/28cb1ff2b23253293601c51aff434c39b461025e/scss/mixins/_table-variants.scss
+// @mixin table-variant($state, $background) {
+//   .table-#{$state} {
+//     $table-hover-bg-factor: 0.075 !default;
+//     $table-striped-bg-factor: 0.05 !default;
+//     $body-bg: $white !default;
+//     $table-active-bg-factor: 0.1 !default;
+//     $table-border-factor: 0.1 !default;
+
+//     $color: color-contrast(mix(rgba($background, 1), $body-bg, opacity($background) * 100));
+//     $color: gray;
+//     $hover-bg: mix($color, $background, percentage($table-hover-bg-factor));
+//     $striped-bg: mix($color, $background, percentage($table-striped-bg-factor));
+//     $active-bg: mix($color, $background, percentage($table-active-bg-factor));
+
+//     --bs-table-bg: #{$background};
+//     --bs-table-striped-bg: #{$striped-bg};
+//     --bs-table-striped-color: #{color-contrast($striped-bg)};
+//     --bs-table-active-bg: #{$active-bg};
+//     --bs-table-active-color: #{color-contrast($active-bg)};
+//     --bs-table-hover-bg: #{$hover-bg};
+//     --bs-table-hover-color: #{color-contrast($hover-bg)};
+
+//     color: $color;
+//     border-color: mix($color, $background, percentage($table-border-factor));
+//   }
+// }

+ 6 - 3
src/client/styles/scss/theme/mono-blue.scss

@@ -12,7 +12,7 @@ html[light] {
 
   // Background colors
   $bgcolor-global: $themelight;
-  $bgcolor-inline-code: lighten($subthemecolor, 70%);
+  $bgcolor-inline-code: #f0f0f0; //optional
   $bgcolor-card: darken($themelight, 5%);
 
   // Font colors
@@ -23,7 +23,7 @@ html[light] {
   $color-link-wiki: lighten($primary, 20%);
   $color-link-wiki-hover: lighten($color-link-wiki, 20%);
   $color-link-nabvar: $color-reversal;
-  $color-inline-code: $subthemecolor;
+  $color-inline-code: #c7254e; // optional
   $color-search: #c0d6df;
 
   // List Group colors
@@ -62,6 +62,7 @@ html[light] {
 
   // Border colors
   $border-color-theme: #ccc;
+  $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors
   $bgcolor-dropdown-link-active: $primary;
@@ -107,7 +108,7 @@ html[dark] {
   // Background colors
   $bgcolor-global: $themedark;
   $bgcolor-navbar: #27343b;
-  $bgcolor-inline-code: #0a121b;
+  $bgcolor-inline-code: #1f1f22; //optional
   $bgcolor-card: darken($themedark, 5%);
 
   // Font colors
@@ -119,6 +120,7 @@ html[dark] {
   $color-link-wiki-hover: lighten($color-link-wiki, 20%);
   $color-link-nabvar: $color-reversal;
   $color-inline-code: $subthemecolor;
+  $color-inline-code: #c7254e; // optional
   $color-search: #000102;
 
   // List Group colors
@@ -158,6 +160,7 @@ html[dark] {
 
   // Border colors
   $border-color-theme: #146aa0;
+  $bordercolor-inline-code: #4d4d4d; // optional
 
   // Dropdown colors
   $bgcolor-dropdown-link-active: $primary;

+ 7 - 6
src/client/styles/scss/theme/nature.scss

@@ -39,13 +39,13 @@ html[light],
 html[dark] {
   $primary: #460039;
   $light: #f0f0f0;
-  
+
   // Background colors
   $bgcolor-global: #fdfdfd;
-  $bgcolor-inline-code: #eaeaea;
+  $bgcolor-inline-code: #f0f0f0; //optional
   $bgcolor-card: #f1ffe4;
   $bgcolor-subnabvar: #fafafa;
-  
+
   // Font colors
   $color-global: #460039;
   $color-reversal: #eeeeee;
@@ -54,14 +54,14 @@ html[dark] {
   $color-link-wiki: lighten($primary, 20%);
   $color-link-wiki-hover: lighten($color-link-wiki, 20%);
   $color-link-nabvar: #a7a7a7;
-  $color-inline-code: #890000;
+  $color-inline-code: #c7254e; // optional
   $color-search: white;
-  
+
   // Navbar
   $bgcolor-navbar: #234136;
   $bgcolor-search-top-dropdown: $themecolor;
   $border-image-navbar: linear-gradient(to right, #5c78ef 0%, #16bc42 50%, #5c78ef 100%);
-  
+
   // Logo colors
   $bgcolor-logo: $bgcolor-navbar;
   $fillcolor-logo-mark: lighten(desaturate($bgcolor-inline-code, 10%), 15%);
@@ -80,6 +80,7 @@ html[dark] {
 
   // Border colors
   $border-color-theme: #ccc;
+  $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors
   $bgcolor-dropdown-link-active: $growi-blue;

+ 21 - 12
src/client/styles/scss/theme/spring.scss

@@ -48,22 +48,22 @@ $accentcolor: #e08dbc;
 html[light],
 html[dark] {
   $primary: $themecolor;
+  $secondary: $accentcolor;
 
   // Background colors
   $bgcolor-global: white;
-  $bgcolor-inline-code: #f9f2f4;
+  $bgcolor-inline-code: #f0f0f0; //optional
   $bgcolor-card: #f5f5f5;
 
   // Font colors
   $color-global: black;
   $color-reversal: white;
-  // $color-header: #2b2b2b;
-  $color-link: lighten($color-global, 20%);
-  $color-link-hover: $subthemecolor;
+  $color-link: $subthemecolor;
+  $color-link-hover: lighten($subthemecolor, 10%);
   $color-link-wiki: $subthemecolor;
-  $color-link-wiki-hover: lighten($color-link-wiki, 20%);
+  $color-link-wiki-hover: lighten($color-link-wiki, 10%);
   $color-link-nabvar: $bgcolor-global;
-  $color-inline-code: #c7254e;
+  $color-inline-code: #c7254e; // optional
 
   // List Group colors
   $color-list: $color-global;
@@ -73,24 +73,33 @@ html[dark] {
   $color-list-hover: lighten($accentcolor, 20%);
 
   // Navbar
-  $bgcolor-navbar: $themecolor;
-  $border-color-navbar-gradient-left: #545fff;
-  $border-color-navbar-gradient-right: #00a6e5;
+  $bgcolor-navbar: #d3687c;
+  $bgcolor-search-top-dropdown: $themecolor;
+  $border-image-navbar: linear-gradient(to right, #cbe682 0%, #4ad6e8 50%, #ea42f0 100%);
 
   // Logo colors
   $bgcolor-logo: $bgcolor-navbar;
   $fillcolor-logo-mark: lighten(desaturate($bgcolor-inline-code, 10%), 15%);
 
   // Sidebar
-  $bgcolor-sidebar: $bgcolor-navbar;
-  $color-sidebar-context: $color-reversal;
-  $bgcolor-sidebar-context: lighten($bgcolor-navbar, 10%);
+  $bgcolor-sidebar: $themecolor;
+  // Sidebar resize button
+  $color-resize-button: $color-reversal;
+  $bgcolor-resize-button: $subthemecolor;
+  $color-resize-button-hover: $color-reversal;
+  $bgcolor-resize-button-hover: lighten($bgcolor-resize-button, 5%);
+  // Sidebar contents
+  $color-sidebar-context: $subthemecolor;
+  $bgcolor-sidebar-context: #f4f6fc;
+  // Sidebar list group
+  $bgcolor-sidebar-list-group: #fafbff; // optional
 
   // Icon colors
   $color-editor-icons: $color-global;
 
   // Border colors
   $border-color-theme: #ccc; // former: `$navbar-border: #ccc;`
+  $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors
   $bgcolor-dropdown-link-active: $growi-blue;

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

@@ -42,7 +42,7 @@ html[dark] {
 
   // Background colors
   $bgcolor-global: #ffffff;
-  $bgcolor-inline-code: #eaeaea;
+  $bgcolor-inline-code: #f0f0f0; //optional
   $bgcolor-card: #ece8de;
 
   // Font colors
@@ -54,7 +54,7 @@ html[dark] {
   $color-link-wiki: lighten($themecolor, 5%);
   $color-link-wiki-hover: lighten($color-link-wiki, 15%);
   $color-link-nabvar: #a7a7a7;
-  $color-inline-code: #890000;
+  $color-inline-code: #c7254e; // optional
   $color-search: white;
 
   // List Group colors
@@ -83,6 +83,7 @@ html[dark] {
 
   // Border colors
   $border-color-theme: #ccc; // former: `$navbar-border: #ccc;`
+  $bordercolor-inline-code: #ccc8c8; // optional
 
   // Dropdown colors
   $bgcolor-dropdown-link-active: $growi-blue;
@@ -123,7 +124,7 @@ html[dark] {
   }
 
   // Sidebar
-  .grw-sidebar div[data-testid='GlobalNavigation']{
+  .grw-sidebar div[data-testid='GlobalNavigation'] {
     * {
       background-image: url('/images/themes/wood/wood-navbar.jpg');
     }

+ 4 - 2
src/lib/models/devided-page-path.js

@@ -1,11 +1,11 @@
-import { pathUtils } from 'growi-commons';
+const { pathUtils } = require('growi-commons');
 
 // https://regex101.com/r/BahpKX/2
 const PATTERN_INCLUDE_DATE = /^(.+\/[^/]+)\/(\d{4}|\d{4}\/\d{2}|\d{4}\/\d{2}\/\d{2})$/;
 // https://regex101.com/r/WVpPpY/1
 const PATTERN_DEFAULT = /^((.*)\/)?([^/]+)$/;
 
-export default class DevidedPagePath {
+class DevidedPagePath {
 
   constructor(path, skipNormalize = false, evalDatePath = false) {
 
@@ -43,3 +43,5 @@ export default class DevidedPagePath {
   }
 
 }
+
+module.exports = DevidedPagePath;

+ 6 - 4
src/lib/models/linked-page-path.js

@@ -1,12 +1,12 @@
-import { pathUtils } from 'growi-commons';
-import { isTrashPage } from '@commons/util/path-utils';
+const { pathUtils } = require('growi-commons');
+const { isTrashPage } = require('@commons/util/path-utils');
 
-import DevidedPagePath from './devided-page-path';
+const DevidedPagePath = require('./devided-page-path');
 
 /**
  * Linked Array Structured PagePath Model
  */
-export default class LinkedPagePath {
+class LinkedPagePath {
 
   constructor(path, skipNormalize = false) {
 
@@ -34,3 +34,5 @@ export default class LinkedPagePath {
   }
 
 }
+
+module.exports = LinkedPagePath;

+ 2 - 2
src/server/models/user.js

@@ -255,10 +255,10 @@ module.exports = function(crowi) {
       const hash = md5(email.trim().toLowerCase());
       return `https://gravatar.com/avatar/${hash}`;
     }
-    if (this.image) {
+    if (this.image != null) {
       return this.image;
     }
-    if (this.imageAttachment) {
+    if (this.imageAttachment != null && this.imageAttachment._id != null) {
       const Attachment = crowi.model('Attachment');
       const imageAttachment = await Attachment.findById(this.imageAttachment);
       return imageAttachment.filePathProxied;

+ 1 - 3
src/server/routes/apiv3/users.js

@@ -585,13 +585,11 @@ module.exports = (crowi) => {
         };
       }));
 
-      let updatedUsers = [];
       if (requests.length > 0) {
         await User.bulkWrite(requests);
-        updatedUsers = await User.find({ _id: { $in: userIds } }, User.USER_PUBLIC_FIELDS);
       }
 
-      return res.apiv3({ updatedUsers });
+      return res.apiv3({});
     }
     catch (err) {
       logger.error('Error', err);

+ 1 - 1
src/server/routes/installer.js

@@ -38,7 +38,7 @@ module.exports = function(crowi, app) {
 
     // create /Sandbox/*
     promises.push(createPage(path.join(crowi.localeDir, lang, 'sandbox.md'), '/Sandbox', owner, lang));
-    promises.push(createPage(path.join(crowi.localeDir, lang, 'sandbox-bootstrap4.md'), '/Sandbox/Bootstrap3', owner, lang));
+    promises.push(createPage(path.join(crowi.localeDir, lang, 'sandbox-bootstrap4.md'), '/Sandbox/Bootstrap4', owner, lang));
     promises.push(createPage(path.join(crowi.localeDir, lang, 'sandbox-diagrams.md'), '/Sandbox/Diagrams', owner, lang));
     promises.push(createPage(path.join(crowi.localeDir, lang, 'sandbox-math.md'), '/Sandbox/Math', owner, lang));
 

+ 22 - 4
src/server/service/customize.js

@@ -1,4 +1,7 @@
-const logger = require('@alias/logger')('growi:service:CustomizeService'); // eslint-disable-line no-unused-vars
+// eslint-disable-next-line no-unused-vars
+const logger = require('@alias/logger')('growi:service:CustomizeService');
+
+const DevidedPagePath = require('@commons/models/devided-page-path');
 
 /**
  * the service class of CustomizeService
@@ -35,17 +38,32 @@ class CustomizeService {
     let configValue = this.configManager.getConfig('crowi', 'customize:title');
 
     if (configValue == null || configValue.trim().length === 0) {
-      configValue = '{{page}} - {{sitename}}';
+      configValue = '{{pagename}} - {{sitename}}';
     }
 
     this.customTitleTemplate = configValue;
   }
 
-  generateCustomTitle(page) {
+  generateCustomTitle(pageOrPath) {
+    const path = pageOrPath.path || pageOrPath;
+    const dPagePath = new DevidedPagePath(path, true, true);
+
+    const customTitle = this.customTitleTemplate
+      .replace('{{sitename}}', this.appService.getAppTitle())
+      .replace('{{pagepath}}', path)
+      .replace('{{page}}', dPagePath.latter) // for backward compatibility
+      .replace('{{pagename}}', dPagePath.latter);
+
+    return this.xssService.process(customTitle);
+  }
+
+  generateCustomTitleForFixedPageName(title) {
     // replace
     const customTitle = this.customTitleTemplate
       .replace('{{sitename}}', this.appService.getAppTitle())
-      .replace('{{page}}', page);
+      .replace('{{page}}', title)
+      .replace('{{pagepath}}', title)
+      .replace('{{pagename}}', title);
 
     return this.xssService.process(customTitle);
   }

+ 1 - 1
src/server/service/passport.js

@@ -854,7 +854,7 @@ class PassportService {
         if (user == null) {
           throw new Error('user not found');
         }
-        if (!user.imageUrlCached) {
+        if (user.imageUrlCached == null) {
           await user.updateImageUrlCached();
           await user.save();
         }

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

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('App Settings')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('App Settings')) }}{% endblock %}
 
 {% block head_warn_alert_siteurl_undefined %} {# remove including block for './widget/alert_siteurl_undefined.html' #}
 {% endblock %}

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

@@ -1,5 +1,5 @@
 {% extends '../layout/admin.html' %}
-{% block html_title %}{{ customizeService.generateCustomTitle(t('Customize')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('Customize')) }}{% endblock %}
 
 {% block html_additional_headers %}
 {% parent %}
@@ -19,6 +19,9 @@
 {% block content_main %}
 <div class="content-main admin-customize row">
   {% parent %}
+  <div id="grw-hljs-container-for-demo">
+    {{ cdnHighlightJsStyleTag(getConfig('crowi', 'customize:highlightJsStyle')) }}
+  </div>
   <div class="col-lg-9" id="admin-customize"></div>
 </div>
 {% endblock content_main %}

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

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('Export Archive Data')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('Export Archive Data')) }}{% endblock %}
 
 {% block content_header %}
 <h1 class="title">{{ t('Export Archive Data') }}</h1>

+ 1 - 1
src/server/views/admin/external-accounts.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('external_account_management')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('external_account_management')) }}{% endblock %}
 
 {% block content_header %}
 <h1 class="title">{{ t('User_Management') }} / {{ t('external_account_management') }}</h1>

+ 1 - 1
src/server/views/admin/global-notification-detail.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('Notification Settings')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('Notification Settings')) }}{% endblock %}
 
 {% block content_header %}
 <h1 class="title">{{ t('Notification Settings') }}</h1>

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

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('Import Data')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('Import Data')) }}{% endblock %}
 
 {% block content_header %}
 <h1 class="title">{{ t('Import Data') }}</h1>

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

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('Wiki Management Home Page')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('Wiki Management Home Page')) }}{% endblock %}
 
 {% block content_header %}
 <h1 class="title"> {{ t('Wiki Management Home Page') }}</h1>

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

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('Markdown Settings')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('Markdown Settings')) }}{% endblock %}
 
 {% block content_header %}
 <h1 class="title">{{ t('Markdown Settings') }}</h1>

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

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('Notification Settings')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('Notification Settings')) }}{% endblock %}
 
 {% block content_header %}
 <h1 class="title">{{ t('Notification Settings') }}</h1>

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

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('Full Text Search Management')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('Full Text Search Management')) }}{% endblock %}
 
 {% block content_header %}
 <h1 class="title">{{ t('Full Text Search Management') }}</h1>

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

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('security_settings')) }} · {% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('security_settings')) }} · {% endblock %}
 
 {% block content_header %}
 <h1 class="title">{{ t('security_settings') }}</h1>

+ 1 - 1
src/server/views/admin/user-group-detail.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('UserGroup Management') + '/' + userGroup.name) | preventXss }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('UserGroup Management') + '/' + userGroup.name) | preventXss }}{% endblock %}
 
 {% block content_header %}
 <h1 class="title">{{ t('UserGroup Management') + '/' + userGroup.name | preventXss }}</h1>

+ 1 - 1
src/server/views/admin/user-groups.html

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('UserGroup Management')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('UserGroup Management')) }}{% endblock %}
 
 {% block content_header %}
 <h1 class="title">{{ t('UserGroup Management') }}</h1>

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

@@ -1,6 +1,6 @@
 {% extends '../layout/admin.html' %}
 
-{% block html_title %}{{ customizeService.generateCustomTitle(t('User_Management')) }}{% endblock %}
+{% block html_title %}{{ customizeService.generateCustomTitleForFixedPageName(t('User_Management')) }}{% endblock %}
 
 {% block content_header %}
 <h1 class="title">{{ t('User_Management') }}</h1>

+ 1 - 1
src/server/views/installer.html

@@ -4,7 +4,7 @@
 <head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-  <title>{{ customizeService.generateCustomTitle(t('installer.setup')) }}</title>
+  <title>{{ customizeService.generateCustomTitleForFixedPageName(t('installer.setup')) }}</title>
   <meta name="description" content="">
   <meta name="author" content="">
 

Некоторые файлы не были показаны из-за большого количества измененных файлов