Создана страницы faq

This commit is contained in:
Web-serfer 2026-04-11 21:38:18 +05:00
parent ed01ec28ed
commit 12d6c87f39
20 changed files with 89 additions and 158 deletions

View file

@ -3,10 +3,11 @@ import { defineConfig } from 'astro/config';
import tailwindcss from '@tailwindcss/vite';
import node from '@astrojs/node';
import mdx from '@astrojs/mdx';
import icon from "astro-icon";
// https://astro.build/config
export default defineConfig({
integrations: [mdx()],
integrations: [mdx(), icon()],
vite: {
plugins: [tailwindcss()],
},

View file

@ -16,6 +16,7 @@
"@astrojs/node": "^10.0.4",
"@tailwindcss/vite": "^4.2.2",
"astro": "^6.0.8",
"astro-icon": "^1.1.5",
"tailwindcss": "^4.2.2"
},
"devDependencies": {

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -1,5 +1,6 @@
---
import Button from '@components/base/Button.astro';
import { Icon } from 'astro-icon/components';
interface PageHeroProps {
badgeText: string;
@ -17,6 +18,7 @@ interface PageHeroProps {
number: string;
text: string;
};
icon?: string; // Название иконки из /src/icons/
}
const {
@ -31,7 +33,8 @@ const {
layout = "default",
sideImage = "",
sideImageAlt = "",
experienceBadge
experienceBadge,
icon
} = Astro.props as PageHeroProps;
const showImage = layout === 'with-image' && sideImage;
@ -43,7 +46,13 @@ const showImage = layout === 'with-image' && sideImage;
<div class="site-container hero-grid">
<div class="hero-content">
<div class="badge animate-load" data-delay="100">
<span class="status-dot"></span>
{icon ? (
<span class="badge-icon">
<Icon name={icon} />
</span>
) : (
<span class="status-dot"></span>
)}
{badgeText}
</div>
@ -207,7 +216,12 @@ const showImage = layout === 'with-image' && sideImage;
margin-bottom: 2.5rem;
}
/* Мерцающая точка */
.badge svg {
color: #eac26e;
flex-shrink: 0;
}
/* Мерцающая точка (только на главной) */
.status-dot {
width: 10px;
height: 10px;
@ -218,6 +232,19 @@ const showImage = layout === 'with-image' && sideImage;
flex-shrink: 0;
}
.badge-icon {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.badge-icon svg {
width: 20px !important;
height: 20px !important;
stroke-width: 2 !important;
}
@keyframes pulse {
0% {
transform: scale(0.95);

View file

@ -7,6 +7,7 @@ interface FaqItem {
const {
sectionSubtitle = "ОТВЕТЫ НА ВОПРОСЫ",
sectionTitle = "Часто задаваемые вопросы",
showTitle = true,
faqItems = [
{
question: "Сколько стоит первичная консультация?",
@ -38,18 +39,20 @@ const {
<section class="faq-section" id="faq">
<div class="site-container">
<!-- Заголовок секции -->
<div class="section-header">
<div class="subtitle-wrapper animate-on-scroll" data-animation="fade-up">
<div class="subtitle-line"></div>
<span class="subtitle">{sectionSubtitle}</span>
<div class="subtitle-line"></div>
{showTitle && (
<!-- Заголовок секции -->
<div class="section-header">
<div class="subtitle-wrapper animate-on-scroll" data-animation="fade-up">
<div class="subtitle-line"></div>
<span class="subtitle">{sectionSubtitle}</span>
<div class="subtitle-line"></div>
</div>
<h2 class="title animate-on-scroll" data-animation="fade-up" data-delay="100">{sectionTitle}</h2>
<p class="section-description animate-on-scroll" data-animation="fade-up" data-delay="150">
Собрали ответы на самые частые вопросы наших клиентов. Не нашли ответ? Позвоните — проконсультируем бесплатно
</p>
</div>
<h2 class="title animate-on-scroll" data-animation="fade-up" data-delay="100">{sectionTitle}</h2>
<p class="section-description animate-on-scroll" data-animation="fade-up" data-delay="150">
Собрали ответы на самые частые вопросы наших клиентов. Не нашли ответ? Позвоните — проконсультируем бесплатно
</p>
</div>
)}
<!-- Аккордеон FAQ -->
<div class="faq-container">

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 16 16"><!-- Icon from Bootstrap Icons by The Bootstrap Authors - https://github.com/twbs/icons/blob/main/LICENSE.md --><g fill="currentColor"><path d="M6.5 1A1.5 1.5 0 0 0 5 2.5V3H1.5A1.5 1.5 0 0 0 0 4.5v1.384l7.614 2.03a1.5 1.5 0 0 0 .772 0L16 5.884V4.5A1.5 1.5 0 0 0 14.5 3H11v-.5A1.5 1.5 0 0 0 9.5 1zm0 1h3a.5.5 0 0 1 .5.5V3H6v-.5a.5.5 0 0 1 .5-.5"/><path d="M0 12.5A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5V6.85L8.129 8.947a.5.5 0 0 1-.258 0L0 6.85z"/></g></svg>

After

Width:  |  Height:  |  Size: 547 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="m6 18l-2.3 2.3q-.475.475-1.088.213T2 19.575V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm1-4h6q.425 0 .713-.288T14 13t-.288-.712T13 12H7q-.425 0-.712.288T6 13t.288.713T7 14m0-3h10q.425 0 .713-.288T18 10t-.288-.712T17 9H7q-.425 0-.712.288T6 10t.288.713T7 11m0-3h10q.425 0 .713-.288T18 7t-.288-.712T17 6H7q-.425 0-.712.288T6 7t.288.713T7 8"/></svg>

After

Width:  |  Height:  |  Size: 604 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Design Icons by Pictogrammers - https://github.com/Templarian/MaterialDesign/blob/master/LICENSE --><path fill="currentColor" d="M8 12h8v2H8zm2 8H6V4h7v5h5v3.1l2-2V8l-6-6H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h4zm-2-2h4.1l.9-.9V16H8zm12.2-5c.1 0 .3.1.4.2l1.3 1.3c.2.2.2.6 0 .8l-1 1l-2.1-2.1l1-1c.1-.1.2-.2.4-.2m0 3.9L14.1 23H12v-2.1l6.1-6.1z"/></svg>

After

Width:  |  Height:  |  Size: 451 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE --><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M14 3v4a1 1 0 0 0 1 1h4"/><path d="M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7l5 5v11a2 2 0 0 1-2 2m-5-4v-6"/><path d="M9.5 14.5L12 17l2.5-2.5"/></g></svg>

After

Width:  |  Height:  |  Size: 452 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols Light by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="M10.616 19.654h2.769q.161 0 .273-.112t.111-.273t-.111-.273q-.112-.111-.273-.111h-2.77q-.161 0-.273.111q-.111.112-.111.273t.111.273t.273.112m-3 2.346q-.69 0-1.152-.462T6 20.385V3.615q0-.69.463-1.152T7.616 2h8.769q.69 0 1.152.463T18 3.616v16.769q0 .69-.462 1.153T16.384 22zM7 16.538h10V5.5H7z"/></svg>

After

Width:  |  Height:  |  Size: 533 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="M14.6 8.075q0-1.075-.712-1.725T12 5.7q-.725 0-1.312.313t-1.013.912q-.4.575-1.088.663T7.4 7.225q-.35-.325-.387-.8t.237-.9q.8-1.2 2.038-1.862T12 3q2.425 0 3.938 1.375t1.512 3.6q0 1.125-.475 2.025t-1.75 2.125q-.925.875-1.25 1.363T13.55 14.6q-.1.6-.513 1t-.987.4t-.987-.387t-.413-.963q0-.975.425-1.787T12.5 11.15q1.275-1.125 1.688-1.737t.412-1.338M12 22q-.825 0-1.412-.587T10 20t.588-1.412T12 18t1.413.588T14 20t-.587 1.413T12 22"/></svg>

After

Width:  |  Height:  |  Size: 661 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from BoxIcons by Atisa - https://creativecommons.org/licenses/by/4.0/ --><path fill="currentColor" d="M20.995 6.9a1 1 0 0 0-.548-.795l-8-4a1 1 0 0 0-.895 0l-8 4a1 1 0 0 0-.547.795c-.011.107-.961 10.767 8.589 15.014a1 1 0 0 0 .812 0c9.55-4.247 8.6-14.906 8.589-15.014M12 19.897C5.231 16.625 4.911 9.642 4.966 7.635L12 4.118l7.029 3.515c.037 1.989-.328 9.018-7.029 12.264"/><path fill="currentColor" d="m11 12.586l-2.293-2.293l-1.414 1.414L11 15.414l5.707-5.707l-1.414-1.414z"/></svg>

After

Width:  |  Height:  |  Size: 575 B

View file

@ -57,6 +57,7 @@ const categories = ['Все', ...new Set(posts.map((post: any) => post.data.cate
text: "ПОЛЕЗНЫХ СТАТЕЙ"
}}
bgImage="/images/blog/blogBg.avif"
icon="edit"
/>
<BlogCategories categories={categories} activeCategory="Все" currentPage={currentPage} />

View file

@ -28,6 +28,7 @@ import CasesList from "@components/cases/CasesList.astro";
text: "ВЫИГРАННЫХ ДЕЛ"
}}
bgImage="/images/cases/casesBg.avif"
icon="briefcase"
/>
<CasesList />
</Layout>

View file

@ -30,6 +30,7 @@ const isAuthorized = false; // Измените на true, чтобы увиде
text: "МИНУТ НА СВЯЗИ"
}}
bgImage="/images/contacts/conBg.avif"
icon="phone"
/>
<!-- Карточки контактов -->

View file

@ -1,6 +1,7 @@
---
import Layout from '@layouts/Layout.astro';
import { SITE_URL } from '@constants';
import PageHero from '@components/base/PageHero.astro';
import DocCard from '@components/documents/DocCard.astro';
import DocCategories from '@components/documents/DocCategories.astro';
import Pagination from '@components/base/Pagination.astro';
@ -34,25 +35,17 @@ const categories = getCategories();
{ label: 'Документы' }
]}
>
<PageHero
badgeText="ДОКУМЕНТЫ"
titleWhite="Документы для"
titleGold="скачивания"
description="Здесь вы можете скачать все необходимые документы, договоры, памятки и шаблоны в удобном формате"
bgImage=""
icon="file"
/>
<section class="documents-section">
<div class="site-container">
<!-- Заголовок секции -->
<div class="section-header">
<div class="subtitle-wrapper animate-on-scroll" data-animation="fade-up">
<div class="subtitle-line"></div>
<span class="subtitle">ДОКУМЕНТЫ</span>
<div class="subtitle-line"></div>
</div>
<div class="title-wrapper animate-on-scroll" data-animation="fade-up" data-delay="100">
<h1 class="title">
Документы для скачивания
</h1>
</div>
<p class="section-description animate-on-scroll" data-animation="fade-up" data-delay="150">
Здесь вы можете скачать все необходимые документы, договоры, памятки и шаблоны в удобном формате
</p>
</div>
<!-- Фильтры по категориям -->
<DocCategories categories={categories} activeCategory={activeCategory} />
@ -99,12 +92,11 @@ const categories = getCategories();
}
.documents-section {
padding: 6rem 1.5rem 4rem;
padding: 2rem 1.5rem 4rem;
background: var(--gradient-docs-bg);
position: relative;
overflow: hidden;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
min-height: 100vh;
}
.documents-section::before {
@ -125,64 +117,6 @@ const categories = getCategories();
z-index: 2;
}
/* Заголовок секции */
.section-header {
margin-bottom: 3rem;
text-align: center;
}
.subtitle-wrapper {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
margin-bottom: 1rem;
}
.subtitle-line {
width: 40px;
height: 1px;
background: linear-gradient(90deg, transparent, var(--color-accent-docs), transparent);
}
.subtitle {
color: var(--color-accent-docs);
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 4px;
}
.title-wrapper {
display: flex;
align-items: center;
justify-content: center;
gap: 1.5rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.title {
color: var(--color-light-docs);
font-size: clamp(2rem, 4vw, 3.5rem);
font-weight: 800;
margin: 0;
line-height: 1.2;
letter-spacing: -0.02em;
background: linear-gradient(135deg, #ffffff 0%, #e2e8f0 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.section-description {
color: var(--color-gray-docs);
font-size: 1.1rem;
max-width: 700px;
margin: 0 auto;
line-height: 1.6;
}
/* Сетка документов */
.documents-grid {
display: grid;
@ -191,23 +125,6 @@ const categories = getCategories();
margin-bottom: 3rem;
}
/* Анимации при скроллинге */
.animate-on-scroll {
opacity: 0;
will-change: opacity, transform;
}
[data-animation="fade-up"] {
transform: translateY(40px);
transition: opacity 0.8s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.8s cubic-bezier(0.4, 0, 0.2, 1);
}
.animate-on-scroll.is-visible {
opacity: 1;
transform: translateY(0);
}
/* Пагинация */
:global(.pagination) {
padding: 2rem 0 4rem;
@ -222,60 +139,16 @@ const categories = getCategories();
@media (max-width: 768px) {
.documents-section {
padding: 4rem 1rem 3rem;
}
.section-header {
margin-bottom: 2.5rem;
}
.title-wrapper {
flex-direction: column;
gap: 1rem;
padding: 2rem 1rem 3rem;
}
.documents-grid {
grid-template-columns: 1fr;
}
}
@media (prefers-reduced-motion: reduce) {
.animate-on-scroll {
opacity: 1;
transform: none;
transition: none;
}
}
</style>
<script>
const setupAnimations = () => {
const observerOptions = {
root: null,
rootMargin: '0px',
threshold: 0.1
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const el = entry.target as HTMLElement;
const delay = parseInt(el.dataset.delay || '0');
setTimeout(() => {
el.classList.add('is-visible');
}, delay);
observer.unobserve(el);
}
});
}, observerOptions);
document.querySelectorAll('.animate-on-scroll').forEach((el) => {
observer.observe(el);
});
};
const setupFilter = () => {
const buttons = document.querySelectorAll('.category-btn');
const cards = document.querySelectorAll('.doc-card');
@ -300,11 +173,9 @@ const categories = getCategories();
});
};
setupAnimations();
setupFilter();
document.addEventListener('astro:after-swap', () => {
setupAnimations();
setupFilter();
});
</script>

View file

@ -1,6 +1,7 @@
---
import Layout from '@layouts/Layout.astro';
import { SITE_URL } from '@constants';
import PageHero from '@components/base/PageHero.astro';
import Faq from '@components/faq/FaqItem.astro';
import Pagination from '@components/base/Pagination.astro';
@ -102,11 +103,26 @@ const currentFaqItems = allFaqItems.slice(startIndex, endIndex);
{ label: 'Частые вопросы' }
]}
>
<PageHero
badgeText="ОТВЕТЫ НА ВОПРОСЫ"
titleWhite="Часто задаваемые"
titleGold="вопросы"
description="Собрали ответы на самые частые вопросы наших клиентов. Не нашли ответ? Позвоните — проконсультируем бесплатно"
layout="with-image"
sideImage="/images/faq/faqImg.avif"
sideImageAlt="Автоюрист Сургут"
experienceBadge={{
number: "98%",
text: "УСПЕШНЫХ ДЕЛ"
}}
bgImage="/images/faq/faqBg.avif"
icon="question"
/>
<section class="faq-page-section">
<Faq
sectionSubtitle="ОТВЕТЫ НА ВОПРОСЫ"
sectionTitle="Часто задаваемые вопросы"
faqItems={currentFaqItems}
showTitle={false}
/>
{totalPages > 1 && (

View file

@ -42,6 +42,7 @@ const paginatedReviews = reviewsData.slice(startIndex, endIndex);
text: "ДОВОЛЬНЫХ КЛИЕНТОВ"
}}
bgImage="/images/reviews/revBg.avif"
icon="chat"
/>
<section class="reviews-page">

View file

@ -30,6 +30,7 @@ import ServiceCategories from "@components/services/ServiceCategories.astro";
text: "НАПРАВЛЕНИЙ ПРАКТИКИ"
}}
bgImage="/images/services/servicesBg.avif"
icon="shield"
/>
<ServiceCategories />
<Pagination