tests
This commit is contained in:
@@ -0,0 +1,329 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Nova — Create Account</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 · Sign Up</div>
|
||||
<h1>Create your account</h1>
|
||||
<p class="subtitle">Fill out the form below to get started with Nova.</p>
|
||||
|
||||
<div id="formBanner"></div>
|
||||
|
||||
<form id="registerForm" novalidate>
|
||||
|
||||
<div class="field">
|
||||
<label for="username">Username
|
||||
<span class="hint">3 to 20 characters</span>
|
||||
</label>
|
||||
<input type="text" id="username" name="username">
|
||||
<div class="error-text" id="usernameError">Username must be between 3 and 20 characters.</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" id="email" name="email">
|
||||
<div class="error-text" id="emailError">Please enter a valid email address.</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="password">Password
|
||||
<span class="hint">at least 8 characters, minimum 1 digit</span>
|
||||
</label>
|
||||
<input type="password" id="password" name="password">
|
||||
<div class="error-text" id="passwordError">Password must be at least 8 characters and contain at least one digit.</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="confirmPassword">Confirm password</label>
|
||||
<input type="password" id="confirmPassword" name="confirmPassword">
|
||||
<div class="error-text" id="confirmPasswordError">Passwords do not match.</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="age">Age
|
||||
<span class="hint">registration is open from 18 to 99 years old</span>
|
||||
</label>
|
||||
<input type="number" id="age" name="age">
|
||||
<div class="error-text" id="ageError">Age must be between 18 and 99.</div>
|
||||
</div>
|
||||
|
||||
<div class="checkbox-row">
|
||||
<input type="checkbox" id="agreeTerms" name="agreeTerms">
|
||||
<label for="agreeTerms">I agree to the Terms of Service and Privacy Policy</label>
|
||||
</div>
|
||||
<div class="error-text" id="termsError" style="margin-top:-14px; margin-bottom: 18px;">You must accept the terms of service.</div>
|
||||
|
||||
<button type="submit">Create account</button>
|
||||
</form>
|
||||
|
||||
<p class="footnote">Already have an account? <a href="#" style="color: var(--mint);">Log in</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 = 'Please fix the errors in the form.';
|
||||
banner.className = 'error';
|
||||
} else {
|
||||
banner.textContent = 'Registration successful! Welcome to Nova.';
|
||||
banner.className = 'success';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user