|
60 | 60 | </div> |
61 | 61 | </div> |
62 | 62 | <div class="form-group mb-3"> |
63 | | - <label for="password">{{ __('Password') }}</label> |
| 63 | + <div class="password-field-header"> |
| 64 | + <label for="password">{{ __('Password') }}</label> |
| 65 | + <span id="capsLockWarning" class="caps-lock-warning" hidden aria-live="polite"> |
| 66 | + <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> |
| 67 | + {{ __('Caps lock is on') }} |
| 68 | + </span> |
| 69 | + </div> |
64 | 70 | <div class="password-container"> |
65 | 71 | <input id="password" type="password" class="form-control form-control-login {{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" placeholder="{{__('Enter your password')}}" required> |
66 | 72 | <i class="fa fa-eye" id="togglePassword"></i> |
@@ -148,12 +154,29 @@ class="login-remember-input" |
148 | 154 |
|
149 | 155 | const togglePassword = document.querySelector('#togglePassword'); |
150 | 156 | const password = document.querySelector('#password'); |
| 157 | + const capsLockWarning = document.querySelector('#capsLockWarning'); |
151 | 158 |
|
152 | 159 | togglePassword.addEventListener('click', function (e) { |
153 | 160 | const type = password.getAttribute('type') === 'password' ? 'text' : 'password'; |
154 | 161 | password.setAttribute('type', type); |
155 | 162 | this.classList.toggle('fa-eye-slash'); |
156 | | -}); |
| 163 | + }); |
| 164 | +
|
| 165 | + function updateCapsLockWarning(event) { |
| 166 | + if (!password || !capsLockWarning || !event.getModifierState) { |
| 167 | + return; |
| 168 | + } |
| 169 | +
|
| 170 | + capsLockWarning.hidden = !event.getModifierState('CapsLock'); |
| 171 | + } |
| 172 | +
|
| 173 | + if (password && capsLockWarning) { |
| 174 | + password.addEventListener('keydown', updateCapsLockWarning); |
| 175 | + password.addEventListener('keyup', updateCapsLockWarning); |
| 176 | + password.addEventListener('blur', function () { |
| 177 | + capsLockWarning.hidden = true; |
| 178 | + }); |
| 179 | + } |
157 | 180 | </script> |
158 | 181 | <script src="{{ mix('builds/login/js/manifest.js') }}"></script> |
159 | 182 | <script src="{{ mix('builds/login/js/vendor.js') }}"></script> |
@@ -228,6 +251,33 @@ class="login-remember-input" |
228 | 251 | margin-bottom: 0.5rem; |
229 | 252 | } |
230 | 253 |
|
| 254 | + .password-field-header { |
| 255 | + align-items: center; |
| 256 | + display: flex; |
| 257 | + gap: 0.75rem; |
| 258 | + justify-content: space-between; |
| 259 | + margin-bottom: 0.5rem; |
| 260 | + } |
| 261 | +
|
| 262 | + .password-field-header label { |
| 263 | + margin-bottom: 0; |
| 264 | + } |
| 265 | +
|
| 266 | + .caps-lock-warning { |
| 267 | + align-items: center; |
| 268 | + color: #C66E00; |
| 269 | + display: inline-flex; |
| 270 | + font-size: 0.75rem; |
| 271 | + font-weight: 500; |
| 272 | + gap: 0.375rem; |
| 273 | + line-height: 1.25rem; |
| 274 | + white-space: nowrap; |
| 275 | + } |
| 276 | +
|
| 277 | + .caps-lock-warning[hidden] { |
| 278 | + display: none !important; |
| 279 | + } |
| 280 | +
|
231 | 281 | .background-cover { |
232 | 282 | background-color: #002D59; |
233 | 283 | background-image: url('{{ asset('img/decisions-bg-pattern.svg') }}'); |
|
0 commit comments