further things around login

This commit is contained in:
2026-03-07 21:21:47 +01:00
parent fb6f87374f
commit 9168730a8a
18 changed files with 408 additions and 42 deletions

View File

@@ -550,6 +550,59 @@
background: transparent;
}
/* ── Logo ── */
.login-logo {
margin-bottom: 1.25rem;
}
.login-logo-img {
max-height: 2.5rem;
max-width: 10rem;
object-fit: contain;
}
/* ── Password toggle ── */
.login-password-wrapper {
position: relative;
display: block;
}
.login-password-wrapper > input {
padding-right: 2.75rem;
}
.login-password-toggle {
position: absolute;
right: 0.5rem;
top: calc(50% - 8px);
transform: translateY(-50%);
display: inline-flex;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
padding: 0;
margin: 0;
background: transparent;
border: 0;
color: var(--app-muted-color);
cursor: pointer;
font-size: 1rem;
border-radius: var(--app-border-radius);
transition: color 0.15s ease;
}
.login-password-toggle:hover {
color: var(--app-contrast);
}
.login-password-toggle:focus-visible {
outline: 2px solid var(--app-primary-focus);
outline-offset: 1px;
}
main.login-main {
min-height: 100dvh;
display: grid;
@@ -693,7 +746,7 @@
display: inline-block;
padding: 0 0.75rem;
font-size: 0.875rem;
color: var(--app-muted);
color: var(--app-muted-color);
background: var(--app-card-background-color);
}
@@ -754,14 +807,6 @@
overflow-wrap: anywhere;
}
.login-tenant-context-title {
margin: 0;
font-size: 0.78rem;
letter-spacing: 0.02em;
text-transform: uppercase;
color: var(--app-muted);
}
.login-tenant-context-name {
margin: 0;
font-size: 11px;
@@ -788,6 +833,8 @@
list-style: none;
margin: 0;
padding: 0;
gap: 10px;
font-size: 0.72rem;
}
@@ -798,20 +845,10 @@
padding: 0;
}
.login-help-links-item + .login-help-links-item::before {
content: "";
display: inline-block;
width: 1px;
height: 0.85em;
margin-right: 0.8rem;
background: color-mix(in srgb, var(--app-muted) 55%, transparent);
transform: translateY(1px);
}
.login-security-note {
font-size: 0.72rem;
margin-bottom: 1px;
color: color-mix(in srgb, var(--app-contrast) 78%, var(--app-muted));
color: color-mix(in srgb, var(--app-contrast) 78%, var(--app-muted-color));
}
.login-security-note i {
@@ -823,7 +860,7 @@
width: 100%;
display: block;
font-size: 9px;
color: color-mix(in srgb, var(--app-muted) 75%, transparent);
color: color-mix(in srgb, var(--app-muted-color) 75%, transparent);
}
form[aria-busy="true"] button[type="submit"],
@@ -832,10 +869,6 @@
cursor: wait;
}
.login-secondary-action {
margin-top: 1rem;
}
@media (prefers-reduced-motion: reduce) {
html[data-theme="dark"] #gradient {
animation: none;

View File

@@ -1,6 +1,7 @@
import './core/app-telemetry.js';
import './components/app-flash-auto-dismiss.js';
import './components/app-password-hints.js';
import './components/app-password-toggle.js';
const focusPrimaryErrorNotice = () => {
const errorNotice = document.querySelector(
@@ -29,6 +30,7 @@ const lockLoginSubmitButtons = () => {
return;
}
submitButton.disabled = true;
submitButton.setAttribute('aria-busy', 'true');
submitButton.dataset.submitState = 'loading';
});
});

View File

@@ -0,0 +1,40 @@
export function initPasswordToggles() {
const inputs = document.querySelectorAll('input[type="password"]');
if (!inputs.length) {return;}
inputs.forEach((input) => {
if (!(input instanceof HTMLInputElement)) {return;}
const label = input.closest('label');
if (!label) {return;}
const wrapper = document.createElement('div');
wrapper.className = 'login-password-wrapper';
const toggle = document.createElement('button');
toggle.type = 'button';
toggle.className = 'login-password-toggle';
toggle.setAttribute('aria-label', 'Show password');
toggle.tabIndex = -1;
toggle.innerHTML = '<i class="bi bi-eye" aria-hidden="true"></i>';
input.replaceWith(wrapper);
wrapper.appendChild(input);
wrapper.appendChild(toggle);
toggle.addEventListener('click', () => {
const isPassword = input.type === 'password';
input.type = isPassword ? 'text' : 'password';
toggle.innerHTML = isPassword
? '<i class="bi bi-eye-slash" aria-hidden="true"></i>'
: '<i class="bi bi-eye" aria-hidden="true"></i>';
toggle.setAttribute('aria-label', isPassword ? 'Hide password' : 'Show password');
input.focus();
});
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initPasswordToggles);
} else {
initPasswordToggles();
}