2941b14b38
- Moved contents of main_dc/yalarba/easySite/easySite/ up to easySite/ - Updated docker-compose.yml build context path - Deleted empty nested easySite/ directory
1142 lines
29 KiB
Vue
1142 lines
29 KiB
Vue
<template>
|
||
<div class="page-wrapper">
|
||
<!-- Хедер -->
|
||
<Header />
|
||
|
||
<!-- Основной контент -->
|
||
<main class="news-page">
|
||
<!-- Hero секция -->
|
||
<section class="news-hero">
|
||
<div class="container">
|
||
<div class="hero-content">
|
||
<h1 class="hero-title">Новости</h1>
|
||
<p class="hero-subtitle">
|
||
Будьте в курсе последних событий, обновлений и важных объявлений компании
|
||
</p>
|
||
<div class="news-stats">
|
||
<div class="stat-item">
|
||
<span class="stat-number">{{ totalNews }}</span>
|
||
<span class="stat-label">новостей</span>
|
||
</div>
|
||
<div class="stat-item">
|
||
<span class="stat-number">{{ currentYear }}</span>
|
||
<span class="stat-label">год</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Фильтры и поиск -->
|
||
<section class="news-filters">
|
||
<div class="container">
|
||
<div class="filters-content">
|
||
<div class="search-box">
|
||
<input
|
||
v-model="searchQuery"
|
||
type="text"
|
||
class="search-input"
|
||
placeholder="Поиск по новостям..."
|
||
@input="handleSearch"
|
||
>
|
||
<span class="search-icon">🔍</span>
|
||
</div>
|
||
|
||
<div class="filter-controls">
|
||
<div class="filter-group">
|
||
<label class="filter-label">Категория:</label>
|
||
<select v-model="selectedCategory" @change="filterNews" class="filter-select">
|
||
<option value="all">Все категории</option>
|
||
<option value="company">Компания</option>
|
||
<option value="updates">Обновления</option>
|
||
<option value="events">События</option>
|
||
<option value="partnership">Партнерство</option>
|
||
<option value="technology">Технологии</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="filter-group">
|
||
<label class="filter-label">Год:</label>
|
||
<select v-model="selectedYear" @change="filterNews" class="filter-select">
|
||
<option value="all">Все годы</option>
|
||
<option v-for="year in availableYears" :key="year" :value="year">
|
||
{{ year }}
|
||
</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="view-toggle">
|
||
<button
|
||
@click="viewMode = 'grid'"
|
||
:class="['view-button', { 'active': viewMode === 'grid' }]"
|
||
aria-label="Сетка"
|
||
>
|
||
▦
|
||
</button>
|
||
<button
|
||
@click="viewMode = 'list'"
|
||
:class="['view-button', { 'active': viewMode === 'list' }]"
|
||
aria-label="Список"
|
||
>
|
||
☰
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Основной контент новостей -->
|
||
<section class="news-content">
|
||
<div class="container">
|
||
<!-- Заголовок с результатами -->
|
||
<div class="results-header">
|
||
<h2 class="results-title">
|
||
{{ filteredNews.length }} {{ getNewsCountText(filteredNews.length) }}
|
||
<span v-if="selectedCategory !== 'all'" class="filter-indicator">
|
||
в категории "{{ getCategoryName(selectedCategory) }}"
|
||
</span>
|
||
<span v-if="selectedYear !== 'all'" class="filter-indicator">
|
||
за {{ selectedYear }} год
|
||
</span>
|
||
</h2>
|
||
</div>
|
||
|
||
<!-- Список новостей -->
|
||
<div v-if="filteredNews.length > 0" :class="['news-grid', { 'list-view': viewMode === 'list' }]">
|
||
<article
|
||
v-for="newsItem in paginatedNews"
|
||
:key="newsItem.id"
|
||
:class="['news-card', { 'featured': newsItem.featured }]"
|
||
>
|
||
<div class="news-image">
|
||
<div class="image-placeholder">
|
||
{{ getCategoryIcon(newsItem.category) }}
|
||
</div>
|
||
<div class="news-badges">
|
||
<span class="news-category">{{ getCategoryName(newsItem.category) }}</span>
|
||
<span v-if="newsItem.featured" class="news-featured">Важно</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="news-body">
|
||
<div class="news-meta">
|
||
<span class="news-date">{{ formatDate(newsItem.date) }}</span>
|
||
<span class="news-read-time">⏱️ {{ newsItem.readTime }}</span>
|
||
</div>
|
||
|
||
<h3 class="news-title">
|
||
<NuxtLink :to="`/news/${newsItem.id}`" class="news-link">
|
||
{{ newsItem.title }}
|
||
</NuxtLink>
|
||
</h3>
|
||
|
||
<p class="news-excerpt">{{ newsItem.excerpt }}</p>
|
||
|
||
<div class="news-footer">
|
||
<div class="news-tags">
|
||
<span
|
||
v-for="tag in (newsItem.tags || []).slice(0, 2)"
|
||
:key="tag"
|
||
class="news-tag"
|
||
>
|
||
#{{ tag }}
|
||
</span>
|
||
<span v-if="(newsItem.tags || []).length > 2" class="news-tag-more">
|
||
+{{ (newsItem.tags || []).length - 2 }}
|
||
</span>
|
||
</div>
|
||
<NuxtLink :to="`/news/${newsItem.id}`" class="read-more">
|
||
Читать далее →
|
||
</NuxtLink>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
|
||
<!-- Пагинация -->
|
||
<div v-if="totalPages > 1 && filteredNews.length > 0" class="pagination">
|
||
<button
|
||
@click="prevPage"
|
||
:disabled="currentPage === 1"
|
||
class="pagination-button prev"
|
||
>
|
||
← Назад
|
||
</button>
|
||
|
||
<div class="pagination-pages">
|
||
<button
|
||
v-for="page in visiblePages"
|
||
:key="page"
|
||
@click="goToPage(page)"
|
||
:class="['pagination-page', { 'active': page === currentPage }]"
|
||
:disabled="page === '...'"
|
||
>
|
||
{{ page }}
|
||
</button>
|
||
</div>
|
||
|
||
<button
|
||
@click="nextPage"
|
||
:disabled="currentPage === totalPages"
|
||
class="pagination-button next"
|
||
>
|
||
Вперед →
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Сообщение, если новостей нет -->
|
||
<div v-if="filteredNews.length === 0" class="no-news">
|
||
<div class="no-news-icon">📰</div>
|
||
<h3 class="no-news-title">Новости не найдены</h3>
|
||
<p class="no-news-description">
|
||
Попробуйте изменить параметры поиска или выбрать другую категорию
|
||
</p>
|
||
<button @click="resetFilters" class="btn btn-primary">
|
||
Сбросить фильтры
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Подписка на новости -->
|
||
<section class="newsletter-section">
|
||
<div class="container">
|
||
<div class="newsletter-card">
|
||
<div class="newsletter-content">
|
||
<h2 class="newsletter-title">Будьте в курсе новостей</h2>
|
||
<p class="newsletter-description">
|
||
Подпишитесь на рассылку и получайте самые важные новости первыми
|
||
</p>
|
||
<form @submit.prevent="subscribeNewsletter" class="newsletter-form">
|
||
<div class="form-group">
|
||
<input
|
||
v-model="email"
|
||
type="email"
|
||
class="newsletter-input"
|
||
placeholder="your@email.com"
|
||
required
|
||
>
|
||
<button type="submit" class="btn btn-primary newsletter-button">
|
||
Подписаться
|
||
</button>
|
||
</div>
|
||
<p class="newsletter-note">
|
||
Подписываясь, вы соглашаетесь с обработкой персональных данных
|
||
</p>
|
||
</form>
|
||
</div>
|
||
<div class="newsletter-icon">📧</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<!-- Футер -->
|
||
<Footer />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
// Импорты в начале файла
|
||
const Header = defineAsyncComponent(() => import('~/components/layout/Header.vue'))
|
||
const Footer = defineAsyncComponent(() => import('~/components/layout/Footer.vue'))
|
||
|
||
definePageMeta({
|
||
title: 'Новости - ООО "ИКЦ ЯЛ АРБА"'
|
||
})
|
||
|
||
// Состояние фильтров и поиска
|
||
const searchQuery = ref('')
|
||
const selectedCategory = ref('all')
|
||
const selectedYear = ref('all')
|
||
const viewMode = ref<'grid' | 'list'>('grid')
|
||
const email = ref('')
|
||
|
||
// Пагинация
|
||
const currentPage = ref(1)
|
||
const itemsPerPage = 6
|
||
|
||
// Моковые данные новостей с гарантированной структурой
|
||
const news = ref([
|
||
{
|
||
id: 1,
|
||
title: 'Запуск новой платформы для создания сайтов',
|
||
excerpt: 'Представляем революционную платформу, которая позволяет создавать профессиональные сайты за считанные минуты без навыков программирования.',
|
||
content: 'Полный текст новости...',
|
||
category: 'updates',
|
||
date: '2025-12-15',
|
||
readTime: '3 мин',
|
||
tags: ['платформа', 'запуск', 'технологии'],
|
||
featured: true
|
||
},
|
||
{
|
||
id: 2,
|
||
title: 'Новое партнерство с ведущими IT-компаниями',
|
||
excerpt: 'Мы объявляем о стратегическом партнерстве с крупными игроками рынка для расширения возможностей нашей платформы.',
|
||
content: 'Полный текст новости...',
|
||
category: 'partnership',
|
||
date: '2023-12-10',
|
||
readTime: '4 мин',
|
||
tags: ['партнерство', 'развитие', 'сотрудничество'],
|
||
featured: false
|
||
},
|
||
{
|
||
id: 3,
|
||
title: 'Обновление интерфейса пользователя',
|
||
excerpt: 'Значительно улучшен пользовательский интерфейс платформы для большего удобства и эффективности работы.',
|
||
content: 'Полный текст новости...',
|
||
category: 'updates',
|
||
date: '2023-12-05',
|
||
readTime: '2 мин',
|
||
tags: ['интерфейс', 'обновление', 'UX'],
|
||
featured: false
|
||
},
|
||
{
|
||
id: 4,
|
||
title: 'Проведение вебинара по цифровой трансформации',
|
||
excerpt: 'Приглашаем на бесплатный вебинар, посвященный современным тенденциям цифровой трансформации бизнеса.',
|
||
content: 'Полный текст новости...',
|
||
category: 'events',
|
||
date: '2023-11-28',
|
||
readTime: '1 мин',
|
||
tags: ['вебинар', 'образование', 'бизнес'],
|
||
featured: true
|
||
},
|
||
{
|
||
id: 5,
|
||
title: 'Расширение команды разработки',
|
||
excerpt: 'Наша команда пополнилась новыми талантливыми разработчиками для ускорения развития платформы.',
|
||
content: 'Полный текст новости...',
|
||
category: 'company',
|
||
date: '2023-11-20',
|
||
readTime: '2 мин',
|
||
tags: ['команда', 'разработка', 'кадры'],
|
||
featured: false
|
||
},
|
||
{
|
||
id: 6,
|
||
title: 'Внедрение искусственного интеллекта',
|
||
excerpt: 'Интегрировали AI-технологии для автоматизации процессов и предоставления умных рекомендаций пользователям.',
|
||
content: 'Полный текст новости...',
|
||
category: 'technology',
|
||
date: '2023-11-15',
|
||
readTime: '5 мин',
|
||
tags: ['AI', 'технологии', 'инновации'],
|
||
featured: false
|
||
}
|
||
])
|
||
|
||
// Вычисляемые свойства
|
||
const totalNews = computed(() => news.value?.length || 0)
|
||
|
||
const currentYear = computed(() => new Date().getFullYear())
|
||
|
||
const availableYears = computed(() => {
|
||
if (!news.value) return []
|
||
const years = new Set(news.value.map(item => new Date(item.date).getFullYear()))
|
||
return Array.from(years).sort((a, b) => b - a)
|
||
})
|
||
|
||
const filteredNews = computed(() => {
|
||
if (!news.value) return []
|
||
|
||
let filtered = [...news.value]
|
||
|
||
// Фильтрация по поисковому запросу
|
||
if (searchQuery.value) {
|
||
const query = searchQuery.value.toLowerCase()
|
||
filtered = filtered.filter(item =>
|
||
item.title?.toLowerCase().includes(query) ||
|
||
item.excerpt?.toLowerCase().includes(query) ||
|
||
item.tags?.some(tag => tag.toLowerCase().includes(query))
|
||
)
|
||
}
|
||
|
||
// Фильтрация по категории
|
||
if (selectedCategory.value !== 'all') {
|
||
filtered = filtered.filter(item => item.category === selectedCategory.value)
|
||
}
|
||
|
||
// Фильтрация по году
|
||
if (selectedYear.value !== 'all') {
|
||
filtered = filtered.filter(item =>
|
||
new Date(item.date).getFullYear().toString() === selectedYear.value
|
||
)
|
||
}
|
||
|
||
// Сортировка по дате (новые сначала)
|
||
return filtered.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
||
})
|
||
|
||
const totalPages = computed(() => Math.ceil((filteredNews.value?.length || 0) / itemsPerPage))
|
||
|
||
const paginatedNews = computed(() => {
|
||
const start = (currentPage.value - 1) * itemsPerPage
|
||
const end = start + itemsPerPage
|
||
return filteredNews.value?.slice(start, end) || []
|
||
})
|
||
|
||
const visiblePages = computed(() => {
|
||
const total = totalPages.value
|
||
const current = currentPage.value
|
||
const pages = []
|
||
|
||
if (total <= 7) {
|
||
for (let i = 1; i <= total; i++) pages.push(i)
|
||
} else {
|
||
if (current <= 4) {
|
||
for (let i = 1; i <= 5; i++) pages.push(i)
|
||
pages.push('...')
|
||
pages.push(total)
|
||
} else if (current >= total - 3) {
|
||
pages.push(1)
|
||
pages.push('...')
|
||
for (let i = total - 4; i <= total; i++) pages.push(i)
|
||
} else {
|
||
pages.push(1)
|
||
pages.push('...')
|
||
for (let i = current - 1; i <= current + 1; i++) pages.push(i)
|
||
pages.push('...')
|
||
pages.push(total)
|
||
}
|
||
}
|
||
|
||
return pages
|
||
})
|
||
|
||
// Методы
|
||
const handleSearch = () => {
|
||
currentPage.value = 1
|
||
}
|
||
|
||
const filterNews = () => {
|
||
currentPage.value = 1
|
||
}
|
||
|
||
const resetFilters = () => {
|
||
searchQuery.value = ''
|
||
selectedCategory.value = 'all'
|
||
selectedYear.value = 'all'
|
||
currentPage.value = 1
|
||
}
|
||
|
||
const prevPage = () => {
|
||
if (currentPage.value > 1) currentPage.value--
|
||
}
|
||
|
||
const nextPage = () => {
|
||
if (currentPage.value < totalPages.value) currentPage.value++
|
||
}
|
||
|
||
const goToPage = (page: number | string) => {
|
||
if (typeof page === 'number') {
|
||
currentPage.value = page
|
||
}
|
||
}
|
||
|
||
const formatDate = (dateString: string) => {
|
||
try {
|
||
const date = new Date(dateString)
|
||
return date.toLocaleDateString('ru-RU', {
|
||
day: 'numeric',
|
||
month: 'long',
|
||
year: 'numeric'
|
||
})
|
||
} catch {
|
||
return dateString
|
||
}
|
||
}
|
||
|
||
const getCategoryName = (category: string) => {
|
||
const categories: { [key: string]: string } = {
|
||
company: 'Компания',
|
||
updates: 'Обновления',
|
||
events: 'События',
|
||
partnership: 'Партнерство',
|
||
technology: 'Технологии'
|
||
}
|
||
return categories[category] || category
|
||
}
|
||
|
||
const getCategoryIcon = (category: string) => {
|
||
const icons: { [key: string]: string } = {
|
||
company: '🏢',
|
||
updates: '🔄',
|
||
events: '📅',
|
||
partnership: '🤝',
|
||
technology: '💻'
|
||
}
|
||
return icons[category] || '📰'
|
||
}
|
||
|
||
const getNewsCountText = (count: number) => {
|
||
if (count % 10 === 1 && count % 100 !== 11) return 'новость'
|
||
if (count % 10 >= 2 && count % 10 <= 4 && (count % 100 < 10 || count % 100 >= 20)) return 'новости'
|
||
return 'новостей'
|
||
}
|
||
|
||
const subscribeNewsletter = async () => {
|
||
if (!email.value) return
|
||
|
||
try {
|
||
// Временно убираем Telegram для устранения ошибок
|
||
console.log('Подписка на рассылку:', email.value)
|
||
|
||
alert('✅ Вы успешно подписались на рассылку!')
|
||
email.value = ''
|
||
} catch (error) {
|
||
console.error('Ошибка подписки:', error)
|
||
alert('❌ Произошла ошибка при подписке. Попробуйте позже.')
|
||
}
|
||
}
|
||
|
||
// Обработка ошибок
|
||
onMounted(() => {
|
||
console.log('News page mounted')
|
||
})
|
||
|
||
onErrorCaptured((error) => {
|
||
console.error('Error captured in news page:', error)
|
||
return false
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.page-wrapper {
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.news-page {
|
||
flex: 1;
|
||
}
|
||
|
||
/* Hero секция */
|
||
.news-hero {
|
||
background: var(--hero-gradient);
|
||
color: white;
|
||
position: relative;
|
||
overflow: hidden;
|
||
padding: 4rem 0;
|
||
text-align: center;
|
||
}
|
||
|
||
.news-hero::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: var(--hero-pattern);
|
||
opacity: 0.1;
|
||
}
|
||
|
||
.hero-content {
|
||
position: relative;
|
||
z-index: 10;
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.hero-title {
|
||
font-family: var(--font-heading);
|
||
font-size: var(--text-4xl);
|
||
font-weight: var(--font-bold);
|
||
line-height: var(--leading-tight);
|
||
margin-bottom: var(--space-lg);
|
||
color: white;
|
||
}
|
||
|
||
.hero-subtitle {
|
||
font-family: var(--font-accent);
|
||
font-size: var(--text-xl);
|
||
font-weight: var(--font-light);
|
||
line-height: var(--leading-relaxed);
|
||
opacity: 0.9;
|
||
color: white;
|
||
margin-bottom: var(--space-2xl);
|
||
}
|
||
|
||
.news-stats {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: var(--space-2xl);
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.stat-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.stat-number {
|
||
font-size: var(--text-3xl);
|
||
font-weight: var(--font-bold);
|
||
color: white;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: var(--text-sm);
|
||
color: rgba(255, 255, 255, 0.8);
|
||
text-transform: uppercase;
|
||
letter-spacing: var(--tracking-wide);
|
||
}
|
||
|
||
/* Фильтры */
|
||
.news-filters {
|
||
background: var(--bg-secondary);
|
||
padding: var(--space-xl) 0;
|
||
border-bottom: 1px solid var(--border-light);
|
||
}
|
||
|
||
.filters-content {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
gap: var(--space-xl);
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.search-box {
|
||
position: relative;
|
||
flex: 1;
|
||
max-width: 400px;
|
||
}
|
||
|
||
.search-input {
|
||
width: 100%;
|
||
padding: var(--space-sm) var(--space-xl) var(--space-sm) var(--space-md);
|
||
border: 1px solid var(--border-medium);
|
||
border-radius: var(--radius-lg);
|
||
background: var(--bg-primary);
|
||
color: var(--text-primary);
|
||
font-size: var(--text-base);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.search-input:focus {
|
||
outline: none;
|
||
border-color: var(--primary-500);
|
||
box-shadow: 0 0 0 3px rgb(14 165 233 / 0.1);
|
||
}
|
||
|
||
.search-icon {
|
||
position: absolute;
|
||
right: var(--space-md);
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
color: var(--text-tertiary);
|
||
}
|
||
|
||
.filter-controls {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-lg);
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.filter-group {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-sm);
|
||
}
|
||
|
||
.filter-label {
|
||
font-size: var(--text-sm);
|
||
color: var(--text-secondary);
|
||
font-weight: var(--font-medium);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.filter-select {
|
||
padding: var(--space-xs) var(--space-sm);
|
||
border: 1px solid var(--border-medium);
|
||
border-radius: var(--radius-md);
|
||
background: var(--bg-primary);
|
||
color: var(--text-primary);
|
||
font-size: var(--text-sm);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.view-toggle {
|
||
display: flex;
|
||
border: 1px solid var(--border-medium);
|
||
border-radius: var(--radius-md);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.view-button {
|
||
padding: var(--space-xs) var(--space-sm);
|
||
background: var(--bg-primary);
|
||
border: none;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
font-size: var(--text-lg);
|
||
}
|
||
|
||
.view-button:hover {
|
||
background: var(--bg-secondary);
|
||
}
|
||
|
||
.view-button.active {
|
||
background: var(--primary-500);
|
||
color: white;
|
||
}
|
||
|
||
/* Основной контент */
|
||
.news-content {
|
||
padding: var(--space-2xl) 0;
|
||
}
|
||
|
||
.results-header {
|
||
margin-bottom: var(--space-2xl);
|
||
}
|
||
|
||
.results-title {
|
||
font-family: var(--font-heading);
|
||
font-size: var(--text-2xl);
|
||
font-weight: var(--font-semibold);
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.filter-indicator {
|
||
color: var(--text-secondary);
|
||
font-weight: var(--font-normal);
|
||
}
|
||
|
||
/* Сетка новостей */
|
||
.news-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
||
gap: var(--space-xl);
|
||
margin-bottom: var(--space-2xl);
|
||
}
|
||
|
||
.news-grid.list-view {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.news-grid.list-view .news-card {
|
||
display: grid;
|
||
grid-template-columns: 200px 1fr;
|
||
gap: var(--space-lg);
|
||
}
|
||
|
||
.news-card {
|
||
background: var(--bg-primary);
|
||
border-radius: var(--radius-xl);
|
||
overflow: hidden;
|
||
border: 1px solid var(--border-light);
|
||
transition: all 0.3s ease;
|
||
position: relative;
|
||
}
|
||
|
||
.news-card:hover {
|
||
transform: translateY(-4px);
|
||
box-shadow: var(--shadow-lg);
|
||
}
|
||
|
||
.news-card.featured {
|
||
border-color: var(--primary-500);
|
||
box-shadow: 0 0 0 1px var(--primary-500);
|
||
}
|
||
|
||
.news-image {
|
||
position: relative;
|
||
height: 200px;
|
||
overflow: hidden;
|
||
background: var(--bg-secondary);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.image-placeholder {
|
||
font-size: 3rem;
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.news-badges {
|
||
position: absolute;
|
||
top: var(--space-md);
|
||
left: var(--space-md);
|
||
display: flex;
|
||
gap: var(--space-xs);
|
||
}
|
||
|
||
.news-category {
|
||
background: var(--primary-500);
|
||
color: white;
|
||
padding: 0.25rem 0.5rem;
|
||
border-radius: var(--radius-sm);
|
||
font-size: var(--text-xs);
|
||
font-weight: var(--font-semibold);
|
||
text-transform: uppercase;
|
||
letter-spacing: var(--tracking-wide);
|
||
}
|
||
|
||
.news-featured {
|
||
background: var(--error-500);
|
||
color: white;
|
||
padding: 0.25rem 0.5rem;
|
||
border-radius: var(--radius-sm);
|
||
font-size: var(--text-xs);
|
||
font-weight: var(--font-semibold);
|
||
}
|
||
|
||
.news-body {
|
||
padding: var(--space-lg);
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex: 1;
|
||
}
|
||
|
||
.news-meta {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: var(--space-sm);
|
||
font-size: var(--text-sm);
|
||
color: var(--text-tertiary);
|
||
}
|
||
|
||
.news-date {
|
||
font-weight: var(--font-medium);
|
||
}
|
||
|
||
.news-read-time {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-xs);
|
||
}
|
||
|
||
.news-title {
|
||
margin-bottom: var(--space-md);
|
||
}
|
||
|
||
.news-link {
|
||
font-family: var(--font-heading);
|
||
font-size: var(--text-xl);
|
||
font-weight: var(--font-semibold);
|
||
color: var(--text-primary);
|
||
text-decoration: none;
|
||
line-height: var(--leading-tight);
|
||
transition: color 0.2s ease;
|
||
}
|
||
|
||
.news-link:hover {
|
||
color: var(--primary-600);
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.news-excerpt {
|
||
color: var(--text-secondary);
|
||
line-height: var(--leading-relaxed);
|
||
margin-bottom: var(--space-lg);
|
||
flex: 1;
|
||
}
|
||
|
||
.news-footer {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-top: auto;
|
||
}
|
||
|
||
.news-tags {
|
||
display: flex;
|
||
gap: var(--space-xs);
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.news-tag {
|
||
background: var(--bg-secondary);
|
||
color: var(--text-secondary);
|
||
padding: 0.25rem 0.5rem;
|
||
border-radius: var(--radius-sm);
|
||
font-size: var(--text-xs);
|
||
font-weight: var(--font-medium);
|
||
}
|
||
|
||
.news-tag-more {
|
||
color: var(--text-tertiary);
|
||
font-size: var(--text-xs);
|
||
font-style: italic;
|
||
}
|
||
|
||
.read-more {
|
||
color: var(--primary-600);
|
||
text-decoration: none;
|
||
font-weight: var(--font-semibold);
|
||
font-size: var(--text-sm);
|
||
transition: color 0.2s ease;
|
||
}
|
||
|
||
.read-more:hover {
|
||
color: var(--primary-700);
|
||
text-decoration: underline;
|
||
}
|
||
|
||
/* Пагинация */
|
||
.pagination {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: var(--space-md);
|
||
margin-top: var(--space-2xl);
|
||
}
|
||
|
||
.pagination-button {
|
||
padding: var(--space-sm) var(--space-md);
|
||
border: 1px solid var(--border-medium);
|
||
border-radius: var(--radius-md);
|
||
background: var(--bg-primary);
|
||
color: var(--text-primary);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
font-weight: var(--font-medium);
|
||
}
|
||
|
||
.pagination-button:hover:not(:disabled) {
|
||
background: var(--bg-secondary);
|
||
border-color: var(--primary-500);
|
||
}
|
||
|
||
.pagination-button:disabled {
|
||
opacity: 0.5;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.pagination-pages {
|
||
display: flex;
|
||
gap: var(--space-xs);
|
||
}
|
||
|
||
.pagination-page {
|
||
padding: var(--space-sm) var(--space-md);
|
||
border: 1px solid var(--border-medium);
|
||
border-radius: var(--radius-md);
|
||
background: var(--bg-primary);
|
||
color: var(--text-primary);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
min-width: 2.5rem;
|
||
text-align: center;
|
||
}
|
||
|
||
.pagination-page.active {
|
||
background: var(--primary-500);
|
||
color: white;
|
||
border-color: var(--primary-500);
|
||
}
|
||
|
||
.pagination-page:hover:not(.active):not(:disabled) {
|
||
background: var(--bg-secondary);
|
||
border-color: var(--primary-500);
|
||
}
|
||
|
||
.pagination-page:disabled {
|
||
cursor: default;
|
||
}
|
||
|
||
/* Сообщение об отсутствии новостей */
|
||
.no-news {
|
||
text-align: center;
|
||
padding: var(--space-2xl);
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.no-news-icon {
|
||
font-size: 4rem;
|
||
margin-bottom: var(--space-lg);
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.no-news-title {
|
||
font-family: var(--font-heading);
|
||
font-size: var(--text-2xl);
|
||
font-weight: var(--font-semibold);
|
||
color: var(--text-primary);
|
||
margin-bottom: var(--space-md);
|
||
}
|
||
|
||
.no-news-description {
|
||
margin-bottom: var(--space-xl);
|
||
max-width: 400px;
|
||
margin-left: auto;
|
||
margin-right: auto;
|
||
}
|
||
|
||
/* Подписка на новости */
|
||
.newsletter-section {
|
||
background: var(--bg-secondary);
|
||
padding: var(--space-2xl) 0;
|
||
border-top: 1px solid var(--border-light);
|
||
}
|
||
|
||
.newsletter-card {
|
||
background: var(--bg-primary);
|
||
border-radius: var(--radius-xl);
|
||
padding: var(--space-2xl);
|
||
display: grid;
|
||
grid-template-columns: 1fr auto;
|
||
gap: var(--space-2xl);
|
||
align-items: center;
|
||
border: 1px solid var(--border-light);
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.newsletter-content {
|
||
flex: 1;
|
||
}
|
||
|
||
.newsletter-title {
|
||
font-family: var(--font-heading);
|
||
font-size: var(--text-2xl);
|
||
font-weight: var(--font-semibold);
|
||
color: var(--text-primary);
|
||
margin-bottom: var(--space-sm);
|
||
}
|
||
|
||
.newsletter-description {
|
||
color: var(--text-secondary);
|
||
margin-bottom: var(--space-lg);
|
||
line-height: var(--leading-relaxed);
|
||
}
|
||
|
||
.newsletter-form {
|
||
max-width: 400px;
|
||
}
|
||
|
||
.newsletter-form .form-group {
|
||
display: flex;
|
||
gap: var(--space-sm);
|
||
margin-bottom: var(--space-sm);
|
||
}
|
||
|
||
.newsletter-input {
|
||
flex: 1;
|
||
padding: var(--space-sm) var(--space-md);
|
||
border: 1px solid var(--border-medium);
|
||
border-radius: var(--radius-md);
|
||
background: var(--bg-primary);
|
||
color: var(--text-primary);
|
||
font-size: var(--text-base);
|
||
}
|
||
|
||
.newsletter-input:focus {
|
||
outline: none;
|
||
border-color: var(--primary-500);
|
||
}
|
||
|
||
.newsletter-button {
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.newsletter-note {
|
||
font-size: var(--text-xs);
|
||
color: var(--text-tertiary);
|
||
margin: 0;
|
||
}
|
||
|
||
.newsletter-icon {
|
||
font-size: 4rem;
|
||
opacity: 0.7;
|
||
}
|
||
|
||
/* Адаптивность */
|
||
@media (max-width: 1024px) {
|
||
.filters-content {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
}
|
||
|
||
.search-box {
|
||
max-width: none;
|
||
}
|
||
|
||
.filter-controls {
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.newsletter-card {
|
||
grid-template-columns: 1fr;
|
||
text-align: center;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.news-hero {
|
||
padding: 3rem 0;
|
||
}
|
||
|
||
.hero-title {
|
||
font-size: var(--text-3xl);
|
||
}
|
||
|
||
.news-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.news-grid.list-view .news-card {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.filter-controls {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
gap: var(--space-md);
|
||
}
|
||
|
||
.filter-group {
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.pagination {
|
||
flex-wrap: wrap;
|
||
gap: var(--space-sm);
|
||
}
|
||
|
||
.newsletter-form .form-group {
|
||
flex-direction: column;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
.news-hero {
|
||
padding: 2rem 0;
|
||
}
|
||
|
||
.hero-title {
|
||
font-size: var(--text-2xl);
|
||
}
|
||
|
||
.news-stats {
|
||
gap: var(--space-lg);
|
||
}
|
||
|
||
.news-card {
|
||
margin: 0 var(--space-sm);
|
||
}
|
||
|
||
.news-body {
|
||
padding: var(--space-md);
|
||
}
|
||
|
||
.news-footer {
|
||
flex-direction: column;
|
||
gap: var(--space-md);
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.newsletter-card {
|
||
padding: var(--space-xl);
|
||
margin: 0 var(--space-sm);
|
||
}
|
||
}
|
||
</style> |