Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Neon Exam Countdown</title> | |
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap" rel="stylesheet"> | |
<style> | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
body { | |
font-family: 'Inter', sans-serif; | |
background: linear-gradient(135deg, #0A0A0B 0%, #141419 100%); | |
min-height: 100vh; | |
color: #fff; | |
overflow-x: hidden; | |
position: relative; | |
} | |
/* Animated background */ | |
.particles { | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
overflow: hidden; | |
z-index: 1; | |
} | |
.particle { | |
position: absolute; | |
width: 4px; | |
height: 4px; | |
background: radial-gradient(circle, rgba(0, 212, 255, 0.5) 0%, transparent 70%); | |
border-radius: 50%; | |
animation: float 20s infinite linear; | |
} | |
@keyframes float { | |
from { | |
transform: translateY(100vh) translateX(0); | |
opacity: 0; | |
} | |
10% { | |
opacity: 1; | |
} | |
90% { | |
opacity: 1; | |
} | |
to { | |
transform: translateY(-100vh) translateX(100px); | |
opacity: 0; | |
} | |
} | |
/* Main container */ | |
.container { | |
max-width: 1200px; | |
margin: 0 auto; | |
padding: 2rem; | |
position: relative; | |
z-index: 2; | |
} | |
/* Header */ | |
.header { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-bottom: 3rem; | |
} | |
h1 { | |
font-size: 2.5rem; | |
font-weight: 700; | |
background: linear-gradient(135deg, #00D4FF 0%, #FF0080 50%, #00FF88 100%); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
background-clip: text; | |
text-shadow: 0 0 30px rgba(0, 212, 255, 0.5); | |
} | |
/* Settings button */ | |
.settings-btn { | |
width: 50px; | |
height: 50px; | |
background: rgba(255, 255, 255, 0.05); | |
backdrop-filter: blur(10px); | |
border: 1px solid rgba(255, 255, 255, 0.1); | |
border-radius: 12px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
} | |
.settings-btn:hover { | |
background: rgba(255, 255, 255, 0.1); | |
border-color: #00D4FF; | |
box-shadow: 0 0 20px rgba(0, 212, 255, 0.5); | |
transform: scale(1.05); | |
} | |
.settings-btn svg { | |
width: 24px; | |
height: 24px; | |
fill: #00D4FF; | |
} | |
/* Exam cards grid */ | |
.exams-grid { | |
display: grid; | |
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
gap: 2rem; | |
} | |
/* Exam card */ | |
.exam-card { | |
background: rgba(255, 255, 255, 0.05); | |
backdrop-filter: blur(20px); | |
border: 1px solid rgba(255, 255, 255, 0.1); | |
border-radius: 20px; | |
padding: 2rem; | |
text-align: center; | |
transition: all 0.3s ease; | |
position: relative; | |
overflow: hidden; | |
} | |
.exam-card::before { | |
content: ''; | |
position: absolute; | |
top: -2px; | |
left: -2px; | |
right: -2px; | |
bottom: -2px; | |
background: linear-gradient(45deg, #00D4FF, #FF0080, #00FF88, #00D4FF); | |
border-radius: 20px; | |
opacity: 0; | |
z-index: -1; | |
transition: opacity 0.3s ease; | |
} | |
.exam-card:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 10px 30px rgba(0, 212, 255, 0.3); | |
} | |
.exam-card:hover::before { | |
opacity: 0.5; | |
} | |
.exam-name { | |
font-size: 1.5rem; | |
font-weight: 600; | |
margin-bottom: 1rem; | |
color: #fff; | |
} | |
.countdown { | |
font-size: 3rem; | |
font-weight: 700; | |
color: #00D4FF; | |
text-shadow: 0 0 20px rgba(0, 212, 255, 0.8); | |
margin-bottom: 0.5rem; | |
} | |
.countdown-label { | |
font-size: 1rem; | |
color: rgba(255, 255, 255, 0.7); | |
} | |
.exam-date { | |
font-size: 0.9rem; | |
color: rgba(255, 255, 255, 0.5); | |
margin-top: 1rem; | |
} | |
.delete-btn { | |
position: absolute; | |
top: 1rem; | |
right: 1rem; | |
width: 30px; | |
height: 30px; | |
background: rgba(255, 0, 128, 0.2); | |
border: 1px solid rgba(255, 0, 128, 0.5); | |
border-radius: 8px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
opacity: 0; | |
} | |
.exam-card:hover .delete-btn { | |
opacity: 1; | |
} | |
.delete-btn:hover { | |
background: rgba(255, 0, 128, 0.4); | |
transform: scale(1.1); | |
} | |
/* Modal */ | |
.modal { | |
display: none; | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background: rgba(0, 0, 0, 0.8); | |
z-index: 1000; | |
align-items: center; | |
justify-content: center; | |
padding: 2rem; | |
} | |
.modal.active { | |
display: flex; | |
} | |
.modal-content { | |
background: rgba(20, 20, 25, 0.95); | |
backdrop-filter: blur(20px); | |
border: 1px solid rgba(255, 255, 255, 0.1); | |
border-radius: 20px; | |
padding: 2rem; | |
width: 100%; | |
max-width: 400px; | |
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5); | |
} | |
.modal-header { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-bottom: 2rem; | |
} | |
.modal-title { | |
font-size: 1.5rem; | |
font-weight: 600; | |
} | |
.close-btn { | |
width: 30px; | |
height: 30px; | |
background: transparent; | |
border: none; | |
cursor: pointer; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
transition: transform 0.3s ease; | |
} | |
.close-btn:hover { | |
transform: rotate(90deg); | |
} | |
.form-group { | |
margin-bottom: 1.5rem; | |
} | |
label { | |
display: block; | |
margin-bottom: 0.5rem; | |
color: rgba(255, 255, 255, 0.8); | |
font-size: 0.9rem; | |
} | |
input { | |
width: 100%; | |
padding: 0.75rem 1rem; | |
background: rgba(255, 255, 255, 0.05); | |
border: 1px solid rgba(255, 255, 255, 0.2); | |
border-radius: 10px; | |
color: #fff; | |
font-size: 1rem; | |
transition: all 0.3s ease; | |
} | |
input:focus { | |
outline: none; | |
border-color: #00D4FF; | |
box-shadow: 0 0 10px rgba(0, 212, 255, 0.5); | |
} | |
.add-btn { | |
width: 100%; | |
padding: 1rem; | |
background: linear-gradient(135deg, #00D4FF 0%, #FF0080 100%); | |
border: none; | |
border-radius: 10px; | |
color: #fff; | |
font-size: 1rem; | |
font-weight: 600; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
} | |
.add-btn:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 5px 20px rgba(0, 212, 255, 0.5); | |
} | |
/* Empty state */ | |
.empty-state { | |
text-align: center; | |
padding: 4rem 2rem; | |
} | |
.empty-state p { | |
font-size: 1.2rem; | |
color: rgba(255, 255, 255, 0.5); | |
margin-bottom: 2rem; | |
} | |
/* Responsive */ | |
@media (max-width: 768px) { | |
h1 { | |
font-size: 2rem; | |
} | |
.exams-grid { | |
grid-template-columns: 1fr; | |
} | |
.countdown { | |
font-size: 2.5rem; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<!-- Animated particles background --> | |
<div class="particles" id="particles"></div> | |
<div class="container"> | |
<div class="header"> | |
<h1>Exam Countdown</h1> | |
<div class="settings-btn" onclick="openModal()"> | |
<svg viewBox="0 0 24 24"> | |
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"/> | |
</svg> | |
</div> | |
</div> | |
<div class="exams-grid" id="examsGrid"> | |
<!-- Exam cards will be inserted here --> | |
</div> | |
<div class="empty-state" id="emptyState" style="display: none;"> | |
<p>No exams scheduled yet. Click the + button to add your first exam!</p> | |
</div> | |
</div> | |
<!-- Add Exam Modal --> | |
<div class="modal" id="modal"> | |
<div class="modal-content"> | |
<div class="modal-header"> | |
<h2 class="modal-title">Add New Exam</h2> | |
<button class="close-btn" onclick="closeModal()"> | |
<svg width="24" height="24" viewBox="0 0 24 24" fill="#fff"> | |
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/> | |
</svg> | |
</button> | |
</div> | |
<form onsubmit="addExam(event)"> | |
<div class="form-group"> | |
<label for="examName">Exam Name</label> | |
<input type="text" id="examName" required placeholder="e.g., Physics Final"> | |
</div> | |
<div class="form-group"> | |
<label for="examDate">Exam Date</label> | |
<input type="date" id="examDate" required> | |
</div> | |
<button type="submit" class="add-btn">Add Exam</button> | |
</form> | |
</div> | |
</div> | |
<script> | |
// Initialize particles | |
function createParticles() { | |
const particlesContainer = document.getElementById('particles'); | |
for (let i = 0; i < 50; i++) { | |
const particle = document.createElement('div'); | |
particle.className = 'particle'; | |
particle.style.left = Math.random() * 100 + '%'; | |
particle.style.animationDelay = Math.random() * 20 + 's'; | |
particle.style.animationDuration = (15 + Math.random() * 10) + 's'; | |
particlesContainer.appendChild(particle); | |
} | |
} | |
// Load exams from localStorage | |
let exams = JSON.parse(localStorage.getItem('exams')) || []; | |
// Modal functions | |
function openModal() { | |
document.getElementById('modal').classList.add('active'); | |
} | |
function closeModal() { | |
document.getElementById('modal').classList.remove('active'); | |
document.getElementById('examName').value = ''; | |
document.getElementById('examDate').value = ''; | |
} | |
// Add exam | |
function addExam(event) { | |
event.preventDefault(); | |
const name = document.getElementById('examName').value; | |
const date = document.getElementById('examDate').value; | |
const exam = { | |
id: Date.now(), | |
name, | |
date | |
}; | |
exams.push(exam); | |
localStorage.setItem('exams', JSON.stringify(exams)); | |
closeModal(); | |
renderExams(); | |
} | |
// Delete exam | |
function deleteExam(id) { | |
exams = exams.filter(exam => exam.id !== id); | |
localStorage.setItem('exams', JSON.stringify(exams)); | |
renderExams(); | |
} | |
// Calculate days until exam | |
function calculateDaysUntil(examDate) { | |
const today = new Date(); | |
const exam = new Date(examDate); | |
const diffTime = exam - today; | |
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); | |
return diffDays; | |
} | |
// Render exams | |
function renderExams() { | |
const grid = document.getElementById('examsGrid'); | |
const emptyState = document.getElementById('emptyState'); | |
grid.innerHTML = ''; | |
if (exams.length === 0) { | |
emptyState.style.display = 'block'; | |
return; | |
} | |
emptyState.style.display = 'none'; | |
// Sort exams by date | |
const sortedExams = [...exams].sort((a, b) => new Date(a.date) - new Date(b.date)); | |
sortedExams.forEach(exam => { | |
const daysUntil = calculateDaysUntil(exam.date); | |
const card = document.createElement('div'); | |
card.className = 'exam-card'; | |
let countdownColor = '#00D4FF'; | |
if (daysUntil <= 3) countdownColor = '#FF0080'; | |
else if (daysUntil <= 7) countdownColor = '#00FF88'; | |
card.innerHTML = ` | |
<div class="delete-btn" onclick="deleteExam(${exam.id})"> | |
<svg width="16" height="16" viewBox="0 0 24 24" fill="#FF0080"> | |
<path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/> | |
</svg> | |
</div> | |
<h3 class="exam-name">${exam.name}</h3> | |
<div class="countdown" style="color: ${countdownColor}; text-shadow: 0 0 20px ${countdownColor}80;"> | |
${daysUntil} | |
</div> | |
<div class="countdown-label">days remaining</div> | |
<div class="exam-date">${new Date(exam.date).toLocaleDateString('en-US', { | |
weekday: 'long', | |
year: 'numeric', | |
month: 'long', | |
day: 'numeric' | |
})}</div> | |
`; | |
grid.appendChild(card); | |
}); | |
} | |
// Set minimum date to today | |
document.getElementById('examDate').min = new Date().toISOString().split('T')[0]; | |
// Initialize | |
createParticles(); | |
renderExams(); | |
// Update countdown every day | |
setInterval(renderExams, 86400000); | |
// Close modal on outside click | |
window.onclick = function(event) { | |
const modal = document.getElementById('modal'); | |
if (event.target === modal) { | |
closeModal(); | |
} | |
} | |
</script> | |
</body> | |
</html> |