Auth pages: light design with top navbar
- White background, card-style forms - Fixed top header: logo, nav links (Главная, Инструменты, Возможности), login/register buttons - Active state highlighting for current page - Placeholders in inputs, password hint - Mobile responsive (nav hidden on small screens) - Red error styling matching light theme
This commit is contained in:
parent
21bfefbe5d
commit
020d031627
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru" class="dark">
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
@ -7,55 +7,104 @@
|
||||
<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' } }
|
||||
colors: { accent: { DEFAULT: '#0054e6', dim: '#0043b8', light: '#e8f0fe' } }
|
||||
}}
|
||||
};
|
||||
</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; }
|
||||
* { margin:0; padding:0; box-sizing:border-box; }
|
||||
body { font-family:'Manrope',sans-serif; background:#f7f8fa; min-height:100vh; color:#1a1a2e; }
|
||||
|
||||
/* Header */
|
||||
.top-header { position:fixed; top:0; left:0; right:0; height:56px; background:#fff; border-bottom:1px solid #e5e7eb; display:flex; align-items:center; padding:0 24px; z-index:50; }
|
||||
.top-logo { font-size:18px; font-weight:800; color:#1a1a2e; text-decoration:none; display:flex; align-items:center; gap:8px; }
|
||||
.top-logo span { color:#0054e6; }
|
||||
.top-nav { display:flex; align-items:center; gap:6px; margin-left:32px; }
|
||||
.top-nav a { font-size:13px; color:#666; text-decoration:none; padding:6px 12px; border-radius:8px; transition:all .15s; font-weight:500; }
|
||||
.top-nav a:hover { color:#1a1a2e; background:#f0f1f3; }
|
||||
.top-right { margin-left:auto; display:flex; align-items:center; gap:8px; }
|
||||
.btn-ghost { font-size:13px; color:#666; text-decoration:none; padding:8px 16px; border-radius:8px; transition:all .15s; font-weight:600; border:none; background:none; cursor:pointer; }
|
||||
.btn-ghost:hover { color:#1a1a2e; background:#f0f1f3; }
|
||||
.btn-ghost.active { color:#0054e6; background:#e8f0fe; }
|
||||
.btn-primary-sm { font-size:13px; color:#fff; background:#0054e6; padding:8px 18px; border-radius:8px; text-decoration:none; font-weight:600; transition:background .15s; border:none; cursor:pointer; }
|
||||
.btn-primary-sm:hover { background:#0043b8; }
|
||||
|
||||
@media(max-width:640px) {
|
||||
.top-nav { display:none; }
|
||||
.top-header { padding:0 16px; }
|
||||
}
|
||||
|
||||
/* Content */
|
||||
.page-body { padding-top:56px; min-height:100vh; display:flex; align-items:center; justify-content:center; }
|
||||
.auth-card { max-width:420px; width:100%; padding:20px; }
|
||||
.auth-card-inner { background:#fff; border:1px solid #e5e7eb; border-radius:16px; padding:36px 32px; box-shadow:0 4px 24px rgba(0,0,0,.04); }
|
||||
.auth-title { font-size:24px; font-weight:800; color:#1a1a2e; text-align:center; }
|
||||
.auth-subtitle { font-size:14px; color:#888; text-align:center; margin-top:6px; }
|
||||
.auth-label { display:block; font-size:13px; color:#888; margin-bottom:6px; font-family:'JetBrains Mono',monospace; font-weight:500; }
|
||||
.auth-input { width:100%; background:#f7f8fa; border:1px solid #e5e7eb; color:#1a1a2e; 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:#0054e6; background:#fff; }
|
||||
.auth-btn { width:100%; padding:14px; background:#0054e6; 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:#0043b8; }
|
||||
.auth-btn:disabled { opacity:0.5; cursor:not-allowed; }
|
||||
.auth-error { background:#fef2f2; border:1px solid #fecaca; color:#dc2626; padding:10px 14px; border-radius:8px; font-size:13px; display:none; }
|
||||
.auth-error.visible { display:block; }
|
||||
.auth-footer { text-align:center; margin-top:20px; font-size:14px; color:#888; }
|
||||
.auth-footer a { color:#0054e6; text-decoration:none; font-weight:600; }
|
||||
.auth-footer a:hover { text-decoration:underline; }
|
||||
.auth-divider { height:1px; background:#e5e7eb; margin:20px 0; }
|
||||
</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>
|
||||
<body>
|
||||
|
||||
<!-- Header -->
|
||||
<header class="top-header">
|
||||
<a href="/" class="top-logo">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0054e6" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5"/></svg>
|
||||
WA Dev <span>Tools</span>
|
||||
</a>
|
||||
<p style="color:var(--text-muted);font-size:14px;margin-top:8px;">Войдите в аккаунт</p>
|
||||
<nav class="top-nav">
|
||||
<a href="/">Главная</a>
|
||||
<a href="/#tools">Инструменты</a>
|
||||
<a href="/#features">Возможности</a>
|
||||
</nav>
|
||||
<div class="top-right">
|
||||
<a href="/auth/login" class="btn-ghost active">Войти</a>
|
||||
<a href="/auth/register" class="btn-primary-sm">Регистрация</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id="error" class="auth-error"></div>
|
||||
<!-- Form -->
|
||||
<div class="page-body">
|
||||
<div class="auth-card">
|
||||
<div class="auth-card-inner">
|
||||
<div class="auth-title">Вход в аккаунт</div>
|
||||
<div class="auth-subtitle">Добро пожаловать обратно</div>
|
||||
|
||||
<form id="loginForm" style="display:flex;flex-direction:column;gap:16px;margin-top:16px;" onsubmit="return handleLogin(event)">
|
||||
<div id="error" class="auth-error" style="margin-top:20px;"></div>
|
||||
|
||||
<form id="loginForm" style="display:flex;flex-direction:column;gap:16px;margin-top:24px;" 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" />
|
||||
<label class="auth-label">Email</label>
|
||||
<input class="auth-input" type="email" name="email" required autofocus autocomplete="email" placeholder="you@example.com" />
|
||||
</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" />
|
||||
<label class="auth-label">Пароль</label>
|
||||
<input class="auth-input" type="password" name="password" required autocomplete="current-password" placeholder="Минимум 6 символов" />
|
||||
</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 class="auth-divider"></div>
|
||||
|
||||
<div class="auth-footer">
|
||||
Нет аккаунта? <a href="/auth/register">Зарегистрируйтесь</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function handleLogin(e) {
|
||||
@ -66,15 +115,11 @@ async function handleLogin(e) {
|
||||
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,
|
||||
}),
|
||||
body: JSON.stringify({ email: form.email.value, password: form.password.value }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.ok) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru" class="dark">
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
@ -7,63 +7,114 @@
|
||||
<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' } }
|
||||
colors: { accent: { DEFAULT: '#0054e6', dim: '#0043b8', light: '#e8f0fe' } }
|
||||
}}
|
||||
};
|
||||
</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; }
|
||||
* { margin:0; padding:0; box-sizing:border-box; }
|
||||
body { font-family:'Manrope',sans-serif; background:#f7f8fa; min-height:100vh; color:#1a1a2e; }
|
||||
|
||||
/* Header */
|
||||
.top-header { position:fixed; top:0; left:0; right:0; height:56px; background:#fff; border-bottom:1px solid #e5e7eb; display:flex; align-items:center; padding:0 24px; z-index:50; }
|
||||
.top-logo { font-size:18px; font-weight:800; color:#1a1a2e; text-decoration:none; display:flex; align-items:center; gap:8px; }
|
||||
.top-logo span { color:#0054e6; }
|
||||
.top-nav { display:flex; align-items:center; gap:6px; margin-left:32px; }
|
||||
.top-nav a { font-size:13px; color:#666; text-decoration:none; padding:6px 12px; border-radius:8px; transition:all .15s; font-weight:500; }
|
||||
.top-nav a:hover { color:#1a1a2e; background:#f0f1f3; }
|
||||
.top-right { margin-left:auto; display:flex; align-items:center; gap:8px; }
|
||||
.btn-ghost { font-size:13px; color:#666; text-decoration:none; padding:8px 16px; border-radius:8px; transition:all .15s; font-weight:600; border:none; background:none; cursor:pointer; }
|
||||
.btn-ghost:hover { color:#1a1a2e; background:#f0f1f3; }
|
||||
.btn-primary-sm { font-size:13px; color:#fff; background:#0054e6; padding:8px 18px; border-radius:8px; text-decoration:none; font-weight:600; transition:background .15s; border:none; cursor:pointer; }
|
||||
.btn-primary-sm:hover { background:#0043b8; }
|
||||
.btn-primary-sm.active { box-shadow:0 0 0 2px #0054e6, 0 0 0 4px rgba(0,84,230,.2); }
|
||||
|
||||
@media(max-width:640px) {
|
||||
.top-nav { display:none; }
|
||||
.top-header { padding:0 16px; }
|
||||
}
|
||||
|
||||
/* Content */
|
||||
.page-body { padding-top:56px; min-height:100vh; display:flex; align-items:center; justify-content:center; }
|
||||
.auth-card { max-width:420px; width:100%; padding:20px; }
|
||||
.auth-card-inner { background:#fff; border:1px solid #e5e7eb; border-radius:16px; padding:36px 32px; box-shadow:0 4px 24px rgba(0,0,0,.04); }
|
||||
.auth-title { font-size:24px; font-weight:800; color:#1a1a2e; text-align:center; }
|
||||
.auth-subtitle { font-size:14px; color:#888; text-align:center; margin-top:6px; }
|
||||
.auth-label { display:block; font-size:13px; color:#888; margin-bottom:6px; font-family:'JetBrains Mono',monospace; font-weight:500; }
|
||||
.auth-input { width:100%; background:#f7f8fa; border:1px solid #e5e7eb; color:#1a1a2e; 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:#0054e6; background:#fff; }
|
||||
.auth-btn { width:100%; padding:14px; background:#0054e6; 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:#0043b8; }
|
||||
.auth-btn:disabled { opacity:0.5; cursor:not-allowed; }
|
||||
.auth-error { background:#fef2f2; border:1px solid #fecaca; color:#dc2626; padding:10px 14px; border-radius:8px; font-size:13px; display:none; }
|
||||
.auth-error.visible { display:block; }
|
||||
.auth-footer { text-align:center; margin-top:20px; font-size:14px; color:#888; }
|
||||
.auth-footer a { color:#0054e6; text-decoration:none; font-weight:600; }
|
||||
.auth-footer a:hover { text-decoration:underline; }
|
||||
.auth-divider { height:1px; background:#e5e7eb; margin:20px 0; }
|
||||
.auth-hint { font-size:11px; color:#aaa; margin-top:4px; font-family:'JetBrains Mono',monospace; }
|
||||
</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>
|
||||
<body>
|
||||
|
||||
<!-- Header -->
|
||||
<header class="top-header">
|
||||
<a href="/" class="top-logo">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0054e6" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5"/></svg>
|
||||
WA Dev <span>Tools</span>
|
||||
</a>
|
||||
<p style="color:var(--text-muted);font-size:14px;margin-top:8px;">Создайте бесплатный аккаунт</p>
|
||||
<nav class="top-nav">
|
||||
<a href="/">Главная</a>
|
||||
<a href="/#tools">Инструменты</a>
|
||||
<a href="/#features">Возможности</a>
|
||||
</nav>
|
||||
<div class="top-right">
|
||||
<a href="/auth/login" class="btn-ghost">Войти</a>
|
||||
<a href="/auth/register" class="btn-primary-sm active">Регистрация</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id="error" class="auth-error"></div>
|
||||
<!-- Form -->
|
||||
<div class="page-body">
|
||||
<div class="auth-card">
|
||||
<div class="auth-card-inner">
|
||||
<div class="auth-title">Создать аккаунт</div>
|
||||
<div class="auth-subtitle">Бесплатный доступ ко всем инструментам</div>
|
||||
|
||||
<form id="regForm" style="display:flex;flex-direction:column;gap:16px;margin-top:16px;" onsubmit="return handleRegister(event)">
|
||||
<div id="error" class="auth-error" style="margin-top:20px;"></div>
|
||||
|
||||
<form id="regForm" style="display:flex;flex-direction:column;gap:16px;margin-top:24px;" onsubmit="return handleRegister(event)">
|
||||
<div>
|
||||
<label style="display:block;font-size:13px;color:var(--text-muted);margin-bottom:6px;font-family:'JetBrains Mono',monospace;">Имя</label>
|
||||
<label class="auth-label">Имя</label>
|
||||
<input class="auth-input" type="text" name="name" placeholder="Как вас зовут" autocomplete="name" />
|
||||
</div>
|
||||
<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" />
|
||||
<label class="auth-label">Email</label>
|
||||
<input class="auth-input" type="email" name="email" required autofocus autocomplete="email" placeholder="you@example.com" />
|
||||
</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 minlength="6" autocomplete="new-password" />
|
||||
<label class="auth-label">Пароль</label>
|
||||
<input class="auth-input" type="password" name="password" required minlength="6" autocomplete="new-password" placeholder="Придумайте пароль" />
|
||||
<div class="auth-hint">минимум 6 символов</div>
|
||||
</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="password2" required minlength="6" autocomplete="new-password" />
|
||||
<label class="auth-label">Подтвердите пароль</label>
|
||||
<input class="auth-input" type="password" name="password2" required minlength="6" autocomplete="new-password" placeholder="Повторите пароль" />
|
||||
</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/login" class="auth-link">Войти</a>
|
||||
</p>
|
||||
<div class="auth-divider"></div>
|
||||
|
||||
<div class="auth-footer">
|
||||
Уже есть аккаунт? <a href="/auth/login">Войти</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function handleRegister(e) {
|
||||
@ -81,7 +132,6 @@ async function handleRegister(e) {
|
||||
|
||||
btn.disabled = true;
|
||||
btn.textContent = 'Регистрация...';
|
||||
|
||||
try {
|
||||
const res = await fetch('/auth/register', {
|
||||
method: 'POST',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user