diff --git a/package.json b/package.json index dbe84a7..bedd93f 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ "@tailwindcss/vite": "^4.1.18", "react": "^19.2.0", "react-dom": "^19.2.0", - "tailwindcss": "^4.1.18" + "react-router-dom": "^7.12.0", + "tailwindcss": "^4.1.18", + "zustand": "^5.0.9" }, "devDependencies": { "@eslint/js": "^9.39.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d95c070..83d5380 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,9 +17,15 @@ importers: react-dom: specifier: ^19.2.0 version: 19.2.3(react@19.2.3) + react-router-dom: + specifier: ^7.12.0 + version: 7.12.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) tailwindcss: specifier: ^4.1.18 version: 4.1.18 + zustand: + specifier: ^5.0.9 + version: 5.0.9(@types/react@19.2.7)(react@19.2.3) devDependencies: '@eslint/js': specifier: ^9.39.1 @@ -743,6 +749,10 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -1126,6 +1136,23 @@ packages: resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} engines: {node: '>=0.10.0'} + react-router-dom@7.12.0: + resolution: {integrity: sha512-pfO9fiBcpEfX4Tx+iTYKDtPbrSLLCbwJ5EqP+SPYQu1VYCXdy79GSj0wttR0U4cikVdlImZuEZ/9ZNCgoaxwBA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.12.0: + resolution: {integrity: sha512-kTPDYPFzDVGIIGNLS5VJykK0HfHLY5MF3b+xj0/tTyNYL1gF1qs7u67Z9jEhQk2sQ98SUaHxlG31g1JtF7IfVw==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + react@19.2.3: resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} engines: {node: '>=0.10.0'} @@ -1151,6 +1178,9 @@ packages: engines: {node: '>=10'} hasBin: true + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1281,6 +1311,24 @@ packages: zod@4.3.5: resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} + zustand@5.0.9: + resolution: {integrity: sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + snapshots: '@babel/code-frame@7.27.1': @@ -1893,6 +1941,8 @@ snapshots: convert-source-map@2.0.0: {} + cookie@1.1.1: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -2252,6 +2302,20 @@ snapshots: react-refresh@0.18.0: {} + react-router-dom@7.12.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react-router: 7.12.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + + react-router@7.12.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + cookie: 1.1.1 + react: 19.2.3 + set-cookie-parser: 2.7.2 + optionalDependencies: + react-dom: 19.2.3(react@19.2.3) + react@19.2.3: {} resolve-from@4.0.0: {} @@ -2293,6 +2357,8 @@ snapshots: semver@7.7.3: {} + set-cookie-parser@2.7.2: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -2378,3 +2444,8 @@ snapshots: zod: 4.3.5 zod@4.3.5: {} + + zustand@5.0.9(@types/react@19.2.7)(react@19.2.3): + optionalDependencies: + '@types/react': 19.2.7 + react: 19.2.3 diff --git a/src/App.css b/src/App.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/App.tsx b/src/App.tsx index 36533fa..f4f8af2 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,10 +1,27 @@ -import "./App.css"; +import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; +import { Login } from "./pages/login"; +import { StudentDashboard } from "./pages/StudentDashboard"; +import { ProtectedRoute } from "./components/ProtectedRoute"; function App() { return ( - <> -

Edbridge Scholars

- + + + } /> + + {/* Protected Routes */} + }> + } /> + {/* Add more subroutes here as needed */} + + + {/* Redirect root to student */} + } /> + + {/* Catch all - redirect to student */} + } /> + + ); } diff --git a/src/assets/auth.css b/src/assets/auth.css new file mode 100644 index 0000000..2c3d7c8 --- /dev/null +++ b/src/assets/auth.css @@ -0,0 +1,172 @@ +/* +* Prefixed by https://autoprefixer.github.io +* PostCSS: v8.4.14, +* Autoprefixer: v10.4.7 +* Browsers: last 4 version +*/ + +/* +* Prefixed by https://autoprefixer.github.io +* PostCSS: v8.4.14, +* Autoprefixer: v10.4.7 +* Browsers: last 4 version +*/ + +/* Auth Pages Styling */ +.login-container { + min-height: 100vh; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + background-color: var(--secondary-bg); + background-image: -o-linear-gradient(315deg, #f5f5f5 0%, #ffffff 100%); + background-image: linear-gradient(135deg, #f5f5f5 0%, #ffffff 100%); + padding: 1rem; +} + +.auth-container { + max-width: 420px; + width: 100%; + padding: 2.5rem; + border-radius: 12px; + -webkit-box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); + background-color: var(--tertiary-bg); + border: 1px solid var(--secondary-border); + -webkit-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} + +.auth-container:hover { + -webkit-box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12); + box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12); + -webkit-transform: translateY(-5px); + -ms-transform: translateY(-5px); + transform: translateY(-5px); +} + +.auth-title { + text-align: center; + margin-bottom: 1.5rem; + color: var(--intensive-text); + font-weight: 700; + font-size: 1.75rem; +} + +.auth-footer { + text-align: center; + margin-top: 1.5rem; + font-size: 0.9rem; + color: var(--neutral); +} + +.auth-footer a { + color: var(--primary-text); + font-weight: 500; + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.auth-footer a:hover { + text-decoration: underline; +} + +/* Form Styling */ +.auth-container .field { + margin-bottom: 1.25rem; +} + +.auth-container .label { + color: var(--intensive-text) !important; + font-weight: 600; + font-size: 0.9rem; + margin-bottom: 0.5rem; +} + +.auth-container .input { + color: var(--intensive-text) !important; + border-radius: 8px; + border: 1px solid var(--secondary-border); + padding: 0.75rem 1rem; + height: auto; + font-size: 1rem; + -webkit-box-shadow: none; + box-shadow: none; + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.auth-container .input:focus { + border-color: var(--primary-bg); + -webkit-box-shadow: 0 0 0 2px rgba(110, 68, 255, 0.1); + box-shadow: 0 0 0 2px rgba(110, 68, 255, 0.1); +} + +.auth-container .input.is-danger { + border-color: var(--error-bg); +} + +.auth-container .button { + height: auto; + padding: 0.75rem 1.5rem; + font-weight: 600; + font-size: 1rem; + border-radius: 8px; + -webkit-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} + +.auth-container .button.is-primary { + background-color: var(--primary-bg); + border: none; +} + +.auth-container .button.is-primary:hover { + background-color: var(--primary-dark); + -webkit-box-shadow: 0 4px 12px rgba(110, 68, 255, 0.3); + box-shadow: 0 4px 12px rgba(110, 68, 255, 0.3); + -webkit-transform: translateY(-2px); + -ms-transform: translateY(-2px); + transform: translateY(-2px); +} + +.auth-container .checkbox { + font-size: 0.9rem; + color: var(--neutral-dark); +} + +.auth-container .help.is-danger { + font-size: 0.8rem; + margin-top: 0.25rem; +} + +.auth-container .notification { + border-radius: 8px; + padding: 1rem; + margin-bottom: 1.5rem; +} + +.auth-container .notification .delete { + position: absolute; + right: 0.75rem; + top: 0.75rem; +} + +/* Responsive Adjustments */ +@media screen and (max-width: 768px) { + .auth-container { + padding: 2rem; + max-width: 100%; + margin: 0 1rem; + } +} diff --git a/src/assets/custom.css b/src/assets/custom.css new file mode 100644 index 0000000..7c6687a --- /dev/null +++ b/src/assets/custom.css @@ -0,0 +1,2087 @@ +/* +* Prefixed by https://autoprefixer.github.io +* PostCSS: v8.4.14, +* Autoprefixer: v10.4.7 +* Browsers: last 4 version +*/ + +/* Custom Bulma Variables */ +:root { + /* Primary Colors */ + --primary: #6e44ff; + --primary-light: #9f84ff; + --primary-dark: #1f0954; + + /* Neutral Colors */ + --black: #000000; + --white: #ffffff; + --neutral-lightest: #f7f7f7; + --neutral-lighter: #ececec; + --neutral-light: #aaaaaa; + --neutral: #666666; + --neutral-dark: #444444; + --neutral-darker: #222222; + --neutral-darkest: #111111; + + /* Color Neutral */ + --neutral-lightest: #eeeeee; + --neutral-lighter: #cccccc; + --neutral-light: #aaaaaa; + --neutral: #666666; + --neutral-dark: #444444; + --neutral-darker: #222222; + --neutral-darkest: #111111; + + /* Success Colors */ + --success-green: #00c7a4; + --success-green-light: #7cfff3; + + /* Error Colors */ + --error-red: #ff2c73; + --error-red-light: #fff2f2; + + /* Semantic Colors */ + --primary-bg: #6e44ff; + --secondary-bg: #eeeeee; + --tertiary-bg: #ffffff; + --intensive-bg: #000000; + --success-bg: #00c7a4; + --error-bg: #ff2c73; + + /* Border Colors */ + --primary-border: #000000; + --secondary-border: #cccccc; + --tertiary-border: #1f0954; + --intensive-border: #000000; + --success-border: #00c7a4; + --error-border: #ff2c73; + + /* Text Colors */ + --primary-text: #6e44ff; + --secondary-text: #9f84ff; + --intensive-text: #000000; + --success-text: #00c7a4; + --error-text: #ff2c73; + --link-text: #6e44ff; +} + +/* Bulma Customization */ +body { + font-family: "Satoshi", sans-serif; + background-color: var(--tertiary-bg); + color: var(--intensive-text); +} + +/* Navbar Styling */ +.navbar { + background-color: var(--tertiary-bg); + color: var(--intensive-text); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); + height: 4rem; + border-bottom: 1px solid var(--secondary-border); + position: sticky; + top: 0; + z-index: 30; +} + +.navbar-item, +.navbar-link { + color: var(--intensive-text); + font-weight: 500; +} + +.navbar-item:hover, +.navbar-link:hover { + background-color: var(--secondary-bg) !important; + color: var(--primary-text) !important; +} + +.navbar-brand .navbar-item { + font-weight: 700; + font-size: 1.25rem; + color: var(--primary-text); +} + +.navbar-item img { + max-height: 2.5rem; +} + +.navbar-burger { + color: var(--intensive-text); +} + +.navbar-menu.is-active { + background-color: var(--tertiary-bg); + -webkit-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05); +} + +/* Button Styling */ +.button { + font-family: "Satoshi", sans-serif; + font-weight: 500; + border-radius: 4px; + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.button.is-primary { + background-color: var(--primary-bg); + border: none; + color: white; +} + +.button.is-primary:hover { + background-color: var(--primary-dark); + -webkit-box-shadow: 0 4px 8px rgba(110, 68, 255, 0.2); + box-shadow: 0 4px 8px rgba(110, 68, 255, 0.2); + color: white; +} + +.button.is-success { + background-color: var(--success-bg); + color: white; +} + +.button.is-success:hover { + background-color: var(--success-green-light); + -webkit-box-shadow: 0 4px 8px rgba(0, 199, 164, 0.2); + box-shadow: 0 4px 8px rgba(0, 199, 164, 0.2); + color: white; +} + +.button.is-danger { + background-color: var(--error-bg); + color: white; +} + +.button.is-danger:hover { + background-color: var(--error-red-light); + color: var(--error-red); + -webkit-box-shadow: 0 4px 8px rgba(255, 44, 115, 0.2); + box-shadow: 0 4px 8px rgba(255, 44, 115, 0.2); +} + +.button.is-outlined { + border: 1px solid var(--primary-border); + color: var(--primary-text); + background: transparent; +} + +.button.is-outlined:hover { + background-color: var(--secondary-bg); +} + +.button.is-info { + background-color: #3e8ed0; + color: white; +} + +.button.is-info:hover { + background-color: #3082c5; + color: white; +} + +.button.is-warning { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning:hover { + background-color: #ffda6a; + color: rgba(0, 0, 0, 0.7); +} + +/* Sidebar Styling */ +.sidebar { + background-color: var(--tertiary-bg); + height: calc(100vh - 4rem); + width: 260px; + position: fixed; + z-index: 20; + top: 4rem; + left: 0; + overflow-y: auto; + padding: 0; + border-right: 1px solid var(--secondary-border); + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-shadow: 1px 0 5px rgba(0, 0, 0, 0.05); + box-shadow: 1px 0 5px rgba(0, 0, 0, 0.05); + -webkit-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} + +.sidebar-header { + padding: 1.5rem 1.5rem 0.5rem; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + border-bottom: 1px solid var(--secondary-border); + margin-bottom: 1rem; +} + +.sidebar-header h3 { + font-size: 0.85rem; + text-transform: uppercase; + letter-spacing: 1.5px; + color: var(--neutral); + font-weight: 600; +} + +.sidebar-menu { + list-style: none; + margin: 0; + padding: 0.75rem 0; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +.sidebar-item { + margin: 0.25rem 0.75rem; +} + +.sidebar-link { + padding: 0.75rem 1rem; + text-decoration: none; + font-size: 0.9rem; + color: var(--neutral-darker); + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; + border-radius: 6px; + font-weight: 500; + position: relative; + overflow: hidden; +} + +.sidebar-link:hover { + background-color: var(--secondary-bg); + color: var(--primary-text); + -webkit-transform: translateX(2px); + -ms-transform: translateX(2px); + transform: translateX(2px); +} + +.sidebar-link.is-active { + background-color: rgba(110, 68, 255, 0.1); + color: var(--primary-text); + font-weight: 600; + position: relative; +} + +.sidebar-link.is-active::before { + content: ""; + position: absolute; + left: 0; + top: 0; + height: 100%; + width: 4px; + background-color: var(--primary-bg); + border-radius: 0 2px 2px 0; +} + +.sidebar-link i { + margin-right: 0.75rem; + font-size: 1rem; + width: 20px; + text-align: center; + color: var(--neutral); + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.sidebar-link:hover i, +.sidebar-link.is-active i { + color: var(--primary-text); +} + +.sidebar-section-title { + font-size: 0.7rem; + text-transform: uppercase; + letter-spacing: 1.5px; + color: var(--neutral); + font-weight: 600; + padding: 0.75rem 1.75rem 0.5rem; + margin-top: 0.5rem; +} + +.sidebar-footer { + padding: 1rem; + border-top: 1px solid var(--secondary-border); + text-align: center; + font-size: 0.75rem; + color: var(--neutral); +} + +.main-content { + margin-left: 260px; + padding: 2rem; + min-height: calc(100vh - 4rem); + background-color: var(--tertiary-bg); +} + +/* Mobile Responsiveness */ +@media screen and (max-width: 768px) { + .sidebar { + width: 100%; + height: auto; + position: relative; + top: 0; + display: none; + } + + .sidebar.is-active { + display: block; + } + + .main-content { + margin-left: 0; + } +} + +/* Card Styling */ +.card { + border-radius: 8px; + -webkit-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + -webkit-transition: -webkit-box-shadow 0.3s ease, -webkit-transform 0.2s ease; + transition: -webkit-box-shadow 0.3s ease, -webkit-transform 0.2s ease; + -o-transition: box-shadow 0.3s ease, transform 0.2s ease; + transition: box-shadow 0.3s ease, transform 0.2s ease; + transition: box-shadow 0.3s ease, transform 0.2s ease, + -webkit-box-shadow 0.3s ease, -webkit-transform 0.2s ease; + border: 1px solid var(--secondary-border); + overflow: hidden; + background-color: var(--tertiary-bg); + margin-bottom: 1.5rem; +} + +.card:hover { + -webkit-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + -webkit-transform: translateY(-2px); + -ms-transform: translateY(-2px); + transform: translateY(-2px); +} + +/* Student Home Page Styling */ +.continue-learning-card { + border-radius: 8px; + overflow: hidden; + -webkit-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + border: 1px solid var(--secondary-border); + height: 100%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +.continue-learning-card .card-content { + padding: 0; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.learning-card-header { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 0.5rem 1rem; + border-bottom: 1px solid var(--secondary-border); +} + +.learning-card-header .tag { + margin-right: 0.5rem; + background-color: #e8f4ff; + color: #0086ff; + border-radius: 4px; + font-weight: 500; + font-size: 0.7rem; +} + +.learning-card-body { + padding: 0.75rem 1rem 1rem; +} + +.learning-card-title { + font-size: 1rem; + font-weight: 600; + margin-bottom: 0.75rem; + color: var(--intensive-text); + line-height: 1.3; + height: 2.6rem; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.learning-card-progress { + margin-bottom: 0.75rem; +} + +.learning-card-progress-text { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + margin-bottom: 0.25rem; + font-size: 0.75rem; + color: var(--neutral); +} + +.learning-card-progress .progress { + height: 0.4rem; + border-radius: 4px; +} + +.learning-card-progress .progress::-webkit-progress-bar { + background-color: #f0f0f0; +} + +.learning-card-progress .progress::-webkit-progress-value { + background-color: #00c48c; +} + +.continue-button { + background-color: white; + color: var(--primary-bg); + border: 1px solid var(--primary-bg); + border-radius: 6px; + padding: 0.4rem 1rem; + font-weight: 500; + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; + font-size: 0.8rem; +} + +.continue-button:hover { + background-color: var(--primary-bg); + color: white; +} + +/* SAT Dates Section Styling */ +.sat-dates-container { + border-radius: 8px; + border: 1px solid var(--secondary-border); + overflow: hidden; + margin-bottom: 1.5rem; +} + +.sat-dates-header { + background-color: #f9f9f9; + padding: 1rem; + border-bottom: 1px solid var(--secondary-border); +} + +.sat-dates-body { + padding: 0; +} + +.sat-dates-table { + width: 100%; + border-collapse: collapse; +} + +.sat-dates-table th { + background-color: #f9f9f9; + padding: 0.75rem 1rem; + font-weight: 600; + font-size: 0.9rem; + color: var(--neutral-dark); + text-align: left; + border-bottom: 1px solid var(--secondary-border); +} + +.sat-dates-table td { + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--secondary-border); + font-size: 0.9rem; +} + +.sat-dates-table tr:last-child td { + border-bottom: none; +} + +.sat-dates-footer { + background-color: #f9f9f9; + padding: 0.75rem 1rem; + border-top: 1px solid var(--secondary-border); + text-align: center; +} + +.sat-dates-footer a { + color: var(--primary-bg); + text-decoration: none; + font-weight: 500; + font-size: 0.9rem; +} + +.sat-dates-footer a:hover { + text-decoration: underline; +} + +.register-button { + background-color: var(--primary-bg); + color: white; + border: none; + border-radius: 4px; + padding: 0.4rem 0.75rem; + font-size: 0.8rem; + font-weight: 500; + cursor: pointer; + -webkit-transition: background-color 0.2s ease; + -o-transition: background-color 0.2s ease; + transition: background-color 0.2s ease; +} + +.register-button:hover { + background-color: #5a38d9; +} + +.sat-tips-container { + border-radius: 8px; + border: 1px solid var(--secondary-border); + overflow: hidden; + height: 100%; +} + +.sat-tips-header { + background-color: #f9f9f9; + padding: 1rem; + border-bottom: 1px solid var(--secondary-border); +} + +.sat-tips-body { + padding: 1rem; +} + +.sat-tips-list { + list-style-type: none; + padding: 0; + margin: 0; +} + +.sat-tips-list li { + padding: 0.5rem 0; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; +} + +.sat-tips-list li:before { + content: "•"; + color: var(--primary-bg); + font-weight: bold; + display: inline-block; + width: 1em; + margin-right: 0.5em; +} + +/* Settings Page Styling */ +.settings-container { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + gap: 1.5rem; +} + +.settings-sidebar { + -webkit-box-flex: 0; + -ms-flex: 0 0 250px; + flex: 0 0 250px; + border-radius: 8px; + border: 1px solid var(--secondary-border); + overflow: hidden; +} + +.settings-sidebar-header { + background-color: #f9f9f9; + padding: 1rem; + border-bottom: 1px solid var(--secondary-border); +} + +.settings-sidebar-body { + padding: 1rem 0; +} + +.menu-list a { + border-radius: 0; + padding: 0.75rem 1.25rem; + margin-bottom: 0; + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; + border-left: 3px solid transparent; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.menu-list a:hover { + background-color: var(--secondary-bg); + color: var(--primary-bg); + border-left-color: var(--secondary-border); +} + +.menu-list a.is-active { + background-color: #f0f0ff; + color: var(--primary-bg); + font-weight: 500; + border-left-color: var(--primary-bg); +} + +.menu-list a .icon { + margin-right: 0.75rem; + font-size: 0.9rem; + width: 20px; + text-align: center; +} + +.menu-label { + color: var(--neutral-dark); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + font-size: 0.75rem; + margin-top: 1.5rem; + margin-bottom: 0.75rem; + padding: 0 1.25rem; +} + +.settings-content { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.settings-panel { + border-radius: 8px; + border: 1px solid var(--secondary-border); + overflow: hidden; + margin-bottom: 1.5rem; +} + +.settings-panel-header { + background-color: #f9f9f9; + padding: 1rem 1.5rem; + border-bottom: 1px solid var(--secondary-border); + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.settings-panel-header .icon { + margin-right: 0.75rem; + color: var(--primary-bg); +} + +.settings-panel-body { + padding: 1.5rem; +} + +.settings-panel-footer { + background-color: #f9f9f9; + padding: 1rem 1.5rem; + border-top: 1px solid var(--secondary-border); + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; +} + +/* Progress Page Styling */ +.metric-card { + border-radius: 8px; + border: 1px solid var(--secondary-border); + padding: 1.25rem; + position: relative; + overflow: hidden; + height: 100%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + background-color: white; +} + +.metric-value { + font-size: 2.5rem; + font-weight: 700; + color: var(--primary-bg); + margin-bottom: 0.5rem; + line-height: 1; +} + +.metric-label { + font-size: 0.75rem; + color: var(--neutral); + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.metric-icon { + position: absolute; + bottom: 1rem; + right: 1rem; + color: rgba(110, 68, 255, 0.1); + font-size: 2rem; + opacity: 0.5; +} + +.progress-panel { + border-radius: 8px; + border: 1px solid var(--secondary-border); + overflow: hidden; + margin-bottom: 1.5rem; +} + +.progress-panel-header { + background-color: #f9f9f9; + padding: 1rem 1.5rem; + border-bottom: 1px solid var(--secondary-border); + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.progress-panel-header .icon { + margin-right: 0.75rem; + color: var(--primary-bg); +} + +.progress-panel-body { + padding: 1.5rem; +} + +.subject-performance { + margin-bottom: 1.5rem; +} + +.subject-label { + font-weight: 500; + color: var(--neutral-dark); +} + +.subject-score { + font-weight: 600; + color: var(--primary-bg); +} + +.progress-table { + width: 100%; + border-collapse: collapse; +} + +.progress-table th { + background-color: #f9f9f9; + padding: 0.75rem 1rem; + font-weight: 600; + font-size: 0.9rem; + color: var(--neutral-dark); + text-align: left; + border-bottom: 1px solid var(--secondary-border); +} + +.progress-table td { + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--secondary-border); + font-size: 0.9rem; +} + +.progress-table tr:last-child td { + border-bottom: none; +} + +.practice-sheet-card { + position: relative; + overflow: hidden; +} + +.practice-sheet-card-icon { + position: absolute; + top: 1rem; + right: 1rem; + opacity: 0.8; +} + +.option-item { + padding: 1rem; + border: 1px solid var(--secondary-border); + border-radius: 8px; + margin-bottom: 1rem; + cursor: pointer; + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.option-item:hover { + background-color: var(--secondary-bg); +} + +.option-item.selected { + border-color: var(--primary-bg); + background-color: rgba(110, 68, 255, 0.05); +} + +.option-marker { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 30px; + height: 30px; + border-radius: 50%; + background-color: var(--secondary-bg); + color: var(--neutral-dark); + font-weight: 600; +} + +.option-item.selected .option-marker { + background-color: var(--primary-bg); + color: white; +} + +.score-display { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin: 1rem 0; +} + +.score-circle { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 180px; + height: 180px; + border-radius: 50%; + background-color: var(--primary-bg); + color: white; + -webkit-box-shadow: 0 4px 12px rgba(110, 68, 255, 0.2); + box-shadow: 0 4px 12px rgba(110, 68, 255, 0.2); +} + +.score-value { + font-size: 3rem; + font-weight: 700; + line-height: 1; + margin-bottom: 0.5rem; +} + +.score-label { + font-size: 0.9rem; + font-weight: 500; + text-align: center; + max-width: 80%; +} + +.section-score { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 1.5rem; + background-color: #f9f9f9; + border-radius: 8px; + border: 1px solid var(--secondary-border); + height: 100%; +} + +.section-score-value { + font-size: 2.5rem; + font-weight: 700; + color: var(--primary-bg); + margin-bottom: 0.5rem; + line-height: 1; +} + +.section-score-label { + font-size: 0.9rem; + font-weight: 500; + color: var(--neutral); +} + +.module-score-item { + border: 1px solid var(--secondary-border); + border-radius: 8px; + padding: 1rem; + background-color: white; +} + +.answer-sheet { + border-radius: 6px; + font-size: 0.9rem; + max-height: 300px; + overflow-y: auto; +} + +.answer-item { + padding-bottom: 0.5rem; + border-bottom: 1px solid var(--secondary-border); +} + +.answer-item:last-child { + border-bottom: none; + padding-bottom: 0; +} + +.subject-performance { + margin-bottom: 1.5rem; +} + +.subject-label { + font-weight: 600; + color: var(--neutral-dark); +} + +.subject-score { + font-weight: 700; + color: var(--primary-bg); +} + +.card-header { + border-bottom: 1px solid var(--secondary-border); + background-color: var(--tertiary-bg); + -webkit-box-shadow: none; + box-shadow: none; +} + +.card-header-title { + font-weight: 600; + font-size: 1.1rem; + color: var(--primary-text); +} + +.card-content { + padding: 1.5rem; +} + +.card-footer { + border-top: 1px solid var(--secondary-border); + background-color: var(--tertiary-bg); +} + +/* Table Styling */ +.table { + width: 100%; + border-collapse: separate; + border-spacing: 0; + border-radius: 8px; + overflow: hidden; + -webkit-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + margin-bottom: 2rem; +} + +.table thead th { + background-color: var(--secondary-bg); + font-weight: 600; + color: var(--intensive-text); + text-transform: uppercase; + font-size: 0.8rem; + letter-spacing: 0.5px; + padding: 1rem; +} + +.table td { + padding: 1rem; + border-bottom: 1px solid var(--secondary-border); + vertical-align: middle; +} + +.table tr:last-child td { + border-bottom: none; +} + +.table tr:hover { + background-color: var(--secondary-bg); +} + +/* Form Styling */ +.field-label { + font-weight: 500; + color: var(--intensive-text); + font-size: 0.9rem; +} + +.input, +.textarea, +.select select { + border-radius: 6px; + border: 1px solid var(--secondary-border); + -webkit-box-shadow: none; + box-shadow: none; + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; + background-color: var(--tertiary-bg); +} + +.input:focus, +.textarea:focus, +.select select:focus { + border-color: var(--primary-bg); + -webkit-box-shadow: 0 0 0 2px rgba(110, 68, 255, 0.1); + box-shadow: 0 0 0 2px rgba(110, 68, 255, 0.1); +} + +.input:hover, +.textarea:hover, +.select select:hover { + border-color: var(--primary-light); +} + +/* Dashboard Header */ +.dashboard-header { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 1.5rem; + padding-bottom: 1rem; + border-bottom: 1px solid var(--secondary-border); +} + +.dashboard-header .title { + margin-bottom: 0; + font-weight: 700; + color: var(--intensive-text); +} + +/* Dashboard Metrics */ +.metric-card { + text-align: center; + padding: 1.5rem; + position: relative; + overflow: hidden; + border-radius: 8px; + border: 1px solid var(--secondary-border); + background-color: var(--tertiary-bg); + -webkit-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; + height: 100%; +} + +.metric-card:hover { + -webkit-transform: translateY(-5px); + -ms-transform: translateY(-5px); + transform: translateY(-5px); + -webkit-box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); +} + +.metric-value { + font-size: 2.5rem; + font-weight: 700; + color: var(--primary-text); + line-height: 1.2; + margin-bottom: 0.5rem; +} + +.metric-label { + font-size: 0.9rem; + color: var(--neutral); + text-transform: uppercase; + letter-spacing: 0.5px; + font-weight: 500; +} + +.metric-icon { + position: absolute; + bottom: 1rem; + right: 1rem; + font-size: 3rem; + opacity: 0.1; + color: var(--primary-text); +} + +/* Graph Container */ +.graph-container { + background-color: var(--tertiary-bg); + border-radius: 8px; + padding: 1.5rem; + -webkit-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + border: 1px solid var(--secondary-border); + margin-bottom: 2rem; +} + +.graph-title { + font-weight: 600; + font-size: 1.1rem; + margin-bottom: 1.5rem; + color: var(--intensive-text); +} + +/* Enrollment Chart */ +.enrollment-chart-container { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + width: 100%; +} + +.enrollment-chart { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + height: 100%; + width: 100%; +} + +.chart-bars { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: end; + -ms-flex-align: end; + align-items: flex-end; + height: 85%; + width: 100%; + padding-bottom: 10px; +} + +.chart-bar { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + margin: 0 4px; + border-radius: 4px 4px 0 0; + -webkit-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} + +.chart-bar:hover { + -webkit-transform: scaleY(1.05); + -ms-transform: scaleY(1.05); + transform: scaleY(1.05); + -webkit-box-shadow: 0 0 10px rgba(110, 68, 255, 0.3); + box-shadow: 0 0 10px rgba(110, 68, 255, 0.3); +} + +.chart-labels { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + width: 100%; + padding: 0 4px; +} + +.chart-label { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + text-align: center; + font-size: 0.75rem; + color: var(--neutral); + font-weight: 500; +} + +/* Subject Performance */ +.subject-performance { + margin-bottom: 1.25rem; +} + +.subject-header { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + margin-bottom: 0.5rem; +} + +.subject-name { + font-weight: 500; + font-size: 0.9rem; +} + +.subject-score { + font-weight: 600; + color: var(--primary-text); +} + +/* Difficulty Distribution */ +.difficulty-distribution { + margin-bottom: 1.25rem; +} + +.difficulty-label { + font-weight: 500; + color: var(--primary-text); + font-size: 0.9rem; +} + +.difficulty-count { + font-weight: 600; + color: var(--primary-text); +} + +/* Activity Statistics */ +.activity-summary { + margin-bottom: 1.25rem; +} + +.stat-label { + font-weight: 500; + color: var(--neutral-dark); + font-size: 0.9rem; +} + +.stat-value { + font-weight: 600; + color: var(--primary-text); +} + +.activity-item { + padding: 0.75rem; + border-radius: 6px; + background-color: var(--neutral-lightest); + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.activity-item:hover { + background-color: var(--secondary-bg); + -webkit-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); +} + +.student-name, +.sheet-name { + font-size: 0.9rem; + line-height: 1.2; +} + +.student-activity, +.sheet-activity { + margin-top: 0.2rem; +} + +.card-header-title .icon { + color: var(--primary-bg); + margin-right: 0.5rem; +} + +.graph-title .icon { + margin-right: 0.5rem; + color: var(--primary-bg); +} + +/* Practice Sheet Styling */ +.practice-sheet-card { + margin-bottom: 1.5rem; + position: relative; + overflow: hidden; +} + +.practice-sheet-header { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 1.5rem; + padding-bottom: 1rem; + border-bottom: 1px solid var(--secondary-border); +} + +.practice-sheet-detail { + position: relative; + padding: 2rem; + background-color: var(--tertiary-bg); + border-radius: 8px; + -webkit-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + border: 1px solid var(--secondary-border); + margin-bottom: 2rem; +} + +.practice-sheet-detail::before { + content: "Practice Sheet"; + position: absolute; + top: -10px; + left: 20px; + background-color: var(--primary-bg); + color: white; + padding: 0.25rem 0.75rem; + border-radius: 20px; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.module-container { + margin-top: 2rem; + position: relative; +} + +.module-list { + position: relative; +} + +.module-list::before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 20px; + width: 2px; + background-color: var(--secondary-border); + z-index: 0; +} + +.module-card { + margin-bottom: 1.5rem; + border-left: 4px solid var(--primary-bg); + border-radius: 0 8px 8px 0; + position: relative; + z-index: 1; + -webkit-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} + +.module-card:hover { + -webkit-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); +} + +.module-card::before { + content: ""; + position: absolute; + top: 50%; + left: -12px; + width: 20px; + height: 20px; + background-color: var(--primary-bg); + border-radius: 50%; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); + z-index: 2; +} + +.module-header { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 1rem 1.5rem; + background-color: rgba(110, 68, 255, 0.05); + border-bottom: 1px solid var(--secondary-border); +} + +.module-title { + font-weight: 600; + font-size: 1.1rem; + color: var(--primary-text); +} + +.module-meta { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + gap: 1rem; + font-size: 0.85rem; + color: var(--neutral); +} + +.module-meta-item { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.module-meta-item i { + margin-right: 0.5rem; + font-size: 0.9rem; +} + +.module-content { + padding: 1.5rem; +} + +.question-list { + position: relative; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + width: 100%; +} + +.question-card { + margin-bottom: 1rem; + border-left: 3px solid var(--success-bg); + border-radius: 0 8px 8px 0; + background-color: var(--tertiary-bg); + position: relative; + -webkit-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; + width: 100%; +} + +.question-card:hover { + -webkit-transform: translateX(5px); + -ms-transform: translateX(5px); + transform: translateX(5px); + -webkit-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + border-left-color: var(--primary-bg); +} + +.question-card.is-dragging { + -webkit-box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15); + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15); + opacity: 0.9; + -webkit-transform: scale(1.02); + -ms-transform: scale(1.02); + transform: scale(1.02); + z-index: 10; +} + +.question-drag-handle { + cursor: -webkit-grab; + cursor: grab; + color: var(--neutral); + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.question-drag-handle:hover { + color: var(--primary-bg); +} + +.question-drag-handle:active { + cursor: -webkit-grabbing; + cursor: grabbing; +} + +.question-index .tag { + font-weight: 600; + min-width: 40px; + text-align: center; +} + +.question-card::before { + content: ""; + position: absolute; + top: 50%; + left: -8px; + width: 12px; + height: 12px; + background-color: var(--success-bg); + border-radius: 50%; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); +} + +.question-header { + padding: 1rem 1.5rem; + border-bottom: 1px solid var(--secondary-border); + font-weight: 500; + -webkit-transition: background-color 0.2s ease; + -o-transition: background-color 0.2s ease; + transition: background-color 0.2s ease; + cursor: pointer; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.question-header:hover { + background-color: rgba(110, 68, 255, 0.05); +} + +.question-header::after { + content: ""; + position: absolute; + top: 50%; + right: 1rem; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); + width: 0; + height: 0; + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.question-content { + padding: 1rem 1.5rem; + -webkit-animation: fadeIn 0.3s ease; + animation: fadeIn 0.3s ease; +} + +.question-options { + margin-top: 1rem; +} + +.question-option { + padding: 0.75rem 1rem; + border: 1px solid var(--secondary-border); + border-radius: 6px; + margin-bottom: 0.5rem; + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; + cursor: pointer; +} + +.question-option:hover { + background-color: var(--secondary-bg); +} + +.question-option.is-correct { + border-color: var(--success-bg); + background-color: rgba(0, 199, 164, 0.05); +} + +.question-explanation { + margin-top: 1rem; + padding: 1rem; + background-color: var(--secondary-bg); + border-radius: 6px; + font-size: 0.9rem; +} + +/* Visual Connector Lines */ +.connector-line { + position: relative; +} + +.connector-line::before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 20px; + width: 2px; + background-color: var(--secondary-border); + z-index: 0; +} + +.connector-dot { + position: absolute; + width: 12px; + height: 12px; + border-radius: 50%; + background-color: var(--primary-bg); + left: 15px; + top: 50%; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); + z-index: 1; +} + +/* Module Tabs Styling */ +.module-tabs-container { + position: relative; + margin-bottom: 2rem; +} + +.module-tabs { + margin-bottom: 0; + overflow-x: auto; + white-space: nowrap; + position: relative; + z-index: 2; +} + +.module-tabs ul { + border-bottom-color: var(--secondary-border); + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; +} + +.module-tabs li { + -webkit-box-flex: 0; + -ms-flex: 0 0 auto; + flex: 0 0 auto; +} + +.module-tabs li a { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 0.75rem 1.25rem; + border-radius: 4px 4px 0 0; + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; + border-bottom: 2px solid transparent; + color: var(--neutral-darker); +} + +.module-tabs li a:hover { + background-color: var(--secondary-bg); + color: var(--primary-text); +} + +.module-tabs li.is-active a { + border-bottom-color: var(--primary-bg); + color: var(--primary-bg); + font-weight: 600; +} + +.module-tabs li.tab-add-button a { + padding: 0.75rem; + color: var(--primary-bg); +} + +.module-tab-content { + display: none; + padding: 1.5rem; + background-color: white; + border: 1px solid var(--secondary-border); + border-top: none; + border-radius: 0 0 8px 8px; + position: relative; + z-index: 1; +} + +.module-tab-content.is-active { + display: block; + -webkit-animation: fadeIn 0.3s ease; + animation: fadeIn 0.3s ease; +} + +@-webkit-keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +/* Module and Question Actions */ +.module-actions, +.question-actions { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + gap: 0.5rem; + z-index: 10; +} + +.module-actions .button, +.question-actions .button { + padding: 0.5rem; + height: auto; +} + +.question-text-container { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 70%; + font-size: 0.95rem; + line-height: 1.5; +} + +.question-text-full { + white-space: normal; + margin-top: 0.5rem; + margin-bottom: 1rem; + padding: 0.75rem 1rem; + background-color: var(--secondary-bg); + border-radius: 6px; + font-size: 1rem; + line-height: 1.6; + color: var(--intensive-text); + border-left: 3px solid var(--primary-bg); +} + +/* Empty State */ +.empty-state { + text-align: center; + padding: 3rem 2rem; + background-color: var(--secondary-bg); + border-radius: 8px; + margin-bottom: 2rem; +} + +.empty-state-icon { + font-size: 3rem; + color: var(--neutral-light); + margin-bottom: 1rem; +} + +.empty-state-title { + font-size: 1.25rem; + font-weight: 600; + color: var(--neutral-dark); + margin-bottom: 0.5rem; +} + +.empty-state-description { + color: var(--neutral); + margin-bottom: 1.5rem; + max-width: 400px; + margin-left: auto; + margin-right: auto; +} + +/* User Management Styling */ +.user-avatar { + border-radius: 50%; + -o-object-fit: cover; + object-fit: cover; + border: 2px solid var(--secondary-border); +} + +.user-card { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 1rem; + border-radius: 8px; + margin-bottom: 1rem; + background-color: var(--tertiary-bg); + border: 1px solid var(--secondary-border); + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.user-card:hover { + -webkit-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + -webkit-transform: translateY(-2px); + -ms-transform: translateY(-2px); + transform: translateY(-2px); +} + +.user-info { + margin-left: 1rem; +} + +.user-name { + font-weight: 600; + font-size: 1.1rem; + margin-bottom: 0.25rem; +} + +.user-email { + color: var(--neutral); + font-size: 0.9rem; +} + +/* Badge Styling */ +.badge { + display: inline-block; + padding: 0.25rem 0.75rem; + border-radius: 20px; + font-size: 0.8rem; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.badge.is-primary { + background-color: var(--primary-bg); + color: white; +} + +.badge.is-success { + background-color: var(--success-bg); + color: white; +} + +.badge.is-error { + background-color: var(--error-bg); + color: white; +} + +/* Timeline Styling */ +.timeline { + position: relative; + margin: 0 0 0 1rem; + padding-left: 1.5rem; +} + +.timeline::before { + content: ""; + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 2px; + background-color: var(--secondary-border); +} + +.timeline-item { + position: relative; + margin-bottom: 1.5rem; +} + +.timeline-marker { + position: absolute; + left: -1.5rem; + width: 12px; + height: 12px; + border-radius: 50%; + background-color: var(--primary-bg); + top: 0.25rem; +} + +.timeline-marker.is-primary { + background-color: var(--primary-bg); +} + +.timeline-marker.is-success { + background-color: var(--success-bg); +} + +.timeline-marker.is-warning { + background-color: #ffe08a; +} + +.timeline-marker.is-danger { + background-color: var(--error-bg); +} + +.timeline-content { + padding-bottom: 1rem; +} + +.timeline-content .heading { + font-size: 0.8rem; + font-weight: 600; + color: var(--neutral); + margin-bottom: 0.25rem; +} + +/* Info Item Styling */ +.info-item { + margin-bottom: 0.75rem; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.info-item strong { + min-width: 100px; + font-weight: 600; + color: var(--neutral-dark); +} + +/* Auth Styling */ +.login-container { + min-height: 100vh; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + background-color: var(--secondary-bg); + background-image: -o-linear-gradient( + 315deg, + var(--secondary-bg) 0%, + var(--tertiary-bg) 100% + ); + background-image: linear-gradient( + 135deg, + var(--secondary-bg) 0%, + var(--tertiary-bg) 100% + ); +} + +.auth-container { + max-width: 400px; + width: 100%; + padding: 2.5rem; + border-radius: 8px; + -webkit-box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); + background-color: var(--tertiary-bg); + border: 1px solid var(--secondary-border); +} + +.auth-title { + text-align: center; + margin-bottom: 2rem; + color: var(--primary-text); + font-weight: 700; + font-size: 1.75rem; +} + +.auth-footer { + text-align: center; + margin-top: 1.5rem; + font-size: 0.9rem; +} diff --git a/src/assets/ed_logo.png b/src/assets/ed_logo.png new file mode 100644 index 0000000..b3c63f7 Binary files /dev/null and b/src/assets/ed_logo.png differ diff --git a/src/assets/ed_logo1.png b/src/assets/ed_logo1.png new file mode 100644 index 0000000..4c61e29 Binary files /dev/null and b/src/assets/ed_logo1.png differ diff --git a/src/assets/fonts/Satoshi-Black.woff2 b/src/assets/fonts/Satoshi-Black.woff2 new file mode 100644 index 0000000..60586db Binary files /dev/null and b/src/assets/fonts/Satoshi-Black.woff2 differ diff --git a/src/assets/fonts/Satoshi-BlackItalic.woff2 b/src/assets/fonts/Satoshi-BlackItalic.woff2 new file mode 100644 index 0000000..b49b74c Binary files /dev/null and b/src/assets/fonts/Satoshi-BlackItalic.woff2 differ diff --git a/src/assets/fonts/Satoshi-Bold.woff2 b/src/assets/fonts/Satoshi-Bold.woff2 new file mode 100644 index 0000000..4c2a42a Binary files /dev/null and b/src/assets/fonts/Satoshi-Bold.woff2 differ diff --git a/src/assets/fonts/Satoshi-BoldItalic.woff2 b/src/assets/fonts/Satoshi-BoldItalic.woff2 new file mode 100644 index 0000000..dae39f9 Binary files /dev/null and b/src/assets/fonts/Satoshi-BoldItalic.woff2 differ diff --git a/src/assets/fonts/Satoshi-Italic.woff2 b/src/assets/fonts/Satoshi-Italic.woff2 new file mode 100644 index 0000000..d4ce445 Binary files /dev/null and b/src/assets/fonts/Satoshi-Italic.woff2 differ diff --git a/src/assets/fonts/Satoshi-Light.woff2 b/src/assets/fonts/Satoshi-Light.woff2 new file mode 100644 index 0000000..dee0f52 Binary files /dev/null and b/src/assets/fonts/Satoshi-Light.woff2 differ diff --git a/src/assets/fonts/Satoshi-LightItalic.woff2 b/src/assets/fonts/Satoshi-LightItalic.woff2 new file mode 100644 index 0000000..fd5aa0e Binary files /dev/null and b/src/assets/fonts/Satoshi-LightItalic.woff2 differ diff --git a/src/assets/fonts/Satoshi-Medium.woff2 b/src/assets/fonts/Satoshi-Medium.woff2 new file mode 100644 index 0000000..46718c6 Binary files /dev/null and b/src/assets/fonts/Satoshi-Medium.woff2 differ diff --git a/src/assets/fonts/Satoshi-MediumItalic.woff2 b/src/assets/fonts/Satoshi-MediumItalic.woff2 new file mode 100644 index 0000000..06f265b Binary files /dev/null and b/src/assets/fonts/Satoshi-MediumItalic.woff2 differ diff --git a/src/assets/fonts/Satoshi-Regular.woff2 b/src/assets/fonts/Satoshi-Regular.woff2 new file mode 100644 index 0000000..4adff66 Binary files /dev/null and b/src/assets/fonts/Satoshi-Regular.woff2 differ diff --git a/src/assets/illustrations/Book lover-bro.svg b/src/assets/illustrations/Book lover-bro.svg new file mode 100644 index 0000000..d9f2cea --- /dev/null +++ b/src/assets/illustrations/Book lover-bro.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/illustrations/Circles-bro.svg b/src/assets/illustrations/Circles-bro.svg new file mode 100644 index 0000000..3886c4d --- /dev/null +++ b/src/assets/illustrations/Circles-bro.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/illustrations/learning_illustration.png b/src/assets/illustrations/learning_illustration.png new file mode 100644 index 0000000..afdcd09 Binary files /dev/null and b/src/assets/illustrations/learning_illustration.png differ diff --git a/src/assets/illustrations/student_learning.svg b/src/assets/illustrations/student_learning.svg new file mode 100644 index 0000000..bd8f553 --- /dev/null +++ b/src/assets/illustrations/student_learning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/illustrations/student_progress.svg b/src/assets/illustrations/student_progress.svg new file mode 100644 index 0000000..f41cc34 --- /dev/null +++ b/src/assets/illustrations/student_progress.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/logo-dark.svg b/src/assets/logo-dark.svg new file mode 100644 index 0000000..4de52bd --- /dev/null +++ b/src/assets/logo-dark.svg @@ -0,0 +1,10 @@ + + + + EDBRIDGE + SCHOLARS + diff --git a/src/assets/logo-purple.svg b/src/assets/logo-purple.svg new file mode 100644 index 0000000..9c56b37 --- /dev/null +++ b/src/assets/logo-purple.svg @@ -0,0 +1,10 @@ + + + + EDBRIDGE + SCHOLARS + diff --git a/src/assets/logo-white.svg b/src/assets/logo-white.svg new file mode 100644 index 0000000..2b54340 --- /dev/null +++ b/src/assets/logo-white.svg @@ -0,0 +1,10 @@ + + + + EDBRIDGE + SCHOLARS + diff --git a/src/assets/math-styles.css b/src/assets/math-styles.css new file mode 100644 index 0000000..1260222 --- /dev/null +++ b/src/assets/math-styles.css @@ -0,0 +1,132 @@ +/* +* Prefixed by https://autoprefixer.github.io +* PostCSS: v8.4.14, +* Autoprefixer: v10.4.7 +* Browsers: last 4 version +*/ + +/* Math Rendering Styles */ + +/* General math container */ +.math-content { + font-size: 1rem; + line-height: 1.6; +} + +/* Inline math */ +.math-inline { + display: inline-block; + vertical-align: middle; +} + +/* Block math */ +.math-block { + display: block; + margin: 1rem 0; + overflow-x: auto; + text-align: center; +} + +/* Math editor toolbar */ +.math-symbols-toolbar { + background-color: #f7f7f7; + border-radius: 6px; + padding: 0.75rem; + margin-top: 0.5rem; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); +} + +.math-symbols-toolbar button { + margin-right: 0.25rem; + margin-bottom: 0.25rem; + -webkit-transition: all 0.2s ease; + -o-transition: all 0.2s ease; + transition: all 0.2s ease; +} + +.math-symbols-toolbar button:hover { + background-color: #6e44ff; + color: white; +} + +/* Math examples section */ +.math-examples { + background-color: #f8f9fa; + border-radius: 6px; + padding: 0.75rem; + margin-top: 0.5rem; + border: 1px solid #e9ecef; +} + +.math-examples table { + margin-bottom: 0; +} + +.math-examples th, +.math-examples td { + padding: 0.4rem 0.5rem; + vertical-align: middle; +} + +.math-examples code { + background-color: rgba(110, 68, 255, 0.1); + color: #6e44ff; + padding: 0.2rem 0.4rem; + border-radius: 4px; +} + +/* Question option styling */ +.option-content { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + max-width: calc(100% - 60px); +} + +/* Short answer styling */ +.short-answer-content { + background-color: rgba(0, 199, 164, 0.05); + border: 1px solid #00c7a4; + border-radius: 6px; + padding: 1rem; +} + +/* Katex specific overrides */ +.katex { + font-size: 1.1em; +} + +.katex-display { + overflow-x: auto; + overflow-y: hidden; + padding: 0.5rem 0; +} + +/* Preview mode styling */ +.preview-container { + min-height: 100px; + background-color: #fff; + border: 1px solid #dbdbdb; + border-radius: 6px; + padding: 1rem; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05); +} + +/* Tabs styling */ +.tabs ul { + border-bottom-color: #dbdbdb; +} + +.tabs li.is-active a { + border-bottom-color: #6e44ff; + color: #6e44ff; +} + +/* Textarea focus styling */ +#math-editor-textarea:focus { + border-color: #6e44ff; + -webkit-box-shadow: 0 0 0 0.125em rgba(110, 68, 255, 0.25); + box-shadow: 0 0 0 0.125em rgba(110, 68, 255, 0.25); +} diff --git a/src/assets/react.svg b/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/assets/studentProfile.css b/src/assets/studentProfile.css new file mode 100644 index 0000000..c0b26e1 --- /dev/null +++ b/src/assets/studentProfile.css @@ -0,0 +1,781 @@ +/* +* Prefixed by https://autoprefixer.github.io +* PostCSS: v8.4.14, +* Autoprefixer: v10.4.7 +* Browsers: last 4 version +*/ + +/* Student Profile Custom Styles - Unconventional Design */ + +/* Container */ +.student-profile-container { + max-width: 1400px; + margin: 0 auto; + padding: 2rem 1rem; + overflow-x: hidden; +} + +/* Back Button */ +.back-button-container { + margin-bottom: 2rem; + position: relative; + z-index: 10; +} + +/* Hero Section */ +.student-profile-hero { + background: -o-linear-gradient(315deg, #6e44ff 0%, #9f84ff 100%); + background: linear-gradient(135deg, #6e44ff 0%, #9f84ff 100%); + border-radius: 0; + padding: 0; + margin-bottom: 3rem; + position: relative; + overflow: hidden; + color: white; + min-height: 400px; + -webkit-box-shadow: 0 15px 30px rgba(110, 68, 255, 0.2); + box-shadow: 0 15px 30px rgba(110, 68, 255, 0.2); +} + +.student-profile-hero::before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z' fill='%23ffffff' fill-opacity='0.1' fill-rule='evenodd'/%3E%3C/svg%3E"); + opacity: 0.5; +} + +.hero-content { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 3rem 2rem; + position: relative; + z-index: 2; +} + +.student-info { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + padding-right: 2rem; +} + +.hero-illustration { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + position: relative; +} + +.hero-illustration img { + max-width: 100%; + max-height: 350px; + -webkit-transform: scale(1.2) translateY(-20px); + -ms-transform: scale(1.2) translateY(-20px); + transform: scale(1.2) translateY(-20px); + -webkit-filter: drop-shadow(0 10px 15px rgba(0, 0, 0, 0.2)); + filter: drop-shadow(0 10px 15px rgba(0, 0, 0, 0.2)); +} + +/* Student Profile Elements */ +.student-profile-avatar { + width: 120px; + height: 120px; + border-radius: 0; + border: 4px solid white; + -webkit-box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + margin-bottom: 1.5rem; +} + +.student-profile-name { + font-size: 2.5rem; + font-weight: 700; + margin-bottom: 0.5rem; +} + +.student-profile-email { + font-size: 1.1rem; + opacity: 0.9; + margin-bottom: 1rem; +} + +.student-profile-tags { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + margin-bottom: 1.5rem; +} + +.student-profile-tag { + background-color: rgba(255, 255, 255, 0.2); + color: white; + border-radius: 0; + padding: 0.3rem 1rem; + margin-right: 0.5rem; + font-weight: 500; +} + +.student-profile-tag.is-active { + background-color: #00c7a4; +} + +.student-profile-tag.is-inactive { + background-color: #ff2c73; +} + +.student-profile-tag.is-suspended { + background-color: #ffa500; +} + +.student-meta { + margin-top: 1.5rem; +} + +.student-meta-item { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 0.5rem; +} + +.student-meta-item .icon { + margin-right: 0.5rem; +} + +/* Main Content Layout */ +.student-profile-main { + display: -ms-grid; + display: grid; + -ms-grid-columns: 1fr 2rem 2fr; + grid-template-columns: 1fr 2fr; + gap: 2rem; + margin-top: 2rem; +} + +/* Sections */ +.student-profile-section { + background-color: white; + border-radius: 0; + -webkit-box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05); + padding: 1.5rem; + margin-bottom: 2rem; + position: relative; + overflow: hidden; + -webkit-transition: -webkit-transform 0.3s ease, -webkit-box-shadow 0.3s ease; + transition: -webkit-transform 0.3s ease, -webkit-box-shadow 0.3s ease; + -o-transition: transform 0.3s ease, box-shadow 0.3s ease; + transition: transform 0.3s ease, box-shadow 0.3s ease; + transition: transform 0.3s ease, box-shadow 0.3s ease, + -webkit-transform 0.3s ease, -webkit-box-shadow 0.3s ease; +} + +.student-profile-section:hover { + -webkit-transform: translateY(-5px); + -ms-transform: translateY(-5px); + transform: translateY(-5px); + -webkit-box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1); +} + +.student-profile-section-title { + font-size: 1.5rem; + font-weight: 700; + margin-bottom: 1.5rem; + color: #333; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.student-profile-section-title::after { + content: ""; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + height: 2px; + background-color: #f0f0f0; + margin-left: 1rem; +} + +/* Statistics Section */ +.stats-section { + position: relative; + overflow: hidden; +} + +.stats-illustration-container { + position: absolute; + top: -20px; + right: -20px; + opacity: 0.1; + z-index: 0; + -webkit-transform: rotate(10deg); + -ms-transform: rotate(10deg); + transform: rotate(10deg); +} + +.stats-illustration { + width: 150px; + height: auto; +} + +/* Performance Overview */ +.performance-overview { + margin-bottom: 1.5rem; + position: relative; + z-index: 1; +} + +.performance-header { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-bottom: 1rem; +} + +.performance-title { + font-size: 1.2rem; + font-weight: 600; + color: #333; +} + +.performance-badge { + background-color: #6e44ff; + color: white; + padding: 0.3rem 1rem; + font-weight: 600; + font-size: 0.9rem; + border-radius: 0; +} + +/* Stats Grid */ +.stats-grid { + display: -ms-grid; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); + gap: 1rem; + position: relative; + z-index: 1; + margin-bottom: 2rem; +} + +.student-profile-stat { + text-align: center; + padding: 1.5rem; + background-color: #f9f9f9; + border-radius: 0; + -webkit-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; +} + +.student-profile-stat:hover { + background-color: #6e44ff; + color: white; + -webkit-transform: translateY(-5px); + -ms-transform: translateY(-5px); + transform: translateY(-5px); +} + +.student-profile-stat:hover .student-profile-stat-value, +.student-profile-stat:hover .student-profile-stat-label, +.student-profile-stat:hover .stat-trend { + color: white; +} + +.student-profile-stat-value { + font-size: 2.5rem; + font-weight: 700; + color: #6e44ff; + line-height: 1; + margin-bottom: 0.5rem; +} + +.student-profile-stat-label { + font-size: 0.9rem; + color: #666; + text-transform: uppercase; + letter-spacing: 1px; + font-weight: 600; + margin-bottom: 0.5rem; +} + +.stat-trend { + font-size: 0.8rem; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + gap: 0.25rem; +} + +.stat-trend.positive { + color: #00c7a4; +} + +.stat-trend.negative { + color: #ff2c73; +} + +.stat-trend.neutral { + color: #999; +} + +/* Subject Performance */ +.subject-performance { + position: relative; + z-index: 1; +} + +.subject-performance-title { + font-size: 1.2rem; + font-weight: 600; + color: #333; + margin-bottom: 1rem; +} + +.subject-cards { + display: -ms-grid; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 1rem; +} + +.subject-card { + background-color: white; + border: 1px solid #f0f0f0; + -webkit-box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05); + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05); + -webkit-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; + overflow: hidden; +} + +.subject-card:hover { + -webkit-transform: translateY(-5px); + -ms-transform: translateY(-5px); + transform: translateY(-5px); + -webkit-box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1); + box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1); +} + +.subject-card-header { + background-color: #6e44ff; + color: white; + padding: 0.75rem 1rem; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.subject-card-label { + font-weight: 600; + font-size: 1rem; +} + +.subject-card-score { + font-weight: 700; + font-size: 1.2rem; +} + +.subject-card-body { + padding: 1rem; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.subject-card-icon { + width: 40px; + height: 40px; + background-color: rgba(110, 68, 255, 0.1); + border-radius: 0; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-right: 1rem; + color: #6e44ff; + font-size: 1.2rem; +} + +.subject-card-info { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.subject-card-trend { + font-size: 0.9rem; + font-weight: 600; + margin-bottom: 0.25rem; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: 0.25rem; +} + +.subject-card-trend.positive { + color: #00c7a4; +} + +.subject-card-trend.negative { + color: #ff2c73; +} + +.subject-card-trend.neutral { + color: #999; +} + +.subject-card-status { + font-size: 0.8rem; + color: #666; + text-transform: uppercase; + letter-spacing: 1px; +} + +/* Settings Section */ +.settings-section { + margin-top: 2rem; +} + +.settings-content { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +.settings-illustration-container { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin-bottom: 1.5rem; +} + +.settings-illustration { + max-width: 100%; + height: 150px; +} + +/* Practice Sheets Section */ +.practice-sheets-section { + position: relative; +} + +.practice-sheets-content { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +.practice-illustration-container { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin-bottom: 1.5rem; +} + +.practice-illustration { + height: 120px; + width: auto; +} + +.practice-sheets-table-container { + position: relative; + z-index: 1; +} + +/* Activity Section */ +.activity-section { + position: relative; +} + +.activity-content { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +.activity-illustration-container { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin-bottom: 1.5rem; +} + +.activity-illustration { + height: 120px; + width: auto; +} + +.activity-timeline-container { + position: relative; + z-index: 1; +} + +.activity-timeline { + position: relative; + padding-left: 2rem; +} + +.activity-timeline::before { + content: ""; + position: absolute; + top: 0; + left: 8px; + height: 100%; + width: 2px; + background-color: #f0f0f0; +} + +.activity-item { + position: relative; + padding-bottom: 1.5rem; +} + +.activity-item:last-child { + padding-bottom: 0; +} + +.activity-marker { + position: absolute; + left: -2rem; + top: 0; + width: 18px; + height: 18px; + border-radius: 0; + background-color: #6e44ff; + border: 3px solid white; + -webkit-box-shadow: 0 0 0 2px #f0f0f0; + box-shadow: 0 0 0 2px #f0f0f0; + z-index: 1; +} + +.activity-marker.is-success { + background-color: #00c7a4; +} + +.activity-marker.is-warning { + background-color: #ffd166; +} + +.activity-date { + font-size: 0.8rem; + color: #999; + margin-bottom: 0.25rem; + font-weight: 500; +} + +.activity-content { + font-weight: 500; + color: #333; +} + +.activity-score { + font-weight: 700; + color: #6e44ff; +} + +/* Illustration Sections */ +.math-illustration-section, +.study-illustration-section { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 2rem; + background-color: #f9f9f9; + min-height: 300px; +} + +.math-illustration, +.study-illustration { + max-width: 100%; + max-height: 250px; + -webkit-filter: drop-shadow(0 10px 15px rgba(0, 0, 0, 0.1)); + filter: drop-shadow(0 10px 15px rgba(0, 0, 0, 0.1)); +} + +/* Button Styles */ +.hip-button { + background-color: #6e44ff; + color: white; + border: none; + border-radius: 0; + padding: 0.5rem 1.5rem; + font-weight: 600; + -webkit-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; + -webkit-box-shadow: 0 4px 10px rgba(110, 68, 255, 0.3); + box-shadow: 0 4px 10px rgba(110, 68, 255, 0.3); +} + +.hip-button:hover { + background-color: #5a36d5; + -webkit-transform: translateY(-2px); + -ms-transform: translateY(-2px); + transform: translateY(-2px); + -webkit-box-shadow: 0 6px 15px rgba(110, 68, 255, 0.4); + box-shadow: 0 6px 15px rgba(110, 68, 255, 0.4); + color: white; +} + +.hip-button.is-small { + padding: 0.25rem 0.75rem; + font-size: 0.85rem; +} + +/* Responsive Styles */ +@media screen and (max-width: 1200px) { + .student-profile-main { + -ms-grid-columns: 1fr; + grid-template-columns: 1fr; + } + + .hero-content { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + text-align: center; + } + + .student-info { + padding-right: 0; + margin-bottom: 2rem; + } + + .student-profile-tags { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + } + + .student-meta { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + } + + .student-meta-item { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + } +} + +@media screen and (max-width: 768px) { + .student-profile-hero { + min-height: auto; + } + + .hero-content { + padding: 2rem 1rem; + } + + .student-profile-name { + font-size: 2rem; + } + + .student-profile-avatar { + width: 100px; + height: 100px; + } + + .hero-illustration img { + max-height: 200px; + } + + .math-illustration-section, + .study-illustration-section { + min-height: 200px; + } + + .math-illustration, + .study-illustration { + max-height: 180px; + } +} diff --git a/src/components/ProtectedRoute.tsx b/src/components/ProtectedRoute.tsx new file mode 100644 index 0000000..737032b --- /dev/null +++ b/src/components/ProtectedRoute.tsx @@ -0,0 +1,13 @@ +import { Navigate, Outlet, useLocation } from "react-router-dom"; +import { useAuthStore } from "../stores/authStore"; + +export const ProtectedRoute = () => { + const isAuthenticated = useAuthStore((state) => state.isAuthenticated); + const location = useLocation(); + + if (!isAuthenticated) { + return ; + } + + return ; +}; diff --git a/src/index.css b/src/index.css index a461c50..bd23856 100644 --- a/src/index.css +++ b/src/index.css @@ -1 +1,161 @@ -@import "tailwindcss"; \ No newline at end of file +@import "tailwindcss"; + +/* ================================ + Satoshi Font Family + ================================ */ + +@font-face { + font-family: "Satoshi"; + src: url("./assets/fonts/Satoshi-Light.woff2") format("woff2"); + font-weight: 300; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Satoshi"; + src: url("./assets/fonts/Satoshi-LightItalic.woff2") format("woff2"); + font-weight: 300; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "Satoshi"; + src: url("./assets/fonts/Satoshi-Regular.woff2") format("woff2"); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Satoshi"; + src: url("./assets/fonts/Satoshi-Italic.woff2") format("woff2"); + font-weight: 400; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "Satoshi"; + src: url("./assets/fonts/Satoshi-Medium.woff2") format("woff2"); + font-weight: 500; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Satoshi"; + src: url("./assets/fonts/Satoshi-MediumItalic.woff2") format("woff2"); + font-weight: 500; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "Satoshi"; + src: url("./assets/fonts/Satoshi-Bold.woff2") format("woff2"); + font-weight: 700; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Satoshi"; + src: url("./assets/fonts/Satoshi-BoldItalic.woff2") format("woff2"); + font-weight: 700; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "Satoshi"; + src: url("./assets/fonts/Satoshi-Black.woff2") format("woff2"); + font-weight: 900; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Satoshi"; + src: url("./assets/fonts/Satoshi-BlackItalic.woff2") format("woff2"); + font-weight: 900; + font-style: italic; + font-display: swap; +} + +@theme { + --font-satoshi: "Satoshi", system-ui, sans-serif; +} + +@layer utilities { + /* Base family */ + .font-satoshi { + font-family: var(--font-satoshi); + } + + /* Light */ + .font-satoshi-light { + font-family: var(--font-satoshi); + font-weight: 300; + font-style: normal; + } + + .font-satoshi-light-italic { + font-family: var(--font-satoshi); + font-weight: 300; + font-style: italic; + } + + /* Regular */ + .font-satoshi-regular { + font-family: var(--font-satoshi); + font-weight: 400; + font-style: normal; + } + + .font-satoshi-italic { + font-family: var(--font-satoshi); + font-weight: 400; + font-style: italic; + } + + /* Medium */ + .font-satoshi-medium { + font-family: var(--font-satoshi); + font-weight: 500; + font-style: normal; + } + + .font-satoshi-medium-italic { + font-family: var(--font-satoshi); + font-weight: 500; + font-style: italic; + } + + /* Bold */ + .font-satoshi-bold { + font-family: var(--font-satoshi); + font-weight: 700; + font-style: normal; + } + + .font-satoshi-bold-italic { + font-family: var(--font-satoshi); + font-weight: 700; + font-style: italic; + } + + /* Black */ + .font-satoshi-black { + font-family: var(--font-satoshi); + font-weight: 900; + font-style: normal; + } + + .font-satoshi-black-italic { + font-family: var(--font-satoshi); + font-weight: 900; + font-style: italic; + } +} diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx new file mode 100644 index 0000000..04b30f5 --- /dev/null +++ b/src/pages/Login.tsx @@ -0,0 +1,157 @@ +import { useState, useEffect } from "react"; +import type { FormEvent } from "react"; +import { useNavigate, useLocation } from "react-router-dom"; +import { useAuthStore } from "../stores/authStore"; + +interface LocationState { + from?: { + pathname: string; + }; +} + +export const Login = () => { + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const navigate = useNavigate(); + const location = useLocation(); + + const { login, isAuthenticated, isLoading, error, clearError } = + useAuthStore(); + + const from = (location.state as LocationState)?.from?.pathname || "/student"; + + // Redirect if already authenticated + useEffect(() => { + if (isAuthenticated) { + navigate("/student", { replace: true }); + } + }, [isAuthenticated, navigate]); + + // Clear error when component unmounts or inputs change + useEffect(() => { + return () => clearError(); + }, [clearError]); + + const handleSubmit = async (e: FormEvent) => { + e.preventDefault(); + clearError(); + + const success = await login({ email, password }); + if (success) { + navigate(from, { replace: true }); + } + }; + + // Don't render login form if already authenticated + if (isAuthenticated) { + return null; + } + + return ( +
+
+
+ EdBridge logo +
+

+ Welcome Back +

+
+
+ + setEmail(e.target.value)} + disabled={isLoading} + className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent outline-none transition disabled:bg-gray-100 disabled:cursor-not-allowed" + placeholder="Enter your email" + /> +
+ +
+ + setPassword(e.target.value)} + disabled={isLoading} + className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent outline-none transition disabled:bg-gray-100 disabled:cursor-not-allowed" + placeholder="Enter your password" + /> +
+ + +
+
+ + {error && ( +
+ {error} +
+ )} + + +
+
+
+ ); +}; diff --git a/src/pages/StudentDashboard.tsx b/src/pages/StudentDashboard.tsx new file mode 100644 index 0000000..cd677a7 --- /dev/null +++ b/src/pages/StudentDashboard.tsx @@ -0,0 +1,62 @@ +import { useNavigate } from "react-router-dom"; +import { useAuthStore } from "../stores/authStore"; + +export const StudentDashboard = () => { + const user = useAuthStore((state) => state.user); + const logout = useAuthStore((state) => state.logout); + const navigate = useNavigate(); + + const handleLogout = () => { + logout(); + navigate("/login"); + }; + + return ( +
+ + +
+
+

Dashboard

+
+

Email: {user?.email}

+

Role: {user?.role}

+

Status: {user?.status}

+

+ Member since:{" "} + {user?.joined_at + ? new Date(user.joined_at).toLocaleDateString() + : "N/A"} +

+
+
+
+
+ ); +}; diff --git a/src/stores/authStore.ts b/src/stores/authStore.ts new file mode 100644 index 0000000..94309bf --- /dev/null +++ b/src/stores/authStore.ts @@ -0,0 +1,75 @@ +import { create } from "zustand"; +import { persist } from "zustand/middleware"; +import { api, type User, type LoginRequest } from "../utils/api"; + +interface AuthState { + user: User | null; + token: string | null; + isAuthenticated: boolean; + isLoading: boolean; + error: string | null; + login: (credentials: LoginRequest) => Promise; + logout: () => void; + clearError: () => void; +} + +export const useAuthStore = create()( + persist( + (set) => ({ + user: null, + token: null, + isAuthenticated: false, + isLoading: false, + error: null, + + login: async (credentials: LoginRequest) => { + set({ isLoading: true, error: null }); + + try { + const response = await api.login(credentials); + + set({ + user: response.user, + token: response.token, + isAuthenticated: true, + isLoading: false, + error: null, + }); + + return true; + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : "Login failed"; + set({ + user: null, + token: null, + isAuthenticated: false, + isLoading: false, + error: errorMessage, + }); + + return false; + } + }, + + logout: () => { + set({ + user: null, + token: null, + isAuthenticated: false, + error: null, + }); + }, + + clearError: () => set({ error: null }), + }), + { + name: "auth-storage", + partialize: (state) => ({ + user: state.user, + token: state.token, + isAuthenticated: state.isAuthenticated, + }), + } + ) +); diff --git a/src/utils/api.ts b/src/utils/api.ts new file mode 100644 index 0000000..4660407 --- /dev/null +++ b/src/utils/api.ts @@ -0,0 +1,101 @@ +const API_URL = "https://dsat-api.edbridgescholars.com"; + +export interface LoginRequest { + email: string; + password: string; +} + +export interface User { + email: string; + name: string; + role: "STUDENT" | "TEACHER" | "ADMIN"; + avatar_url: string; + id: string; + status: "ACTIVE" | "INACTIVE"; + joined_at: string; + last_active: string; +} + +export interface LoginResponse { + token: string; + token_type: string; + user: User; +} + +export interface ApiError { + detail?: string; + message?: string; +} + +class ApiClient { + private baseURL: string; + + constructor(baseURL: string) { + this.baseURL = baseURL; + } + + private async request( + endpoint: string, + options: RequestInit = {} + ): Promise { + const url = `${this.baseURL}${endpoint}`; + + const config: RequestInit = { + ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, + }; + + try { + const response = await fetch(url, config); + + if (!response.ok) { + const error: ApiError = await response.json().catch(() => ({ + message: "An error occurred", + })); + throw new Error(error.detail || error.message || "Request failed"); + } + + return await response.json(); + } catch (error) { + if (error instanceof Error) { + throw error; + } + throw new Error("Network error occurred"); + } + } + + // Auth endpoints + async login(credentials: LoginRequest): Promise { + return this.request("/auth/login/", { + method: "POST", + body: JSON.stringify(credentials), + }); + } + + // Authenticated request helper + async authenticatedRequest( + endpoint: string, + token: string, + options: RequestInit = {} + ): Promise { + return this.request(endpoint, { + ...options, + headers: { + ...options.headers, + Authorization: `Bearer ${token}`, + }, + }); + } + + // Example: Get user profile (authenticated endpoint) + async getUserProfile(token: string): Promise { + return this.authenticatedRequest("/auth/me", token); + } + + // Add more API methods here as needed +} + +export const api = new ApiClient(API_URL);