kasramojallal commited on
Commit
6a87196
·
verified ·
1 Parent(s): 44b0e60

Add 2 files

Browse files
Files changed (2) hide show
  1. index.html +426 -766
  2. prompts.txt +3 -1
index.html CHANGED
@@ -3,850 +3,510 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Job Application Tracker Pro</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
- <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
10
- <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"></script>
11
  <style>
12
- .fade-in {
13
- animation: fadeIn 0.3s ease-in-out;
14
- }
15
- @keyframes fadeIn {
16
- from { opacity: 0; transform: translateY(10px); }
17
- to { opacity: 1; transform: translateY(0); }
18
- }
19
- .pulse {
20
- animation: pulse 1s infinite;
21
- }
22
- @keyframes pulse {
23
- 0% { transform: scale(1); }
24
- 50% { transform: scale(1.05); }
25
- 100% { transform: scale(1); }
26
- }
27
- .modal {
28
- transition: opacity 0.3s ease;
29
- }
30
- .modal-overlay {
31
- background-color: rgba(0, 0, 0, 0.5);
32
  }
33
  .chart-bar {
34
- transition: height 0.5s ease-out;
35
- }
36
- .progress-ring__circle {
37
- transition: stroke-dashoffset 0.5s ease-out;
38
- transform: rotate(-90deg);
39
- transform-origin: 50% 50%;
40
- }
41
- .glow {
42
- box-shadow: 0 0 15px rgba(99, 102, 241, 0.5);
43
  }
44
  </style>
45
  </head>
46
- <body class="bg-gradient-to-br from-blue-50 to-indigo-100 min-h-screen">
47
  <div class="container mx-auto px-4 py-8 max-w-4xl">
48
- <header class="text-center mb-8">
49
- <h1 class="text-4xl font-bold text-indigo-800 mb-2">Job Application Tracker Pro</h1>
50
- <p class="text-indigo-600">Track, analyze, and optimize your job search</p>
 
51
  </header>
52
 
53
- <div class="bg-white rounded-xl shadow-lg p-6 mb-8">
54
- <div class="flex flex-col md:flex-row justify-between items-center mb-6">
55
- <div class="text-center md:text-left mb-4 md:mb-0">
56
- <h2 class="text-2xl font-semibold text-gray-800">Today's Applications</h2>
57
- <p class="text-gray-500" id="today-date">Loading date...</p>
58
- <div class="mt-2 flex items-center justify-center md:justify-start">
59
- <span class="text-xs bg-indigo-100 text-indigo-800 px-2 py-1 rounded-full flex items-center">
60
- <i class="fas fa-clock mr-1 text-xs"></i>
61
- <span id="timezone-display">Detecting timezone...</span>
62
- </span>
 
 
63
  </div>
64
  </div>
65
- <div class="flex items-center space-x-4">
66
- <div class="relative">
67
- <svg class="w-24 h-24">
68
- <circle
69
- class="text-gray-200"
70
- stroke-width="8"
71
- stroke="currentColor"
72
- fill="transparent"
73
- r="36"
74
- cx="40"
75
- cy="40"
76
- />
77
- <circle
78
- class="progress-ring__circle text-indigo-600"
79
- stroke-width="8"
80
- stroke-linecap="round"
81
- stroke="currentColor"
82
- fill="transparent"
83
- r="36"
84
- cx="40"
85
- cy="40"
86
- id="progress-ring"
87
- />
88
- </svg>
89
- <div class="absolute inset-0 flex items-center justify-center">
90
- <span class="text-2xl font-bold text-indigo-800" id="today-count">0</span>
91
- </div>
92
- </div>
93
- <div class="flex flex-col space-y-2">
94
- <div class="flex space-x-2">
95
- <button id="decrease-btn" class="bg-red-500 hover:bg-red-600 text-white rounded-full w-12 h-12 flex items-center justify-center shadow-md transition-all transform hover:scale-105">
96
- <i class="fas fa-minus text-lg"></i>
97
- </button>
98
- <button id="add-btn" class="bg-indigo-600 hover:bg-indigo-700 text-white rounded-full w-12 h-12 flex items-center justify-center shadow-md transition-all transform hover:scale-105">
99
- <i class="fas fa-plus text-lg"></i>
100
- </button>
101
- </div>
102
- <button id="add-custom-btn" class="bg-indigo-100 hover:bg-indigo-200 text-indigo-700 rounded-full w-full h-8 flex items-center justify-center shadow-md text-sm transition-all">
103
- <i class="fas fa-calendar-day mr-1"></i> Custom Date
104
  </button>
105
  </div>
106
  </div>
107
  </div>
108
-
109
- <div class="border-t pt-4">
110
- <div class="flex justify-between items-center mb-2">
111
- <h3 class="font-medium text-gray-700">Total Applications</h3>
112
- <span class="text-xl font-bold text-indigo-800" id="total-count">0</span>
113
- </div>
114
- <div class="w-full bg-gray-200 rounded-full h-2.5">
115
- <div id="total-progress" class="bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div>
116
- </div>
117
- </div>
118
- </div>
119
-
120
- <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
121
- <div class="bg-white rounded-xl shadow-lg p-6">
122
- <h2 class="text-xl font-semibold text-gray-800 mb-4">Weekly Overview</h2>
123
- <div class="flex justify-between items-end h-40 mt-6">
124
- <!-- Weekly chart bars will be added here -->
125
- </div>
126
- </div>
127
- <div class="bg-white rounded-xl shadow-lg p-6">
128
- <h2 class="text-xl font-semibold text-gray-800 mb-4">Monthly Progress</h2>
129
- <div class="flex justify-center">
130
- <div id="monthly-chart" class="w-full h-40">
131
- <!-- Monthly chart will be added here -->
132
- </div>
133
- </div>
134
  </div>
135
  </div>
136
 
137
- <div class="bg-white rounded-xl shadow-lg p-6">
138
- <div class="flex justify-between items-center mb-4">
139
- <h2 class="text-2xl font-semibold text-gray-800">Application History</h2>
140
- <div class="flex space-x-2">
141
- <button id="settings-btn" class="text-indigo-600 hover:text-indigo-800 flex items-center">
142
- <i class="fas fa-cog mr-1"></i>
143
- <span>Settings</span>
144
- </button>
145
- </div>
146
- </div>
147
-
148
- <div id="history-list" class="space-y-3">
149
- <div class="text-center py-8 text-gray-400" id="empty-state">
150
- <i class="fas fa-clipboard-list text-4xl mb-2"></i>
151
- <p>No applications recorded yet</p>
152
- <button id="get-started-btn" class="mt-4 px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-md">
153
- Add Your First Application
154
- </button>
155
- </div>
156
- <!-- History items will be added here dynamically -->
157
- </div>
158
- </div>
159
-
160
- <div class="mt-6 text-center text-sm text-gray-500">
161
- <p>Every application is a step closer to your dream job. Keep going!</p>
162
- </div>
163
- </div>
164
-
165
- <!-- Modal for custom date entry -->
166
- <div id="date-modal" class="fixed inset-0 flex items-center justify-center z-50 modal opacity-0 pointer-events-none">
167
- <div class="modal-overlay absolute inset-0"></div>
168
- <div class="bg-white rounded-xl shadow-xl p-6 z-10 w-full max-w-md transform transition-all scale-95">
169
- <div class="flex justify-between items-center mb-4">
170
- <h3 class="text-xl font-semibold text-gray-800">Add/Edit Applications</h3>
171
- <button id="close-modal" class="text-gray-500 hover:text-gray-700">
172
- <i class="fas fa-times"></i>
173
- </button>
174
- </div>
175
- <div class="mb-4">
176
- <label for="custom-date" class="block text-sm font-medium text-gray-700 mb-1">Select Date</label>
177
- <input type="date" id="custom-date" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
178
- </div>
179
  <div class="mb-4">
180
- <label for="custom-count" class="block text-sm font-medium text-gray-700 mb-1">Number of Applications</label>
181
- <div class="flex items-center">
182
- <button id="decrease-custom" class="bg-gray-200 hover:bg-gray-300 text-gray-800 rounded-l-md w-10 h-10 flex items-center justify-center">
183
- <i class="fas fa-minus"></i>
184
- </button>
185
- <input type="number" id="custom-count" min="0" value="1" class="w-full px-3 py-2 border-t border-b border-gray-300 text-center focus:outline-none">
186
- <button id="increase-custom" class="bg-gray-200 hover:bg-gray-300 text-gray-800 rounded-r-md w-10 h-10 flex items-center justify-center">
187
- <i class="fas fa-plus"></i>
188
- </button>
189
  </div>
190
  </div>
191
- <div class="mb-4">
192
- <label for="custom-notes" class="block text-sm font-medium text-gray-700 mb-1">Notes (optional)</label>
193
- <textarea id="custom-notes" rows="2" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="Add any notes about these applications..."></textarea>
194
- </div>
195
- <div class="flex justify-end space-x-3">
196
- <button id="delete-entry" class="px-4 py-2 text-red-600 hover:text-red-800 hidden">
197
- <i class="fas fa-trash mr-1"></i> Delete
198
- </button>
199
- <button id="cancel-modal" class="px-4 py-2 text-gray-600 hover:text-gray-800">
200
- Cancel
201
  </button>
202
- <button id="save-custom" class="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-md">
203
- Save
 
204
  </button>
205
  </div>
 
 
 
206
  </div>
207
- </div>
208
 
209
- <!-- Settings Modal -->
210
- <div id="settings-modal" class="fixed inset-0 flex items-center justify-center z-50 modal opacity-0 pointer-events-none">
211
- <div class="modal-overlay absolute inset-0"></div>
212
- <div class="bg-white rounded-xl shadow-xl p-6 z-10 w-full max-w-md transform transition-all scale-95">
213
- <div class="flex justify-between items-center mb-4">
214
- <h3 class="text-xl font-semibold text-gray-800">Settings</h3>
215
- <button id="close-settings" class="text-gray-500 hover:text-gray-700">
216
- <i class="fas fa-times"></i>
217
- </button>
218
  </div>
219
- <div class="mb-4">
220
- <label for="timezone-select" class="block text-sm font-medium text-gray-700 mb-1">Timezone</label>
221
- <select id="timezone-select" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
222
- <option value="auto">Auto-detect</option>
223
- <!-- Timezone options will be added dynamically -->
224
- </select>
225
- </div>
226
- <div class="mb-4">
227
- <label for="daily-goal" class="block text-sm font-medium text-gray-700 mb-1">Daily Goal</label>
228
- <input type="number" id="daily-goal" min="1" value="5" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
229
- </div>
230
- <div class="mb-4">
231
- <label class="block text-sm font-medium text-gray-700 mb-1">Visual Theme</label>
232
- <div class="flex space-x-2">
233
- <button data-theme="indigo" class="theme-btn w-8 h-8 rounded-full bg-indigo-600 border-2 border-indigo-800"></button>
234
- <button data-theme="emerald" class="theme-btn w-8 h-8 rounded-full bg-emerald-600 border-2 border-transparent"></button>
235
- <button data-theme="rose" class="theme-btn w-8 h-8 rounded-full bg-rose-600 border-2 border-transparent"></button>
236
- <button data-theme="violet" class="theme-btn w-8 h-8 rounded-full bg-violet-600 border-2 border-transparent"></button>
237
- <button data-theme="sky" class="theme-btn w-8 h-8 rounded-full bg-sky-600 border-2 border-transparent"></button>
238
- </div>
239
  </div>
240
- <div class="flex justify-end space-x-3">
241
- <button id="cancel-settings" class="px-4 py-2 text-gray-600 hover:text-gray-800">
242
- Cancel
243
- </button>
244
- <button id="save-settings" class="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-md">
245
- Save Settings
246
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
247
  </div>
248
  </div>
249
  </div>
250
 
251
  <script>
252
- document.addEventListener('DOMContentLoaded', function() {
253
- // Get elements
254
- const addBtn = document.getElementById('add-btn');
255
- const decreaseBtn = document.getElementById('decrease-btn');
256
- const addCustomBtn = document.getElementById('add-custom-btn');
257
- const todayCountEl = document.getElementById('today-count');
258
- const totalCountEl = document.getElementById('total-count');
259
- const historyList = document.getElementById('history-list');
260
- const emptyState = document.getElementById('empty-state');
261
- const getStartedBtn = document.getElementById('get-started-btn');
262
- const todayDateEl = document.getElementById('today-date');
263
- const timezoneDisplay = document.getElementById('timezone-display');
264
- const progressRing = document.getElementById('progress-ring');
265
- const totalProgress = document.getElementById('total-progress');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
- // Modal elements
268
- const dateModal = document.getElementById('date-modal');
269
- const closeModal = document.getElementById('close-modal');
270
- const cancelModal = document.getElementById('cancel-modal');
271
- const saveCustom = document.getElementById('save-custom');
272
- const customDate = document.getElementById('custom-date');
273
- const customCount = document.getElementById('custom-count');
274
- const customNotes = document.getElementById('custom-notes');
275
- const decreaseCustom = document.getElementById('decrease-custom');
276
- const increaseCustom = document.getElementById('increase-custom');
277
- const deleteEntryBtn = document.getElementById('delete-entry');
 
 
278
 
279
- // Settings modal elements
280
- const settingsModal = document.getElementById('settings-modal');
281
- const settingsBtn = document.getElementById('settings-btn');
282
- const closeSettings = document.getElementById('close-settings');
283
- const cancelSettings = document.getElementById('cancel-settings');
284
- const saveSettings = document.getElementById('save-settings');
285
- const timezoneSelect = document.getElementById('timezone-select');
286
- const dailyGoalInput = document.getElementById('daily-goal');
287
- const themeButtons = document.querySelectorAll('.theme-btn');
288
 
289
- // Initialize with default settings
290
- let userSettings = JSON.parse(localStorage.getItem('jobAppSettings')) || {
291
- timezone: 'manual',
292
- dailyGoal: 5,
293
- theme: 'indigo'
294
- };
295
 
296
- // Apply theme
297
- function applyTheme(theme) {
298
- const colors = {
299
- indigo: { primary: 'indigo', secondary: 'blue' },
300
- emerald: { primary: 'emerald', secondary: 'green' },
301
- rose: { primary: 'rose', secondary: 'pink' },
302
- violet: { primary: 'violet', secondary: 'purple' },
303
- sky: { primary: 'sky', secondary: 'cyan' }
304
- };
305
-
306
- const colorSet = colors[theme] || colors.indigo;
307
 
308
- // Update all elements with theme classes
309
- document.querySelectorAll('[class*="bg-indigo-"]').forEach(el => {
310
- el.className = el.className.replace(/bg-indigo-\d+/g, `bg-${colorSet.primary}-600`);
311
- });
312
 
313
- document.querySelectorAll('[class*="text-indigo-"]').forEach(el => {
314
- el.className = el.className.replace(/text-indigo-\d+/g, `text-${colorSet.primary}-800`);
315
- });
316
 
317
- document.querySelectorAll('[class*="border-indigo-"]').forEach(el => {
318
- el.className = el.className.replace(/border-indigo-\d+/g, `border-${colorSet.primary}-800`);
319
- });
320
 
321
- document.querySelectorAll('[class*="from-blue-"]').forEach(el => {
322
- el.className = el.className.replace(/from-blue-\d+/g, `from-${colorSet.secondary}-50`);
323
- });
324
 
325
- document.querySelectorAll('[class*="to-indigo-"]').forEach(el => {
326
- el.className = el.className.replace(/to-indigo-\d+/g, `to-${colorSet.primary}-100`);
327
- });
 
 
328
 
329
- // Update progress bar
330
- if (totalProgress) {
331
- totalProgress.className = totalProgress.className.replace(/bg-indigo-\d+/g, `bg-${colorSet.primary}-600`);
332
- }
333
 
334
- // Update theme buttons
335
- themeButtons.forEach(btn => {
336
- if (btn.dataset.theme === theme) {
337
- btn.classList.replace('border-transparent', `border-${colorSet.primary}-800`);
338
- } else {
339
- btn.classList.replace(`border-${colorSet.primary}-800`, 'border-transparent');
340
- }
341
- });
342
- }
343
-
344
- // Apply saved theme
345
- applyTheme(userSettings.theme);
346
-
347
- // Populate timezone dropdown
348
- function populateTimezones() {
349
- const timezones = moment.tz.names();
350
- timezoneSelect.innerHTML = '<option value="auto">Auto-detect</option>';
351
 
352
- timezones.forEach(tz => {
353
- const option = document.createElement('option');
354
- option.value = tz;
355
- option.textContent = tz;
356
- if (tz === userSettings.timezone && userSettings.timezone !== 'auto') {
357
- option.selected = true;
358
- }
359
- timezoneSelect.appendChild(option);
360
- });
361
- }
362
-
363
- populateTimezones();
364
-
365
- // Get current date based on user's timezone
366
- function getCurrentDate() {
367
- if (userSettings.timezone === 'auto') {
368
- return moment().format('YYYY-MM-DD');
369
- } else {
370
- return moment().tz(userSettings.timezone).format('YYYY-MM-DD');
371
- }
372
- }
373
-
374
- // Format date for display
375
- function formatDateDisplay(dateStr) {
376
- if (userSettings.timezone === 'auto') {
377
- return moment(dateStr).format('dddd, MMMM D, YYYY');
378
- } else {
379
- return moment.tz(dateStr, userSettings.timezone).format('dddd, MMMM D, YYYY');
380
- }
381
- }
382
-
383
- // Set today's date
384
- const todayKey = getCurrentDate();
385
- todayDateEl.textContent = formatDateDisplay(todayKey);
386
-
387
- // Display timezone
388
- function displayTimezone() {
389
- if (userSettings.timezone === 'auto') {
390
- const detectedTz = moment.tz.guess();
391
- timezoneDisplay.textContent = detectedTz;
392
- } else {
393
- timezoneDisplay.textContent = userSettings.timezone;
394
- }
395
- }
396
-
397
- displayTimezone();
398
-
399
- // Set default date in modal to today
400
- customDate.value = todayKey;
401
- dailyGoalInput.value = userSettings.dailyGoal;
402
-
403
- // Initialize data from localStorage or create new
404
- let appData = JSON.parse(localStorage.getItem('jobAppData')) || {
405
- total: 0,
406
- history: []
407
- };
408
 
409
- // Check if today's date exists in history
410
- let todayEntry = appData.history.find(entry => entry.date === todayKey);
411
 
412
- if (!todayEntry) {
413
- todayEntry = { date: todayKey, count: 0, notes: '' };
414
- appData.history.unshift(todayEntry);
415
- saveData();
416
  }
417
 
418
- // Update UI
419
- updateCounts();
420
- renderHistory();
421
- renderCharts();
422
-
423
- // Update progress ring
424
- function updateProgressRing() {
425
- const radius = 36;
426
- const circumference = radius * 2 * Math.PI;
427
- const progress = (todayEntry.count / userSettings.dailyGoal) * 100;
428
- const offset = circumference - (progress / 100) * circumference;
429
 
430
- progressRing.style.strokeDasharray = `${circumference} ${circumference}`;
431
- progressRing.style.strokeDashoffset = offset;
 
432
 
433
- if (progress >= 100) {
434
- progressRing.classList.add('glow');
435
- } else {
436
- progressRing.classList.remove('glow');
437
- }
438
- }
439
-
440
- // Add button click handler
441
- addBtn.addEventListener('click', function() {
442
- todayEntry.count++;
443
- appData.total++;
444
 
445
- // Add animation effect
446
- this.classList.add('pulse');
447
- setTimeout(() => this.classList.remove('pulse'), 1000);
448
 
449
- saveData();
450
- updateCounts();
451
- renderHistory();
452
- renderCharts();
453
- });
454
-
455
- // Decrease button click handler
456
- decreaseBtn.addEventListener('click', function() {
457
- if (todayEntry.count > 0) {
458
- todayEntry.count--;
459
- appData.total--;
460
-
461
- saveData();
462
- updateCounts();
463
- renderHistory();
464
- renderCharts();
465
- }
466
- });
467
-
468
- // Add custom date button click handler
469
- addCustomBtn.addEventListener('click', function() {
470
- // Reset modal values
471
- customDate.value = todayKey;
472
- customCount.value = 1;
473
- customNotes.value = '';
474
- deleteEntryBtn.classList.add('hidden');
475
 
476
- // Show modal
477
- openModal();
478
- });
479
-
480
- // Get started button
481
- getStartedBtn.addEventListener('click', function() {
482
- addBtn.click();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
483
  });
484
-
485
- // Modal open/close handlers
486
- function openModal() {
487
- dateModal.classList.remove('opacity-0', 'pointer-events-none');
488
- dateModal.classList.add('opacity-100', 'pointer-events-auto');
489
- setTimeout(() => {
490
- dateModal.querySelector('.z-10').classList.remove('scale-95');
491
- dateModal.querySelector('.z-10').classList.add('scale-100');
492
- }, 10);
493
- }
494
-
495
- function closeModalHandler() {
496
- dateModal.querySelector('.z-10').classList.remove('scale-100');
497
- dateModal.querySelector('.z-10').classList.add('scale-95');
498
- setTimeout(() => {
499
- dateModal.classList.remove('opacity-100', 'pointer-events-auto');
500
- dateModal.classList.add('opacity-0', 'pointer-events-none');
501
- }, 200);
502
  }
503
 
504
- closeModal.addEventListener('click', closeModalHandler);
505
- cancelModal.addEventListener('click', closeModalHandler);
506
 
507
- // Settings modal handlers
508
- function openSettingsModal() {
509
- settingsModal.classList.remove('opacity-0', 'pointer-events-none');
510
- settingsModal.classList.add('opacity-100', 'pointer-events-auto');
511
- setTimeout(() => {
512
- settingsModal.querySelector('.z-10').classList.remove('scale-95');
513
- settingsModal.querySelector('.z-10').classList.add('scale-100');
514
- }, 10);
515
  }
516
 
517
- function closeSettingsHandler() {
518
- settingsModal.querySelector('.z-10').classList.remove('scale-100');
519
- settingsModal.querySelector('.z-10').classList.add('scale-95');
520
- setTimeout(() => {
521
- settingsModal.classList.remove('opacity-100', 'pointer-events-auto');
522
- settingsModal.classList.add('opacity-0', 'pointer-events-none');
523
- }, 200);
524
  }
525
 
526
- settingsBtn.addEventListener('click', openSettingsModal);
527
- closeSettings.addEventListener('click', closeSettingsHandler);
528
- cancelSettings.addEventListener('click', closeSettingsHandler);
529
 
530
- // Save settings
531
- saveSettings.addEventListener('click', function() {
532
- userSettings.timezone = timezoneSelect.value;
533
- userSettings.dailyGoal = parseInt(dailyGoalInput.value);
534
-
535
- // Find and apply selected theme
536
- themeButtons.forEach(btn => {
537
- if (btn.classList.contains('border-indigo-800') ||
538
- btn.classList.contains('border-emerald-800') ||
539
- btn.classList.contains('border-rose-800') ||
540
- btn.classList.contains('border-violet-800') ||
541
- btn.classList.contains('border-sky-800')) {
542
- userSettings.theme = btn.dataset.theme;
543
- }
544
- });
545
-
546
- localStorage.setItem('jobAppSettings', JSON.stringify(userSettings));
547
- applyTheme(userSettings.theme);
548
- displayTimezone();
549
- closeSettingsHandler();
550
-
551
- // Update today's date if timezone changed
552
- const newTodayKey = getCurrentDate();
553
- if (newTodayKey !== todayKey) {
554
- // Need to handle timezone change - this would require more complex logic
555
- // For now, we'll just refresh the display
556
- location.reload();
557
- }
558
- });
559
-
560
- // Theme selection
561
- themeButtons.forEach(btn => {
562
- btn.addEventListener('click', function() {
563
- themeButtons.forEach(b => {
564
- b.classList.replace(/border-\w+-800/g, 'border-transparent');
565
- });
566
-
567
- const theme = this.dataset.theme;
568
- const colorSet = {
569
- indigo: 'indigo',
570
- emerald: 'emerald',
571
- rose: 'rose',
572
- violet: 'violet',
573
- sky: 'sky'
574
- }[theme];
575
-
576
- this.classList.replace('border-transparent', `border-${colorSet}-800`);
577
- });
578
- });
579
 
580
- // Custom count controls
581
- decreaseCustom.addEventListener('click', function() {
582
- if (customCount.value > 0) {
583
- customCount.value--;
584
- }
585
- });
586
-
587
- increaseCustom.addEventListener('click', function() {
588
- customCount.value++;
589
- });
 
 
 
 
 
590
 
591
- // Save custom entry
592
- saveCustom.addEventListener('click', function() {
593
- const selectedDate = customDate.value;
594
- const count = parseInt(customCount.value);
595
- const notes = customNotes.value.trim();
596
-
597
- if (isNaN(count) || count < 0) {
598
- alert('Please enter a valid number of applications');
599
- return;
600
- }
601
-
602
- // Find or create entry for selected date
603
- let entry = appData.history.find(entry => entry.date === selectedDate);
604
-
605
- if (entry) {
606
- // Calculate the difference to update total correctly
607
- const diff = count - (entry.count || 0);
608
- entry.count = count;
609
- entry.notes = notes;
610
- appData.total += diff;
611
  } else {
612
- // Create new entry
613
- entry = { date: selectedDate, count: count, notes: notes };
614
- appData.history.unshift(entry);
615
- appData.total += count;
616
- }
617
-
618
- // If this is today's entry, update todayEntry reference
619
- if (selectedDate === todayKey) {
620
- todayEntry = entry;
621
  }
622
 
623
- saveData();
624
- updateCounts();
625
- renderHistory();
626
- renderCharts();
627
- closeModalHandler();
628
- });
629
-
630
- // Delete entry
631
- deleteEntryBtn.addEventListener('click', function() {
632
- const selectedDate = customDate.value;
633
- const entryIndex = appData.history.findIndex(entry => entry.date === selectedDate);
634
-
635
- if (entryIndex !== -1) {
636
- const entry = appData.history[entryIndex];
637
- appData.total -= entry.count;
638
- appData.history.splice(entryIndex, 1);
639
-
640
- saveData();
641
- updateCounts();
642
- renderHistory();
643
- renderCharts();
644
- closeModalHandler();
645
- }
646
- });
647
-
648
- // Update count displays
649
- function updateCounts() {
650
- todayCountEl.textContent = todayEntry.count;
651
- totalCountEl.textContent = appData.total;
652
-
653
- // Update progress ring
654
- updateProgressRing();
655
-
656
- // Update total progress (simple visualization)
657
- const maxTotal = 100; // Just for visualization purposes
658
- const progressPercent = Math.min((appData.total / maxTotal) * 100, 100);
659
- totalProgress.style.width = `${progressPercent}%`;
660
-
661
- // Add animation when count changes
662
- todayCountEl.classList.add('fade-in');
663
- totalCountEl.classList.add('fade-in');
664
- setTimeout(() => {
665
- todayCountEl.classList.remove('fade-in');
666
- totalCountEl.classList.remove('fade-in');
667
- }, 300);
668
  }
669
 
670
- // Render history list
671
- function renderHistory() {
672
- if (appData.history.length === 0 || (appData.history.length === 1 && appData.history[0].count === 0)) {
673
- emptyState.style.display = 'block';
674
- return;
675
- }
676
-
677
- emptyState.style.display = 'none';
678
- historyList.innerHTML = '';
679
-
680
- // Sort history by date (newest first)
681
- const sortedHistory = [...appData.history].sort((a, b) => new Date(b.date) - new Date(a.date));
682
-
683
- sortedHistory.forEach(entry => {
684
- if (entry.count === 0 && entry.date === todayKey) return;
685
-
686
- const entryDate = new Date(entry.date);
687
- const isToday = entry.date === todayKey;
688
-
689
- let formattedEntryDate;
690
- if (userSettings.timezone === 'auto') {
691
- formattedEntryDate = moment(entry.date).format('ddd, MMM D, YYYY');
692
- } else {
693
- formattedEntryDate = moment.tz(entry.date, userSettings.timezone).format('ddd, MMM D, YYYY');
694
- }
695
-
696
- const historyItem = document.createElement('div');
697
- historyItem.className = 'flex justify-between items-center p-3 bg-gray-50 rounded-lg fade-in hover:bg-gray-100 cursor-pointer transition-colors';
698
- if (isToday) {
699
- historyItem.classList.add('border-l-4', `border-${userSettings.theme}-500`);
700
- }
701
-
702
- historyItem.innerHTML = `
703
- <div class="flex items-center">
704
- <div class="w-10 h-10 rounded-full bg-${userSettings.theme}-100 flex items-center justify-center mr-3">
705
- <i class="fas fa-briefcase text-${userSettings.theme}-600"></i>
706
- </div>
707
- <div>
708
- <p class="font-medium ${isToday ? `text-${userSettings.theme}-800` : 'text-gray-800'}">${formattedEntryDate}</p>
709
- ${entry.notes ? `<p class="text-xs text-gray-500 truncate max-w-xs">${entry.notes}</p>` : ''}
710
- </div>
711
- </div>
712
- <div class="flex items-center space-x-2">
713
- <span class="text-lg font-bold ${isToday ? `text-${userSettings.theme}-800` : 'text-gray-700'}">${entry.count}</span>
714
- </div>
715
- `;
716
-
717
- // Add click handler to edit entry
718
- historyItem.addEventListener('click', function() {
719
- customDate.value = entry.date;
720
- customCount.value = entry.count;
721
- customNotes.value = entry.notes || '';
722
- deleteEntryBtn.classList.remove('hidden');
723
-
724
- // Change save button behavior to update existing entry
725
- saveCustom.onclick = function() {
726
- const newCount = parseInt(customCount.value);
727
- const notes = customNotes.value.trim();
728
-
729
- if (isNaN(newCount) || newCount < 0) {
730
- alert('Please enter a valid number of applications');
731
- return;
732
- }
733
-
734
- // Calculate the difference to update total correctly
735
- const diff = newCount - entry.count;
736
- entry.count = newCount;
737
- entry.notes = notes;
738
- appData.total += diff;
739
-
740
- // If this is today's entry, update todayEntry reference
741
- if (entry.date === todayKey) {
742
- todayEntry = entry;
743
- }
744
-
745
- saveData();
746
- updateCounts();
747
- renderHistory();
748
- renderCharts();
749
- closeModalHandler();
750
- };
751
-
752
- openModal();
753
- });
754
-
755
- historyList.appendChild(historyItem);
756
- });
757
  }
758
 
759
- // Render charts
760
- function renderCharts() {
761
- // Weekly chart
762
- const weeklyChart = document.querySelector('.flex.justify-between.items-end');
763
- weeklyChart.innerHTML = '';
764
-
765
- // Get last 7 days
766
- const days = [];
767
- for (let i = 6; i >= 0; i--) {
768
- const date = new Date();
769
- date.setDate(date.getDate() - i);
770
- const dateKey = moment(date).format('YYYY-MM-DD');
771
- days.push(dateKey);
772
- }
773
-
774
- // Find max count for scaling
775
- let maxCount = 1;
776
- days.forEach(day => {
777
- const entry = appData.history.find(e => e.date === day);
778
- if (entry && entry.count > maxCount) {
779
- maxCount = entry.count;
780
- }
781
- });
782
-
783
- // Create bars for each day
784
- days.forEach(day => {
785
- const entry = appData.history.find(e => e.date === day) || { count: 0 };
786
- const heightPercent = (entry.count / maxCount) * 100;
787
- const isToday = day === todayKey;
788
-
789
- const dayName = moment(day).format('ddd');
790
-
791
- const barContainer = document.createElement('div');
792
- barContainer.className = 'flex flex-col items-center';
793
-
794
- const bar = document.createElement('div');
795
- bar.className = `chart-bar w-8 rounded-t-md bg-${userSettings.theme}-${isToday ? '600' : '400'} mb-1`;
796
- bar.style.height = `${heightPercent}%`;
797
- bar.style.minHeight = '4px';
798
-
799
- const dayLabel = document.createElement('span');
800
- dayLabel.className = 'text-xs text-gray-500';
801
- dayLabel.textContent = dayName;
802
-
803
- const countLabel = document.createElement('span');
804
- countLabel.className = `text-xs font-medium text-${userSettings.theme}-800`;
805
- countLabel.textContent = entry.count;
806
-
807
- barContainer.appendChild(countLabel);
808
- barContainer.appendChild(bar);
809
- barContainer.appendChild(dayLabel);
810
- weeklyChart.appendChild(barContainer);
811
- });
812
-
813
- // Monthly chart (simplified)
814
- const monthlyChart = document.getElementById('monthly-chart');
815
- monthlyChart.innerHTML = '';
816
-
817
- // Create a simple bar for monthly progress
818
- const thisMonth = moment().format('YYYY-MM');
819
- const monthEntries = appData.history.filter(entry => entry.date.startsWith(thisMonth));
820
- const monthTotal = monthEntries.reduce((sum, entry) => sum + entry.count, 0);
821
-
822
- const monthContainer = document.createElement('div');
823
- monthContainer.className = 'flex flex-col h-full justify-center';
824
-
825
- const monthBar = document.createElement('div');
826
- monthBar.className = `h-6 rounded-full bg-${userSettings.theme}-200 relative overflow-hidden`;
827
-
828
- const monthProgress = document.createElement('div');
829
- monthProgress.className = `absolute top-0 left-0 h-full bg-${userSettings.theme}-600 rounded-full`;
830
- monthProgress.style.width = `${Math.min((monthTotal / 50) * 100, 100)}%`;
831
-
832
- const monthText = document.createElement('div');
833
- monthText.className = 'flex justify-between items-center mt-2';
834
- monthText.innerHTML = `
835
- <span class="text-sm text-gray-600">${moment().format('MMMM')}</span>
836
- <span class="text-sm font-medium text-${userSettings.theme}-800">${monthTotal} apps</span>
837
- `;
838
-
839
- monthBar.appendChild(monthProgress);
840
- monthContainer.appendChild(monthBar);
841
- monthContainer.appendChild(monthText);
842
- monthlyChart.appendChild(monthContainer);
843
  }
 
 
 
 
 
 
 
 
844
 
845
- // Save data to localStorage
846
- function saveData() {
847
- localStorage.setItem('jobAppData', JSON.stringify(appData));
848
  }
 
 
849
  });
 
 
 
850
  </script>
851
  <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=kasramojallal/application-tracker" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
852
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Job Application Tracker</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
+ .progress-bar {
11
+ transition: width 0.5s ease-in-out;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  }
13
  .chart-bar {
14
+ transition: height 0.5s ease-in-out;
 
 
 
 
 
 
 
 
15
  }
16
  </style>
17
  </head>
18
+ <body class="bg-gray-100 min-h-screen">
19
  <div class="container mx-auto px-4 py-8 max-w-4xl">
20
+ <!-- Header -->
21
+ <header class="mb-8">
22
+ <h1 class="text-3xl font-bold text-indigo-700 mb-2">Job Application Tracker</h1>
23
+ <p class="text-gray-600">Track your daily job applications and reach your goals</p>
24
  </header>
25
 
26
+ <!-- User Section -->
27
+ <div class="bg-white rounded-lg shadow-md p-6 mb-6">
28
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">User Profile</h2>
29
+ <div class="flex flex-col md:flex-row gap-4">
30
+ <div class="flex-1">
31
+ <label for="username" class="block text-sm font-medium text-gray-700 mb-1">Username</label>
32
+ <div class="flex">
33
+ <input type="text" id="username" placeholder="Enter your username"
34
+ class="flex-1 px-4 py-2 border border-gray-300 rounded-l-md focus:ring-indigo-500 focus:border-indigo-500">
35
+ <button id="saveUserBtn" class="bg-indigo-600 text-white px-4 py-2 rounded-r-md hover:bg-indigo-700 transition">
36
+ Save
37
+ </button>
38
  </div>
39
  </div>
40
+ <div class="flex-1">
41
+ <label for="dailyGoal" class="block text-sm font-medium text-gray-700 mb-1">Daily Goal</label>
42
+ <div class="flex">
43
+ <input type="number" id="dailyGoal" min="1" value="30"
44
+ class="flex-1 px-4 py-2 border border-gray-300 rounded-l-md focus:ring-indigo-500 focus:border-indigo-500">
45
+ <button id="saveGoalBtn" class="bg-indigo-600 text-white px-4 py-2 rounded-r-md hover:bg-indigo-700 transition">
46
+ Set Goal
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  </button>
48
  </div>
49
  </div>
50
  </div>
51
+ <div id="currentUser" class="mt-4 text-sm text-gray-600 hidden">
52
+ <span class="font-medium">Current user:</span> <span id="userDisplay"></span> |
53
+ <span class="font-medium">Daily goal:</span> <span id="goalDisplay"></span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  </div>
55
  </div>
56
 
57
+ <!-- Today's Progress -->
58
+ <div class="bg-white rounded-lg shadow-md p-6 mb-6">
59
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">Today's Progress</h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  <div class="mb-4">
61
+ <div class="flex justify-between mb-1">
62
+ <span class="text-sm font-medium text-gray-700">Applications today</span>
63
+ <span id="progressText" class="text-sm font-medium text-gray-700">0/30</span>
64
+ </div>
65
+ <div class="w-full bg-gray-200 rounded-full h-2.5">
66
+ <div id="progressBar" class="progress-bar bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div>
 
 
 
67
  </div>
68
  </div>
69
+ <div class="flex items-center justify-center gap-4 mb-4">
70
+ <button id="decreaseBtn" class="bg-red-500 text-white p-3 rounded-full hover:bg-red-600 transition disabled:opacity-50" disabled>
71
+ <i class="fas fa-minus"></i>
 
 
 
 
 
 
 
72
  </button>
73
+ <div class="text-4xl font-bold w-20 text-center" id="countDisplay">0</div>
74
+ <button id="increaseBtn" class="bg-green-500 text-white p-3 rounded-full hover:bg-green-600 transition">
75
+ <i class="fas fa-plus"></i>
76
  </button>
77
  </div>
78
+ <button id="saveTodayBtn" class="w-full bg-indigo-600 text-white py-2 px-4 rounded-md hover:bg-indigo-700 transition">
79
+ Save Today's Applications
80
+ </button>
81
  </div>
 
82
 
83
+ <!-- Weekly History -->
84
+ <div class="bg-white rounded-lg shadow-md p-6 mb-6">
85
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">Weekly History</h2>
86
+ <div class="flex justify-between items-end h-40 mb-4 border-b border-gray-200">
87
+ <!-- Chart bars will be inserted here by JavaScript -->
 
 
 
 
88
  </div>
89
+ <div class="overflow-x-auto">
90
+ <table class="min-w-full divide-y divide-gray-200">
91
+ <thead class="bg-gray-50">
92
+ <tr>
93
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
94
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Applications</th>
95
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Goal</th>
96
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
97
+ </tr>
98
+ </thead>
99
+ <tbody id="historyTable" class="bg-white divide-y divide-gray-200">
100
+ <!-- History rows will be inserted here by JavaScript -->
101
+ </tbody>
102
+ </table>
 
 
 
 
 
 
103
  </div>
104
+ </div>
105
+
106
+ <!-- All Users Data (Admin View) -->
107
+ <div id="adminSection" class="bg-white rounded-lg shadow-md p-6 hidden">
108
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">All Users Data</h2>
109
+ <div class="overflow-x-auto">
110
+ <table class="min-w-full divide-y divide-gray-200">
111
+ <thead class="bg-gray-50">
112
+ <tr>
113
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">User</th>
114
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Today</th>
115
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Weekly Avg</th>
116
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Total</th>
117
+ </tr>
118
+ </thead>
119
+ <tbody id="usersTable" class="bg-white divide-y divide-gray-200">
120
+ <!-- Users data will be inserted here by JavaScript -->
121
+ </tbody>
122
+ </table>
123
  </div>
124
  </div>
125
  </div>
126
 
127
  <script>
128
+ // DOM Elements
129
+ const usernameInput = document.getElementById('username');
130
+ const saveUserBtn = document.getElementById('saveUserBtn');
131
+ const dailyGoalInput = document.getElementById('dailyGoal');
132
+ const saveGoalBtn = document.getElementById('saveGoalBtn');
133
+ const currentUserDiv = document.getElementById('currentUser');
134
+ const userDisplay = document.getElementById('userDisplay');
135
+ const goalDisplay = document.getElementById('goalDisplay');
136
+ const decreaseBtn = document.getElementById('decreaseBtn');
137
+ const increaseBtn = document.getElementById('increaseBtn');
138
+ const countDisplay = document.getElementById('countDisplay');
139
+ const progressText = document.getElementById('progressText');
140
+ const progressBar = document.getElementById('progressBar');
141
+ const saveTodayBtn = document.getElementById('saveTodayBtn');
142
+ const historyTable = document.getElementById('historyTable');
143
+ const adminSection = document.getElementById('adminSection');
144
+ const usersTable = document.getElementById('usersTable');
145
+
146
+ // State
147
+ let currentUser = localStorage.getItem('currentUser') || '';
148
+ let dailyGoal = parseInt(localStorage.getItem(`${currentUser}_dailyGoal`)) || 30;
149
+ let todayCount = 0;
150
+ let applicationsData = JSON.parse(localStorage.getItem('applicationsData')) || {};
151
+ let allUsersData = JSON.parse(localStorage.getItem('allUsersData')) || {};
152
+
153
+ // Initialize
154
+ function init() {
155
+ if (currentUser) {
156
+ usernameInput.value = currentUser;
157
+ dailyGoalInput.value = dailyGoal;
158
+ showCurrentUser();
159
+ loadTodayCount();
160
+ loadHistory();
161
+ loadAllUsersData();
162
+ }
163
+
164
+ // Check if current user is admin
165
+ if (currentUser === 'admin') {
166
+ adminSection.classList.remove('hidden');
167
+ }
168
+ }
169
+
170
+ // Show current user info
171
+ function showCurrentUser() {
172
+ currentUserDiv.classList.remove('hidden');
173
+ userDisplay.textContent = currentUser;
174
+ goalDisplay.textContent = dailyGoal;
175
+ progressText.textContent = `0/${dailyGoal}`;
176
+ }
177
+
178
+ // Load today's count
179
+ function loadTodayCount() {
180
+ const today = new Date().toISOString().split('T')[0];
181
+ if (applicationsData[currentUser] && applicationsData[currentUser][today]) {
182
+ todayCount = applicationsData[currentUser][today].count;
183
+ updateCountDisplay();
184
+ }
185
+ }
186
+
187
+ // Update count display
188
+ function updateCountDisplay() {
189
+ countDisplay.textContent = todayCount;
190
+ progressText.textContent = `${todayCount}/${dailyGoal}`;
191
+ const progressPercentage = Math.min((todayCount / dailyGoal) * 100, 100);
192
+ progressBar.style.width = `${progressPercentage}%`;
193
+
194
+ // Change progress bar color based on completion
195
+ if (progressPercentage >= 100) {
196
+ progressBar.classList.remove('bg-indigo-600');
197
+ progressBar.classList.add('bg-green-500');
198
+ } else if (progressPercentage >= 75) {
199
+ progressBar.classList.remove('bg-green-500', 'bg-yellow-500');
200
+ progressBar.classList.add('bg-indigo-600');
201
+ } else if (progressPercentage >= 50) {
202
+ progressBar.classList.remove('bg-indigo-600', 'bg-red-500');
203
+ progressBar.classList.add('bg-yellow-500');
204
+ } else {
205
+ progressBar.classList.remove('bg-indigo-600', 'bg-yellow-500');
206
+ progressBar.classList.add('bg-red-500');
207
+ }
208
 
209
+ // Enable/disable buttons
210
+ decreaseBtn.disabled = todayCount <= 0;
211
+ }
212
+
213
+ // Load history
214
+ function loadHistory() {
215
+ if (!applicationsData[currentUser]) {
216
+ historyTable.innerHTML = '<tr><td colspan="4" class="px-6 py-4 text-center text-gray-500">No data available</td></tr>';
217
+ return;
218
+ }
219
+
220
+ // Clear existing rows
221
+ historyTable.innerHTML = '';
222
 
223
+ // Get sorted dates (newest first)
224
+ const userData = applicationsData[currentUser];
225
+ const dates = Object.keys(userData).sort((a, b) => new Date(b) - new Date(a));
 
 
 
 
 
 
226
 
227
+ // Limit to 30 entries for display
228
+ const displayDates = dates.slice(0, 30);
 
 
 
 
229
 
230
+ // Create chart
231
+ createWeeklyChart(displayDates.slice(0, 7).reverse());
232
+
233
+ // Add rows
234
+ displayDates.forEach(date => {
235
+ const entry = userData[date];
236
+ const row = document.createElement('tr');
 
 
 
 
237
 
238
+ const dateCell = document.createElement('td');
239
+ dateCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
240
+ dateCell.textContent = formatDate(date);
 
241
 
242
+ const countCell = document.createElement('td');
243
+ countCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
244
+ countCell.textContent = entry.count;
245
 
246
+ const goalCell = document.createElement('td');
247
+ goalCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
248
+ goalCell.textContent = entry.goal;
249
 
250
+ const statusCell = document.createElement('td');
251
+ statusCell.className = 'px-6 py-4 whitespace-nowrap text-sm';
 
252
 
253
+ const statusSpan = document.createElement('span');
254
+ statusSpan.className = entry.count >= entry.goal ?
255
+ 'px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800' :
256
+ 'px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800';
257
+ statusSpan.textContent = entry.count >= entry.goal ? 'Completed' : 'Pending';
258
 
259
+ statusCell.appendChild(statusSpan);
 
 
 
260
 
261
+ row.appendChild(dateCell);
262
+ row.appendChild(countCell);
263
+ row.appendChild(goalCell);
264
+ row.appendChild(statusCell);
 
 
 
 
 
 
 
 
 
 
 
 
 
265
 
266
+ historyTable.appendChild(row);
267
+ });
268
+ }
269
+
270
+ // Create weekly chart
271
+ function createWeeklyChart(dates) {
272
+ const chartContainer = document.querySelector('.flex.justify-between.items-end');
273
+ chartContainer.innerHTML = '';
274
+
275
+ if (!dates.length) return;
276
+
277
+ // Find max value for scaling
278
+ const maxValue = Math.max(...dates.map(date => {
279
+ return applicationsData[currentUser][date].count;
280
+ }), dailyGoal);
281
+
282
+ dates.forEach(date => {
283
+ const entry = applicationsData[currentUser][date];
284
+ const day = new Date(date).toLocaleDateString('en-US', { weekday: 'short' });
285
+ const count = entry.count;
286
+ const goal = entry.goal;
287
+
288
+ const barContainer = document.createElement('div');
289
+ barContainer.className = 'flex flex-col items-center';
290
+
291
+ const barWrapper = document.createElement('div');
292
+ barWrapper.className = 'relative h-32 w-10';
293
+
294
+ // Goal bar (background)
295
+ const goalBar = document.createElement('div');
296
+ goalBar.className = 'absolute bottom-0 w-full bg-gray-200 rounded-t';
297
+ goalBar.style.height = `${(goal / maxValue) * 100}%`;
298
+
299
+ // Count bar (foreground)
300
+ const countBar = document.createElement('div');
301
+ countBar.className = 'chart-bar absolute bottom-0 w-full bg-indigo-600 rounded-t';
302
+ countBar.style.height = `${(count / maxValue) * 100}%`;
303
+
304
+ // Label
305
+ const label = document.createElement('div');
306
+ label.className = 'text-xs text-gray-500 mt-1';
307
+ label.textContent = day;
308
+
309
+ barWrapper.appendChild(goalBar);
310
+ barWrapper.appendChild(countBar);
311
+ barContainer.appendChild(barWrapper);
312
+ barContainer.appendChild(label);
313
+
314
+ chartContainer.appendChild(barContainer);
315
+ });
316
+ }
317
+
318
+ // Load all users data (for admin)
319
+ function loadAllUsersData() {
320
+ if (currentUser !== 'admin') return;
 
321
 
322
+ usersTable.innerHTML = '';
 
323
 
324
+ const users = Object.keys(allUsersData);
325
+ if (users.length === 0) {
326
+ usersTable.innerHTML = '<tr><td colspan="4" class="px-6 py-4 text-center text-gray-500">No user data available</td></tr>';
327
+ return;
328
  }
329
 
330
+ users.forEach(user => {
331
+ if (user === 'admin') return;
 
 
 
 
 
 
 
 
 
332
 
333
+ const userData = allUsersData[user];
334
+ const today = new Date().toISOString().split('T')[0];
335
+ const todayCount = userData.applications[today] ? userData.applications[today].count : 0;
336
 
337
+ // Calculate weekly average
338
+ const dates = Object.keys(userData.applications);
339
+ const last7Days = dates
340
+ .filter(date => {
341
+ const dateObj = new Date(date);
342
+ const todayObj = new Date();
343
+ return dateObj >= new Date(todayObj.setDate(todayObj.getDate() - 7));
344
+ })
345
+ .map(date => userData.applications[date].count);
 
 
346
 
347
+ const weeklyAvg = last7Days.length > 0 ?
348
+ Math.round(last7Days.reduce((a, b) => a + b, 0) / last7Days.length) : 0;
 
349
 
350
+ // Calculate total
351
+ const total = dates.reduce((sum, date) => sum + userData.applications[date].count, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
 
353
+ const row = document.createElement('tr');
354
+
355
+ const userCell = document.createElement('td');
356
+ userCell.className = 'px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900';
357
+ userCell.textContent = user;
358
+
359
+ const todayCell = document.createElement('td');
360
+ todayCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
361
+ todayCell.textContent = todayCount;
362
+
363
+ const weeklyCell = document.createElement('td');
364
+ weeklyCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
365
+ weeklyCell.textContent = weeklyAvg;
366
+
367
+ const totalCell = document.createElement('td');
368
+ totalCell.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
369
+ totalCell.textContent = total;
370
+
371
+ row.appendChild(userCell);
372
+ row.appendChild(todayCell);
373
+ row.appendChild(weeklyCell);
374
+ row.appendChild(totalCell);
375
+
376
+ usersTable.appendChild(row);
377
  });
378
+ }
379
+
380
+ // Format date for display
381
+ function formatDate(dateString) {
382
+ const options = { year: 'numeric', month: 'short', day: 'numeric', weekday: 'short' };
383
+ return new Date(dateString).toLocaleDateString('en-US', options);
384
+ }
385
+
386
+ // Event Listeners
387
+ saveUserBtn.addEventListener('click', () => {
388
+ const newUser = usernameInput.value.trim();
389
+ if (!newUser) {
390
+ alert('Please enter a username');
391
+ return;
 
 
 
 
392
  }
393
 
394
+ currentUser = newUser;
395
+ localStorage.setItem('currentUser', currentUser);
396
 
397
+ // Initialize user data if it doesn't exist
398
+ if (!applicationsData[currentUser]) {
399
+ applicationsData[currentUser] = {};
 
 
 
 
 
400
  }
401
 
402
+ // Initialize allUsersData if it doesn't exist
403
+ if (!allUsersData[currentUser]) {
404
+ allUsersData[currentUser] = {
405
+ goal: dailyGoal,
406
+ applications: {}
407
+ };
408
+ localStorage.setItem('allUsersData', JSON.stringify(allUsersData));
409
  }
410
 
411
+ // Load user's daily goal
412
+ dailyGoal = allUsersData[currentUser].goal || 30;
413
+ dailyGoalInput.value = dailyGoal;
414
 
415
+ showCurrentUser();
416
+ loadTodayCount();
417
+ loadHistory();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
 
419
+ // Show admin section if user is admin
420
+ if (currentUser === 'admin') {
421
+ adminSection.classList.remove('hidden');
422
+ loadAllUsersData();
423
+ } else {
424
+ adminSection.classList.add('hidden');
425
+ }
426
+ });
427
+
428
+ saveGoalBtn.addEventListener('click', () => {
429
+ const newGoal = parseInt(dailyGoalInput.value);
430
+ if (isNaN(newGoal) || newGoal < 1) {
431
+ alert('Please enter a valid goal (minimum 1)');
432
+ return;
433
+ }
434
 
435
+ dailyGoal = newGoal;
436
+ goalDisplay.textContent = dailyGoal;
437
+ progressText.textContent = `${todayCount}/${dailyGoal}`;
438
+
439
+ // Save goal for current user
440
+ if (currentUser) {
441
+ if (!allUsersData[currentUser]) {
442
+ allUsersData[currentUser] = {
443
+ goal: dailyGoal,
444
+ applications: {}
445
+ };
 
 
 
 
 
 
 
 
 
446
  } else {
447
+ allUsersData[currentUser].goal = dailyGoal;
 
 
 
 
 
 
 
 
448
  }
449
 
450
+ localStorage.setItem('allUsersData', JSON.stringify(allUsersData));
451
+ localStorage.setItem(`${currentUser}_dailyGoal`, dailyGoal);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
452
  }
453
 
454
+ updateCountDisplay();
455
+ });
456
+
457
+ increaseBtn.addEventListener('click', () => {
458
+ todayCount++;
459
+ updateCountDisplay();
460
+ });
461
+
462
+ decreaseBtn.addEventListener('click', () => {
463
+ if (todayCount > 0) {
464
+ todayCount--;
465
+ updateCountDisplay();
466
+ }
467
+ });
468
+
469
+ saveTodayBtn.addEventListener('click', () => {
470
+ if (!currentUser) {
471
+ alert('Please set a username first');
472
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
  }
474
 
475
+ const today = new Date().toISOString().split('T')[0];
476
+
477
+ // Save to applicationsData
478
+ applicationsData[currentUser][today] = {
479
+ count: todayCount,
480
+ goal: dailyGoal
481
+ };
482
+ localStorage.setItem('applicationsData', JSON.stringify(applicationsData));
483
+
484
+ // Save to allUsersData
485
+ if (!allUsersData[currentUser]) {
486
+ allUsersData[currentUser] = {
487
+ goal: dailyGoal,
488
+ applications: {}
489
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
  }
491
+ allUsersData[currentUser].applications[today] = {
492
+ count: todayCount,
493
+ goal: dailyGoal
494
+ };
495
+ localStorage.setItem('allUsersData', JSON.stringify(allUsersData));
496
+
497
+ // Reload history
498
+ loadHistory();
499
 
500
+ // If admin, reload all users data
501
+ if (currentUser === 'admin') {
502
+ loadAllUsersData();
503
  }
504
+
505
+ alert('Today\'s applications saved successfully!');
506
  });
507
+
508
+ // Initialize the app
509
+ init();
510
  </script>
511
  <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=kasramojallal/application-tracker" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
512
  </html>
prompts.txt CHANGED
@@ -1,2 +1,4 @@
1
  add a few functionalities for me to also decrease the number if I added by mistake. also let me choose another date if I want to add the number for previous days.
2
- add option for decreasing as well. also you got the todays date wrong. add the option to add time zone or location so it can figure the todays day correct. also make the visualization better and delete the clear data option. add as many editing options as possible.
 
 
 
1
  add a few functionalities for me to also decrease the number if I added by mistake. also let me choose another date if I want to add the number for previous days.
2
+ add option for decreasing as well. also you got the todays date wrong. add the option to add time zone or location so it can figure the todays day correct. also make the visualization better and delete the clear data option. add as many editing options as possible.
3
+ the website is not working. fix the issue and forget about detecting timezone we can add it manually.
4
+ I want you to create a job application tracker for me so that I can add each day I applied for how many jobs and there should be a add and decrease button and also it should show the history of the number of jobs I applied each day and there should be a weekly history and each day I should set a goal of like 30 jobs that it should be filled. also I want other peolpe to use it so I want them to be able to add their username.