SolarumAsteridion commited on
Commit
1eac0d3
·
verified ·
1 Parent(s): 01baaf3

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +110 -87
index.html CHANGED
@@ -341,40 +341,32 @@
341
  </style>
342
  </head>
343
  <body>
344
- <!-- Animated particles background -->
345
  <div class="particles" id="particles"></div>
346
-
347
  <div class="container">
348
  <div class="header">
349
  <h1>Exam Countdown</h1>
350
- <div class="settings-btn" onclick="openModal()">
351
  <svg viewBox="0 0 24 24">
352
  <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"/>
353
  </svg>
354
  </div>
355
  </div>
356
-
357
- <div class="exams-grid" id="examsGrid">
358
- <!-- Exam cards will be inserted here -->
359
- </div>
360
-
361
  <div class="empty-state" id="emptyState" style="display: none;">
362
  <p>No exams scheduled yet. Click the + button to add your first exam!</p>
363
  </div>
364
  </div>
365
-
366
- <!-- Add Exam Modal -->
367
  <div class="modal" id="modal">
368
  <div class="modal-content">
369
  <div class="modal-header">
370
  <h2 class="modal-title">Add New Exam</h2>
371
- <button class="close-btn" onclick="closeModal()">
372
  <svg width="24" height="24" viewBox="0 0 24 24" fill="#fff">
373
  <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"/>
374
  </svg>
375
  </button>
376
  </div>
377
- <form onsubmit="addExam(event)">
378
  <div class="form-group">
379
  <label for="examName">Exam Name</label>
380
  <input type="text" id="examName" required placeholder="e.g., Physics Final">
@@ -388,10 +380,39 @@
388
  </div>
389
  </div>
390
 
391
- <script>
392
- // Initialize particles
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  function createParticles() {
394
  const particlesContainer = document.getElementById('particles');
 
395
  for (let i = 0; i < 50; i++) {
396
  const particle = document.createElement('div');
397
  particle.className = 'particle';
@@ -402,120 +423,122 @@
402
  }
403
  }
404
 
405
- // Load exams from localStorage
406
- let exams = JSON.parse(localStorage.getItem('exams')) || [];
 
407
 
408
- // Modal functions
409
- function openModal() {
410
- document.getElementById('modal').classList.add('active');
411
- }
412
-
413
- function closeModal() {
414
- document.getElementById('modal').classList.remove('active');
415
- document.getElementById('examName').value = '';
416
- document.getElementById('examDate').value = '';
417
- }
418
-
419
- // Add exam
420
  function addExam(event) {
421
  event.preventDefault();
422
- const name = document.getElementById('examName').value;
423
- const date = document.getElementById('examDate').value;
424
-
425
- const exam = {
426
- id: Date.now(),
427
- name,
428
- date
429
- };
430
-
431
- exams.push(exam);
432
- localStorage.setItem('exams', JSON.stringify(exams));
433
  closeModal();
434
- renderExams();
435
  }
436
 
437
- // Delete exam
438
  function deleteExam(id) {
439
- exams = exams.filter(exam => exam.id !== id);
440
- localStorage.setItem('exams', JSON.stringify(exams));
441
- renderExams();
442
  }
443
 
444
- // Calculate days until exam
445
  function calculateDaysUntil(examDate) {
446
  const today = new Date();
 
447
  const exam = new Date(examDate);
448
- const diffTime = exam - today;
449
- const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
450
- return diffDays;
451
  }
452
 
453
- // Render exams
454
- function renderExams() {
455
  const grid = document.getElementById('examsGrid');
456
  const emptyState = document.getElementById('emptyState');
457
-
458
  grid.innerHTML = '';
459
 
460
- if (exams.length === 0) {
461
  emptyState.style.display = 'block';
462
  return;
463
  }
464
 
465
  emptyState.style.display = 'none';
466
-
467
- // Sort exams by date
468
- const sortedExams = [...exams].sort((a, b) => new Date(a.date) - new Date(b.date));
469
 
470
  sortedExams.forEach(exam => {
471
  const daysUntil = calculateDaysUntil(exam.date);
472
  const card = document.createElement('div');
473
  card.className = 'exam-card';
474
-
475
- let countdownColor = '#00D4FF';
476
- if (daysUntil <= 3) countdownColor = '#FF0080';
477
- else if (daysUntil <= 7) countdownColor = '#00FF88';
478
 
479
  card.innerHTML = `
480
- <div class="delete-btn" onclick="deleteExam(${exam.id})">
481
- <svg width="16" height="16" viewBox="0 0 24 24" fill="#FF0080">
482
- <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/>
483
- </svg>
484
  </div>
485
  <h3 class="exam-name">${exam.name}</h3>
486
- <div class="countdown" style="color: ${countdownColor}; text-shadow: 0 0 20px ${countdownColor}80;">
487
- ${daysUntil}
488
- </div>
489
  <div class="countdown-label">days remaining</div>
490
- <div class="exam-date">${new Date(exam.date).toLocaleDateString('en-US', {
491
- weekday: 'long',
492
- year: 'numeric',
493
- month: 'long',
494
- day: 'numeric'
495
- })}</div>
496
- `;
497
 
 
498
  grid.appendChild(card);
499
  });
500
  }
 
 
 
 
 
 
 
 
 
 
 
 
501
 
502
- // Set minimum date to today
503
- document.getElementById('examDate').min = new Date().toISOString().split('T')[0];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
 
505
- // Initialize
506
  createParticles();
507
- renderExams();
508
-
509
- // Update countdown every day
510
- setInterval(renderExams, 86400000);
511
-
512
- // Close modal on outside click
513
- window.onclick = function(event) {
514
- const modal = document.getElementById('modal');
515
- if (event.target === modal) {
516
- closeModal();
 
 
 
 
 
517
  }
518
- }
 
 
519
  </script>
520
  </body>
521
  </html>
 
341
  </style>
342
  </head>
343
  <body>
 
344
  <div class="particles" id="particles"></div>
 
345
  <div class="container">
346
  <div class="header">
347
  <h1>Exam Countdown</h1>
348
+ <div class="settings-btn" id="openModalBtn">
349
  <svg viewBox="0 0 24 24">
350
  <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"/>
351
  </svg>
352
  </div>
353
  </div>
354
+ <div class="exams-grid" id="examsGrid"></div>
 
 
 
 
355
  <div class="empty-state" id="emptyState" style="display: none;">
356
  <p>No exams scheduled yet. Click the + button to add your first exam!</p>
357
  </div>
358
  </div>
 
 
359
  <div class="modal" id="modal">
360
  <div class="modal-content">
361
  <div class="modal-header">
362
  <h2 class="modal-title">Add New Exam</h2>
363
+ <button class="close-btn" id="closeModalBtn">
364
  <svg width="24" height="24" viewBox="0 0 24 24" fill="#fff">
365
  <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"/>
366
  </svg>
367
  </button>
368
  </div>
369
+ <form id="addExamForm">
370
  <div class="form-group">
371
  <label for="examName">Exam Name</label>
372
  <input type="text" id="examName" required placeholder="e.g., Physics Final">
 
380
  </div>
381
  </div>
382
 
383
+ <script type="module">
384
+ // Import the functions you need from the SDKs you need
385
+ import { initializeApp } from "https://www.gstatic.com/firebasejs/10.7.0/firebase-app.js";
386
+ import { getDatabase, ref, onValue, push, remove, child } from "https://www.gstatic.com/firebasejs/10.7.0/firebase-database.js";
387
+
388
+ // Your web app's Firebase configuration
389
+ const firebaseConfig = {
390
+ apiKey: "AIzaSyCBGYdGdPjYJiKsTMjVYZ9mf9F82ns7g4Q",
391
+ authDomain: "pikachu-rxppbp.firebaseapp.com",
392
+ databaseURL: "https://pikachu-rxppbp.firebaseio.com",
393
+ projectId: "pikachu-rxppbp",
394
+ storageBucket: "pikachu-rxppbp.appspot.com",
395
+ messagingSenderId: "241970333280",
396
+ appId: "1:241970333280:web:704e8930bd591c138d6505"
397
+ };
398
+
399
+ // Initialize Firebase
400
+ const app = initializeApp(firebaseConfig);
401
+ const database = getDatabase(app);
402
+ const examsRef = ref(database, 'exams');
403
+
404
+ // --- DOM Elements ---
405
+ const openModalBtn = document.getElementById('openModalBtn');
406
+ const closeModalBtn = document.getElementById('closeModalBtn');
407
+ const modal = document.getElementById('modal');
408
+ const addExamForm = document.getElementById('addExamForm');
409
+ const examNameInput = document.getElementById('examName');
410
+ const examDateInput = document.getElementById('examDate');
411
+
412
+ // --- Particle Background ---
413
  function createParticles() {
414
  const particlesContainer = document.getElementById('particles');
415
+ if (particlesContainer.children.length > 0) return;
416
  for (let i = 0; i < 50; i++) {
417
  const particle = document.createElement('div');
418
  particle.className = 'particle';
 
423
  }
424
  }
425
 
426
+ // --- Modal ---
427
+ function openModal() { modal.classList.add('active'); }
428
+ function closeModal() { modal.classList.remove('active'); addExamForm.reset(); }
429
 
430
+ // --- Firebase Data Operations ---
 
 
 
 
 
 
 
 
 
 
 
431
  function addExam(event) {
432
  event.preventDefault();
433
+ const newExam = { name: examNameInput.value, date: examDateInput.value };
434
+ push(examsRef, newExam);
 
 
 
 
 
 
 
 
 
435
  closeModal();
 
436
  }
437
 
 
438
  function deleteExam(id) {
439
+ remove(child(examsRef, id));
 
 
440
  }
441
 
442
+ // --- Rendering Logic ---
443
  function calculateDaysUntil(examDate) {
444
  const today = new Date();
445
+ today.setHours(0, 0, 0, 0);
446
  const exam = new Date(examDate);
447
+ return Math.ceil((exam - today) / (1000 * 60 * 60 * 24));
 
 
448
  }
449
 
450
+ function renderExams(examsList) {
 
451
  const grid = document.getElementById('examsGrid');
452
  const emptyState = document.getElementById('emptyState');
 
453
  grid.innerHTML = '';
454
 
455
+ if (!examsList || examsList.length === 0) {
456
  emptyState.style.display = 'block';
457
  return;
458
  }
459
 
460
  emptyState.style.display = 'none';
461
+ const sortedExams = [...examsList].sort((a, b) => new Date(a.date) - new Date(b.date));
 
 
462
 
463
  sortedExams.forEach(exam => {
464
  const daysUntil = calculateDaysUntil(exam.date);
465
  const card = document.createElement('div');
466
  card.className = 'exam-card';
467
+ let color = daysUntil <= 3 ? '#FF0080' : (daysUntil <= 7 ? '#00FF88' : '#00D4FF');
 
 
 
468
 
469
  card.innerHTML = `
470
+ <div class="delete-btn">
471
+ <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>
 
 
472
  </div>
473
  <h3 class="exam-name">${exam.name}</h3>
474
+ <div class="countdown" style="color: ${color}; text-shadow: 0 0 20px ${color}80;">${daysUntil}</div>
 
 
475
  <div class="countdown-label">days remaining</div>
476
+ <div class="exam-date">${new Date(exam.date).toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}</div>`;
 
 
 
 
 
 
477
 
478
+ card.querySelector('.delete-btn').addEventListener('click', () => deleteExam(exam.id));
479
  grid.appendChild(card);
480
  });
481
  }
482
+
483
+ // ===================================================================================
484
+ // ONE-TIME MANUAL IMPORT FUNCTION
485
+ // TO USE: Open developer console (F12) and type `runManualImport()` then press Enter.
486
+ // AFTER RUNNING ONCE, DELETE THIS ENTIRE FUNCTION.
487
+ // ===================================================================================
488
+ window.runManualImport = function() {
489
+ const localExamsJSON = localStorage.getItem('exams');
490
+ if (!localExamsJSON) {
491
+ console.log("No data found in LocalStorage. Nothing to import.");
492
+ return;
493
+ }
494
 
495
+ try {
496
+ const localExams = JSON.parse(localExamsJSON);
497
+ if (Array.isArray(localExams) && localExams.length > 0) {
498
+ console.log(`Found ${localExams.length} exams in LocalStorage. Importing...`);
499
+
500
+ const importPromises = localExams.map(exam => {
501
+ const examToPush = { name: exam.name, date: exam.date };
502
+ return push(examsRef, examToPush);
503
+ });
504
+
505
+ Promise.all(importPromises).then(() => {
506
+ console.log("SUCCESS: All exams have been imported to Firebase.");
507
+ alert("Import complete! Your data is now in Firebase. You can now delete the runManualImport function from your code.");
508
+ });
509
+ } else {
510
+ console.log("LocalStorage data is empty or invalid. Nothing to import.");
511
+ }
512
+ } catch (error) {
513
+ console.error("FAILED to parse or import from LocalStorage:", error);
514
+ alert("Import failed. Check the console for errors.");
515
+ }
516
+ };
517
+ // ===================================================================================
518
+ // END OF IMPORT FUNCTION - REMOVE AFTER USE
519
+ // ===================================================================================
520
 
521
+ // --- INITIALIZATION & EVENT LISTENERS ---
522
  createParticles();
523
+ examDateInput.min = new Date().toISOString().split('T')[0];
524
+
525
+ openModalBtn.addEventListener('click', openModal);
526
+ closeModalBtn.addEventListener('click', closeModal);
527
+ addExamForm.addEventListener('submit', addExam);
528
+ window.addEventListener('click', (event) => {
529
+ if (event.target === modal) closeModal();
530
+ });
531
+
532
+ // Real-time listener for Firebase data
533
+ onValue(examsRef, (snapshot) => {
534
+ const examsData = snapshot.val();
535
+ const examsList = [];
536
+ for (let id in examsData) {
537
+ examsList.push({ id, ...examsData[id] });
538
  }
539
+ renderExams(examsList);
540
+ });
541
+
542
  </script>
543
  </body>
544
  </html>