diff --git a/package-lock.json b/package-lock.json index 00f169e..f9cac62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15434,22 +15434,6 @@ } } }, - "node_modules/tailwindcss/node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", - "extraneous": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", @@ -15938,9 +15922,9 @@ } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "license": "Apache-2.0", "peer": true, "bin": { @@ -15948,7 +15932,7 @@ "tsserver": "bin/tsserver" }, "engines": { - "node": ">=14.17" + "node": ">=4.2.0" } }, "node_modules/unbox-primitive": { diff --git a/src/App.css b/src/App.css index 50cda4c..4edbcd6 100644 --- a/src/App.css +++ b/src/App.css @@ -1,13 +1,960 @@ +/* ============================ + CSS Variables / Theming + ============================ */ +:root { + --primary: #4f46e5; + --primary-dark: #3730a3; + --primary-light: #e0e7ff; + --accent: #ec4899; + --accent-dark: #db2777; + --success: #10b981; + --danger: #ef4444; + --danger-dark: #dc2626; + --warning: #f59e0b; + + --bg: #f1f5f9; + --card-bg: #ffffff; + --header-bg: linear-gradient(135deg, #1e1b4b 0%, #312e81 50%, #4338ca 100%); + --nav-bg: #312e81; + --nav-hover: rgba(255,255,255,0.1); + + --text: #0f172a; + --text-muted: #64748b; + --text-light: #94a3b8; + --border: #e2e8f0; + --border-focus: #a5b4fc; + + --shadow-sm: 0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.06); + --shadow-md: 0 4px 6px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.06); + --shadow-lg: 0 10px 25px rgba(0,0,0,0.1), 0 5px 10px rgba(0,0,0,0.06); + --shadow-xl: 0 20px 60px rgba(0,0,0,0.15); + + --radius-sm: 6px; + --radius-md: 10px; + --radius-lg: 16px; + --radius-xl: 24px; + --radius-full: 9999px; + + --transition: 0.2s ease; +} + +/* ============================ + App Layout + ============================ */ .App { min-height: 100vh; display: flex; flex-direction: column; + background: var(--bg); } .main-content { flex: 1; - padding: 20px; + padding: 24px 20px; max-width: 1200px; margin: 0 auto; width: 100%; } + +/* ============================ + Shared Buttons + ============================ */ +.btn-primary { + background: var(--primary); + color: white; + border: none; + padding: 10px 22px; + border-radius: var(--radius-md); + cursor: pointer; + font-size: 15px; + font-weight: 600; + transition: background var(--transition), transform var(--transition), box-shadow var(--transition); + display: inline-flex; + align-items: center; + gap: 6px; +} +.btn-primary:hover:not(:disabled) { + background: var(--primary-dark); + transform: translateY(-1px); + box-shadow: var(--shadow-md); +} +.btn-primary:disabled, .btn-disabled { + background: var(--text-light); + cursor: not-allowed; + color: white; + border: none; + padding: 10px 22px; + border-radius: var(--radius-md); + font-size: 15px; + font-weight: 600; + display: inline-flex; + align-items: center; + gap: 6px; +} +.btn-full { width: 100%; justify-content: center; } + +.btn-outline { + background: transparent; + color: var(--primary); + border: 2px solid var(--primary); + padding: 9px 20px; + border-radius: var(--radius-md); + cursor: pointer; + font-size: 15px; + font-weight: 600; + transition: all var(--transition); +} +.btn-outline:hover { + background: var(--primary-light); +} + +.btn-danger { + background: var(--danger); + color: white; + border: none; + padding: 9px 18px; + border-radius: var(--radius-md); + cursor: pointer; + font-size: 14px; + font-weight: 600; + transition: background var(--transition); +} +.btn-danger:hover { background: var(--danger-dark); } + +.btn-sm { + padding: 6px 12px; + font-size: 13px; +} + +.btn-back { + background: transparent; + border: none; + color: var(--primary); + font-size: 15px; + font-weight: 600; + cursor: pointer; + padding: 6px 0; + display: inline-flex; + align-items: center; + gap: 4px; + transition: color var(--transition); +} +.btn-back:hover { color: var(--primary-dark); } + +.btn-text-link { + background: none; + border: none; + color: var(--text-muted); + font-size: 14px; + cursor: pointer; + text-decoration: underline; + padding: 0; + margin-top: 8px; + transition: color var(--transition); +} +.btn-text-link:hover { color: var(--primary); } + +.btn-next { + margin-top: 20px; + padding: 12px 28px; + border-radius: var(--radius-md); + font-size: 16px; + font-weight: 600; +} + +/* ============================ + Header + ============================ */ +.site-header { + background: var(--header-bg); + color: white; + padding: 14px 24px; + display: flex; + justify-content: space-between; + align-items: center; + gap: 12px; + position: sticky; + top: 0; + z-index: 100; + box-shadow: 0 2px 12px rgba(0,0,0,0.2); +} + +.header-brand { + display: flex; + align-items: center; + gap: 12px; + cursor: pointer; + text-decoration: none; + flex-shrink: 0; +} +.header-flag { font-size: 28px; } +.header-title-group { display: flex; flex-direction: column; } +.header-title { font-size: 22px; font-weight: 700; letter-spacing: -0.5px; } +.header-subtitle { font-size: 12px; opacity: 0.75; } + +.header-actions { + display: flex; + align-items: center; + gap: 10px; +} + +.btn-find-tutor { + background: var(--accent); + color: white; + border: none; + padding: 8px 16px; + border-radius: var(--radius-full); + cursor: pointer; + font-size: 13px; + font-weight: 600; + transition: background var(--transition), transform var(--transition); + white-space: nowrap; +} +.btn-find-tutor:hover { background: var(--accent-dark); transform: translateY(-1px); } + +.btn-login { + background: rgba(255,255,255,0.15); + color: white; + border: 1.5px solid rgba(255,255,255,0.4); + padding: 8px 16px; + border-radius: var(--radius-full); + cursor: pointer; + font-size: 13px; + font-weight: 600; + transition: background var(--transition); +} +.btn-login:hover { background: rgba(255,255,255,0.25); } + +/* User dropdown */ +.user-menu-wrapper { position: relative; } +.user-avatar-btn { + background: rgba(255,255,255,0.15); + color: white; + border: 1.5px solid rgba(255,255,255,0.35); + padding: 7px 14px; + border-radius: var(--radius-full); + cursor: pointer; + font-size: 14px; + display: flex; + align-items: center; + gap: 7px; + transition: background var(--transition); +} +.user-avatar-btn:hover { background: rgba(255,255,255,0.25); } +.user-avatar-icon { font-size: 16px; } +.user-name-short { font-weight: 600; max-width: 80px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.chevron { font-size: 10px; opacity: 0.8; } + +.user-dropdown { + position: absolute; + right: 0; + top: calc(100% + 8px); + background: white; + border-radius: var(--radius-lg); + box-shadow: var(--shadow-xl); + min-width: 200px; + z-index: 200; + overflow: hidden; + animation: dropIn 0.15s ease; +} +@keyframes dropIn { + from { opacity: 0; transform: translateY(-6px); } + to { opacity: 1; transform: translateY(0); } +} +.user-dropdown-info { + padding: 14px 16px; + border-bottom: 1px solid var(--border); + display: flex; + flex-direction: column; + gap: 2px; +} +.user-dropdown-info strong { color: var(--text); font-size: 14px; } +.user-dropdown-info small { color: var(--text-muted); font-size: 12px; } +.badge-admin { + background: var(--primary); + color: white; + font-size: 10px; + padding: 2px 8px; + border-radius: var(--radius-full); + font-weight: 700; + width: fit-content; + margin-top: 4px; +} +.dropdown-item { + width: 100%; + text-align: left; + background: none; + border: none; + padding: 11px 16px; + font-size: 14px; + color: var(--text); + cursor: pointer; + transition: background var(--transition); + display: flex; + align-items: center; + gap: 8px; +} +.dropdown-item:hover { background: var(--bg); } +.dropdown-item-danger { color: var(--danger); } +.dropdown-item-danger:hover { background: #fef2f2; } + +/* ============================ + Navigation + ============================ */ +.site-nav { + background: var(--nav-bg); + position: relative; +} +.nav-items { + display: flex; + flex-wrap: wrap; +} +.nav-item { + background: transparent; + color: rgba(255,255,255,0.8); + border: none; + padding: 13px 18px; + cursor: pointer; + font-size: 14px; + font-weight: 500; + border-bottom: 3px solid transparent; + transition: all var(--transition); + white-space: nowrap; +} +.nav-item:hover { background: var(--nav-hover); color: white; } +.nav-item-active { + color: white !important; + border-bottom-color: var(--accent) !important; + background: rgba(255,255,255,0.07) !important; + font-weight: 700; +} +.nav-hamburger { + display: none; + background: none; + border: none; + color: white; + font-size: 22px; + padding: 12px 18px; + cursor: pointer; + width: 100%; + text-align: left; +} + +/* ============================ + Shared Form Elements + ============================ */ +.form-group { + display: flex; + flex-direction: column; + gap: 6px; + margin-bottom: 16px; +} +.form-group label { + font-size: 14px; + font-weight: 600; + color: var(--text); +} +.form-input { + border: 1.5px solid var(--border); + border-radius: var(--radius-md); + padding: 10px 14px; + font-size: 15px; + color: var(--text); + background: white; + transition: border-color var(--transition), box-shadow var(--transition); + width: 100%; + font-family: inherit; + resize: vertical; +} +.form-input:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 3px var(--primary-light); +} +.form-error { + background: #fef2f2; + color: var(--danger); + border: 1px solid #fecaca; + border-radius: var(--radius-md); + padding: 10px 14px; + font-size: 14px; + margin-bottom: 12px; +} +.hint-text { font-size: 12px; color: var(--text-muted); margin-top: 4px; } +.section-title { font-size: 18px; font-weight: 700; color: var(--text); margin: 24px 0 12px; } + +.form-actions { + display: flex; + gap: 12px; + justify-content: flex-end; + margin-top: 24px; + padding-top: 16px; + border-top: 1px solid var(--border); +} + +/* ============================ + Login Page + ============================ */ +.login-page { + min-height: 70vh; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; +} +.login-card { + background: white; + border-radius: var(--radius-xl); + box-shadow: var(--shadow-xl); + padding: 40px 36px; + width: 100%; + max-width: 420px; +} +.login-logo { + text-align: center; + margin-bottom: 28px; +} +.logo-flag { font-size: 48px; display: block; margin-bottom: 8px; } +.login-logo h1 { font-size: 28px; font-weight: 800; color: var(--primary); } +.login-logo p { color: var(--text-muted); font-size: 14px; margin-top: 4px; } + +.login-tabs { + display: flex; + border: 1.5px solid var(--border); + border-radius: var(--radius-md); + overflow: hidden; + margin-bottom: 24px; +} +.login-tab { + flex: 1; + padding: 10px; + background: none; + border: none; + cursor: pointer; + font-size: 14px; + font-weight: 600; + color: var(--text-muted); + transition: all var(--transition); +} +.login-tab.active { + background: var(--primary); + color: white; +} +.login-form { margin-bottom: 20px; } + +.login-divider { + text-align: center; + position: relative; + margin: 20px 0; + color: var(--text-muted); + font-size: 13px; +} +.login-divider::before, .login-divider::after { + content: ''; + position: absolute; + top: 50%; + width: calc(50% - 20px); + height: 1px; + background: var(--border); +} +.login-divider::before { left: 0; } +.login-divider::after { right: 0; } + +.btn-google { + width: 100%; + padding: 11px 16px; + border: 1.5px solid var(--border); + border-radius: var(--radius-md); + background: white; + cursor: pointer; + font-size: 15px; + font-weight: 600; + color: var(--text); + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + transition: background var(--transition), border-color var(--transition), box-shadow var(--transition); +} +.btn-google:hover { + background: #f8fafc; + border-color: #9ca3af; + box-shadow: var(--shadow-sm); +} +.google-icon { width: 20px; height: 20px; flex-shrink: 0; } + +.login-hint { + font-size: 12px; + color: var(--text-muted); + text-align: center; + margin-top: 16px; + padding: 10px; + background: var(--bg); + border-radius: var(--radius-md); +} + +/* ============================ + Modal + ============================ */ +.modal-overlay { + position: fixed; + inset: 0; + background: rgba(15,23,42,0.55); + backdrop-filter: blur(3px); + display: flex; + align-items: center; + justify-content: center; + z-index: 500; + padding: 20px; + animation: fadeIn 0.15s ease; +} +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} +.modal-card { + background: white; + border-radius: var(--radius-xl); + padding: 32px 28px; + max-width: 400px; + width: 100%; + box-shadow: var(--shadow-xl); + animation: slideUp 0.2s ease; +} +@keyframes slideUp { + from { transform: translateY(20px); opacity: 0; } + to { transform: translateY(0); opacity: 1; } +} +.modal-header { + text-align: center; + margin-bottom: 24px; +} +.google-logo { + width: 48px; + height: 48px; + background: var(--primary); + color: white; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 24px; + font-weight: 800; + margin: 0 auto 12px; +} +.modal-header h2 { font-size: 20px; font-weight: 700; color: var(--text); margin-bottom: 4px; } +.modal-header p { font-size: 14px; color: var(--text-muted); } +.modal-form { margin-top: 20px; } +.modal-actions { + display: flex; + gap: 10px; + margin-top: 20px; +} +.btn-google-confirm { + flex: 1; + background: var(--primary); + color: white; + border: none; + padding: 10px; + border-radius: var(--radius-md); + cursor: pointer; + font-size: 15px; + font-weight: 600; + transition: background var(--transition); +} +.btn-google-confirm:hover { background: var(--primary-dark); } + +/* ============================ + Admin Panel + ============================ */ +.admin-denied { + text-align: center; + padding: 80px 20px; +} +.admin-denied-icon { font-size: 60px; margin-bottom: 16px; } +.admin-denied h2 { font-size: 28px; font-weight: 700; margin-bottom: 8px; } +.admin-denied p { color: var(--text-muted); } + +.admin-panel { max-width: 900px; margin: 0 auto; } +.admin-panel-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 28px; + gap: 16px; + flex-wrap: wrap; +} +.admin-panel-header h2 { font-size: 26px; font-weight: 800; color: var(--text); margin-bottom: 4px; } +.admin-subtitle { color: var(--text-muted); font-size: 14px; } + +.empty-state { + text-align: center; + padding: 60px 20px; + background: white; + border-radius: var(--radius-xl); + box-shadow: var(--shadow-sm); +} +.empty-icon { font-size: 56px; margin-bottom: 16px; } +.empty-state h3 { font-size: 22px; font-weight: 700; margin-bottom: 8px; } +.empty-state p { color: var(--text-muted); } + +.tests-list { display: flex; flex-direction: column; gap: 14px; } +.test-card-admin { + background: white; + border-radius: var(--radius-lg); + padding: 20px 24px; + box-shadow: var(--shadow-sm); + display: flex; + justify-content: space-between; + align-items: center; + gap: 16px; + flex-wrap: wrap; + border: 1.5px solid var(--border); + transition: box-shadow var(--transition), border-color var(--transition); +} +.test-card-admin:hover { box-shadow: var(--shadow-md); border-color: var(--border-focus); } +.test-card-admin-info h3 { font-size: 18px; font-weight: 700; margin-bottom: 4px; } +.test-card-admin-info p { color: var(--text-muted); font-size: 14px; margin-bottom: 6px; } +.test-meta { font-size: 12px; color: var(--primary); font-weight: 600; background: var(--primary-light); padding: 2px 10px; border-radius: var(--radius-full); } +.test-card-admin-actions { display: flex; gap: 8px; flex-shrink: 0; } + +/* Test Form */ +.test-form { background: white; border-radius: var(--radius-xl); padding: 28px; box-shadow: var(--shadow-sm); } + +.question-editor { + background: var(--bg); + border-radius: var(--radius-lg); + padding: 20px; + margin-bottom: 16px; + border: 1.5px solid var(--border); +} +.question-editor-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 16px; +} +.question-editor-header h4 { font-size: 16px; font-weight: 700; color: var(--primary); } +.btn-icon-danger { + background: #fef2f2; + color: var(--danger); + border: 1.5px solid #fecaca; + border-radius: var(--radius-full); + width: 28px; + height: 28px; + cursor: pointer; + font-size: 13px; + display: flex; + align-items: center; + justify-content: center; + transition: background var(--transition); +} +.btn-icon-danger:hover { background: #fee2e2; } + +.options-grid { display: flex; flex-direction: column; gap: 10px; margin-bottom: 8px; } +.option-row { + display: flex; + align-items: center; + gap: 10px; +} +.option-row input[type="radio"] { + width: 18px; + height: 18px; + accent-color: var(--primary); + flex-shrink: 0; + cursor: pointer; +} + +.media-upload-row { + display: flex; + gap: 16px; + flex-wrap: wrap; + margin-top: 14px; +} +.media-upload-item { display: flex; flex-direction: column; gap: 8px; flex: 1; min-width: 200px; } +.media-upload-label { font-size: 13px; font-weight: 600; color: var(--text-muted); } +.btn-upload { + background: white; + border: 1.5px dashed var(--border); + border-radius: var(--radius-md); + padding: 8px 14px; + cursor: pointer; + font-size: 13px; + color: var(--primary); + font-weight: 600; + transition: border-color var(--transition), background var(--transition); +} +.btn-upload:hover { border-color: var(--primary); background: var(--primary-light); } + +.media-preview { position: relative; display: inline-block; } +.image-preview { max-width: 120px; max-height: 80px; border-radius: var(--radius-md); object-fit: cover; border: 1.5px solid var(--border); } +.audio-preview { max-width: 200px; height: 36px; } +.btn-remove-media { + position: absolute; + top: -6px; + right: -6px; + background: var(--danger); + color: white; + border: none; + border-radius: 50%; + width: 20px; + height: 20px; + cursor: pointer; + font-size: 11px; + display: flex; + align-items: center; + justify-content: center; + line-height: 1; +} + +.btn-add-question { + width: 100%; + padding: 12px; + border: 2px dashed var(--primary); + border-radius: var(--radius-lg); + background: var(--primary-light); + color: var(--primary); + font-size: 15px; + font-weight: 700; + cursor: pointer; + transition: background var(--transition); + margin-bottom: 8px; +} +.btn-add-question:hover { background: #c7d2fe; } + +/* ============================ + Skill Test Page + ============================ */ +.skill-test-page { max-width: 900px; margin: 0 auto; } +.page-subtitle { color: var(--text-muted); margin-bottom: 28px; font-size: 16px; } +.test-selection-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: 18px; +} +.test-selection-card { + background: white; + border-radius: var(--radius-xl); + padding: 28px 24px; + box-shadow: var(--shadow-sm); + text-align: center; + cursor: pointer; + border: 2px solid var(--border); + transition: all var(--transition); + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; +} +.test-selection-card:hover { + border-color: var(--primary); + box-shadow: var(--shadow-lg); + transform: translateY(-3px); +} +.test-selection-icon { font-size: 42px; } +.test-selection-card h3 { font-size: 18px; font-weight: 700; color: var(--text); } +.test-selection-card p { font-size: 14px; color: var(--text-muted); } +.test-question-count { font-size: 12px; background: var(--primary-light); color: var(--primary); font-weight: 700; padding: 3px 12px; border-radius: var(--radius-full); } +.btn-start-test { margin-top: 8px; } + +/* Test Runner */ +.test-runner { max-width: 700px; margin: 0 auto; } +.test-runner-header { + display: flex; + align-items: center; + gap: 16px; + margin-bottom: 16px; + flex-wrap: wrap; +} +.test-runner-header h2 { flex: 1; font-size: 22px; font-weight: 700; } +.question-counter { font-size: 13px; font-weight: 700; color: var(--text-muted); background: var(--bg); padding: 4px 12px; border-radius: var(--radius-full); } + +.progress-bar-wrapper { + height: 6px; + background: var(--border); + border-radius: var(--radius-full); + margin-bottom: 24px; + overflow: hidden; +} +.progress-bar-fill { + height: 100%; + background: linear-gradient(90deg, var(--primary), var(--accent)); + border-radius: var(--radius-full); + transition: width 0.4s ease; +} + +.question-card { + background: white; + border-radius: var(--radius-xl); + padding: 28px; + box-shadow: var(--shadow-md); +} +.question-image-wrapper { margin-bottom: 16px; } +.question-image { max-width: 100%; max-height: 200px; border-radius: var(--radius-lg); object-fit: contain; } +.question-audio-wrapper { margin-bottom: 16px; } +.question-audio { width: 100%; } +.question-text { font-size: 20px; font-weight: 700; color: var(--text); margin-bottom: 20px; line-height: 1.4; } + +.options-list { display: flex; flex-direction: column; gap: 10px; } +.option-btn { + background: var(--bg); + color: var(--text); + border: 2px solid var(--border); + padding: 13px 16px; + border-radius: var(--radius-md); + cursor: pointer; + text-align: left; + font-size: 15px; + display: flex; + align-items: center; + gap: 12px; + transition: all var(--transition); + font-family: inherit; + font-weight: 500; +} +.option-btn:hover { border-color: var(--primary); background: var(--primary-light); } +.option-btn-selected { + background: var(--primary) !important; + color: white !important; + border-color: var(--primary) !important; +} +.option-letter { + width: 28px; + height: 28px; + background: white; + color: var(--primary); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 13px; + font-weight: 800; + flex-shrink: 0; + transition: all var(--transition); +} +.option-btn-selected .option-letter { background: rgba(255,255,255,0.3); color: white; } + +/* Test Finished */ +.test-finished { + text-align: center; + max-width: 480px; + margin: 0 auto; + padding: 40px 20px; +} +.test-finished-icon { font-size: 72px; margin-bottom: 16px; } +.test-finished h2 { font-size: 30px; font-weight: 800; margin-bottom: 20px; } +.score-display { display: flex; align-items: baseline; justify-content: center; gap: 8px; margin-bottom: 8px; } +.score-number { font-size: 64px; font-weight: 900; color: var(--primary); line-height: 1; } +.score-divider { font-size: 36px; color: var(--text-muted); } +.score-total { font-size: 36px; color: var(--text-muted); font-weight: 700; } +.score-percent { font-size: 16px; color: var(--text-muted); margin-bottom: 8px; } +.score-message { font-size: 18px; font-weight: 700; color: var(--text); margin-bottom: 28px; } +.test-finished-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } + +/* ============================ + Home Page + ============================ */ +.home-hero { + text-align: center; + padding: 60px 20px 40px; +} +.home-hero h1 { font-size: 42px; font-weight: 900; color: var(--text); margin-bottom: 12px; } +.home-hero p { font-size: 18px; color: var(--text-muted); margin-bottom: 48px; } +.home-cards { display: flex; justify-content: center; gap: 20px; flex-wrap: wrap; } +.home-card { + background: white; + border-radius: var(--radius-xl); + padding: 28px 24px; + width: 200px; + box-shadow: var(--shadow-sm); + cursor: pointer; + text-align: center; + border: 2px solid var(--border); + transition: all var(--transition); +} +.home-card:hover { + border-color: var(--primary); + box-shadow: var(--shadow-lg); + transform: translateY(-4px); +} +.home-card-icon { font-size: 44px; margin-bottom: 14px; } +.home-card h3 { font-size: 17px; font-weight: 700; margin-bottom: 8px; } +.home-card p { color: var(--text-muted); font-size: 13px; } + +/* ============================ + Resources Page + ============================ */ +.resources-container { max-width: 900px; margin: 0 auto; } +.resource-section { margin-bottom: 32px; } +.resource-section h2 { font-size: 20px; font-weight: 700; margin-bottom: 14px; color: var(--text); } +.resource-items { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; } +.resource-item { background: white; border-radius: var(--radius-lg); padding: 18px; box-shadow: var(--shadow-sm); border: 1.5px solid var(--border); transition: box-shadow var(--transition), border-color var(--transition); } +.resource-item:hover { box-shadow: var(--shadow-md); border-color: var(--border-focus); } +.resource-item h3 { font-size: 15px; font-weight: 700; margin-bottom: 6px; } +.resource-item p { color: var(--text-muted); font-size: 13px; line-height: 1.5; } + +/* ============================ + Page Title Shared + ============================ */ +h1 { font-size: 28px; font-weight: 800; margin-bottom: 6px; color: var(--text); } + +/* ============================ + Responsive + ============================ */ +@media (max-width: 768px) { + .main-content { padding: 16px 14px; } + + /* Header */ + .site-header { padding: 12px 14px; } + .header-subtitle { display: none; } + .btn-find-tutor { display: none; } + .header-title { font-size: 18px; } + .header-flag { font-size: 22px; } + .btn-login { font-size: 12px; padding: 7px 12px; } + .user-name-short { display: none; } + + /* Nav */ + .nav-hamburger { display: block; } + .nav-items { + display: none; + flex-direction: column; + width: 100%; + border-top: 1px solid rgba(255,255,255,0.1); + } + .nav-items-open { display: flex; } + .nav-item { padding: 14px 18px; width: 100%; border-bottom: none; border-left: 3px solid transparent; } + .nav-item-active { border-left-color: var(--accent) !important; border-bottom: none !important; } + + /* Login */ + .login-card { padding: 28px 20px; } + + /* Admin */ + .test-card-admin { flex-direction: column; align-items: flex-start; } + .test-card-admin-actions { width: 100%; } + .test-card-admin-actions .btn-outline, + .test-card-admin-actions .btn-danger { flex: 1; text-align: center; justify-content: center; } + + /* Test finished */ + .score-number { font-size: 48px; } + .score-divider, .score-total { font-size: 28px; } + + /* Home */ + .home-hero h1 { font-size: 28px; } + .home-hero p { font-size: 16px; } + .home-card { width: 150px; padding: 20px 16px; } + .home-card-icon { font-size: 36px; } + + /* Question card */ + .question-card { padding: 20px; } + .question-text { font-size: 17px; } +} + +@media (max-width: 480px) { + .home-cards { gap: 12px; } + .home-card { width: 140px; } + .modal-card { padding: 24px 18px; } + .form-actions { flex-direction: column-reverse; } + .form-actions .btn-outline, .form-actions .btn-primary { width: 100%; text-align: center; justify-content: center; } + .media-upload-row { flex-direction: column; } +} + diff --git a/src/App.js b/src/App.js index 3adbaae..894c868 100644 --- a/src/App.js +++ b/src/App.js @@ -1,5 +1,6 @@ import React, { useState } from 'react'; import './App.css'; +import { AuthProvider } from './context/AuthContext'; import Header from './components/Header'; import Navigation from './components/Navigation'; import Home from './pages/Home'; @@ -8,8 +9,10 @@ import Advanced from './pages/Advanced'; import SkillTest from './pages/SkillTest'; import FindTutor from './pages/FindTutor'; import Resources from './pages/Resources'; +import Login from './pages/Login'; +import AdminPanel from './pages/AdminPanel'; -function App() { +function AppContent() { const [currentPage, setCurrentPage] = useState('home'); const renderPage = () => { @@ -26,15 +29,30 @@ function App() { return ; case 'resources': return ; + case 'admin': + return ; + case 'login': + return setCurrentPage('home')} />; default: return ; } }; + function handleLoginClick() { + setCurrentPage('login'); + } + return (
-
setCurrentPage('find-tutor')} /> - +
setCurrentPage('find-tutor')} + onLoginClick={handleLoginClick} + setCurrentPage={setCurrentPage} + /> +
{renderPage()}
@@ -42,4 +60,12 @@ function App() { ); } +function App() { + return ( + + + + ); +} + export default App; \ No newline at end of file diff --git a/src/components/Header.js b/src/components/Header.js index cf988ad..ac89eef 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -1,16 +1,64 @@ -import React from 'react'; +import React, { useState } from 'react'; +import { useAuth } from '../context/AuthContext'; + +function Header({ onFindTutor, onLoginClick, setCurrentPage }) { + const { currentUser, logout } = useAuth(); + const [menuOpen, setMenuOpen] = useState(false); + + function handleLogout() { + logout(); + setMenuOpen(false); + setCurrentPage('home'); + } -function Header({ onFindTutor }) { return ( -
-

🇩🇪 Blebetalo

-

Platforma za učenje nemačkog jezika na srpskom

- +
+
setCurrentPage('home')} role="button" tabIndex={0} onKeyDown={e => e.key === 'Enter' && setCurrentPage('home')}> + 🇩🇪 +
+

Blebetalo

+

Učenje nemačkog na srpskom

+
+
+ +
+ + + {currentUser ? ( +
+ + {menuOpen && ( +
+
+ {currentUser.name} + {currentUser.email} + {currentUser.isAdmin && Admin} +
+ {currentUser.isAdmin && ( + + )} + +
+ )} +
+ ) : ( + + )} +
); } diff --git a/src/components/Navigation.js b/src/components/Navigation.js index bbec25c..df8f62b 100644 --- a/src/components/Navigation.js +++ b/src/components/Navigation.js @@ -1,4 +1,5 @@ -import React from 'react'; +import React, { useState } from 'react'; +import { useAuth } from '../context/AuthContext'; const navItems = [ { id: 'home', label: '🏠 Početna' }, @@ -10,25 +11,33 @@ const navItems = [ ]; function Navigation({ currentPage, setCurrentPage }) { + const { currentUser } = useAuth(); + const [mobileOpen, setMobileOpen] = useState(false); + + const items = currentUser?.isAdmin + ? [...navItems, { id: 'admin', label: '⚙️ Admin' }] + : navItems; + return ( -