| <!DOCTYPE html>
|
| <html lang="en">
|
| <head>
|
| <meta charset="UTF-8">
|
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| <title>Smart Timetable Editor</title>
|
| <script src="/static/script.js" defer></script>
|
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
| <style>
|
|
|
| * {
|
| box-sizing: border-box;
|
| margin: 0;
|
| padding: 0;
|
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
| }
|
|
|
| body {
|
| background: linear-gradient(135deg, #f0f4f8 0%, #d7e1ec 100%);
|
| min-height: 100vh;
|
| display: flex;
|
| flex-direction: column;
|
| align-items: center;
|
| padding: 30px 20px;
|
| color: #333;
|
| }
|
|
|
| .container {
|
| width: 100%;
|
| max-width: 1000px;
|
| margin: 0 auto;
|
| }
|
|
|
|
|
| header {
|
| width: 100%;
|
| background: #fff;
|
| box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
| padding: 15px 0;
|
| margin-bottom: 30px;
|
| border-bottom: 3px solid #1a4a7c;
|
| border-radius: 10px;
|
| }
|
|
|
| header .header-content {
|
| display: flex;
|
| align-items: center;
|
| justify-content: center;
|
| padding: 0 20px;
|
| }
|
|
|
| header h1 {
|
| font-size: 1.8rem;
|
| font-weight: 600;
|
| color: #1a4a7c;
|
| margin: 0;
|
| text-align: center;
|
| }
|
|
|
|
|
| .card {
|
| background-color: #ffffff;
|
| border-radius: 12px;
|
| padding: 25px;
|
| width: 100%;
|
| box-shadow: 0 10px 25px rgba(0,0,0,0.12);
|
| margin-bottom: 30px;
|
| border-top: 4px solid #1a4a7c;
|
| position: relative;
|
| }
|
|
|
| .card h3 {
|
| color: #1a4a7c;
|
| margin-bottom: 20px;
|
| font-weight: 600;
|
| position: relative;
|
| padding-bottom: 10px;
|
| }
|
|
|
| .card h3:after {
|
| content: "";
|
| position: absolute;
|
| bottom: 0;
|
| left: 0;
|
| width: 80px;
|
| height: 3px;
|
| background: linear-gradient(90deg, #1a4a7c, #3498db);
|
| }
|
|
|
|
|
| .input-group {
|
| margin-bottom: 15px;
|
| position: relative;
|
| }
|
|
|
| .input-group label {
|
| display: block;
|
| margin-bottom: 8px;
|
| color: #444;
|
| font-size: 14px;
|
| font-weight: 500;
|
| }
|
|
|
| .input-group select,
|
| .input-group input {
|
| width: 100%;
|
| padding: 12px 15px;
|
| border: 1px solid #ddd;
|
| border-radius: 8px;
|
| font-size: 14px;
|
| transition: all 0.3s;
|
| background-color: #f9fbff;
|
| }
|
|
|
| .input-group select:focus,
|
| .input-group input:focus {
|
| border-color: #3498db;
|
| outline: none;
|
| box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.15);
|
| background-color: #fff;
|
| }
|
|
|
|
|
| .btn {
|
| display: inline-block;
|
| padding: 10px 18px;
|
| border: none;
|
| border-radius: 8px;
|
| cursor: pointer;
|
| font-size: 14px;
|
| font-weight: 600;
|
| text-align: center;
|
| transition: all 0.3s;
|
| margin: 5px;
|
| }
|
|
|
| .btn-primary {
|
| color: #fff;
|
| background: linear-gradient(to right, #1a4a7c, #3498db);
|
| box-shadow: 0 4px 8px rgba(26, 74, 124, 0.25);
|
| }
|
|
|
| .btn-primary:hover {
|
| transform: translateY(-2px);
|
| box-shadow: 0 6px 12px rgba(26, 74, 124, 0.35);
|
| background: linear-gradient(to right, #155785, #2980b9);
|
| }
|
|
|
| .btn-secondary {
|
| color: #1a4a7c;
|
| background: #e6f0ff;
|
| border: 1px solid #c5d9f1;
|
| }
|
|
|
| .btn-secondary:hover {
|
| background: #d1e3ff;
|
| transform: translateY(-1px);
|
| }
|
|
|
| .btn-danger {
|
| color: #fff;
|
| background: linear-gradient(to right, #e74c3c, #c0392b);
|
| box-shadow: 0 4px 8px rgba(231, 76, 60, 0.25);
|
| }
|
|
|
| .btn-danger:hover {
|
| transform: translateY(-2px);
|
| box-shadow: 0 6px 12px rgba(231, 76, 60, 0.35);
|
| }
|
|
|
| .btn-action {
|
| display: flex;
|
| align-items: center;
|
| justify-content: center;
|
| }
|
|
|
| .btn-action i {
|
| margin-right: 5px;
|
| }
|
|
|
|
|
| .config-item {
|
| display: inline-block;
|
| background-color: #f0f7ff;
|
| border: 1px solid #c5d9f1;
|
| padding: 5px 10px;
|
| border-radius: 15px;
|
| margin: 5px;
|
| font-size: 13px;
|
| }
|
|
|
| .config-list {
|
| margin: 10px 0;
|
| min-height: 30px;
|
| }
|
|
|
| .delete-btn {
|
| color: #e74c3c;
|
| cursor: pointer;
|
| margin-left: 5px;
|
| font-size: 12px;
|
| }
|
|
|
|
|
| .timetable-container {
|
| overflow-x: auto;
|
| width: 100%;
|
| box-shadow: 0 5px 15px rgba(0,0,0,0.08);
|
| border-radius: 10px;
|
| background: white;
|
| }
|
|
|
| table {
|
| border-collapse: collapse;
|
| width: 100%;
|
| margin-top: 5px;
|
| background-color: white;
|
| }
|
|
|
| th, td {
|
| border: 1px solid #e0e0e0;
|
| padding: 12px 15px;
|
| text-align: center;
|
| vertical-align: middle;
|
| font-size: 14px;
|
| }
|
|
|
| th {
|
| background-color: #1a4a7c;
|
| color: white;
|
| font-weight: 600;
|
| position: sticky;
|
| top: 0;
|
| }
|
|
|
| tr:nth-child(even) {
|
| background-color: #f9fbff;
|
| }
|
|
|
| tr:hover {
|
| background-color: #f0f7ff;
|
| }
|
|
|
|
|
| .modal {
|
| display: none;
|
| position: fixed;
|
| top: 0; left: 0; width: 100%; height: 100%;
|
| background: rgba(0,0,0,0.6);
|
| justify-content: center;
|
| align-items: center;
|
| z-index: 1000;
|
| backdrop-filter: blur(3px);
|
| }
|
|
|
| .modal-content {
|
| background: #fff;
|
| padding: 25px;
|
| border-radius: 12px;
|
| width: 90%;
|
| max-width: 450px;
|
| box-shadow: 0 15px 30px rgba(0,0,0,0.2);
|
| position: relative;
|
| border-top: 4px solid #1a4a7c;
|
| animation: modalFadeIn 0.3s;
|
| }
|
|
|
| @keyframes modalFadeIn {
|
| from { opacity: 0; transform: translateY(-20px); }
|
| to { opacity: 1; transform: translateY(0); }
|
| }
|
|
|
| .close-modal {
|
| position: absolute;
|
| top: 15px; right: 15px;
|
| background: #f0f4f8;
|
| border: none;
|
| font-size: 18px;
|
| color: #555;
|
| cursor: pointer;
|
| width: 30px;
|
| height: 30px;
|
| border-radius: 50%;
|
| display: flex;
|
| align-items: center;
|
| justify-content: center;
|
| transition: all 0.3s;
|
| }
|
|
|
| .close-modal:hover {
|
| background: #e0e6ed;
|
| color: #1a4a7c;
|
| transform: rotate(90deg);
|
| }
|
|
|
| .modal-content h3 {
|
| color: #1a4a7c;
|
| margin-bottom: 20px;
|
| font-weight: 600;
|
| text-align: center;
|
| position: relative;
|
| padding-bottom: 10px;
|
| }
|
|
|
| .modal-content h3:after {
|
| content: "";
|
| position: absolute;
|
| bottom: 0;
|
| left: 50%;
|
| transform: translateX(-50%);
|
| width: 80px;
|
| height: 3px;
|
| background: linear-gradient(90deg, #1a4a7c, #3498db);
|
| }
|
|
|
|
|
| .action-bar {
|
| display: flex;
|
| justify-content: space-between;
|
| margin-bottom: 20px;
|
| flex-wrap: wrap;
|
| }
|
|
|
| .action-group {
|
| display: flex;
|
| gap: 10px;
|
| margin: 5px 0;
|
| }
|
|
|
|
|
| @media (max-width: 768px) {
|
| header h1 { font-size: 1.4rem; }
|
| .card { padding: 20px; }
|
| .input-group label { font-size: 13px; }
|
| .input-group select, .input-group input { padding: 10px; font-size: 13px; }
|
| .modal-content { padding: 20px; }
|
| .btn { padding: 8px 15px; font-size: 13px; }
|
| }
|
|
|
| @media (max-width: 576px) {
|
| header h1 { font-size: 1.2rem; }
|
| .action-bar { flex-direction: column; }
|
| .action-group { width: 100%; justify-content: center; }
|
| th, td { padding: 8px; font-size: 12px; }
|
| }
|
|
|
|
|
| .toast-container {
|
| position: fixed;
|
| bottom: 20px;
|
| right: 20px;
|
| z-index: 1001;
|
| }
|
|
|
| .toast {
|
| background-color: rgba(26, 74, 124, 0.9);
|
| color: white;
|
| padding: 15px 25px;
|
| border-radius: 8px;
|
| box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
| margin-top: 10px;
|
| display: flex;
|
| align-items: center;
|
| animation: toastFadeIn 0.3s;
|
| backdrop-filter: blur(5px);
|
| }
|
|
|
| .toast i {
|
| margin-right: 10px;
|
| font-size: 20px;
|
| }
|
|
|
| @keyframes toastFadeIn {
|
| from { opacity: 0; transform: translateY(20px); }
|
| to { opacity: 1; transform: translateY(0); }
|
| }
|
| </style>
|
| </head>
|
| <body>
|
| <div class="container">
|
| <header>
|
| <div class="header-content">
|
| <h1><i class="fas fa-calendar-alt"></i> Smart Timetable Editor</h1>
|
| </div>
|
| </header>
|
|
|
| <div class="card">
|
| <h3>Class Configuration</h3>
|
| <div class="input-group">
|
| <label for="classSelect"><i class="fas fa-users"></i> Select Class:</label>
|
| <select id="classSelect" onchange="loadForSelectedClass()">
|
| <option value="">--Select Class--</option>
|
| <option value="SY-19">SY-19</option>
|
| <option value="SY-20">SY-20</option>
|
| <option value="SY-21">SY-21</option>
|
| <option value="SY-22">SY-22</option>
|
| </select>
|
| </div>
|
| </div>
|
|
|
| <div class="card">
|
| <h3>Subject Configuration</h3>
|
|
|
|
|
| <div class="input-group">
|
| <label for="subjectInput"><i class="fas fa-book"></i> Subject:</label>
|
| <div style="display: flex; gap: 10px;">
|
| <input type="text" id="subjectInput" placeholder="Enter subject name">
|
| <button class="btn btn-primary" onclick="addConfig('subject')">Add</button>
|
| </div>
|
| </div>
|
| <div class="config-list" id="subjectList"></div>
|
|
|
|
|
| <div class="input-group">
|
| <label for="specSubjectInput"><i class="fas fa-book-reader"></i> Specialization Subject:</label>
|
| <div style="display: flex; gap: 10px;">
|
| <input type="text" id="specSubjectInput" placeholder="Enter specialization subject">
|
| <button class="btn btn-primary" onclick="addConfig('specSubject')">Add</button>
|
| </div>
|
| </div>
|
| <div class="config-list" id="specSubjectList"></div>
|
|
|
|
|
| <div class="input-group">
|
| <label for="batchInput"><i class="fas fa-layer-group"></i> Batch:</label>
|
| <div style="display: flex; gap: 10px;">
|
| <input type="text" id="batchInput" placeholder="Enter batch name">
|
| <button class="btn btn-primary" onclick="addConfig('batch')">Add</button>
|
| </div>
|
| </div>
|
| <div class="config-list" id="batchList"></div>
|
|
|
|
|
| <div class="input-group">
|
| <label for="practicalSubjectInput"><i class="fas fa-flask"></i> Practical Subject:</label>
|
| <div style="display: flex; gap: 10px;">
|
| <input type="text" id="practicalSubjectInput" placeholder="Enter practical subject">
|
| <button class="btn btn-primary" onclick="addConfig('practical')">Add</button>
|
| </div>
|
| </div>
|
| <div class="config-list" id="practicalSubjectList"></div>
|
| </div>
|
|
|
| <div class="action-bar">
|
| <div class="action-group">
|
| <button class="btn btn-primary btn-action" onclick="openModal()">
|
| <i class="fas fa-plus-circle"></i> Create/Update Timetable
|
| </button>
|
| </div>
|
| <div class="action-group">
|
| <button class="btn btn-secondary btn-action" onclick="downloadExcel()">
|
| <i class="fas fa-file-download"></i> Download Excel
|
| </button>
|
| </div>
|
| </div>
|
|
|
| <div class="timetable-container">
|
| <table id="timetable"></table>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="modal" id="popupModal">
|
| <div class="modal-content">
|
| <span class="close-modal" onclick="closeModal()">×</span>
|
| <h3>Update Timetable</h3>
|
|
|
| <div class="input-group">
|
| <label for="daySelect"><i class="fas fa-calendar-day"></i> Select Day:</label>
|
| <select id="daySelect">
|
| <option value="">--Select Day--</option>
|
| <option value="Monday">Monday</option>
|
| <option value="Tuesday">Tuesday</option>
|
| <option value="Wednesday">Wednesday</option>
|
| <option value="Thursday">Thursday</option>
|
| <option value="Friday">Friday</option>
|
| <option value="Saturday">Saturday</option>
|
| <option value="Sunday">Sunday</option>
|
| </select>
|
| </div>
|
|
|
| <div class="input-group">
|
| <label for="optionType"><i class="fas fa-list-alt"></i> Choose Option:</label>
|
| <select id="optionType" onchange="optionTypeChanged()">
|
| <option value="">--Select Option--</option>
|
| <option value="subject">Subject</option>
|
| <option value="specSubject">Specialization Subject</option>
|
| <option value="practical">Practical Subject</option>
|
| </select>
|
| </div>
|
|
|
| <div id="subjectDropdown" class="input-group" style="display:none;">
|
| <label for="subjectSelect"><i class="fas fa-book"></i> Select Subject:</label>
|
| <select id="subjectSelect"></select>
|
| </div>
|
|
|
| <div id="specSubjectDropdown" class="input-group" style="display:none;">
|
| <label for="specSubjectSelect"><i class="fas fa-book-reader"></i> Select Specialization Subject:</label>
|
| <select id="specSubjectSelect"></select>
|
| </div>
|
|
|
| <div id="practicalDropdown" class="input-group" style="display:none;">
|
| <label for="practicalSelect"><i class="fas fa-flask"></i> Select Practical Subject:</label>
|
| <select id="practicalSelect"></select>
|
|
|
| <label for="batchSelect" style="margin-top:10px;"><i class="fas fa-layer-group"></i> Select Batch:</label>
|
| <select id="batchSelect"></select>
|
| </div>
|
|
|
| <div id="timeSlotDiv" class="input-group" style="display:none;">
|
| <label for="timeSlotSelect"><i class="fas fa-clock"></i> Select Time Slot:</label>
|
| <select id="timeSlotSelect"></select>
|
| </div>
|
|
|
| <button id="submitBtn" class="btn btn-primary" style="display:none; width:100%; margin-top:20px;" onclick="submitTimetableEntry()">
|
| <i class="fas fa-check-circle"></i> Submit
|
| </button>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="toast-container" id="toastContainer"></div>
|
|
|
| <script>
|
|
|
|
|
|
|
|
|
| function showToast(message, type = 'info') {
|
| const toastContainer = document.getElementById('toastContainer');
|
| const toast = document.createElement('div');
|
| toast.className = 'toast';
|
|
|
| let icon = 'info-circle';
|
| if (type === 'success') icon = 'check-circle';
|
| if (type === 'error') icon = 'exclamation-circle';
|
|
|
| toast.innerHTML = `<i class="fas fa-${icon}"></i> ${message}`;
|
| toastContainer.appendChild(toast);
|
|
|
| setTimeout(() => {
|
| toast.style.opacity = '0';
|
| toast.style.transform = 'translateY(20px)';
|
| toast.style.transition = 'all 0.3s ease';
|
| setTimeout(() => toast.remove(), 300);
|
| }, 3000);
|
| }
|
|
|
|
|
| function loadForSelectedClass() {
|
| const selectedClass = document.getElementById('classSelect').value;
|
| if(selectedClass) {
|
| showToast(`Loading data for class ${selectedClass}`, 'info');
|
| }
|
| }
|
|
|
| function addConfig(type) {
|
| let inputId, listId;
|
| switch(type) {
|
| case 'subject':
|
| inputId = 'subjectInput';
|
| listId = 'subjectList';
|
| break;
|
| case 'specSubject':
|
| inputId = 'specSubjectInput';
|
| listId = 'specSubjectList';
|
| break;
|
| case 'batch':
|
| inputId = 'batchInput';
|
| listId = 'batchList';
|
| break;
|
| case 'practical':
|
| inputId = 'practicalSubjectInput';
|
| listId = 'practicalSubjectList';
|
| break;
|
| }
|
|
|
| const input = document.getElementById(inputId);
|
| const value = input.value.trim();
|
|
|
| if (value) {
|
| const list = document.getElementById(listId);
|
| const item = document.createElement('span');
|
| item.className = 'config-item';
|
| item.innerHTML = `${value} <span class="delete-btn" onclick="this.parentElement.remove()"><i class="fas fa-times"></i></span>`;
|
| list.appendChild(item);
|
| input.value = '';
|
| showToast(`Added ${value} to ${type}s`, 'success');
|
| }
|
| }
|
|
|
| function openModal() {
|
| document.getElementById('popupModal').style.display = 'flex';
|
| }
|
|
|
| function closeModal() {
|
| document.getElementById('popupModal').style.display = 'none';
|
| }
|
|
|
| function optionTypeChanged() {
|
| const optionType = document.getElementById('optionType').value;
|
| document.getElementById('subjectDropdown').style.display = 'none';
|
| document.getElementById('specSubjectDropdown').style.display = 'none';
|
| document.getElementById('practicalDropdown').style.display = 'none';
|
| document.getElementById('timeSlotDiv').style.display = 'none';
|
| document.getElementById('submitBtn').style.display = 'none';
|
|
|
| if (optionType === 'subject') {
|
| document.getElementById('subjectDropdown').style.display = 'block';
|
| document.getElementById('timeSlotDiv').style.display = 'block';
|
| document.getElementById('submitBtn').style.display = 'block';
|
| } else if (optionType === 'specSubject') {
|
| document.getElementById('specSubjectDropdown').style.display = 'block';
|
| document.getElementById('timeSlotDiv').style.display = 'block';
|
| document.getElementById('submitBtn').style.display = 'block';
|
| } else if (optionType === 'practical') {
|
| document.getElementById('practicalDropdown').style.display = 'block';
|
| document.getElementById('timeSlotDiv').style.display = 'block';
|
| document.getElementById('submitBtn').style.display = 'block';
|
| }
|
| }
|
|
|
| function submitTimetableEntry() {
|
| const day = document.getElementById('daySelect').value;
|
| const optionType = document.getElementById('optionType').value;
|
| const timeSlot = document.getElementById('timeSlotSelect').value;
|
|
|
| if (!day || !optionType || !timeSlot) {
|
| showToast('Please fill all required fields', 'error');
|
| return;
|
| }
|
|
|
| showToast('Timetable entry added successfully', 'success');
|
| closeModal();
|
| }
|
|
|
| function downloadExcel() {
|
| showToast('Downloading Excel file...', 'info');
|
|
|
| }
|
|
|
|
|
| window.addEventListener('DOMContentLoaded', () => {
|
| const table = document.getElementById('timetable');
|
|
|
|
|
| const days = ['Time', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'];
|
| const times = ['9:00-10:00', '10:00-11:00', '11:00-12:00', '12:00-1:00', '1:00-2:00'];
|
|
|
|
|
| const headerRow = document.createElement('tr');
|
| days.forEach(day => {
|
| const th = document.createElement('th');
|
| th.textContent = day;
|
| headerRow.appendChild(th);
|
| });
|
| table.appendChild(headerRow);
|
|
|
|
|
| times.forEach(time => {
|
| const row = document.createElement('tr');
|
|
|
|
|
| const timeCell = document.createElement('td');
|
| timeCell.textContent = time;
|
| timeCell.style.fontWeight = 'bold';
|
| timeCell.style.backgroundColor = '#f0f7ff';
|
| row.appendChild(timeCell);
|
|
|
|
|
| for (let i = 1; i < days.length; i++) {
|
| const td = document.createElement('td');
|
| td.textContent = '';
|
| row.appendChild(td);
|
| }
|
|
|
| table.appendChild(row);
|
| });
|
|
|
|
|
| const timeSlotSelect = document.getElementById('timeSlotSelect');
|
| times.forEach(time => {
|
| const option = document.createElement('option');
|
| option.value = time;
|
| option.textContent = time;
|
| timeSlotSelect.appendChild(option);
|
| });
|
| });
|
| </script>
|
| <script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'93ecda760d73bf9d',t:'MTc0NzA4MzcwNy4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
|
| </html> |