Przeglądaj źródła

Merge branch 'support/apply-bootstrap4' into support/reactify-login-page-stock

yusuketk 6 lat temu
rodzic
commit
6359dc325b
36 zmienionych plików z 521 dodań i 435 usunięć
  1. 1 1
      resource/locales/ja/translation.json
  2. 1 1
      src/client/js/bootstrap.jsx
  3. 0 2
      src/client/js/components/Admin/App/AppSetting.jsx
  4. 2 2
      src/client/js/components/Admin/Customize/CustomizeBehaviorSetting.jsx
  5. 6 6
      src/client/js/components/Admin/Customize/CustomizeFunctionSetting.jsx
  6. 2 2
      src/client/js/components/Admin/Customize/CustomizeHighlightSetting.jsx
  7. 67 65
      src/client/js/components/Admin/MarkdownSetting/PresentationForm.jsx
  8. 74 72
      src/client/js/components/Admin/MarkdownSetting/XssForm.jsx
  9. 1 1
      src/client/js/components/Admin/Notification/GlobalNotification.jsx
  10. 1 1
      src/client/js/components/Admin/Notification/UserTriggerNotification.jsx
  11. 2 2
      src/client/js/components/Admin/Security/BasicSecuritySetting.jsx
  12. 4 4
      src/client/js/components/Admin/Security/GoogleSecuritySetting.jsx
  13. 4 4
      src/client/js/components/Admin/Security/LocalSecuritySetting.jsx
  14. 9 9
      src/client/js/components/Admin/Security/TwitterSecuritySetting.jsx
  15. 32 70
      src/client/js/components/Admin/UserManagement.jsx
  16. 1 1
      src/client/js/components/Me/ApiSettings.jsx
  17. 9 5
      src/client/js/components/Navbar/GrowiSubNavigation.jsx
  18. 12 8
      src/client/js/components/Navbar/GrowiSubNavigationForUserPage.jsx
  19. 12 3
      src/client/js/components/Navbar/NavbarToggler.jsx
  20. 2 2
      src/client/js/components/PageEditorByHackmd.jsx
  21. 88 38
      src/client/js/components/Sidebar.jsx
  22. 7 0
      src/client/js/services/AppContainer.js
  23. 0 56
      src/client/styles/scss/_layout.scss
  24. 10 0
      src/client/styles/scss/_on-edit.scss
  25. 89 0
      src/client/styles/scss/_sidebar.scss
  26. 5 1
      src/client/styles/scss/_variables.scss
  27. 1 0
      src/client/styles/scss/_vendor.scss
  28. 1 0
      src/client/styles/scss/style-app.scss
  29. 0 10
      src/client/styles/scss/theme/_apply-colors-kibela.scss
  30. 22 12
      src/client/styles/scss/theme/_apply-colors.scss
  31. 14 0
      src/client/styles/scss/theme/antarctic.scss
  32. 14 2
      src/client/styles/scss/theme/default.scss
  33. 14 0
      src/client/styles/scss/theme/kibela.scss
  34. 1 1
      src/server/views/_form.html
  35. 6 48
      src/server/views/layout-kibela/widget/header.html
  36. 7 6
      src/server/views/layout/layout.html

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

@@ -381,7 +381,7 @@
     "discard_changes": "HackMD の変更を破棄する",
     "integration_failed": "HackMD の統合に失敗しました",
     "fail_to_connect": "GROWI クライアントが HackMD の GROWI agent に接続できませんでした。",
-    "check_configuration": "<a href='https://docs.growi.org/guide/admin-cookbook/integrate-with-hackmd.html'>こちらのマニュアル</a>から設定を確認してください",
+    "check_configuration": "<a href='https://docs.growi.org/ja/admin-guide/admin-cookbook/integrate-with-hackmd.html'>こちらのマニュアル</a>から設定を確認してください",
     "not_initialized": "HackMD コンポーネントは初期化されていません",
     "someone_editing": "このページは、HackMD で編集されています。",
     "this_page_has_draft": "このページは、HackMD のドラフトがあります。"

+ 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 />,
 };

+ 0 - 2
src/client/js/components/Admin/App/AppSetting.jsx

@@ -112,8 +112,6 @@ class AppSetting extends React.Component {
             </div>
 
             <p className="form-text text-muted">
-              {t('admin:app_setting.enable_files_except_image')}
-              <br />
               {t('admin:app_setting.attach_enable')}
             </p>
           </div>

+ 2 - 2
src/client/js/components/Admin/Customize/CustomizeBehaviorSetting.jsx

@@ -42,7 +42,7 @@ class CustomizeBehaviorSetting extends React.Component {
           <div className="col-12">
             <h2 className="admin-setting-header">{t('admin:customize_setting.behavior')}</h2>
             <div className="row">
-              <div className="col-6">
+              <div className="col-md-6">
                 <CustomizeBehaviorOption
                   behaviorType="growi"
                   isSelected={adminCustomizeContainer.state.currentBehavior === 'growi'}
@@ -57,7 +57,7 @@ class CustomizeBehaviorSetting extends React.Component {
                 </CustomizeBehaviorOption>
               </div>
 
-              <div className="col-6">
+              <div className="col-md-6">
                 <CustomizeBehaviorOption
                   behaviorType="crowi-plus"
                   isSelected={adminCustomizeContainer.state.currentBehavior === 'crowi-plus'}

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

@@ -60,7 +60,7 @@ class CustomizeBehaviorSetting extends React.Component {
 
 
             <div className="form-group row">
-              <div className="offset-3 col-6 text-left">
+              <div className="offset-md-3 col-md-6 text-left">
                 <CustomizeFunctionOption
                   optionId="isEnabledTimeline"
                   label={t('admin:customize_setting.function_options.timeline')}
@@ -77,7 +77,7 @@ class CustomizeBehaviorSetting extends React.Component {
             </div>
 
             <div className="form-group row">
-              <div className="offset-3 col-6 text-left">
+              <div className="offset-md-3 col-md-6 text-left">
                 <CustomizeFunctionOption
                   optionId="isSavedStatesOfTabChanges"
                   label={t('admin:customize_setting.function_options.tab_switch')}
@@ -93,7 +93,7 @@ class CustomizeBehaviorSetting extends React.Component {
             </div>
 
             <div className="form-group row">
-              <div className="offset-3 col-6 text-left">
+              <div className="offset-md-3 col-md-6 text-left">
                 <CustomizeFunctionOption
                   optionId="isEnabledAttachTitleHeader"
                   label={t('admin:customize_setting.function_options.attach_title_header')}
@@ -108,7 +108,7 @@ class CustomizeBehaviorSetting extends React.Component {
             </div>
 
             <div className="form-group row">
-              <div className="offset-3 col-6 text-left">
+              <div className="offset-md-3 col-md-6 text-left">
                 <div className="my-0 w-100">
                   <label>{t('admin:customize_setting.function_options.recent_created__n_draft_num_desc')}</label>
                 </div>
@@ -135,7 +135,7 @@ class CustomizeBehaviorSetting extends React.Component {
             </div>
 
             <div className="form-group row">
-              <div className="offset-3 col-6 text-left">
+              <div className="offset-md-3 col-md-6 text-left">
                 <CustomizeFunctionOption
                   optionId="isEnabledStaleNotification"
                   label={t('admin:customize_setting.function_options.stale_notification')}
@@ -150,7 +150,7 @@ class CustomizeBehaviorSetting extends React.Component {
             </div>
 
             <div className="form-group row">
-              <div className="offset-3 col-6 text-left">
+              <div className="offset-md-3 col-md-6 text-left">
                 <CustomizeFunctionOption
                   optionId="isAllReplyShown"
                   label={t('admin:customize_setting.function_options.show_all_reply_comments')}

+ 2 - 2
src/client/js/components/Admin/Customize/CustomizeHighlightSetting.jsx

@@ -93,7 +93,7 @@ class CustomizeHighlightSetting extends React.Component {
             <h2 className="admin-setting-header">{t('admin:customize_setting.code_highlight')}</h2>
 
             <div className="form-group row">
-              <div className="offset-3 col-6 text-left">
+              <div className="offset-md-3 col-md-6 text-left">
                 <div className="my-0">
                   <label>{t('admin:customize_setting.theme')}</label>
                 </div>
@@ -113,7 +113,7 @@ class CustomizeHighlightSetting extends React.Component {
             </div>
 
             <div className="form-group row">
-              <div className="offset-3 col-6 text-left">
+              <div className="offset-md-3 col-md-6 text-left">
                 <div className="custom-control custom-switch custom-checkbox-success">
                   <input
                     type="checkbox"

+ 67 - 65
src/client/js/components/Admin/MarkdownSetting/PresentationForm.jsx

@@ -46,74 +46,76 @@ class PresentationForm extends React.Component {
           {t('admin:markdown_setting.presentation_options.page_break_setting')}
         </label>
 
-        <div className="form-group form-check-inline col-12 my-3">
-          <div className="col-4 align-self-start">
-            <div className="custom-control custom-radio">
-              <input
-                type="radio"
-                className="custom-control-input"
-                id="pageBreakOption1"
-                checked={pageBreakSeparator === 1}
-                onChange={() => adminMarkDownContainer.switchPageBreakSeparator(1)}
-              />
-              <label className="custom-control-label" htmlFor="pageBreakOption1">
-                <p className="font-weight-bold">{ t('admin:markdown_setting.presentation_options.preset_one_separator') }</p>
-                <div className="mt-3">
-                  { t('admin:markdown_setting.presentation_options.preset_one_separator_desc') }
-                  <input
-                    className="form-control"
-                    type="text"
-                    value={t('admin:markdown_setting.presentation_options.preset_one_separator_value')}
-                    readOnly
-                  />
-                </div>
-              </label>
+        <div className="form-group col-12 my-3">
+          <div className="row">
+            <div className="col-md-4 col-sm-12 align-self-start mb-4">
+              <div className="custom-control custom-radio">
+                <input
+                  type="radio"
+                  className="custom-control-input"
+                  id="pageBreakOption1"
+                  checked={pageBreakSeparator === 1}
+                  onChange={() => adminMarkDownContainer.switchPageBreakSeparator(1)}
+                />
+                <label className="custom-control-label w-100" htmlFor="pageBreakOption1">
+                  <p className="font-weight-bold">{ t('admin:markdown_setting.presentation_options.preset_one_separator') }</p>
+                  <div className="mt-3">
+                    { t('admin:markdown_setting.presentation_options.preset_one_separator_desc') }
+                    <input
+                      className="form-control"
+                      type="text"
+                      value={t('admin:markdown_setting.presentation_options.preset_one_separator_value')}
+                      readOnly
+                    />
+                  </div>
+                </label>
+              </div>
             </div>
-          </div>
 
-          <div className="col-4 align-self-start">
-            <div className="custom-control custom-radio">
-              <input
-                type="radio"
-                className="custom-control-input"
-                id="pageBreakOption2"
-                checked={pageBreakSeparator === 2}
-                onChange={() => adminMarkDownContainer.switchPageBreakSeparator(2)}
-              />
-              <label className="custom-control-label" htmlFor="pageBreakOption2">
-                <p className="font-weight-bold">{ t('admin:markdown_setting.presentation_options.preset_two_separator') }</p>
-                <div className="mt-3">
-                  { t('admin:markdown_setting.presentation_options.preset_two_separator_desc') }
-                  <input
-                    className="form-control"
-                    type="text"
-                    value={t('admin:markdown_setting.presentation_options.preset_two_separator_value')}
-                    readOnly
-                  />
-                </div>
-              </label>
+            <div className="col-md-4 col-sm-12 align-self-start mb-4">
+              <div className="custom-control custom-radio">
+                <input
+                  type="radio"
+                  className="custom-control-input"
+                  id="pageBreakOption2"
+                  checked={pageBreakSeparator === 2}
+                  onChange={() => adminMarkDownContainer.switchPageBreakSeparator(2)}
+                />
+                <label className="custom-control-label w-100" htmlFor="pageBreakOption2">
+                  <p className="font-weight-bold">{ t('admin:markdown_setting.presentation_options.preset_two_separator') }</p>
+                  <div className="mt-3">
+                    { t('admin:markdown_setting.presentation_options.preset_two_separator_desc') }
+                    <input
+                      className="form-control"
+                      type="text"
+                      value={t('admin:markdown_setting.presentation_options.preset_two_separator_value')}
+                      readOnly
+                    />
+                  </div>
+                </label>
+              </div>
             </div>
-          </div>
-          <div className="col-4 align-self-start">
-            <div className="custom-control custom-radio">
-              <input
-                type="radio"
-                id="pageBreakOption3"
-                className="custom-control-input"
-                checked={pageBreakSeparator === 3}
-                onChange={() => adminMarkDownContainer.switchPageBreakSeparator(3)}
-              />
-              <label className="custom-control-label" htmlFor="pageBreakOption3">
-                <p className="font-weight-bold">{ t('admin:markdown_setting.presentation_options.custom_separator') }</p>
-                <div className="mt-3">
-                  { t('admin:markdown_setting.presentation_options.custom_separator_desc') }
-                  <input
-                    className="form-control"
-                    defaultValue={pageBreakCustomSeparator}
-                    onChange={(e) => { adminMarkDownContainer.setPageBreakCustomSeparator(e.target.value) }}
-                  />
-                </div>
-              </label>
+            <div className="col-md-4 col-sm-12 align-self-start mb-4">
+              <div className="custom-control custom-radio">
+                <input
+                  type="radio"
+                  id="pageBreakOption3"
+                  className="custom-control-input"
+                  checked={pageBreakSeparator === 3}
+                  onChange={() => adminMarkDownContainer.switchPageBreakSeparator(3)}
+                />
+                <label className="custom-control-label w-100" htmlFor="pageBreakOption3">
+                  <p className="font-weight-bold">{ t('admin:markdown_setting.presentation_options.custom_separator') }</p>
+                  <div className="mt-3">
+                    { t('admin:markdown_setting.presentation_options.custom_separator_desc') }
+                    <input
+                      className="form-control"
+                      defaultValue={pageBreakCustomSeparator}
+                      onChange={(e) => { adminMarkDownContainer.setPageBreakCustomSeparator(e.target.value) }}
+                    />
+                  </div>
+                </label>
+              </div>
             </div>
           </div>
         </div>

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

@@ -42,82 +42,84 @@ class XssForm extends React.Component {
     const { xssOption } = adminMarkDownContainer.state;
 
     return (
-      <div className="form-group form-check-inline col-12 my-3">
-        <div className="col-4 align-self-start">
-          <div className="custom-control custom-radio ">
-            <input
-              type="radio"
-              className="custom-control-input"
-              id="xssOption1"
-              name="XssOption"
-              checked={xssOption === 1}
-              onChange={() => { adminMarkDownContainer.setState({ xssOption: 1 }) }}
-            />
-            <label className="custom-control-label" htmlFor="xssOption1">
-              <p className="font-weight-bold">{t('admin:markdown_setting.xss_options.ignore_all_tags') }</p>
-              <div className="mt-4">
-                {t('admin:markdown_setting.xss_options.ignore_all_tags_desc') }
-              </div>
-            </label>
+      <div className="form-group col-12 my-3">
+        <div className="row">
+          <div className="col-md-4 col-sm-12 align-self-start mb-4">
+            <div className="custom-control custom-radio ">
+              <input
+                type="radio"
+                className="custom-control-input"
+                id="xssOption1"
+                name="XssOption"
+                checked={xssOption === 1}
+                onChange={() => { adminMarkDownContainer.setState({ xssOption: 1 }) }}
+              />
+              <label className="custom-control-label w-100" htmlFor="xssOption1">
+                <p className="font-weight-bold">{t('admin:markdown_setting.xss_options.ignore_all_tags')}</p>
+                <div className="mt-4">
+                  {t('admin:markdown_setting.xss_options.ignore_all_tags_desc')}
+                </div>
+              </label>
+            </div>
           </div>
-        </div>
 
-        <div className="col-4 align-self-start">
-          <div className="custom-control custom-radio">
-            <input
-              type="radio"
-              className="custom-control-input"
-              id="xssOption2"
-              name="XssOption"
-              checked={xssOption === 2}
-              onChange={() => { adminMarkDownContainer.setState({ xssOption: 2 }) }}
-            />
-            <label className="custom-control-label" htmlFor="xssOption2">
-              <p className="font-weight-bold">{t('admin:markdown_setting.xss_options.recommended_setting')}</p>
-              <div className="m-t-15">
-                <div className="d-flex justify-content-between">
-                  {t('admin:markdown_setting.xss_options.tag_names')}
+          <div className="col-md-4 col-sm-12 align-self-start mb-4">
+            <div className="custom-control custom-radio">
+              <input
+                type="radio"
+                className="custom-control-input"
+                id="xssOption2"
+                name="XssOption"
+                checked={xssOption === 2}
+                onChange={() => { adminMarkDownContainer.setState({ xssOption: 2 }) }}
+              />
+              <label className="custom-control-label w-100" htmlFor="xssOption2">
+                <p className="font-weight-bold">{t('admin:markdown_setting.xss_options.recommended_setting')}</p>
+                <div className="m-t-15">
+                  <div className="d-flex justify-content-between">
+                    {t('admin:markdown_setting.xss_options.tag_names')}
+                  </div>
+                  <textarea
+                    className="form-control xss-list"
+                    name="recommendedTags"
+                    rows="6"
+                    cols="40"
+                    readOnly
+                    defaultValue={tags}
+                  />
                 </div>
-                <textarea
-                  className="form-control xss-list"
-                  name="recommendedTags"
-                  rows="6"
-                  cols="40"
-                  readOnly
-                  defaultValue={tags}
-                />
-              </div>
-              <div className="m-t-15">
-                <div className="d-flex justify-content-between">
-                  {t('admin:markdown_setting.xss_options.tag_attributes')}
+                <div className="m-t-15">
+                  <div className="d-flex justify-content-between">
+                    {t('admin:markdown_setting.xss_options.tag_attributes')}
+                  </div>
+                  <textarea
+                    className="form-control xss-list"
+                    name="recommendedAttrs"
+                    rows="6"
+                    cols="40"
+                    readOnly
+                    defaultValue={attrs}
+                  />
                 </div>
-                <textarea
-                  className="form-control xss-list"
-                  name="recommendedAttrs"
-                  rows="6"
-                  cols="40"
-                  readOnly
-                  defaultValue={attrs}
-                />
-              </div>
-            </label>
+              </label>
+            </div>
           </div>
-        </div>
 
-        <div className="col-4 align-self-start">
-          <div className="custom-control custom-radio">
-            <input
-              type="radio"
-              className="custom-control-input"
-              id="xssOption3"
-              name="XssOption"
-              checked={xssOption === 3}
-              onChange={() => { adminMarkDownContainer.setState({ xssOption: 3 }) }}
-            />
-            <label className="custom-control-label" htmlFor="xssOption3">
-              <p className="font-weight-bold">{t('admin:markdown_setting.xss_options.custom_whitelist') }</p>
-              <WhiteListInput customizable />
-            </label>
+          <div className="col-md-4 col-sm-12 align-self-start mb-4">
+            <div className="custom-control custom-radio">
+              <input
+                type="radio"
+                className="custom-control-input"
+                id="xssOption3"
+                name="XssOption"
+                checked={xssOption === 3}
+                onChange={() => { adminMarkDownContainer.setState({ xssOption: 3 }) }}
+              />
+              <label className="custom-control-label w-100" htmlFor="xssOption3">
+                <p className="font-weight-bold">{t('admin:markdown_setting.xss_options.custom_whitelist')}</p>
+                <WhiteListInput customizable />
+              </label>
+            </div>
           </div>
         </div>
       </div>
@@ -142,8 +144,8 @@ class XssForm extends React.Component {
                   checked={isEnabledXss}
                   onChange={adminMarkDownContainer.switchEnableXss}
                 />
-                <label className="custom-control-label" htmlFor="XssEnable">
-                  {t('admin:markdown_setting.xss_options.enable_xss_prevention') }
+                <label className="custom-control-label w-100" htmlFor="XssEnable">
+                  {t('admin:markdown_setting.xss_options.enable_xss_prevention')}
                 </label>
               </div>
             </div>

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

@@ -40,7 +40,7 @@ class GlobalNotification extends React.Component {
     return (
       <React.Fragment>
 
-        <h2 className="border-bottom">{t('notification_setting.valid_page')}</h2>
+        <h2 className="border-bottom my-4">{t('notification_setting.valid_page')}</h2>
 
         <p className="card well">
           {/* eslint-disable-next-line react/no-danger */}

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

@@ -82,7 +82,7 @@ class UserTriggerNotification extends React.Component {
 
     return (
       <React.Fragment>
-        <h2 className="border-bottom my-5">{t('notification_setting.user_trigger_notification_header')}</h2>
+        <h2 className="border-bottom my-4">{t('notification_setting.user_trigger_notification_header')}</h2>
 
         <table className="table table-bordered">
           <thead>

+ 2 - 2
src/client/js/components/Admin/Security/BasicSecuritySetting.jsx

@@ -68,7 +68,7 @@ class BasicSecurityManagement extends React.Component {
         )}
 
         <div className="row mb-5">
-          <div className="col-6 offset-3">
+          <div className="col-md-6 offset-md-3">
             <div className="custom-control custom-switch custom-checkbox-success">
               <input
                 id="isBasicEnabled"
@@ -95,7 +95,7 @@ class BasicSecurityManagement extends React.Component {
         {isBasicEnabled && (
         <React.Fragment>
           <div className="row mb-5">
-            <div className="offset-3 col-6">
+            <div className="offset-md-3 col-md-6">
               <div className="custom-control custom-checkbox custom-checkbox-success">
                 <input
                   id="bindByEmail-basic"

+ 4 - 4
src/client/js/components/Admin/Security/GoogleSecuritySetting.jsx

@@ -68,8 +68,8 @@ class GoogleSecurityManagement extends React.Component {
           </div>
         )}
 
-        <div className="row mb-5">
-          <div className="offset-3 col-6">
+        <div className="row mb-5 mt-3">
+          <div className="col-12 offset-md-3 col-md-6">
             <div className="custom-control custom-switch custom-checkbox-success">
               <input
                 id="isGoogleEnabled"
@@ -88,8 +88,8 @@ class GoogleSecurityManagement extends React.Component {
         </div>
 
         <div className="row mb-5">
-          <label className="col-3 text-right py-2">{t('security_setting.callback_URL')}</label>
-          <div className="col-6">
+          <label className="col-12 col-md-3 text-left text-md-right py-2">{t('security_setting.callback_URL')}</label>
+          <div className="col-12 col-md-6">
             <input
               className="form-control"
               type="text"

+ 4 - 4
src/client/js/components/Admin/Security/LocalSecuritySetting.jsx

@@ -100,10 +100,10 @@ class LocalSecuritySetting extends React.Component {
             <h3 className="border-bottom">{t('security_setting.configuration')}</h3>
 
             <div className="row">
-              <div className="col-3 text-right py-2">
+              <div className="col-12 col-md-3 text-left text-md-right py-2">
                 <strong>{t('Register limitation')}</strong>
               </div>
-              <div className="col-6">
+              <div className="col-12 col-md-6">
                 <div className="dropdown">
                   <button
                     className="btn btn-outline-secondary dropdown-toggle"
@@ -136,10 +136,10 @@ class LocalSecuritySetting extends React.Component {
               </div>
             </div>
             <div className="row">
-              <div className="col-3 text-right">
+              <div className="col-12 col-md-3 text-left text-md-right">
                 <strong dangerouslySetInnerHTML={{ __html: t('The whitelist of registration permission E-mail address') }} />
               </div>
-              <div className="col-6">
+              <div className="col-12 col-md-6">
                 <textarea
                   className="form-control"
                   type="textarea"

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

@@ -69,7 +69,7 @@ class TwitterSecurityManagement extends React.Component {
         )}
 
         <div className="row mb-5">
-          <div className="offset-3 col-6">
+          <div className="offset-md-3 col-md-6">
             <div className="custom-control custom-switch custom-checkbox-success">
               <input
                 id="isTwitterEnabled"
@@ -88,8 +88,8 @@ class TwitterSecurityManagement extends React.Component {
         </div>
 
         <div className="row mb-5">
-          <label className="col-3 text-right py-2">{t('security_setting.callback_URL')}</label>
-          <div className="col-6">
+          <label className="col-md-3 text-md-right py-2">{t('security_setting.callback_URL')}</label>
+          <div className="col-md-6">
             <input
               className="form-control"
               type="text"
@@ -116,8 +116,8 @@ class TwitterSecurityManagement extends React.Component {
             <h3 className="border-bottom">{t('security_setting.configuration')}</h3>
 
             <div className="row mb-5">
-              <label htmlFor="TwitterConsumerId" className="col-3 text-right py-2">{t('security_setting.clientID')}</label>
-              <div className="col-6">
+              <label htmlFor="TwitterConsumerId" className="col-md-3 text-md-right py-2">{t('security_setting.clientID')}</label>
+              <div className="col-md-6">
                 <input
                   className="form-control"
                   type="text"
@@ -132,8 +132,8 @@ class TwitterSecurityManagement extends React.Component {
             </div>
 
             <div className="row mb-5">
-              <label htmlFor="TwitterConsumerSecret" className="col-3 text-right py-2">{t('security_setting.client_secret')}</label>
-              <div className="col-6">
+              <label htmlFor="TwitterConsumerSecret" className="col-md-3 text-md-right py-2">{t('security_setting.client_secret')}</label>
+              <div className="col-md-6">
                 <input
                   className="form-control"
                   type="text"
@@ -148,7 +148,7 @@ class TwitterSecurityManagement extends React.Component {
             </div>
 
             <div className="row mb-5">
-              <div className="offset-3 col-6">
+              <div className="offset-md-3 col-md-6">
                 <div className="custom-control custom-checkbox custom-checkbox-success">
                   <input
                     id="bindByUserNameTwitter"
@@ -170,7 +170,7 @@ class TwitterSecurityManagement extends React.Component {
             </div>
 
             <div className="row my-3">
-              <div className="offset-3 col-5">
+              <div className="offset-4 col-5">
                 <button
                   type="button"
                   className="btn btn-primary"

+ 32 - 70
src/client/js/components/Admin/UserManagement.jsx

@@ -91,6 +91,25 @@ class UserManagement extends React.Component {
     this.props.adminUsersContainer.handleChangeSearchText(event.target.value);
   }
 
+  renderCheckbox(status, statusLabel, statusColor) {
+    return (
+      <div className={`custom-control custom-checkbox custom-checkbox-${statusColor} mr-2`}>
+        <input
+          className="custom-control-input"
+          type="checkbox"
+          id={`c_${status}`}
+          checked={this.props.adminUsersContainer.isSelected(status)}
+          onClick={() => { this.handleClick(status) }}
+        />
+        <label className="custom-control-label" htmlFor={`c_${status}`}>
+          <span className={`badge badge-pill badge-${statusColor} d-inline-block vt mt-1`}>
+            {statusLabel}
+          </span>
+        </label>
+      </div>
+    );
+  }
+
   render() {
     const { t, adminUsersContainer } = this.props;
 
@@ -138,11 +157,10 @@ class UserManagement extends React.Component {
         </p>
 
         <h2>{t('User_Management')}</h2>
-
         <div className="border-top border-bottom">
 
           <div className="d-flex justify-content-start align-items-center my-2">
-            <div>
+            <div className="d-flex align-items-baseline">
               <i className="icon-magnifier mr-1"></i>
               <span className="search-typeahead">
                 <input
@@ -154,70 +172,19 @@ class UserManagement extends React.Component {
               </span>
             </div>
 
-            <div className="mx-5 form-inline">
-              <div className="custom-control custom-checkbox custom-checkbox-primary mr-2">
-                <input
-                  className="custom-control-input"
-                  type="checkbox"
-                  id="c1"
-                  checked={adminUsersContainer.isSelected('all')}
-                  onClick={() => { this.handleClick('all') }}
-                />
-                <label className="custom-control-label" htmlFor="c1">
-                  <span className="badge badge-pill badge-primary d-inline-block vt mt-1">All</span>
-                </label>
-              </div>
-
-              <div className="custom-control custom-checkbox custom-checkbox-info mr-2">
-                <input
-                  className="custom-control-input"
-                  type="checkbox"
-                  id="c2"
-                  checked={adminUsersContainer.isSelected('registered')}
-                  onClick={() => { this.handleClick('registered') }}
-                />
-                <label className="custom-control-label" htmlFor="c2">
-                  <span className="badge badge-pill badge-info d-inline-block vt mt-1">Approval Pending</span>
-                </label>
-              </div>
-
-              <div className="custom-control custom-checkbox custom-checkbox-success mr-2">
-                <input
-                  className="custom-control-input"
-                  type="checkbox"
-                  id="c3"
-                  checked={adminUsersContainer.isSelected('active')}
-                  onClick={() => { this.handleClick('active') }}
-                />
-                <label className="custom-control-label" htmlFor="c3">
-                  <span className="badge badge-pill badge-success d-inline-block vt mt-1">Active</span>
-                </label>
-              </div>
-
-              <div className="custom-control custom-checkbox custom-checkbox-warning mr-2">
-                <input
-                  className="custom-control-input"
-                  type="checkbox"
-                  id="c4"
-                  checked={adminUsersContainer.isSelected('suspended')}
-                  onClick={() => { this.handleClick('suspended') }}
-                />
-                <label className="custom-control-label" htmlFor="c4">
-                  <span className="badge badge-pill badge-warning d-inline-block vt mt-1">Suspended</span>
-                </label>
+            <div className="mx-5">
+              <div className="form-inline">
+                {this.renderCheckbox('all', 'All', 'primary')}
+                {this.renderCheckbox('registered', 'Approval Pending', 'info')}
+                {this.renderCheckbox('active', 'Active', 'success')}
+                {this.renderCheckbox('suspended', 'Suspended', 'warning')}
+                {this.renderCheckbox('invited', 'Invited', 'info')}
               </div>
-
-              <div className="custom-control custom-checkbox custom-checkbox-info">
-                <input
-                  className="custom-control-input"
-                  type="checkbox"
-                  id="c5"
-                  checked={adminUsersContainer.isSelected('invited')}
-                  onClick={() => { this.handleClick('invited') }}
-                />
-                <label className="custom-control-label" htmlFor="c5">
-                  <span className="badge badge-pill badge-info d-inline-block vt mt-1">Invited</span>
-                </label>
+              <div>
+                {
+                  this.state.isNotifyCommentShow
+                  && <span className="text-warning">{t('admin:user_management.click_twice_same_checkbox')}</span>
+                }
               </div>
             </div>
 
@@ -234,11 +201,6 @@ class UserManagement extends React.Component {
                 Reset
               </button>
             </div>
-
-            <div className="ml-4">
-              {this.state.isNotifyCommentShow && <span className="text-warning">{t('admin:user_management.click_twice_same_checkbox')}</span>}
-            </div>
-
           </div>
         </div>
 

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

@@ -65,7 +65,7 @@ class ApiSettings extends React.Component {
 
 
         <div className="row">
-          <div className="offset-lg-1 col-lg-7">
+          <div className="offset-lg-2 col-lg-7">
 
             <p className="alert alert-warning">
               { t('page_me_apitoken.notice.update_token1') }<br />

+ 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>
   );
 
 };

+ 2 - 2
src/client/js/components/PageEditorByHackmd.jsx

@@ -376,10 +376,10 @@ class PageEditorByHackmd extends React.Component {
 
         { this.state.hasError && (
           <div className="hackmd-error position-absolute d-flex flex-column justify-content-center align-items-center">
-            <div className="white-box text-center">
+            <div className="bg-box p-5 text-center">
               <h2 className="text-warning"><i className="icon-fw icon-exclamation"></i> {t('hackmd.integration_failed')}</h2>
               <h4>{this.state.errorMessage}</h4>
-              <p className="well well-sm text-danger">
+              <p className="card well well-sm text-danger">
                 {this.state.errorReason}
               </p>
               {/* eslint-disable-next-line react/no-danger */}

+ 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;

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

@@ -60,6 +60,16 @@ body.on-edit {
     display: none;
   }
 
+  &.hackmd .grw-nav-item-edit {
+    display: none;
+  }
+
+  &.hackmd {
+    #page-editor-options-selector {
+      display: none !important;
+    }
+  }
+
   &:not(.hackmd) .nav-tab-hackmd {
     display: none;
   }

+ 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 {
+}

+ 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 {

+ 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';

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

@@ -25,11 +25,6 @@ body.kibela {
     background-color: $bgcolor-global;
   }
 
-  /* header*/
-  .background-t {
-    background-color: transparent;
-  }
-
   .search-input-group,
   .search-typeahead {
     .btn {
@@ -160,11 +155,6 @@ body.kibela {
     }
   }
 
-  /* subnavbar */
-  .grw-subnavbar {
-    background: transparent;
-  }
-
   /* navbar */
   .grw-navbar {
     .nav-item > .nav-link:hover {

+ 22 - 12
src/client/styles/scss/theme/_apply-colors.scss

@@ -40,6 +40,21 @@ $link-hover-color: $color-link-hover;
   }
 }
 
+// List Group
+.list-group {
+  .list-group-item {
+    color: $color-list;
+    background-color: $bgcolor-list;
+    &:hover {
+      background-color: $color-list-hover;
+    }
+    &.active {
+      color: $color-list-active;
+      background-color: $bgcolor-list-active;
+    }
+  }
+}
+
 // Form
 .form-control {
   @include form-control-focus();
@@ -167,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
  */
@@ -308,3 +311,10 @@ mark.rbt-highlight-text {
     }
   }
 }
+
+/*
+ * HackMd
+ */
+.bg-box {
+  background-color: $bgcolor-global;
+}

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

@@ -63,6 +63,13 @@ html[light] {
   $color-link-nabvar: $color-reversal;
   $color-inline-code: #c7254e;
 
+  // List Group colors
+  $color-list: $color-global;
+  $bgcolor-list: $bgcolor-global;
+  $color-list-active: $color-reversal;
+  $bgcolor-list-active: $primary;
+  $color-list-hover: $color-reversal;
+
   // Logo colors
   $bgcolor-logo: $bgcolor-navbar;
   $fillcolor-logo-mark: lighten(desaturate($bgcolor-navbar, 10%), 15%);
@@ -109,6 +116,13 @@ html[dark] {
   $color-link-nabvar: $color-global;
   $color-inline-code: #c7254e;
 
+  // List Group colors
+  $color-list: $color-global;
+  $bgcolor-list: $bgcolor-global;
+  $color-list-active: $color-reversal;
+  $bgcolor-list-active: $primary;
+  $color-list-hover: $color-reversal;
+
   // Logo colors
   $bgcolor-logo: $bgcolor-navbar;
   $fillcolor-logo-mark: #444;

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

@@ -17,7 +17,6 @@
 //
 html[light] {
   $primary: #112744;
-  $light: white;
 
   // Background colors
   $bgcolor-global: white;
@@ -36,6 +35,13 @@ html[light] {
   $color-link-nabvar: $color-reversal;
   $color-inline-code: #c7254e;
 
+  // List Group colors
+  $color-list: $color-global;
+  $bgcolor-list: $bgcolor-global;
+  $color-list-active: $color-reversal;
+  $bgcolor-list-active: $primary;
+  $color-list-hover: $color-reversal;
+
   // Logo colors
   $bgcolor-logo: $bgcolor-navbar;
   $fillcolor-logo-mark: lighten(desaturate($bgcolor-navbar, 10%), 15%);
@@ -62,7 +68,6 @@ html[light] {
 //
 html[dark] {
   $primary: #d65a31;
-  $light: white;
 
   $basecolor: #222831;
 
@@ -83,6 +88,13 @@ html[dark] {
   $color-link-nabvar: $color-global;
   $color-inline-code: #c7254e;
 
+  // List Group colors
+  $color-list: $color-global;
+  $bgcolor-list: $bgcolor-global;
+  $color-list-active: $color-global;
+  $bgcolor-list-active: $primary;
+  $color-list-hover: $color-reversal;
+
   // Logo colors
   $bgcolor-logo: $bgcolor-navbar;
   $fillcolor-logo-mark: #444;

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

@@ -25,6 +25,13 @@ html[light] {
   $primary: $bgcolor-theme;
   $info: lighten($bgcolor-theme, 20%);
 
+  // List Group colors
+  $color-list: $color-global;
+  $bgcolor-list: $bgcolor-global;
+  $color-list-active: $color-reversal;
+  $bgcolor-list-active: $primary;
+  $color-list-hover: $color-reversal;
+
   // Logo colors
   $bgcolor-logo: transparent;
   $fillcolor-logo-mark: lighten($bgcolor-theme, 20%);
@@ -74,6 +81,13 @@ html[dark] {
   $primary: $bgcolor-theme;
   $info: lighten($bgcolor-theme, 20%);
 
+  // List Group colors
+  $color-list: $color-global;
+  $bgcolor-list: $bgcolor-global;
+  $color-list-active: $color-reversal;
+  $bgcolor-list-active: $primary;
+  $color-list-hover: $color-reversal;
+
   // Logo colors
   $bgcolor-logo: red;
   $fillcolor-logo-mark: lighten($bgcolor-theme, 20%);

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

@@ -12,7 +12,7 @@
 <div class="page-editor-footer d-flex flex-row align-items-center justify-content-between">
 
   <div>
-    <div id="page-editor-options-selector" class="d-none d-sm-block"></div>
+    <div id="page-editor-options-selector" class="d-none d-md-block"></div>
   </div>
 
   <div id="save-page-controls"

+ 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 #}