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

Merge branch 'master' into support/share-link-for-outside-for-merge

itizawa 5 лет назад
Родитель
Сommit
a8c1a252d5

+ 7 - 0
CHANGES.md

@@ -2,7 +2,14 @@
 
 ## v4.0.3-RC
 
+* Feature: Copy page path dropdown with Append params switch
+* Improvement: Truncate overflowed user browsing history
+* Improvement: Tabs appearance on mobile
+* Improvement: Search help appearance on mobile
+* Improvement: Accessibility of login page
+* Fix: Editor was broken by long lines
 * Fix: Editor doesn't work on mobile
+* Fix: Word break in Recent Updated contents
 * Fix: navbar is broken on Safari
 
 ## v4.0.2

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

@@ -61,8 +61,8 @@
   "No diff": "No diff",
   "Shrink versions that have no diffs": "Shrink versions that have no diffs",
   "User ID": "User ID",
-  "User's Home": "User's Home",
-  "User Settings": "User Settings",
+  "Home": "Home",
+  "Settings": "Settings",
   "User Information": "User information",
   "Basic Info": "Basic info",
   "Name": "Name",

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

@@ -61,8 +61,8 @@
   "No diff": "差分なし",
   "Shrink versions that have no diffs": "差分のないバージョンをコンパクトに表示する",
   "User ID": "ユーザーID",
-  "User's Home": "ユーザーホーム",
-  "User Settings": "ユーザー設定",
+  "Home": "ホーム",
+  "Settings": "設定",
   "User Information": "ユーザー情報",
   "Basic Info": "ユーザーの基本情報",
   "Name": "名前",

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

@@ -26,7 +26,6 @@ import PageShareManagement from './components/Page/PageShareManagement';
 import TrashPageAlert from './components/Page/TrashPageAlert';
 import PageAttachment from './components/PageAttachment';
 import PageStatusAlert from './components/PageStatusAlert';
-import PagePathAutoComplete from './components/PagePathAutoComplete';
 import RecentCreated from './components/RecentCreated/RecentCreated';
 import MyDraftList from './components/MyDraftList/MyDraftList';
 import UserPictureList from './components/User/UserPictureList';
@@ -97,7 +96,6 @@ if (pageContainer.state.pageId != null) {
     'revision-toc': <TableOfContents />,
     'seen-user-list': <UserPictureList userIds={pageContainer.state.seenUserIds} />,
     'liker-list': <UserPictureList userIds={pageContainer.state.likerUserIds} />,
-    'rename-page-name-input': <PagePathAutoComplete crowi={appContainer} initializedPath={pageContainer.state.path} />,
 
     'user-created-list': <RecentCreated />,
     'user-draft-list': <MyDraftList />,

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

@@ -59,7 +59,7 @@ class CustomizeScriptSetting extends React.Component {
               Placeholders:<br />
               (Available after <code>load</code> event)
             </div>
-            <table className="table table-borderless table-sm form-text text-muted offset-1">
+            <table className="table table-borderless table-sm form-text text-muted offset-1 col-11">
               <tbody>
                 <tr>
                   <th className="text-right"><code>$</code></th>

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

@@ -116,7 +116,7 @@ class LoginForm extends React.Component {
 
     return (
       <>
-        <div className="border-top border-bottom">
+        <div className="grw-external-auth-form border-top border-bottom">
           <div id="external-auth" className={`external-auth ${collapsibleClass}`}>
             <div className="row mt-2">
               {Object.keys(objOfIsExternalAuthEnableds).map((auth) => {
@@ -131,7 +131,7 @@ class LoginForm extends React.Component {
         <div className="text-center">
           <button
             type="button"
-            className="btn btn-secondary btn-sm rounded-0 mb-3"
+            className="btn btn-secondary btn-external-auth-tab btn-sm rounded-0 mb-3"
             data-toggle={isExternalAuthCollapsible ? 'collapse' : ''}
             data-target="#external-auth"
             aria-expanded="false"

+ 18 - 3
src/client/js/components/Navbar/PersonalDropdown.jsx

@@ -65,8 +65,23 @@ const PersonalDropdown = (props) => {
       {/* Menu */}
       <div className="dropdown-menu dropdown-menu-right">
 
-        <a className="dropdown-item" href={`/user/${user.username}`}><i className="icon-fw icon-user"></i>{ t('User\'s Home') }</a>
-        <a className="dropdown-item" href="/me"><i className="icon-fw icon-wrench"></i>{ t('User Settings') }</a>
+        <div className="px-4 pt-3 pb-2 text-center">
+          <UserPicture user={user} size="lg" noLink noTooltip />
+
+          <h5 className="mt-2">
+            {user.name}
+          </h5>
+
+          <div className="my-2">
+            <i className="icon-user icon-fw"></i>{user.username}<br />
+            <i className="icon-envelope icon-fw"></i><span className="grw-email-sm">{user.email}</span>
+          </div>
+
+          <div className="btn-group btn-block mt-2" role="group">
+            <a className="btn btn-sm btn-outline-secondary" href={`/user/${user.username}`}><i className="icon-fw icon-home"></i>{ t('Home') }</a>
+            <a className="btn btn-sm btn-outline-secondary" href="/me"><i className="icon-fw icon-wrench"></i>{ t('Settings') }</a>
+          </div>
+        </div>
 
         <div className="dropdown-divider"></div>
 
@@ -107,7 +122,7 @@ const PersonalDropdown = (props) => {
 
         <div className="dropdown-divider"></div>
 
-        <a className="dropdown-item" onClick={logoutHandler}><i className="icon-fw icon-power"></i>{ t('Sign out') }</a>
+        <button type="button" className="dropdown-item" onClick={logoutHandler}><i className="icon-fw icon-power"></i>{ t('Sign out') }</button>
       </div>
 
     </>

+ 35 - 16
src/client/js/components/Page/CopyDropdown.jsx

@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
 import {
-  Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
+  UncontrolledDropdown, DropdownToggle, DropdownMenu, DropdownItem,
   Tooltip,
 } from 'reactstrap';
 
@@ -18,6 +18,7 @@ class CopyDropdown extends React.Component {
     this.state = {
       dropdownOpen: false,
       tooltipOpen: false,
+      isParamsAppended: true,
     };
 
     this.toggle = this.toggle.bind(this);
@@ -39,13 +40,22 @@ class CopyDropdown extends React.Component {
     }, 1000);
   }
 
-  generatePagePathWithParams() {
-    const { pagePath } = this.props;
+  get uriParams() {
+    const { isParamsAppended } = this.state;
+
+    if (!isParamsAppended) {
+      return '';
+    }
+
     const {
       search, hash,
     } = window.location;
+    return `${search}${hash}`;
+  }
 
-    return `${pagePath}${search}${hash}`;
+  generatePagePathWithParams() {
+    const { pagePath } = this.props;
+    return decodeURI(`${pagePath}${this.uriParams}`);
   }
 
   generatePagePathUrl() {
@@ -55,25 +65,18 @@ class CopyDropdown extends React.Component {
 
   generatePermalink() {
     const { pageId } = this.props;
-    const { location } = window;
 
     if (pageId == null) {
       return null;
     }
 
-    const {
-      origin, search, hash,
-    } = location;
-    return `${origin}/${pageId}${search}${hash}`;
+    return decodeURI(`${origin}/${pageId}${this.uriParams}`);
   }
 
   generateMarkdownLink() {
     const { pagePath } = this.props;
-    const {
-      search, hash,
-    } = window.location;
 
-    const label = `${pagePath}${search}${hash}`;
+    const label = decodeURI(`${pagePath}${this.uriParams}`);
     const permalink = this.generatePermalink();
 
     return `[${label}](${permalink})`;
@@ -88,6 +91,7 @@ class CopyDropdown extends React.Component {
 
   render() {
     const { t, pageId } = this.props;
+    const { isParamsAppended } = this.state;
 
     const pagePathWithParams = this.generatePagePathWithParams();
     const pagePathUrl = this.generatePagePathUrl();
@@ -97,7 +101,7 @@ class CopyDropdown extends React.Component {
 
     return (
       <>
-        <Dropdown id="copyPagePathDropdown" className="grw-copy-dropdown" isOpen={this.state.dropdownOpen} toggle={this.toggle}>
+        <UncontrolledDropdown id="copyPagePathDropdown" className="grw-copy-dropdown">
 
           <DropdownToggle
             caret
@@ -108,7 +112,22 @@ class CopyDropdown extends React.Component {
           </DropdownToggle>
 
           <DropdownMenu>
-            <DropdownItem header className="px-3">{ t('copy_to_clipboard.Copy to clipboard') }</DropdownItem>
+
+            <div className="d-flex align-items-center justify-content-between">
+              <DropdownItem header className="px-3">
+                { t('copy_to_clipboard.Copy to clipboard') }
+              </DropdownItem>
+              <div className="px-3 custom-control custom-switch custom-switch-sm">
+                <input
+                  type="checkbox"
+                  id="customSwitchForParams"
+                  className="custom-control-input"
+                  checked={isParamsAppended}
+                  onChange={e => this.setState({ isParamsAppended: !isParamsAppended })}
+                />
+                <label className="custom-control-label small" htmlFor="customSwitchForParams">Append params</label>
+              </div>
+            </div>
 
             <DropdownItem divider className="my-0"></DropdownItem>
 
@@ -162,7 +181,7 @@ class CopyDropdown extends React.Component {
             )}
           </DropdownMenu>
 
-        </Dropdown>
+        </UncontrolledDropdown>
 
         <Tooltip placement="bottom" isOpen={this.state.tooltipOpen} target="copyPagePathDropdown" fade={false}>
           copied!

+ 0 - 1
src/client/js/components/PageDuplicateModal.jsx

@@ -82,7 +82,6 @@ const PageDuplicateModal = (props) => {
                 <PagePathAutoComplete
                   crowi={appContainer}
                   initializedPath={path}
-                  addTrailingSlash
                   onSubmit={ppacSubmitHandler}
                   onInputChange={ppacInputChangeHandler}
                 />

+ 0 - 1
src/client/js/components/PagePathAutoComplete.jsx

@@ -61,7 +61,6 @@ PagePathAutoComplete.propTypes = {
 
 PagePathAutoComplete.defaultProps = {
   initializedPath: '/',
-  addTrailingSlash: true,
 };
 
 export default PagePathAutoComplete;

+ 5 - 4
src/client/js/services/AppContainer.js

@@ -119,9 +119,9 @@ export default class AppContainer extends Container {
   }
 
   async initColorScheme() {
-    const switchStateByMediaQuery = (mql) => {
+    const switchStateByMediaQuery = async(mql) => {
       const preferDarkMode = mql.matches;
-      this.setState({ preferDarkModeByMediaQuery: preferDarkMode });
+      await this.setState({ preferDarkModeByMediaQuery: preferDarkMode });
 
       this.applyColorScheme();
     };
@@ -130,13 +130,13 @@ export default class AppContainer extends Container {
     // add event listener
     mqlForDarkMode.addListener(switchStateByMediaQuery);
 
-    // restore settings from localStorage
+    // initialize1: restore settings from localStorage
     const { localStorage } = window;
     if (localStorage.preferDarkModeByUser != null) {
       await this.setState({ preferDarkModeByUser: localStorage.preferDarkModeByUser === 'true' });
     }
 
-    // initialize
+    // initialize2: check media query
     switchStateByMediaQuery(mqlForDarkMode);
   }
 
@@ -413,6 +413,7 @@ export default class AppContainer extends Container {
    */
   applyColorScheme() {
     const { preferDarkModeByMediaQuery, preferDarkModeByUser } = this.state;
+
     let isDarkMode = preferDarkModeByMediaQuery;
     if (preferDarkModeByUser != null) {
       isDarkMode = preferDarkModeByUser;

+ 10 - 55
src/client/styles/scss/_login.scss

@@ -1,12 +1,4 @@
 .nologin {
-  $gray-800-for-login: darken(white, 30%);
-  $color-gradient: #3e4d6c;
-
-  // background color
-  background: linear-gradient(45deg, darken($color-gradient, 30%) 0%, hsla(340, 100%, 55%, 0) 70%),
-    linear-gradient(135deg, $growi-green 10%, hsla(225, 95%, 50%, 0) 70%), linear-gradient(225deg, $growi-blue 10%, hsla(140, 90%, 50%, 0) 80%),
-    linear-gradient(315deg, darken($color-gradient, 25%) 100%, hsla(35, 95%, 55%, 0) 70%);
-
   #page-wrapper {
     background: none;
   }
@@ -62,43 +54,20 @@
 
   // styles
   .login-header {
-    background-color: rgba(white, 0.5);
-
-    .logo {
-      background-color: rgba(black, 0);
-      fill: rgba(black, 0.5);
-    }
-
     h1 {
       font-size: 22px;
       line-height: 1em;
-      color: rgba(black, 0.5);
     }
   }
 
-  .login-dialog {
-    background-color: rgba(white, 0.5);
-  }
-
   .input-group {
     margin-bottom: 10px;
 
     .input-group-text {
-      color: $gray-800-for-login;
       text-align: center;
-      background-color: rgba(black, 0.4);
       border: none;
       border-radius: 0;
     }
-
-    .form-control {
-      color: white;
-      background-color: rgba(lighten(black, 10%), 0.4);
-
-      &::placeholder {
-        color: $gray-800-for-login;
-      }
-    }
   }
 
   .input-group:not(.has-error) {
@@ -114,39 +83,39 @@
   $btn-fill-colors: (
     'login': (
       rgba($danger, 0.4),
-      rgba(#7e4153, 0.5),
+      rgba(#7e4153, 0.7),
     ),
     'register': (
       rgba($success, 0.4),
-      rgba(#3f7263, 0.5),
+      rgba(#3f7263, 0.7),
     ),
     'google': (
       rgba(#24292e, 0.4),
-      #555,
+      #444,
     ),
     'github': (
       rgba(lighten(black, 20%), 0.4),
-      #555,
+      #444,
     ),
     'facebook': (
       rgba(#29487d, 0.4),
-      #555,
+      #444,
     ),
     'twitter': (
       rgba(#1da1f2, 0.4),
-      #555,
+      #444,
     ),
     'oidc': (
       rgba(#24292e, 0.4),
-      #555,
+      #444,
     ),
     'saml': (
       rgba(#55a79a, 0.4),
-      #555,
+      #444,
     ),
     'basic': (
       rgba(#24292e, 0.4),
-      #555,
+      #444,
     ),
   );
 
@@ -165,26 +134,12 @@
   .link-growi-org {
     font-size: smaller;
     font-weight: bold;
-    color: rgba(black, 0.4);
 
     &,
     .growi,
     .org {
       transition: color 0.8s;
     }
-
-    &:hover,
-    &.focus {
-      color: black;
-
-      .growi {
-        color: darken($growi-green, 20%);
-      }
-
-      .org {
-        color: darken($growi-blue, 15%);
-      }
-    }
   }
 
   .link-switch {
@@ -210,7 +165,7 @@
   .link-growi-org {
     position: absolute;
     bottom: 9px;
-    z-index: 2;
+    z-index: 3;
   }
 
   // To adjust the behavior, this problem is not solved.

+ 10 - 5
src/client/styles/scss/_navbar.scss

@@ -4,6 +4,10 @@
   border-bottom: $grw-navbar-border-width solid;
   border-left: 0;
 
+  .grw-app-title {
+    @include variable-font-size(24px);
+  }
+
   .grw-navbar-toggler {
     padding: 0.5rem;
     font-size: 1.5em;
@@ -23,11 +27,6 @@
     padding: 0 1rem;
   }
 
-  #personal-dropdown::after {
-    // hide caret
-    content: none;
-  }
-
   .nav-link {
     &:hover {
       background: rgba(0, 0, 0, 0.1);
@@ -40,4 +39,10 @@
   .nav-item.confidential {
     background: rgba(0, 0, 0, 0.2);
   }
+
+  .grw-personal-dropdown {
+    .grw-email-sm {
+      font-size: 0.75em;
+    }
+  }
 }

+ 3 - 3
src/client/styles/scss/_override-bootstrap.scss

@@ -77,13 +77,13 @@
   }
 
   // Dropdowns
-  .dropdown {
-    .dropdown-toggle.btn.disabled {
+  .dropdown-toggle {
+    &.btn.disabled {
       cursor: not-allowed;
     }
 
     // hide caret
-    .dropdown-toggle.dropdown-toggle-no-caret::after {
+    &.dropdown-toggle-no-caret::after {
       content: none;
     }
   }

+ 1 - 1
src/client/styles/scss/atoms/_buttons.scss

@@ -41,7 +41,7 @@
   color: white;
   text-align: center;
   cursor: pointer;
-  background-color: rgba(lighten(black, 20%), 0.4);
+  background-color: rgba(lighten(black, 15%), 0.5);
   border: none;
 
   .btn-label {

+ 31 - 0
src/client/styles/scss/atoms/_custom_control.scss

@@ -1,3 +1,34 @@
 label.custom-control-label {
   font-weight: normal;
 }
+
+.custom-switch.custom-switch-sm {
+  $custom-control-indicator-size-sm: $custom-control-indicator-size * 0.8;
+  $custom-switch-width-sm: $custom-control-indicator-size-sm * 1.75;
+  $custom-control-gutter-sm: $custom-control-gutter * 0.8;
+  $custom-control-indicator-size-sm: $custom-control-indicator-size * 0.8;
+  $custom-switch-indicator-size-sm: subtract($custom-control-indicator-size-sm, $custom-control-indicator-border-width * 4);
+
+  padding-left: $custom-switch-width-sm + $custom-control-gutter-sm;
+
+  .custom-control-label {
+    &::before {
+      left: -($custom-switch-width-sm + $custom-control-gutter-sm);
+      width: $custom-switch-width-sm;
+      height: $custom-control-indicator-size-sm;
+    }
+
+    &::after {
+      top: add(($font-size-base * $line-height-base - $custom-control-indicator-size) / 2, $custom-control-indicator-border-width * 2);
+      left: add(-($custom-switch-width-sm + $custom-control-gutter-sm), $custom-control-indicator-border-width * 2);
+      width: $custom-switch-indicator-size-sm;
+      height: $custom-switch-indicator-size-sm;
+    }
+  }
+
+  .custom-control-input:checked ~ .custom-control-label {
+    &::after {
+      transform: translateX($custom-switch-width-sm - $custom-control-indicator-size-sm);
+    }
+  }
+}

+ 2 - 0
src/client/styles/scss/molecules/copy-dropdown.scss

@@ -1,5 +1,7 @@
 .grw-copy-dropdown {
   .dropdown-menu {
+    min-width: 310px;
+
     .dropdown-header {
       margin-bottom: 0.5em;
       font-size: 1.1em;

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

@@ -94,6 +94,87 @@ ul.pagination {
   }
 }
 
+/*
+ * GROWI Login form
+ */
+.nologin {
+  // background color
+  $color-gradient: #3c465c;
+  background: linear-gradient(45deg, darken($color-gradient, 30%) 0%, hsla(340, 100%, 55%, 0) 70%),
+    linear-gradient(135deg, darken($growi-green, 30%) 10%, hsla(225, 95%, 50%, 0) 70%),
+    linear-gradient(225deg, darken($growi-blue, 20%) 10%, hsla(140, 90%, 50%, 0) 80%),
+    linear-gradient(315deg, darken($color-gradient, 25%) 100%, hsla(35, 95%, 55%, 0) 70%);
+
+  .login-header {
+    background-color: rgba(black, 0.5);
+
+    .logo {
+      background-color: rgba(white, 0);
+      fill: rgba(white, 0.5);
+    }
+
+    h1 {
+      color: rgba(white, 0.5);
+    }
+  }
+
+  .login-dialog {
+    background-color: rgba(black, 0.5);
+  }
+
+  .input-group {
+    .input-group-text {
+      color: darken(white, 30%);
+      background-color: rgba(#444, 0.7);
+    }
+
+    .form-control {
+      color: white;
+      background-color: rgba(#505050, 0.7);
+      box-shadow: unset;
+
+      &::placeholder {
+        color: darken(white, 30%);
+      }
+    }
+  }
+
+  .btn-fill {
+    .btn-label {
+      color: #ccc;
+    }
+    .btn-label-text {
+      color: #aaa;
+    }
+  }
+
+  .grw-external-auth-form {
+    border-color: gray !important;
+  }
+
+  .btn-external-auth-tab {
+    @extend .btn-dark;
+  }
+
+  // footer link text
+  .link-growi-org {
+    color: rgba(white, 0.4);
+
+    &:hover,
+    &.focus {
+      color: rgba(white, 0.7);
+
+      .growi {
+        color: darken($growi-green, 5%);
+      }
+
+      .org {
+        color: darken($growi-blue, 5%);
+      }
+    }
+  }
+}
+
 /*
  * GROWI page list
  */

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

@@ -38,6 +38,69 @@ $table-hover-bg: $bgcolor-table-hover;
   background-color: darken($bgcolor-global, 5%);
 }
 
+/*
+ * GROWI Login form
+ */
+.nologin {
+  // background color
+  $color-gradient: #3e4d6c;
+  background: linear-gradient(45deg, darken($color-gradient, 30%) 0%, hsla(340, 100%, 55%, 0) 70%),
+    linear-gradient(135deg, $growi-green 10%, hsla(225, 95%, 50%, 0) 70%), linear-gradient(225deg, $growi-blue 10%, hsla(140, 90%, 50%, 0) 80%),
+    linear-gradient(315deg, darken($color-gradient, 25%) 100%, hsla(35, 95%, 55%, 0) 70%);
+
+  .login-header {
+    background-color: rgba(white, 0.5);
+
+    .logo {
+      background-color: rgba(black, 0);
+      fill: rgba(black, 0.5);
+    }
+
+    h1 {
+      color: rgba(black, 0.5);
+    }
+  }
+
+  .login-dialog {
+    background-color: rgba(white, 0.5);
+  }
+
+  .input-group {
+    .input-group-text {
+      color: darken(white, 30%);
+      background-color: rgba(#444, 0.7);
+    }
+
+    .form-control {
+      color: white;
+      background-color: rgba(#505050, 0.7);
+      box-shadow: unset;
+
+      &::placeholder {
+        color: darken(white, 30%);
+      }
+    }
+  }
+
+  // footer link text
+  .link-growi-org {
+    color: rgba(black, 0.4);
+
+    &:hover,
+    &.focus {
+      color: black;
+
+      .growi {
+        color: darken($growi-green, 20%);
+      }
+
+      .org {
+        color: darken($growi-blue, 15%);
+      }
+    }
+  }
+}
+
 /*
  * GROWI subnavigation
  */

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

@@ -148,6 +148,10 @@ pre:not(.hljs):not(.CodeMirror-line) {
 
   border-image: $border-image-navbar;
   border-image-slice: 1;
+
+  .grw-app-title {
+    color: $fillcolor-logo-mark;
+  }
 }
 
 .search-top {

+ 10 - 3
src/client/styles/scss/theme/antarctic.scss

@@ -123,9 +123,16 @@ html[dark] {
     }
   }
 
-  a#login.link-switch,
-  a#register.link-switch {
-    color: rgba(black, 0.5);
+  // login and register
+  .nologin {
+    a#login.link-switch,
+    a#register.link-switch {
+      color: rgba(black, 0.5);
+    }
+
+    .grw-external-auth-form {
+      border-color: #aaa !important;
+    }
   }
 }
 

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

@@ -135,22 +135,26 @@ html[dark] {
   // login page
   .nologin {
     .input-group {
-      .input-group-addon {
-        background-color: rgba(lighten(black, 10%), 0.6);
+      .input-group-text {
+        color: #444;
+        background-color: rgba(darken(white, 20%), 0.6);
       }
       .form-control {
-        background-color: rgba(lighten(black, 10%), 0.6);
+        color: #444;
+        background-color: rgba(white, 0.6);
       }
     }
 
-    &.login-page {
-      .login-header,
-      .login-dialog {
-        background-color: rgba(#ccc, 0.5);
-      }
-      .link-switch {
-        color: #bd3425;
-      }
+    .login-header,
+    .login-dialog {
+      background-color: rgba(#ccc, 0.5);
+    }
+    .link-switch {
+      color: #bd3425;
+    }
+
+    .grw-external-auth-form {
+      border-color: #aaa !important;
     }
   }
 

+ 14 - 5
src/client/styles/scss/theme/spring.scss

@@ -104,7 +104,8 @@ html[dark] {
     }
   }
 
-  .growi.login-page {
+  // login and register
+  .nologin {
     #page-wrapper {
       background-color: $themelight;
       background-image: url('/images/themes/spring/spring.svg');
@@ -112,11 +113,19 @@ html[dark] {
       background-position: bottom;
       background-size: cover;
     }
-  }
 
-  a#login.link-switch,
-  a#register.link-switch {
-    color: $color-global;
+    .login-header,
+    .login-dialog {
+      background-color: rgba(black, 0.1);
+    }
+
+    .link-switch {
+      color: $color-global;
+    }
+
+    .grw-external-auth-form {
+      border-color: $accentcolor !important;
+    }
   }
 
   .table {

+ 13 - 7
src/client/styles/scss/theme/wood.scss

@@ -144,14 +144,20 @@ html[dark] {
   }
 
   // login and register
+  .nologin {
+    background: white;
 
-  .login-header,
-  .login-dialog {
-    background-color: rgba(black, 0.1);
-  }
+    .login-header,
+    .login-dialog {
+      background-color: rgba(black, 0.1);
+    }
 
-  a#login.link-switch,
-  a#register.link-switch {
-    color: rgba(black, 0.5);
+    .link-switch {
+      color: rgba(black, 0.5);
+    }
+
+    .grw-external-auth-form {
+      border-color: #aaa !important;
+    }
   }
 }

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

@@ -75,16 +75,18 @@
 
   {% block layout_head_nav %}
   <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-0">
       <a class="grw-logo d-block" href="/">
         {% include '../widget/logo.html' %}
       </a>
     </div>
+    <ul class="navbar-nav d-md-none">
+      <li id="grw-navbar-toggler" class="nav-item"></li>
+    </ul>
+    <div class="grw-app-title d-none d-md-block">
+      {{ appService.getAppTitle() | preventXss }}
+    </div>
 
     {# Navbar Right #}
     <ul class="navbar-nav ml-auto">
@@ -97,7 +99,7 @@
             </a>
           </li>
         {% endif %}
-        <li id="personal-dropdown" class="nav-item dropdown dropdown-toggle"></li>
+        <li id="personal-dropdown" class="grw-personal-dropdown nav-item dropdown dropdown-toggle dropdown-toggle-no-caret"></li>
       {% else %}
         <li id="login-user" class="nav-item"><a class="nav-link" href="/login">Login</a></li>
       {% endif %}