add login, register layout
This commit is contained in:
@@ -38,4 +38,32 @@ export async function testConnect() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function authenticate(
|
||||||
|
prevState: string | undefined,
|
||||||
|
formData: FormData,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
console.log(formData);
|
||||||
|
} catch (error) {
|
||||||
|
if (error) {
|
||||||
|
return 'Something went wrong.';
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function registration(
|
||||||
|
prevState: string | undefined,
|
||||||
|
formData: FormData,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
console.log(formData);
|
||||||
|
} catch (error) {
|
||||||
|
if (error) {
|
||||||
|
return 'Something went wrong.';
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+39
-2
@@ -1,4 +1,8 @@
|
|||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
|
import styles from '@/app/styles/login.module.scss'
|
||||||
|
import LogoIcon from '@/app/ui/logo-icon';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import LoginForm from '@/app/ui/login-form';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Login',
|
title: 'Login',
|
||||||
@@ -6,8 +10,41 @@ export const metadata: Metadata = {
|
|||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={`${styles['login-container-wrapper']}`}>
|
||||||
plz login
|
<div className={`${styles['login-container']}`}>
|
||||||
|
<div className={`${styles['logo']}`}>
|
||||||
|
<LogoIcon />
|
||||||
|
<h1>NO COPY</h1>
|
||||||
|
<p>Защита авторских прав</p>
|
||||||
|
</div>
|
||||||
|
<LoginForm />
|
||||||
|
<div className="divider">
|
||||||
|
<span>или войти через</span>
|
||||||
|
</div>
|
||||||
|
<div className={`${styles['register-link']}`}>
|
||||||
|
<p>Нет аккаунта? <Link href="register">Зарегистрироваться</Link></p>
|
||||||
|
</div>
|
||||||
|
<div className={`${styles['features']}`}>
|
||||||
|
<div className={`${styles['feature']}`}>
|
||||||
|
<svg className={`${styles['feature-icon']}`} viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||||
|
</svg>
|
||||||
|
Защита контента скрытыми водяными знаками
|
||||||
|
</div>
|
||||||
|
<div className={`${styles['feature']}`}>
|
||||||
|
<svg className={`${styles['feature-icon']}`} viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<path d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
||||||
|
</svg>
|
||||||
|
Мониторинг нарушений в реальном времени
|
||||||
|
</div>
|
||||||
|
<div className={`${styles['feature']}`}>
|
||||||
|
<svg className={`${styles['feature-icon']}`} viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<path d="M12 1L3 5v6c0 5.55 3.84 9.74 9 11 5.16-1.26 9-5.45 9-11V5l-9-4z"></path>
|
||||||
|
</svg>
|
||||||
|
Надежное хранение и безопасность данных
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import LogoIcon from '@/app/ui/logo-icon';
|
||||||
|
import styles from '@/app/styles/login.module.scss'
|
||||||
|
import Link from 'next/link';
|
||||||
|
import RegisterForm from '@/app/ui/register-form';
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<div className={`${styles['login-container-wrapper']}`}>
|
||||||
|
<div className={`${styles['login-container']}`}>
|
||||||
|
<div className={`${styles['logo']}`}>
|
||||||
|
<LogoIcon />
|
||||||
|
<h1>NO COPY</h1>
|
||||||
|
<p>Создать аккаунт</p>
|
||||||
|
</div>
|
||||||
|
<div className={`${styles['subscription-info']}`}>
|
||||||
|
<h4>🎉 Бесплатный старт</h4>
|
||||||
|
<p>При регистрации вы получаете подписку "ДЕМО" с возможностью маркировки до 3 файлов в месяц и 10 МБ хранилища.</p>
|
||||||
|
</div>
|
||||||
|
<RegisterForm />
|
||||||
|
<div className="divider">
|
||||||
|
<span>или зарегистрироваться через</span>
|
||||||
|
</div>
|
||||||
|
<div className={`${styles['register-link']}`}>
|
||||||
|
<p>Уже есть аккаунт? <Link href="login">Войти</Link></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -24,4 +24,28 @@
|
|||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 8px 25px rgba(99, 102, 241, 0.3);
|
box-shadow: 0 8px 25px rgba(99, 102, 241, 0.3);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
text-align: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
position: relative;
|
||||||
|
color: #9ca3af;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 1px;
|
||||||
|
background: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
background: white;
|
||||||
|
padding: 0 15px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
.login-container-wrapper {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-container {
|
||||||
|
background: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 40px;
|
||||||
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.1);
|
||||||
|
width: 100%;
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1f2937;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #374151;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label.required::after {
|
||||||
|
content: ' *';
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border: 2px solid #e5e7eb;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
background: #f9fafb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-options {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
margin-right: 10px;
|
||||||
|
accent-color: #6366f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #6b7280;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #6366f1;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.forgot-password {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #6366f1;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 100%;
|
||||||
|
padding: 14px;
|
||||||
|
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-link {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #6366f1;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: color 0.3s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.features {
|
||||||
|
margin-top: 30px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin-right: 8px;
|
||||||
|
color: #10b981;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscription-info {
|
||||||
|
background: #f0f9ff;
|
||||||
|
border: 1px solid #bae6fd;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
color: #0369a1;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #0c4a6e;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import styles from '@/app/styles/login.module.scss'
|
||||||
|
import { useActionState } from 'react';
|
||||||
|
import { authenticate } from '@/app/api/action';
|
||||||
|
|
||||||
|
export default function LoginForm() {
|
||||||
|
const [errorMessage, formAction, isPending] = useActionState(
|
||||||
|
authenticate,
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={formAction}>
|
||||||
|
<div className={`${styles['form-group']}`}>
|
||||||
|
<label className={`${styles['form-label']}`}>Email адрес</label>
|
||||||
|
<input type="readOnly" id="email" name="email" className={`${styles['form-input']}`} placeholder="Введите ваш email" />
|
||||||
|
</div>
|
||||||
|
<div className={`${styles['form-group']}`}>
|
||||||
|
<label className={`${styles['form-label']}`}>Пароль</label>
|
||||||
|
<input type="password" id="password" name="password" className={`${styles['form-input']}`} placeholder="Введите пароль" />
|
||||||
|
</div>
|
||||||
|
{errorMessage && (
|
||||||
|
<p className="text-sm text-red-500">{errorMessage}</p>
|
||||||
|
)}
|
||||||
|
<div className={`${styles['form-options']}`}>
|
||||||
|
<div className={`${styles['form-checkbox']}`}>
|
||||||
|
<input type="checkbox" id="remember" name="remember" />
|
||||||
|
<label>Запомнить меня</label>
|
||||||
|
</div>
|
||||||
|
<a href="forgot-password" className={`${styles['forgot-password']}`} >Забыли пароль?</a>
|
||||||
|
</div>
|
||||||
|
<button type="submit" className={`${styles['btn']}`}>Войти в систему</button>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import style from "./ui.module.scss"
|
||||||
|
|
||||||
|
export default function LogoIcon() {
|
||||||
|
return (
|
||||||
|
<div className={`${style['logo-icon']}`}>
|
||||||
|
<svg viewBox="0 0 24 24">
|
||||||
|
<path d="M12 2L2 7v10c0 5.55 3.84 9.74 9 11 5.16-1.26 9-5.45 9-11V7l-10-5z"></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import styles from '@/app/styles/login.module.scss';
|
||||||
|
import { useActionState } from 'react';
|
||||||
|
import { registration } from '@/app/api/action';
|
||||||
|
|
||||||
|
export default function RegisterForm() {
|
||||||
|
const [errorMessage, formAction, isPending] = useActionState(
|
||||||
|
registration,
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={formAction}>
|
||||||
|
<div className={`${styles['form-group']}`}>
|
||||||
|
<label
|
||||||
|
className={`${styles['form-label']} ${styles['required']}`}
|
||||||
|
>
|
||||||
|
Полное имя
|
||||||
|
</label>
|
||||||
|
<input type="readOnly" id="full_name" name="full_name" className={`${styles['form-input']}`} placeholder="Иванов Иван Иванович" />
|
||||||
|
</div>
|
||||||
|
<div className={`${styles['form-row']}`}>
|
||||||
|
<div className={`${styles['form-group']}`}>
|
||||||
|
<label className={`${styles['form-label']} ${styles['required']}`}>Email адрес</label>
|
||||||
|
<input type="password" id="email" name="email" className={`${styles['form-input']}`} placeholder="ivan@example.com" />
|
||||||
|
</div>
|
||||||
|
<div className={`${styles['form-group']}`}>
|
||||||
|
<label className={`${styles['form-label']}`}>Телефон</label>
|
||||||
|
<input type="phone" id="phone" name="phone" className={`${styles['form-input']}`} placeholder="+7 (999) 123-45-67" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={`${styles['form-group']}`}>
|
||||||
|
<label
|
||||||
|
className={`${styles['form-label']}`}
|
||||||
|
>
|
||||||
|
Компания
|
||||||
|
</label>
|
||||||
|
<input type="readOnly" id="company" name="company" className={`${styles['form-input']}`} placeholder="ООО «Ваша компания»" />
|
||||||
|
</div>
|
||||||
|
<div className={`${styles['form-row']}`}>
|
||||||
|
<div className={`${styles['form-group']}`}>
|
||||||
|
<label className={`${styles['form-label']} ${styles['required']}`}>Пароль</label>
|
||||||
|
<input type="password" id="password" name="password" className={`${styles['form-input']}`} placeholder="Минимум 6 символов" />
|
||||||
|
</div>
|
||||||
|
<div className={`${styles['form-group']}`}>
|
||||||
|
<label className={`${styles['form-label']} ${styles['required']}`}>Подтвердите пароль</label>
|
||||||
|
<input type="password" id="confirm_password" name="confirm_password" className={`${styles['form-input']}`} placeholder="Повторите пароль" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{errorMessage && (
|
||||||
|
<p className="text-sm text-red-500">{errorMessage}</p>
|
||||||
|
)}
|
||||||
|
<div className={`${styles['form-checkbox']}`} style={{ marginBottom: "20px" }}>
|
||||||
|
<input type="checkbox" id="remember" name="remember" />
|
||||||
|
<label>Я соглашаюсь с <a href="forgot-password" >условиями использования и политикой конфиденциальности</a></label>
|
||||||
|
</div>
|
||||||
|
<button type="submit" className={`${styles['btn']}`}>Создать аккаунт</button>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -83,4 +83,21 @@
|
|||||||
height: 32px;
|
height: 32px;
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
||||||
|
border-radius: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user