Sfoglia il codice sorgente

Merge branch 'support/apply-bootstrap4' into support/adjust-list-group-colors

itizawa 6 anni fa
parent
commit
e17917785a
79 ha cambiato i file con 856 aggiunte e 628 eliminazioni
  1. 5 0
      .github/workflows/build-rc.yml
  2. 5 0
      .github/workflows/build.yml
  3. 8 4
      .github/workflows/ci.yml
  4. 1 1
      config/webpack.common.js
  5. 7 2
      resource/locales/en-US/admin/admin.json
  6. 1 1
      resource/locales/en-US/translation.json
  7. 6 1
      resource/locales/ja/admin/admin.json
  8. 2 2
      resource/locales/ja/translation.json
  9. 1 1
      src/client/js/bootstrap.jsx
  10. 15 15
      src/client/js/components/Admin/App/AwsSetting.jsx
  11. 7 7
      src/client/js/components/Admin/App/MailSetting.jsx
  12. 1 1
      src/client/js/components/Admin/App/SiteUrlSetting.jsx
  13. 1 1
      src/client/js/components/Admin/Common/AdminUpdateButtonRow.jsx
  14. 3 1
      src/client/js/components/Admin/Customize/CustomizeHeaderSetting.jsx
  15. 1 1
      src/client/js/components/Admin/Customize/CustomizeThemeOptions.jsx
  16. 3 3
      src/client/js/components/Admin/ElasticsearchManagement/ElasticsearchManagement.jsx
  17. 4 3
      src/client/js/components/Admin/ElasticsearchManagement/StatusTable.jsx
  18. 1 1
      src/client/js/components/Admin/ExportArchiveData/SelectCollectionsModal.jsx
  19. 1 1
      src/client/js/components/Admin/ImportData/GrowiArchive/ErrorViewer.jsx
  20. 1 1
      src/client/js/components/Admin/ImportData/GrowiArchive/ImportCollectionConfigurationModal.jsx
  21. 17 15
      src/client/js/components/Admin/ImportData/GrowiArchive/ImportForm.jsx
  22. 3 3
      src/client/js/components/Admin/ImportData/GrowiArchive/UploadForm.jsx
  23. 16 16
      src/client/js/components/Admin/ImportDataPage.jsx
  24. 1 1
      src/client/js/components/Admin/Notification/NotificationDeleteModal.jsx
  25. 5 5
      src/client/js/components/Admin/Notification/SlackAppConfiguration.jsx
  26. 1 3
      src/client/js/components/Admin/Security/LdapAuthTestModal.jsx
  27. 9 9
      src/client/js/components/Admin/Security/SecuritySetting.jsx
  28. 1 1
      src/client/js/components/Admin/UserGroup/UserGroupDeleteModal.jsx
  29. 1 1
      src/client/js/components/Admin/UserGroupDetail/UserGroupUserModal.jsx
  30. 5 5
      src/client/js/components/Admin/UserManagement.jsx
  31. 1 1
      src/client/js/components/Admin/Users/PasswordResetModal.jsx
  32. 1 1
      src/client/js/components/Admin/Users/UserInviteModal.jsx
  33. 1 1
      src/client/js/components/Admin/Users/UserTable.jsx
  34. 4 4
      src/client/js/components/Me/ApiSettings.jsx
  35. 2 2
      src/client/js/components/Me/AssociateModal.jsx
  36. 12 12
      src/client/js/components/Me/BasicInfoSettings.jsx
  37. 1 1
      src/client/js/components/Me/DisassociateModal.jsx
  38. 1 1
      src/client/js/components/Me/ImageCropModal.jsx
  39. 17 15
      src/client/js/components/Me/PasswordSettings.jsx
  40. 6 6
      src/client/js/components/Me/ProfileImageSettings.jsx
  41. 9 5
      src/client/js/components/Navbar/GrowiSubNavigation.jsx
  42. 12 8
      src/client/js/components/Navbar/GrowiSubNavigationForUserPage.jsx
  43. 12 3
      src/client/js/components/Navbar/NavbarToggler.jsx
  44. 1 1
      src/client/js/components/Page/TagEditor.jsx
  45. 1 1
      src/client/js/components/PageAttachment/DeleteAttachmentModal.jsx
  46. 2 2
      src/client/js/components/PageComment/DeleteCommentModal.jsx
  47. 1 1
      src/client/js/components/PageEditor/Editor.jsx
  48. 14 6
      src/client/js/components/PageEditor/HandsontableModal.jsx
  49. 1 1
      src/client/js/components/PageHistory/RevisionDiff.jsx
  50. 1 1
      src/client/js/components/SavePageControls/GrantSelector.jsx
  51. 1 1
      src/client/js/components/SearchPage/DeletePageListModal.jsx
  52. 1 1
      src/client/js/components/SearchPage/SearchPageForm.jsx
  53. 88 38
      src/client/js/components/Sidebar.jsx
  54. 7 0
      src/client/js/services/AppContainer.js
  55. 0 56
      src/client/styles/scss/_layout.scss
  56. 3 134
      src/client/styles/scss/_layout_kibela.scss
  57. 1 1
      src/client/styles/scss/_override-bootstrap-variables.scss
  58. 8 5
      src/client/styles/scss/_override-bootstrap.scss
  59. 1 0
      src/client/styles/scss/_page.scss
  60. 3 2
      src/client/styles/scss/_search.scss
  61. 89 0
      src/client/styles/scss/_sidebar.scss
  62. 2 0
      src/client/styles/scss/_user.scss
  63. 5 1
      src/client/styles/scss/_variables.scss
  64. 1 0
      src/client/styles/scss/_vendor.scss
  65. 2 0
      src/client/styles/scss/atoms/_buttons.scss
  66. 1 0
      src/client/styles/scss/style-app.scss
  67. 1 9
      src/client/styles/scss/theme/_apply-colors-dark.scss
  68. 174 0
      src/client/styles/scss/theme/_apply-colors-kibela.scss
  69. 7 27
      src/client/styles/scss/theme/_apply-colors.scss
  70. 0 39
      src/client/styles/scss/theme/_layout_kibela_variable.scss
  71. 8 1
      src/client/styles/scss/theme/_reboot-bootstrap-theme-colors.scss
  72. 14 0
      src/client/styles/scss/theme/antarctic.scss
  73. 14 0
      src/client/styles/scss/theme/default.scss
  74. 103 7
      src/client/styles/scss/theme/kibela.scss
  75. 1 1
      src/server/routes/apiv3/customize-setting.js
  76. 6 48
      src/server/views/layout-kibela/widget/header.html
  77. 7 6
      src/server/views/layout/layout.html
  78. 1 1
      src/server/views/modal/create_page.html
  79. 74 71
      src/server/views/modal/shortcuts.html

+ 5 - 0
.github/workflows/build-rc.yml

@@ -52,3 +52,8 @@ jobs:
         target: weseek/growi
         semver: ${{ env.SEMVER }}
         publish: true
+
+    - name: Check whether workspace is clean
+      run: |
+        STATUS=`git status --porcelain`
+        if [ -z "$STATUS" ]; then exit 0; else exit 1; fi

+ 5 - 0
.github/workflows/build.yml

@@ -66,6 +66,11 @@ jobs:
         additional-tags: 'latest'
         publish: true
 
+    - name: Check whether workspace is clean
+      run: |
+        STATUS=`git status --porcelain`
+        if [ -z "$STATUS" ]; then exit 0; else exit 1; fi
+
   publish-desc:
 
     runs-on: ubuntu-latest

+ 8 - 4
.github/workflows/ci.yml

@@ -53,12 +53,13 @@ jobs:
         yarn lint
 
     - name: Slack Notification
-      uses: homoluctus/slatify@master
+      uses: weseek/ghaction-slack-notification@master
       if: failure()
       with:
         type: ${{ job.status }}
         job_name: '*test (${{ matrix.node-version }})*'
         channel: '#ci'
+        isCompactMode: true
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
 
 
@@ -113,12 +114,13 @@ jobs:
         MONGO_URI: mongodb://localhost:27017/growi_test
 
     - name: Slack Notification
-      uses: homoluctus/slatify@master
+      uses: weseek/ghaction-slack-notification@master
       if: failure()
       with:
         type: ${{ job.status }}
         job_name: '*test (${{ matrix.node-version }})*'
         channel: '#ci'
+        isCompactMode: true
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
 
 
@@ -183,12 +185,13 @@ jobs:
         yarn build:dev
 
     - name: Slack Notification
-      uses: homoluctus/slatify@master
+      uses: weseek/ghaction-slack-notification@master
       if: failure()
       with:
         type: ${{ job.status }}
         job_name: '*build-dev (${{ matrix.node-version }})*'
         channel: '#ci'
+        isCompactMode: true
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
 
 
@@ -268,10 +271,11 @@ jobs:
         path: report
 
     - name: Slack Notification
-      uses: homoluctus/slatify@master
+      uses: weseek/ghaction-slack-notification@master
       if: failure()
       with:
         type: ${{ job.status }}
         job_name: '*build-prod (${{ matrix.node-version }})*'
         channel: '#ci'
+        isCompactMode: true
         url: ${{ secrets.SLACK_WEBHOOK_URL }}

+ 1 - 1
config/webpack.common.js

@@ -38,7 +38,7 @@ module.exports = (options) => {
       // 'styles/theme-mono-blue':       './src/client/styles/scss/theme/mono-blue.scss',
       // 'styles/theme-future':          './src/client/styles/scss/theme/future.scss',
       // 'styles/theme-blue-night':      './src/client/styles/scss/theme/blue-night.scss',
-      // 'styles/theme-kibela':          './src/client/styles/scss/theme/kibela.scss',
+      'styles/theme-kibela':          './src/client/styles/scss/theme/kibela.scss',
       // 'styles/theme-halloween':       './src/client/styles/scss/theme/halloween.scss',
       // 'styles/theme-wood':          './src/client/styles/scss/theme/wood.scss',
       // 'styles/theme-christmas':          './src/client/styles/scss/theme/christmas.scss',

+ 7 - 2
resource/locales/en-US/admin/admin.json

@@ -105,7 +105,7 @@
     },
     "behavior": "Behavior",
     "behavior_desc": {
-      "growi_text1": "Both of <code>/page</code> and <code>/page/</code> shows the same page",
+      "growi_text1": "Both of <code>/page</code> and <code>/page/</code> shows the same page.",
       "growi_text2": "<code>/nonexistent_page</code> shows editing form",
       "growi_text3": "All pages shows the list of sub pages <b>if using GROWI Enhanced Layout</b>",
       "crowi_text1": "<code>/page</code> shows the page",
@@ -151,7 +151,12 @@
     "import_from": "Import from {{from}}",
     "import_growi_archive": "Import GROWI Archive",
     "growi_settings": {
-      "overwrite_documents": "Imported documents will overwrite existing documents",
+      "description_of_import_mode": {
+        "about": "When you import data with the same name as an existing one, choose from the following three modes below.",
+        "insert": "Insert: Skip importing the data.",
+        "upsert": "Upsert: Overwrite and update the existing data with imported data.",
+        "flash_and_insert": "Flash and Insert: After deleting the existing data completely, import the data"
+      },
       "growi_archive_file": "GROWI Archive File",
       "uploaded_data": "Uploaded Data",
       "extracted_file": "Extracted File",

+ 1 - 1
resource/locales/en-US/translation.json

@@ -294,7 +294,7 @@
   "modal_shortcuts": {
     "global": {
       "title": "Global shortcuts",
-      "Open/Close shortcut help": "Open/Close shortcut help",
+      "Open/Close shortcut help": "Open/Close<br>shortcut help",
       "Edit Page": "Edit Page",
       "Create Page": "Create Page",
       "Show Contributors": "Show Contributors",

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

@@ -169,7 +169,12 @@
     "import_from": "{{from}} からインポート",
     "import_growi_archive": "GROWI アーカイブをインポート",
     "growi_settings": {
-      "overwrite_documents": "インポートされたドキュメントは既存のドキュメントを上書きします",
+      "description_of_import_mode": {
+        "about": "既存のデータと同名であるデータをインポートする際の挙動は以下の3つのモードから選べます。",
+        "insert": "Insert: 当該データのインポートをスキップします。",
+        "upsert": "Upsert: 既存のデータをインポートデータで上書き更新します。",
+        "flash_and_insert": "Flash and Insert: 既存のデータを完全に削除した後、インポートを行います。"
+      },
       "growi_archive_file": "GROWI アーカイブファイル",
       "uploaded_data": "アップロードされたデータ",
       "extracted_file": "展開されたファイル",

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

@@ -292,10 +292,10 @@
   "modal_shortcuts": {
     "global": {
       "title": "グローバルショートカット",
-      "Open/Close shortcut help": "ショートカットヘルプの表示/非表示",
+      "Open/Close shortcut help": "ショートカットヘルプ<br>の表示/非表示",
       "Edit Page": "ページ編集",
       "Create Page": "ページ作成",
-      "Show Contributors": "コントリビューターを表示",
+      "Show Contributors": "コントリビューター<br>を表示",
       "Konami Code": "コナミコマンド",
       "konami_code_url": "https://ja.wikipedia.org/wiki/コナミコマンド"
     },

+ 1 - 1
src/client/js/bootstrap.jsx

@@ -44,7 +44,7 @@ const componentMappings = {
   'search-sidebar': <HeaderSearchBox crowi={appContainer} />,
   'personal-dropdown': <PersonalDropdown />,
 
-  'grw-sidebar': <Sidebar />,
+  'grw-sidebar-wrapper': <Sidebar />,
 
   'staff-credit': <StaffCredit />,
 };

+ 15 - 15
src/client/js/components/Admin/App/AwsSetting.jsx

@@ -50,11 +50,11 @@ class AwsSetting extends React.Component {
           </span>
         </p>
 
-        <div className="row form-group mb-5">
-          <label className="col-3 col-form-label">
+        <div className="row form-group">
+          <label className="text-left text-md-right col-md-3 col-form-label">
             {t('admin:app_setting.region')}
           </label>
-          <div className="col-6">
+          <div className="col-md-6">
             <input
               className="form-control"
               placeholder={`${t('eg')} ap-northeast-1`}
@@ -66,11 +66,11 @@ class AwsSetting extends React.Component {
           </div>
         </div>
 
-        <div className="row form-group mb-5">
-          <label className="col-3 col-form-label">
+        <div className="row form-group">
+          <label className="text-left text-md-right col-md-3 col-form-label">
             {t('admin:app_setting.custom_endpoint')}
           </label>
-          <div className="col-6">
+          <div className="col-md-6">
             <input
               className="form-control"
               type="text"
@@ -84,11 +84,11 @@ class AwsSetting extends React.Component {
           </div>
         </div>
 
-        <div className="row form-group mb-5">
-          <label className="col-3 col-form-label">
+        <div className="row form-group">
+          <label className="text-left text-md-right col-md-3 col-form-label">
             {t('admin:app_setting.bucket_name')}
           </label>
-          <div className="col-6">
+          <div className="col-md-6">
             <input
               className="form-control"
               type="text"
@@ -101,11 +101,11 @@ class AwsSetting extends React.Component {
           </div>
         </div>
 
-        <div className="row form-group mb-5">
-          <label className="col-3 col-form-label">
+        <div className="row form-group">
+          <label className="text-left text-md-right col-md-3 col-form-label">
             Access Key ID
           </label>
-          <div className="col-6">
+          <div className="col-md-6">
             <input
               className="form-control"
               type="text"
@@ -117,11 +117,11 @@ class AwsSetting extends React.Component {
           </div>
         </div>
 
-        <div className="row form-group mb-5">
-          <label className="col-3 col-form-label">
+        <div className="row form-group">
+          <label className="text-left text-md-right col-md-3 col-form-label">
             Secret Access Key
           </label>
-          <div className="col-6">
+          <div className="col-md-6">
             <input
               className="form-control"
               type="text"

+ 7 - 7
src/client/js/components/Admin/App/MailSetting.jsx

@@ -40,8 +40,8 @@ class MailSetting extends React.Component {
       <React.Fragment>
         <p className="card well">{t('admin:app_setting.smtp_used')} {t('admin:app_setting.smtp_but_aws')}<br />{t('admin:app_setting.neihter_of')}</p>
         <div className="row form-group mb-5">
-          <label className="col-3 col-form-label">{t('admin:app_setting.from_e-mail_address')}</label>
-          <div className="col-6">
+          <label className="col-md-3 col-form-label text-left">{t('admin:app_setting.from_e-mail_address')}</label>
+          <div className="col-md-6">
             <input
               className="form-control"
               type="text"
@@ -53,8 +53,8 @@ class MailSetting extends React.Component {
         </div>
 
         <div className="row form-group mb-5">
-          <label className="col-3 col-form-label">{t('admin:app_setting.smtp_settings')}</label>
-          <div className="col-4">
+          <label className="col-md-3 col-form-label text-left">{t('admin:app_setting.smtp_settings')}</label>
+          <div className="col-md-4">
             <label>{t('admin:app_setting.host')}</label>
             <input
               className="form-control"
@@ -63,7 +63,7 @@ class MailSetting extends React.Component {
               onChange={(e) => { adminAppContainer.changeSmtpHost(e.target.value) }}
             />
           </div>
-          <div className="col-2">
+          <div className="col-md-2">
             <label>{t('admin:app_setting.port')}</label>
             <input
               className="form-control"
@@ -74,7 +74,7 @@ class MailSetting extends React.Component {
         </div>
 
         <div className="row form-group mb-5">
-          <div className="col-3 offset-3">
+          <div className="col-md-3 offset-md-3">
             <label>{t('admin:app_setting.user')}</label>
             <input
               className="form-control"
@@ -83,7 +83,7 @@ class MailSetting extends React.Component {
               onChange={(e) => { adminAppContainer.changeSmtpUser(e.target.value) }}
             />
           </div>
-          <div className="col-3">
+          <div className="col-md-3">
             <label>{t('Password')}</label>
             <input
               className="form-control"

+ 1 - 1
src/client/js/components/Admin/App/SiteUrlSetting.jsx

@@ -43,7 +43,7 @@ class SiteUrlSetting extends React.Component {
           && (<p className="alert alert-danger"><i className="icon-exclamation"></i> {t('admin:app_setting.site_url_warn')}</p>)}
 
         <div className="row form-group">
-          <div className="col-9 offset-3">
+          <div className="col-md-9 offset-md-3">
             <table className="table settings-table">
               <colgroup>
                 <col className="from-db" />

+ 1 - 1
src/client/js/components/Admin/Common/AdminUpdateButtonRow.jsx

@@ -7,7 +7,7 @@ const AdminUpdateButtonRow = (props) => {
 
   return (
     <div className="row my-3">
-      <div className="offset-4 col-5">
+      <div className="mx-auto">
         <button type="button" className="btn btn-primary" onClick={props.onClick} disabled={props.disabled}>{ t('Update') }</button>
       </div>
     </div>

+ 3 - 1
src/client/js/components/Admin/Customize/CustomizeHeaderSetting.jsx

@@ -53,7 +53,9 @@ class CustomizeHeaderSetting extends React.Component {
               { t('Example') }:
               <pre className="hljs">
                 {/* eslint-disable-next-line react/no-unescaped-entities */}
-                <code>&lt;script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.13.0/build/languages/yaml.min.js" defer&gt;&lt;/script&gt;</code>
+                <code className="text-wrap">&lt;script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.13.0/build/languages/yaml.min.js"
+                defer&gt;&lt;/script&gt;
+                </code>
               </pre>
             </div>
 

+ 1 - 1
src/client/js/components/Admin/Customize/CustomizeThemeOptions.jsx

@@ -42,7 +42,7 @@ class CustomizeThemeOptions extends React.Component {
     return (
       <div id="themeOptions" className={`${currentLayout === 'kibela' && 'disabled'}`}>
         {/* Light Themes  */}
-        <div className="d-flex">
+        <div className="d-flex flex-wrap">
           {lightTheme.map((theme) => {
             return (
               <ThemeColorBox

+ 3 - 3
src/client/js/components/Admin/ElasticsearchManagement/ElasticsearchManagement.jsx

@@ -162,7 +162,7 @@ class ElasticsearchManagement extends React.Component {
 
         {/* Controls */}
         <div className="row">
-          <label className="col-md-3 col-form-label">{ t('full_text_search_management.reconnect') }</label>
+          <label className="col-md-3 col-form-label text-left text-md-right">{ t('full_text_search_management.reconnect') }</label>
           <div className="col-md-6">
             <ReconnectControls
               isConfigured={isConfigured}
@@ -175,7 +175,7 @@ class ElasticsearchManagement extends React.Component {
         <hr />
 
         <div className="row">
-          <label className="col-md-3 col-form-label">{ t('full_text_search_management.normalize') }</label>
+          <label className="col-md-3 col-form-label text-left text-md-right">{ t('full_text_search_management.normalize') }</label>
           <div className="col-md-6">
             <NormalizeIndicesControls
               isRebuildingProcessing={isRebuildingProcessing}
@@ -189,7 +189,7 @@ class ElasticsearchManagement extends React.Component {
         <hr />
 
         <div className="row">
-          <label className="col-md-3 col-form-label">{ t('full_text_search_management.rebuild') }</label>
+          <label className="col-md-3 col-form-label text-left text-md-right">{ t('full_text_search_management.rebuild') }</label>
           <div className="col-md-6">
             <RebuildIndexControls
               isRebuildingProcessing={isRebuildingProcessing}

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

@@ -20,10 +20,11 @@ class StatusTable extends React.PureComponent {
     return (
       <div className="card">
         <div className="card-header">
-          <a role="button" data-toggle="collapse" href={`#${collapseId}`} aria-expanded="true" aria-controls={collapseId}>
+
+          <a role="button" className="text-nowrap mr-2" data-toggle="collapse" href={`#${collapseId}`} aria-expanded="true" aria-controls={collapseId}>
             <i className="fa fa-fw fa-database"></i> {indexName}
           </a>
-          <span className="ml-3">{aliasLabels}</span>
+          <span className="ml-md-3">{aliasLabels}</span>
         </div>
         <div id={collapseId} className="collapse">
           <div className="card-body">
@@ -82,7 +83,7 @@ class StatusTable extends React.PureComponent {
       <div className="row">
         { Object.keys(indexNameToDataMap).map((indexName) => {
           return (
-            <div key={`col-${indexName}`} className="col-6">
+            <div key={`col-${indexName}`} className="col-md-6">
               { this.renderIndexInfoPanel(indexName, indexNameToDataMap[indexName], indexNameToAliasMap[indexName]) }
             </div>
           );

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

@@ -175,7 +175,7 @@ class SelectCollectionsModal extends React.Component {
 
     return (
       <Modal isOpen={this.props.isOpen} toggle={this.props.onClose}>
-        <ModalHeader tag="h4" toggle={this.props.onClose}>
+        <ModalHeader tag="h4" toggle={this.props.onClose} className="bg-info text-light">
           {t('admin:export_management.export_collections')}
         </ModalHeader>
 

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

@@ -21,7 +21,7 @@ class ErrorViewer extends React.Component {
 
     return (
       <Modal isOpen={this.props.isOpen} toggle={this.props.onClose}>
-        <ModalHeader tag="h4" toggle={this.props.onClose} className="bg-danger text-white">
+        <ModalHeader tag="h4" toggle={this.props.onClose} className="bg-danger text-light">
           Errors
         </ModalHeader>
         <ModalBody>

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

@@ -204,7 +204,7 @@ class ImportCollectionConfigurationModal extends React.Component {
 
     return (
       <Modal isOpen={this.props.isOpen} toggle={this.props.onClose} onEnter={this.initialize}>
-        <ModalHeader tag="h4" toggle={this.props.onClose}>
+        <ModalHeader tag="h4" toggle={this.props.onClose} className="bg-info text-light">
           {`'${collectionName}'`} Configuration
         </ModalHeader>
 

+ 17 - 15
src/client/js/components/Admin/ImportData/GrowiArchive/ImportForm.jsx

@@ -333,7 +333,7 @@ class ImportForm extends React.Component {
     );
   }
 
-  renderGroups(groupList, groupName, errors, { wellContent } = {}) {
+  renderGroups(groupList, groupName, errors) {
     const collectionNames = groupList.filter((collectionName) => {
       return this.allCollectionNames.includes(collectionName);
     });
@@ -343,19 +343,10 @@ class ImportForm extends React.Component {
     }
 
     return (
-      <div className="mt-4 row">
-        <div className="col-12">
-          <h3 className="admin-setting-header">{groupName} Collections</h3>
-          { wellContent != null && (
-            <div className="card well small" role="alert">
-              <ul>
-                <li>{wellContent}</li>
-              </ul>
-            </div>
-          )}
-          {this.renderImportItems(collectionNames)}
-          {this.renderWarnForGroups(errors, `warnFor${groupName}`)}
-        </div>
+      <div className="mt-4">
+        <legend>{groupName} Collections</legend>
+        {this.renderImportItems(collectionNames)}
+        {this.renderWarnForGroups(errors, `warnFor${groupName}`)}
       </div>
     );
   }
@@ -466,7 +457,18 @@ class ImportForm extends React.Component {
           </div>
         </form>
 
-        {this.renderGroups(GROUPS_PAGE, 'Page', warnForPageGroups, { wellContent: t('admin:importer_management.growi_settings.overwrite_documents') })}
+        <div className="card well small my-4">
+          <ul>
+            <li>{t('admin:importer_management.growi_settings.description_of_import_mode.about')}</li>
+            <ul>
+              <li>{t('admin:importer_management.growi_settings.description_of_import_mode.insert')}</li>
+              <li>{t('admin:importer_management.growi_settings.description_of_import_mode.upsert')}</li>
+              <li>{t('admin:importer_management.growi_settings.description_of_import_mode.flash_and_insert')}</li>
+            </ul>
+          </ul>
+        </div>
+
+        {this.renderGroups(GROUPS_PAGE, 'Page', warnForPageGroups)}
         {this.renderGroups(GROUPS_USER, 'User', warnForUserGroups)}
         {this.renderGroups(GROUPS_CONFIG, 'Config', warnForConfigGroups)}
         {this.renderOthers()}

+ 3 - 3
src/client/js/components/Admin/ImportData/GrowiArchive/UploadForm.jsx

@@ -51,8 +51,8 @@ class UploadForm extends React.Component {
       <form onSubmit={this.uploadZipFile}>
         <fieldset>
           <div className="form-group row">
-            <label htmlFor="file" className="col-3 control-label">{t('admin:importer_management.growi_settings.growi_archive_file')}</label>
-            <div className="col-6">
+            <label htmlFor="file" className="col-md-3 control-label">{t('admin:importer_management.growi_settings.growi_archive_file')}</label>
+            <div className="col-md-6">
               <input
                 type="file"
                 name="file"
@@ -64,7 +64,7 @@ class UploadForm extends React.Component {
             </div>
           </div>
           <div className="form-group row">
-            <div className="offset-3 col-6">
+            <div className="mx-auto">
               <button type="submit" className="btn btn-primary" disabled={!this.validateForm()}>
                 {t('admin:importer_management.growi_settings.upload')}
               </button>

+ 16 - 16
src/client/js/components/Admin/ImportDataPage.jsx

@@ -182,26 +182,26 @@ class ImportDataPage extends React.Component {
             </div>
 
             <div className="form-group row">
-              <label htmlFor="settingForm[importer:esa:team_name]" className="col-3 col-form-label">
+              <label htmlFor="settingForm[importer:esa:team_name]" className="text-left text-md-right col-md-3 col-form-label">
                 { t('admin:importer_management.esa_settings.team_name') }
               </label>
-              <div className="col-6">
+              <div className="col-md-6">
                 <input className="form-control" type="text" name="esaTeamName" value={esaTeamName} onChange={this.handleInputValue} />
               </div>
 
             </div>
 
             <div className="form-group row">
-              <label htmlFor="settingForm[importer:esa:access_token]" className="col-3 col-form-label">
+              <label htmlFor="settingForm[importer:esa:access_token]" className="text-left text-md-right col-md-3 col-form-label">
                 { t('admin:importer_management.esa_settings.access_token') }
               </label>
-              <div className="col-6">
+              <div className="col-md-6">
                 <input className="form-control" type="password" name="esaAccessToken" value={esaAccessToken} onChange={this.handleInputValue} />
               </div>
             </div>
 
             <div className="form-group row">
-              <div className="offset-3 col-6">
+              <div className="offset-md-3 col-md-6">
                 <input
                   id="testConnectionToEsa"
                   type="button"
@@ -211,12 +211,12 @@ class ImportDataPage extends React.Component {
                   value={t('admin:importer_management.import')}
                 />
                 <input type="button" className="btn btn-secondary" onClick={this.esaHandleSubmitUpdate} value={t('Update')} />
-                <span className="offset-1">
+                <span className="offset-0 offset-sm-1">
                   <input
-                    name="Esa"
-                    type="button"
                     id="importFromEsa"
-                    className="btn btn-outline-secondary btn-esa"
+                    type="button"
+                    name="Esa"
+                    className="btn btn-secondary btn-esa"
                     onClick={this.esaHandleSubmitTest}
                     value={t('admin:importer_management.esa_settings.test_connection')}
                   />
@@ -275,26 +275,26 @@ class ImportDataPage extends React.Component {
               <input type="password" name="dummypass" style={{ display: 'none', top: '-100px', left: '-100px' }} />
             </div>
             <div className="form-group row">
-              <label htmlFor="settingForm[importer:qiita:team_name]" className="col-3 col-form-label">
+              <label htmlFor="settingForm[importer:qiita:team_name]" className="text-left text-md-right col-md-3 col-form-label">
                 { t('admin:importer_management.qiita_settings.team_name') }
               </label>
-              <div className="col-6">
+              <div className="col-md-6">
                 <input className="form-control" type="text" name="qiitaTeamName" value={qiitaTeamName} onChange={this.handleInputValue} />
               </div>
             </div>
 
             <div className="form-group row">
-              <label htmlFor="settingForm[importer:qiita:access_token]" className="col-3 col-form-label">
+              <label htmlFor="settingForm[importer:qiita:access_token]" className="text-left text-md-right col-md-3 col-form-label">
                 { t('admin:importer_management.qiita_settings.access_token') }
               </label>
-              <div className="col-6">
+              <div className="col-md-6">
                 <input className="form-control" type="password" name="qiitaAccessToken" value={qiitaAccessToken} onChange={this.handleInputValue} />
               </div>
             </div>
 
 
             <div className="form-group row">
-              <div className="offset-3 col-6">
+              <div className="offset-md-3 col-md-6">
                 <input
                   id="testConnectionToQiita"
                   type="button"
@@ -304,12 +304,12 @@ class ImportDataPage extends React.Component {
                   value={t('admin:importer_management.import')}
                 />
                 <input type="button" className="btn btn-secondary" onClick={this.qiitaHandleSubmitUpdate} value={t('Update')} />
-                <span className="offset-1">
+                <span className="offset-0 offset-sm-1">
                   <input
                     name="Qiita"
                     type="button"
                     id="importFromQiita"
-                    className="btn btn-outline-secondary btn-qiita"
+                    className="btn btn-secondary btn-qiita"
                     onClick={this.qiitaHandleSubmitTest}
                     value={t('admin:importer_management.qiita_settings.test_connection')}
                   />

+ 1 - 1
src/client/js/components/Admin/Notification/NotificationDeleteModal.jsx

@@ -12,7 +12,7 @@ class NotificationDeleteModal extends React.PureComponent {
     const { t, notificationForConfiguration } = this.props;
     return (
       <Modal isOpen={this.props.isOpen} toggle={this.props.onClose}>
-        <ModalHeader tag="h4" toggle={this.props.onClose} className="modal-header">
+        <ModalHeader tag="h4" toggle={this.props.onClose} className="bg-danger text-light">
           <i className="icon icon-fire"></i> Delete Global Notification Setting
         </ModalHeader>
         <ModalBody>

+ 5 - 5
src/client/js/components/Admin/Notification/SlackAppConfiguration.jsx

@@ -64,8 +64,8 @@ class SlackAppConfiguration extends React.Component {
             <h2 className="border-bottom mb-5">{t('notification_setting.slack_incoming_configuration')}</h2>
 
             <div className="row mb-3">
-              <label className="col-3 text-right">Webhook URL</label>
-              <div className="col-6">
+              <label className="col-md-3 text-left text-md-right">Webhook URL</label>
+              <div className="col-md-6">
                 <input
                   className="form-control"
                   type="text"
@@ -76,7 +76,7 @@ class SlackAppConfiguration extends React.Component {
             </div>
 
             <div className="row mb-3">
-              <div className="offset-3 col-6 text-left">
+              <div className="offset-md-3 col-md-6 text-left">
                 <div className="custom-control custom-checkbox custom-checkbox-success">
                   <input
                     type="checkbox"
@@ -116,8 +116,8 @@ class SlackAppConfiguration extends React.Component {
               </div>
 
               <div className="row mb-5">
-                <label className="col-3 text-right">OAuth Access Token</label>
-                <div className="col-6">
+                <label className="col-md-3 text-left text-md-right">OAuth Access Token</label>
+                <div className="col-md-6">
                   <input
                     className="form-control"
                     type="text"

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

@@ -6,7 +6,6 @@ import {
   Modal,
   ModalHeader,
   ModalBody,
-  ModalFooter,
 } from 'reactstrap';
 
 import { createSubscribedElement } from '../../UnstatedUtils';
@@ -48,7 +47,7 @@ class LdapAuthTestModal extends React.Component {
 
     return (
       <Modal isOpen={this.props.isOpen} toggle={this.props.onClose}>
-        <ModalHeader tag="h4" className="modal-header" toggle={this.props.onClose}>
+        <ModalHeader tag="h4" toggle={this.props.onClose} className="bg-info text-light">
           Test LDAP Account
         </ModalHeader>
         <ModalBody>
@@ -59,7 +58,6 @@ class LdapAuthTestModal extends React.Component {
             onChangePassword={this.onChangePassword}
           />
         </ModalBody>
-        <ModalFooter />
       </Modal>
     );
   }

+ 9 - 9
src/client/js/components/Admin/Security/SecuritySetting.jsx

@@ -58,10 +58,10 @@ class SecuritySetting extends React.Component {
         </div>
           )}
         <div className="row mb-5">
-          <div className="col-3 text-right py-2">
+          <div className="col-md-3 text-md-right text-nowrap py-2 mr-md-5">
             <strong>{t('security_setting.Guest Users Access')}</strong>
           </div>
-          <div className="col-6">
+          <div className="col-md-6 ml-md-5">
             <div className="dropdown">
               <button
                 className={`btn btn-outline-secondary dropdown-toggle ${adminGeneralSecurityContainer.isWikiModeForced && 'disabled'}`}
@@ -102,9 +102,9 @@ class SecuritySetting extends React.Component {
         </div>
           )}
         <div className="row mb-5">
-          <strong className="col-3 text-right" dangerouslySetInnerHTML={{ __html: t('security_setting.page_listing_1') }} />
-          <div className="col-6">
-            <div className="custom-control custom-checkbox custom-checkbox-success">
+          <strong className="col-md-3 text-md-right text-nowrap mb-2 mr-md-5" dangerouslySetInnerHTML={{ __html: t('security_setting.page_listing_1') }} />
+          <div className="col-md-6">
+            <div className="custom-control custom-checkbox custom-checkbox-success ml-md-5">
               <input
                 type="checkbox"
                 className="custom-control-input"
@@ -120,8 +120,8 @@ class SecuritySetting extends React.Component {
         </div>
 
         <div className="row mb-5">
-          <strong className="col-3 text-right" dangerouslySetInnerHTML={{ __html: t('security_setting.page_listing_2') }} />
-          <div className="col-6">
+          <strong className="col-md-3 text-md-right text-nowrap mr-md-5 mb-2" dangerouslySetInnerHTML={{ __html: t('security_setting.page_listing_2') }} />
+          <div className="col-md-6 ml-md-5">
             <div className="custom-control custom-checkbox custom-checkbox-success">
               <input
                 type="checkbox"
@@ -138,10 +138,10 @@ class SecuritySetting extends React.Component {
         </div>
 
         <div className="row mb-5">
-          <div className="col-3 text-right">
+          <div className="col-md-3 text-md-right mr-md-5 mb-2">
             <strong>{t('security_setting.complete_deletion')}</strong>
           </div>
-          <div className="col-9">
+          <div className="col-md-6 ml-md-5">
             <div className="dropdown">
               <button
                 className="btn btn-outline-secondary dropdown-toggle"

+ 1 - 1
src/client/js/components/Admin/UserGroup/UserGroupDeleteModal.jsx

@@ -164,7 +164,7 @@ class UserGroupDeleteModal extends React.Component {
 
     return (
       <Modal className="modal-md" isOpen={this.props.isShow} toggle={this.props.onHide}>
-        <ModalHeader tag="h4" toggle={this.props.onHide} className="modal-header bg-danger">
+        <ModalHeader tag="h4" toggle={this.props.onHide} className="bg-danger text-light">
           <i className="icon icon-fire"></i> {t('admin:user_group_management.delete_modal.header')}
         </ModalHeader>
         <ModalBody>

+ 1 - 1
src/client/js/components/Admin/UserGroupDetail/UserGroupUserModal.jsx

@@ -19,7 +19,7 @@ class UserGroupUserModal extends React.Component {
 
     return (
       <Modal isOpen={adminUserGroupDetailContainer.state.isUserGroupUserModalOpen} toggle={adminUserGroupDetailContainer.closeUserGroupUserModal}>
-        <ModalHeader tag="h4" toggle={adminUserGroupDetailContainer.closeUserGroupUserModal}>
+        <ModalHeader tag="h4" toggle={adminUserGroupDetailContainer.closeUserGroupUserModal} className="bg-info text-light">
           {t('admin:user_group_management.add_modal.add_user') }
         </ModalHeader>
         <ModalBody>

+ 5 - 5
src/client/js/components/Admin/UserManagement.jsx

@@ -131,7 +131,7 @@ class UserManagement extends React.Component {
         )}
         <p>
           <InviteUserControl />
-          <a className="btn text-dark btn-outline-secondary ml-2" href="/admin/users/external-accounts" role="button">
+          <a className="btn btn-outline-secondary ml-2" href="/admin/users/external-accounts" role="button">
             <i className="icon-user-follow" aria-hidden="true"></i>
             {t('admin:user_management.external_account')}
           </a>
@@ -194,7 +194,7 @@ class UserManagement extends React.Component {
                 </label>
               </div>
 
-              <div className="custom-control custom-checkbox custom-checkbox-secondary mr-2">
+              <div className="custom-control custom-checkbox custom-checkbox-warning mr-2">
                 <input
                   className="custom-control-input"
                   type="checkbox"
@@ -203,7 +203,7 @@ class UserManagement extends React.Component {
                   onClick={() => { this.handleClick('suspended') }}
                 />
                 <label className="custom-control-label" htmlFor="c4">
-                  <span className="badge badge-pill badge-secondary d-inline-block vt mt-1">Suspended</span>
+                  <span className="badge badge-pill badge-warning d-inline-block vt mt-1">Suspended</span>
                 </label>
               </div>
 
@@ -235,8 +235,8 @@ class UserManagement extends React.Component {
               </button>
             </div>
 
-            <div className="ml-5">
-              {this.state.isNotifyCommentShow && <span className="text-warning small">{t('admin:user_management.click_twice_same_checkbox')}</span>}
+            <div className="ml-4">
+              {this.state.isNotifyCommentShow && <span className="text-warning">{t('admin:user_management.click_twice_same_checkbox')}</span>}
             </div>
 
           </div>

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

@@ -83,7 +83,7 @@ class PasswordResetModal extends React.Component {
 
     return (
       <Modal isOpen={this.props.isOpen} toggle={this.props.onClose}>
-        <ModalHeader tag="h4" toggle={this.props.onClose} className="modal-header">
+        <ModalHeader tag="h4" toggle={this.props.onClose} className="bg-warning text-light">
           {t('admin:user_management.reset_password') }
         </ModalHeader>
         <ModalBody>

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

@@ -194,7 +194,7 @@ class UserInviteModal extends React.Component {
 
     return (
       <Modal isOpen={adminUsersContainer.state.isUserInviteModalShown}>
-        <ModalHeader tag="h4" toggle={this.onToggleModal} className="modal-header">
+        <ModalHeader tag="h4" toggle={this.onToggleModal} className="bg-info text-light">
           {t('admin:user_management.invite_users') }
         </ModalHeader>
         <ModalBody>

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

@@ -42,7 +42,7 @@ class UserTable extends React.Component {
         text = 'Active';
         break;
       case 3:
-        additionalClassName = 'badge-secondary';
+        additionalClassName = 'badge-warning';
         text = 'Suspended';
         break;
       case 4:

+ 4 - 4
src/client/js/components/Me/ApiSettings.jsx

@@ -43,8 +43,8 @@ class ApiSettings extends React.Component {
         </div>
 
         <div className="row mb-3">
-          <label htmlFor="apiToken" className="col-3 text-right">{t('Current API Token')}</label>
-          <div className="col-6">
+          <label htmlFor="apiToken" className="col-md-3 text-md-right">{t('Current API Token')}</label>
+          <div className="col-md-6">
             {personalContainer.state.apiToken != null
             ? (
               <input
@@ -65,7 +65,7 @@ class ApiSettings extends React.Component {
 
 
         <div className="row">
-          <div className="offset-3 col-6">
+          <div className="offset-lg-1 col-lg-7">
 
             <p className="alert alert-warning">
               { t('page_me_apitoken.notice.update_token1') }<br />
@@ -79,7 +79,7 @@ class ApiSettings extends React.Component {
           <div className="offset-4 col-5">
             <button
               type="button"
-              className="btn btn-primary"
+              className="btn btn-primary text-nowrap"
               onClick={this.onClickSubmit}
             >
               {t('Update API Token')}

+ 2 - 2
src/client/js/components/Me/AssociateModal.jsx

@@ -70,8 +70,8 @@ class AssociateModal extends React.Component {
     const { t } = this.props;
 
     return (
-      <Modal isOpen={this.props.isOpen} toggle={this.props.onClose} className="mw-100 m-4">
-        <ModalHeader className="bg-info" toggle={this.props.onClose}>
+      <Modal isOpen={this.props.isOpen} toggle={this.props.onClose} size="lg">
+        <ModalHeader className="bg-info text-light" toggle={this.props.onClose}>
           { t('Create External Account') }
         </ModalHeader>
         <ModalBody>

+ 12 - 12
src/client/js/components/Me/BasicInfoSettings.jsx

@@ -45,9 +45,9 @@ class BasicInfoSettings extends React.Component {
     return (
       <Fragment>
 
-        <div className="row form-group mb-3">
-          <label htmlFor="userForm[name]" className="col-sm-2 text-right">{t('Name')}</label>
-          <div className="col-sm-4 text-left">
+        <div className="form-group row">
+          <label htmlFor="userForm[name]" className="text-left text-md-right col-md-3 col-form-label">{t('Name')}</label>
+          <div className="col-md-6">
             <input
               className="form-control"
               type="text"
@@ -58,9 +58,9 @@ class BasicInfoSettings extends React.Component {
           </div>
         </div>
 
-        <div className="row form-group mb-3">
-          <label htmlFor="userForm[email]" className="col-sm-2 text-right">{t('Email')}</label>
-          <div className="col-sm-4 text-left">
+        <div className="form-group row">
+          <label htmlFor="userForm[email]" className="text-left text-md-right col-md-3 col-form-label">{t('Email')}</label>
+          <div className="col-md-6">
             <input
               className="form-control"
               type="text"
@@ -81,9 +81,9 @@ class BasicInfoSettings extends React.Component {
           )}
         </div>
 
-        <div className="row mb-3">
-          <label className="col-sm-2 text-right">{t('Disclose E-mail')}</label>
-          <div className="col-6">
+        <div className="form-group row">
+          <label className="text-left text-md-right col-md-3 col-form-label">{t('Disclose E-mail')}</label>
+          <div className="col-md-6">
             <div className="custom-control custom-radio custom-control-inline">
               <input
                 type="radio"
@@ -109,9 +109,9 @@ class BasicInfoSettings extends React.Component {
           </div>
         </div>
 
-        <div className="row mb-3">
-          <label className="col-sm-2 col-form-label text-right">{t('Language')}</label>
-          <div className="col-6">
+        <div className="form-group row">
+          <label className="text-left text-md-right col-md-3 col-form-label">{t('Language')}</label>
+          <div className="col-md-6">
             <div className="custom-control custom-radio custom-control-inline">
               <input
                 type="radio"

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

@@ -49,7 +49,7 @@ class DisassociateModal extends React.Component {
 
     return (
       <Modal isOpen={this.props.isOpen} toggle={this.props.onClose}>
-        <ModalHeader className="bg-info" toggle={this.props.onClose}>
+        <ModalHeader className="bg-info text-light" toggle={this.props.onClose}>
           {t('personal_settings.disassociate_external_account')}
         </ModalHeader>
         <ModalBody>

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

@@ -87,7 +87,7 @@ class ImageCropModal extends React.Component {
   render() {
     return (
       <Modal isOpen={this.props.show} toggle={this.props.onModalClose}>
-        <ModalHeader tag="h4" toggle={this.props.onModalClose}>
+        <ModalHeader tag="h4" toggle={this.props.onModalClose} className="bg-info text-light">
           Image Crop
         </ModalHeader>
         <ModalBody className="my-4">

+ 17 - 15
src/client/js/components/Me/PasswordSettings.jsx

@@ -76,8 +76,8 @@ class PasswordSettings extends React.Component {
         {(personalContainer.state.isPasswordSet)
         && (
           <div className="row mb-3">
-            <label htmlFor="oldPassword" className="col-3 text-right">{ t('personal_settings.current_password') }</label>
-            <div className="col-6">
+            <label htmlFor="oldPassword" className="col-md-3 text-md-right">{ t('personal_settings.current_password') }</label>
+            <div className="col-md-5">
               <input
                 className="form-control"
                 type="password"
@@ -89,8 +89,8 @@ class PasswordSettings extends React.Component {
           </div>
         )}
         <div className="row mb-3">
-          <label htmlFor="newPassword" className="col-3 text-right">{t('personal_settings.new_password') }</label>
-          <div className="col-6">
+          <label htmlFor="newPassword" className="col-md-3 text-md-right">{t('personal_settings.new_password') }</label>
+          <div className="col-md-5">
             <input
               className="form-control"
               type="password"
@@ -101,8 +101,8 @@ class PasswordSettings extends React.Component {
           </div>
         </div>
         <div className={`row mb-3 ${isIncorrectConfirmPassword && 'has-error'}`}>
-          <label htmlFor="newPasswordConfirm" className="col-3 text-right">{t('personal_settings.new_password_confirm') }</label>
-          <div className="col-6">
+          <label htmlFor="newPasswordConfirm" className="col-md-3 text-md-right">{t('personal_settings.new_password_confirm') }</label>
+          <div className="col-md-5">
             <input
               className="form-control"
               type="password"
@@ -115,15 +115,17 @@ class PasswordSettings extends React.Component {
           </div>
         </div>
 
-        <div className="my-3 text-center">
-          <button
-            type="button"
-            className="btn btn-primary"
-            onClick={this.onClickSubmit}
-            disabled={this.state.retrieveError != null || isIncorrectConfirmPassword}
-          >
-            {t('Update')}
-          </button>
+        <div className="row my-3">
+          <div className="offset-5">
+            <button
+              type="button"
+              className="btn btn-primary"
+              onClick={this.onClickSubmit}
+              disabled={this.state.retrieveError != null || isIncorrectConfirmPassword}
+            >
+              {t('Update')}
+            </button>
+          </div>
         </div>
       </React.Fragment>
     );

+ 6 - 6
src/client/js/components/Me/ProfileImageSettings.jsx

@@ -102,7 +102,7 @@ class ProfileImageSettings extends React.Component {
     return (
       <React.Fragment>
         <div className="row">
-          <div className="col-md-2 offset-1 col-sm-4">
+          <div className="col-md-3 offset-1 col-sm-4">
             <h4>
               <div className="custom-control custom-radio radio-primary">
                 <input
@@ -126,7 +126,7 @@ class ProfileImageSettings extends React.Component {
             <img src={this.generateGravatarSrc()} width="64" />
           </div>
 
-          <div className="col-md-4 col-sm-7">
+          <div className="col-md-3 offset-1 col-sm-4">
             <h4>
               <div className="custom-control custom-radio radio-primary">
                 <input
@@ -144,19 +144,19 @@ class ProfileImageSettings extends React.Component {
               </div>
             </h4>
             <div className="row mb-3">
-              <label className="col-sm-4 control-label">
+              <label className="col-sm-4 col-12 control-label">
                 { t('Current Image') }
               </label>
-              <div className="col-sm-8">
+              <div className="col-sm-8 col-12">
                 {uploadedPictureSrc && (<p><img src={uploadedPictureSrc} className="picture picture-lg rounded-circle" id="settingUserPicture" /></p>)}
                 {isUploadedPicture && <button type="button" className="btn btn-danger" onClick={this.onClickDeleteBtn}>{ t('Delete Image') }</button>}
               </div>
             </div>
             <div className="row">
-              <label className="col-sm-4 control-label">
+              <label className="col-sm-4 col-12 control-label">
                 {t('Upload new image')}
               </label>
-              <div className="col-sm-8">
+              <div className="col-sm-8 col-12">
                 <input type="file" onChange={this.onSelectFile} name="profileImage" accept="image/*" />
               </div>
             </div>

+ 9 - 5
src/client/js/components/Navbar/GrowiSubNavigation.jsx

@@ -44,11 +44,15 @@ const GrowiSubNavigation = (props) => {
   }
 
   const additionalClassNames = ['grw-subnavbar'];
-  if (isHeaderSticky) {
-    additionalClassNames.push('grw-subnavbar-sticky');
-  }
-  if (isSubnavCompact) {
-    additionalClassNames.push('grw-subnavbar-compact');
+  const layoutType = appContainer.getConfig().layoutType;
+
+  if (layoutType === 'growi') {
+    if (isHeaderSticky) {
+      additionalClassNames.push('grw-subnavbar-sticky');
+    }
+    if (isSubnavCompact) {
+      additionalClassNames.push('grw-subnavbar-compact');
+    }
   }
 
   return (

+ 12 - 8
src/client/js/components/Navbar/GrowiSubNavigationForUserPage.jsx

@@ -16,14 +16,18 @@ const GrowiSubNavigationForUserPage = (props) => {
   const { pageId, isHeaderSticky, isSubnavCompact } = pageContainer.state;
 
   const additionalClassNames = ['grw-subnavbar', 'grw-subnavbar-user-page'];
-  if (isHeaderSticky) {
-    additionalClassNames.push('grw-subnavbar-sticky');
-  }
-  if (isSubnavCompact) {
-    additionalClassNames.push('py-2 grw-subnavbar-compact');
-  }
-  else {
-    additionalClassNames.push('py-3');
+  const layoutType = appContainer.getConfig().layoutType;
+
+  if (layoutType === 'growi') {
+    if (isHeaderSticky) {
+      additionalClassNames.push('grw-subnavbar-sticky');
+    }
+    if (isSubnavCompact) {
+      additionalClassNames.push('py-2 grw-subnavbar-compact');
+    }
+    else {
+      additionalClassNames.push('py-3');
+    }
   }
 
   return (

+ 12 - 3
src/client/js/components/Navbar/NavbarToggler.jsx

@@ -8,13 +8,22 @@ import AppContainer from '../../services/AppContainer';
 
 const NavbarToggler = (props) => {
 
-  // eslint-disable-next-line no-unused-vars
   const { appContainer } = props;
 
+  const clickHandler = () => {
+    appContainer.toggleDrawer();
+  };
+
   return (
-    <button className="navbar-toggler grw-navbar-toggler border-0" type="button" aria-expanded="false" aria-label="Toggle navigation">
+    <a
+      className="nav-link grw-navbar-toggler border-0 waves-effect waves-light"
+      type="button"
+      aria-expanded="false"
+      aria-label="Toggle navigation"
+      onClick={clickHandler}
+    >
       <i className="icon-menu"></i>
-    </button>
+    </a>
   );
 
 };

+ 1 - 1
src/client/js/components/Page/TagEditor.jsx

@@ -47,7 +47,7 @@ export default class TagEditor extends React.Component {
   render() {
     return (
       <Modal isOpen={this.state.isOpenModal} toggle={this.closeModalHandler} id="edit-tag-modal">
-        <ModalHeader tag="h4" toggle={this.closeModalHandler} className="bg-primary">
+        <ModalHeader tag="h4" toggle={this.closeModalHandler} className="bg-primary text-light">
           <span className="text-white">Edit Tags</span>
         </ModalHeader>
         <ModalBody>

+ 1 - 1
src/client/js/components/PageAttachment/DeleteAttachmentModal.jsx

@@ -73,7 +73,7 @@ export default class DeleteAttachmentModal extends React.Component {
 
     return (
       <Modal {...props} className="attachment-delete-modal" bssize="large" aria-labelledby="contained-modal-title-lg">
-        <ModalHeader tag="h4" toggle={this.props.toggle}>
+        <ModalHeader tag="h4" toggle={this.props.toggle} className="bg-danger text-light">
           <span id="contained-modal-title-lg">Delete attachment?</span>
         </ModalHeader>
         <ModalBody>

+ 2 - 2
src/client/js/components/PageComment/DeleteCommentModal.jsx

@@ -37,9 +37,9 @@ export default class DeleteCommentModal extends React.Component {
 
     return (
       <Modal isOpen={this.props.isShown} toggle={this.props.cancel} className="page-comment-delete-modal">
-        <ModalHeader tag="h4" toggle={this.props.cancel}>
+        <ModalHeader tag="h4" toggle={this.props.cancel} className="bg-danger text-light">
           <span>
-            <i className="icon-fw icon-fire text-danger"></i>
+            <i className="icon-fw icon-fire"></i>
             Delete comment?
           </span>
         </ModalHeader>

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

@@ -260,7 +260,7 @@ export default class Editor extends AbstractEditor {
 
     return (
       <Modal isOpen={this.state.isCheatsheetModalShown} toggle={hideCheatsheetModal} className="modal-gfm-cheatsheet">
-        <ModalHeader tag="h4" toggle={hideCheatsheetModal} className="bg-primary">
+        <ModalHeader tag="h4" toggle={hideCheatsheetModal} className="bg-primary text-light">
           <span className="text-white"><i className="icon-fw icon-question" />Markdown Help</span>
         </ModalHeader>
         <ModalBody>

+ 14 - 6
src/client/js/components/PageEditor/HandsontableModal.jsx

@@ -2,7 +2,6 @@ import React from 'react';
 import PropTypes from 'prop-types';
 
 import {
-  Button,
   Collapse,
   Modal, ModalHeader, ModalBody, ModalFooter,
 } from 'reactstrap';
@@ -434,10 +433,19 @@ export default class HandsontableModal extends React.PureComponent {
 
     return (
       <Modal isOpen={this.state.show} toggle={this.cancel} size="lg" className={dialogClassName}>
-        <ModalHeader tag="h4" toggle={this.cancel} close={buttons}>Edit Table</ModalHeader>
+        <ModalHeader tag="h4" toggle={this.cancel} close={buttons} className="bg-primary text-light">
+          Edit Table
+        </ModalHeader>
         <ModalBody className="p-0 d-flex flex-column">
           <div className="px-4 py-3 modal-navbar bg-light">
-            <button type="button" className="mr-4 data-import-button btn btn-secondary" onClick={this.toggleDataImportArea}>
+            <button
+              type="button"
+              className="mr-4 data-import-button btn btn-secondary"
+              data-toggle="collapse"
+              data-target="#collapseDataImport"
+              aria-expanded={this.state.isDataImportAreaExpanded}
+              onClick={this.toggleDataImportArea}
+            >
               <span className="mr-3">Data Import</span><i className={this.state.isDataImportAreaExpanded ? 'fa fa-angle-up' : 'fa fa-angle-down'}></i>
             </button>
             <div role="group" className="btn-group">
@@ -467,10 +475,10 @@ export default class HandsontableModal extends React.PureComponent {
           </div>
         </ModalBody>
         <ModalFooter className="grw-modal-footer">
-          <Button color="danger" onClick={this.reset}>Reset</Button>
+          <button type="button" className="btn btn-danger" onClick={this.reset}>Reset</button>
           <div className="ml-auto">
-            <Button className="mr-2" color="secondary" onClick={this.cancel}>Cancel</Button>
-            <Button color="primary" onClick={this.save}>Done</Button>
+            <button type="button" className="mr-2 btn btn-secondary" onClick={this.cancel}>Cancel</button>
+            <button type="button" className="btn btn-primary" onClick={this.save}>Done</button>
           </div>
         </ModalFooter>
       </Modal>

+ 1 - 1
src/client/js/components/PageHistory/RevisionDiff.jsx

@@ -39,7 +39,7 @@ export default class RevisionDiff extends React.Component {
 
     const diffView = { __html: diffViewHTML };
     // eslint-disable-next-line react/no-danger
-    return <div className="revision-history-diff" dangerouslySetInnerHTML={diffView} />;
+    return <div className="revision-history-diff d-table w-100" dangerouslySetInnerHTML={diffView} />;
   }
 
 }

+ 1 - 1
src/client/js/components/SavePageControls/GrantSelector.jsx

@@ -217,7 +217,7 @@ class GrantSelector extends React.Component {
         isOpen={this.state.isSelectGroupModalShown}
         toggle={this.hideSelectGroupModal}
       >
-        <ModalHeader tag="h4" toggle={this.hideSelectGroupModal}>
+        <ModalHeader tag="h4" toggle={this.hideSelectGroupModal} className="bg-info text-light">
           Select a Group
         </ModalHeader>
         <ModalBody>

+ 1 - 1
src/client/js/components/SearchPage/DeletePageListModal.jsx

@@ -29,7 +29,7 @@ export default class DeletePageListModal extends React.Component {
 
     return (
       <Modal isOpen={this.props.isShown} toggle={this.props.cancel} className="page-list-delete-modal">
-        <ModalHeader tag="h4" toggle={this.props.cancel}>
+        <ModalHeader tag="h4" toggle={this.props.cancel} className="bg-danger text-light">
           Deleting pages:
         </ModalHeader>
         <ModalBody>

+ 1 - 1
src/client/js/components/SearchPage/SearchPageForm.jsx

@@ -42,7 +42,7 @@ class SearchPageForm extends React.Component {
           />
         </div>
         <div className="input-group-append">
-          <button className="btn btn-outline-secondary" type="button" id="button-addon2" onClick={this.search}>
+          <button className="btn btn-secondary" type="button" id="button-addon2" onClick={this.search}>
             <i className="icon-magnifier"></i>
           </button>
         </div>

+ 88 - 38
src/client/js/components/Sidebar.jsx

@@ -10,8 +10,6 @@ import {
   ThemeProvider, modeGenerator,
 } from '@atlaskit/navigation-next';
 
-import Drawer from '@atlaskit/drawer';
-
 import { createSubscribedElement } from './UnstatedUtils';
 import AppContainer from '../services/AppContainer';
 
@@ -19,20 +17,71 @@ import SidebarNav from './Sidebar/SidebarNav';
 import History from './Sidebar/History';
 import CustomSidebar from './Sidebar/CustomSidebar';
 
+
+const sidebarDefaultWidth = 240;
+
 class Sidebar extends React.Component {
 
   static propTypes = {
+    appContainer: PropTypes.instanceOf(AppContainer).isRequired,
     navigationUIController: PropTypes.any.isRequired,
   };
 
   state = {
     currentContentsId: 'custom',
-    isDrawerOpen: false,
   };
 
-  openDrawer = () => this.setState({ isDrawerOpen: true });
+  componentWillMount() {
+    this.initBreakpointEvents();
+  }
 
-  closeDrawer = () => this.setState({ isDrawerOpen: false });
+  initBreakpointEvents() {
+    const { appContainer, navigationUIController } = this.props;
+
+    document.addEventListener('DOMContentLoaded', () => {
+      // get the value of '--breakpoint-*'
+      // const breakpointSm = parseInt(window.getComputedStyle(document.documentElement).getPropertyValue('--breakpoint-sm'), 10);
+      const breakpointMd = parseInt(window.getComputedStyle(document.documentElement).getPropertyValue('--breakpoint-md'), 10);
+
+      const smHandler = (mql) => {
+        if (mql.matches) {
+          // cache width
+          this.sidebarWidthCached = navigationUIController.state.productNavWidth;
+
+          appContainer.setState({ isDrawerOpened: false });
+          navigationUIController.disableResize();
+          navigationUIController.expand();
+
+          // fix width
+          navigationUIController.setState({ productNavWidth: sidebarDefaultWidth });
+        }
+        else {
+          appContainer.setState({ isDrawerOpened: false });
+          navigationUIController.enableResize();
+
+          // restore width
+          if (this.sidebarWidthCached != null) {
+            navigationUIController.setState({ productNavWidth: this.sidebarWidthCached });
+          }
+        }
+      };
+
+      // const mediaQueryForXs = window.matchMedia(`(max-width: ${breakpointSm}px)`);
+      const mediaQueryForSm = window.matchMedia(`(max-width: ${breakpointMd}px)`);
+
+      // add event listener
+      // mediaQueryForXs.addListener(xsHandler);
+      mediaQueryForSm.addListener(smHandler);
+      // initialize
+      // xsHandler(mediaQueryForXs);
+      smHandler(mediaQueryForSm);
+    });
+  }
+
+  backdropClickedHandler = () => {
+    const { appContainer } = this.props;
+    appContainer.setState({ isDrawerOpened: false });
+  }
 
   itemSelectedHandler = (contentsId) => {
     const { navigationUIController } = this.props;
@@ -47,19 +96,10 @@ class Sidebar extends React.Component {
       this.setState({ currentContentsId: contentsId });
       navigationUIController.expand();
     }
-
-    // if (contentsId === 'drawer') {
-    //   this.openDrawer();
-    // }
   }
 
   renderGlobalNavigation = () => (
-    <>
-      <SidebarNav currentContentsId={this.state.currentContentsId} onItemSelected={this.itemSelectedHandler} />
-      <Drawer onClose={this.closeDrawer} isOpen={this.state.isDrawerOpen} width="wide">
-        <code>Drawer contents</code>
-      </Drawer>
-    </>
+    <SidebarNav currentContentsId={this.state.currentContentsId} onItemSelected={this.itemSelectedHandler} />
   );
 
   renderSidebarContents = () => {
@@ -75,30 +115,40 @@ class Sidebar extends React.Component {
   }
 
   render() {
+    const { isDrawerOpened } = this.props.appContainer.state;
+
     return (
-      <ThemeProvider
-        theme={theme => ({
-          ...theme,
-          context: 'product',
-          mode: modeGenerator({
-            product: { text: '#ffffff', background: '#334455' },
-          }),
-        })}
-      >
-        <LayoutManager
-          globalNavigation={this.renderGlobalNavigation}
-          productNavigation={() => null}
-          containerNavigation={this.renderSidebarContents}
-          experimental_hideNavVisuallyOnCollapse
-          experimental_flyoutOnHover
-          experimental_alternateFlyoutBehaviour
-          // experimental_fullWidthFlyout
-          shouldHideGlobalNavShadow
-          showContextualNavigation
-          topOffset={50}
-        >
-        </LayoutManager>
-      </ThemeProvider>
+      <>
+        <div className={`grw-sidebar ${isDrawerOpened ? 'open' : ''}`}>
+          <ThemeProvider
+            theme={theme => ({
+              ...theme,
+              context: 'product',
+              mode: modeGenerator({
+                product: { text: '#ffffff', background: '#334455' },
+              }),
+            })}
+          >
+            <LayoutManager
+              globalNavigation={this.renderGlobalNavigation}
+              productNavigation={() => null}
+              containerNavigation={this.renderSidebarContents}
+              experimental_hideNavVisuallyOnCollapse
+              experimental_flyoutOnHover
+              experimental_alternateFlyoutBehaviour
+              // experimental_fullWidthFlyout
+              shouldHideGlobalNavShadow
+              showContextualNavigation
+              topOffset={50}
+            >
+            </LayoutManager>
+          </ThemeProvider>
+        </div>
+
+        { isDrawerOpened && (
+          <div className="grw-sidebar-backdrop modal-backdrop show" onClick={this.backdropClickedHandler}></div>
+        ) }
+      </>
     );
   }
 

+ 7 - 0
src/client/js/services/AppContainer.js

@@ -33,6 +33,7 @@ export default class AppContainer extends Container {
       editorMode: null,
       preferDarkModeByMediaQuery: false,
       preferDarkModeByUser: null,
+      isDrawerOpened: false,
     };
 
     const body = document.querySelector('body');
@@ -100,6 +101,7 @@ export default class AppContainer extends Container {
   }
 
   init() {
+    // this.initBreakpointEvents();
     this.initColorScheme();
     this.initPlugins();
   }
@@ -323,6 +325,11 @@ export default class AppContainer extends Container {
     return users;
   }
 
+  toggleDrawer() {
+    const { isDrawerOpened } = this.state;
+    this.setState({ isDrawerOpened: !isDrawerOpened });
+  }
+
   launchHandsontableModal(componentKind, beginLineNumber, endLineNumber) {
     let targetComponent;
     switch (componentKind) {

+ 0 - 56
src/client/styles/scss/_layout.scss

@@ -49,66 +49,10 @@
   font-weight: bold;
 }
 
-.grw-sidebar {
-  .ak-navigation-resize-button {
-    top: calc(50vh - 20px);
-  }
-
-  // override @atlaskit/navigation-next styles
-  div[class$='-NavigationContainer'] {
-    // Adjust to be on top of the growi subnavigation
-    z-index: $zindex-sticky + 5;
-  }
-
-  // override @atlaskit/navigation-next styles
-  div[class$='-Outer'] {
-    div[class$='-Shadow'] {
-      background: unset;
-      border-right: 1px solid $border;
-    }
-  }
-
-  .grw-global-item-container {
-    i {
-      font-size: 1.5em;
-    }
-
-    // icon opacity
-    &:not(.active) {
-      i {
-        opacity: 0.4;
-      }
-      &:hover,
-      &:focus {
-        i {
-          opacity: 0.7;
-        }
-      }
-    }
-
-    &.active {
-      button {
-        @extend %fukidashi-for-active;
-      }
-    }
-  }
-}
-
 #page-wrapper {
   margin-top: $grw-navbar-height;
 }
 
-.grw-sidebar-header-container {
-  padding: 10px;
-
-  h3 {
-    margin-bottom: 0;
-  }
-}
-
-.grw-sidebar-content-container {
-}
-
 .grw-modal-head {
   font-size: 1em;
   border-bottom: 1px solid $grw-line-gray;

+ 3 - 134
src/client/styles/scss/_layout_kibela.scss

@@ -1,28 +1,8 @@
-@import '../scss/theme/layout_kibela_variable';
-
 body.kibela {
-  .icon-link,
-  .CodeMirror-hint-active,
-  .grw-nav-main-left-tab,
-  .tav-pane,
-  .active {
-    color: #5882fa;
-  }
-
-  .bg-white {
-    background: #fefffe !important;
-  }
-
-  .bg-primary {
-    background-color: $primary !important;
-  }
-
+  /* Logo */
   .logo {
-    background: transparent;
-
     .logo-mark {
       height: 50px;
-      background-color: white;
       box-shadow: none;
 
       svg {
@@ -32,10 +12,6 @@ body.kibela {
   }
 
   /* header */
-  .background-t {
-    background-color: transparent;
-  }
-
   .authors {
     padding-top: 10px;
 
@@ -44,28 +20,12 @@ body.kibela {
     }
   }
 
-  .search-input-group,
-  .search-typeahead {
-    .btn {
-      background-color: transparent;
-    }
-  }
-
   .panel-heading {
     border-radius: 0 !important;
   }
 
-  .btn-open-dropzone {
-    background: rgb(243, 245, 247);
-  }
-
   /* page list */
-  .page-list {
-    background: white;
-  }
-
   .page-attachments-row {
-    background-color: #e5ecf1 !important;
     border: 0px;
   }
 
@@ -75,7 +35,6 @@ body.kibela {
 
   .round-corner-top {
     z-index: absolute;
-    border-top: solid 0.4em #5584e1;
     border-radius: 0.35em;
   }
 
@@ -86,16 +45,14 @@ body.kibela {
     bottom: 0px;
     left: 0px;
     z-index: absolute;
-    height: 11em;
     max-width: 840px;
+    height: 11em;
     margin: auto;
-    border-top: solid 0.4em #5584e1;
     border-radius: 0.35em;
   }
 
   .grw-subnav {
     position: relative;
-    background: transparent;
     border: none;
 
     svg {
@@ -131,114 +88,27 @@ body.kibela {
     .list-group-item + .list-group-item.active {
       margin-top: 2px;
     }
-
-    .list-group-item.active {
-      color: #fff;
-      background: #1256a3;
-    }
-
-    .list-group-item {
-      &:hover {
-        background: #eee;
-      }
-    }
-  }
-
-  /* search page */
-  .search-result-list,
-  .page-list-li {
-    background: #f4f5f6;
   }
 
   /* Tabs */
   .nav.nav-tabs {
     > .nav-item {
-      color: #5882fa;
       cursor: pointer;
-      background: transparent;
-
-      &:hover,
-      &:focus {
-        > .nav-link {
-          color: #7a94d9;
-        }
-      }
 
       > .nav-link {
-        color: #5882fa;
         border: none;
         border-radius: 3px;
       }
-
-      > .nav-link.active {
-        background: transparent !important;
-        border-bottom: solid 2.7px #5584e1;
-      }
-    }
-
-    .wiki {
-      h1 {
-        border-bottom: solid 2px #5584e1 !important;
-      }
-
-      h2 {
-        border-color: solid 1px #5584e1;
-      }
-    }
-  }
-
-  /* Modal */
-  .modal-content {
-    background-color: $themelight;
-
-    .modal-header.bg-primary {
-      color: white;
-
-      .close {
-        color: white;
-      }
-    }
-  }
-
-  /* Inline Code */
-  :not(.hljs) > code:not(.hljs) {
-    background-color: $bgcolor-inline-code;
-    color: $color-inline-code;
-  }
-
-  /* Card */
-  .card {
-    border: 1px solid $border;
-
-    .card-header {
-      background-color: $lightthemecolor;
-      border-bottom: 1px solid $border;
-    }
-
-    .card-body {
-      background-color: $themelight;
-    }
-
-    .card-footer {
-      background: white;
-      border-top: 1px solid $border;
     }
   }
 
   /* button */
   .btn {
-    border-radius: $radius;
-  }
-
-  .btn-primary {
-    background: $primary;
-    border: 1px solid $primary;
+    // border-radius: $radius;
   }
 
   /* edit */
   .CodeMirror {
-    border: solid 1.2px #d8d8d8;
-    border-top: solid 0.3em #5584e1 !important;
     border-radius: 0.35em;
   }
 
@@ -279,7 +149,6 @@ body.kibela {
     .page-editor-preview-container {
       padding-right: 0px !important;
       padding-left: 2em;
-      background: white !important;
     }
 
     .page-editor-footer {

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

@@ -18,7 +18,7 @@ $dark: #3e4d6c !default;
 //## Font, line-height, and color for body text, headings, and more.
 $font-family-sans-serif:  Lato, -apple-system, BlinkMacSystemFont, 'Hiragino Kaku Gothic ProN', Meiryo, sans-serif;
 $font-family-serif:       Georgia, "Times New Roman", Times, serif;
-$font-family-monospace: Osaka-Mono, 'MS Gothic', Monaco, Menlo, Consolas, 'Courier New', monospace;
+$font-family-monospace: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
 $font-family-base:        $font-family-sans-serif;
 
 $font-size-root: 14px;

+ 8 - 5
src/client/styles/scss/_override-bootstrap.scss

@@ -39,11 +39,6 @@
     line-height: 14px;
   }
 
-  .small {
-    font-size: 65%;
-    line-height: 10px;
-  }
-
   code {
     padding: 2px 4px;
     font-size: 90%;
@@ -59,6 +54,14 @@
     }
   }
 
+  // Custom Control
+  .custom-control {
+    .custom-control-input,
+    .custom-control-input + .custom-control-label {
+      cursor: pointer;
+    }
+  }
+
   // card (substitute panel of bootstrap3)
   .card {
     margin-bottom: 20px;

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

@@ -70,6 +70,7 @@
       .revision-history-diff {
         padding-left: 40px;
         color: #333;
+        table-layout: fixed;
       }
     }
 

+ 3 - 2
src/client/styles/scss/_search.scss

@@ -177,8 +177,9 @@
 
 .search-page-input {
   position: sticky;
-  top: 15px;
-  z-index: 1;
+  top: 65px;
+  // placed at front-most
+  z-index: 15;
 
   margin-bottom: 15px;
 

+ 89 - 0
src/client/styles/scss/_sidebar.scss

@@ -0,0 +1,89 @@
+.grw-sidebar {
+  .ak-navigation-resize-button {
+    top: calc(50vh - 20px);
+  }
+
+  // override @atlaskit/navigation-next styles
+  div[data-testid='GlobalNavigation'] {
+    width: $grw-sidebar-nav-width;
+  }
+  div[class$='-NavigationContainer'] {
+    // Adjust to be on top of the growi subnavigation
+    z-index: $zindex-sticky + 5;
+  }
+  div[class$='-Outer'] {
+    div[class$='-Shadow'] {
+      background: unset;
+      border-right: 1px solid $border;
+    }
+  }
+
+  .grw-global-item-container {
+    i {
+      font-size: 1.5em;
+    }
+
+    // icon opacity
+    &:not(.active) {
+      i {
+        opacity: 0.4;
+      }
+      &:hover,
+      &:focus {
+        i {
+          opacity: 0.7;
+        }
+      }
+    }
+
+    &.active {
+      button {
+        @extend %fukidashi-for-active;
+      }
+    }
+  }
+}
+
+// Drawer Mode
+@include media-breakpoint-down(sm) {
+  .grw-sidebar {
+    position: fixed;
+    z-index: $zindex-fixed - 2;
+
+    // override @atlaskit/navigation-next styles
+    div[class$='-Outer'],
+    div[class$='-teprsg'] {
+      display: none;
+    }
+
+    &:not(.open) {
+      div[class$='-NavigationContainer'] {
+        left: -#{$grw-sidebar-nav-width + $grw-sidebar-content-min-width};
+      }
+    }
+    &.open {
+      div[class$='-NavigationContainer'] {
+        left: 0;
+      }
+    }
+
+    div[class$='-NavigationContainer'] {
+      transition: left 300ms cubic-bezier(0.25, 1, 0.5, 1);
+    }
+  }
+
+  .grw-sidebar-backdrop.modal-backdrop {
+    z-index: $zindex-fixed - 4;
+  }
+}
+
+.grw-sidebar-header-container {
+  padding: 10px;
+
+  h3 {
+    margin-bottom: 0;
+  }
+}
+
+.grw-sidebar-content-container {
+}

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

@@ -90,6 +90,8 @@ $easeInOutCubic: cubic-bezier(0.65, 0, 0.35, 1);
 
   .btn.btn-bookmark {
     &.btn-lg {
+      width: 50px;
+      height: 50px;
       font-size: 1.5em;
     }
   }

+ 5 - 1
src/client/styles/scss/_variables.scss

@@ -6,7 +6,11 @@ $font-family-monospace-not-strictly: Monaco, Menlo, Consolas, 'Courier New', Mei
 
 //== Layout
 $grw-navbar-height: 50px;
-$grw-logo-width: 64px;
+
+$grw-sidebar-nav-width: 64px;
+$grw-sidebar-content-min-width: 240px;
+
+$grw-logo-width: $grw-sidebar-nav-width;
 $grw-logomark-width: 40px;
 
 // fix tab width to 95 pixels

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

@@ -3,6 +3,7 @@
 @import '~bootstrap/scss/variables';
 @import '~bootstrap/scss/mixins';
 @import '~bootstrap/scss/utilities';
+@import '~bootstrap/scss/root';
 
 // increase specificity with ':root' for GROWI theming
 :root {

+ 2 - 0
src/client/styles/scss/atoms/_buttons.scss

@@ -9,6 +9,8 @@
   &:not(:hover):not(.active) {
     background-color: transparent;
   }
+  width: 35px;
+  height: 35px;
 }
 
 .btn-copy,

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

@@ -50,6 +50,7 @@
 @import 'page';
 @import 'search';
 @import 'shortcuts';
+@import 'sidebar';
 @import 'subnav';
 @import 'tag';
 @import 'user';

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

@@ -7,7 +7,7 @@
   &.active,
   &.active:hover,
   &.active:focus {
-    color: white;
+    color: $light;
     background-color: lighten($bgcolor-global, 5%);
   }
 }
@@ -47,14 +47,6 @@ textarea.form-control {
   }
 }
 
-.modal {
-  .modal-header {
-    .close {
-      color: white;
-    }
-  }
-}
-
 /*
  * Panel
  */

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

@@ -0,0 +1,174 @@
+body.kibela {
+  .icon-link,
+  .CodeMirror-hint-active,
+  .grw-nav-main-left-tab,
+  .tav-pane,
+  .active {
+    color: $subthemecolor;
+  }
+
+  .bg-white {
+    background: #fefffe !important;
+  }
+
+  .bg-primary {
+    background-color: $primary !important;
+  }
+
+  /* kibela block */
+  .kibela-block {
+    border-top: solid 0.4em $thickborder;
+  }
+
+  /* page wrapper */
+  #page-wrapper {
+    background-color: $bgcolor-global;
+  }
+
+  .search-input-group,
+  .search-typeahead {
+    .btn {
+      background-color: transparent;
+    }
+  }
+
+  .btn-open-dropzone {
+    background: $themelight;
+  }
+
+  /* page list */
+  .page-list {
+    background: white;
+  }
+
+  .page-attachments-row {
+    background-color: #e5ecf1;
+  }
+
+  /* round */
+  .round-corner-top {
+    border-top: solid 0.4em $thickborder;
+  }
+
+  /* admin navigation */
+  .admin-navigation {
+    .list-group-item {
+      background-color: transparent;
+
+      &:hover {
+        background: #eee;
+      }
+    }
+
+    .list-group-item.active {
+      color: white;
+      background: $bgcolor-navbar-active;
+    }
+  }
+
+  /* search page */
+  .search-result-list,
+  .page-list-li {
+    background: $themelight;
+  }
+
+  /* Tabs */
+  .nav.nav-tabs {
+    > .nav-item {
+      color: $color-link;
+      background: transparent;
+
+      &:hover,
+      &:focus {
+        > .nav-link {
+          color: $color-link-hover;
+        }
+      }
+
+      > .nav-link {
+        color: $color-link;
+      }
+
+      > .nav-link.active {
+        background: transparent !important;
+        border-bottom: solid 2.7px $thickborder;
+      }
+    }
+  }
+
+  /* wiki */
+  .wiki {
+    h1 {
+      border-bottom: solid 2px $thickborder !important;
+    }
+
+    h2 {
+      border-color: solid 1px $thickborder;
+    }
+
+    // change color of highlighted header in wiki (default: orange)
+    .code-line.revision-head.highlighted {
+      color: $themelight;
+      background-color: lighten($bgcolor-theme, 20%);
+
+      .icon-note,
+      .icon-link {
+        color: $themelight;
+      }
+    }
+  }
+
+  /* Modal */
+  .modal-content {
+    background-color: $themelight;
+
+    .modal-header.bg-primary {
+      color: white;
+
+      .close {
+        color: white;
+      }
+    }
+  }
+
+  /* Inline Code */
+  :not(.hljs) > code:not(.hljs) {
+    color: $color-inline-code;
+    background-color: $bgcolor-inline-code;
+  }
+
+  /* button */
+  .btn-primary {
+    background: $primary;
+    border: 1px solid $primary;
+  }
+
+  /* edit */
+  .CodeMirror {
+    border: solid 1.2px #d8d8d8;
+    border-top: solid 0.3em $thickborder !important;
+  }
+
+  &.on-edit {
+    .page-editor-preview-container {
+      background: white !important;
+    }
+  }
+
+  /* navbar */
+  .grw-navbar {
+    .nav-item > .nav-link:hover {
+      color: $color-link-nabvar-hover;
+    }
+  }
+
+  /* h */
+  h1,
+  h2,
+  h3,
+  h4,
+  h5,
+  h6 {
+    color: $color-header;
+  }
+}

+ 7 - 27
src/client/styles/scss/theme/_apply-colors.scss

@@ -25,6 +25,12 @@ $link-hover-color: $color-link-hover;
 }
 
 // Dropdown
+.dropdown-menu {
+  form {
+    color: $color-global;
+  }
+}
+
 .dropdown-item {
   color: $color-global;
   &.active,
@@ -71,7 +77,7 @@ $link-hover-color: $color-link-hover;
 //
 
 .grw-logo {
-  background-color: darken($bgcolor-navbar, 10%);
+  background-color: darken($bgcolor-logo, 10%);
 
   // set transition for fill
   svg * {
@@ -125,22 +131,8 @@ $link-hover-color: $color-link-hover;
 .modal {
   .modal-header {
     border-bottom-color: $border-color-theme;
-
-    &.bg-primary,
-    &.bg-info,
-    &.bg-success,
-    &.bg-warning,
-    &.bg-danger {
-      color: white;
-
-      .close {
-        color: white;
-      }
-    }
-
     .close {
       opacity: 0.5;
-
       &:hover {
         opacity: 0.9;
       }
@@ -190,18 +182,6 @@ $link-hover-color: $color-link-hover;
   }
 }
 
-/*
- * Crowi sidebar
- */
-.crowi-sidebar {
-  background-color: darken($bgcolor-global, 4%);
-  border-left: solid 1px $border-color;
-
-  .system-version {
-    background-color: darken($bgcolor-global, 4%);
-  }
-}
-
 /*
  * GROWI wiki
  */

+ 0 - 39
src/client/styles/scss/theme/_layout_kibela_variable.scss

@@ -1,39 +0,0 @@
-$radius: .25em;
-
-$bgcolor-theme: rgb(18, 86, 163);
-$themelight: #f4f5f6;
-$subthemecolor: rgb(90, 149, 216);
-$lightthemecolor: rgba(181, 203, 247, 0.61);
-
-$bgcolor-navbar: $bgcolor-theme;
-$bgcolor-global: $themelight;
-$bgcolor-global: $themelight;
-
-$color-header: $bgcolor-theme;
-$color-global: #3c4a60;
-$linktext: rgb(74, 109, 204);
-$linktext-hover: lighten($linktext, 12%);
-$sidebar-text: $bgcolor-theme;
-
-$primary: $bgcolor-theme;
-$info: lighten($bgcolor-theme, 20%);
-
-$fillcolor-logo-mark: lighten($bgcolor-theme, 20%);
-$color-link-wiki: lighten($bgcolor-theme, 20%);
-$color-link-wiki-hover: lighten($color-link-wiki, 20%);
-$color-inline-code: $subthemecolor;
-$bgcolor-inline-code: lighten($subthemecolor, 70%);
-$border: $lightthemecolor;
-
-// change color of highlighted header in wiki (default: orange)
-.wiki {
-  .code-line.revision-head.highlighted {
-    color: $themelight;
-    background-color: lighten($bgcolor-theme, 20%);
-
-    .icon-note,
-    .icon-link {
-      color: $themelight;
-    }
-  }
-}

+ 8 - 1
src/client/styles/scss/theme/_reboot-bootstrap-theme-colors.scss

@@ -42,7 +42,7 @@
 
 @each $theme-color, $color in $theme-colors {
   .alert.alert-#{$theme-color} {
-    color: $bgcolor-global;
+    color: $color-alert;
     background: $color;
     border: none;
 
@@ -56,3 +56,10 @@
     }
   }
 }
+
+@each $theme-color, $color in $theme-colors {
+  .badge.badge-#{$theme-color} {
+    color: $color-badge;
+    background: $color;
+  }
+}

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

@@ -70,6 +70,7 @@ html[light] {
   $bgcolor-list-active: $primary;
 
   // Logo colors
+  $bgcolor-logo: $bgcolor-navbar;
   $fillcolor-logo-mark: lighten(desaturate($bgcolor-navbar, 10%), 15%);
 
   // Border colors
@@ -80,6 +81,12 @@ html[light] {
   $color-dropdown-link-active: $color-reversal;
   $color-dropdown-link-hover: $color-global;
 
+  // alert
+  $color-alert: $color-reversal;
+
+  // badge
+  $color-badge: $color-reversal;
+
   @import 'apply-colors';
   @import 'apply-colors-light';
 }
@@ -115,6 +122,7 @@ html[dark] {
   $bgcolor-list-active: $primary;
 
   // Logo colors
+  $bgcolor-logo: $bgcolor-navbar;
   $fillcolor-logo-mark: #444;
 
   // Border colors
@@ -125,6 +133,12 @@ html[dark] {
   $color-dropdown-link-active: $color-global;
   $color-dropdown-link-hover: $color-reversal;
 
+  // alert
+  $color-alert: $color-global;
+
+  // badge
+  $color-badge: $color-global;
+
   @import 'apply-colors';
   @import 'apply-colors-dark';
 }

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

@@ -42,6 +42,7 @@ html[light] {
   $bgcolor-list-active: $primary;
 
   // Logo colors
+  $bgcolor-logo: $bgcolor-navbar;
   $fillcolor-logo-mark: lighten(desaturate($bgcolor-navbar, 10%), 15%);
 
   // Border colors
@@ -52,6 +53,12 @@ html[light] {
   $color-dropdown-link-active: $color-reversal;
   $color-dropdown-link-hover: $color-reversal;
 
+  // alert
+  $color-alert: $color-reversal;
+
+  // badge
+  $color-badge: $color-reversal;
+
   @import 'apply-colors';
   @import 'apply-colors-light';
 }
@@ -87,6 +94,7 @@ html[dark] {
   $bgcolor-list-active: $primary;
 
   // Logo colors
+  $bgcolor-logo: $bgcolor-navbar;
   $fillcolor-logo-mark: #444;
 
   // Border colors
@@ -97,6 +105,12 @@ html[dark] {
   $color-dropdown-link-active: $color-global;
   $color-dropdown-link-hover: $color-reversal;
 
+  // alert
+  $color-alert: $color-reversal;
+
+  // badge
+  $color-badge: $color-reversal;
+
   @import 'apply-colors';
   @import 'apply-colors-dark';
 }

+ 103 - 7
src/client/styles/scss/theme/kibela.scss

@@ -1,9 +1,105 @@
-// import colors
-@import '../../agile-admin/inverse/colors/kibela';
-@import 'layout_kibela_valiable';
+@import '../variables';
+@import '../override-bootstrap-variables';
 
-// apply agile-admin theme
-@import '../../agile-admin/inverse/style';
+$bgcolor-theme: rgb(18, 86, 163);
+$themelight: #f4f5f6;
+$subthemecolor: rgb(88, 130, 250);
+$lightthemecolor: rgba(181, 203, 247, 0.61);
 
-// override
-@import 'override-agileadmin';
+// Light Mode
+html[light] {
+  // 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%);
+
+  // Logo colors
+  $bgcolor-logo: transparent;
+  $fillcolor-logo-mark: lighten($bgcolor-theme, 20%);
+
+  $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;
+
+  // alert
+  $color-alert: $color-reversal;
+
+  // badge
+  $color-badge: $color-reversal;
+
+  @import 'apply-colors';
+  @import 'apply-colors-light';
+  @import 'apply-colors-kibela';
+}
+
+// Dark Mode ( same as Light Mode )
+html[dark] {
+  // Background colors
+  $bgcolor-navbar: transparent;
+  $bgcolor-navbar-active: $bgcolor-theme;
+  $bgcolor-global: $themelight;
+  $bgcolor-card: #e3e5e7;
+  $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%);
+
+  // Logo colors
+  $bgcolor-logo: red;
+  $fillcolor-logo-mark: lighten($bgcolor-theme, 20%);
+
+  $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;
+
+  // alert
+  $color-alert: $color-global;
+
+  // badge
+  $color-badge: $color-global;
+
+  @import 'apply-colors';
+  @import 'apply-colors-light';
+  @import 'apply-colors-kibela';
+}

+ 1 - 1
src/server/routes/apiv3/customize-setting.js

@@ -100,7 +100,7 @@ module.exports = (crowi) => {
       ]),
     ],
     layoutTheme: [
-      body('layoutType').isString().isIn(['growi', 'kibela', 'crowi']),
+      body('layoutType').isString().isIn(['growi', 'kibela']),
       body('themeType').isString().isIn([
         'default', 'nature', 'mono-blue', 'wood', 'island', 'christmas', 'antarctic', 'future', 'blue-night', 'halloween', 'spring',
       ]),

+ 6 - 48
src/server/views/layout-kibela/widget/header.html

@@ -1,49 +1,7 @@
-<header id="page-header background-t">
-  <div class="d-flex align-items-center">
-    <div class="hidden-xs hidden-sm">
-      <a class="logo" href="/">
-        <div class="">{% include '../../widget/logo.html' %}</div>
-      </a>
-    </div>
-    <div class="title-container">
-      <h1 class="title" id="revision-path"></h1>
-      {% if not forbidden and not isTrashPage() %}
-        <div id="tag-label"></div>
-      {% endif %}
-    </div>
-    {% if page %}
+<div id="grw-subnav" class="grw-subnav" data-is-forbidden-page="{{ forbidden }}"></div>
 
-    <ul class="authors hidden-sm hidden-xs text-nowrap grw-pt-10px">
-      <li>
-        <div class="d-flex align-items-center b">
-          <a class="mr-2" href="{{ userPageRoot(page.creator) }}">
-            <img src="{{ page.creator|default(author)|picture }}" class="picture rounded-circle">
-          </a>
-          <div>
-            <div>Created by
-              <a href="{{ userPageRoot(page.creator) }}">{{ page.creator.name|default(author.name) }}</a>
-            </div>
-            <div class="text-muted">{{ page.createdAt|datetz('Y/m/d H:i:s') }}</div>
-          </div>
-        </div>
-      </li>
-      <li class="mt-2">
-        <div class="d-flex align-items-center">
-          <a class="mr-2" href="{{ userPageRoot(author) }}">
-            <img src="{{ author|picture }}" class="picture rounded-circle">
-          </a>
-          <div>
-            <div>Updated by
-              <a href="{{ userPageRoot(author) }}">{{ author.name }}</a>
-            </div>
-            <div class="text-muted">{{ page.updatedAt|datetz('Y/m/d H:i:s') }}</div>
-          </div>
-        </div>
-      </li>
-    </ul>
-    {% endif %} {% if not page and ('/' === path or 'crowi' === getConfig('crowi', 'customize:behavior')) and not isUserPageList(path) and !isTrashPage()
-    %} {% if '/' === path.slice(-1) %} {% include '../../widget/create_portal.html' %} {% endif %} {% endif %}
-
-  </div>
-
-</header>
+{% if not page and ('/' === path or 'crowi' === getConfig('crowi', 'customize:behavior')) and not isUserPageList(path) and !isTrashPage() %}
+  {% if '/' === path.slice(-1) %}
+    {% include '../../widget/create_portal.html' %}
+  {% endif %}
+{% endif %}

+ 7 - 6
src/server/views/layout/layout.html

@@ -74,11 +74,13 @@
 <div id="wrapper">
 
   {% block layout_head_nav %}
-  <nav class="navbar grw-navbar navbar-expand-sm navbar-dark fixed-top mb-0 p-sm-0">
-    <div id="grw-navbar-toggler" class="d-sm-none mr-auto"></div>
+  <nav class="navbar grw-navbar navbar-expand navbar-dark fixed-top mb-0 px-0">
+    <ul class="navbar-nav d-md-none mr-auto">
+      <li id="grw-navbar-toggler" class="nav-item"></li>
+    </ul>
 
     {# Brand Logo #}
-    <div class="navbar-brand mr-sm-auto">
+    <div class="navbar-brand mr-md-auto">
       <a class="grw-logo d-block" href="/">
         {% include '../widget/logo.html' %}
       </a>
@@ -134,9 +136,8 @@
 
   <div class="d-flex">
     {# Sidebar #}
-    <nav class="d-none d-sm-block">
-      <div id="grw-sidebar" class="grw-sidebar"></div>
-    </nav>
+    <div id="grw-sidebar-wrapper"></div>
+
     <div id="page-wrapper" class="flex-grow-1">
       {% block layout_main %}
       {% endblock %} {# layout_main #}

+ 1 - 1
src/server/views/modal/create_page.html

@@ -71,7 +71,7 @@
                 </div>
 
               </div>
-              <div class="create-page-button-container my-auto">
+              <div class="create-page-button-container">
                 <a id="link-to-template" href="{{ page.path || path }}" class="btn btn-outline-primary rounded-pill disabled">
                   <i class="icon-fw icon-doc"></i>
                   <span id="create-template-button-link">{{ t('Edit') }}</span>

+ 74 - 71
src/server/views/modal/shortcuts.html

@@ -8,86 +8,89 @@
       </div>
 
       <div class="modal-body">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-6">
+              <h3><strong>{{ t('modal_shortcuts.global.title') }}</strong></h3>
 
-        <div class="row">
-          <div class="col-lg-6">
-            <h3><strong>{{ t('modal_shortcuts.global.title') }}</strong></h3>
+                <table class="table table-responsive">
+                  <tr>
+                    <th>{{ t('modal_shortcuts.global.Open/Close shortcut help') }}:</th>
+                    <td><span class="key cmd-key"></span> + <span class="key">/</span></td>
+                  </tr>
+                  <tr>
+                    <th>{{ t('modal_shortcuts.global.Create Page') }}:</th>
+                    <td><span class="key">C</span></td>
+                  </tr>
+                  <tr>
+                    <th>{{ t('modal_shortcuts.global.Edit Page') }}:</th>
+                    <td><span class="key">E</span></td>
+                  </tr>
+                  <tr>
+                    <th>{{ t('modal_shortcuts.global.Show Contributors') }}:</th>
+                    <td>
+                      <a href="{{ t('modal_shortcuts.global.konami_code_url') }}" target="_blank">{{ t('modal_shortcuts.global.Konami Code') }}</a><br>
+                      <span class="key key-small">↑</span>&nbsp;<span class="key key-small">↑</span>
+                      <span class="key key-small">↓</span>&nbsp;<span class="key key-small">↓</span>
+                      <span class="key key-small">←</span><br><span class="key key-small">→</span>
+                      <span class="key key-small">←</span>&nbsp;<span class="key key-small">→</span>
+                      <span class="key key-small">B</span>&nbsp;<span class="key key-small">A</span>
+                    </td>
+                  </tr>
+                </table>
+            </div><!-- /.col-lg-6 -->
 
-            <table class="table">
-              <tr>
-                <th>{{ t('modal_shortcuts.global.Open/Close shortcut help') }}:</th>
-                <td><span class="key cmd-key"></span> + <span class="key">/</span></td>
-              </tr>
-              <tr>
-                <th>{{ t('modal_shortcuts.global.Create Page') }}:</th>
-                <td><span class="key">C</span></td>
-              </tr>
-              <tr>
-                <th>{{ t('modal_shortcuts.global.Edit Page') }}:</th>
-                <td><span class="key">E</span></td>
-              </tr>
-              <tr>
-                <th>{{ t('modal_shortcuts.global.Show Contributors') }}:</th>
-                <td>
-                  <a href="{{ t('modal_shortcuts.global.konami_code_url') }}" target="_blank">{{ t('modal_shortcuts.global.Konami Code') }}</a><br>
-                  <span class="key key-small">↑</span>&nbsp;<span class="key key-small">↑</span>
-                  <span class="key key-small">↓</span>&nbsp;<span class="key key-small">↓</span>
-                  <span class="key key-small">←</span>&nbsp;<span class="key key-small">→</span>
-                  <span class="key key-small">←</span>&nbsp;<span class="key key-small">→</span>
-                  <span class="key key-small">B</span>&nbsp;<span class="key key-small">A</span>
-                </td>
-              </tr>
-            </table>
-          </div><!-- /.col-lg-6 -->
 
-          <div class="col-lg-6">
-            <h3><strong>{{ t('modal_shortcuts.editor.title') }}</strong></h3>
+            <div class="col-lg-6">
+              <h3><strong>{{ t('modal_shortcuts.editor.title') }}</strong></h3>
 
-            <table class="table">
-              <tr>
-                <th>{{ t('modal_shortcuts.editor.Indent') }}:</th>
-                <td><span class="key key-longer">Tab</span></td>
-              </tr>
-              <tr>
-                <th>{{ t('modal_shortcuts.editor.Outdent') }}:</th>
-                <td class="text-nowrap"><span class="key key-long">Shift</span> + <span class="key key-longer">Tab</span></td>
-              </tr>
-              <tr>
-                <th>{{ t('modal_shortcuts.editor.Save Page') }}:</th>
-                <td><span class="key cmd-key"></span> + <span class="key">S</span></td>
-              </tr>
-              <tr>
-                <th>{{ t('modal_shortcuts.editor.Delete Line') }}:</th>
-                <td><span class="key cmd-key"></span> + <span class="key">D</span></td>
-              </tr>
-            </table>
-          </div><!-- /.col-lg-6 -->
+              <table class="table table-responsive">
+                <tr>
+                  <th>{{ t('modal_shortcuts.editor.Indent') }}:</th>
+                  <td><span class="key key-longer">Tab</span></td>
+                </tr>
+                <tr>
+                  <th>{{ t('modal_shortcuts.editor.Outdent') }}:</th>
+                  <td class="text-nowrap"><span class="key key-long">Shift</span> + <span class="key key-longer">Tab</span></td>
+                </tr>
+                <tr>
+                  <th>{{ t('modal_shortcuts.editor.Save Page') }}:</th>
+                  <td><span class="key cmd-key"></span> + <span class="key">S</span></td>
+                </tr>
+                <tr>
+                  <th>{{ t('modal_shortcuts.editor.Delete Line') }}:</th>
+                  <td><span class="key cmd-key"></span> + <span class="key">D</span></td>
+                </tr>
+              </table>
+            </div><!-- /.col-lg-6 -->
+          </div><!-- /.row -->
+        </div><!-- /.container -->
 
-        </div><!-- /.row -->
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-6">
+              <h3><strong></strong></h3>
+            </div><!-- /.col-lg-6 -->
 
-        <div class="row">
-          <div class="col-lg-6">
-            <h3><strong></strong></h3>
-          </div><!-- /.col-lg-6 -->
+            <div class="col-lg-6">
+              <h3><strong>{{ t('modal_shortcuts.commentform.title') }}</strong></h3>
 
-          <div class="col-lg-6">
-            <h3><strong>{{ t('modal_shortcuts.commentform.title') }}</strong></h3>
-
-            <table class="table">
-              <tr>
-                <th>{{ t('modal_shortcuts.commentform.Post') }}:</th>
-                <td><span class="key cmd-key"></span> + <span class="key key-longer">{% include '../widget/icon-keyboard-return-enter.html' %}</span></td>
-              </tr>
-              <tr>
-                <th>{{ t('modal_shortcuts.editor.Delete Line') }}:</th>
-                <td><span class="key cmd-key"></span> + <span class="key">D</span></td>
-              </tr>
-            </table>
-          </div><!-- /.col-lg-6 -->
-
-        </div><!-- /.row -->
+              <table class="table table-responsive">
+                <tr>
+                  <th>{{ t('modal_shortcuts.commentform.Post') }}:</th>
+                  <td><span class="key cmd-key"></span> + <span class="key key-longer">{% include '../widget/icon-keyboard-return-enter.html' %}</span></td>
+                </tr>
+                <tr>
+                  <th>{{ t('modal_shortcuts.editor.Delete Line') }}:</th>
+                  <td><span class="key cmd-key"></span> + <span class="key">D</span></td>
+                </tr>
+              </table>
+            </div><!-- /.col-lg-6 -->
 
+          </div><!-- /.row -->
+        </div><!-- /.container -->
       </div>
+    </div>
 
 
     </div><!-- /.modal-content -->