Changeset ba52069 for src/components
- Timestamp:
- 02/13/26 19:32:02 (7 months ago)
- Branches:
- master
- Children:
- d7deae5
- Parents:
- 50f2fb4
- Location:
- src/components
- Files:
-
- 2 added
- 5 edited
-
LanguageSwitcher.tsx (modified) (2 diffs)
-
exams.tsx (modified) (9 diffs)
-
header.tsx (modified) (3 diffs)
-
navbar.tsx (modified) (4 diffs)
-
professor-navbar.tsx (modified) (4 diffs)
-
theme-provider.tsx (added)
-
theme-toggle.tsx (added)
Legend:
- Unmodified
- Added
- Removed
-
src/components/LanguageSwitcher.tsx
r50f2fb4 rba52069 13 13 <button 14 14 onClick={() => changeLanguage('mk')} 15 className={`px-3 py-1 rounded border-2 text-sm font-semibold transition-all duration-150 ${i18n.language === 'mk' ? 'border- blue-600 text-blue-700 bg-blue-50' : 'border-gray-300 text-gray-700 bg-white hover:border-blue-400 hover:text-blue-600'}`}15 className={`px-3 py-1 rounded border-2 text-sm font-semibold transition-all duration-150 ${i18n.language === 'mk' ? 'border-primary text-primary bg-accent' : 'border-border text-muted-foreground bg-card hover:border-primary hover:text-primary'}`} 16 16 aria-label="Macedonian" 17 17 > … … 20 20 <button 21 21 onClick={() => changeLanguage('en')} 22 className={`px-3 py-1 rounded border-2 text-sm font-semibold transition-all duration-150 ${i18n.language === 'en' ? 'border- blue-600 text-blue-700 bg-blue-50' : 'border-gray-300 text-gray-700 bg-white hover:border-blue-400 hover:text-blue-600'}`}22 className={`px-3 py-1 rounded border-2 text-sm font-semibold transition-all duration-150 ${i18n.language === 'en' ? 'border-primary text-primary bg-accent' : 'border-border text-muted-foreground bg-card hover:border-primary hover:text-primary'}`} 23 23 aria-label="English" 24 24 > -
src/components/exams.tsx
r50f2fb4 rba52069 116 116 117 117 const getGradeColor = (grade: number) => { 118 if (grade >= 9) return "bg-green- 100 text-green-800 border-green-200";119 if (grade >= 8) return "bg-yellow- 100 text-yellow-800 border-yellow-200";120 if (grade >= 6) return "bg-orange- 100 text-orange-800 border-orange-200";121 return "bg-red- 100 text-red-800 border-red-200";118 if (grade >= 9) return "bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/20"; 119 if (grade >= 8) return "bg-yellow-500/10 text-yellow-600 dark:text-yellow-400 border-yellow-500/20"; 120 if (grade >= 6) return "bg-orange-500/10 text-orange-600 dark:text-orange-400 border-orange-500/20"; 121 return "bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/20"; 122 122 }; 123 123 … … 186 186 if (isLoading) { 187 187 return ( 188 <div className="bg- whiterounded-lg shadow-sm p-6">188 <div className="bg-card rounded-lg shadow-sm p-6"> 189 189 {t('loading', 'Loading...')} 190 190 </div> … … 194 194 if (errorMessage) { 195 195 return ( 196 <div className="bg- whiterounded-lg shadow-sm p-6">197 <div className="rounded-lg border border-red- 200 bg-red-50 px-4 py-3 text-sm text-red-700">196 <div className="bg-card rounded-lg shadow-sm p-6"> 197 <div className="rounded-lg border border-red-500/20 bg-red-500/10 px-4 py-3 text-sm text-red-600 dark:text-red-400"> 198 198 {t('failed_to_load_exams', errorMessage)} 199 199 </div> … … 203 203 204 204 return ( 205 <div className="bg- whiterounded-lg shadow-sm p-6 space-y-6">205 <div className="bg-card rounded-lg shadow-sm p-6 space-y-6"> 206 206 {/* Statistics Section */} 207 207 <div className="space-y-4"> … … 209 209 {/* Average Grade */} 210 210 <div className="text-center"> 211 <div className="text-3xl font-bold text- gray-900">{stats.average}</div>212 <div className="text-sm text- gray-500mt-1">{t('average', 'Просек')}</div>211 <div className="text-3xl font-bold text-card-foreground">{stats.average}</div> 212 <div className="text-sm text-muted-foreground mt-1">{t('average', 'Просек')}</div> 213 213 </div> 214 214 215 215 {/* Credits */} 216 216 <div className="text-center"> 217 <div className="text-3xl font-bold text- gray-900">217 <div className="text-3xl font-bold text-card-foreground"> 218 218 {stats.credits.current} 219 <span className="text-lg text- gray-400">/{stats.credits.total}</span>219 <span className="text-lg text-muted-foreground">/{stats.credits.total}</span> 220 220 </div> 221 <div className="text-sm text- gray-500mt-1">{t('credits', 'Кредити')}</div>221 <div className="text-sm text-muted-foreground mt-1">{t('credits', 'Кредити')}</div> 222 222 </div> 223 223 224 224 {/* Passed Exams */} 225 225 <div className="text-center"> 226 <div className="text-3xl font-bold text- gray-900">{stats.passed}</div>227 <div className="text-sm text- gray-500mt-1">{t('passed', 'Положени')}</div>226 <div className="text-3xl font-bold text-card-foreground">{stats.passed}</div> 227 <div className="text-sm text-muted-foreground mt-1">{t('passed', 'Положени')}</div> 228 228 </div> 229 229 230 230 {/* Remaining Exams */} 231 231 <div className="text-center"> 232 <div className="text-3xl font-bold text- gray-900">{stats.remaining}</div>233 <div className="text-sm text- gray-500mt-1">{t('remaining', 'Останато')}</div>232 <div className="text-3xl font-bold text-card-foreground">{stats.remaining}</div> 233 <div className="text-sm text-muted-foreground mt-1">{t('remaining', 'Останато')}</div> 234 234 </div> 235 235 </div> 236 236 237 237 {/* Progress Bar spanning entire statistics section */} 238 <div className="w-full bg- gray-200rounded-full h-2">238 <div className="w-full bg-secondary rounded-full h-2"> 239 239 <div 240 className="bg- blue-500h-2 rounded-full transition-all duration-300"240 className="bg-primary h-2 rounded-full transition-all duration-300" 241 241 style={{ width: `${creditsPercentage}%` }} 242 242 ></div> … … 246 246 {/* Exams Table */} 247 247 <div> 248 <h3 className="text-xl font-semibold text- gray-900mb-4">{t('exams', 'Испити')}</h3>248 <h3 className="text-xl font-semibold text-card-foreground mb-4">{t('exams', 'Испити')}</h3> 249 249 250 250 <div className="overflow-x-auto"> 251 251 <table className="min-w-full"> 252 252 <thead> 253 <tr className="border-b border- gray-200">254 <th className="text-left py-3 px-4 text-sm font-medium text- gray-500">#</th>255 <th className="text-left py-3 px-4 text-sm font-medium text- gray-500">{t('subject', 'Предмет')}</th>256 <th className="text-left py-3 px-4 text-sm font-medium text- gray-500">{t('semester', 'Семестар')}</th>257 <th className="text-left py-3 px-4 text-sm font-medium text- gray-500">{t('credits', 'Кредити')}</th>258 <th className="text-left py-3 px-4 text-sm font-medium text- gray-500">253 <tr className="border-b border-border"> 254 <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">#</th> 255 <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">{t('subject', 'Предмет')}</th> 256 <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">{t('semester', 'Семестар')}</th> 257 <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground">{t('credits', 'Кредити')}</th> 258 <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground"> 259 259 <button 260 260 onClick={handleSortByDate} 261 className="flex items-center gap-2 px-2 py-1 rounded-md hover:bg- gray-100 hover:text-gray-900transition-all duration-200 transform hover:scale-105"261 className="flex items-center gap-2 px-2 py-1 rounded-md hover:bg-accent hover:text-accent-foreground transition-all duration-200 transform hover:scale-105" 262 262 > 263 263 {t('date', 'Датум')} … … 265 265 icon={getSortIcon('date')} 266 266 className={`text-xs transition-colors duration-200 ${ 267 sortField === 'date' ? 'text- blue-600' : 'text-gray-400 group-hover:text-gray-600'267 sortField === 'date' ? 'text-primary' : 'text-muted-foreground group-hover:text-foreground' 268 268 }`} 269 269 /> 270 270 </button> 271 271 </th> 272 <th className="text-left py-3 px-4 text-sm font-medium text- gray-500">272 <th className="text-left py-3 px-4 text-sm font-medium text-muted-foreground"> 273 273 <button 274 274 onClick={handleSortByGrade} 275 className="flex items-center gap-2 px-2 py-1 rounded-md hover:bg- gray-100 hover:text-gray-900transition-all duration-200 transform hover:scale-105"275 className="flex items-center gap-2 px-2 py-1 rounded-md hover:bg-accent hover:text-accent-foreground transition-all duration-200 transform hover:scale-105" 276 276 > 277 277 {t('grade', 'Оценка')} … … 279 279 icon={getSortIcon('grade')} 280 280 className={`text-xs transition-colors duration-200 ${ 281 sortField === 'grade' ? 'text- blue-600' : 'text-gray-400 group-hover:text-gray-600'281 sortField === 'grade' ? 'text-primary' : 'text-muted-foreground group-hover:text-foreground' 282 282 }`} 283 283 /> … … 286 286 </tr> 287 287 </thead> 288 <tbody className="divide-y divide- gray-100">288 <tbody className="divide-y divide-border"> 289 289 {getSortedExams().map((exam) => ( 290 <tr key={exam.id} className="hover:bg- gray-50 transition-colors duration-150">291 <td className="py-4 px-4 text-sm text- gray-900">{exam.id}</td>292 <td className="py-4 px-4 text-sm text- gray-900font-medium">{exam.subject}</td>293 <td className="py-4 px-4 text-sm text- gray-500">{exam.semester}</td>294 <td className="py-4 px-4 text-sm text- gray-500">{exam.credits}</td>295 <td className="py-4 px-4 text-sm text- gray-500">{exam.date}</td>290 <tr key={exam.id} className="hover:bg-accent/50 transition-colors duration-150"> 291 <td className="py-4 px-4 text-sm text-card-foreground">{exam.id}</td> 292 <td className="py-4 px-4 text-sm text-card-foreground font-medium">{exam.subject}</td> 293 <td className="py-4 px-4 text-sm text-muted-foreground">{exam.semester}</td> 294 <td className="py-4 px-4 text-sm text-muted-foreground">{exam.credits}</td> 295 <td className="py-4 px-4 text-sm text-muted-foreground">{exam.date}</td> 296 296 <td className="py-4 px-4"> 297 297 <span className={`inline-flex items-center px-2.5 py-1 rounded-md text-sm font-medium border ${getGradeColor(exam.grade)}`}> -
src/components/header.tsx
r50f2fb4 rba52069 45 45 46 46 return ( 47 <header className="bg- white shadow-sm border-b border-gray-200">47 <header className="bg-card shadow-sm border-b border-border"> 48 48 <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> 49 49 <div className="flex flex-col sm:flex-row sm:justify-between sm:items-center py-4 gap-4 sm:gap-0"> … … 72 72 {/* University Text */} 73 73 <div className="hidden sm:block"> 74 <div className="text- gray-900font-medium text-sm">74 <div className="text-card-foreground font-medium text-sm"> 75 75 {t('university')} 76 76 </div> 77 <div className="text- gray-700text-sm">77 <div className="text-muted-foreground text-sm"> 78 78 {t('faculty')} 79 79 </div> … … 88 88 <div className="flex items-center gap-2 sm:gap-3 w-full sm:w-auto justify-center sm:justify-end"> 89 89 {/* User Avatar */} 90 <div className="hidden sm:flex items-center justify-center w-10 h-10 bg- gray-800 text-whiterounded-full">90 <div className="hidden sm:flex items-center justify-center w-10 h-10 bg-primary text-primary-foreground rounded-full"> 91 91 <FontAwesomeIcon icon={faUser} className="text-sm" /> 92 92 </div> 93 93 {/* User Name */} 94 <div className="hidden sm:block text- gray-900font-medium">94 <div className="hidden sm:block text-card-foreground font-medium"> 95 95 {userName || '...'} 96 96 </div> 97 97 {/* Logout Button - more stylish and full width on mobile */} 98 98 <button 99 className="w-full sm:w-auto ml-0 sm:ml-2 px-4 py-2 border-2 border-primary text-primary bg- white rounded-lg font-semibold flex items-center justify-center gap-2 hover:bg-blue-50transition-all duration-200 shadow-sm"99 className="w-full sm:w-auto ml-0 sm:ml-2 px-4 py-2 border-2 border-primary text-primary bg-card rounded-lg font-semibold flex items-center justify-center gap-2 hover:bg-accent transition-all duration-200 shadow-sm" 100 100 onClick={handleLogout} 101 101 > -
src/components/navbar.tsx
r50f2fb4 rba52069 32 32 <> 33 33 {/* Desktop Navbar */} 34 <nav className="hidden md:flex flex-row gap-2 justify-evenly bg-primary text- whitep-7 rounded-xl my-5 text-xl">34 <nav className="hidden md:flex flex-row gap-2 justify-evenly bg-primary text-primary-foreground p-7 rounded-xl my-5 text-xl"> 35 35 {menuItems.map((item, index) => ( 36 36 <Link key={index} href={item.href}> 37 <div className="group flex flex-row items-center gap-2 px-3 py-2 rounded-lg cursor-pointer transition-all duration-300 hover:bg- white hover:bg-opacity-20 hover:scale-105 hover:shadow-lg hover:text-primary">37 <div className="group flex flex-row items-center gap-2 px-3 py-2 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground hover:scale-105 hover:shadow-lg"> 38 38 <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" /> 39 39 <span>{item.label}</span> … … 44 44 45 45 {/* Mobile Navbar */} 46 <nav className="md:hidden bg-primary text- whiterounded-xl my-5">46 <nav className="md:hidden bg-primary text-primary-foreground rounded-xl my-5"> 47 47 <div className="flex justify-between items-center p-4"> 48 48 {/* IKnow Logo/Text */} … … 55 55 <button 56 56 onClick={toggleMenu} 57 className="p-2 rounded-lg hover:bg- white hover:bg-opacity-20transition-colors duration-300"57 className="p-2 rounded-lg hover:bg-card hover:text-card-foreground transition-colors duration-300" 58 58 > 59 59 <FontAwesomeIcon … … 71 71 {menuItems.map((item, index) => ( 72 72 <Link key={index} href={item.href}> 73 <div className="group flex flex-row items-center gap-3 px-3 py-3 rounded-lg cursor-pointer transition-all duration-300 hover:bg- white hover:bg-opacity-20 hover:text-primary">73 <div className="group flex flex-row items-center gap-3 px-3 py-3 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground"> 74 74 <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" /> 75 75 <span className="text-lg">{item.label}</span> -
src/components/professor-navbar.tsx
r50f2fb4 rba52069 23 23 <> 24 24 {/* Desktop Navbar */} 25 <nav className="hidden md:flex flex-row gap-2 justify-evenly bg-primary text- whitep-7 rounded-xl my-5 text-xl">25 <nav className="hidden md:flex flex-row gap-2 justify-evenly bg-primary text-primary-foreground p-7 rounded-xl my-5 text-xl"> 26 26 {menuItems.map((item) => ( 27 27 <Link key={item.href} href={item.href}> 28 <div className="group flex flex-row items-center gap-2 px-3 py-2 rounded-lg cursor-pointer transition-all duration-300 hover:bg- white hover:bg-opacity-20 hover:scale-105 hover:shadow-lg hover:text-primary">28 <div className="group flex flex-row items-center gap-2 px-3 py-2 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground hover:scale-105 hover:shadow-lg"> 29 29 <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" /> 30 30 <span>{item.label}</span> … … 35 35 36 36 {/* Mobile Navbar */} 37 <nav className="md:hidden bg-primary text- whiterounded-xl my-5">37 <nav className="md:hidden bg-primary text-primary-foreground rounded-xl my-5"> 38 38 <div className="flex justify-between items-center p-4"> 39 39 <div className="flex items-center gap-2 text-xl font-bold"> … … 44 44 <button 45 45 onClick={toggleMenu} 46 className="p-2 rounded-lg hover:bg- white hover:bg-opacity-20transition-colors duration-300"46 className="p-2 rounded-lg hover:bg-card hover:text-card-foreground transition-colors duration-300" 47 47 aria-label="Toggle menu" 48 48 > … … 62 62 {menuItems.map((item) => ( 63 63 <Link key={item.href} href={item.href}> 64 <div className="group flex flex-row items-center gap-3 px-3 py-3 rounded-lg cursor-pointer transition-all duration-300 hover:bg- white hover:bg-opacity-20 hover:text-primary">64 <div className="group flex flex-row items-center gap-3 px-3 py-3 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground"> 65 65 <FontAwesomeIcon 66 66 icon={item.icon}
Note:
See TracChangeset
for help on using the changeset viewer.
