harshdhane's picture
Upload 21 files
8ad39f4 verified
Raw
History Blame Contribute Delete
22.2 kB
<!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>
/* ====== Reset & Base ====== */
* {
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 ====== */
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 Styles ====== */
.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);
}
/* ====== Form Elements ====== */
.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;
}
/* Button Styles */
.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 Items ====== */
.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 ====== */
.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 ====== */
.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 ====== */
.action-bar {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
flex-wrap: wrap;
}
.action-group {
display: flex;
gap: 10px;
margin: 5px 0;
}
/* ====== Responsive Adjustments ====== */
@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 message */
.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>
<!-- Regular Subjects -->
<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>
<!-- Specialization Subjects -->
<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>
<!-- Batches -->
<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>
<!-- Practical Subjects -->
<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>
<!-- Modal Dialog -->
<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>
<!-- Toast container -->
<div class="toast-container" id="toastContainer"></div>
<script>
// This script will be replaced by your /static/script.js
// We're keeping the original script.js file reference at the top
// Just adding a few helper functions to demonstrate the toast
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);
}
// Placeholder functions to prevent console errors
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');
// Implement actual Excel download logic
}
// Initialize a sample timetable
window.addEventListener('DOMContentLoaded', () => {
const table = document.getElementById('timetable');
// Sample timetable data
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'];
// Create header row
const headerRow = document.createElement('tr');
days.forEach(day => {
const th = document.createElement('th');
th.textContent = day;
headerRow.appendChild(th);
});
table.appendChild(headerRow);
// Create time rows
times.forEach(time => {
const row = document.createElement('tr');
// Add time cell
const timeCell = document.createElement('td');
timeCell.textContent = time;
timeCell.style.fontWeight = 'bold';
timeCell.style.backgroundColor = '#f0f7ff';
row.appendChild(timeCell);
// Add empty cells for each day
for (let i = 1; i < days.length; i++) {
const td = document.createElement('td');
td.textContent = '';
row.appendChild(td);
}
table.appendChild(row);
});
// Populate dropdown for time slots
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>