diff --git a/package-lock.json b/package-lock.json index 90126c1..61eb764 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "react": "^19.1.1", "react-bootstrap": "^2.10.10", "react-dom": "^19.1.1", + "react-router-dom": "^7.7.1", "react-scripts": "5.0.1", "react-slick": "^0.30.3", "slick-carousel": "^1.8.1", @@ -14163,6 +14164,53 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.7.1.tgz", + "integrity": "sha512-jVKHXoWRIsD/qS6lvGveckwb862EekvapdHJN/cGmzw40KnJH5gg53ujOJ4qX6EKIK9LSBfFed/xiQ5yeXNrUA==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.7.1.tgz", + "integrity": "sha512-bavdk2BA5r3MYalGKZ01u8PGuDBloQmzpBZVhDLrOOv1N943Wq6dcM9GhB3x8b7AbqPMEezauv4PeGkAJfy7FQ==", + "license": "MIT", + "dependencies": { + "react-router": "7.7.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -15108,6 +15156,12 @@ "node": ">= 0.8.0" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", diff --git a/package.json b/package.json index 956651f..9dfe3d5 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "react": "^19.1.1", "react-bootstrap": "^2.10.10", "react-dom": "^19.1.1", + "react-router-dom": "^7.7.1", "react-scripts": "5.0.1", "react-slick": "^0.30.3", "slick-carousel": "^1.8.1", diff --git a/public/kediri-technopark-logo.png b/public/kediri-technopark-logo.png new file mode 100644 index 0000000..f30925d Binary files /dev/null and b/public/kediri-technopark-logo.png differ diff --git a/src/App.js b/src/App.js index 22629a8..18f661a 100644 --- a/src/App.js +++ b/src/App.js @@ -1,10 +1,10 @@ -import React, { useEffect, useState } from 'react'; -import 'bootstrap/dist/css/bootstrap.min.css'; -// import './assets/css/templatemo-chain-app-dev.css'; // Assuming you copy your original CSS here -// import './assets/css/animated.css'; -// import './assets/css/owl.css'; +import React, { useEffect, useState, useRef } from 'react'; +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; +import styles from './components/Styles.module.css'; + +// Import components +import Login from './components/Login'; -// Import your converted React components import Header from './components/Header'; import HeroSection from './components/HeroSection'; import ServicesSection from './components/ServicesSection'; @@ -15,14 +15,70 @@ import KnowledgeBaseSection from './components/KnowledgeBaseSection'; import ClientsSection from './components/ClientsSection'; import Footer from './components/Footer'; +import ProductDetailPage from './components/ProductDetailPage'; + + +function HomePage({ + hoveredCard, + setHoveredCard, + selectedProduct, + setSelectedProduct, + showedModal, + setShowedModal, + productSectionRef, + courseSectionRef +}) { + + return ( + <> + + + + + + + + + ); +} + function App() { const [loading, setLoading] = useState(true); + // State yang diperlukan untuk HomePage + const [hoveredCard, setHoveredCard] = useState(null); + const [selectedProduct, setSelectedProduct] = useState({}); + const [showedModal, setShowedModal] = useState(null); // 'product' | 'login' | null + const [postLoginAction, setPostLoginAction] = useState(null); + + const [username, setUsername] = useState(null); + + + const productSectionRef = useRef(null); + const courseSectionRef = useRef(null); + + const scrollToProduct = () => { + productSectionRef.current?.scrollIntoView({ behavior: "smooth" }); + }; + const scrollToCourse = () => { + courseSectionRef.current?.scrollIntoView({ behavior: "smooth" }); + }; + useEffect(() => { - // Simulate preloader and remove it after some time const timer = setTimeout(() => { setLoading(false); - }, 1000); // Adjust time as needed + }, 1000); return () => clearTimeout(timer); }, []); @@ -42,29 +98,60 @@ function App() { } return ( -
-
- - {/* FULL WIDTH IMAGE SECTION */} - {/* This can be a separate component or integrated into HeroSection */} -
- -
- -
-
-
+ +
+
+ + + } + /> + +
+ {/* Unified Modal */} + {showedModal && ( +
{ + setShowedModal(null); + setSelectedProduct({}); + }} + > +
e.stopPropagation()} + > + {showedModal === 'product' && ( + { + setShowedModal(null); + setSelectedProduct({}); + }} + /> + )} + {showedModal === 'login' && ( + setShowedModal(null)} /> + )} +
+
+ )}
- - - - - - - -
-
+ ); } -export default App; \ No newline at end of file +export default App; diff --git a/src/components/AcademySection.js b/src/components/AcademySection.js index 5461879..6bc9166 100644 --- a/src/components/AcademySection.js +++ b/src/components/AcademySection.js @@ -1,7 +1,8 @@ import React, { useEffect, useState } from 'react'; -import { Container, Row, Col, Card, Button } from 'react-bootstrap'; +import { Container } from 'react-bootstrap'; +import styles from './Styles.module.css'; -const AcademySection = () => { +const AcademySection = ({hoveredCard, setHoveredCard, setSelectedProduct, setShowedModal, courseSectionRef}) => { const [products, setProducts] = useState([]); useEffect(() => { @@ -18,43 +19,53 @@ const AcademySection = () => { }, []); return ( -
+ +

OUR ACADEMY PROGRAM

Academy Program adalah wadah belajar digital untuk anak-anak dan remaja. Didesain interaktif, kreatif, dan gratis — setiap modul membekali peserta dengan keterampilan masa depan, dari teknologi dasar hingga coding dan proyek nyata.

- - {products.map((product, idx) => ( - - - - {product.name} -
- {product.name} +
+ {products && + products[0]?.name && + products.map(product => ( +
{ + setSelectedProduct(product); + setShowedModal('product'); + }} + onMouseEnter={() => setHoveredCard(product.id)} + onMouseLeave={() => setHoveredCard(null)} + > +
+ {product.price === 0 && ( + Free + )} +
+
+

{product.name}

+

{product.description}

+
+ + {product.price == null + ? 'Pay-As-You-Go' + : `Rp ${product.price.toLocaleString('id-ID')}`} +
-
    - {product.duration && ( -
  • - Durasi:{" "} - {product.duration.hours - ? `${product.duration.hours} jam` - : product.duration.days - ? `${product.duration.days} hari` - : "-"} -
  • - )} -
  • Harga: {product.currency} {product.price.toLocaleString()}
  • -
-
- -
- - - - ))} - +
+
+ ))} +
); diff --git a/src/components/Header.js b/src/components/Header.js index eff36e7..9a96808 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -1,24 +1,72 @@ -import React from 'react'; -import { Navbar, Nav, Container } from 'react-bootstrap'; +import React, { useState, useEffect, useRef } from 'react'; +import { useNavigate } from 'react-router-dom'; + +import { Navbar, Nav, Container } from 'react-bootstrap'; +import styles from './Styles.module.css'; + +const Header = ({ username, scrollToProduct, scrollToCourse, setShowedModal }) => { + const navigate = useNavigate(); + const [hoveredNav, setHoveredNav] = useState(null); + -const Header = () => { return ( - - - Kediri Technopark - - - - - - + +
+ Logo + + + +
+ {username ? ( + + Halo, {username} + + ) : ( + + )} +
+
); }; diff --git a/src/components/Login.js b/src/components/Login.js new file mode 100644 index 0000000..007206d --- /dev/null +++ b/src/components/Login.js @@ -0,0 +1,240 @@ +import React, { useState } from 'react'; + +const LoginRegister = ({postLoginAction, setPostLoginAction}) => { + const [tab, setTab] = useState('login'); // 'login' or 'register' + const [email, setEmail] = useState(''); + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + + const styles = { + container: { + backgroundColor: 'white', + borderRadius: '1rem', + padding: '2rem', + maxWidth: '400px', + margin: '0 auto', + boxShadow: '0 8px 25px rgba(0, 0, 0, 0.15)', + fontFamily: 'Inter, system-ui, sans-serif', + }, + title: { + fontSize: '1.3rem', + fontWeight: 'bold', + color: '#1e293b', + marginBottom: '1.5rem', + textAlign: 'center', + }, + tabContainer: { + display: 'flex', + justifyContent: 'center', + marginBottom: '1.5rem', + }, + tabButton: (active) => ({ + cursor: 'pointer', + padding: '0.5rem 1rem', + borderBottom: active ? '2px solid #2563eb' : '2px solid transparent', + fontWeight: active ? 'bold' : 'normal', + color: active ? '#2563eb' : '#64748b', + background: 'none', + border: 'none', + outline: 'none', + fontSize: '1rem', + margin: '0 0.5rem', + }), + input: { + display: 'block', + padding: '0.75rem 1rem', + marginBottom: '1rem', + borderRadius: '0.5rem', + border: '1px solid #cbd5e1', + fontSize: '0.9rem', + outline: 'none', + boxSizing: 'border-box', + width: '100%', + }, + inputWrapper: { + width: '100%', + }, + button: { + display: 'block', + width: '100%', + padding: '0.75rem 1.5rem', + borderRadius: '0.5rem', + border: 'none', + fontSize: '0.75rem', + fontWeight: '600', + cursor: 'pointer', + transition: 'all 0.3s ease', + textTransform: 'uppercase', + backgroundColor: '#2563eb', + color: 'white', + }, + }; + + const handleLogin = async (e) => { + e.preventDefault(); + if (!username || !password) { + alert('Username dan password wajib diisi'); + return; + } + + try { + const res = await fetch('https://bot.kediritechnopark.com/webhook/user-dev/login', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ username, password }), + }); + + if (!res.ok) { + const err = await res.text(); + alert(`Login gagal: ${err}`); + return; + } + + const data = await res.json(); + const token = data[0].token; + if (token) { + document.cookie = `token=${token}; path=/; max-age=${7 * 24 * 60 * 60}`; + + if (postLoginAction) { + postLoginAction(); // resume action (e.g., checkout) + setPostLoginAction(null); + } + } else { + alert('Token tidak ditemukan pada respons login'); + } + } catch (error) { + alert('Terjadi kesalahan saat login'); + console.error(error); + } + }; + + const handleRegister = async (e) => { + e.preventDefault(); + if (!email || !username || !password) { + alert('Email, username, dan password wajib diisi'); + return; + } + + try { + const res = await fetch('https://bot.kediritechnopark.com/webhook/user-dev/register', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ email, username, password }), + }); + + if (!res.ok) { + const err = await res.text(); + alert(`Registrasi gagal: ${err}`); + return; + } + + alert('Registrasi berhasil! Silakan login.'); + setTab('login'); + setEmail(''); + setUsername(''); + setPassword(''); + } catch (error) { + alert('Terjadi kesalahan saat registrasi'); + console.error(error); + } + }; + + return ( +
+

{tab === 'login' ? 'Login' : 'Register'}

+ +
+ + +
+ + {tab === 'login' ? ( +
+
+ setUsername(e.target.value)} + autoComplete="username" + /> +
+
+ setPassword(e.target.value)} + autoComplete="current-password" + /> +
+ +
+ ) : ( +
+
+ setEmail(e.target.value)} + autoComplete="email" + /> +
+
+ setUsername(e.target.value)} + autoComplete="username" + /> +
+
+ setPassword(e.target.value)} + autoComplete="new-password" + /> +
+ +
+ )} +
+ ); +}; + +export default LoginRegister; diff --git a/src/components/ProductDetail.module.css b/src/components/ProductDetail.module.css new file mode 100644 index 0000000..c48ab22 --- /dev/null +++ b/src/components/ProductDetail.module.css @@ -0,0 +1,95 @@ +.container { + background-color: white; + border-radius: 1rem; + padding: 2rem; + max-width: 700px; + margin: 0 auto; + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); + font-family: 'Inter', system-ui, sans-serif; + text-align: center; +} + +.image { + width: 100%; + height: 260px; + background-color: #e2e8f0; + border-radius: 0.75rem; + display: flex; + align-items: center; + justify-content: center; + color: #64748b; + font-size: 1rem; + margin-bottom: 1.5rem; +} + +.headerRow { + display: flex; + justify-content: center; + align-items: center; + gap: 1rem; + margin-bottom: 1rem; + text-align: center; +} + +.title { + font-size: 1.1rem; + font-weight: bold; + color: #1e293b; + margin: 0; +} + +.price { + font-size: 1.1rem; + font-weight: bold; + color: #2563eb; /* default color, bisa override di inline style */ +} + +.description { + font-size: 1rem; + color: #64748b; + margin-bottom: 1.5rem; + line-height: 1.6; +} + +.buttonGroup { + display: flex; + justify-content: space-between; + gap: 1rem; +} + +.button { + padding: 0.75rem 0.4rem; + border-radius: 0.5rem; + border: none; + font-size: 0.55rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + text-transform: uppercase; +} + +.addToCartButton { + background-color: #fbbf24; + color: #1e293b; + margin-right: 0.5rem; + flex: 1; +} + +.checkoutButton { + background-color: #2563eb; + color: white; + flex: 1; +} + +/* Responsive untuk mobile */ +@media (max-width: 600px) { + .container { + text-align: left; + } + .headerRow { + justify-content: flex-start; + } + .buttonGroup { + gap: 0.5rem; + } +} diff --git a/src/components/ProductDetailPage.js b/src/components/ProductDetailPage.js new file mode 100644 index 0000000..4f27524 --- /dev/null +++ b/src/components/ProductDetailPage.js @@ -0,0 +1,133 @@ +import React, { useEffect, useState } from 'react'; +import styles from './ProductDetail.module.css'; + +const ProductDetail = ({ product, setPostLoginAction, setShowedModal }) => { + const [inCart, setInCart] = useState(false); + + useEffect(() => { + const existingCookie = document.cookie + .split('; ') + .find(row => row.startsWith('itemsId=')); + let items = []; + if (existingCookie) { + try { + const value = decodeURIComponent(existingCookie.split('=')[1]); + items = JSON.parse(value); + if (!Array.isArray(items)) items = []; + } catch (e) { + items = []; + } + } + setInCart(items.includes(product.id)); + }, [product.id]); + + const onSetCart = () => { + const existingCookie = document.cookie + .split('; ') + .find(row => row.startsWith('itemsId=')); + + let items = []; + + if (existingCookie) { + try { + const value = decodeURIComponent(existingCookie.split('=')[1]); + items = JSON.parse(value); + if (!Array.isArray(items)) items = []; + } catch (e) { + items = []; + } + } + + let updatedItems; + if (items.includes(product.id)) { + updatedItems = items.filter(id => id !== product.id); // remove + setInCart(false); + } else { + updatedItems = [...items, product.id]; // add + setInCart(true); + } + + document.cookie = `itemsId=${JSON.stringify(updatedItems)}; path=/; max-age=${7 * 24 * 60 * 60 + }`; + }; + + const onCheckout = () => { + // Ambil token dari cookie + const tokenCookie = document.cookie + .split('; ') + .find(row => row.startsWith('token=')); + const token = tokenCookie ? tokenCookie.split('=')[1] : ''; + + // Ambil itemsId dari cookie + const itemsCookie = document.cookie + .split('; ') + .find(row => row.startsWith('itemsId=')); + + let items = []; + if (itemsCookie) { + try { + items = JSON.parse(itemsCookie.split('=')[1]); + if (!Array.isArray(items)) items = []; + } catch (e) { + items = []; + } + } + + if (!items.includes(product.id)) { + items.push(product.id); + } + // Encode items ke string untuk query param + const itemsParam = JSON.stringify(items); + + if (!tokenCookie) { + setPostLoginAction(() => () => onCheckout()); // remember intent + setShowedModal('login'); + return; + } + + // Redirect dengan token dan itemsId di query + window.location.href = `http://localhost:3001/?token=${token}&itemsId=${itemsParam}&redirect_uri=http://localhost:3000/courses&redirect_failed=http://localhost:3000`; + }; + + + // Override harga warna jika free + const priceColor = product.price === 0 ? '#059669' : '#2563eb'; + + return ( +
+
📦
+ +
+

{product.name}

+
+ {product.price === 0 + ? 'Free' + : `Rp ${parseInt(product.price).toLocaleString('id-ID')}`} +
+
+ +

{product.description}

+ +
+ + +
+
+ ); +}; + +export default ProductDetail; diff --git a/src/components/ProductSection.js b/src/components/ProductSection.js index d8e0b61..deec58d 100644 --- a/src/components/ProductSection.js +++ b/src/components/ProductSection.js @@ -1,7 +1,9 @@ import React, { useEffect, useState } from 'react'; -import { Container, Row, Col, Card } from 'react-bootstrap'; +import { Container } from 'react-bootstrap'; +import styles from './Styles.module.css'; -const ProductSection = () => { + +const ProductSection = ({ hoveredCard, setHoveredCard, setSelectedProduct, setShowedModal, productSectionRef }) => { const [products, setProducts] = useState([]); useEffect(() => { @@ -10,7 +12,7 @@ const ProductSection = () => { headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify({ type: 'product', onlyParents:true }), + body: JSON.stringify({ type: 'product', onlyParents: true }), }) .then(res => res.json()) .then(data => setProducts(data)) @@ -18,27 +20,53 @@ const ProductSection = () => { }, []); return ( -
+ +
-

OUR PRODUCT

+

OUR PRODUCTS

Kami menyediakan berbagai solusi teknologi untuk mendukung transformasi digital bisnis dan masyarakat.

- - -
- {products.map((product, idx) => ( - - - - {product.name} - - - ))} -
- -
+
+ {products && + products[0]?.name && + products.map(product => ( +
{ + setSelectedProduct(product); + setShowedModal('product'); + }} + onMouseEnter={() => setHoveredCard(product.id)} + onMouseLeave={() => setHoveredCard(null)} + > +
+ {product.price === 0 && ( + Free + )} +
+
+

{product.name}

+

{product.description}

+
+ + {product.price == null + ? 'Pay-As-You-Go' + : `Rp ${product.price.toLocaleString('id-ID')}`} + +
+
+
+ ))} +
); diff --git a/src/components/Styles.module.css b/src/components/Styles.module.css new file mode 100644 index 0000000..13e823a --- /dev/null +++ b/src/components/Styles.module.css @@ -0,0 +1,550 @@ +/* TechnoAcademyWebsite.module.css */ + +/* Header */ +.modal { + position: fixed; + width: 100%; + height: 100%; + top: 0; + color: white; + background-color: rgba(0, 0, 0, 0.527); + text-align: center; + display: flex; + justify-content: center; + align-items: center; + z-index: 1001; +} + +.modalBody { + color: white; + text-align: center; + display: flex; + align-items: center; +} + +.header { + background-color: white; + padding: 14px 6rem; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + position: sticky; + top: 0; + z-index: 1000; +} + +.logo { + display: flex; + align-items: center; + font-size: 1.2rem; + font-weight: bold; + width: 130px; +} + +.nav { + display: flex; + gap: 2rem; + align-items: center; +} + +.navLink { + text-decoration: none; + color: #64748b; + font-weight: 500; + font-size: 0.95rem; + transition: color 0.3s ease; + cursor: pointer; +} + +.navLinkHover { + color: #2563eb; +} + +.authButtons { + display: flex; + gap: 1rem; + align-items: center; +} + +.searchButton, +.userButton { + background-color: #2563eb; + color: white; + border: none; + border-radius: 50%; + width: 34px; + height: 34px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.3s ease; +} + +.loginButton { + background-color: transparent; + color: #64748b; + border: none; + font-size: 0.9rem; + cursor: pointer; + padding: 0.5rem 1rem; +} + +/* Hero Section */ +.hero { + background-image: url('https://academy.kediritechnopark.com/wp-content/uploads/2025/07/pexels-fauxels-3184360-scaled.jpg'); + background-size: cover; + background-position: center; + padding: 0 2rem; + color: white; + position: relative; + border-radius: 0 0 0 60px; + text-align: left; + height: calc(100vh - 61.61px); + display: flex; +} + +.heroContainer { + max-width: 1200px; + margin: 0 auto; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 4rem; + align-items: center; +} + +.heroContent { + z-index: 2; +} + +.heroTitle { + font-size: 3.5rem; + font-weight: bold; + margin-top: 0px; + margin-bottom: 1.5rem; + line-height: 1.1; +} + +.heroDescription { + font-size: 1.1rem; + line-height: 1.6; + margin-bottom: 2rem; + opacity: 0.9; +} + +.joinButton { + background: linear-gradient(135deg, rgb(59, 130, 246) 0%, rgb(30, 64, 175) 100%); + color: white; + border: none; + padding: 1rem 2rem; + border-radius: 0.5rem; + font-size: 1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + text-transform: uppercase; +} + +.heroImage { + display: flex; + justify-content: center; + align-items: center; +} + +.heroImagePlaceholder { + width: 500px; + height: 350px; + background-color: rgba(255, 255, 255, 0.1); + border-radius: 1rem; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.2rem; + color: white; + border: 2px dashed rgba(255, 255, 255, 0.3); +} + +.Section { + padding: 2rem 6rem; + background-color: #f8fafc; +} + +.coursesContainer { + max-width: 1200px; + margin: 0 auto; +} + +.coursesTitle { + font-size: 2.5rem; + font-weight: bold; + color: #1e293b; + margin-bottom: 3rem; +} + +.coursesGrid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 2rem; +} +.courseCard { + background-color: white; + border-radius: 1rem; + overflow: hidden; + box-shadow: 2px 4px 6px rgba(0, 0, 0, 0.3); + transition: all 0.3s ease; + cursor: pointer; + + /* Tambahan untuk menghilangkan highlight biru */ + -webkit-tap-highlight-color: transparent; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + outline: none; +} + +.courseCard:focus { + outline: none; +} + + +.courseCardHover { + transform: translateY(-4px); + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); +} + +.courseImage { + width: 100%; + height: 200px; + background-color: #e2e8f0; + position: relative; + display: flex; + align-items: center; + justify-content: center; + color: #64748b; + + background-repeat: no-repeat; + background-size: cover; + background-position: center; +} + +.courseLabel { + position: absolute; + top: 1rem; + right: 1rem; + background-color: #ef4444; + color: white; + padding: 0.25rem 0.75rem; + border-radius: 1rem; + font-size: 0.8rem; + font-weight: 600; +} + +.courseContent { + padding: 1.5rem; + text-align: left; +} + +.courseCategory { + font-size: 0.8rem; + color: #64748b; + margin-bottom: 0.5rem; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.courseTitle { + font-size: 1.2rem; + font-weight: bold; + color: #1e293b; + margin-bottom: 1rem; + margin-top: 0; +} + +.courseStats { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; + font-size: 0.9rem; + color: #64748b; +} + +.courseStat { + display: flex; + align-items: center; + gap: 0.25rem; +} + +.coursePrice { + display: flex; + align-items: center; + justify-content: space-between; +} + +.originalPrice { + text-decoration: line-through; + color: #94a3b8; + font-size: 0.9rem; +} + +.currentPrice { + font-size: 1.2rem; + font-weight: bold; + color: #2563eb; +} + +.freePrice { + font-size: 1.2rem; + font-weight: bold; + color: #059669; +} + +.featuresContainer { + max-width: 1200px; + margin: 0 auto; +} + +.featuresTitle { + font-size: 2.5rem; + font-weight: bold; + color: #1e293b; + margin-bottom: 2rem; + margin-top: 0; + text-align: left; +} + +.featuresDescription { + font-size: 1.1rem; + color: #64748b; + line-height: 1.6; + margin-bottom: 3rem; + text-align: left; + max-width: 800px; +} + +.featuresList { + display: grid; + gap: 2rem; +} + +.featureItem { + display: flex; + gap: 1.5rem; + background-color: #f8fafc; + border-radius: 1rem; + align-items: flex-start; +} + +.featureIcon { + width: 60px; + height: 60px; + border-radius: 50%; + background-color: #2563eb; + color: white; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + font-size: 1.5rem; +} + +.featureContent { + flex: 1; +} + +.featureTitle { + font-size: 1.3rem; + font-weight: bold; + color: #1e293b; + margin-top: 6px; + margin-bottom: 0.5rem; + text-align: left; +} + +.featureDescription { + color: #64748b; + line-height: 1.6; + text-align: left; +} + +.ctaContainer { + max-width: 1200px; + margin: 0 auto; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 4rem; +} + +.ctaCard { + background-color: white; + padding: 3rem; + border-radius: 1rem; + text-align: center; + box-shadow: 10px 10px 10px rgb(0 0 0 / 15%); + transition: all 0.3s ease; + + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.ctaIcon { + width: 80px; + height: 80px; + border-radius: 50%; + background-color: #2563eb; + color: white; + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto 2rem; + font-size: 2rem; +} + +.ctaTitle { + font-size: 1.5rem; + font-weight: bold; + color: #1e293b; + margin-bottom: 1rem; +} + +.ctaDescription { + color: #64748b; + line-height: 1.6; + margin-bottom: 2rem; +} + +.ctaButton { + background-color: #2563eb; + color: white; + border: none; + padding: 1rem 2rem; + border-radius: 0.5rem; + font-size: 1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + text-transform: uppercase; +} + +/* Footer */ +.footer { + background-color: #1e293b; + color: white; + padding: 2rem; + text-align: center; +} + +.footerContent { + max-width: 1200px; + margin: 0 auto; + display: flex; + justify-content: space-between; + align-items: center; +} + +.footerText { + font-size: 0.9rem; + color: #94a3b8; +} + +.socialLinks { + display: flex; + gap: 1rem; +} + +.socialLink { + width: 40px; + height: 40px; + background-color: #374151; + border-radius: 0.5rem; + display: flex; + align-items: center; + justify-content: center; + color: white; + text-decoration: none; + transition: all 0.3s ease; + cursor: pointer; +} + +.socialLink:hover { + background-color: #4b5563; +} + +/* Responsive Styles */ +@media (max-width: 800px) { + .modalBody { + width: 80%; + } + + .header { + padding: 14px 2rem; + } + + .heroContainer { + grid-template-columns: 1fr; + text-align: center; + } + + .ctaTitle, + .courseTitle { + font-size: 15px; + margin: 0; + } + + .ctaDescription, + .courseContent p { + font-size: 13px; + margin: 6px 0px; + } + + .ctaCard, + .Section { + padding: 2rem 0.8rem; + background-color: #f8fafc; + } + + .courseContent { + text-align: left; + padding: 0.8rem; + } + + .ctaContainer, + .coursesGrid { + grid-template-columns: repeat(auto-fit, minmax(138px, 1fr)); + gap: 0.8rem; + } + + .featureTitle { + margin-top: 6px; + margin-bottom: 0.5rem; + text-align: left; + } + + .featureDescription { + text-align: left; + margin-bottom: 0; + } + + .featuresList { + gap: 0rem; + } + + +.ctaButton { + font-size: 12px; + padding: 1rem 1rem; + margin-top: 10px; +} + +} + + + +@media (max-width: 600px) { + .nav { + display: none; + } +}