css
This commit is contained in:
+73
-26
@@ -1,34 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Logowanie</title>
|
||||
<style>
|
||||
body { font-family: sans-serif; max-width: 400px; margin: 4rem auto; padding: 0 1rem; }
|
||||
form { display: flex; flex-direction: column; gap: 0.75rem; }
|
||||
label { font-weight: bold; }
|
||||
input { padding: 0.5rem; font-size: 1rem; }
|
||||
button { padding: 0.6rem; font-size: 1rem; cursor: pointer; }
|
||||
.error { background: #fee2e2; border: 1px solid #fca5a5; color: #991b1b; padding: 0.5rem 0.75rem; border-radius: 4px; }
|
||||
</style>
|
||||
<title>Login — Yggdrasil</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=VT323&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='retro.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Logowanie</h1>
|
||||
{% if error %}
|
||||
<p class="error">{{ error }}</p>
|
||||
{% endif %}
|
||||
<form method="post" action="{{ url_for('login', next=next) if next else url_for('login') }}">
|
||||
<input type="hidden" name="next" value="{{ next }}">
|
||||
<div>
|
||||
<label for="username">Użytkownik:</label><br>
|
||||
<input type="text" id="username" name="username" required autocomplete="username" style="width: 100%; box-sizing: border-box;">
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Hasło:</label><br>
|
||||
<input type="password" id="password" name="password" required autocomplete="current-password" style="width: 100%; box-sizing: border-box;">
|
||||
</div>
|
||||
<button type="submit">Zaloguj</button>
|
||||
</form>
|
||||
<div class="dialog">
|
||||
<div class="dialog-title">[ Login ]</div>
|
||||
<h1>Yggdrasil</h1>
|
||||
{% if error %}
|
||||
<p class="error">! {{ error }}</p>
|
||||
{% endif %}
|
||||
<form method="post" action="{{ url_for('login', next=next) if next else url_for('login') }}">
|
||||
<input type="hidden" name="next" value="{{ next }}">
|
||||
<div>
|
||||
<label for="username">Username:</label><br>
|
||||
<div class="term-field">
|
||||
<input type="text" id="username" name="username" required autocomplete="username" autofocus>
|
||||
<span class="caret-block" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password:</label><br>
|
||||
<div class="term-field">
|
||||
<input type="password" id="password" name="password" required autocomplete="current-password">
|
||||
<span class="caret-block" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit">[ OK ] Log in</button>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
// Block caret, Midnight Commander style.
|
||||
// The native caret is hidden (only when this script runs) and a
|
||||
// blinking block is drawn exactly where the text cursor is.
|
||||
// Measurement is exact because the font is monospace.
|
||||
// Without JS the fields keep their normal native caret.
|
||||
function attachBlockCaret(input) {
|
||||
const field = input.closest('.term-field');
|
||||
const block = field.querySelector('.caret-block');
|
||||
input.classList.add('js-caret');
|
||||
const ctx = document.createElement('canvas').getContext('2d');
|
||||
|
||||
function place() {
|
||||
const cs = getComputedStyle(input);
|
||||
ctx.font = cs.font;
|
||||
const pos = (input.selectionStart !== null && input.selectionStart !== undefined)
|
||||
? input.selectionStart
|
||||
: input.value.length;
|
||||
let text = input.value.slice(0, pos);
|
||||
if (input.type === 'password') text = '\u2022'.repeat(text.length);
|
||||
const padLeft = parseFloat(cs.paddingLeft) || 0;
|
||||
const borderLeft = parseFloat(cs.borderLeftWidth) || 0;
|
||||
const x = borderLeft + padLeft + ctx.measureText(text).width - (input.scrollLeft || 0);
|
||||
block.style.left = Math.max(borderLeft + padLeft, x) + 'px';
|
||||
}
|
||||
|
||||
function show() {
|
||||
field.classList.add('active');
|
||||
requestAnimationFrame(place);
|
||||
}
|
||||
function hide() { field.classList.remove('active'); }
|
||||
|
||||
['input', 'change', 'keyup', 'click', 'select', 'focus'].forEach((ev) => {
|
||||
input.addEventListener(ev, show);
|
||||
});
|
||||
input.addEventListener('blur', hide);
|
||||
window.addEventListener('load', () => setTimeout(place, 300)); // late autofill
|
||||
if (document.fonts && document.fonts.ready) document.fonts.ready.then(place);
|
||||
if (document.activeElement === input) show();
|
||||
}
|
||||
|
||||
document.querySelectorAll('.term-field input').forEach(attachBlockCaret);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user