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