Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Student Leave Application System</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| .animated-input { | |
| transition: all 0.3s ease; | |
| } | |
| .animated-input:focus { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| } | |
| .btn-submit:hover { | |
| transform: translateY(-3px); | |
| box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); | |
| } | |
| .btn-submit:active { | |
| transform: translateY(-1px); | |
| } | |
| .floating-label { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| transition: all 0.2s ease; | |
| pointer-events: none; | |
| transform-origin: top left; | |
| } | |
| .input-container:focus-within .floating-label, | |
| .input-filled .floating-label { | |
| transform: translateY(-20px) scale(0.8); | |
| color: #3b82f6; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 min-h-screen"> | |
| <div class="container mx-auto px-4 py-8 max-w-4xl"> | |
| <!-- Header --> | |
| <div class="text-center mb-8"> | |
| <div class="flex justify-center mb-4"> | |
| <div class="bg-blue-100 p-4 rounded-full"> | |
| <i class="fas fa-calendar-alt text-blue-600 text-3xl"></i> | |
| </div> | |
| </div> | |
| <h1 class="text-3xl font-bold text-gray-800 mb-2">Student Leave Application</h1> | |
| <p class="text-gray-600">Please fill out this form to apply for leave from school</p> | |
| </div> | |
| <!-- Progress Steps --> | |
| <div class="mb-8"> | |
| <div class="flex justify-between items-center relative"> | |
| <div class="absolute top-1/2 left-0 right-0 h-1 bg-gray-200 -z-10"></div> | |
| <div class="step flex flex-col items-center relative" data-step="1"> | |
| <div class="w-10 h-10 rounded-full bg-blue-600 text-white flex items-center justify-center mb-2"> | |
| <span>1</span> | |
| </div> | |
| <span class="text-sm font-medium text-blue-600">Personal Info</span> | |
| </div> | |
| <div class="step flex flex-col items-center relative" data-step="2"> | |
| <div class="w-10 h-10 rounded-full bg-gray-200 text-gray-600 flex items-center justify-center mb-2"> | |
| <span>2</span> | |
| </div> | |
| <span class="text-sm font-medium text-gray-500">Leave Details</span> | |
| </div> | |
| <div class="step flex flex-col items-center relative" data-step="3"> | |
| <div class="w-10 h-10 rounded-full bg-gray-200 text-gray-600 flex items-center justify-center mb-2"> | |
| <span>3</span> | |
| </div> | |
| <span class="text-sm font-medium text-gray-500">Review</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Form Container --> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden p-6 md:p-8"> | |
| <form id="leaveForm" class="space-y-6"> | |
| <!-- Step 1: Personal Information --> | |
| <div class="step-content" data-step="1"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-6 flex items-center"> | |
| <i class="fas fa-user-circle text-blue-500 mr-2"></i> Personal Information | |
| </h2> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <!-- Student ID --> | |
| <div class="input-container relative"> | |
| <input type="text" id="studentId" name="studentId" | |
| class="w-full px-4 py-3 border border-gray-300 rounded-lg animated-input focus:border-blue-500 focus:outline-none" | |
| required> | |
| <label for="studentId" class="floating-label ml-3 mt-3 text-gray-500">Student ID</label> | |
| </div> | |
| <!-- Full Name --> | |
| <div class="input-container relative"> | |
| <input type="text" id="fullName" name="fullName" | |
| class="w-full px-4 py-3 border border-gray-300 rounded-lg animated-input focus:border-blue-500 focus:outline-none" | |
| required> | |
| <label for="fullName" class="floating-label ml-3 mt-3 text-gray-500">Full Name</label> | |
| </div> | |
| <!-- Class/Grade --> | |
| <div class="input-container relative"> | |
| <select id="department" name="department" | |
| class="w-full px-4 py-3 border border-gray-300 rounded-lg animated-input focus:border-blue-500 focus:outline-none appearance-none" | |
| required> | |
| <option value="" disabled selected></option> | |
| <option value="CS">Computer Science</option> | |
| <option value="AM">Account Management</option> | |
| <option value="Elektrik">Electrical Engineering</option> | |
| <option value="Culinary">Culinary Arts</option> | |
| <option value="F&B">Food & Beverage</option> | |
| </select> | |
| <label for="department" class="floating-label ml-3 mt-3 text-gray-500">Department</label> | |
| <i class="fas fa-chevron-down absolute right-3 top-4 text-gray-400"></i> | |
| </div> | |
| <!-- Contact Number --> | |
| <div class="input-container relative"> | |
| <input type="tel" id="contactNumber" name="contactNumber" | |
| class="w-full px-4 py-3 border border-gray-300 rounded-lg animated-input focus:border-blue-500 focus:outline-none" | |
| required> | |
| <label for="contactNumber" class="floating-label ml-3 mt-3 text-gray-500">Contact Number</label> | |
| </div> | |
| </div> | |
| <div class="flex justify-end mt-8"> | |
| <button type="button" class="next-step bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-6 rounded-lg transition duration-300 btn-submit"> | |
| Next <i class="fas fa-arrow-right ml-2"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Step 2: Leave Details --> | |
| <div class="step-content hidden" data-step="2"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-6 flex items-center"> | |
| <i class="fas fa-calendar-check text-blue-500 mr-2"></i> Leave Details | |
| </h2> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <!-- Leave Type --> | |
| <div class="input-container relative"> | |
| <select id="leaveType" name="leaveType" | |
| class="w-full px-4 py-3 border border-gray-300 rounded-lg animated-input focus:border-blue-500 focus:outline-none appearance-none" | |
| required> | |
| <option value="" disabled selected></option> | |
| <option value="Medical">Medical Leave</option> | |
| <option value="Personal">Personal Leave</option> | |
| <option value="Family">Family Emergency</option> | |
| <option value="Other">Other</option> | |
| </select> | |
| <label for="leaveType" class="floating-label ml-3 mt-3 text-gray-500">Leave Type</label> | |
| <i class="fas fa-chevron-down absolute right-3 top-4 text-gray-400"></i> | |
| </div> | |
| <!-- Start Date --> | |
| <div class="input-container relative"> | |
| <input type="date" id="startDate" name="startDate" | |
| class="w-full px-4 py-3 border border-gray-300 rounded-lg animated-input focus:border-blue-500 focus:outline-none" | |
| required> | |
| <label for="startDate" class="floating-label ml-3 mt-3 text-gray-500">Start Date</label> | |
| </div> | |
| <!-- End Date --> | |
| <div class="input-container relative"> | |
| <input type="date" id="endDate" name="endDate" | |
| class="w-full px-4 py-3 border border-gray-300 rounded-lg animated-input focus:border-blue-500 focus:outline-none" | |
| required> | |
| <label for="endDate" class="floating-label ml-3 mt-3 text-gray-500">End Date</label> | |
| </div> | |
| <!-- Days Requested --> | |
| <div class="input-container relative"> | |
| <input type="number" id="daysRequested" name="daysRequested" min="1" | |
| class="w-full px-4 py-3 border border-gray-300 rounded-lg animated-input focus:border-blue-500 focus:outline-none" | |
| required> | |
| <label for="daysRequested" class="floating-label ml-3 mt-3 text-gray-500">Days Requested</label> | |
| </div> | |
| </div> | |
| <!-- Reason for Leave --> | |
| <div class="mt-6"> | |
| <div class="input-container relative"> | |
| <textarea id="reason" name="reason" rows="4" | |
| class="w-full px-4 py-3 border border-gray-300 rounded-lg animated-input focus:border-blue-500 focus:outline-none" | |
| required></textarea> | |
| <label for="reason" class="floating-label ml-3 mt-3 text-gray-500">Reason for Leave</label> | |
| </div> | |
| </div> | |
| <!-- Supporting Documents --> | |
| <div class="mt-6"> | |
| <label class="block text-sm font-medium text-gray-700 mb-2">Supporting Documents (if any)</label> | |
| <div class="flex items-center justify-center w-full"> | |
| <label for="documents" class="flex flex-col items-center justify-center w-full h-32 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 hover:bg-gray-100"> | |
| <div class="flex flex-col items-center justify-center pt-5 pb-6"> | |
| <i class="fas fa-cloud-upload-alt text-gray-400 text-3xl mb-2"></i> | |
| <p class="mb-2 text-sm text-gray-500"><span class="font-semibold">Click to upload</span> or drag and drop</p> | |
| <p class="text-xs text-gray-500">PDF, JPG, PNG (MAX. 5MB)</p> | |
| </div> | |
| <input id="documents" name="documents" type="file" class="hidden" multiple> | |
| </label> | |
| </div> | |
| </div> | |
| <div class="flex justify-between mt-8"> | |
| <button type="button" class="prev-step bg-gray-200 hover:bg-gray-300 text-gray-700 font-medium py-2 px-6 rounded-lg transition duration-300"> | |
| <i class="fas fa-arrow-left mr-2"></i> Back | |
| </button> | |
| <button type="button" class="next-step bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-6 rounded-lg transition duration-300 btn-submit"> | |
| Next <i class="fas fa-arrow-right ml-2"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Step 3: Review and Submit --> | |
| <div class="step-content hidden" data-step="3"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-6 flex items-center"> | |
| <i class="fas fa-check-circle text-blue-500 mr-2"></i> Review Your Application | |
| </h2> | |
| <div class="bg-blue-50 border border-blue-100 rounded-lg p-6 mb-6"> | |
| <h3 class="text-lg font-medium text-blue-800 mb-4">Application Summary</h3> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
| <div> | |
| <p class="text-sm text-gray-600">Student ID</p> | |
| <p id="reviewStudentId" class="font-medium"></p> | |
| </div> | |
| <div> | |
| <p class="text-sm text-gray-600">Full Name</p> | |
| <p id="reviewFullName" class="font-medium"></p> | |
| </div> | |
| <div> | |
| <p class="text-sm text-gray-600">Department</p> | |
| <p id="reviewDepartment" class="font-medium"></p> | |
| </div> | |
| <div> | |
| <p class="text-sm text-gray-600">Contact Number</p> | |
| <p id="reviewContactNumber" class="font-medium"></p> | |
| </div> | |
| <div> | |
| <p class="text-sm text-gray-600">Leave Type</p> | |
| <p id="reviewLeaveType" class="font-medium"></p> | |
| </div> | |
| <div> | |
| <p class="text-sm text-gray-600">Leave Period</p> | |
| <p id="reviewLeavePeriod" class="font-medium"></p> | |
| </div> | |
| <div> | |
| <p class="text-sm text-gray-600">Days Requested</p> | |
| <p id="reviewDaysRequested" class="font-medium"></p> | |
| </div> | |
| <div class="md:col-span-2"> | |
| <p class="text-sm text-gray-600">Reason</p> | |
| <p id="reviewReason" class="font-medium"></p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Terms and Conditions --> | |
| <div class="flex items-start mb-6"> | |
| <div class="flex items-center h-5"> | |
| <input id="terms" name="terms" type="checkbox" class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-blue-300" required> | |
| </div> | |
| <label for="terms" class="ml-2 text-sm font-medium text-gray-700"> | |
| I confirm that all information provided is accurate and I agree to the <a href="#" class="text-blue-600 hover:underline">terms and conditions</a> of leave application. | |
| </label> | |
| </div> | |
| <div class="flex justify-between"> | |
| <button type="button" class="prev-step bg-gray-200 hover:bg-gray-300 text-gray-700 font-medium py-2 px-6 rounded-lg transition duration-300"> | |
| <i class="fas fa-arrow-left mr-2"></i> Back | |
| </button> | |
| <button type="submit" class="bg-green-600 hover:bg-green-700 text-white font-medium py-2 px-6 rounded-lg transition duration-300 btn-submit"> | |
| <i class="fas fa-paper-plane mr-2"></i> Submit Application | |
| </button> | |
| </div> | |
| </div> | |
| </form> | |
| </div> | |
| <!-- Success Modal --> | |
| <div id="successModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> | |
| <div class="bg-white rounded-xl p-8 max-w-md w-full mx-4"> | |
| <div class="text-center"> | |
| <div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100 mb-4"> | |
| <i class="fas fa-check text-green-600 text-xl"></i> | |
| </div> | |
| <h3 class="text-lg font-medium text-gray-900 mb-2">Application Submitted!</h3> | |
| <p class="text-sm text-gray-500 mb-6">Your leave application has been successfully submitted. You will receive a confirmation email shortly.</p> | |
| <div class="mt-4"> | |
| <button id="closeModal" type="button" class="inline-flex justify-center rounded-md border border-transparent bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"> | |
| Close | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Initialize floating labels | |
| const inputs = document.querySelectorAll('.input-container input, .input-container select, .input-container textarea'); | |
| inputs.forEach(input => { | |
| // Check if input has value on load | |
| if (input.value) { | |
| input.parentElement.classList.add('input-filled'); | |
| } | |
| input.addEventListener('focus', function() { | |
| this.parentElement.classList.add('input-filled'); | |
| }); | |
| input.addEventListener('blur', function() { | |
| if (!this.value) { | |
| this.parentElement.classList.remove('input-filled'); | |
| } | |
| }); | |
| }); | |
| // Form navigation | |
| let currentStep = 1; | |
| const totalSteps = 3; | |
| // Next step button | |
| document.querySelectorAll('.next-step').forEach(button => { | |
| button.addEventListener('click', function() { | |
| if (validateStep(currentStep)) { | |
| showStep(currentStep + 1); | |
| } | |
| }); | |
| }); | |
| // Previous step button | |
| document.querySelectorAll('.prev-step').forEach(button => { | |
| button.addEventListener('click', function() { | |
| showStep(currentStep - 1); | |
| }); | |
| }); | |
| function showStep(step) { | |
| // Hide all step contents | |
| document.querySelectorAll('.step-content').forEach(content => { | |
| content.classList.add('hidden'); | |
| }); | |
| // Show current step content | |
| document.querySelector(`.step-content[data-step="${step}"]`).classList.remove('hidden'); | |
| // Update progress steps | |
| document.querySelectorAll('.step').forEach(stepElement => { | |
| const stepNumber = parseInt(stepElement.dataset.step); | |
| const circle = stepElement.querySelector('div'); | |
| const text = stepElement.querySelector('span:last-child'); | |
| if (stepNumber < step) { | |
| circle.classList.remove('bg-gray-200', 'text-gray-600'); | |
| circle.classList.add('bg-green-500', 'text-white'); | |
| text.classList.remove('text-gray-500'); | |
| text.classList.add('text-green-600'); | |
| } else if (stepNumber === step) { | |
| circle.classList.remove('bg-gray-200', 'text-gray-600', 'bg-green-500'); | |
| circle.classList.add('bg-blue-600', 'text-white'); | |
| text.classList.remove('text-gray-500', 'text-green-600'); | |
| text.classList.add('text-blue-600'); | |
| } else { | |
| circle.classList.remove('bg-blue-600', 'bg-green-500', 'text-white'); | |
| circle.classList.add('bg-gray-200', 'text-gray-600'); | |
| text.classList.remove('text-blue-600', 'text-green-600'); | |
| text.classList.add('text-gray-500'); | |
| } | |
| }); | |
| // Update current step | |
| currentStep = step; | |
| // For review step, populate the review fields | |
| if (currentStep === 3) { | |
| document.getElementById('reviewStudentId').textContent = document.getElementById('studentId').value; | |
| document.getElementById('reviewFullName').textContent = document.getElementById('fullName').value; | |
| document.getElementById('reviewDepartment').textContent = document.getElementById('department').value; | |
| document.getElementById('reviewContactNumber').textContent = document.getElementById('contactNumber').value; | |
| document.getElementById('reviewLeaveType').textContent = document.getElementById('leaveType').value; | |
| const startDate = new Date(document.getElementById('startDate').value); | |
| const endDate = new Date(document.getElementById('endDate').value); | |
| const options = { year: 'numeric', month: 'long', day: 'numeric' }; | |
| document.getElementById('reviewLeavePeriod').textContent = | |
| `${startDate.toLocaleDateString('en-US', options)} to ${endDate.toLocaleDateString('en-US', options)}`; | |
| document.getElementById('reviewDaysRequested').textContent = document.getElementById('daysRequested').value; | |
| document.getElementById('reviewReason').textContent = document.getElementById('reason').value; | |
| } | |
| } | |
| function validateStep(step) { | |
| let isValid = true; | |
| if (step === 1) { | |
| const requiredFields = ['studentId', 'fullName', 'department', 'contactNumber']; | |
| requiredFields.forEach(fieldId => { | |
| const field = document.getElementById(fieldId); | |
| if (!field.value) { | |
| field.classList.add('border-red-500'); | |
| isValid = false; | |
| } else { | |
| field.classList.remove('border-red-500'); | |
| } | |
| }); | |
| // Simple phone number validation | |
| const phone = document.getElementById('contactNumber').value; | |
| if (phone && !/^[\d\s\-+]{8,15}$/.test(phone)) { | |
| document.getElementById('contactNumber').classList.add('border-red-500'); | |
| isValid = false; | |
| } | |
| } else if (step === 2) { | |
| const requiredFields = ['leaveType', 'startDate', 'endDate', 'daysRequested', 'reason']; | |
| requiredFields.forEach(fieldId => { | |
| const field = document.getElementById(fieldId); | |
| if (!field.value) { | |
| field.classList.add('border-red-500'); | |
| isValid = false; | |
| } else { | |
| field.classList.remove('border-red-500'); | |
| } | |
| }); | |
| // Date validation | |
| const startDate = new Date(document.getElementById('startDate').value); | |
| const endDate = new Date(document.getElementById('endDate').value); | |
| if (startDate && endDate && startDate > endDate) { | |
| document.getElementById('startDate').classList.add('border-red-500'); | |
| document.getElementById('endDate').classList.add('border-red-500'); | |
| isValid = false; | |
| } | |
| } | |
| if (!isValid) { | |
| // Scroll to first error | |
| const firstError = document.querySelector('.border-red-500'); | |
| if (firstError) { | |
| firstError.scrollIntoView({ behavior: 'smooth', block: 'center' }); | |
| } | |
| } | |
| return isValid; | |
| } | |
| // Form submission | |
| document.getElementById('leaveForm').addEventListener('submit', function(e) { | |
| e.preventDefault(); | |
| if (validateStep(currentStep) && document.getElementById('terms').checked) { | |
| // In a real application, you would send the data to the server here | |
| // For this demo, we'll just show the success modal | |
| document.getElementById('successModal').classList.remove('hidden'); | |
| } else if (!document.getElementById('terms').checked) { | |
| document.getElementById('terms').nextElementSibling.classList.add('text-red-500'); | |
| } | |
| }); | |
| // Close modal | |
| document.getElementById('closeModal').addEventListener('click', function() { | |
| document.getElementById('successModal').classList.add('hidden'); | |
| // Reset form | |
| document.getElementById('leaveForm').reset(); | |
| // Reset all input-filled classes | |
| document.querySelectorAll('.input-container').forEach(container => { | |
| container.classList.remove('input-filled'); | |
| }); | |
| // Go back to step 1 | |
| showStep(1); | |
| }); | |
| // Calculate days requested when dates change | |
| const startDateInput = document.getElementById('startDate'); | |
| const endDateInput = document.getElementById('endDate'); | |
| const daysRequestedInput = document.getElementById('daysRequested'); | |
| function calculateDays() { | |
| if (startDateInput.value && endDateInput.value) { | |
| const startDate = new Date(startDateInput.value); | |
| const endDate = new Date(endDateInput.value); | |
| const diffTime = Math.abs(endDate - startDate); | |
| const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1; // +1 to include both start and end dates | |
| daysRequestedInput.value = diffDays; | |
| } | |
| } | |
| startDateInput.addEventListener('change', calculateDays); | |
| endDateInput.addEventListener('change', calculateDays); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=LOHITT49/leave-application" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |