first commit
This commit is contained in:
commit
af43d08e90
41 changed files with 5197 additions and 0 deletions
139
frontend/src/components/base/Button.astro
Normal file
139
frontend/src/components/base/Button.astro
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
---
|
||||
export interface Props {
|
||||
// Основные пропсы компонента
|
||||
href?: string;
|
||||
type?: 'button' | 'submit' | 'reset';
|
||||
variant?: 'primary' | 'secondary' | 'outline' | 'gold';
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
disabled?: boolean;
|
||||
class?: string;
|
||||
|
||||
// Стандартные HTML-атрибуты
|
||||
id?: string;
|
||||
name?: string;
|
||||
value?: string | number | string[];
|
||||
onclick?: string | ((event: MouseEvent) => void);
|
||||
|
||||
// Data-атрибуты
|
||||
[key: `data-${string}`]: string | undefined;
|
||||
|
||||
// ARIA и другие атрибуты
|
||||
role?: string;
|
||||
'aria-label'?: string;
|
||||
'aria-describedby'?: string;
|
||||
'aria-expanded'?: string;
|
||||
'aria-controls'?: string;
|
||||
'aria-pressed'?: string;
|
||||
tabindex?: number | string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
href,
|
||||
type = 'button',
|
||||
variant = 'primary',
|
||||
size = 'md',
|
||||
disabled = false,
|
||||
class: className = '',
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
onclick,
|
||||
role,
|
||||
tabindex,
|
||||
title,
|
||||
...dataAttrs // Все data-* атрибуты
|
||||
}: Props = Astro.props;
|
||||
|
||||
const baseClasses = 'btn inline-flex items-center justify-center font-semibold transition-all duration-300 rounded-md cursor-pointer';
|
||||
|
||||
const variantClasses = {
|
||||
primary: 'bg-primary text-white hover:bg-primary-dark',
|
||||
secondary: 'bg-secondary text-white hover:bg-secondary-dark',
|
||||
outline: 'border-2 border-primary text-primary hover:bg-primary hover:text-white',
|
||||
gold: 'bg-gradient-to-b from-[#eac26e] to-[#ce9f40] text-white hover:opacity-90',
|
||||
};
|
||||
|
||||
const sizeClasses = {
|
||||
sm: 'px-3 py-1.5 text-sm',
|
||||
md: 'px-4 py-2 text-base',
|
||||
lg: 'px-6 py-3 text-lg',
|
||||
};
|
||||
|
||||
const classes = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${disabled ? 'opacity-50 cursor-not-allowed' : ''} ${className}`;
|
||||
|
||||
// Фильтруем undefined значения для чистого HTML
|
||||
const commonAttrs = Object.fromEntries(
|
||||
Object.entries({
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
onclick,
|
||||
role,
|
||||
tabindex,
|
||||
title,
|
||||
...dataAttrs
|
||||
}).filter(([, v]) => v !== undefined)
|
||||
);
|
||||
---
|
||||
|
||||
{href ? (
|
||||
<a
|
||||
href={href}
|
||||
class={classes}
|
||||
{...commonAttrs}
|
||||
>
|
||||
<slot />
|
||||
</a>
|
||||
) : (
|
||||
<button
|
||||
type={type}
|
||||
class={classes}
|
||||
disabled={disabled}
|
||||
{...commonAttrs}
|
||||
>
|
||||
<slot />
|
||||
</button>
|
||||
)}
|
||||
|
||||
<style>
|
||||
.btn {
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.3),
|
||||
transparent
|
||||
);
|
||||
transition: left 0.5s ease;
|
||||
}
|
||||
|
||||
.btn:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn:active:not(:disabled) {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
285
frontend/src/components/base/ConsultationModal.astro
Normal file
285
frontend/src/components/base/ConsultationModal.astro
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
---
|
||||
const title = 'Бесплатная консультация';
|
||||
---
|
||||
|
||||
<div id="consultation-modal" class="modal-overlay" aria-hidden="true">
|
||||
<div class="modal-container" role="dialog" aria-modal="true" aria-labelledby="modal-title">
|
||||
<button class="modal-close" aria-label="Закрыть" id="modal-close-btn">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<div class="modal-content">
|
||||
<h2 id="modal-title" class="modal-title">{title}</h2>
|
||||
<p class="modal-description">
|
||||
Оставьте свои контактные данные, и мы свяжемся с вами в течение 15 минут
|
||||
</p>
|
||||
|
||||
<form class="modal-form" action="#" method="POST" id="consultation-form">
|
||||
<div class="form-group">
|
||||
<label for="name" class="form-label">Ваше имя</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
class="form-input"
|
||||
placeholder="Иван Иванов"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="phone" class="form-label">Телефон</label>
|
||||
<input
|
||||
type="tel"
|
||||
id="phone"
|
||||
name="phone"
|
||||
class="form-input"
|
||||
placeholder="+7 (___) ___-__-__"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="modal-submit">
|
||||
Отправить заявку
|
||||
</button>
|
||||
|
||||
<p class="form-privacy">
|
||||
Нажимая кнопку, вы соглашаетесь с
|
||||
<a href="/privacy" class="privacy-link">политикой конфиденциальности</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const modal = document.getElementById('consultation-modal');
|
||||
const closeBtn = document.getElementById('modal-close-btn');
|
||||
const form = document.getElementById('consultation-form');
|
||||
|
||||
function openModal() {
|
||||
if (!modal) return;
|
||||
modal.classList.add('active');
|
||||
modal.setAttribute('aria-hidden', 'false');
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
if (!modal) return;
|
||||
modal.classList.remove('active');
|
||||
modal.setAttribute('aria-hidden', 'true');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
// Открытие по кастомному событию
|
||||
window.addEventListener('open-modal', (e: Event) => {
|
||||
const customEvent = e as CustomEvent<string>;
|
||||
if (customEvent.detail === 'consultation-modal') {
|
||||
openModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Закрытие по крестику
|
||||
closeBtn?.addEventListener('click', closeModal);
|
||||
|
||||
// Закрытие по клику вне модального окна
|
||||
modal?.addEventListener('click', (e) => {
|
||||
if (e.target === modal) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Закрытие по Escape
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && modal?.classList.contains('active')) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Обработка отправки формы
|
||||
form?.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
// Здесь добавь логику отправки формы
|
||||
console.log('Форма отправлена');
|
||||
closeModal();
|
||||
});
|
||||
|
||||
// Для Astro View Transitions
|
||||
document.addEventListener('astro:page-load', () => {
|
||||
// Переинициализация при навигации
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
backdrop-filter: blur(4px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.3s ease, visibility 0.3s ease;
|
||||
}
|
||||
|
||||
.modal-overlay.active {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.modal-container {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
max-width: 440px;
|
||||
width: 90%;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
transform: translateY(-20px) scale(0.95);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.modal-overlay.active .modal-container {
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
border-radius: 8px;
|
||||
color: #535e6c;
|
||||
transition: background 0.2s ease, color 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modal-close:hover {
|
||||
background: #f0f2f5;
|
||||
color: #1e3050;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
padding: 40px 32px 32px;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: #1e3050;
|
||||
margin: 0 0 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal-description {
|
||||
color: #535e6c;
|
||||
font-size: 0.95rem;
|
||||
text-align: center;
|
||||
margin: 0 0 28px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.modal-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
color: #1e3050;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
padding: 12px 16px;
|
||||
border: 2px solid #e0e4e8;
|
||||
border-radius: 8px;
|
||||
font-size: 1rem;
|
||||
font-family: inherit;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
border-color: #1e3050;
|
||||
box-shadow: 0 0 0 3px rgba(30, 48, 80, 0.1);
|
||||
}
|
||||
|
||||
.form-input::placeholder {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.modal-submit {
|
||||
background: linear-gradient(180deg, #eac26e 0%, #ce9f40 100%);
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
padding: 14px 24px;
|
||||
border-radius: 8px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 12px rgba(234, 194, 110, 0.3);
|
||||
}
|
||||
|
||||
.modal-submit:hover {
|
||||
box-shadow: 0 6px 20px rgba(234, 194, 110, 0.5);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.modal-submit:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.form-privacy {
|
||||
font-size: 0.8rem;
|
||||
color: #9ca3af;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.privacy-link {
|
||||
color: #1e3050;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
|
||||
.privacy-link:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.modal-content {
|
||||
padding: 32px 24px 24px;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
328
frontend/src/components/home/Hero.astro
Normal file
328
frontend/src/components/home/Hero.astro
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
---
|
||||
import Button from '@components/base/Button.astro';
|
||||
|
||||
// Текстовые константы для удобного редактирования
|
||||
const badgeText = "ЗАЩИТА ПРАВ ВОДИТЕЛЕЙ В СУРГУТЕ";
|
||||
const titleWhite = "Защитите свои права";
|
||||
const titleGold = "и водительское удостоверение";
|
||||
const description = "Профессиональная юридическая помощь при ДТП, спорах с ГИБДД и страховыми компаниями. Работаем на результат в судах ХМАО-Югры.";
|
||||
|
||||
const btnPrimary = "Бесплатная консультация";
|
||||
const btnSecondary = "Наши услуги";
|
||||
|
||||
// Пути к изображениям (замените на свои локальные файлы в папке public/ или src/assets/)
|
||||
// Для демо я использую плейсхолдеры
|
||||
const bgImageUrl = "/images/home/bg_hero.png";
|
||||
const lawyerImageUrl = "/images/home/heroImg.jpg";
|
||||
---
|
||||
|
||||
<section class="hero-section">
|
||||
<!-- Оверлей для синего оттенка фона -->
|
||||
<div class="hero-overlay"></div>
|
||||
|
||||
<div class="hero-container">
|
||||
|
||||
<!-- Левая колонка: Текст -->
|
||||
<div class="hero-content">
|
||||
<!-- Верхняя плашка -->
|
||||
<div class="badge">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
|
||||
</svg>
|
||||
{badgeText}
|
||||
</div>
|
||||
|
||||
<!-- Заголовок -->
|
||||
<h1 class="hero-title">
|
||||
<span class="text-white">{titleWhite}</span>
|
||||
<br />
|
||||
<span class="text-gold">{titleGold}</span>
|
||||
</h1>
|
||||
|
||||
<!-- Описание -->
|
||||
<p class="hero-description">{description}</p>
|
||||
|
||||
<!-- Кнопки -->
|
||||
<div class="hero-actions">
|
||||
<Button variant="gold" size="lg" id="consultation-btn" data-modal-target="consultation-modal">
|
||||
{btnPrimary}
|
||||
</Button>
|
||||
<a href="/services" class="btn btn-secondary">{btnSecondary}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Правая колонка: Изображение -->
|
||||
<div class="hero-image-wrapper">
|
||||
|
||||
<!-- Композиция с фото -->
|
||||
<div class="image-composition">
|
||||
<img src={lawyerImageUrl} alt="Юрист" class="main-image" />
|
||||
|
||||
<!-- Плавающая плашка с опытом -->
|
||||
<div class="experience-badge">
|
||||
<span class="exp-number">20+</span>
|
||||
<span class="exp-text">ЛЕТ ОПЫТА В ХМАО</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style define:vars={{ bgImageUrl: `url("${bgImageUrl}")` }}>
|
||||
/* Основная секция с фоном */
|
||||
.hero-section {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 85vh; /* Высота на весь экран или минимум 85% */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-image: var(--bgImageUrl);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
overflow: hidden; /* Чтобы декоративные элементы не вылазили */
|
||||
}
|
||||
|
||||
/* Темно-синий оверлей поверх картинки */
|
||||
.hero-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* Градиент от плотного синего к чуть прозрачному */
|
||||
background: linear-gradient(90deg, #0a2540 0%, rgba(10, 37, 64, 0.85) 50%, rgba(10, 37, 64, 0.6) 100%);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Контейнер для выравнивания */
|
||||
.hero-container {
|
||||
position: relative;
|
||||
z-index: 2; /* Поверх оверлея */
|
||||
width: 100%;
|
||||
max-width: var(--site-max-width);
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 4rem;
|
||||
}
|
||||
|
||||
/* --- Левая часть (Текст) --- */
|
||||
.hero-content {
|
||||
flex: 1;
|
||||
max-width: 650px;
|
||||
}
|
||||
|
||||
/* Плашка сверху (Badge) */
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
background-color: rgba(209, 176, 107, 0.15); /* Прозрачный золотой фон */
|
||||
border: 1px solid rgba(209, 176, 107, 0.3);
|
||||
color: #d1b06b;
|
||||
padding: 0.4rem 0.8rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
/* Заголовок */
|
||||
.hero-title {
|
||||
font-size: clamp(2.5rem, 4vw, 4rem); /* Адаптивный размер шрифта */
|
||||
line-height: 1.1;
|
||||
margin: 0 0 1.5rem 0;
|
||||
font-weight: 800;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
.text-white {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.text-gold {
|
||||
color: #e2c07b; /* Золотистый/желтый цвет из макета */
|
||||
}
|
||||
|
||||
/* Описание */
|
||||
.hero-description {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-size: 1.05rem;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 3rem;
|
||||
max-width: 550px;
|
||||
}
|
||||
|
||||
/* Блок кнопок */
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
padding: 0.8rem 2rem;
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(180deg, #eac26e 0%, #ce9f40 100%);
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
box-shadow: 0 4px 15px rgba(206, 159, 64, 0.4);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: rgba(255, 255, 255, 0.08); /* Полупрозрачный синий/белый */
|
||||
backdrop-filter: blur(5px);
|
||||
color: #ffffff;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
/* --- Правая часть (Картинка) --- */
|
||||
.hero-image-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Обертка для фото и белой подложки */
|
||||
.image-composition {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 450px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Имитация повернутой белой карточки на заднем фоне */
|
||||
.image-composition::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
left: 25px;
|
||||
right: -25px;
|
||||
bottom: 15px;
|
||||
background-color: #ffffff;
|
||||
border-radius: 12px;
|
||||
transform: rotate(4deg);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
/* Основное фото */
|
||||
.main-image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
object-fit: cover;
|
||||
border-radius: 12px;
|
||||
border: 6px solid #ffffff; /* Белая рамка */
|
||||
filter: grayscale(100%); /* Делаем фото черно-белым, как на макете */
|
||||
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
/* Плашка "15+ лет" */
|
||||
.experience-badge {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: -40px; /* Сдвигаем влево за пределы фото */
|
||||
background: #ffffff;
|
||||
padding: 1.2rem;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.15);
|
||||
z-index: 3;
|
||||
min-width: 160px;
|
||||
}
|
||||
|
||||
.exp-number {
|
||||
font-size: 2rem;
|
||||
font-weight: 900;
|
||||
color: #1e3050; /* Темно-синий */
|
||||
line-height: 1;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.exp-text {
|
||||
font-size: 0.65rem;
|
||||
font-weight: 700;
|
||||
color: #6c7a8c;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* --- Адаптивность --- */
|
||||
@media (max-width: 1024px) {
|
||||
.hero-container {
|
||||
flex-direction: column;
|
||||
text-align: center; /* Центрируем контент на планшетах */
|
||||
padding: 4rem 2rem;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hero-description {
|
||||
margin: 0 auto 3rem auto;
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hero-image-wrapper {
|
||||
justify-content: center;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.experience-badge {
|
||||
left: -10px; /* Сдвигаем внутрь, чтобы не вылазило за экран */
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.hero-actions {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.image-composition::before {
|
||||
display: none; /* Убираем повернутую подложку на мобилках для простоты */
|
||||
}
|
||||
|
||||
.experience-badge {
|
||||
bottom: -20px;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
355
frontend/src/components/home/Services.astro
Normal file
355
frontend/src/components/home/Services.astro
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
---
|
||||
|
||||
const sectionSubtitle = "Специализация";
|
||||
const sectionTitle = "Комплексная защита на дороге";
|
||||
|
||||
const services = {
|
||||
card1: {
|
||||
title: "Возврат водительских прав",
|
||||
desc: "Оспаривание протоколов за отказ от мед. освидетельствования, выезд на встречную полосу и другие нарушения. Анализируем ошибки инспекторов.",
|
||||
linkText: "Узнать подробнее"
|
||||
},
|
||||
card2: {
|
||||
title: "Споры по ОСАГО/КАСКО",
|
||||
desc: "Добиваемся полных выплат от страховых. Взыскание недоплаченных сумм, УТС и штрафов."
|
||||
},
|
||||
card3: {
|
||||
title: "Разбор ДТП",
|
||||
desc: "Установление истинного виновника аварии. Независимая экспертиза и трасология."
|
||||
},
|
||||
card4: {
|
||||
title: "Представительство в суде",
|
||||
desc: "Берем на себя всю бумажную волокиту и посещение заседаний. Защищаем ваши интересы во всех судебных инстанциях Сургута и округа.",
|
||||
btnText: "Записаться на встречу"
|
||||
}
|
||||
};
|
||||
---
|
||||
|
||||
<section class="services-section">
|
||||
<div class="container">
|
||||
|
||||
<!-- Заголовок секции -->
|
||||
<div class="section-header">
|
||||
<span class="subtitle">{sectionSubtitle}</span>
|
||||
<h2 class="title">{sectionTitle}</h2>
|
||||
</div>
|
||||
|
||||
<!-- Сетка карточек (Bento Grid) -->
|
||||
<div class="bento-grid">
|
||||
|
||||
<!-- Карточка 1: Широкая светлая -->
|
||||
<div class="card large-card light-bg">
|
||||
<!-- Фоновый водяной знак (Молоток) -->
|
||||
<div class="bg-watermark">
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 13L10 9M14 13L15.5 11.5C16.3284 10.6716 16.3284 9.32843 15.5 8.5C14.6716 7.67157 13.3284 7.67157 12.5 8.5L11 10M14 13L16 15C16.8284 15.8284 18.1716 15.8284 19 15C19.8284 14.1716 19.8284 12.8284 19 12L17 10M10 9L8 11C7.17157 11.8284 5.82843 11.8284 5 11C4.17157 10.1716 4.17157 8.82843 5 8L7 6M10 9L8.5 7.5C7.67157 6.67157 7.67157 5.32843 8.5 4.5C9.32843 3.67157 10.6716 3.67157 11.5 4.5L13 6M4 20L9 15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M4 20H8V22H2V16H4V20Z" fill="currentColor"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="icon dark-icon">
|
||||
<!-- Иконка: Перечеркнутая камера -->
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="1" y1="1" x2="23" y2="23"></line><path d="M21 15V7a2 2 0 0 0-2-2H8.5"></path><path d="M3 7v8a2 2 0 0 0 2 2h14"></path><circle cx="12" cy="13" r="3"></circle></svg>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3 class="card-title">{services.card1.title}</h3>
|
||||
<p class="card-desc">{services.card1.desc}</p>
|
||||
</div>
|
||||
<a href="#services" class="text-link">
|
||||
{services.card1.linkText}
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Карточка 2: Маленькая белая -->
|
||||
<div class="card small-card white-bg">
|
||||
<div class="icon gold-icon">
|
||||
<!-- Иконка: Документ/Страховка -->
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path><circle cx="12" cy="13" r="2"></circle></svg>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3 class="card-title">{services.card2.title}</h3>
|
||||
<p class="card-desc">{services.card2.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Карточка 3: Маленькая белая -->
|
||||
<div class="card small-card white-bg">
|
||||
<div class="icon gold-icon">
|
||||
<!-- Иконка: Автомобиль с восклицательным знаком -->
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 16H9m10 0h3v-3.15a1 1 0 0 0-.84-.99L16 11l-2.7-3.6a2 2 0 0 0-1.6-.8H9.3a2 2 0 0 0-1.6.8L5 11l-5.16.86a1 1 0 0 0-.84.99V16h3"></path><circle cx="6.5" cy="16.5" r="2.5"></circle><circle cx="16.5" cy="16.5" r="2.5"></circle><path d="M12 2v4m0 4h.01"></path></svg>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3 class="card-title">{services.card3.title}</h3>
|
||||
<p class="card-desc">{services.card3.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Карточка 4: Широкая темная -->
|
||||
<div class="card large-card dark-bg">
|
||||
<!-- Фоновый водяной знак (Весы) -->
|
||||
<div class="bg-watermark watermark-bottom">
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 3v18M3 10l4-4 4 4M21 10l-4-4-4 4M5 10v4a2 2 0 002 2h0a2 2 0 002-2v-4M15 10v4a2 2 0 002 2h0a2 2 0 002-2v-4"/>
|
||||
<path d="M10 21h4M9 6h6"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="card-content card-content-bottom">
|
||||
<h3 class="card-title">{services.card4.title}</h3>
|
||||
<p class="card-desc">{services.card4.desc}</p>
|
||||
<a href="#contact" class="btn-outline">{services.card4.btnText}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
/* Общие стили секции */
|
||||
.services-section {
|
||||
padding: 6rem 2rem;
|
||||
background-color: #ffffff;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* Заголовок секции */
|
||||
.section-header {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
display: block;
|
||||
color: #d1b06b; /* Золотой цвет */
|
||||
font-size: 0.8rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #1e3050; /* Темно-синий */
|
||||
font-size: clamp(2rem, 3vw, 2.8rem);
|
||||
font-weight: 800;
|
||||
margin: 0;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
/* Настройка сетки Bento */
|
||||
.bento-grid {
|
||||
display: grid;
|
||||
/* Делим на 3 равные колонки */
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
/* 2 строки авто-высоты */
|
||||
grid-template-rows: auto auto;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
/* Общие стили карточек */
|
||||
.card {
|
||||
position: relative;
|
||||
border-radius: 12px;
|
||||
padding: 2.5rem;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
/* Размеры карточек в сетке */
|
||||
.large-card {
|
||||
grid-column: span 2; /* Занимает 2 колонки из 3 */
|
||||
min-height: 380px;
|
||||
}
|
||||
|
||||
.small-card {
|
||||
grid-column: span 1; /* Занимает 1 колонку из 3 */
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
/* Цветовые темы карточек */
|
||||
.light-bg {
|
||||
background-color: #f6f8fb; /* Светло-серый/голубоватый */
|
||||
box-shadow: inset 0 0 0 1px rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.white-bg {
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.05), 0 1px 3px rgba(0,0,0,0.02);
|
||||
}
|
||||
|
||||
.dark-bg {
|
||||
background-color: #0b2341; /* Глубокий синий */
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Иконки в левом верхнем углу */
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.dark-icon { color: #1e3050; }
|
||||
.gold-icon { color: #d1b06b; }
|
||||
|
||||
/* Типографика внутри карточек */
|
||||
.card-content {
|
||||
flex-grow: 1;
|
||||
z-index: 2; /* Поверх водяных знаков */
|
||||
}
|
||||
|
||||
/* Заголовки карточек сделаны шрифтом с засечками для солидности */
|
||||
.card-title {
|
||||
font-family: Georgia, 'Times New Roman', Times, serif;
|
||||
font-size: 1.4rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1rem 0;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.light-bg .card-title, .white-bg .card-title {
|
||||
color: #1e3050;
|
||||
}
|
||||
|
||||
/* Описание карточек */
|
||||
.card-desc {
|
||||
font-family: Georgia, 'Times New Roman', Times, serif;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.light-bg .card-desc, .white-bg .card-desc {
|
||||
color: #6c7a8c;
|
||||
}
|
||||
|
||||
.dark-bg .card-desc {
|
||||
color: #8c9bb0;
|
||||
}
|
||||
|
||||
/* Фоновые водяные знаки (Огромные полупрозрачные иконки) */
|
||||
.bg-watermark {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Для первой карточки (Молоток по центру) */
|
||||
.light-bg .bg-watermark {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) rotate(-15deg);
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
color: rgba(210, 217, 228, 0.5); /* Очень бледный серо-голубой */
|
||||
}
|
||||
|
||||
/* Для темной карточки (Весы в правом нижнем углу) */
|
||||
.dark-bg .bg-watermark {
|
||||
bottom: -20px;
|
||||
right: 10px;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
color: rgba(255, 255, 255, 0.03); /* Очень прозрачный белый */
|
||||
}
|
||||
|
||||
/* Элементы действий (Ссылки и Кнопки) */
|
||||
.text-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
color: #1e3050;
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
font-size: 0.95rem;
|
||||
margin-top: 2rem;
|
||||
z-index: 2;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.text-link:hover {
|
||||
color: #d1b06b;
|
||||
}
|
||||
|
||||
/* Кнопка в темной карточке */
|
||||
.card-content-bottom {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
align-self: flex-start;
|
||||
margin-top: 2rem;
|
||||
padding: 0.8rem 1.8rem;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
background: #ffffff;
|
||||
color: #0b2341;
|
||||
}
|
||||
|
||||
/* --- Адаптивность --- */
|
||||
|
||||
/* Планшеты (перестраиваем в 2 колонки) */
|
||||
@media (max-width: 1024px) {
|
||||
.bento-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.large-card {
|
||||
grid-column: span 2; /* На планшете широкие карточки занимают всю ширину */
|
||||
}
|
||||
|
||||
.small-card {
|
||||
grid-column: span 1; /* Маленькие встают по две в ряд */
|
||||
}
|
||||
}
|
||||
|
||||
/* Мобильные телефоны (все в 1 колонку) */
|
||||
@media (max-width: 768px) {
|
||||
.services-section {
|
||||
padding: 4rem 1.5rem;
|
||||
}
|
||||
|
||||
.bento-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.large-card, .small-card {
|
||||
grid-column: span 1;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2rem 1.5rem;
|
||||
}
|
||||
|
||||
.light-bg .bg-watermark {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
256
frontend/src/components/home/WhyUs.astro
Normal file
256
frontend/src/components/home/WhyUs.astro
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
---
|
||||
// src/components/WhyUs.astro
|
||||
|
||||
const sectionData = {
|
||||
subtitle: "Почему мы?",
|
||||
title: "Локальная экспертиза в Сургуте",
|
||||
floatingText: "Знаем специфику судов Сургута и регламенты местной полиции изнутри.",
|
||||
// Плейсхолдер картинки (замените на свою локальную, например src/assets/gavel.jpg)
|
||||
imageUrl: "https://images.unsplash.com/photo-1589829085413-56de8ae18c73?q=80&w=1000&auto=format&fit=crop"
|
||||
};
|
||||
|
||||
const features = [
|
||||
{
|
||||
title: "Местный опыт",
|
||||
desc: "Мы работаем только в Сургуте и ХМАО. Это позволяет нам знать практику каждого судьи и особенности работы местных отделов ГИБДД.",
|
||||
// Иконка: Пин на карте
|
||||
icon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle></svg>`
|
||||
},
|
||||
{
|
||||
title: "92% Успешных дел",
|
||||
desc: "Высокий процент выигранных дел по возврату прав и страховым спорам. Работаем на результат, а не на процесс.",
|
||||
// Иконка: Галочка-бейджик
|
||||
icon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path><path d="m9 12 2 2 4-4"></path></svg>`
|
||||
},
|
||||
{
|
||||
title: "Срочный выезд",
|
||||
desc: "Оперативно выезжаем на место ДТП или задержания в любой район города для фиксации нарушений.",
|
||||
// Иконка: Часы с историей
|
||||
icon: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path><path d="M12 7v5l4 2"></path></svg>`
|
||||
}
|
||||
];
|
||||
---
|
||||
|
||||
<section class="why-us-section">
|
||||
<div class="container">
|
||||
|
||||
<!-- Левая колонка: Изображение -->
|
||||
<div class="image-column">
|
||||
<div class="image-wrapper">
|
||||
<img src={sectionData.imageUrl} alt="Юридическая практика" class="main-image" loading="lazy" />
|
||||
|
||||
<!-- Плавающая бежевая плашка -->
|
||||
<div class="floating-card">
|
||||
<p>{sectionData.floatingText}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Правая колонка: Текст и особенности -->
|
||||
<div class="content-column">
|
||||
<div class="section-header">
|
||||
<span class="subtitle">{sectionData.subtitle}</span>
|
||||
<h2 class="title">{sectionData.title}</h2>
|
||||
</div>
|
||||
|
||||
<div class="features-list">
|
||||
{features.map((feature) => (
|
||||
<div class="feature-item">
|
||||
<div class="icon-box" set:html={feature.icon} />
|
||||
<div class="feature-text">
|
||||
<h3 class="feature-title">{feature.title}</h3>
|
||||
<p class="feature-desc">{feature.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
/* Общие стили секции */
|
||||
.why-us-section {
|
||||
padding: 6rem 2rem;
|
||||
background-color: #f4f6f9; /* Очень светлый серо-голубой фон (из макета) */
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1300px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr; /* Две равные колонки */
|
||||
gap: 6rem; /* Большой отступ между колонками */
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* --- Левая колонка (Изображение) --- */
|
||||
.image-column {
|
||||
position: relative;
|
||||
padding-bottom: 2rem; /* Место для плавающей плашки */
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
.image-wrapper {
|
||||
position: relative;
|
||||
border-radius: 12px;
|
||||
overflow: visible; /* Чтобы плашка могла выходить за края */
|
||||
}
|
||||
|
||||
.main-image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
aspect-ratio: 4/4.5; /* Пропорции картинки как на макете */
|
||||
object-fit: cover;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Бежевая плавающая плашка */
|
||||
.floating-card {
|
||||
position: absolute;
|
||||
bottom: -30px;
|
||||
right: -30px;
|
||||
background-color: #fce1a8; /* Бежево-желтый цвет */
|
||||
padding: 1.8rem;
|
||||
border-radius: 6px;
|
||||
max-width: 320px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.floating-card p {
|
||||
font-family: Georgia, 'Times New Roman', Times, serif; /* Шрифт с засечками */
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.5;
|
||||
color: #1e3050;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* --- Правая колонка (Контент) --- */
|
||||
.section-header {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
display: block;
|
||||
color: #1e3050;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 2px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #1e3050;
|
||||
font-size: clamp(2rem, 3vw, 2.5rem);
|
||||
font-weight: 800;
|
||||
line-height: 1.1;
|
||||
margin: 0;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
/* Список особенностей (Features) */
|
||||
.features-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2.5rem; /* Расстояние между пунктами */
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
display: flex;
|
||||
gap: 1.5rem; /* Расстояние между иконкой и текстом */
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
/* Темно-синие квадратные иконки */
|
||||
.icon-box {
|
||||
flex-shrink: 0;
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
background-color: #122138; /* Темно-синий фон иконки */
|
||||
color: #ffffff;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px; /* Внутренний отступ для SVG */
|
||||
box-shadow: 0 4px 10px rgba(18, 33, 56, 0.2);
|
||||
}
|
||||
|
||||
/* Типографика текстов особенностей */
|
||||
.feature-text {
|
||||
flex-grow: 1;
|
||||
padding-top: 0.2rem;
|
||||
}
|
||||
|
||||
/* Заголовки пунктов - шрифт с засечками */
|
||||
.feature-title {
|
||||
font-family: Georgia, 'Times New Roman', Times, serif;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
color: #1e3050;
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
/* Описание пунктов - шрифт с засечками, серый цвет */
|
||||
.feature-desc {
|
||||
font-family: Georgia, 'Times New Roman', Times, serif;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.6;
|
||||
color: #6c7a8c;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* --- Адаптивность --- */
|
||||
@media (max-width: 1024px) {
|
||||
.container {
|
||||
gap: 3rem; /* Уменьшаем отступ между колонками на планшетах */
|
||||
}
|
||||
|
||||
.floating-card {
|
||||
right: -10px; /* Сдвигаем плашку, чтобы не вылазила за экран */
|
||||
max-width: 280px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.why-us-section {
|
||||
padding: 4rem 1.5rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
grid-template-columns: 1fr; /* Одна колонка на мобильных */
|
||||
gap: 4rem;
|
||||
}
|
||||
|
||||
/* Картинка встает сверху, плашка выравнивается */
|
||||
.image-column {
|
||||
padding-right: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.floating-card {
|
||||
bottom: -20px;
|
||||
right: 20px; /* Не даем уйти за правый край экрана */
|
||||
left: 20px; /* Растягиваем на мобилках */
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.feature-item {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.icon-box {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
239
frontend/src/components/layout/footer/Footer.astro
Normal file
239
frontend/src/components/layout/footer/Footer.astro
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
---
|
||||
|
||||
const sectionsLinks = [
|
||||
{ label: 'Главная', href: '/' },
|
||||
{ label: 'Услуги', href: '/services' },
|
||||
];
|
||||
|
||||
const legalLinks = [
|
||||
{ label: 'Privacy Policy', href: '#' },
|
||||
{ label: 'Terms of Service', href: '#' },
|
||||
{ label: 'Legal Disclaimer', href: '#' },
|
||||
{ label: 'Cookie Settings', href: '#' },
|
||||
];
|
||||
---
|
||||
|
||||
<footer class="footer">
|
||||
<div class="footer-container">
|
||||
|
||||
<!-- Верхняя часть футера (Колонки) -->
|
||||
<div class="footer-top">
|
||||
|
||||
<!-- Колонка 1: Бренд и описание -->
|
||||
<div class="footer-col brand-col">
|
||||
<a href="/" class="footer-logo">Автоюрист086</a>
|
||||
<p class="brand-desc">
|
||||
Специализированная юридическая помощь<br/>
|
||||
для водителей в Сургуте и Ханты-<br/>
|
||||
Мансийском автономном округе-Югры.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Колонка 2: Разделы и Блог -->
|
||||
<div class="footer-col">
|
||||
<h4 class="col-title">Разделы</h4>
|
||||
<ul class="footer-links">
|
||||
{sectionsLinks.map(link => (
|
||||
<li><a href={link.href}>{link.label}</a></li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<h4 class="col-title mt-4">Блог</h4>
|
||||
<ul class="footer-links">
|
||||
<li><a href="/contacts">Контакты</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Колонка 3: Правовая информация -->
|
||||
<div class="footer-col">
|
||||
<h4 class="col-title">Правовая информация</h4>
|
||||
<ul class="footer-links">
|
||||
{legalLinks.map(link => (
|
||||
<li><a href={link.href}>{link.label}</a></li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Колонка 4: Контакты -->
|
||||
<div class="footer-col">
|
||||
<h4 class="col-title">Связь с нами</h4>
|
||||
<p class="address">Сургут, ул. Мира, 15</p>
|
||||
<a href="tel:+73462000000" class="footer-phone">+7 (3462) 00-00-00</a>
|
||||
|
||||
<!-- Иконка "Поделиться" -->
|
||||
<button class="share-btn" aria-label="Share">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="18" cy="5" r="3"></circle>
|
||||
<circle cx="6" cy="12" r="3"></circle>
|
||||
<circle cx="18" cy="19" r="3"></circle>
|
||||
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line>
|
||||
<line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Нижняя часть футера (Копирайт) -->
|
||||
<div class="footer-bottom">
|
||||
<p class="copyright">© 2026 Автоюрист086. Все права защищены.</p>
|
||||
<p class="developer">Designed for Justice</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
/* Базовые стили футера */
|
||||
.footer {
|
||||
background-color: #031529; /* Темно-синий фон */
|
||||
color: #8c9bb0; /* Приглушенный серо-голубой цвет текста */
|
||||
/* Используем шрифт с засечками (serif), как на макете */
|
||||
font-family: Georgia, 'Times New Roman', Times, serif;
|
||||
padding: 4rem 2rem 1.5rem 2rem;
|
||||
}
|
||||
|
||||
.footer-container {
|
||||
width: 100%;
|
||||
max-width: var(--site-max-width);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* Сетка для колонок */
|
||||
.footer-top {
|
||||
display: grid;
|
||||
/* Пропорции колонок: первая чуть шире, остальные равны */
|
||||
grid-template-columns: 1.5fr 1fr 1fr 1fr;
|
||||
gap: 2rem;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
/* Колонка 1 */
|
||||
.footer-logo {
|
||||
display: inline-block;
|
||||
color: #ffffff;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
margin-bottom: 1.5rem;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.brand-desc {
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.8;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Заголовки колонок (Золотой цвет) */
|
||||
.col-title {
|
||||
color: #d1b06b; /* Золотистый/бежевый */
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
margin: 0 0 1.5rem 0;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.mt-4 {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
/* Списки ссылок */
|
||||
.footer-links {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.footer-links li {
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
|
||||
.footer-links a {
|
||||
color: #8c9bb0;
|
||||
text-decoration: none;
|
||||
font-size: 0.85rem;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.footer-links a:hover {
|
||||
color: #d1b06b; /* При наведении становятся золотыми */
|
||||
}
|
||||
|
||||
/* Колонка Контактов */
|
||||
.address {
|
||||
font-size: 0.85rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.footer-phone {
|
||||
display: block;
|
||||
color: #d1b06b;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
margin-bottom: 1.5rem;
|
||||
font-family: system-ui, -apple-system, sans-serif; /* Цифры лучше читаются в sans-serif */
|
||||
}
|
||||
|
||||
/* Кнопка "Поделиться" */
|
||||
.share-btn {
|
||||
background: transparent;
|
||||
border: 1px solid #2a3a50;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #8c9bb0;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.share-btn:hover {
|
||||
border-color: #d1b06b;
|
||||
color: #d1b06b;
|
||||
background-color: rgba(209, 176, 107, 0.05);
|
||||
}
|
||||
|
||||
/* Нижняя панель (Копирайт) */
|
||||
.footer-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 1.5rem;
|
||||
border-top: 1px solid rgba(140, 155, 176, 0.1); /* Тонкая полоска разделителя */
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.copyright, .developer {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Адаптивность для планшетов */
|
||||
@media (max-width: 1024px) {
|
||||
.footer-top {
|
||||
grid-template-columns: 1fr 1fr; /* 2 колонки */
|
||||
gap: 3rem 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Адаптивность для мобильных устройств */
|
||||
@media (max-width: 640px) {
|
||||
.footer {
|
||||
padding: 3rem 1.5rem 1rem 1.5rem;
|
||||
}
|
||||
|
||||
.footer-top {
|
||||
grid-template-columns: 1fr; /* 1 колонка */
|
||||
gap: 2.5rem;
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
189
frontend/src/components/layout/header/Header.astro
Normal file
189
frontend/src/components/layout/header/Header.astro
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
---
|
||||
import Logo from './Logo.astro';
|
||||
import LoginButton from './LoginButton.astro';
|
||||
import Navbar from './Navbar.astro';
|
||||
import MobileMenu from './MobileMenu.astro';
|
||||
---
|
||||
|
||||
<header class="header-wrapper">
|
||||
<div class="header-container">
|
||||
<!-- Логотип -->
|
||||
<Logo />
|
||||
|
||||
<!-- Навигация -->
|
||||
<Navbar />
|
||||
|
||||
<!-- Блок контактов (Кнопка входа + Гамбургер) -->
|
||||
<div class="contact-block">
|
||||
<LoginButton />
|
||||
|
||||
<!-- Кнопка гамбургера -->
|
||||
<button class="burger-btn" id="burger-btn" aria-label="Открыть меню">
|
||||
<span class="burger-line"></span>
|
||||
<span class="burger-line"></span>
|
||||
<span class="burger-line"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<MobileMenu />
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const burgerBtn = document.getElementById('burger-btn');
|
||||
const mobileMenuOverlay = document.getElementById('mobile-menu-overlay');
|
||||
const mobileMenuClose = document.getElementById('mobile-menu-close');
|
||||
const mobileNavLinks = mobileMenuOverlay?.querySelectorAll('.mobile-nav-link');
|
||||
|
||||
function openMenu() {
|
||||
mobileMenuOverlay?.classList.add('active');
|
||||
document.body.style.overflow = 'hidden';
|
||||
burgerBtn?.classList.add('active');
|
||||
}
|
||||
|
||||
function closeMenu() {
|
||||
mobileMenuOverlay?.classList.remove('active');
|
||||
document.body.style.overflow = '';
|
||||
burgerBtn?.classList.remove('active');
|
||||
}
|
||||
|
||||
// Открытие меню
|
||||
burgerBtn?.addEventListener('click', openMenu);
|
||||
|
||||
// Закрытие по крестику
|
||||
mobileMenuClose?.addEventListener('click', closeMenu);
|
||||
|
||||
// Закрытие по клику вне меню
|
||||
mobileMenuOverlay?.addEventListener('click', (e) => {
|
||||
if (e.target === mobileMenuOverlay) {
|
||||
closeMenu();
|
||||
}
|
||||
});
|
||||
|
||||
// Закрытие по клику на ссылку
|
||||
mobileNavLinks?.forEach(link => {
|
||||
link.addEventListener('click', closeMenu);
|
||||
});
|
||||
|
||||
// Закрытие по Escape
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && mobileMenuOverlay?.classList.contains('active')) {
|
||||
closeMenu();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Общая обертка хедера (фон и скругления как на скриншоте) */
|
||||
.header-wrapper {
|
||||
background-color: #d1d9e4; /* Серо-голубой фон */
|
||||
border-top-left-radius: 8px; /* Скругления из макета */
|
||||
border-top-right-radius: 8px;
|
||||
padding: 1.2rem 2rem;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
}
|
||||
|
||||
/* Контейнер для выравнивания контента */
|
||||
.header-container {
|
||||
width: 100%;
|
||||
max-width: var(--site-max-width);
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
/* Блок с телефоном и кнопкой */
|
||||
.contact-block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.phone-number {
|
||||
color: #1e3050;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Кнопка гамбургера */
|
||||
.burger-btn {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
width: 30px;
|
||||
height: 21px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
z-index: 1001;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.burger-line {
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, #1e3050 0%, #2a4266 100%);
|
||||
border-radius: 2px;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.burger-line:nth-child(1) {
|
||||
transform-origin: top center;
|
||||
}
|
||||
|
||||
.burger-line:nth-child(3) {
|
||||
transform-origin: bottom center;
|
||||
}
|
||||
|
||||
/* Анимация гамбургера в крестик */
|
||||
.burger-btn.active .burger-line:nth-child(1) {
|
||||
transform: rotate(45deg) translate(5px, 5px);
|
||||
}
|
||||
|
||||
.burger-btn.active .burger-line:nth-child(2) {
|
||||
opacity: 0;
|
||||
transform: scaleX(0);
|
||||
}
|
||||
|
||||
.burger-btn.active .burger-line:nth-child(3) {
|
||||
transform: rotate(-45deg) translate(5px, -5px);
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.burger-btn {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.contact-block {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
/* Скрываем кнопку входа на мобильных */
|
||||
.login-btn {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.contact-block {
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.header-container {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
98
frontend/src/components/layout/header/LoginButton.astro
Normal file
98
frontend/src/components/layout/header/LoginButton.astro
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
---
|
||||
export interface Props {
|
||||
href?: string;
|
||||
variant?: 'outline' | 'primary';
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
href = '/login',
|
||||
variant = 'outline',
|
||||
size = 'md',
|
||||
class: className = '',
|
||||
}: Props = Astro.props;
|
||||
|
||||
const baseClasses = 'login-btn inline-flex items-center justify-center font-semibold transition-all duration-300 rounded-md cursor-pointer';
|
||||
|
||||
const variantClasses = {
|
||||
primary: 'bg-primary text-white hover:bg-primary-dark',
|
||||
outline: 'border-2 border-[#1e3050] text-[#1e3050] hover:bg-[#1e3050] hover:text-white',
|
||||
};
|
||||
|
||||
const sizeClasses = {
|
||||
sm: 'px-3 py-1.5 text-sm',
|
||||
md: 'px-4 py-2 text-base',
|
||||
lg: 'px-6 py-3 text-lg',
|
||||
};
|
||||
|
||||
const classes = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${className}`;
|
||||
---
|
||||
|
||||
<a href={href} class={classes}>
|
||||
<div class="login-content">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="login-icon">
|
||||
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path>
|
||||
<polyline points="10 17 15 12 10 7"></polyline>
|
||||
<line x1="15" y1="12" x2="3" y2="12"></line>
|
||||
</svg>
|
||||
<span class="login-text">Вход</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<style>
|
||||
.login-btn {
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.login-content {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.login-btn::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.3),
|
||||
transparent
|
||||
);
|
||||
transition: left 0.5s ease;
|
||||
}
|
||||
|
||||
.login-btn:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.login-btn:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.login-btn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.login-icon {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.login-btn:hover .login-icon {
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
.login-text {
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
214
frontend/src/components/layout/header/Logo.astro
Normal file
214
frontend/src/components/layout/header/Logo.astro
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
---
|
||||
export interface Props {
|
||||
href?: string;
|
||||
variant?: 'light' | 'dark';
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
href = '/',
|
||||
variant = 'light',
|
||||
class: className = '',
|
||||
}: Props = Astro.props;
|
||||
|
||||
const isDark = variant === 'dark';
|
||||
const accentColor = '#eac26e';
|
||||
---
|
||||
|
||||
<a href={href} class={className} aria-label="Автоюрист 086 - главная страница">
|
||||
<div class="logo-container">
|
||||
<!-- Иконка: щит с рулём -->
|
||||
<div class="logo-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none" class="shield">
|
||||
<!-- Маска для анимации блика -->
|
||||
<defs>
|
||||
<linearGradient id="shineGradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" stop-color="black" />
|
||||
<stop offset="50%" stop-color="white" />
|
||||
<stop offset="100%" stop-color="black" />
|
||||
</linearGradient>
|
||||
<mask id="shineMask">
|
||||
<rect x="-100%" y="0" width="100%" height="48" fill="url(#shineGradient)" class="mask-rect" />
|
||||
</mask>
|
||||
</defs>
|
||||
|
||||
<!-- Базовый щит -->
|
||||
<path
|
||||
d="M24 4L6 10V22C6 34 24 44 24 44C24 44 42 34 42 22V10L24 4Z"
|
||||
fill={accentColor}
|
||||
stroke={accentColor}
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
|
||||
<!-- Слой блика с маской -->
|
||||
<path
|
||||
class="shine-layer"
|
||||
d="M24 4L6 10V22C6 34 24 44 24 44C24 44 42 34 42 22V10L24 4Z"
|
||||
fill="rgba(255,255,255,0.7)"
|
||||
mask="url(#shineMask)"
|
||||
style="opacity: 0;"
|
||||
/>
|
||||
|
||||
<!-- Руль внутри щита -->
|
||||
<circle cx="24" cy="24" r="8" fill={isDark ? '#1e3050' : '#ffffff'} opacity="0.9"/>
|
||||
<circle cx="24" cy="24" r="3" fill={accentColor}/>
|
||||
|
||||
<!-- Спицы руля -->
|
||||
<line x1="24" y1="16" x2="24" y2="20" stroke={isDark ? '#1e3050' : '#ffffff'} stroke-width="2"/>
|
||||
<line x1="24" y1="28" x2="24" y2="32" stroke={isDark ? '#1e3050' : '#ffffff'} stroke-width="2"/>
|
||||
<line x1="16" y1="24" x2="20" y2="24" stroke={isDark ? '#1e3050' : '#ffffff'} stroke-width="2"/>
|
||||
<line x1="28" y1="24" x2="32" y2="24" stroke={isDark ? '#1e3050' : '#ffffff'} stroke-width="2"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- Текст логотипа -->
|
||||
<div class="logo-text">
|
||||
<span class="logo-name">Автоюрист</span>
|
||||
<span class="logo-number">086</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<style>
|
||||
.logo-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
text-decoration: none;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.logo-container:hover {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
|
||||
position: relative;
|
||||
overflow: hidden; /* Обрезаем всё что выходит за границы */
|
||||
border-radius: 8px; /* Скругление для красоты */
|
||||
}
|
||||
|
||||
.shield {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: transform 0.3s ease;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Маска по умолчанию слева (не видно блика) */
|
||||
.mask-rect {
|
||||
transform: translateX(0%);
|
||||
transition: transform 0s;
|
||||
}
|
||||
|
||||
/* Слой блика скрыт по умолчанию */
|
||||
.shine-layer {
|
||||
opacity: 0;
|
||||
transition: opacity 0.1s ease;
|
||||
}
|
||||
|
||||
/* При наведении — анимируем маску и показываем блик */
|
||||
.logo-container:hover .shine-layer {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.logo-container:hover .mask-rect {
|
||||
animation: shineSlide 0.8s ease-out forwards;
|
||||
}
|
||||
|
||||
@keyframes shineSlide {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(200%);
|
||||
}
|
||||
}
|
||||
|
||||
/* CSS блик — теперь внутри иконки */
|
||||
.logo-icon::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -50%; /* Начинаем изнутри */
|
||||
width: 30%; /* Уменьшили ширину */
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
rgba(255, 255, 255, 0.9) 50%,
|
||||
transparent 100%
|
||||
);
|
||||
transform: skewX(-25deg);
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.logo-container:hover .logo-icon::after {
|
||||
animation: cssShine 0.7s ease-out 0.1s forwards;
|
||||
}
|
||||
|
||||
@keyframes cssShine {
|
||||
0% {
|
||||
left: -30%;
|
||||
opacity: 0;
|
||||
}
|
||||
10% {
|
||||
opacity: 1;
|
||||
}
|
||||
90% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
left: 100%; /* Останавливаемся внутри иконки */
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.logo-container:hover .shield {
|
||||
transform: rotate(-3deg);
|
||||
}
|
||||
|
||||
.logo-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.logo-name {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: #1e3050;
|
||||
letter-spacing: -0.3px;
|
||||
}
|
||||
|
||||
.logo-number {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 900;
|
||||
color: #eac26e;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.logo-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.logo-name {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.logo-number {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
291
frontend/src/components/layout/header/MobileMenu.astro
Normal file
291
frontend/src/components/layout/header/MobileMenu.astro
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
---
|
||||
import { NAV_LINKS } from '../../../constants/index.ts';
|
||||
---
|
||||
|
||||
<div class="mobile-menu-overlay" id="mobile-menu-overlay">
|
||||
<div class="mobile-menu">
|
||||
<!-- Кнопка закрытия -->
|
||||
<button class="mobile-menu-close" id="mobile-menu-close" aria-label="Закрыть меню">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- Логотип -->
|
||||
<a href="/" class="mobile-logo">
|
||||
<div class="logo-container">
|
||||
<div class="logo-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none" class="shield">
|
||||
<path d="M24 4L6 10V22C6 34 24 44 24 44C24 44 42 34 42 22V10L24 4Z" fill="#eac26e" stroke="#eac26e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="24" cy="24" r="8" fill="#1e3050" opacity="0.9"/>
|
||||
<circle cx="24" cy="24" r="3" fill="#eac26e"/>
|
||||
<line x1="24" y1="16" x2="24" y2="20" stroke="#1e3050" stroke-width="2"/>
|
||||
<line x1="24" y1="28" x2="24" y2="32" stroke="#1e3050" stroke-width="2"/>
|
||||
<line x1="16" y1="24" x2="20" y2="24" stroke="#1e3050" stroke-width="2"/>
|
||||
<line x1="28" y1="24" x2="32" y2="24" stroke="#1e3050" stroke-width="2"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="logo-text">
|
||||
<span class="logo-name">Автоюрист</span>
|
||||
<span class="logo-number">086</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- Навигация -->
|
||||
<nav class="mobile-nav">
|
||||
<ul class="mobile-nav-list">
|
||||
{NAV_LINKS.map((link, index) => (
|
||||
<li style={`--item-index: ${index}`}>
|
||||
<a href={link.url} class="mobile-nav-link">
|
||||
{link.name}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="link-arrow">
|
||||
<polyline points="9 18 15 12 9 6"></polyline>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- Контакты -->
|
||||
<div class="mobile-contacts">
|
||||
<a href="tel:+73462000000" class="mobile-phone">+7 (3462) 00-00-00</a>
|
||||
<a href="/login" class="mobile-login-btn">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path>
|
||||
<polyline points="10 17 15 12 10 7"></polyline>
|
||||
<line x1="15" y1="12" x2="3" y2="12"></line>
|
||||
</svg>
|
||||
<span>Вход в кабинет</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.mobile-menu-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(3, 21, 41, 0.95);
|
||||
backdrop-filter: blur(8px);
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.4s ease, visibility 0.4s ease;
|
||||
}
|
||||
|
||||
.mobile-menu-overlay.active {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.mobile-menu {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
height: 100%;
|
||||
background: linear-gradient(180deg, #0a2540 0%, #031529 100%);
|
||||
padding: 2rem 1.5rem;
|
||||
transform: translateX(100%);
|
||||
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.mobile-menu-overlay.active .mobile-menu {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
/* Кнопка закрытия */
|
||||
.mobile-menu-close {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #8c9bb0;
|
||||
cursor: pointer;
|
||||
padding: 0.5rem;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.mobile-menu-close:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #eac26e;
|
||||
}
|
||||
|
||||
/* Логотип */
|
||||
.mobile-logo {
|
||||
text-decoration: none;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
.shield {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.logo-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.logo-name {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
letter-spacing: -0.3px;
|
||||
}
|
||||
|
||||
.logo-number {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 900;
|
||||
color: #eac26e;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
/* Навигация */
|
||||
.mobile-nav {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mobile-nav-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.mobile-nav-list li {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
transition: opacity 0.3s ease, transform 0.3s ease;
|
||||
transition-delay: calc(0.05s * var(--item-index));
|
||||
}
|
||||
|
||||
.mobile-menu-overlay.active .mobile-nav-list li {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.mobile-nav-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 0.75rem;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.mobile-nav-link:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: #eac26e;
|
||||
}
|
||||
|
||||
.mobile-nav-link:hover .link-arrow {
|
||||
transform: translateX(4px);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.link-arrow {
|
||||
opacity: 0;
|
||||
transition: all 0.3s ease;
|
||||
color: #eac26e;
|
||||
}
|
||||
|
||||
/* Контакты */
|
||||
.mobile-contacts {
|
||||
margin-top: 2rem;
|
||||
padding-top: 2rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.mobile-phone {
|
||||
color: #eac26e;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
padding: 0.75rem;
|
||||
border-radius: 8px;
|
||||
background: rgba(234, 194, 110, 0.1);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.mobile-phone:hover {
|
||||
background: rgba(234, 194, 110, 0.2);
|
||||
}
|
||||
|
||||
.mobile-login-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.875rem 1.5rem;
|
||||
background: linear-gradient(135deg, #1e3050 0%, #2a4266 100%);
|
||||
color: #ffffff;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 12px rgba(30, 48, 80, 0.3);
|
||||
}
|
||||
|
||||
.mobile-login-btn:hover {
|
||||
box-shadow: 0 6px 20px rgba(30, 48, 80, 0.5);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
.mobile-menu::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.mobile-menu::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.mobile-menu::-webkit-scrollbar-thumb {
|
||||
background: rgba(234, 194, 110, 0.3);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.mobile-menu::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(234, 194, 110, 0.5);
|
||||
}
|
||||
</style>
|
||||
64
frontend/src/components/layout/header/Navbar.astro
Normal file
64
frontend/src/components/layout/header/Navbar.astro
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
export interface Props {
|
||||
links?: Array<{ name: string; url: string }>;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const defaultLinks = [
|
||||
{ name: 'Услуги', url: '/services' },
|
||||
{ name: 'Кейсы', url: '/cases' },
|
||||
{ name: 'Блог', url: '/blog' },
|
||||
{ name: 'Отзывы', url: '/reviews' },
|
||||
{ name: 'Контакты', url: '/contacts' },
|
||||
];
|
||||
|
||||
const {
|
||||
links = defaultLinks,
|
||||
class: className = '',
|
||||
}: Props = Astro.props;
|
||||
---
|
||||
|
||||
<nav class={className}>
|
||||
<ul class="nav-list">
|
||||
{links.map((link) => (
|
||||
<li>
|
||||
<a href={link.url} class="nav-link">{link.name}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<style>
|
||||
.nav-list {
|
||||
display: flex;
|
||||
gap: 2.5rem;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: #535e6c;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
transition: color 0.2s ease, background-position 0.3s ease;
|
||||
background-image: linear-gradient(to right, #1e3050 0%, #1e3050 100%);
|
||||
background-size: 0% 2px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: left bottom;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
color: #1e3050;
|
||||
background-size: 100% 2px;
|
||||
}
|
||||
|
||||
/* Адаптив: скрываем меню на мобильных */
|
||||
@media (max-width: 992px) {
|
||||
.nav-list {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue