mahen23 commited on
Commit
46ea0d1
·
verified ·
1 Parent(s): 4b5acb3

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +545 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Anniversay
3
- emoji: 📚
4
- colorFrom: gray
5
  colorTo: yellow
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: anniversay
3
+ emoji: 🐳
4
+ colorFrom: red
5
  colorTo: yellow
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,545 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Anniversary Reminder</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ @keyframes pulse {
11
+ 0%, 100% { transform: scale(1); }
12
+ 50% { transform: scale(1.05); }
13
+ }
14
+ .pulse-animation {
15
+ animation: pulse 2s infinite;
16
+ }
17
+ .anniversary-card:hover {
18
+ transform: translateY(-5px);
19
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
20
+ }
21
+ .anniversary-card {
22
+ transition: all 0.3s ease;
23
+ }
24
+ .notification-badge {
25
+ position: absolute;
26
+ top: -8px;
27
+ right: -8px;
28
+ }
29
+ </style>
30
+ </head>
31
+ <body class="bg-gradient-to-br from-indigo-50 to-purple-50 min-h-screen">
32
+ <div class="container mx-auto px-4 py-8">
33
+ <!-- Header -->
34
+ <header class="text-center mb-12">
35
+ <h1 class="text-4xl font-bold text-indigo-800 mb-2">Anniversary Reminder</h1>
36
+ <p class="text-lg text-gray-600">Never forget important dates again</p>
37
+ <div class="w-24 h-1 bg-indigo-400 mx-auto mt-4 rounded-full"></div>
38
+ </header>
39
+
40
+ <!-- Main Content -->
41
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
42
+ <!-- Add Anniversary Form -->
43
+ <div class="bg-white rounded-xl shadow-lg p-6 lg:col-span-1 h-fit sticky top-8">
44
+ <div class="flex items-center mb-6">
45
+ <i class="fas fa-calendar-plus text-2xl text-indigo-600 mr-3"></i>
46
+ <h2 class="text-2xl font-semibold text-gray-800">Add New Anniversary</h2>
47
+ </div>
48
+
49
+ <form id="anniversaryForm" class="space-y-4">
50
+ <div>
51
+ <label for="name" class="block text-sm font-medium text-gray-700 mb-1">Name/Title</label>
52
+ <input type="text" id="name" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
53
+ </div>
54
+
55
+ <div>
56
+ <label for="date" class="block text-sm font-medium text-gray-700 mb-1">Date</label>
57
+ <input type="date" id="date" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
58
+ </div>
59
+
60
+ <div>
61
+ <label for="notes" class="block text-sm font-medium text-gray-700 mb-1">Notes (Optional)</label>
62
+ <textarea id="notes" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"></textarea>
63
+ </div>
64
+
65
+ <div class="flex items-center">
66
+ <input type="checkbox" id="recurring" class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded">
67
+ <label for="recurring" class="ml-2 block text-sm text-gray-700">Recurring annually</label>
68
+ </div>
69
+
70
+ <button type="submit" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-2 px-4 rounded-lg transition duration-200 flex items-center justify-center">
71
+ <i class="fas fa-save mr-2"></i> Save Anniversary
72
+ </button>
73
+ </form>
74
+
75
+ <div class="mt-6 pt-6 border-t border-gray-200">
76
+ <h3 class="text-lg font-medium text-gray-800 mb-3">Notification Settings</h3>
77
+ <div class="flex items-center mb-2">
78
+ <input type="checkbox" id="enableNotifications" class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded">
79
+ <label for="enableNotifications" class="ml-2 block text-sm text-gray-700">Enable browser notifications</label>
80
+ </div>
81
+ <div class="flex items-center">
82
+ <input type="number" id="daysBefore" min="0" max="30" value="1" class="w-16 px-2 py-1 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
83
+ <label for="daysBefore" class="ml-2 block text-sm text-gray-700">days before anniversary</label>
84
+ </div>
85
+ </div>
86
+ </div>
87
+
88
+ <!-- Upcoming Anniversaries -->
89
+ <div class="lg:col-span-2">
90
+ <div class="flex items-center justify-between mb-6">
91
+ <div class="flex items-center">
92
+ <i class="fas fa-bell text-2xl text-indigo-600 mr-3"></i>
93
+ <h2 class="text-2xl font-semibold text-gray-800">Upcoming Anniversaries</h2>
94
+ </div>
95
+ <div class="relative">
96
+ <button id="filterBtn" class="flex items-center text-indigo-600 hover:text-indigo-800">
97
+ <i class="fas fa-filter mr-1"></i> Filter
98
+ </button>
99
+ <div id="filterDropdown" class="hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg z-10">
100
+ <div class="py-1">
101
+ <a href="#" class="filter-option block px-4 py-2 text-sm text-gray-700 hover:bg-indigo-50" data-days="7">Next 7 days</a>
102
+ <a href="#" class="filter-option block px-4 py-2 text-sm text-gray-700 hover:bg-indigo-50" data-days="30">Next 30 days</a>
103
+ <a href="#" class="filter-option block px-4 py-2 text-sm text-gray-700 hover:bg-indigo-50" data-days="all">All anniversaries</a>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </div>
108
+
109
+ <!-- Anniversary Cards -->
110
+ <div id="anniversaryList" class="grid grid-cols-1 md:grid-cols-2 gap-4">
111
+ <!-- Cards will be dynamically inserted here -->
112
+ <div class="text-center py-10 text-gray-500" id="emptyState">
113
+ <i class="fas fa-calendar-check text-4xl mb-3"></i>
114
+ <p>No anniversaries added yet. Add one to get started!</p>
115
+ </div>
116
+ </div>
117
+
118
+ <!-- Today's Anniversaries (only shown if there are any) -->
119
+ <div id="todaySection" class="mt-12 hidden">
120
+ <div class="flex items-center mb-6">
121
+ <i class="fas fa-gift text-2xl text-indigo-600 mr-3"></i>
122
+ <h2 class="text-2xl font-semibold text-gray-800">Today's Anniversaries</h2>
123
+ </div>
124
+ <div id="todayList" class="grid grid-cols-1 md:grid-cols-2 gap-4">
125
+ <!-- Today's cards will be inserted here -->
126
+ </div>
127
+ </div>
128
+ </div>
129
+ </div>
130
+ </div>
131
+
132
+ <!-- Edit Modal -->
133
+ <div id="editModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
134
+ <div class="bg-white rounded-xl shadow-xl p-6 w-full max-w-md">
135
+ <div class="flex justify-between items-center mb-4">
136
+ <h3 class="text-xl font-semibold text-gray-800">Edit Anniversary</h3>
137
+ <button id="closeModal" class="text-gray-500 hover:text-gray-700">
138
+ <i class="fas fa-times"></i>
139
+ </button>
140
+ </div>
141
+ <form id="editForm" class="space-y-4">
142
+ <input type="hidden" id="editId">
143
+ <div>
144
+ <label for="editName" class="block text-sm font-medium text-gray-700 mb-1">Name/Title</label>
145
+ <input type="text" id="editName" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
146
+ </div>
147
+
148
+ <div>
149
+ <label for="editDate" class="block text-sm font-medium text-gray-700 mb-1">Date</label>
150
+ <input type="date" id="editDate" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
151
+ </div>
152
+
153
+ <div>
154
+ <label for="editNotes" class="block text-sm font-medium text-gray-700 mb-1">Notes</label>
155
+ <textarea id="editNotes" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"></textarea>
156
+ </div>
157
+
158
+ <div class="flex items-center">
159
+ <input type="checkbox" id="editRecurring" class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded">
160
+ <label for="editRecurring" class="ml-2 block text-sm text-gray-700">Recurring annually</label>
161
+ </div>
162
+
163
+ <div class="flex justify-between pt-4">
164
+ <button type="button" id="deleteBtn" class="bg-red-100 hover:bg-red-200 text-red-700 font-medium py-2 px-4 rounded-lg transition duration-200 flex items-center">
165
+ <i class="fas fa-trash mr-2"></i> Delete
166
+ </button>
167
+ <button type="submit" class="bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-2 px-4 rounded-lg transition duration-200 flex items-center">
168
+ <i class="fas fa-save mr-2"></i> Save Changes
169
+ </button>
170
+ </div>
171
+ </form>
172
+ </div>
173
+ </div>
174
+
175
+ <script>
176
+ document.addEventListener('DOMContentLoaded', function() {
177
+ // DOM Elements
178
+ const anniversaryForm = document.getElementById('anniversaryForm');
179
+ const anniversaryList = document.getElementById('anniversaryList');
180
+ const todaySection = document.getElementById('todaySection');
181
+ const todayList = document.getElementById('todayList');
182
+ const emptyState = document.getElementById('emptyState');
183
+ const filterBtn = document.getElementById('filterBtn');
184
+ const filterDropdown = document.getElementById('filterDropdown');
185
+ const editModal = document.getElementById('editModal');
186
+ const closeModal = document.getElementById('closeModal');
187
+ const editForm = document.getElementById('editForm');
188
+ const deleteBtn = document.getElementById('deleteBtn');
189
+ const enableNotifications = document.getElementById('enableNotifications');
190
+ const daysBefore = document.getElementById('daysBefore');
191
+
192
+ // State
193
+ let anniversaries = JSON.parse(localStorage.getItem('anniversaries')) || [];
194
+ let filterDays = 30; // Default filter: next 30 days
195
+
196
+ // Initialize
197
+ renderAnniversaries();
198
+ checkTodayAnniversaries();
199
+ setupNotificationPermission();
200
+
201
+ // Event Listeners
202
+ anniversaryForm.addEventListener('submit', handleAddAnniversary);
203
+ filterBtn.addEventListener('click', toggleFilterDropdown);
204
+ document.addEventListener('click', closeFilterDropdown);
205
+ closeModal.addEventListener('click', () => editModal.classList.add('hidden'));
206
+
207
+ // Functions
208
+ function handleAddAnniversary(e) {
209
+ e.preventDefault();
210
+
211
+ const name = document.getElementById('name').value;
212
+ const date = document.getElementById('date').value;
213
+ const notes = document.getElementById('notes').value;
214
+ const recurring = document.getElementById('recurring').checked;
215
+
216
+ const newAnniversary = {
217
+ id: Date.now().toString(),
218
+ name,
219
+ date,
220
+ notes,
221
+ recurring,
222
+ createdAt: new Date().toISOString()
223
+ };
224
+
225
+ anniversaries.push(newAnniversary);
226
+ saveAnniversaries();
227
+ renderAnniversaries();
228
+ checkTodayAnniversaries();
229
+
230
+ // Reset form
231
+ anniversaryForm.reset();
232
+
233
+ // Show success message
234
+ showToast('Anniversary added successfully!', 'success');
235
+ }
236
+
237
+ function renderAnniversaries() {
238
+ if (anniversaries.length === 0) {
239
+ emptyState.classList.remove('hidden');
240
+ anniversaryList.innerHTML = '';
241
+ anniversaryList.appendChild(emptyState);
242
+ return;
243
+ }
244
+
245
+ emptyState.classList.add('hidden');
246
+ anniversaryList.innerHTML = '';
247
+
248
+ // Sort anniversaries by upcoming date
249
+ const sortedAnniversaries = [...anniversaries].sort((a, b) => {
250
+ return daysUntilDate(a.date) - daysUntilDate(b.date);
251
+ });
252
+
253
+ // Filter based on selected days
254
+ const filteredAnniversaries = sortedAnniversaries.filter(anniversary => {
255
+ if (filterDays === 'all') return true;
256
+ return daysUntilDate(anniversary.date) <= filterDays;
257
+ });
258
+
259
+ if (filteredAnniversaries.length === 0) {
260
+ const noResults = document.createElement('div');
261
+ noResults.className = 'col-span-full text-center py-10 text-gray-500';
262
+ noResults.innerHTML = `
263
+ <i class="fas fa-calendar-times text-4xl mb-3"></i>
264
+ <p>No anniversaries found for this filter.</p>
265
+ `;
266
+ anniversaryList.appendChild(noResults);
267
+ return;
268
+ }
269
+
270
+ filteredAnniversaries.forEach(anniversary => {
271
+ const card = createAnniversaryCard(anniversary);
272
+ anniversaryList.appendChild(card);
273
+ });
274
+ }
275
+
276
+ function createAnniversaryCard(anniversary) {
277
+ const daysUntil = daysUntilDate(anniversary.date);
278
+ const isToday = daysUntil === 0;
279
+ const isUpcoming = daysUntil > 0 && daysUntil <= 7;
280
+
281
+ const card = document.createElement('div');
282
+ card.className = 'anniversary-card bg-white rounded-xl shadow-md p-5 relative';
283
+ card.dataset.id = anniversary.id;
284
+
285
+ if (isToday) {
286
+ card.classList.add('border-2', 'border-indigo-400');
287
+ }
288
+
289
+ let badge = '';
290
+ if (isToday) {
291
+ badge = `
292
+ <div class="absolute top-3 right-3 bg-indigo-600 text-white text-xs font-bold px-2 py-1 rounded-full">
293
+ TODAY
294
+ </div>
295
+ `;
296
+ } else if (isUpcoming) {
297
+ badge = `
298
+ <div class="absolute top-3 right-3 bg-yellow-500 text-white text-xs font-bold px-2 py-1 rounded-full">
299
+ SOON
300
+ </div>
301
+ `;
302
+ }
303
+
304
+ const dateObj = new Date(anniversary.date);
305
+ const formattedDate = dateObj.toLocaleDateString('en-US', {
306
+ month: 'long',
307
+ day: 'numeric',
308
+ year: 'numeric'
309
+ });
310
+
311
+ const daysText = isToday ? 'Today!' :
312
+ daysUntil === 1 ? 'Tomorrow' :
313
+ `${daysUntil} days from now`;
314
+
315
+ card.innerHTML = `
316
+ ${badge}
317
+ <div class="flex items-start mb-3">
318
+ <div class="bg-indigo-100 text-indigo-600 rounded-lg p-3 mr-4">
319
+ <i class="fas fa-calendar-day text-xl"></i>
320
+ </div>
321
+ <div class="flex-1">
322
+ <h3 class="text-lg font-semibold text-gray-800">${anniversary.name}</h3>
323
+ <p class="text-sm text-gray-600">${formattedDate}</p>
324
+ ${anniversary.notes ? `<p class="text-sm text-gray-500 mt-2">${anniversary.notes}</p>` : ''}
325
+ </div>
326
+ </div>
327
+ <div class="flex justify-between items-center pt-3 border-t border-gray-100">
328
+ <span class="text-sm font-medium ${isToday ? 'text-indigo-600' : 'text-gray-500'}">
329
+ <i class="far fa-clock mr-1"></i> ${daysText}
330
+ </span>
331
+ <div class="flex space-x-2">
332
+ <button class="edit-btn text-indigo-600 hover:text-indigo-800 p-1 rounded-full">
333
+ <i class="fas fa-edit"></i>
334
+ </button>
335
+ ${anniversary.recurring ? '<span class="text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full">Recurring</span>' : ''}
336
+ </div>
337
+ </div>
338
+ `;
339
+
340
+ // Add edit event
341
+ const editBtn = card.querySelector('.edit-btn');
342
+ editBtn.addEventListener('click', () => openEditModal(anniversary));
343
+
344
+ return card;
345
+ }
346
+
347
+ function openEditModal(anniversary) {
348
+ document.getElementById('editId').value = anniversary.id;
349
+ document.getElementById('editName').value = anniversary.name;
350
+ document.getElementById('editDate').value = anniversary.date;
351
+ document.getElementById('editNotes').value = anniversary.notes || '';
352
+ document.getElementById('editRecurring').checked = anniversary.recurring;
353
+
354
+ editModal.classList.remove('hidden');
355
+
356
+ // Set up form submission
357
+ editForm.onsubmit = function(e) {
358
+ e.preventDefault();
359
+
360
+ const id = document.getElementById('editId').value;
361
+ const name = document.getElementById('editName').value;
362
+ const date = document.getElementById('editDate').value;
363
+ const notes = document.getElementById('editNotes').value;
364
+ const recurring = document.getElementById('editRecurring').checked;
365
+
366
+ const index = anniversaries.findIndex(a => a.id === id);
367
+ if (index !== -1) {
368
+ anniversaries[index] = {
369
+ ...anniversaries[index],
370
+ name,
371
+ date,
372
+ notes,
373
+ recurring
374
+ };
375
+
376
+ saveAnniversaries();
377
+ renderAnniversaries();
378
+ checkTodayAnniversaries();
379
+ editModal.classList.add('hidden');
380
+
381
+ showToast('Anniversary updated successfully!', 'success');
382
+ }
383
+ };
384
+
385
+ // Set up delete button
386
+ deleteBtn.onclick = function() {
387
+ if (confirm('Are you sure you want to delete this anniversary?')) {
388
+ anniversaries = anniversaries.filter(a => a.id !== anniversary.id);
389
+ saveAnniversaries();
390
+ renderAnniversaries();
391
+ checkTodayAnniversaries();
392
+ editModal.classList.add('hidden');
393
+
394
+ showToast('Anniversary deleted successfully!', 'success');
395
+ }
396
+ };
397
+ }
398
+
399
+ function checkTodayAnniversaries() {
400
+ const todayAnniversaries = anniversaries.filter(anniversary => {
401
+ return daysUntilDate(anniversary.date) === 0;
402
+ });
403
+
404
+ if (todayAnniversaries.length > 0) {
405
+ todaySection.classList.remove('hidden');
406
+ todayList.innerHTML = '';
407
+
408
+ todayAnniversaries.forEach(anniversary => {
409
+ const card = createAnniversaryCard(anniversary);
410
+ card.classList.add('pulse-animation');
411
+ todayList.appendChild(card);
412
+ });
413
+
414
+ // Check if notifications are enabled
415
+ if (enableNotifications.checked && Notification.permission === 'granted') {
416
+ const notificationDays = parseInt(daysBefore.value) || 1;
417
+
418
+ todayAnniversaries.forEach(anniversary => {
419
+ // Check if we should notify for this anniversary
420
+ if (daysUntilDate(anniversary.date) <= notificationDays) {
421
+ const notificationTitle = `Anniversary Reminder: ${anniversary.name}`;
422
+ const notificationBody = anniversary.notes
423
+ ? `Today is ${anniversary.name}! ${anniversary.notes}`
424
+ : `Today is ${anniversary.name}!`;
425
+
426
+ new Notification(notificationTitle, {
427
+ body: notificationBody,
428
+ icon: 'https://cdn-icons-png.flaticon.com/512/3652/3652191.png'
429
+ });
430
+ }
431
+ });
432
+ }
433
+ } else {
434
+ todaySection.classList.add('hidden');
435
+ }
436
+ }
437
+
438
+ function daysUntilDate(dateString) {
439
+ const today = new Date();
440
+ today.setHours(0, 0, 0, 0);
441
+
442
+ const targetDate = new Date(dateString);
443
+ targetDate.setHours(0, 0, 0, 0);
444
+
445
+ // Adjust year for recurring anniversaries
446
+ if (targetDate < today) {
447
+ targetDate.setFullYear(today.getFullYear());
448
+ if (targetDate < today) {
449
+ targetDate.setFullYear(today.getFullYear() + 1);
450
+ }
451
+ }
452
+
453
+ const diffTime = targetDate - today;
454
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
455
+
456
+ return diffDays;
457
+ }
458
+
459
+ function saveAnniversaries() {
460
+ localStorage.setItem('anniversaries', JSON.stringify(anniversaries));
461
+ }
462
+
463
+ function toggleFilterDropdown(e) {
464
+ e.stopPropagation();
465
+ filterDropdown.classList.toggle('hidden');
466
+ }
467
+
468
+ function closeFilterDropdown(e) {
469
+ if (!filterDropdown.contains(e.target) && e.target !== filterBtn) {
470
+ filterDropdown.classList.add('hidden');
471
+ }
472
+ }
473
+
474
+ function setupNotificationPermission() {
475
+ // Check if notifications are supported
476
+ if (!('Notification' in window)) {
477
+ enableNotifications.disabled = true;
478
+ enableNotifications.parentNode.querySelector('label').textContent += ' (not supported)';
479
+ return;
480
+ }
481
+
482
+ // Check current permission
483
+ if (Notification.permission === 'granted') {
484
+ enableNotifications.checked = true;
485
+ } else if (Notification.permission === 'denied') {
486
+ enableNotifications.disabled = true;
487
+ enableNotifications.parentNode.querySelector('label').textContent += ' (blocked)';
488
+ }
489
+
490
+ // Set up change listener
491
+ enableNotifications.addEventListener('change', function() {
492
+ if (this.checked && Notification.permission !== 'granted') {
493
+ Notification.requestPermission().then(permission => {
494
+ if (permission === 'granted') {
495
+ showToast('Notifications enabled!', 'success');
496
+ } else {
497
+ this.checked = false;
498
+ showToast('Notifications blocked', 'warning');
499
+ }
500
+ });
501
+ }
502
+ });
503
+ }
504
+
505
+ function showToast(message, type) {
506
+ const toast = document.createElement('div');
507
+ toast.className = `fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-lg text-white font-medium flex items-center ${
508
+ type === 'success' ? 'bg-green-500' : 'bg-yellow-500'
509
+ }`;
510
+ toast.innerHTML = `
511
+ <i class="fas ${type === 'success' ? 'fa-check-circle' : 'fa-exclamation-triangle'} mr-2"></i>
512
+ ${message}
513
+ `;
514
+
515
+ document.body.appendChild(toast);
516
+
517
+ setTimeout(() => {
518
+ toast.classList.add('opacity-0', 'transition-opacity', 'duration-300');
519
+ setTimeout(() => toast.remove(), 300);
520
+ }, 3000);
521
+ }
522
+
523
+ // Set up filter options
524
+ document.querySelectorAll('.filter-option').forEach(option => {
525
+ option.addEventListener('click', function(e) {
526
+ e.preventDefault();
527
+ filterDays = this.dataset.days === 'all' ? 'all' : parseInt(this.dataset.days);
528
+ renderAnniversaries();
529
+ filterDropdown.classList.add('hidden');
530
+
531
+ // Update filter button text
532
+ let filterText = '';
533
+ if (filterDays === 'all') filterText = 'All';
534
+ else filterText = `Next ${filterDays} days`;
535
+
536
+ filterBtn.innerHTML = `<i class="fas fa-filter mr-1"></i> ${filterText}`;
537
+ });
538
+ });
539
+
540
+ // Check for anniversaries every day
541
+ setInterval(checkTodayAnniversaries, 24 * 60 * 60 * 1000);
542
+ });
543
+ </script>
544
+ <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=mahen23/anniversay" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
545
+ </html>