- Redesigned base.html: dark Minecraft theme, sticky header, responsive grid, cards, server cards with status indicators, profile styles - index.html: hero section, server list grid, how-to-start steps, features section - login.html: centered card layout, client-side validation, fetch API - registration.html: password confirmation, pattern validation, error alerts - profile.html: new page — skin/cape upload & delete, launcher download links, auth-gated via localStorage token - templates.go: added /profile route, extended pageData with Username/UUID
62 lines
2.4 KiB
HTML
62 lines
2.4 KiB
HTML
{{define "content"}}
|
||
<div class="container-narrow">
|
||
<div class="card text-center">
|
||
<h1 style="margin-bottom:0.5rem">👋 С возвращением</h1>
|
||
<p class="muted mb-0">Войди в аккаунт, чтобы управлять профилем и скачать лаунчер.</p>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div id="alert" class="alert alert-error"></div>
|
||
<form id="loginForm" novalidate>
|
||
<label for="username">Логин или Email</label>
|
||
<input type="text" id="username" name="username" required autocomplete="username" placeholder="player или player@email.com">
|
||
|
||
<label for="password">Пароль</label>
|
||
<input type="password" id="password" name="password" required autocomplete="current-password" placeholder="••••••••">
|
||
|
||
<button type="submit" class="btn" style="width:100%">Войти</button>
|
||
</form>
|
||
<p class="text-center mt-2 muted">Нет аккаунта? <a href="/register">Зарегистрироваться</a></p>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
document.getElementById('loginForm').addEventListener('submit', async function(e) {
|
||
e.preventDefault();
|
||
const alert = document.getElementById('alert');
|
||
alert.className = 'alert alert-error';
|
||
alert.classList.remove('show');
|
||
|
||
const username = document.getElementById('username').value.trim();
|
||
const password = document.getElementById('password').value;
|
||
|
||
if (!username || !password) {
|
||
alert.textContent = 'Заполните все поля';
|
||
alert.classList.add('show');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const res = await fetch('/api/web/login', {
|
||
method: 'POST',
|
||
headers: {'Content-Type': 'application/json'},
|
||
body: JSON.stringify({username, password})
|
||
});
|
||
const data = await res.json();
|
||
if (!res.ok) {
|
||
alert.textContent = data.error || 'Ошибка входа';
|
||
alert.classList.add('show');
|
||
return;
|
||
}
|
||
localStorage.setItem('token', data.token);
|
||
localStorage.setItem('uuid', data.uuid);
|
||
localStorage.setItem('username', data.username);
|
||
window.location.href = '/profile';
|
||
} catch (err) {
|
||
alert.textContent = 'Ошибка сети. Попробуй ещё раз.';
|
||
alert.classList.add('show');
|
||
}
|
||
});
|
||
</script>
|
||
{{end}}
|