wa-dev-tools/public/login.html
treamz f8616e32b4 Auth + Landing + Categories
- Local auth: registration/login with email+password (bcrypt, MariaDB)
- Landing page: marketing page at / with hero, categories, advantages, CTA
- Tool categories: Images (4), Code (3), Web (3), Utilities (2)
- Sidebar: category dividers, user avatar with logout
- Protected routes: all tools require auth, landing/login/register public
- New files: lib/db.js, routes/auth.js, login.html, register.html, landing.html
- Dependencies: bcrypt, mysql2
2026-03-21 22:54:31 +03:00

96 lines
4.6 KiB
HTML

<!DOCTYPE html>
<html lang="ru" class="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Вход — WA Dev Tools</title>
<script src="/vendor/tailwind.js"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: { extend: {
fontFamily: { mono: ['JetBrains Mono', 'monospace'], sans: ['Manrope', 'sans-serif'] },
colors: { surface: { 900: '#060c18', 800: '#091020', 700: '#0d1828', 600: '#162040' }, accent: { DEFAULT: '#0054e6', dim: '#0043b8', bright: '#6b9fff' } }
}}
};
</script>
<link href="/vendor/fonts.css" rel="stylesheet">
<link href="/shared.css" rel="stylesheet">
<style>
.auth-card { max-width: 400px; width: 100%; }
.auth-input { width: 100%; background: var(--select-bg); border: 1px solid var(--surface-600); color: var(--select-color); padding: 12px 16px; border-radius: 10px; font-family: 'Manrope', sans-serif; font-size: 15px; outline: none; transition: border-color .2s; }
.auth-input:focus { border-color: var(--accent); }
.auth-btn { width: 100%; padding: 14px; background: var(--accent); color: #fff; border: none; border-radius: 10px; font-family: 'Manrope', sans-serif; font-weight: 700; font-size: 16px; cursor: pointer; transition: background .2s; }
.auth-btn:hover { background: var(--accent-dim); }
.auth-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.auth-error { background: rgba(255,82,82,.1); border: 1px solid rgba(255,82,82,.3); color: #ff5252; padding: 10px 14px; border-radius: 8px; font-size: 13px; display: none; }
.auth-error.visible { display: block; }
.auth-link { color: var(--accent); text-decoration: none; }
.auth-link:hover { text-decoration: underline; }
</style>
</head>
<body style="display:flex;align-items:center;justify-content:center;min-height:100vh;padding:20px;">
<div class="auth-card">
<div style="text-align:center;margin-bottom:32px;">
<a href="/" style="text-decoration:none;">
<h1 style="font-size:28px;font-weight:800;color:var(--text-primary);font-family:'Manrope',sans-serif;">WA Dev <span style="color:var(--accent);">Tools</span></h1>
</a>
<p style="color:var(--text-muted);font-size:14px;margin-top:8px;">Войдите в аккаунт</p>
</div>
<div id="error" class="auth-error"></div>
<form id="loginForm" style="display:flex;flex-direction:column;gap:16px;margin-top:16px;" onsubmit="return handleLogin(event)">
<div>
<label style="display:block;font-size:13px;color:var(--text-muted);margin-bottom:6px;font-family:'JetBrains Mono',monospace;">Email</label>
<input class="auth-input" type="email" name="email" required autofocus autocomplete="email" />
</div>
<div>
<label style="display:block;font-size:13px;color:var(--text-muted);margin-bottom:6px;font-family:'JetBrains Mono',monospace;">Пароль</label>
<input class="auth-input" type="password" name="password" required autocomplete="current-password" />
</div>
<button class="auth-btn" type="submit" id="submitBtn">Войти</button>
</form>
<p style="text-align:center;margin-top:24px;font-size:14px;color:var(--text-muted);">
Нет аккаунта? <a href="/auth/register" class="auth-link">Зарегистрируйтесь</a>
</p>
</div>
<script>
async function handleLogin(e) {
e.preventDefault();
const form = e.target;
const btn = document.getElementById('submitBtn');
const err = document.getElementById('error');
err.classList.remove('visible');
btn.disabled = true;
btn.textContent = 'Вход...';
try {
const res = await fetch('/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: form.email.value,
password: form.password.value,
}),
});
const data = await res.json();
if (data.ok) {
window.location.href = data.redirect || '/dashboard';
} else {
err.textContent = data.error;
err.classList.add('visible');
}
} catch {
err.textContent = 'Ошибка сети';
err.classList.add('visible');
}
btn.disabled = false;
btn.textContent = 'Войти';
}
</script>
</body>
</html>