Spaces:
Running
Running
| <html lang="en" class="h-full" data-theme="light"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>TKQuest</title> | |
| <!-- Tailwind --> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <!-- daisyUI --> | |
| <link href="https://cdn.jsdelivr.net/npm/daisyui@4.12.10/dist/full.min.css" rel="stylesheet" type="text/css" /> | |
| <!-- Font --> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> | |
| <!-- Add custom color theme --> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| primary: { | |
| 500: '#436bd9', // royal blue | |
| 600: '#3a5fc4', | |
| }, | |
| secondary: { | |
| 500: '#9ec2f2', // light blue | |
| 600: '#8ab1ea', | |
| } | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <style> | |
| body { | |
| font-family: 'Inter', sans-serif; | |
| overflow: hidden; /* Prevent body scroll */ | |
| } | |
| /* Ensure main area takes full viewport height and scrolls */ | |
| #main-app-view main { | |
| height: 100vh; /* Full viewport height */ | |
| overflow-y: auto; /* Allow main area to scroll independently */ | |
| padding-left: 16rem; /* Initial padding for w-64 sidebar */ | |
| transition: padding-left 0.3s ease-in-out; /* Smooth transition for padding */ | |
| width: 100%; /* Ensure main takes full width relative to its container */ | |
| } | |
| /* Style for collapsed sidebar state - applied to body */ | |
| body.sidebar-collapsed #main-app-view main { | |
| padding-left: 4rem; /* Padding for collapsed w-16 sidebar */ | |
| } | |
| /* Keep sidebar fixed and full height */ | |
| #main-app-view aside { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| height: 100vh; | |
| z-index: 30; /* Ensure sidebar is above main content scrollbar but below modals */ | |
| } | |
| /* Custom Theme Overrides */ | |
| :root[data-theme="light"] { | |
| --p: #436bd9; /* primary-500 */ | |
| --pc: #ffffff; /* text on primary buttons */ | |
| --s: #9ec2f2; /* secondary-500 */ | |
| --sc: #1d264e; /* text on secondary buttons */ | |
| --a: #70a1ea; /* accent between primary and secondary */ | |
| --ac: #1d264e; /* text on accent buttons */ | |
| --n: #293b7f; /* royal-blue-900 */ | |
| --nc: #ffffff; | |
| --b1: #ffffff; /* base-100 (white) */ | |
| --b2: #f1f5fd; /* royal-blue-50 (light bg) */ | |
| --b3: #dfeafa; /* royal-blue-100 (lighter bg) */ | |
| --bc: #000000; /* base-content (black text) */ | |
| --in: #70a1ea; | |
| --su: #4ade80; /* Use DaisyUI success color */ | |
| --wa: #facc15; | |
| --er: #f43f5e; | |
| /* Custom class for blue text */ | |
| .text-primary-blue { | |
| color: var(--p); | |
| } | |
| } | |
| /* Custom style for active sidebar link */ | |
| #sidebar-menu li.active > a { | |
| background-color: var(--b2); /* royal-blue-50 */ | |
| color: var(--p); /* royal-blue-600 */ | |
| } | |
| #sidebar-menu li.active > a svg { | |
| stroke: var(--p); /* royal-blue-600 */ | |
| } | |
| /* Ensure dropdowns have high z-index */ | |
| .dropdown-content { | |
| z-index: 50 ; | |
| background-color: var(--b1) ; /* Force white background */ | |
| } | |
| /* Custom class for content cards */ | |
| .content-card { | |
| background-color: var(--b1); | |
| border-radius: 0.5rem; /* 8px */ | |
| box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); | |
| transition: all 0.2s ease-in-out; | |
| } | |
| /* Floating User Info Box */ | |
| #floating-user-info { | |
| position: fixed; | |
| top: 1.5rem; /* Adjust as needed */ | |
| right: 1.5rem; /* Adjust as needed */ | |
| z-index: 40; /* Below dropdowns, above most content */ | |
| } | |
| /* Ensure modals scroll internally */ | |
| .modal-box { | |
| max-height: 85vh; | |
| overflow-y: auto; | |
| } | |
| /* --- Custom Progress Bar Styles --- */ | |
| .progress-bar-container { | |
| width: 100%; | |
| background-color: var(--b3); /* Light background for the track */ | |
| border-radius: 9999px; /* Fully rounded */ | |
| height: 1rem; /* 16px - slightly thicker */ | |
| overflow: hidden; /* Ensure fill stays inside */ | |
| position: relative; /* For potential future text overlay */ | |
| box-shadow: inset 0 1px 3px rgba(0,0,0,0.1); /* Inner shadow for depth */ | |
| } | |
| .progress-bar-fill { | |
| background: linear-gradient(to right, #4ade80, #16a34a); /* Adjusted green gradient (using DaisyUI success) */ | |
| height: 100%; | |
| border-radius: 9999px; | |
| width: 0%; /* Start at 0 */ | |
| transition: width 0.6s cubic-bezier(0.68, -0.55, 0.27, 1.55); /* Bouncy animation */ | |
| /* Add subtle stripes for visual interest */ | |
| background-image: linear-gradient( | |
| 45deg, | |
| rgba(255, 255, 255, .15) 25%, | |
| transparent 25%, | |
| transparent 50%, | |
| rgba(255, 255, 255, .15) 50%, | |
| rgba(255, 255, 255, .15) 75%, | |
| transparent 75%, | |
| transparent | |
| ); | |
| background-size: 1rem 1rem; /* Stripe size */ | |
| } | |
| /* Style for the temporary Dev button */ | |
| #dev-switch-role-btn { | |
| /* Positioned relative to the header */ | |
| z-index: 100; /* Ensure it's clickable */ | |
| } | |
| </style> | |
| </head> | |
| <body class="h-full bg-base-300"> | |
| <!-- App Container --> | |
| <div id="app" class="min-h-full"> | |
| <!-- 1. Authentication View (Login/Register) --> | |
| <div id="auth-view" class="hidden min-h-screen flex items-center justify-center p-4"> | |
| <div class="card w-full max-w-md bg-base-100 shadow-xl"> | |
| <div class="card-body"> | |
| <div role="tablist" class="tabs tabs-lifted tabs-lg"> | |
| <!-- Login Tab --> | |
| <input type="radio" name="auth_tabs" role="tab" class="tab" aria-label="Login" checked /> | |
| <div role="tabpanel" class="tab-content bg-base-100 rounded-box p-6"> | |
| <h2 class="text-2xl font-bold mb-6 text-center text-primary-blue">Log In to TKQuest</h2> | |
| <form id="login-form-element" class="space-y-4"> | |
| <div class="form-control"> | |
| <label class="label"><span class="label-text">Email</span></label> | |
| <input type="email" id="login-email" required class="input input-bordered w-full"> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"><span class="label-text">Password</span></label> | |
| <input type="password" id="login-password" required class="input input-bordered w-full"> | |
| </div> | |
| <p id="login-error" class="text-error text-sm hidden"></p> | |
| <button type="submit" class="btn btn-primary w-full">Log In</button> | |
| </form> | |
| </div> | |
| <!-- Register Tab --> | |
| <input type="radio" name="auth_tabs" role="tab" class="tab" aria-label="Register" /> | |
| <div role="tabpanel" class="tab-content bg-base-100 rounded-box p-6"> | |
| <h2 class="text-2xl font-bold mb-6 text-center text-primary-blue">Create Student Account</h2> | |
| <form id="register-form-element" class="space-y-4"> | |
| <div class="form-control"> | |
| <label class="label"><span class="label-text">Full Name</span></label> | |
| <input type="text" id="register-name" required class="input input-bordered w-full"> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"><span class="label-text">Email</span></label> | |
| <input type="email" id="register-email" required class="input input-bordered w-full"> | |
| </div> | |
| <div class="form-control"> | |
| <label class="label"><span class="label-text">Password (min. 6 characters)</span></label> | |
| <input type="password" id="register-password" required minlength="6" class="input input-bordered w-full"> | |
| </div> | |
| <input type="hidden" id="register-role" value="student"> | |
| <div class="form-control" id="belt-level-field"> | |
| <label class="label"><span class="label-text">Current Belt Level</span></label> | |
| <select id="register-belt" class="select select-bordered w-full"> | |
| <option value="White" selected>White</option> | |
| <option value="Yellow">Yellow</option> | |
| <option value="Blue">Blue</option> | |
| <option value="Red">Red</option> | |
| <option value="Brown">Brown</option> | |
| </select> | |
| </div> | |
| <p id="register-error" class="text-error text-sm hidden"></p> | |
| <button type="submit" class="btn btn-primary w-full">Register</button> | |
| </form> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 2. Main App View --> | |
| <div id="main-app-view" class="hidden h-screen flex fixed inset-0 overflow-hidden"> | |
| <!-- Sidebar --> | |
| <aside id="sidebar" class="bg-base-100 shadow-xl flex flex-col h-full z-10 transition-all duration-300 ease-in-out w-64"> | |
| <div class="p-4 flex items-center justify-between"> | |
| <a id="sidebar-logo" class="btn btn-ghost text-2xl font-bold text-primary-blue whitespace-nowrap overflow-hidden">TKQuest</a> | |
| <button id="sidebar-toggle-btn" class="btn btn-ghost btn-circle"> | |
| <svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m11 17-5-5 5-5"/><path d="m18 17-5-5 5-5"/></svg> | |
| </button> | |
| </div> | |
| <ul id="sidebar-menu" class="menu p-4 w-full text-base-content space-y-2 overflow-y-auto flex-grow"> | |
| <!-- Links injected by JS --> | |
| </ul> | |
| <div class="mt-auto p-4 border-t border-base-200"> | |
| <div id="user-info" class="items-center gap-2"> | |
| <span id="user-display" class="text-sm font-medium sidebar-link-text block truncate"></span> | |
| <button id="logout-btn" class="btn btn-error btn-outline btn-sm w-full mt-2"> | |
| <svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" x2="9" y1="12" y2="12"/></svg> | |
| <span class="sidebar-link-text">Logout</span> | |
| </button> | |
| </div> | |
| </div> | |
| </aside> | |
| <!-- Floating User Info Box (Student Only) --> | |
| <div id="floating-user-info" class="hidden card bg-base-100 shadow-lg p-3 text-xs w-48"> | |
| <p><span class="font-semibold">Name:</span> <span id="float-user-name">N/A</span></p> | |
| <p><span class="font-semibold">Belt:</span> <span id="float-user-belt">N/A</span></p> | |
| <p><span class="font-semibold">ID:</span> <span id="float-user-number">N/A</span></p> | |
| </div> | |
| <!-- Main Content Area --> | |
| <main class="bg-base-200 overflow-y-auto"> | |
| <div class="py-10"> | |
| <header class="sticky top-0 bg-base-200/80 backdrop-blur z-20 pt-2 pb-2 -mt-10"> | |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex justify-between items-center"> | |
| <h1 id="main-header" class="text-3xl font-bold leading-tight text-primary-blue"> | |
| Dashboard | |
| </h1> | |
| <!-- Temporary Dev Button --> | |
| <button id="dev-switch-role-btn" class="btn btn-warning btn-sm hidden">Switch Role (Dev)</button> | |
| </div> | |
| </header> | |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 mt-8 pb-10"> | |
| <!-- Page: Dashboard (Improved) --> | |
| <div id="dashboard-page" class="app-page hidden"> | |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-6"> | |
| <!-- Quick Stats --> | |
| <div class="card bg-base-100 shadow-md"> | |
| <div class="card-body"> | |
| <h2 class="card-title text-lg">Quick Stats</h2> | |
| <div class="space-y-1 text-sm"> | |
| <p><span class="font-medium">Current Belt:</span> <span id="stat-current-belt">Loading...</span></p> | |
| <p><span class="font-medium">Lessons Completed:</span> <span id="stat-lessons-completed">Loading...</span></p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Progress Overview (Student Only) --> | |
| <div id="dashboard-progress-overview" class="card bg-base-100 shadow-md hidden"> | |
| <div class="card-body"> | |
| <h2 class="card-title text-lg">Current Belt Progress</h2> | |
| <div class="progress-bar-container mt-2"> | |
| <div id="dashboard-progress-bar-fill" class="progress-bar-fill"></div> | |
| </div> | |
| <p class="text-xs text-center mt-1"><span id="dashboard-progress-text">0%</span> completed</p> | |
| </div> | |
| </div> | |
| <!-- Upcoming Event --> | |
| <div class="card bg-base-100 shadow-md"> | |
| <div class="card-body"> | |
| <h2 class="card-title text-lg">Next Event</h2> | |
| <div id="dashboard-next-event" class="text-sm"> | |
| <p class="opacity-60">No upcoming events scheduled.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <!-- Announcements --> | |
| <div> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="text-2xl font-semibold">Announcements</h2> | |
| <div id="instructor-actions-dashboard"> | |
| <button id="add-announcement-btn" class="btn btn-primary btn-sm">Post Announcement</button> | |
| </div> | |
| </div> | |
| <div class="card bg-base-100 shadow-xl max-h-[50vh] overflow-y-auto"> | |
| <div id="announcements-list" class="card-body space-y-4"> | |
| <div class="announcement"> | |
| <h3 class="font-bold">Welcome to TKQuest!</h3> | |
| <p class="text-sm">Get started by exploring the curriculum and completing your first lesson.</p> | |
| <p class="text-xs text-gray-500">Posted on: Today</p> | |
| </div> | |
| <div class="announcement"> | |
| <h3 class="font-bold">Belt Testing Dates</h3> | |
| <p class="text-sm">Next belt testing will be on December 15th. Make sure to complete all requirements.</p> | |
| <p class="text-xs text-gray-500">Posted on: Nov 20</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Notifications/Recent Activity --> | |
| <div> | |
| <h2 class="text-2xl font-semibold mb-4">Recent Activity</h2> | |
| <div class="card bg-base-100 shadow-xl max-h-[50vh] overflow-y-auto"> | |
| <div id="dashboard-notifications" class="card-body space-y-3 text-sm"> | |
| <p class="opacity-60">No recent activity.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Page: Curriculum --> | |
| <div id="lessons-page" class="app-page hidden"> | |
| <div class="flex justify-end gap-2 mb-4" id="instructor-actions-lessons"> | |
| <button id="edit-belt-names-btn" class="btn btn-outline">Edit Section Names</button> | |
| <button id="add-topic-btn" class="btn btn-secondary">Add Topic</button> | |
| </div> | |
| <div class="card bg-base-100 shadow-xl"> | |
| <div class="card-body"> | |
| <div id="lessons-list" class="space-y-6 pt-4"> | |
| <p class="text-base-content opacity-60">No lessons loaded.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Page: My Progress (Student Only) --> | |
| <div id="my-progress-page" class="app-page hidden space-y-8"> | |
| <!-- Belt Progress Checklist --> | |
| <div class="card bg-base-100 shadow-xl"> | |
| <div class="card-body"> | |
| <h2 class="card-title text-2xl mb-4">Belt Progress (<span id="checklist-belt-name">Current Belt</span>)</h2> | |
| <div class="flex justify-end mb-4" id="instructor-actions-checklist"> | |
| <button id="add-checklist-item-btn" class="btn btn-primary btn-sm">Add Checklist Item</button> | |
| </div> | |
| <div id="belt-checklist" class="space-y-3 mb-4"> | |
| <p class="opacity-60">Checklist items loading...</p> | |
| </div> | |
| <div> | |
| <label class="label"><span class="label-text font-medium">Progress Bar</span></label> | |
| <div class="progress-bar-container"> | |
| <div id="preparedness-bar-fill" class="progress-bar-fill" style="width: 0%;"></div> | |
| </div> | |
| <p id="preparedness-message" class="text-center text-sm mt-2 font-medium hidden">You are now ready to take the belt advancement examination!</p> | |
| <p id="instructor-notification-status" class="text-center text-xs mt-1 text-info hidden">Instructor has been notified.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- History of Completed Lessons --> | |
| <div class="card bg-base-100 shadow-xl"> | |
| <div class="card-body"> | |
| <h2 class="card-title text-2xl">Completed Lessons History</h2> | |
| <div id="completed-lessons-history" class="space-y-2 pt-4 max-h-96 overflow-y-auto"> | |
| <p class="opacity-60">No lessons completed yet.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Page: Tasks & Exercises --> | |
| <div id="tasks-page" class="app-page hidden space-y-8"> | |
| <!-- Quizzes --> | |
| <div class="card bg-base-100 shadow-xl"> | |
| <div class="card-body"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="card-title text-2xl">Quizzes</h2> | |
| <div id="instructor-actions-quizzes"> | |
| <button id="add-quiz-btn" class="btn btn-primary btn-sm">Add Quiz Link</button> | |
| </div> | |
| </div> | |
| <div id="quiz-list" class="space-y-3"> | |
| <p class="opacity-60">No quizzes assigned.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Weekly Tasks --> | |
| <div class="card bg-base-100 shadow-xl"> | |
| <div class="card-body"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="card-title text-2xl">Weekly Tasks (<span id="tasks-belt-name">Your Belt</span>)</h2> | |
| <div id="instructor-actions-tasks"> | |
| <button id="add-task-btn" class="btn btn-primary btn-sm">Add Weekly Task</button> | |
| </div> | |
| </div> | |
| <div id="weekly-tasks-list" class="space-y-3"> | |
| <p class="opacity-60">No weekly tasks assigned.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Challenges --> | |
| <div class="card bg-base-100 shadow-xl"> | |
| <div class="card-body"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h2 class="card-title text-2xl">Challenges</h2> | |
| <div id="instructor-actions-challenges"> | |
| <button id="add-challenge-btn" class="btn btn-primary btn-sm">Add Challenge</button> | |
| </div> | |
| </div> | |
| <div id="challenges-list" class="space-y-3"> | |
| <p class="opacity-60">No challenges available.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Page: Events --> | |
| <div id="events-page" class="app-page hidden"> | |
| <div class="flex justify-end mb-4" id="instructor-actions-events"> | |
| <button id="add-event-btn" class="btn btn-primary">Create Event</button> | |
| </div> | |
| <div class="card bg-base-100 shadow-xl"> | |
| <div class="card-body"> | |
| <h2 class="card-title text-2xl">Upcoming Events</h2> | |
| <div id="events-list" class="space-y-4 pt-4"> | |
| <p class="opacity-60">No upcoming events.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Page: Manage Users (Instructor only) --> | |
| <div id="manage-users-page" class="app-page hidden"> | |
| <div class="card bg-base-100 shadow-xl"> | |
| <div class="card-body"> | |
| <h2 class="card-title text-2xl">Manage Students</h2> | |
| <div id="student-users-list" class="space-y-3 pt-4 max-h-[70vh] overflow-y-auto"> | |
| <p class="text-base-content opacity-60">No students found.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Page: Settings --> | |
| <div id="settings-page" class="app-page hidden"> | |
| <div class="card bg-base-100 shadow-xl max-w-lg mx-auto"> | |
| <div class="card-body"> | |
| <h2 class="card-title text-2xl">Settings</h2> | |
| <p class="text-sm text-base-content mb-4">Your User ID: <kbd id="user-id-kbd" class="kbd kbd-sm"></kbd></p> | |
| <div class="divider">Update Profile</div> | |
| <form id="update-profile-form" class="space-y-4"> | |
| <div class="form-control"> | |
| <label class="label"><span class="label-text">Full Name</span></label> | |
| <input type="text" id="update-name" required class="input input-bordered w-full"> | |
| </div> | |
| <button type="submit" class="btn btn-primary">Save Name</button> | |
| <p id="update-profile-success" class="text-success text-sm hidden">Profile updated!</p> | |
| </form> | |
| <div class="divider">Change Password</div> | |
| <form id="update-password-form" class="space-y-4"> | |
| <div class="form-control"> | |
| <label class="label"><span class="label-text">New Password</span></label> | |
| <input type="password" id="update-password" required minlength="6" class="input input-bordered w-full"> | |
| </div> | |
| <p class="text-info text-sm">Note: For security, you may be asked to log in again after changing your password.</p> | |
| <button type="submit" class="btn btn-secondary">Update Password</button> | |
| <p id="update-password-error" class="text-error text-sm hidden"></p> | |
| <p id="update-password-success" class="text-success text-sm hidden">Password updated!</p> | |
| </form> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| </div> | |
| </div> | |
| <!-- Modals --> | |
| <!-- All modal dialogs remain the same as in original code --> | |
| <!-- ... --> | |
| <!-- Firebase SDK --> | |
| <script type="module"> | |
| /* Firebase imports and initialization remain the same */ | |
| /* ... */ | |
| </script> | |
| <!-- Main Application Script --> | |
| <script src="script.js"></script> | |
| <script src="components/navbar.js"></script> | |
| <script src="components/footer.js"></script> | |
| </body> | |
| </html> |