Files
anti-plagiarism/services/frontend/src/components/Layout.tsx
jze9 673e72a15a feat(infra): переход прод/test на общую инфраструктуру вместо self-hosted
Postgres/Redis/RabbitMQ/MinIO/Ollama теперь общие серверы сети (адреса в .env),
локально в докере остаётся только Elasticsearch + app-сервисы. Старый
docker-compose.yml (полностью автономный стек) сохранён как
docker-compose.selfhosted.yml.example на случай отдельного GPU-сервера в
будущем. Добавлен docker-compose.prod.yml (app + свой nginx с TLS,
собирающий фронтенд в статику). Makefile переписан под три режима
(dev/test-up/prod). Мелкая чистка неиспользуемых импортов во фронтенде.
2026-07-27 12:22:36 +05:00

152 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Link, NavLink, useNavigate } from 'react-router-dom';
import { GraduationCap, Search, BookOpen, Upload, LayoutDashboard, LogOut } from 'lucide-react';
import { clsx } from 'clsx';
import { useAuthStore } from '../store/auth';
import { EmailVerificationModal } from './EmailVerificationModal';
interface LayoutProps {
children: React.ReactNode;
}
export function Layout({ children }: LayoutProps) {
const { isAuthenticated, user, logout } = useAuthStore();
const navigate = useNavigate();
const handleLogout = () => {
logout();
navigate('/');
};
return (
<div className="min-h-screen bg-gray-50">
{/* Навигация */}
<nav className="bg-white border-b border-gray-100 sticky top-0 z-50">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16">
{/* Логотип */}
<Link
to="/"
className="flex items-center gap-2.5 text-gray-900 hover:text-brand-600 transition-colors"
>
<div className="p-1.5 bg-brand-600 rounded-lg">
<GraduationCap className="w-5 h-5 text-white" />
</div>
<span className="font-semibold text-base hidden sm:block">Академический помощник</span>
<span className="font-semibold text-base sm:hidden">АкадПомощник</span>
</Link>
{/* Центральная навигация */}
<div className="flex items-center gap-1">
<NavLink
to="/search"
className={({ isActive }) =>
clsx(
'flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm font-medium transition-colors',
isActive
? 'bg-brand-50 text-brand-700'
: 'text-gray-600 hover:bg-gray-100'
)
}
>
<Search className="w-4 h-4" />
<span className="hidden md:block">Поиск</span>
</NavLink>
<NavLink
to="/check"
className={({ isActive }) =>
clsx(
'flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm font-medium transition-colors',
isActive
? 'bg-brand-50 text-brand-700'
: 'text-gray-600 hover:bg-gray-100'
)
}
>
<Upload className="w-4 h-4" />
<span className="hidden md:block">Плагиат</span>
</NavLink>
<NavLink
to="/bibliography"
className={({ isActive }) =>
clsx(
'flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm font-medium transition-colors',
isActive
? 'bg-brand-50 text-brand-700'
: 'text-gray-600 hover:bg-gray-100'
)
}
>
<BookOpen className="w-4 h-4" />
<span className="hidden md:block">Библиография</span>
</NavLink>
</div>
{/* Авторизация */}
<div className="flex items-center gap-2">
{isAuthenticated ? (
<>
<NavLink
to="/cabinet"
className={({ isActive }) =>
clsx(
'flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm font-medium transition-colors',
isActive
? 'bg-brand-50 text-brand-700'
: 'text-gray-600 hover:bg-gray-100'
)
}
>
<LayoutDashboard className="w-4 h-4" />
<span className="hidden md:block">Кабинет</span>
</NavLink>
<div className="flex items-center gap-2 pl-2 border-l border-gray-100">
<div className="flex items-center gap-1.5">
<div className="w-8 h-8 bg-brand-100 rounded-full flex items-center justify-center">
<span className="text-xs font-semibold text-brand-700">
{user?.name?.[0]?.toUpperCase() || 'U'}
</span>
</div>
<span className="text-sm text-gray-600 hidden lg:block">{user?.name}</span>
</div>
<button
onClick={handleLogout}
className="p-1.5 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition-colors"
title="Выйти"
>
<LogOut className="w-4 h-4" />
</button>
</div>
</>
) : (
<>
<Link
to="/login"
className="px-4 py-2 text-sm font-medium text-gray-600 hover:text-gray-900 transition-colors"
>
Войти
</Link>
<Link
to="/register"
className="px-4 py-2 text-sm font-medium bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Регистрация
</Link>
</>
)}
</div>
</div>
</div>
</nav>
{/* Основной контент */}
<main className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{children}
</main>
<EmailVerificationModal />
</div>
);
}