diff --git a/docs/css/custom.css b/docs/css/custom.css index 03bc49d..76631b8 100644 --- a/docs/css/custom.css +++ b/docs/css/custom.css @@ -1074,3 +1074,252 @@ .comment__replies { margin-top: 0.5rem; } +/* ── Auth pages (login / signup) ───────────────────────────────────────── */ + +.auth-page { + max-width: 420px; + margin: 0 auto; + padding: 1rem 0 3rem; +} + +.auth-page__title { + margin-bottom: 1.5rem; +} + +.auth-card { + border: 1px solid var(--background-color1, #ccc); + border-radius: 10px; + padding: 2rem 1.75rem; + background: var(--background-color); +} + +/* Message banner — always reserves space so the form never shifts */ +.auth-message { + border-radius: 6px; + padding: 0.65rem 0.9rem; + font-size: 0.88rem; + margin-bottom: 1.2rem; + line-height: 1.4; + min-height: 3rem; + box-sizing: border-box; + border: 1px solid transparent; + opacity: 0; + pointer-events: none; + transition: opacity 0.15s ease; +} + +.auth-message.is-visible { + opacity: 1; + pointer-events: auto; +} + +.auth-message--error { + background: rgba(255, 61, 61, 0.1); + border: 1px solid rgba(255, 61, 61, 0.4); + color: #ff3d3d; +} + +[data-theme='dark'] .auth-message--error { + color: #ff3d3d; + background: rgba(255, 61, 61, 0.15); + border-color: rgba(255, 61, 61, 0.5); +} + +.auth-message--success { + background: rgba(39, 174, 96, 0.12); + border: 1px solid rgba(39, 174, 96, 0.4); + color: #1e8449; +} + +[data-theme='dark'] .auth-message--success { + color: #58d68d; + background: rgba(39, 174, 96, 0.18); + border-color: rgba(39, 174, 96, 0.5); +} + +/* Form fields */ +.auth-form { + display: flex; + flex-direction: column; + gap: 1.1rem; +} + +.auth-form__group { + display: flex; + flex-direction: column; + gap: 0.3rem; +} + +.auth-form__label { + font-size: 0.85rem; + font-weight: 600; + color: var(--foreground-color); +} + +.auth-form__input-wrap { + position: relative; + display: flex; + align-items: center; +} + +.auth-form__input-wrap .auth-form__input { + padding-right: 2.5rem; +} + +.auth-form__input { + width: 100%; + box-sizing: border-box; + padding: 0.5rem 0.75rem; + border: 1px solid var(--background-color1, #ccc); + border-radius: 5px; + font-size: 0.9rem; + background: var(--background-color); + color: var(--foreground-color); + transition: + border-color 0.18s ease, + box-shadow 0.18s ease; + outline: none; + font-family: inherit; +} + +.auth-form__input:focus { + border-color: var(--accent-color); + box-shadow: 0 0 0 2px rgba(var(--accent-color-rgb, 17, 51, 233), 0.15); +} + +.auth-form__input::placeholder { + color: var(--foreground-color3, #888); + opacity: 0.7; +} + +.auth-form__eye { + position: absolute; + right: 0.6rem; + background: none; + border: none; + cursor: pointer; + color: var(--foreground-color3, #888); + display: inline-flex; + align-items: center; + padding: 0.2rem; + line-height: 1; + transition: color 0.15s ease; +} + +.auth-form__eye:hover { + color: var(--foreground-color); +} + +.auth-form__hint { + font-size: 0.75rem; + color: var(--foreground-color3, #888); +} + +/* Submit button */ +.auth-form__submit { + margin-top: 0.5rem; + width: 100%; + padding: 0.6rem 1rem; + border: none; + border-radius: 5px; + background: var(--accent-color); + color: var(--background-color, #fff); + font-size: 0.92rem; + font-weight: 600; + font-family: inherit; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.4rem; + transition: opacity 0.18s ease; +} + +.auth-form__submit:hover:not(:disabled) { + opacity: 0.85; +} + +.auth-form__submit:disabled { + cursor: not-allowed; + opacity: 0.6; +} + +.auth-form__submit-loader { + display: inline-flex; + align-items: center; +} + +/* Spinner animation */ +@keyframes auth-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +.spin { + animation: auth-spin 0.8s linear infinite; +} + +/* Footer link */ +.auth-card__footer { + margin-top: 1.4rem; + text-align: center; + font-size: 0.85rem; + color: var(--foreground-color3, #888); +} + +.auth-card__link { + color: var(--accent-color); + text-decoration: none; + font-weight: 600; +} + +.auth-card__link:hover { + text-decoration: underline; +} + +/* Light theme override for submit button text */ +[data-theme='light'] .auth-form__submit { + color: #fff; +} + +/* ── OTP panel ───────────────────────────────────────────────────────────── */ + +.otp-panel__hint { + font-size: 0.87rem; + line-height: 1.5; + color: var(--foreground-color); + margin: 0; +} + +.otp-panel__input { + letter-spacing: 0.25em; + font-size: 1.15rem; + text-align: center; +} + +.otp-panel__resend { + font-size: 0.82rem; + color: var(--foreground-color3, #888); + text-align: center; + margin: 0; +} + +.otp-panel__resend-btn { + background: none; + border: none; + padding: 0; + font: inherit; + font-size: 0.82rem; + color: var(--accent-color); + cursor: pointer; + font-weight: 600; + text-decoration: underline; +} + +.otp-panel__resend-btn:hover { + opacity: 0.8; +} diff --git a/docs/login/index.html b/docs/login/index.html index acb5647..fdea14b 100644 --- a/docs/login/index.html +++ b/docs/login/index.html @@ -5,11 +5,11 @@ Sign Up
-

Login

+

Login

\ No newline at end of file +
\ No newline at end of file diff --git a/docs/signup/index.html b/docs/signup/index.html index 8ccd269..b74ba3d 100644 --- a/docs/signup/index.html +++ b/docs/signup/index.html @@ -5,7 +5,7 @@ Sign Up
-

Sign Up

+

Sign Up

(3-32 characters; letters, numbers, _ and - only)
@@ -24,4 +24,4 @@ -

\ No newline at end of file +

\ No newline at end of file diff --git a/layouts/login/single.html b/layouts/login/single.html index ed0a65c..8639eb7 100644 --- a/layouts/login/single.html +++ b/layouts/login/single.html @@ -3,7 +3,7 @@

{{ .Title }}

- +
@@ -97,8 +97,7 @@ if (localStorage.getItem('f4_username')) { document.getElementById('auth-message').textContent = 'You are already logged in!'; document.getElementById('auth-message').className = - 'auth-message auth-message--success'; - document.getElementById('auth-message').style.display = 'block'; + 'auth-message auth-message--success is-visible'; document.getElementById('login-form').style.display = 'none'; return; } @@ -138,13 +137,12 @@ function showMsg(text, type) { msgBox.textContent = text; - msgBox.className = 'auth-message auth-message--' + type; - msgBox.style.display = 'block'; + msgBox.className = 'auth-message auth-message--' + type + ' is-visible'; } form.addEventListener('submit', function (e) { e.preventDefault(); - msgBox.style.display = 'none'; + msgBox.className = 'auth-message'; var username = document.getElementById('login-username').value.trim(); var password = pwdInput.value; diff --git a/layouts/signup/single.html b/layouts/signup/single.html index 4a4c41f..ceb5983 100644 --- a/layouts/signup/single.html +++ b/layouts/signup/single.html @@ -3,7 +3,7 @@

{{ .Title }}

- +
@@ -180,8 +180,7 @@ if (localStorage.getItem('f4_username')) { document.getElementById('auth-message').textContent = 'You are already logged in!'; document.getElementById('auth-message').className = - 'auth-message auth-message--success'; - document.getElementById('auth-message').style.display = 'block'; + 'auth-message auth-message--success is-visible'; document.getElementById('signup-form').style.display = 'none'; return; } @@ -221,11 +220,10 @@ function showMsg(text, type) { msgBox.textContent = text; - msgBox.className = 'auth-message auth-message--' + type; - msgBox.style.display = 'block'; + msgBox.className = 'auth-message auth-message--' + type + ' is-visible'; } function hideMsg() { - msgBox.style.display = 'none'; + msgBox.className = 'auth-message'; } function setLoading(btn, on) { diff --git a/static/css/custom.css b/static/css/custom.css index 03bc49d..76631b8 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -1074,3 +1074,252 @@ .comment__replies { margin-top: 0.5rem; } +/* ── Auth pages (login / signup) ───────────────────────────────────────── */ + +.auth-page { + max-width: 420px; + margin: 0 auto; + padding: 1rem 0 3rem; +} + +.auth-page__title { + margin-bottom: 1.5rem; +} + +.auth-card { + border: 1px solid var(--background-color1, #ccc); + border-radius: 10px; + padding: 2rem 1.75rem; + background: var(--background-color); +} + +/* Message banner — always reserves space so the form never shifts */ +.auth-message { + border-radius: 6px; + padding: 0.65rem 0.9rem; + font-size: 0.88rem; + margin-bottom: 1.2rem; + line-height: 1.4; + min-height: 3rem; + box-sizing: border-box; + border: 1px solid transparent; + opacity: 0; + pointer-events: none; + transition: opacity 0.15s ease; +} + +.auth-message.is-visible { + opacity: 1; + pointer-events: auto; +} + +.auth-message--error { + background: rgba(255, 61, 61, 0.1); + border: 1px solid rgba(255, 61, 61, 0.4); + color: #ff3d3d; +} + +[data-theme='dark'] .auth-message--error { + color: #ff3d3d; + background: rgba(255, 61, 61, 0.15); + border-color: rgba(255, 61, 61, 0.5); +} + +.auth-message--success { + background: rgba(39, 174, 96, 0.12); + border: 1px solid rgba(39, 174, 96, 0.4); + color: #1e8449; +} + +[data-theme='dark'] .auth-message--success { + color: #58d68d; + background: rgba(39, 174, 96, 0.18); + border-color: rgba(39, 174, 96, 0.5); +} + +/* Form fields */ +.auth-form { + display: flex; + flex-direction: column; + gap: 1.1rem; +} + +.auth-form__group { + display: flex; + flex-direction: column; + gap: 0.3rem; +} + +.auth-form__label { + font-size: 0.85rem; + font-weight: 600; + color: var(--foreground-color); +} + +.auth-form__input-wrap { + position: relative; + display: flex; + align-items: center; +} + +.auth-form__input-wrap .auth-form__input { + padding-right: 2.5rem; +} + +.auth-form__input { + width: 100%; + box-sizing: border-box; + padding: 0.5rem 0.75rem; + border: 1px solid var(--background-color1, #ccc); + border-radius: 5px; + font-size: 0.9rem; + background: var(--background-color); + color: var(--foreground-color); + transition: + border-color 0.18s ease, + box-shadow 0.18s ease; + outline: none; + font-family: inherit; +} + +.auth-form__input:focus { + border-color: var(--accent-color); + box-shadow: 0 0 0 2px rgba(var(--accent-color-rgb, 17, 51, 233), 0.15); +} + +.auth-form__input::placeholder { + color: var(--foreground-color3, #888); + opacity: 0.7; +} + +.auth-form__eye { + position: absolute; + right: 0.6rem; + background: none; + border: none; + cursor: pointer; + color: var(--foreground-color3, #888); + display: inline-flex; + align-items: center; + padding: 0.2rem; + line-height: 1; + transition: color 0.15s ease; +} + +.auth-form__eye:hover { + color: var(--foreground-color); +} + +.auth-form__hint { + font-size: 0.75rem; + color: var(--foreground-color3, #888); +} + +/* Submit button */ +.auth-form__submit { + margin-top: 0.5rem; + width: 100%; + padding: 0.6rem 1rem; + border: none; + border-radius: 5px; + background: var(--accent-color); + color: var(--background-color, #fff); + font-size: 0.92rem; + font-weight: 600; + font-family: inherit; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.4rem; + transition: opacity 0.18s ease; +} + +.auth-form__submit:hover:not(:disabled) { + opacity: 0.85; +} + +.auth-form__submit:disabled { + cursor: not-allowed; + opacity: 0.6; +} + +.auth-form__submit-loader { + display: inline-flex; + align-items: center; +} + +/* Spinner animation */ +@keyframes auth-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +.spin { + animation: auth-spin 0.8s linear infinite; +} + +/* Footer link */ +.auth-card__footer { + margin-top: 1.4rem; + text-align: center; + font-size: 0.85rem; + color: var(--foreground-color3, #888); +} + +.auth-card__link { + color: var(--accent-color); + text-decoration: none; + font-weight: 600; +} + +.auth-card__link:hover { + text-decoration: underline; +} + +/* Light theme override for submit button text */ +[data-theme='light'] .auth-form__submit { + color: #fff; +} + +/* ── OTP panel ───────────────────────────────────────────────────────────── */ + +.otp-panel__hint { + font-size: 0.87rem; + line-height: 1.5; + color: var(--foreground-color); + margin: 0; +} + +.otp-panel__input { + letter-spacing: 0.25em; + font-size: 1.15rem; + text-align: center; +} + +.otp-panel__resend { + font-size: 0.82rem; + color: var(--foreground-color3, #888); + text-align: center; + margin: 0; +} + +.otp-panel__resend-btn { + background: none; + border: none; + padding: 0; + font: inherit; + font-size: 0.82rem; + color: var(--accent-color); + cursor: pointer; + font-weight: 600; + text-decoration: underline; +} + +.otp-panel__resend-btn:hover { + opacity: 0.8; +}