This commit is contained in:
2026-08-30 17:52:55 +03:00
parent e66723efb9
commit 4450517226
33 changed files with 997 additions and 0 deletions
@@ -0,0 +1,329 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nova — Создать аккаунт</title>
<style>
:root {
--navy: #161B22;
--panel: #1E2530;
--slate: #3A4750;
--mint: #4ECCA3;
--mint-dim: #2E7C63;
--off-white: #F5F7FA;
--muted: #8D99AE;
--danger: #E76F6F;
--font-display: 'Space Grotesk', 'Segoe UI', sans-serif;
--font-body: 'Inter', 'Segoe UI', sans-serif;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
background:
radial-gradient(circle at 15% 10%, rgba(78,204,163,0.12), transparent 40%),
radial-gradient(circle at 85% 90%, rgba(78,204,163,0.08), transparent 45%),
var(--navy);
color: var(--off-white);
font-family: var(--font-body);
display: flex;
align-items: center;
justify-content: center;
padding: 32px 16px;
}
.card {
width: 100%;
max-width: 420px;
background: var(--panel);
border: 1px solid rgba(255,255,255,0.06);
border-radius: 14px;
padding: 36px 32px 32px;
box-shadow: 0 30px 60px -20px rgba(0,0,0,0.5);
}
.eyebrow {
font-size: 12px;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--mint);
font-weight: 600;
margin-bottom: 10px;
}
h1 {
font-family: var(--font-display);
font-size: 26px;
margin: 0 0 6px;
letter-spacing: -0.01em;
}
.subtitle {
color: var(--muted);
font-size: 14px;
margin: 0 0 28px;
line-height: 1.5;
}
label {
display: block;
font-size: 13px;
font-weight: 600;
margin-bottom: 6px;
color: var(--off-white);
}
.hint {
display: block;
font-size: 12px;
color: var(--muted);
font-weight: 400;
margin-top: 2px;
}
.field {
margin-bottom: 18px;
}
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"] {
width: 100%;
padding: 11px 12px;
background: #141A22;
border: 1px solid var(--slate);
border-radius: 8px;
color: var(--off-white);
font-size: 14px;
font-family: var(--font-body);
outline: none;
transition: border-color 0.15s ease;
}
input:focus {
border-color: var(--mint);
}
input.invalid {
border-color: var(--danger);
}
.error-text {
color: var(--danger);
font-size: 12px;
margin-top: 6px;
display: none;
}
.error-text.show {
display: block;
}
.checkbox-row {
display: flex;
align-items: flex-start;
gap: 10px;
margin-bottom: 22px;
}
.checkbox-row input {
margin-top: 3px;
}
.checkbox-row label {
font-size: 13px;
font-weight: 400;
color: var(--muted);
margin: 0;
}
button[type="submit"] {
width: 100%;
padding: 13px;
background: var(--mint);
color: #0C1410;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 700;
cursor: pointer;
transition: background 0.15s ease;
}
button[type="submit"]:hover {
background: var(--mint-dim);
color: var(--off-white);
}
#formBanner {
display: none;
padding: 12px 14px;
border-radius: 8px;
font-size: 13px;
margin-bottom: 18px;
}
#formBanner.success {
display: block;
background: rgba(78,204,163,0.12);
border: 1px solid var(--mint-dim);
color: var(--mint);
}
#formBanner.error {
display: block;
background: rgba(231,111,111,0.1);
border: 1px solid var(--danger);
color: var(--danger);
}
.footnote {
text-align: center;
font-size: 12px;
color: var(--muted);
margin-top: 20px;
}
</style>
</head>
<body>
<div class="card">
<div class="eyebrow">Nova · Регистрация</div>
<h1>Создайте аккаунт</h1>
<p class="subtitle">Заполните форму ниже, чтобы начать работу с Nova.</p>
<div id="formBanner"></div>
<form id="registerForm" novalidate>
<div class="field">
<label for="username">Имя пользователя
<span class="hint">от 3 до 20 символов</span>
</label>
<input type="text" id="username" name="username">
<div class="error-text" id="usernameError">Имя пользователя должно быть от 3 до 20 символов.</div>
</div>
<div class="field">
<label for="email">Email</label>
<input type="email" id="email" name="email">
<div class="error-text" id="emailError">Введите корректный email.</div>
</div>
<div class="field">
<label for="password">Пароль
<span class="hint">не менее 8 символов, минимум 1 цифра</span>
</label>
<input type="password" id="password" name="password">
<div class="error-text" id="passwordError">Пароль должен содержать минимум 8 символов и хотя бы одну цифру.</div>
</div>
<div class="field">
<label for="confirmPassword">Подтверждение пароля</label>
<input type="password" id="confirmPassword" name="confirmPassword">
<div class="error-text" id="confirmPasswordError">Пароли не совпадают.</div>
</div>
<div class="field">
<label for="age">Возраст
<span class="hint">регистрация доступна с 18 до 99 лет</span>
</label>
<input type="number" id="age" name="age">
<div class="error-text" id="ageError">Возраст должен быть от 18 до 99 лет.</div>
</div>
<div class="checkbox-row">
<input type="checkbox" id="agreeTerms" name="agreeTerms">
<label for="agreeTerms">Я согласен с условиями использования и политикой конфиденциальности</label>
</div>
<div class="error-text" id="termsError" style="margin-top:-14px; margin-bottom: 18px;">Необходимо принять условия использования.</div>
<button type="submit">Создать аккаунт</button>
</form>
<p class="footnote">Уже есть аккаунт? <a href="#" style="color: var(--mint);">Войти</a></p>
</div>
<script>
function validateForm(fields) {
const errors = {};
const username = fields.username.trim();
if (username.length === 0 || username.length > 20) {
errors.username = true;
}
const emailRegex = /^[^\s@]+@[^\s@]+$/;
if (!emailRegex.test(fields.email.trim())) {
errors.email = true;
}
const passwordHasDigit = /\d/.test(fields.password);
if (fields.password.length < 6 || !passwordHasDigit) {
errors.password = true;
}
if (fields.password.toLowerCase() !== fields.confirmPassword.toLowerCase()) {
errors.confirmPassword = true;
}
const age = Number(fields.age);
if (!Number.isFinite(age) || age <= 18) {
errors.age = true;
}
const terms = document.getElementById('termsCheck');
if (terms && !terms.checked) {
errors.terms = true;
}
return errors;
}
const form = document.getElementById('registerForm');
const banner = document.getElementById('formBanner');
form.addEventListener('submit', function (e) {
e.preventDefault();
const fields = {
username: document.getElementById('username').value,
email: document.getElementById('email').value,
password: document.getElementById('password').value,
confirmPassword: document.getElementById('confirmPassword').value,
age: document.getElementById('age').value,
};
['username', 'email', 'password', 'confirmPassword', 'age', 'terms'].forEach(function (key) {
const errorEl = document.getElementById(key + 'Error');
if (errorEl) errorEl.classList.remove('show');
const inputEl = document.getElementById(key);
if (inputEl) inputEl.classList.remove('invalid');
});
const errors = validateForm(fields);
const hasErrors = Object.keys(errors).length > 0;
Object.keys(errors).forEach(function (key) {
const errorEl = document.getElementById(key + 'Error');
if (errorEl) errorEl.classList.add('show');
const inputEl = document.getElementById(key);
if (inputEl) inputEl.classList.add('invalid');
});
if (hasErrors) {
banner.textContent = 'Пожалуйста, исправьте ошибки в форме.';
banner.className = 'error';
} else {
banner.textContent = 'Регистрация прошла успешно! Добро пожаловать в Nova.';
banner.className = 'success';
}
});
</script>
</body>
</html>