You've already forked OpenIntegrations
mirror of
https://github.com/Bayselonarrend/OpenIntegrations.git
synced 2025-11-23 22:05:15 +02:00
Fastfix
This commit is contained in:
303
docs/docusaurus/src/pages/courses.js
vendored
303
docs/docusaurus/src/pages/courses.js
vendored
@@ -1,303 +0,0 @@
|
|||||||
import React, { useState, useMemo } from 'react';
|
|
||||||
import Layout from '@theme/Layout';
|
|
||||||
import Link from '@docusaurus/Link';
|
|
||||||
import Heading from '@theme/Heading';
|
|
||||||
import styles from './courses.module.css';
|
|
||||||
import CustomFooter from '@site/src/components/CustomFooter';
|
|
||||||
import coursesData from '../../data/courses.json';
|
|
||||||
|
|
||||||
const CoursesPage = () => {
|
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
|
||||||
const [selectedCategory, setSelectedCategory] = useState('all');
|
|
||||||
const [showSubscriptionModal, setShowSubscriptionModal] = useState(false);
|
|
||||||
const [showPurchaseModal, setShowPurchaseModal] = useState(false);
|
|
||||||
const [selectedCourse, setSelectedCourse] = useState(null);
|
|
||||||
|
|
||||||
const { courses, categories, subscriptionInfo } = coursesData;
|
|
||||||
|
|
||||||
const filteredCourses = useMemo(() => {
|
|
||||||
return courses.filter(course => {
|
|
||||||
const matchesSearch = course.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
||||||
course.description.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
||||||
course.tags.some(tag => tag.toLowerCase().includes(searchQuery.toLowerCase()));
|
|
||||||
|
|
||||||
const matchesCategory = selectedCategory === 'all' || course.category === selectedCategory;
|
|
||||||
|
|
||||||
return matchesSearch && matchesCategory;
|
|
||||||
});
|
|
||||||
}, [searchQuery, selectedCategory]);
|
|
||||||
|
|
||||||
const handlePurchaseClick = (course) => {
|
|
||||||
setSelectedCourse(course);
|
|
||||||
setShowPurchaseModal(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const SubscriptionModal = () => (
|
|
||||||
<div className={`${styles.modalOverlay} ${showSubscriptionModal ? styles.modalOverlayVisible : ''}`}
|
|
||||||
onClick={() => setShowSubscriptionModal(false)}>
|
|
||||||
<div className={styles.modalFeaturesContent} onClick={(e) => e.stopPropagation()}>
|
|
||||||
<div className={styles.modalHeader}>
|
|
||||||
<h1>{subscriptionInfo.title}</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.modalBody}>
|
|
||||||
<p className={styles.subscriptionDescription}>{subscriptionInfo.description}</p>
|
|
||||||
|
|
||||||
<div className={styles.featuresGrid}>
|
|
||||||
{subscriptionInfo.features.map((feature, index) => (
|
|
||||||
<div key={index} className={styles.featureCard}>
|
|
||||||
<svg className={styles.featureIcon} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={0.8} stroke="currentColor">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d={feature.icon} />
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<h3 className={styles.featureTitle}>{feature.title}</h3>
|
|
||||||
<p className={styles.featureDescription}>{feature.description}</p>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.modalFooter}>
|
|
||||||
<button
|
|
||||||
className={styles.secondaryButton}
|
|
||||||
onClick={() => setShowSubscriptionModal(false)}
|
|
||||||
>
|
|
||||||
Закрыть
|
|
||||||
</button>
|
|
||||||
<Link
|
|
||||||
href={subscriptionInfo.boostyUrl}
|
|
||||||
className={styles.primaryButton}
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
Перейти на Boosty
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const PurchaseModal = () => {
|
|
||||||
if (!selectedCourse) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={`${styles.modalOverlay} ${showPurchaseModal ? styles.modalOverlayVisible : ''}`}
|
|
||||||
onClick={() => setShowPurchaseModal(false)}>
|
|
||||||
<div className={styles.modalContent} onClick={(e) => e.stopPropagation()}>
|
|
||||||
<div className={styles.courseBannerModal}>
|
|
||||||
<img
|
|
||||||
src={selectedCourse.banner}
|
|
||||||
alt={selectedCourse.title}
|
|
||||||
onError={(e) => {
|
|
||||||
e.target.src = '/img/Courses/default.png';
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.modalHeader}>
|
|
||||||
<h2>{selectedCourse.title}</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.modalBody}>
|
|
||||||
<div className={styles.tags}>
|
|
||||||
{selectedCourse.tags.map(tag => (
|
|
||||||
<span key={tag} className={styles.tag}>#{tag}</span>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.courseDescriptionModal}>
|
|
||||||
<h3>О материале</h3>
|
|
||||||
<p>{selectedCourse.descriptionExtended}</p>
|
|
||||||
|
|
||||||
<div className={styles.courseDetails}>
|
|
||||||
<div className={styles.detailItem}>
|
|
||||||
<strong>Формат:</strong> {selectedCourse.format}
|
|
||||||
</div>
|
|
||||||
<div className={styles.detailItem}>
|
|
||||||
<strong>Доступ:</strong> Бессрочный
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.courseProgram}>
|
|
||||||
<h3>Что вы получите:</h3>
|
|
||||||
<ul className={styles.programList}>
|
|
||||||
<li>✓ Полный доступ к текстовому материалу</li>
|
|
||||||
<li>✓ Обновления контента бесплатно</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.accessInfo}>
|
|
||||||
<h4>Как работает доступ:</h4>
|
|
||||||
<p>
|
|
||||||
Доступ приобретается путем покупки поста на сервисе Boosty. Внутри этого поста находится ссылка для перехода к купленным материалам. Подобные ссылки обновляются в начале каждого месяца. Если ссылка была обновлена (перестала работать) или вы утратили свою старую ссылку еще до обновления, то всегда можете получить ее повторно в том же посте, что приобрели ранее.
|
|
||||||
</p>
|
|
||||||
<br/>
|
|
||||||
<p>Если вы столкнулись с проблемой, то можете связаться со мной одним из следующих способов:</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<span>Email:</span> <a href={"mailto:support@openintegrations.dev"}>support@openintegrations.dev</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<span>Telegram:</span> <a href={"https://t.me/bayselonarrend"}>@bayselonarrend</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.modalFooter}>
|
|
||||||
<button
|
|
||||||
className={styles.secondaryButton}
|
|
||||||
onClick={() => setShowPurchaseModal(false)}
|
|
||||||
>
|
|
||||||
Закрыть
|
|
||||||
</button>
|
|
||||||
<Link
|
|
||||||
href={selectedCourse.buyUrl}
|
|
||||||
className={styles.primaryButton}
|
|
||||||
target="_blank"
|
|
||||||
onClick={() => setShowPurchaseModal(false)}
|
|
||||||
>
|
|
||||||
Купить за {selectedCourse.price} ₽
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const CourseCard = ({ course }) => (
|
|
||||||
<div className={styles.courseCard}>
|
|
||||||
<div className={styles.courseBanner}>
|
|
||||||
<img
|
|
||||||
src={course.banner}
|
|
||||||
alt={course.title}
|
|
||||||
onError={(e) => {
|
|
||||||
e.target.src = '/img/Courses/default.png';
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.courseContent}>
|
|
||||||
<div className={styles.courseHeader}>
|
|
||||||
<h3 className={styles.courseTitle}>{course.title}</h3>
|
|
||||||
<div className={styles.tags}>
|
|
||||||
{course.tags.map(tag => (
|
|
||||||
<span key={tag} className={styles.tag}>#{tag}</span>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p className={styles.courseDescription}>{course.description}</p>
|
|
||||||
|
|
||||||
<div className={styles.courseActions}>
|
|
||||||
{course.type === 'free' ? (
|
|
||||||
<Link
|
|
||||||
href={course.externalUrl}
|
|
||||||
className={styles.freeButton}
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<svg className={styles.buttonIcon} viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
|
|
||||||
</svg>
|
|
||||||
Бесплатно
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<button
|
|
||||||
className={styles.buyButton}
|
|
||||||
onClick={() => handlePurchaseClick(course)}
|
|
||||||
>
|
|
||||||
{course.price} ₽
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className={styles.subscriptionButton}
|
|
||||||
onClick={() => setShowSubscriptionModal(true)}
|
|
||||||
>
|
|
||||||
<svg className={styles.buttonIcon} viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
|
|
||||||
</svg>
|
|
||||||
По подписке
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout
|
|
||||||
title="Курсы"
|
|
||||||
description="Курсы и материалы"
|
|
||||||
wrapperClassName={styles.layoutWrapper}
|
|
||||||
>
|
|
||||||
<div className={styles.pageContainer}>
|
|
||||||
<main className={`container margin-vert--lg ${styles.mainContent}`}>
|
|
||||||
<div className={styles.coursesHeader}>
|
|
||||||
<svg className={styles.coursesIcon} viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.746 0 3.332.477 4.5 1.253v13C19.832 18.477 18.246 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
|
|
||||||
</svg>
|
|
||||||
<div>
|
|
||||||
<Heading as="h1" className={styles.coursesTitle}>
|
|
||||||
Обучающие курсы и материалы
|
|
||||||
</Heading>
|
|
||||||
<p className={styles.coursesSubtitle}>
|
|
||||||
Углубленное изучение аспектов и практик разработки с использованием Открытого пакета интеграций
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<div className={styles.filtersSection}>
|
|
||||||
<div className={styles.searchBox}>
|
|
||||||
<svg className={styles.searchIcon} viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
|
||||||
</svg>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="Поиск по материалам..."
|
|
||||||
value={searchQuery}
|
|
||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
|
||||||
className={styles.searchInput}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.categories}>
|
|
||||||
{categories.map(category => (
|
|
||||||
<button
|
|
||||||
key={category.id}
|
|
||||||
className={`${styles.categoryButton} ${
|
|
||||||
selectedCategory === category.id ? styles.categoryButtonActive : ''
|
|
||||||
}`}
|
|
||||||
onClick={() => setSelectedCategory(category.id)}
|
|
||||||
>
|
|
||||||
{category.name}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.coursesGrid}>
|
|
||||||
{filteredCourses.map(course => (
|
|
||||||
<CourseCard key={course.id} course={course} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{filteredCourses.length === 0 && (
|
|
||||||
<div className={styles.noResults}>
|
|
||||||
<p>Материалы по вашему запросу не найдены</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<SubscriptionModal />
|
|
||||||
<PurchaseModal />
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<CustomFooter />
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CoursesPage;
|
|
||||||
532
docs/docusaurus/src/pages/courses.module.css
vendored
532
docs/docusaurus/src/pages/courses.module.css
vendored
@@ -1,532 +0,0 @@
|
|||||||
.layoutWrapper {
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pageContainer {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mainContent {
|
|
||||||
flex: 1;
|
|
||||||
padding-bottom: 2rem; /* Отступ перед футером */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Остальные ваши существующие стили остаются без изменений */
|
|
||||||
.coursesHeader {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 1rem;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.coursesIcon {
|
|
||||||
width: 4rem;
|
|
||||||
height: 4rem;
|
|
||||||
flex-shrink: 0;
|
|
||||||
color: #004943;
|
|
||||||
margin-top: 0.31rem;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.coursesTitle {
|
|
||||||
margin: 0;
|
|
||||||
font-weight: 350;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.coursesSubtitle {
|
|
||||||
margin: 0.1rem 0 0;
|
|
||||||
font-weight: lighter;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Фильтры */
|
|
||||||
.filtersSection {
|
|
||||||
margin: 2rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.searchBox {
|
|
||||||
position: relative;
|
|
||||||
max-width: 400px;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.searchIcon {
|
|
||||||
position: absolute;
|
|
||||||
left: 12px;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.searchInput {
|
|
||||||
width: 100%;
|
|
||||||
padding: 12px 12px 12px 40px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 12px;
|
|
||||||
font-size: 1rem;
|
|
||||||
transition: border-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.searchInput:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: #004943;
|
|
||||||
}
|
|
||||||
|
|
||||||
.categories {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.categoryButton {
|
|
||||||
padding: 8px 16px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 20px;
|
|
||||||
background: white;
|
|
||||||
color: #555;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.categoryButton:hover {
|
|
||||||
border-color: #004943;
|
|
||||||
color: #004943;
|
|
||||||
}
|
|
||||||
|
|
||||||
.categoryButtonActive {
|
|
||||||
background: #004943;
|
|
||||||
border-color: #004943;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.categoryButtonActive:hover {
|
|
||||||
color: white;
|
|
||||||
background: #025a53;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Сетка курсов */
|
|
||||||
.coursesGrid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
|
||||||
gap: 2rem;
|
|
||||||
margin-top: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseCard {
|
|
||||||
background: white;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 16px;
|
|
||||||
overflow: hidden;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseCard:hover {
|
|
||||||
transform: translateY(-4px);
|
|
||||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseBanner {
|
|
||||||
width: 100%;
|
|
||||||
height: 160px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseBanner img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseContent {
|
|
||||||
padding: 1.5rem;
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseHeader {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseTitle {
|
|
||||||
margin: 0 0 0.5rem 0;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 1.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tags {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: #666;
|
|
||||||
background: #f5f5f5;
|
|
||||||
padding: 2px 8px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseDescription {
|
|
||||||
flex: 1;
|
|
||||||
margin: 0 0 1.5rem 0;
|
|
||||||
color: #555;
|
|
||||||
line-height: 1.5;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseActions {
|
|
||||||
display: flex;
|
|
||||||
gap: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Кнопки */
|
|
||||||
.freeButton,
|
|
||||||
.buyButton,
|
|
||||||
.subscriptionButton {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 10px 16px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 12px;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
font-weight: 500;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.freeButton {
|
|
||||||
background: #e8f5e8;
|
|
||||||
color: #2e7d32;
|
|
||||||
border: 1px solid #c8e6c9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.freeButton:hover {
|
|
||||||
background: #d4edda;
|
|
||||||
color: #1b5e20;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buyButton {
|
|
||||||
background: #004943;
|
|
||||||
color: white; /* Вместо lightgray */
|
|
||||||
font-weight: 500; /* Вместо 100 */
|
|
||||||
font-size: 0.95rem; /* Вместо 1em */
|
|
||||||
font-style: normal;
|
|
||||||
font-family: inherit; /* Добавьте это */
|
|
||||||
text-rendering: optimizeLegibility; /* Улучшает четкость */
|
|
||||||
-webkit-font-smoothing: antialiased; /* Для Mac */
|
|
||||||
-moz-osx-font-smoothing: grayscale; /* Для Firefox */
|
|
||||||
}
|
|
||||||
|
|
||||||
.buyButton:hover {
|
|
||||||
background: #00302a;
|
|
||||||
text-decoration: none;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subscriptionButton {
|
|
||||||
background: #e3f2fd;
|
|
||||||
color: #1565c0;
|
|
||||||
border: 1px solid #bbdefb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subscriptionButton:hover {
|
|
||||||
background: #bbdefb;
|
|
||||||
color: #0d47a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonIcon {
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.noResults {
|
|
||||||
text-align: center;
|
|
||||||
padding: 3rem;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Адаптивность */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.coursesGrid {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
gap: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseActions {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.categories {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.modalOverlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
z-index: 1000;
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modalOverlayVisible {
|
|
||||||
opacity: 1;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modalContent {
|
|
||||||
background: white;
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 0;
|
|
||||||
max-width: 670px;
|
|
||||||
width: 90%;
|
|
||||||
max-height: 90vh;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modalFeaturesContent {
|
|
||||||
background: white;
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 0;
|
|
||||||
max-width: 840px;
|
|
||||||
width: 90%;
|
|
||||||
max-height: 90vh;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modalHeader {
|
|
||||||
display: flex;
|
|
||||||
justify-content: between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 1.5rem 1.5rem 0;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modalHeader h2 {
|
|
||||||
margin: 0;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.closeButton {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
font-size: 2rem;
|
|
||||||
cursor: pointer;
|
|
||||||
color: #666;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modalBody {
|
|
||||||
padding: 1.5rem;
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subscriptionDescription {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
color: #555;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.featuresGrid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
||||||
gap: 1rem;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.featureCard {
|
|
||||||
text-align: center;
|
|
||||||
background: white;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 1.2rem;
|
|
||||||
box-shadow:
|
|
||||||
inset 0 1px 3px rgba(255, 255, 255, 0.7),
|
|
||||||
0 4px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.featureCard:hover {
|
|
||||||
box-shadow:
|
|
||||||
inset 0 1px 3px rgba(255, 255, 255, 0.7),
|
|
||||||
0 6px 12px rgba(0, 0, 0, 0.12);
|
|
||||||
}
|
|
||||||
|
|
||||||
.featureIcon {
|
|
||||||
width: 4rem;
|
|
||||||
height: 4rem;
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
color: #004943;
|
|
||||||
}
|
|
||||||
|
|
||||||
.featureTitle {
|
|
||||||
margin: 0 0 0.5rem 0;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.featureDescription {
|
|
||||||
margin: 0;
|
|
||||||
color: #666;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modalFooter {
|
|
||||||
display: flex;
|
|
||||||
gap: 1rem;
|
|
||||||
padding: 1rem 1.5rem;
|
|
||||||
border-top: 1px solid #eee;
|
|
||||||
background: #fafafa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondaryButton {
|
|
||||||
flex: 1;
|
|
||||||
padding: 12px 24px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 8px;
|
|
||||||
background: white;
|
|
||||||
color: #666;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primaryButton {
|
|
||||||
flex: 2;
|
|
||||||
padding: 12px 24px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 8px;
|
|
||||||
background: #004943;
|
|
||||||
color: white;
|
|
||||||
text-decoration: none;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.primaryButton:hover {
|
|
||||||
background: #00302a;
|
|
||||||
color: white;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Адаптивность */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.featuresGrid {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modalFooter {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modalContent {
|
|
||||||
width: 95%;
|
|
||||||
margin: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Стили для модалки покупки */
|
|
||||||
.courseBannerModal {
|
|
||||||
width: 100%;
|
|
||||||
height: 300px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseBannerModal img {
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseDescriptionModal h3 {
|
|
||||||
margin: 1rem 0 0.5rem 0;
|
|
||||||
color: #333;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseDetails {
|
|
||||||
margin: 1rem 0;
|
|
||||||
padding: 1rem;
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailItem {
|
|
||||||
margin: 0.5rem 0;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseProgram {
|
|
||||||
margin: 1.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.courseProgram h3 {
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.programList {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.programList li {
|
|
||||||
padding: 0.3rem 0;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.accessInfo {
|
|
||||||
margin: 1.5rem 0 0 0;
|
|
||||||
padding: 1rem;
|
|
||||||
background: #fff3cd;
|
|
||||||
border: 1px solid #ffeaa7;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.accessInfo h4 {
|
|
||||||
margin: 0 0 0.5rem 0;
|
|
||||||
color: #856404;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.accessInfo p {
|
|
||||||
margin: 0;
|
|
||||||
color: #856404;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user