Skip to content

Commit

Permalink
Merge pull request #33 from kewonit/custom-exams-to-custom-timekeeper
Browse files Browse the repository at this point in the history
added custom exams to custom timekeeper
  • Loading branch information
kewonit authored Jul 16, 2024
2 parents 64e7ee7 + dc05ddb commit 92181cc
Show file tree
Hide file tree
Showing 9 changed files with 478 additions and 136 deletions.
17 changes: 6 additions & 11 deletions src/components/Footer.astro
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,13 @@ const today = new Date();
gtag("config", "G-M4LCZ4JGCV");
</script>
</body>
<footer class="footer footer-center p-4 bg-base-300 text-base-content">
<div>
<p class="max-w-screen-lg">
It is strongly recommended to double-check the information provided on
this website with official sources to ensure its accuracy. This website
holds no responsibility for any damages, losses, or inconveniences arising
from the use of its services.
<footer>
<div class="py-8 px-8 border-t border-gray-600">
<p class="text-sm text-gray-500">
&copy; {new Date().getFullYear()}. TimeKeeper | Built by <a href="https://github.com/kewonit" class="text-blue-300">Kewonit</a> | Repo on <a href="https://github.com/kewonit/Timekeeper" class="text-blue-300">Github</a>
</p>
<p>
Built by KewKartik | <a
href="https://github.com/kewkartik">Github</a
>
<p class="text-xs text-gray-500">
It is strongly recommended to double-check the information provided on this website with official sources to ensure its accuracy. This website holds no responsibility for any damages, losses, or inconveniences arising from the use of its services.
</p>
</div>
</footer>
Expand Down
15 changes: 9 additions & 6 deletions src/components/Head.astro
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<meta charset="UTF-8" />
<title>
JeeNeeTards Countdown/Timer for Exams like JEE, NEET, BITSAT 2023/2024/2025
JeeNeeTards Countdown/Timer for Exams like JEE, NEET, BITSAT 2023/2024/2025/2026
</title>
<meta
name="description"
content="JeeNeeTards Countdown/Timer for Exams like JEE, NEET, BITSAT 2023/2024/2025"
content="JEE NEET BITSAT Exam Countdown Timer 2023/2024/2025 | JeeNeeTards: Your Ultimate Preparation TimeKeeper Tool for JEE Main, JEE Advanced, NEET-UG, and BITSAT. Stay Motivated with Real-Time Countdowns. Ace Your Entrance Exams!"
/>
<link rel="icon" type="image/x-icon" href="../favicon.ico" />
<meta name="generator" content={Astro.generator} />
Expand Down Expand Up @@ -41,11 +41,14 @@
<li><a href="../exams/neet">NEET</a></li>
<li><a href="../exams/bitsat">BITSAT</a></li>
<li><a href="../exams/mhtcet">MHT-CET</a></li>
<hr />
<li><a href="../eleventh/eleventh">2026</a></li>
<hr />
<hr class="border-gray-600"/>
<li class="bg-pink-200 text-black">
<a href="../eleventh/eleventh">2026</a>
</li>
<hr class="border-gray-600"/>
<li><a id="popup-button">motivation</a></li>
<li>
<hr class="border-gray-600"/>
<li class="bg-cyan-200 text-black">
<a target="_blank" href="https://www.reddit.com/r/mht_cet/"
>r/mht_cet</a
>
Expand Down
245 changes: 245 additions & 0 deletions src/components/custom-minibar.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
<script>
import { onMount } from 'svelte';
import examsData from '../data/2025.json';
let year = 2025;
let { exams } = examsData;
let countdowns = [];
let showAddForm = false;
let availableExams = [];
const pageName = window.location.pathname.split('/').filter(Boolean).pop() || 'home';
const getStorageKey = (key) => `${pageName}_${key}`;
const colorOptions = [
{ name: 'Rose', value: 'rose-300' },
{ name: 'Blue', value: 'blue-500' },
{ name: 'Green', value: 'green-500' },
{ name: 'Yellow', value: 'yellow-500' },
{ name: 'Purple', value: 'purple-500' },
{ name: 'Pink', value: 'pink-500' },
{ name: 'Indigo', value: 'indigo-500' },
{ name: 'Teal', value: 'teal-500' },
{ name: 'Orange', value: 'orange-500' },
{ name: 'Cyan', value: 'cyan-500' },
];
const createEventObject = (exam) => ({
name: `${exam.name} ${exam.year || year}`,
date: new Date(`${exam.month} ${exam.day}, ${exam.year || year} 00:00:00`).getTime(),
color: exam.color
});
const initializeCountdowns = () => {
let savedCountdowns = JSON.parse(localStorage.getItem(getStorageKey('countdowns')));
let savedAvailableExams = JSON.parse(localStorage.getItem(getStorageKey('availableExams')));
let savedYear = localStorage.getItem(getStorageKey('year'));
if (savedYear) {
year = parseInt(savedYear);
} else {
year = 2025;
}
if (savedCountdowns && savedAvailableExams) {
countdowns = savedCountdowns;
availableExams = savedAvailableExams;
} else {
countdowns = exams.slice(0, 3).map((exam, index) => ({
...createEventObject(exam),
timerIdx: `${pageName}_timer${index + 1}`,
remaining: { days: 0, hours: 0, minutes: 0, seconds: 0 }
}));
availableExams = exams.slice(3);
}
};
const saveToLocalStorage = () => {
localStorage.setItem(getStorageKey('countdowns'), JSON.stringify(countdowns));
localStorage.setItem(getStorageKey('availableExams'), JSON.stringify(availableExams));
localStorage.setItem(getStorageKey('year'), year.toString());
};
onMount(() => {
initializeCountdowns();
const interval = setInterval(() => {
const now = new Date().getTime();
countdowns = countdowns.map(countdown => {
const distance = countdown.date - now;
if (distance > 0) {
return {
...countdown,
remaining: {
days: Math.floor(distance / (1000 * 60 * 60 * 24)),
hours: Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)),
minutes: Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)),
seconds: Math.floor((distance % (1000 * 60)) / 1000)
}
};
} else {
return { ...countdown, remaining: null };
}
});
saveToLocalStorage();
}, 1000);
return () => clearInterval(interval);
});
const toggleAddForm = () => {
showAddForm = !showAddForm;
};
const addExam = (event) => {
event.preventDefault();
const form = event.target;
const newExam = {
name: form.name.value,
month: form.month.value,
day: parseInt(form.day.value),
color: form.color.value,
year: parseInt(form.year.value)
};
const examObject = createEventObject(newExam);
countdowns = [...countdowns, {
...examObject,
timerIdx: `${pageName}_timer${countdowns.length + 1}`,
remaining: { days: 0, hours: 0, minutes: 0, seconds: 0 }
}];
availableExams = availableExams.filter(exam => exam.name !== newExam.name);
showAddForm = false;
saveToLocalStorage();
};
const removeExam = (index) => {
const removedExam = countdowns[index];
countdowns = countdowns.filter((_, i) => i !== index);
if (!availableExams.some(exam => exam.name === removedExam.name)) {
availableExams = [...availableExams, { name: removedExam.name.replace(` ${year}`, ''), month: new Date(removedExam.date).toLocaleString('default', { month: 'long' }), day: new Date(removedExam.date).getDate(), color: removedExam.color }];
}
saveToLocalStorage();
};
const addAvailableExam = (exam) => {
countdowns = [...countdowns, {...createEventObject(exam), timerIdx: `${pageName}_timer${countdowns.length + 1}`, remaining: { days: 0, hours: 0, minutes: 0, seconds: 0 }}];
availableExams = availableExams.filter(e => e.name !== exam.name);
saveToLocalStorage();
};
const removeAvailableExam = (index) => {
availableExams = availableExams.filter((_, i) => i !== index);
saveToLocalStorage();
};
const updateYear = (newYear) => {
year = parseInt(newYear);
countdowns = countdowns.map(countdown => ({
...countdown,
...createEventObject({
name: countdown.name.replace(/\d{4}$/, year),
month: new Date(countdown.date).toLocaleString('default', { month: 'long' }),
day: new Date(countdown.date).getDate(),
color: countdown.color
})
}));
saveToLocalStorage();
};
</script>

{#each Array(Math.ceil(countdowns.length / 3)) as _, rowIndex}
<div class="stats flex shadow border-y border-x border-gray-600">
{#each countdowns.slice(rowIndex * 3, rowIndex * 3 + 3) as countdown, index}
<div class="stat block relative group">
<button on:click={() => removeExam(rowIndex * 3 + index)} class="btn btn-sm btn-circle absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity">✕</button>
<div class="stat-figure">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="inline-block w-8 h-8 stroke-current text-{countdown.color}">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
</svg>
</div>
<div class="stat-title">
<p>{countdown.name}</p>
</div>
<div id={countdown.timerIdx} class="">
{#if countdown.remaining}
<div class="grid grid-flow-col gap-5 text-center auto-cols-max">
<div class="flex flex-col">
<span class="font-mono text-4xl">
<span style="--value:{countdown.remaining.days.toString().padStart(2, '0')};">{countdown.remaining.days.toString().padStart(2, '0')}</span>
</span>
days
</div>
<div class="flex flex-col">
<span class="countdown font-mono text-4xl">
<span style="--value:{countdown.remaining.hours.toString().padStart(2, '0')};">{countdown.remaining.hours.toString().padStart(2, '0')}</span>
</span>
hours
</div>
<div class="flex flex-col">
<span class="countdown font-mono text-4xl">
<span style="--value:{countdown.remaining.minutes.toString().padStart(2, '0')};">{countdown.remaining.minutes.toString().padStart(2, '0')}</span>
</span>
min
</div>
<div class="flex flex-col">
<span class="countdown font-mono text-4xl">
<span style="--value:{countdown.remaining.seconds.toString().padStart(2, '0')};">{countdown.remaining.seconds.toString().padStart(2, '0')}</span>
</span>
sec
</div>
</div>
{:else}
Best of Luck
{/if}
</div>
</div>
{/each}
</div>
{/each}

<div>
<button on:click={toggleAddForm} class="btn bg-[#212121] shadow border-y border-x border-gray-600 text-[#f1f5f9] hover:bg-[#f1f5f9]/40 h-8 rounded-md px-3 text-xs w-full mt-6 mb-6">
{showAddForm ? 'Cancel' : 'Add Exam'}
</button>
</div>

{#if showAddForm}
<form on:submit={addExam} class="mb-4 p-4 border rounded">
<div class="grid grid-cols-2 gap-4">
<input name="name" type="text" placeholder="Exam Name" required class="input input-bordered" />
<input name="month" type="text" placeholder="Month (Jan / Feb / Mar)" required class="input input-bordered" />
<input name="day" type="number" placeholder="Day" required class="input input-bordered" />
<select name="color" required class="select select-bordered">
<option value="">Select Color</option>
{#each colorOptions as color}
<option value={color.value}>{color.name}</option>
{/each}
</select>
<input
name="year"
type="number"
placeholder="Year"
bind:value={year}
class="input input-bordered"
/>
</div>
<button type="submit" class="btn btn-primary mt-4">Add Custom Exam</button>
</form>

{#if availableExams.length > 0}
<div class="my-4">
<h3 class="text-lg font-semibold mb-2">Available Exams:</h3>
<div class="flex flex-wrap gap-2">
{#each availableExams as exam, index}
<div class="relative group">
<button on:click={() => addAvailableExam(exam)} class="btn btn-sm btn-outline">
{exam.name}
</button>
<button on:click={() => removeAvailableExam(index)} class="btn btn-xs btn-circle absolute -top-2 -right-2 opacity-0 group-hover:opacity-100 transition-opacity">✕</button>
</div>
{/each}
</div>
</div>
{/if}
{/if}

19 changes: 11 additions & 8 deletions src/components/customcountdown.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
var timer = null;
var end;
var toZero;
var btn = document.getElementById("btn"); // The element ID should be "start-count" not "btn"
var oDay = document.getElementById("day");
var oHour = document.getElementById("hour");
var oMinute = document.getElementById("minute");
Expand All @@ -14,6 +13,8 @@
var storedEndtime = localStorage.getItem("endtime");
if (storedEndtime) {
endtime.value = storedEndtime;
// Automatically start the countdown if there's a stored endtime
startCountdown();
}
toZero =
Expand All @@ -23,7 +24,9 @@
oSecond.innerHTML =
"00";
startBtn.onclick = function () {
startBtn.onclick = startCountdown;
function startCountdown() {
end = endtime.value;
if (!end) {
alert("Please enter a date");
Expand All @@ -34,7 +37,7 @@
// Save the endtime in local storage
localStorage.setItem("endtime", end);
};
}
function countDown() {
var timedate = new Date(Date.parse(end.replace(/-/g, "/")));
Expand All @@ -49,12 +52,12 @@
var second = Math.floor(_second);
function toDou(n) {
if (n < 10) {
return "0" + n;
} else {
return "" + n;
}
if (n < 10) {
return "0" + n;
} else {
return "" + n;
}
}
if (date > 0) {
oDay.innerHTML = toDou(day);
oHour.innerHTML = toDou(hour);
Expand Down
1 change: 0 additions & 1 deletion src/components/elevenfooter.astro
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const today = new Date();
</script>
</body>
<footer>
<div>
<div class="py-8 px-8">
<p class="text-sm text-gray-500">
&copy; {new Date().getFullYear()}. TimeKeeper | Built by <a href="https://github.com/kewonit" class="text-blue-300">Kewonit</a> | Repo on <a href="https://github.com/kewonit/Timekeeper" class="text-blue-300">Github</a>
Expand Down
Loading

0 comments on commit 92181cc

Please sign in to comment.