From ea4553c6eb4b31f061e921948660b23c60cd15b3 Mon Sep 17 00:00:00 2001 From: sameerreddy213 Date: Sat, 12 Jul 2025 16:18:56 +0530 Subject: [PATCH] updated ui --- .../client/src/App.css | 779 ++++++++++++++---- .../client/src/App.tsx | 55 +- .../client/src/components/DiscussModal.tsx | 12 +- .../client/src/components/Footer.tsx | 242 ++++++ .../src/components/LearnedConceptCard.tsx | 124 ++- .../client/src/components/LoadingSpinner.tsx | 73 +- .../client/src/components/Navbar.tsx | 167 ++-- .../client/src/components/QuizCard.tsx | 117 ++- .../client/src/index.css | 286 ++++++- .../client/src/pages/DiscussionDetailPage.tsx | 9 +- .../client/src/pages/DiscussionPage.tsx | 2 +- .../client/src/pages/HomePage.tsx | 350 ++++++-- .../client/src/pages/LoginPage.tsx | 223 +++-- .../client/src/pages/PlaygroundPage.tsx | 24 +- .../client/src/pages/RegisterPage.tsx | 422 ++++++---- 15 files changed, 2242 insertions(+), 643 deletions(-) diff --git a/team-bhavitha-dsarecommender/client/src/App.css b/team-bhavitha-dsarecommender/client/src/App.css index 88c23a8f7..2cc25c53e 100644 --- a/team-bhavitha-dsarecommender/client/src/App.css +++ b/team-bhavitha-dsarecommender/client/src/App.css @@ -1,14 +1,36 @@ -/* client/src/App.css - Ensure these styles are present, and remove any others */ +/* client/src/App.css - Enhanced Modern Design */ -/* Basic Spinner */ +/* Modern Color Palette */ +:root { + --primary-purple: #8b5cf6; + --primary-purple-dark: #7c3aed; + --primary-purple-light: #a78bfa; + --secondary-blue: #3b82f6; + --accent-green: #10b981; + --accent-orange: #f59e0b; + --accent-red: #ef4444; + --dark-bg: #0f172a; + --dark-card: #1e293b; + --dark-border: #334155; + --text-primary: #f8fafc; + --text-secondary: #cbd5e1; + --text-muted: #94a3b8; + --gradient-primary: linear-gradient(135deg, #8b5cf6 0%, #3b82f6 100%); + --gradient-secondary: linear-gradient(135deg, #1e293b 0%, #334155 100%); + --shadow-soft: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + --shadow-medium: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + --shadow-large: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); +} + +/* Enhanced Spinner */ .spinner { - border: 4px solid rgba(255, 255, 255, 0.3); - border-top: 4px solid #a872e6; /* Primary color for spinner */ + border: 3px solid rgba(139, 92, 246, 0.1); + border-top: 3px solid var(--primary-purple); border-radius: 50%; width: 24px; height: 24px; animation: spin 1s linear infinite; - display: inline-block; /* To allow text beside it */ + display: inline-block; } @keyframes spin { @@ -16,244 +38,653 @@ 100% { transform: rotate(360deg); } } -/* Full-page Overlay for major loading states */ +/* Enhanced Loading Overlay */ .loading-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; - background-color: rgba(0, 0, 0, 0.7); /* Semi-transparent dark background */ + background: linear-gradient(135deg, rgba(15, 23, 42, 0.95) 0%, rgba(30, 41, 59, 0.95) 100%); + backdrop-filter: blur(10px); display: flex; justify-content: center; align-items: center; - z-index: 1050; /* Above Bootstrap navbars, etc. */ - color: white; + z-index: 1050; + color: var(--text-primary); flex-direction: column; } .loading-overlay .spinner { - width: 50px; /* Larger spinner for overlay */ - height: 50px; - border-width: 6px; - margin-bottom: 15px; + width: 60px; + height: 60px; + border-width: 4px; + margin-bottom: 20px; } -/* --- Existing App.css styles (keep these) --- */ +/* Enhanced Body Styles */ body { - background-color: #1a1a1a; - color: #e0e0e0; + background: var(--dark-bg); + color: var(--text-primary); + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + line-height: 1.6; } #root { - background-color: #1a1a1a; - color: #e0e0e0; + background: var(--dark-bg); + color: var(--text-primary); + min-height: 100vh; } +/* Enhanced Text Colors */ .text-dark-contrast { - color: #333333 !important; + color: #1e293b !important; } .text-purple { - color: #a872e6 !important; + color: var(--primary-purple) !important; } -.border-dashed { - border-style: dashed !important; + +.text-purple-dark { + color: var(--primary-purple-dark) !important; +} + +.text-purple-light { + color: var(--primary-purple-light) !important; } -.form-control::placeholder, -.form-control:-ms-input-placeholder, -.form-control::-ms-input-placeholder { - color: #aaaaaa; +/* Enhanced Form Controls */ +.form-control { + background-color: var(--dark-card); + border: 2px solid var(--dark-border); + color: var(--text-primary); + border-radius: 12px; + padding: 12px 16px; + transition: all 0.3s ease; +} + +.form-control:focus { + background-color: var(--dark-card); + border-color: var(--primary-purple); + box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1); + color: var(--text-primary); +} + +.form-control::placeholder { + color: var(--text-muted); opacity: 1; } +/* Enhanced Buttons */ +.btn { + border-radius: 12px; + font-weight: 600; + padding: 12px 24px; + transition: all 0.3s ease; + border: none; + position: relative; + overflow: hidden; +} + +.btn-primary { + background: var(--gradient-primary); + color: white; + box-shadow: var(--shadow-soft); +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-medium); + background: linear-gradient(135deg, var(--primary-purple-dark) 0%, var(--secondary-blue) 100%); +} + +.btn-success { + background: linear-gradient(135deg, var(--accent-green) 0%, #059669 100%); + color: white; + box-shadow: var(--shadow-soft); +} + +.btn-success:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-medium); + background: linear-gradient(135deg, #059669 0%, #047857 100%); +} + +.btn-warning { + background: linear-gradient(135deg, var(--accent-orange) 0%, #d97706 100%); + color: white; + box-shadow: var(--shadow-soft); +} + +.btn-warning:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-medium); + background: linear-gradient(135deg, #d97706 0%, #b45309 100%); +} + +.btn-info { + background: linear-gradient(135deg, var(--secondary-blue) 0%, #2563eb 100%); + color: white; + box-shadow: var(--shadow-soft); +} + +.btn-info:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-medium); + background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%); +} + +/* Enhanced Cards */ +.card { + background: var(--dark-card); + border: 2px solid var(--dark-border); + border-radius: 16px; + box-shadow: var(--shadow-soft); + transition: all 0.3s ease; + overflow: hidden; +} + +.card:hover { + transform: translateY(-4px); + box-shadow: var(--shadow-large); + border-color: var(--primary-purple); +} + +.card-body { + padding: 1.5rem; +} + +/* Enhanced Clickable Elements */ .clickable-badge { - cursor: pointer; - transition: background-color 0.2s ease; + cursor: pointer; + transition: all 0.3s ease; + border-radius: 20px; + padding: 8px 16px; + font-weight: 600; } + .clickable-badge:hover { - background-color: #555555 !important; + background: var(--gradient-primary) !important; + color: white !important; + transform: translateY(-2px); + box-shadow: var(--shadow-medium); } .clickable-card { - transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; + transition: all 0.3s ease; + cursor: pointer; } .clickable-card:hover { - transform: translateY(-5px); /* Lift effect */ - box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2) !important; /* Stronger shadow */ + transform: translateY(-8px) scale(1.02); + box-shadow: var(--shadow-large) !important; + border-color: var(--primary-purple) !important; } -/* Ensure the text color is correctly applied for LearnedConceptCard */ -.text-dark { - color: #333333 !important; +/* Enhanced Navigation */ +.navbar { + background: rgba(15, 23, 42, 0.95) !important; + backdrop-filter: blur(20px); + border-bottom: 2px solid var(--dark-border); + box-shadow: var(--shadow-medium); } -.text-dark-emphasis { - color: #5a5a5a !important; /* Slightly lighter dark for emphasis */ +.navbar-brand { + font-weight: 800; + font-size: 1.5rem; + background: var(--gradient-primary); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; } -/* client/src/App.css */ +.nav-link { + font-weight: 600; + transition: all 0.3s ease; + border-radius: 8px; + padding: 8px 16px !important; +} -/* ... existing styles ... */ +.nav-link:hover { + background: rgba(139, 92, 246, 0.1); + color: var(--primary-purple) !important; +} .active-link { - color: var(--bs-primary) !important; /* Or your custom --lf-primary */ - border-bottom: 2px solid var(--bs-primary); - padding-bottom: 5px; /* Adjust as needed */ + background: var(--gradient-primary) !important; + color: white !important; + box-shadow: var(--shadow-soft); } +/* Enhanced Dropdown */ .dropdown-menu-dark { - background-color: #343a40; /* Darker background */ - border: 1px solid #495057; /* Darker border */ + background: var(--dark-card); + border: 2px solid var(--dark-border); + border-radius: 12px; + box-shadow: var(--shadow-large); + backdrop-filter: blur(20px); } .dropdown-menu-dark .dropdown-item { - color: #f8f9fa; /* Light text */ + color: var(--text-primary); + padding: 12px 20px; + transition: all 0.3s ease; + border-radius: 8px; + margin: 4px 8px; } .dropdown-menu-dark .dropdown-item:hover { - background-color: #495057; /* Slightly lighter on hover */ - color: #ffffff; + background: var(--gradient-primary); + color: white; + transform: translateX(4px); } .dropdown-menu-dark .dropdown-divider { - border-top-color: #6c757d; /* Dark divider */ + border-top-color: var(--dark-border); + margin: 8px 16px; } -/* --- Educator Dashboard Enhancements --- */ -.educator-section-card { - border: 2px solid #a872e6 !important; /* Purple border */ - border-radius: 18px !important; - background: rgba(40, 40, 60, 0.97) !important; - box-shadow: 0 4px 24px rgba(168, 114, 230, 0.10), 0 1.5px 8px rgba(0,0,0,0.10); - padding: 2rem 1.5rem; - margin-bottom: 2.5rem; - transition: box-shadow 0.2s, border-color 0.2s; +/* Enhanced Dashboard Sections */ +.dashboard-section { + background: var(--dark-card); + border: 2px solid var(--dark-border); + border-radius: 20px; + padding: 2rem; + margin-bottom: 2rem; + box-shadow: var(--shadow-soft); + transition: all 0.3s ease; } -.educator-section-card:hover { - box-shadow: 0 8px 32px rgba(168, 114, 230, 0.18), 0 2px 12px rgba(0,0,0,0.13); - border-color: #7c3aed !important; + +.dashboard-section:hover { + border-color: var(--primary-purple); + box-shadow: var(--shadow-medium); } -.educator-section-title { - font-size: 1.5rem; - font-weight: 600; - color: #a872e6; - text-align: center; - margin-bottom: 1.2rem; - letter-spacing: 0.5px; -} -.educator-section-desc { - text-align: center; - color: #b0b0b0; + +/* Enhanced Charts */ +.chart-container { + background: var(--dark-card); + border: 2px solid var(--dark-border); + border-radius: 16px; + padding: 1.5rem; + box-shadow: var(--shadow-soft); +} + +/* Enhanced List Groups */ +.list-group-item { + background: var(--dark-card); + border: 2px solid var(--dark-border); + color: var(--text-primary); + border-radius: 12px; margin-bottom: 0.5rem; + transition: all 0.3s ease; } -.enrolled-student-card { - background: linear-gradient(135deg, #232946 60%, #a872e6 100%) !important; - border: 2.5px solid #a872e6 !important; - border-radius: 18px !important; - color: #fff !important; - box-shadow: 0 6px 24px rgba(168, 114, 230, 0.13), 0 2px 10px rgba(0,0,0,0.13); - transition: box-shadow 0.2s, border-color 0.2s, transform 0.15s; -} -.enrolled-student-card:hover { - box-shadow: 0 12px 32px rgba(168, 114, 230, 0.22), 0 4px 16px rgba(0,0,0,0.18); - border-color: #7c3aed !important; - transform: translateY(-4px) scale(1.03); -} - -/* --- Educator Discussion Enhancements --- */ -.discussion-thread-card { - background: linear-gradient(120deg, #232946 70%, #a872e6 100%) !important; - border: 2.5px solid #a872e6 !important; - border-radius: 18px !important; - color: #fff !important; - box-shadow: 0 6px 24px rgba(168, 114, 230, 0.13), 0 2px 10px rgba(0,0,0,0.13); - margin-bottom: 2.5rem; - padding: 1.5rem 1.2rem; - transition: box-shadow 0.2s, border-color 0.2s, transform 0.15s; -} -.discussion-thread-card:hover { - box-shadow: 0 12px 32px rgba(168, 114, 230, 0.22), 0 4px 16px rgba(0,0,0,0.18); - border-color: #7c3aed !important; - transform: translateY(-4px) scale(1.01); -} -.discussion-thread-title { - font-size: 1.3rem; +.list-group-item:hover { + background: rgba(139, 92, 246, 0.1); + border-color: var(--primary-purple); + transform: translateX(4px); +} + +/* Enhanced Badges */ +.badge { + border-radius: 20px; font-weight: 600; - color: #a872e6; - margin-bottom: 0.5rem; - letter-spacing: 0.2px; -} -.discussion-thread-meta { - color: #b0b0b0; - font-size: 0.95rem; -} -.discussion-comment { - background: #2d314d !important; - border-left: 4px solid #a872e6 !important; - border-radius: 12px !important; - margin-top: 1.2rem; - margin-bottom: 0.7rem; - padding: 1rem 1.2rem; - color: #fff !important; -} -.discussion-reply { - background: #232946 !important; - border-left: 4px solid #7c3aed !important; - border-radius: 10px !important; - margin-top: 0.7rem; - margin-bottom: 0.5rem; - padding: 0.8rem 1rem; - color: #e0e0e0 !important; + padding: 8px 16px; + font-size: 0.875rem; +} + +.badge.bg-primary { + background: var(--gradient-primary) !important; +} + +.badge.bg-success { + background: linear-gradient(135deg, var(--accent-green) 0%, #059669 100%) !important; +} + +.badge.bg-warning { + background: linear-gradient(135deg, var(--accent-orange) 0%, #d97706 100%) !important; +} + +/* Enhanced Progress Bars */ +.progress { + background: var(--dark-border); + border-radius: 12px; + height: 12px; + overflow: hidden; +} + +.progress-bar { + background: var(--gradient-primary); + border-radius: 12px; + transition: all 0.3s ease; } -.discussion-username { - color: #a872e6 !important; + +/* Enhanced Alerts */ +.alert { + border-radius: 12px; + border: none; + padding: 1rem 1.5rem; font-weight: 600; - font-size: 1.05rem; -} -.discussion-date { - color: #fff !important; -} - -/* --- HomePage UI Enhancements --- */ -.homepage-gradient { - background: linear-gradient(120deg, #232946 60%, #a872e6 100%) !important; - border-radius: 24px !important; - box-shadow: 0 8px 32px rgba(168, 114, 230, 0.13), 0 2px 10px rgba(0,0,0,0.13); - padding: 2.5rem 2rem; -} -.homepage-card { - background: linear-gradient(120deg, #fff 70%, #e0d7f7 100%) !important; - border: 2px solid #a872e6 !important; - border-radius: 18px !important; - transition: box-shadow 0.2s, border-color 0.2s, transform 0.15s; - box-shadow: 0 4px 16px rgba(168, 114, 230, 0.10), 0 1.5px 8px rgba(0,0,0,0.10); -} -.homepage-card:hover { - box-shadow: 0 12px 32px rgba(168, 114, 230, 0.18), 0 4px 16px rgba(0,0,0,0.13); - border-color: #7c3aed !important; - transform: translateY(-4px) scale(1.03); -} -.homepage-features-list .list-group-item { - background: #232946 !important; - color: #fff !important; - border: none !important; - border-radius: 12px !important; - margin-bottom: 1rem; - font-size: 1.08rem; - box-shadow: 0 2px 8px rgba(168, 114, 230, 0.07); -} -.homepage-features-list .list-group-item strong { - color: #a872e6 !important; -} -.homepage-section-title { - font-size: 2rem; - font-weight: 700; - color: #a872e6; - margin-bottom: 1.5rem; - text-align: center; - letter-spacing: 0.5px; +} + +.alert-primary { + background: rgba(139, 92, 246, 0.1); + color: var(--primary-purple); + border-left: 4px solid var(--primary-purple); +} + +.alert-success { + background: rgba(16, 185, 129, 0.1); + color: var(--accent-green); + border-left: 4px solid var(--accent-green); +} + +.alert-warning { + background: rgba(245, 158, 11, 0.1); + color: var(--accent-orange); + border-left: 4px solid var(--accent-orange); +} + +.alert-danger { + background: rgba(239, 68, 68, 0.1); + color: var(--accent-red); + border-left: 4px solid var(--accent-red); +} + +/* Enhanced Modal */ +.modal-content { + background: var(--dark-card); + border: 2px solid var(--dark-border); + border-radius: 16px; + box-shadow: var(--shadow-large); +} + +.modal-header { + border-bottom: 2px solid var(--dark-border); + padding: 1.5rem; +} + +.modal-body { + padding: 1.5rem; +} + +.modal-footer { + border-top: 2px solid var(--dark-border); + padding: 1.5rem; +} + +/* Enhanced Tables */ +.table { + color: var(--text-primary); +} + +.table-dark { + background: var(--dark-card); + border-radius: 12px; + overflow: hidden; +} + +.table-dark th { + background: var(--dark-border); + border-color: var(--dark-border); + font-weight: 600; +} + +.table-dark td { + border-color: var(--dark-border); +} + +/* Enhanced Animations */ +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideInLeft { + from { + opacity: 0; + transform: translateX(-30px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes pulse { + 0%, 100% { + transform: scale(1); + } + 50% { + transform: scale(1.05); + } +} + +.animate-fade-in-up { + animation: fadeInUp 0.6s ease-out; +} + +.animate-slide-in-left { + animation: slideInLeft 0.6s ease-out; +} + +.animate-pulse { + animation: pulse 2s infinite; +} + +/* Enhanced Scrollbar */ +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: var(--dark-border); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb { + background: var(--gradient-primary); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--primary-purple-dark); +} + +/* Enhanced Focus States */ +*:focus { + outline: 2px solid var(--primary-purple); + outline-offset: 2px; +} + +/* Enhanced Responsive Design */ +@media (max-width: 768px) { + .card { + margin-bottom: 1rem; + } + + .btn { + width: 100%; + margin-bottom: 0.5rem; + } + + .dashboard-section { + padding: 1rem; + } +} + +/* Enhanced Loading States */ +.skeleton { + background: linear-gradient(90deg, var(--dark-border) 25%, var(--dark-card) 50%, var(--dark-border) 75%); + background-size: 200% 100%; + animation: loading 1.5s infinite; + border-radius: 8px; +} + +@keyframes loading { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } +} + +/* Enhanced Tooltips */ +.tooltip { + background: var(--dark-card); + border: 2px solid var(--dark-border); + border-radius: 8px; + box-shadow: var(--shadow-medium); +} + +.tooltip-inner { + background: var(--dark-card); + color: var(--text-primary); + border-radius: 6px; + padding: 8px 12px; +} + +/* Enhanced Form Validation */ +.form-control.is-valid { + border-color: var(--accent-green); + box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1); +} + +.form-control.is-invalid { + border-color: var(--accent-red); + box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1); +} + +.valid-feedback { + color: var(--accent-green); + font-weight: 600; +} + +.invalid-feedback { + color: var(--accent-red); + font-weight: 600; +} + +/* Enhanced Grid System */ +.row { + margin-left: -0.75rem; + margin-right: -0.75rem; +} + +.col, .col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} + +/* Enhanced Container */ +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 1rem; +} + +/* Enhanced Spacing Utilities */ +.mt-6 { margin-top: 4rem !important; } +.mb-6 { margin-bottom: 4rem !important; } +.pt-6 { padding-top: 4rem !important; } +.pb-6 { padding-bottom: 4rem !important; } + +/* Enhanced Border Radius */ +.rounded-xl { border-radius: 1rem !important; } +.rounded-2xl { border-radius: 1.5rem !important; } +.rounded-3xl { border-radius: 2rem !important; } + +/* Enhanced Shadows */ +.shadow-xl { + box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04) !important; +} + +.shadow-2xl { + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25) !important; +} + +/* Enhanced Gradients */ +.bg-gradient-primary { + background: var(--gradient-primary) !important; +} + +.bg-gradient-secondary { + background: var(--gradient-secondary) !important; +} + +/* Enhanced Glass Effect */ +.glass { + background: rgba(30, 41, 59, 0.8); + backdrop-filter: blur(20px); + border: 2px solid rgba(255, 255, 255, 0.1); +} + +/* Enhanced Hover Effects */ +.hover-lift:hover { + transform: translateY(-4px); + box-shadow: var(--shadow-large); +} + +.hover-scale:hover { + transform: scale(1.05); +} + +.hover-glow:hover { + box-shadow: 0 0 20px rgba(139, 92, 246, 0.3); +} + +/* Enhanced Text Gradients */ +.text-gradient { + background: var(--gradient-primary); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +/* Enhanced Border Gradients */ +.border-gradient { + border: 2px solid; + border-image: var(--gradient-primary) 1; +} + +/* Enhanced Focus Ring */ +.focus-ring { + transition: all 0.3s ease; +} + +.focus-ring:focus { + box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.3); + outline: none; +} + +/* Enhanced Disabled States */ +.btn:disabled, +.form-control:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +/* Enhanced Selection */ +::selection { + background: var(--primary-purple); + color: white; +} + +/* Enhanced Print Styles */ +@media print { + .no-print { + display: none !important; + } + + body { + background: white !important; + color: black !important; + } } \ No newline at end of file diff --git a/team-bhavitha-dsarecommender/client/src/App.tsx b/team-bhavitha-dsarecommender/client/src/App.tsx index f15fdc62e..1e3773ea2 100644 --- a/team-bhavitha-dsarecommender/client/src/App.tsx +++ b/team-bhavitha-dsarecommender/client/src/App.tsx @@ -7,6 +7,7 @@ import QuizPage from "./pages/QuizPage"; import QuizSelectPage from "./pages/QuizSelectPage"; import HomePage from './pages/HomePage'; import Navbar from './components/Navbar'; +import Footer from './components/Footer'; import ExploreTopicPage from "./pages/ExploreTopicPage"; import RecommendationPage from "./pages/RecommendationPage"; import AppEntry from "./routes/AppEntry"; @@ -22,33 +23,33 @@ import PlaygroundPage from './pages/PlaygroundPage.tsx'; function App() { return ( - - {/* Add padding top to account for fixed navbar height, and center content vertically and horizontally */} -
{/* Adjusted styling here */} - - } /> - } /> - } /> - } /> - - {/* Public routes go here */} - {/* Protected routes go here */} - }> - -} /> - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - +
+ +
+ + } /> + } /> + } /> + } /> + + {/* Public routes go here */} + {/* Protected routes go here */} + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + +
+
); diff --git a/team-bhavitha-dsarecommender/client/src/components/DiscussModal.tsx b/team-bhavitha-dsarecommender/client/src/components/DiscussModal.tsx index 75fd19963..2afc08a74 100644 --- a/team-bhavitha-dsarecommender/client/src/components/DiscussModal.tsx +++ b/team-bhavitha-dsarecommender/client/src/components/DiscussModal.tsx @@ -41,16 +41,17 @@ const StartDiscussionModal = ({ show, onClose, onRefresh, username }: Props) => return ( - + Start a Discussion - +
setType("general")} + style={{ border: '1px solid #dee2e6', padding: '10px', borderRadius: '5px', marginBottom: '10px' }} /> checked={type === "question"} onChange={() => setType("question")} className="mb-3" + style={{ border: '1px solid #dee2e6', padding: '10px', borderRadius: '5px' }} /> {type === "general" ? ( @@ -70,6 +72,7 @@ const StartDiscussionModal = ({ show, onClose, onRefresh, username }: Props) => value={text} onChange={(e) => setText(e.target.value)} placeholder="What's on your mind?" + style={{ border: '2px solid #0d6efd', borderRadius: '8px' }} /> @@ -82,6 +85,7 @@ const StartDiscussionModal = ({ show, onClose, onRefresh, username }: Props) => value={topic} onChange={(e) => setTopic(e.target.value)} placeholder="e.g., Graph Theory" + style={{ border: '2px solid #0d6efd', borderRadius: '8px' }} /> @@ -90,6 +94,7 @@ const StartDiscussionModal = ({ show, onClose, onRefresh, username }: Props) => type="number" value={questionIndex} onChange={(e) => setQuestionIndex(e.target.value === "" ? "" : Number(e.target.value))} + style={{ border: '2px solid #0d6efd', borderRadius: '8px' }} /> @@ -99,13 +104,14 @@ const StartDiscussionModal = ({ show, onClose, onRefresh, username }: Props) => rows={2} value={questionText} onChange={(e) => setQuestionText(e.target.value)} + style={{ border: '2px solid #0d6efd', borderRadius: '8px' }} /> )}
- + diff --git a/team-bhavitha-dsarecommender/client/src/components/Footer.tsx b/team-bhavitha-dsarecommender/client/src/components/Footer.tsx index e69de29bb..a80a4ce58 100644 --- a/team-bhavitha-dsarecommender/client/src/components/Footer.tsx +++ b/team-bhavitha-dsarecommender/client/src/components/Footer.tsx @@ -0,0 +1,242 @@ +import { motion } from 'framer-motion'; +import { Heart, Github, Linkedin, Mail, BookOpen } from 'lucide-react'; + +const Footer = () => { + const currentYear = new Date().getFullYear(); + + const containerVariants = { + hidden: { opacity: 0, y: 50 }, + visible: { + opacity: 1, + y: 0, + transition: { + duration: 0.6, + ease: "easeOut" as const, + staggerChildren: 0.1 + } + } + }; + + const itemVariants = { + hidden: { opacity: 0, y: 20 }, + visible: { + opacity: 1, + y: 0, + transition: { + duration: 0.5, + ease: "easeOut" as const + } + } + }; + + return ( + +
+
+ +
+ +
LearnFlow
+
+ +
+ + + + + + + + + +
+
+ + +
Features
+
    +
  • + + Personalized Learning + +
  • +
  • + + Adaptive Quizzes + +
  • +
  • + + Progress Tracking + +
  • +
  • + + Knowledge Graph + +
  • +
+
+ + +
Resources
+
    +
  • + + Documentation + +
  • +
  • + + API Reference + +
  • +
  • + + Tutorials + +
  • +
  • + + Support + +
  • +
+
+ + +
Company
+
    +
  • + + About Us + +
  • +
  • + + Careers + +
  • +
  • + + Privacy Policy + +
  • +
  • + + Terms of Service + +
  • +
+
+ + +
Stats
+ +
+
+ + +
+
+

+ © {currentYear} LearnFlow. All rights reserved. +

+
+
+

+ Made with +

+
+
+
+
+
+ ); +}; + +export default Footer; diff --git a/team-bhavitha-dsarecommender/client/src/components/LearnedConceptCard.tsx b/team-bhavitha-dsarecommender/client/src/components/LearnedConceptCard.tsx index 0ec9b835b..d129e47e7 100644 --- a/team-bhavitha-dsarecommender/client/src/components/LearnedConceptCard.tsx +++ b/team-bhavitha-dsarecommender/client/src/components/LearnedConceptCard.tsx @@ -1,10 +1,11 @@ // client/src/components/LearnedConceptCard.tsx import React from 'react'; -import { BookOpen, Code, FlaskConical, Calculator, BrainCircuit, Lightbulb, GraduationCap } from 'lucide-react'; +import { BookOpen, Code, FlaskConical, Calculator, BrainCircuit, Lightbulb, GraduationCap, CheckCircle, TrendingUp, Award } from 'lucide-react'; +import { motion } from 'framer-motion'; interface LearnedConceptCardProps { title: string; - quizScores?: { score: any; date: any }[]; + quizScores?: { score: number; date: string }[]; } // A simple map for topic-to-icon. Expand this as needed. @@ -20,28 +21,113 @@ const topicIcons: { [key: string]: React.ElementType } = { const LearnedConceptCard = ({ title, quizScores }: LearnedConceptCardProps) => { const IconComponent = topicIcons[title] || BookOpen; + const lastScore = quizScores && quizScores.length > 0 ? quizScores[quizScores.length - 1].score : null; + + const cardVariants = { + hidden: { opacity: 0, scale: 0.9, y: 20 }, + visible: { + opacity: 1, + scale: 1, + y: 0, + transition: { + duration: 0.5, + ease: "easeOut" as const + } + }, + hover: { + scale: 1.05, + y: -8, + transition: { + duration: 0.3, + ease: "easeOut" as const + } + } + }; + + const iconVariants = { + hover: { + rotate: 360, + scale: 1.1, + transition: { + duration: 0.6, + ease: "easeOut" as const + } + } + }; + + const getScoreColor = (score: number) => { + if (score >= 90) return "text-success"; + if (score >= 80) return "text-warning"; + if (score >= 70) return "text-info"; + return "text-secondary"; + }; + + const getScoreIcon = (score: number) => { + if (score >= 90) return Award; + if (score >= 80) return TrendingUp; + return CheckCircle; + }; return ( -
-
-
- -
-

{title}

-

Status: Completed

- {/* This div ensures consistent height regardless of quizScores presence */} - {/* It reserves space for the 'Last Score' line, even if empty */} -
{/* Adjust minHeight if content needs more space */} - {quizScores && quizScores.length > 0 && ( -

- Last Score: **{quizScores[quizScores.length - 1].score.toFixed(0)}%** -

- )} +
+ + + + +

{title}

+ +
+ + Completed
+ + {lastScore && ( + +
+ {React.createElement(getScoreIcon(lastScore), { size: 16, className: "me-2" })} + Last Score: {lastScore.toFixed(0)}% +
+ +
+ +
+
+ )} + + +
+ + Mastered +
+
-
+ ); }; diff --git a/team-bhavitha-dsarecommender/client/src/components/LoadingSpinner.tsx b/team-bhavitha-dsarecommender/client/src/components/LoadingSpinner.tsx index fd0e1d037..40d48edc4 100644 --- a/team-bhavitha-dsarecommender/client/src/components/LoadingSpinner.tsx +++ b/team-bhavitha-dsarecommender/client/src/components/LoadingSpinner.tsx @@ -1,48 +1,49 @@ // client/src/components/LoadingSpinner.tsx -import React from 'react'; +import { motion } from 'framer-motion'; +import { Loader2 } from 'lucide-react'; interface LoadingSpinnerProps { - size?: 'sm' | 'md' | 'lg'; // Small, medium, or large spinner - color?: string; // Custom color for the spinner border top - className?: string; // Additional CSS classes - message?: string; // Optional message to display below the spinner + size?: "sm" | "md" | "lg"; + text?: string; + className?: string; } -const LoadingSpinner: React.FC = ({ size = 'md', color = '#a872e6', className = '', message }) => { - let spinnerSize = '24px'; - let borderWidth = '4px'; - let messageClass = ''; - - // Adjust spinner size and border based on 'size' prop - switch (size) { - case 'sm': - spinnerSize = '18px'; - borderWidth = '3px'; - messageClass = 'fs-6'; - break; - case 'md': - spinnerSize = '24px'; - borderWidth = '4px'; - messageClass = 'fs-5'; - break; - case 'lg': - spinnerSize = '50px'; - borderWidth = '6px'; - messageClass = 'fs-4'; - break; - } +const LoadingSpinner = ({ size = "md", text, className = "" }: LoadingSpinnerProps) => { + const sizeMap = { + sm: 16, + md: 24, + lg: 32 + }; - const spinnerStyle: React.CSSProperties = { - width: spinnerSize, - height: spinnerSize, - border: `${borderWidth} solid rgba(255, 255, 255, 0.3)`, // Light border - borderTop: `${borderWidth} solid ${color}`, // Colored top border for animation + const spinnerVariants = { + animate: { + rotate: 360, + transition: { + duration: 1, + repeat: Infinity, + ease: "linear" as const + } + } }; return ( -
-
- {message &&

{message}

} +
+ + + + {text && ( + + {text} + + )}
); }; diff --git a/team-bhavitha-dsarecommender/client/src/components/Navbar.tsx b/team-bhavitha-dsarecommender/client/src/components/Navbar.tsx index 08917a6ec..e96cbd9f4 100644 --- a/team-bhavitha-dsarecommender/client/src/components/Navbar.tsx +++ b/team-bhavitha-dsarecommender/client/src/components/Navbar.tsx @@ -1,13 +1,14 @@ import { Link, NavLink, useNavigate, useLocation } from "react-router-dom"; import { useAuthStore } from "../store/authStore"; import { useUserStore } from "../store/userStore"; -import { UserCircle } from "lucide-react"; +import { UserCircle, LogOut, Home, BookOpen, Target, MessageCircle, Upload, BarChart3 } from "lucide-react"; +import { motion } from "framer-motion"; const Navbar = () => { const isAuthenticated = useAuthStore((state) => state.isAuthenticated); const logout = useAuthStore((state) => state.logout); const username = useUserStore((state) => state.username); - const role = useUserStore((state) => state.role); // <-- Get role + const role = useUserStore((state) => state.role); const navigate = useNavigate(); const location = useLocation(); @@ -25,14 +26,44 @@ const Navbar = () => { : `/dashboard/${username}` : "/"; + const navItemVariants = { + hidden: { opacity: 0, y: -10 }, + visible: { + opacity: 1, + y: 0, + transition: { + duration: 0.3, + ease: "easeOut" as const + } + }, + hover: { + y: -2, + transition: { + duration: 0.2, + ease: "easeOut" as const + } + } + }; + return ( - + ); }; diff --git a/team-bhavitha-dsarecommender/client/src/components/QuizCard.tsx b/team-bhavitha-dsarecommender/client/src/components/QuizCard.tsx index ea4293796..91e8be39f 100644 --- a/team-bhavitha-dsarecommender/client/src/components/QuizCard.tsx +++ b/team-bhavitha-dsarecommender/client/src/components/QuizCard.tsx @@ -1,27 +1,118 @@ // client/src/components/QuizCard.tsx -import LoadingSpinner from "./LoadingSpinner"; // Import LoadingSpinner +import LoadingSpinner from "./LoadingSpinner"; +import { motion } from "framer-motion"; +import { Target, Play } from "lucide-react"; interface QuizCardProps { topic: string; onTakeQuiz: (topic: string) => void; - isLoading?: boolean; // Add isLoading prop + isLoading?: boolean; } const QuizCard = ({ topic, onTakeQuiz, isLoading }: QuizCardProps) => { + const cardVariants = { + hidden: { opacity: 0, scale: 0.9, y: 20 }, + visible: { + opacity: 1, + scale: 1, + y: 0, + transition: { + duration: 0.5, + ease: "easeOut" as const + } + }, + hover: { + scale: 1.05, + y: -8, + transition: { + duration: 0.3, + ease: "easeOut" as const + } + } + }; + + const buttonVariants = { + hover: { + scale: 1.05, + transition: { + duration: 0.2, + ease: "easeOut" as const + } + }, + tap: { + scale: 0.95, + transition: { + duration: 0.1, + ease: "easeOut" as const + } + } + }; + return ( -
-
-

{topic}

-

Ready to test your knowledge?

- + { + e.stopPropagation(); + onTakeQuiz(topic); + }} + className="btn btn-primary w-100 d-flex align-items-center justify-content-center" + disabled={isLoading} + whileHover={{ scale: 1.02 }} + whileTap={{ scale: 0.98 }} + > + {isLoading ? ( +
+ + Loading... +
+ ) : ( +
+ + Take Quiz +
+ )} +
+ + + + +
-
+ ); }; diff --git a/team-bhavitha-dsarecommender/client/src/index.css b/team-bhavitha-dsarecommender/client/src/index.css index df6877f6d..10683b3f7 100644 --- a/team-bhavitha-dsarecommender/client/src/index.css +++ b/team-bhavitha-dsarecommender/client/src/index.css @@ -1,6 +1,9 @@ +/* Import Google Fonts */ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap'); + :root { - font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; + font-family: 'Inter', system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.6; font-weight: 400; color-scheme: light dark; @@ -17,4 +20,283 @@ body { margin: 0; min-width: 320px; min-height: 100vh; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; +} + +/* Smooth scrolling */ +html { + scroll-behavior: smooth; +} + +/* Better focus indicators for accessibility */ +*:focus-visible { + outline: 2px solid var(--primary-purple); + outline-offset: 2px; +} + +/* Improved selection colors */ +::selection { + background: var(--primary-purple); + color: white; +} + +/* Custom scrollbar for webkit browsers */ +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: var(--dark-border); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb { + background: var(--gradient-primary); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--primary-purple-dark); +} + +/* Prevent horizontal scroll on mobile */ +html, body { + overflow-x: hidden; +} + +/* Better text rendering */ +* { + text-rendering: optimizeLegibility; + -webkit-font-feature-settings: "kern" 1; + font-feature-settings: "kern" 1; +} + +/* Improved button focus states */ +.btn:focus { + box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.3); +} + +/* Better form control focus states */ +.form-control:focus { + box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1); +} + +/* Improved card hover effects */ +.card { + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +/* Better animation performance */ +* { + will-change: auto; +} + +/* Improved loading states */ +.loading { + position: relative; + overflow: hidden; +} + +.loading::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient( + 90deg, + transparent, + rgba(255, 255, 255, 0.1), + transparent + ); + animation: loading-shimmer 1.5s infinite; +} + +@keyframes loading-shimmer { + 0% { + left: -100%; + } + 100% { + left: 100%; + } +} + +/* Better responsive typography */ +@media (max-width: 768px) { + html { + font-size: 14px; + } +} + +@media (min-width: 1200px) { + html { + font-size: 16px; + } +} + +/* Improved print styles */ +@media print { + * { + background: transparent !important; + color: black !important; + box-shadow: none !important; + text-shadow: none !important; + } + + .no-print { + display: none !important; + } +} + +/* Better mobile touch targets */ +@media (max-width: 768px) { + .btn { + min-height: 44px; + min-width: 44px; + } + + .nav-link { + padding: 12px 16px !important; + } +} + +/* Improved dark mode support */ +@media (prefers-color-scheme: dark) { + :root { + color-scheme: dark; + } +} + +/* Better animation performance for transforms */ +.gpu-accelerated { + transform: translateZ(0); + backface-visibility: hidden; + perspective: 1000px; +} + +/* Improved loading animations */ +.fade-in { + animation: fadeIn 0.6s ease-out; +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Better hover effects */ +.hover-lift { + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.hover-lift:hover { + transform: translateY(-4px); +} + +/* Improved focus management */ +.focus-visible { + outline: 2px solid var(--primary-purple); + outline-offset: 2px; +} + +/* Better accessibility */ +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* Improved form validation styles */ +.form-control.is-valid { + border-color: var(--accent-green); + box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1); +} + +.form-control.is-invalid { + border-color: var(--accent-red); + box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1); +} + +/* Better button states */ +.btn:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +/* Improved modal backdrop */ +.modal-backdrop { + backdrop-filter: blur(10px); +} + +/* Better tooltip positioning */ +.tooltip { + z-index: 1070; +} + +/* Improved dropdown positioning */ +.dropdown-menu { + z-index: 1000; +} + +/* Better responsive images */ +.img-fluid { + max-width: 100%; + height: auto; +} + +/* Improved text truncation */ +.text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* Better responsive utilities */ +@media (max-width: 576px) { + .container { + padding-left: 1rem; + padding-right: 1rem; + } +} + +/* Improved animation performance */ +.animate-on-scroll { + opacity: 0; + transform: translateY(30px); + transition: all 0.6s ease-out; +} + +.animate-on-scroll.animated { + opacity: 1; + transform: translateY(0); +} + +/* Better loading states */ +.skeleton { + background: linear-gradient(90deg, var(--dark-border) 25%, var(--dark-card) 50%, var(--dark-border) 75%); + background-size: 200% 100%; + animation: loading 1.5s infinite; + border-radius: 8px; +} + +@keyframes loading { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } } \ No newline at end of file diff --git a/team-bhavitha-dsarecommender/client/src/pages/DiscussionDetailPage.tsx b/team-bhavitha-dsarecommender/client/src/pages/DiscussionDetailPage.tsx index db0ffbceb..a8b8d0f24 100644 --- a/team-bhavitha-dsarecommender/client/src/pages/DiscussionDetailPage.tsx +++ b/team-bhavitha-dsarecommender/client/src/pages/DiscussionDetailPage.tsx @@ -179,7 +179,7 @@ const DiscussionDetailPage = () => { return (
-
+

{thread.title || "Discussion"}

{userRole === 'educator' && ( @@ -204,7 +204,7 @@ const DiscussionDetailPage = () => {

No comments yet. Be the first to reply!

) : ( thread.comments.map((c) => ( -
+
@@ -241,7 +241,7 @@ const DiscussionDetailPage = () => { {(c.replies?.length ?? 0) > 0 && (
{c.replies!.map((r) => ( -
+
@@ -302,7 +302,7 @@ const DiscussionDetailPage = () => {
{/* Main Comment Input */} -
+
📝 Add a Comment