From 07b1247e9a8425f790a325913fd901abd47ea5d6 Mon Sep 17 00:00:00 2001 From: Veronaet <191837011+Veronaet@users.noreply.github.com> Date: Tue, 10 Jun 2025 05:01:42 -0700 Subject: [PATCH 1/4] Create manifest.json --- submissions/Homework Tracker/manifest.json | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 submissions/Homework Tracker/manifest.json diff --git a/submissions/Homework Tracker/manifest.json b/submissions/Homework Tracker/manifest.json new file mode 100644 index 00000000..62496658 --- /dev/null +++ b/submissions/Homework Tracker/manifest.json @@ -0,0 +1,25 @@ +{ + "manifest_version": 3, + "name": "Homework Tracker", + "version": "1.0", + "description": "Track your homework assignments and never miss a deadline", + "permissions": [ + "storage" + ], + "action": { + "default_popup": "popup.html", + "default_title": "Homework Tracker", + "default_icon": { + "16": "icon16.png", + "32": "icon32.png", + "48": "icon48.png", + "128": "icon128.png" + } + }, + "icons": { + "16": "icon16.png", + "32": "icon32.png", + "48": "icon48.png", + "128": "icon128.png" + } +} From 094c4140f0021cdb059d3f47fea33a6c02c82b5d Mon Sep 17 00:00:00 2001 From: Veronaet <191837011+Veronaet@users.noreply.github.com> Date: Tue, 10 Jun 2025 05:03:43 -0700 Subject: [PATCH 2/4] Create popup.html --- submissions/Homework Tracker/popup.html | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 submissions/Homework Tracker/popup.html diff --git a/submissions/Homework Tracker/popup.html b/submissions/Homework Tracker/popup.html new file mode 100644 index 00000000..55456a07 --- /dev/null +++ b/submissions/Homework Tracker/popup.html @@ -0,0 +1,39 @@ + + + + + + Homework Tracker + + + +
+
+

📚 Homework Tracker

+
+ +
+ + + + + +
+ +
+ + + +
+ +
+
+
+

No assignments yet. Add one above!

+
+
+
+ + + + From 38da1868264d315b8944df6d4e2370e888c812b9 Mon Sep 17 00:00:00 2001 From: Veronaet <191837011+Veronaet@users.noreply.github.com> Date: Tue, 10 Jun 2025 05:06:21 -0700 Subject: [PATCH 3/4] Create styles.css --- submissions/Homework Tracker/styles.css | 275 ++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 submissions/Homework Tracker/styles.css diff --git a/submissions/Homework Tracker/styles.css b/submissions/Homework Tracker/styles.css new file mode 100644 index 00000000..b092a813 --- /dev/null +++ b/submissions/Homework Tracker/styles.css @@ -0,0 +1,275 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + width: 400px; + min-height: 500px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: #333; +} + +.container { + background: white; + margin: 0; + min-height: 500px; + display: flex; + flex-direction: column; +} + +header { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + padding: 20px; + text-align: center; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); +} + +header h1 { + font-size: 20px; + font-weight: 600; +} + +.add-form { + padding: 20px; + background: #f8f9fa; + border-bottom: 1px solid #e9ecef; +} + +.add-form input, +.add-form textarea, +.add-form button { + width: 100%; + margin-bottom: 10px; + padding: 12px; + border: 1px solid #ddd; + border-radius: 8px; + font-size: 14px; + font-family: inherit; +} + +.add-form input:focus, +.add-form textarea:focus { + outline: none; + border-color: #667eea; + box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2); +} + +.add-form textarea { + resize: vertical; + min-height: 60px; + max-height: 100px; +} + +#addBtn { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + border: none; + font-weight: 600; + cursor: pointer; + transition: transform 0.2s, box-shadow 0.2s; +} + +#addBtn:hover { + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); +} + +#addBtn:active { + transform: translateY(0); +} + +.filters { + display: flex; + padding: 0 20px; + background: white; + border-bottom: 1px solid #e9ecef; +} + +.filter-btn { + flex: 1; + padding: 12px; + border: none; + background: transparent; + cursor: pointer; + font-size: 14px; + font-weight: 500; + color: #666; + transition: all 0.2s; + border-bottom: 2px solid transparent; +} + +.filter-btn:hover { + color: #667eea; + background: rgba(102, 126, 234, 0.05); +} + +.filter-btn.active { + color: #667eea; + border-bottom-color: #667eea; + background: rgba(102, 126, 234, 0.1); +} + +.assignments-container { + flex: 1; + padding: 20px; + overflow-y: auto; +} + +.assignment-item { + background: white; + border: 1px solid #e9ecef; + border-radius: 12px; + padding: 16px; + margin-bottom: 12px; + box-shadow: 0 2px 8px rgba(0,0,0,0.05); + transition: all 0.2s; + position: relative; +} + +.assignment-item:hover { + transform: translateY(-1px); + box-shadow: 0 4px 16px rgba(0,0,0,0.1); +} + +.assignment-item.completed { + opacity: 0.7; + background: #f8f9fa; +} + +.assignment-item.completed .assignment-title { + text-decoration: line-through; + color: #666; +} + +.assignment-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 8px; +} + +.assignment-title { + font-weight: 600; + font-size: 16px; + color: #333; + margin: 0; + flex: 1; +} + +.assignment-actions { + display: flex; + gap: 5px; +} + +.action-btn { + background: none; + border: none; + font-size: 16px; + cursor: pointer; + padding: 4px; + border-radius: 4px; + transition: background 0.2s; +} + +.action-btn:hover { + background: rgba(0,0,0,0.1); +} + +.complete-btn { + color: #28a745; +} + +.delete-btn { + color: #dc3545; +} + +.assignment-meta { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; +} + +.assignment-subject { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + padding: 4px 8px; + border-radius: 12px; + font-size: 12px; + font-weight: 500; +} + +.assignment-date { + font-size: 12px; + color: #666; + font-weight: 500; +} + +.assignment-date.overdue { + color: #dc3545; + font-weight: 600; +} + +.assignment-date.due-soon { + color: #ffc107; + font-weight: 600; +} + +.assignment-description { + font-size: 14px; + color: #666; + line-height: 1.4; + margin-top: 8px; + padding-top: 8px; + border-top: 1px solid #f0f0f0; +} + +.empty-state { + text-align: center; + color: #666; + font-style: italic; + padding: 40px 20px; +} + +.empty-state p { + font-size: 16px; +} + +/* Scrollbar styling */ +.assignments-container::-webkit-scrollbar { + width: 6px; +} + +.assignments-container::-webkit-scrollbar-track { + background: #f1f1f1; + border-radius: 3px; +} + +.assignments-container::-webkit-scrollbar-thumb { + background: #ccc; + border-radius: 3px; +} + +.assignments-container::-webkit-scrollbar-thumb:hover { + background: #999; +} + +/* Animation for new items */ +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.assignment-item.new { + animation: slideIn 0.3s ease-out; +} From ed321ff359b5736a5b26324cc4dbd8076e3d36a1 Mon Sep 17 00:00:00 2001 From: Veronaet <191837011+Veronaet@users.noreply.github.com> Date: Tue, 10 Jun 2025 05:07:37 -0700 Subject: [PATCH 4/4] Create popup.js --- submissions/Homework Tracker/popup.js | 299 ++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 submissions/Homework Tracker/popup.js diff --git a/submissions/Homework Tracker/popup.js b/submissions/Homework Tracker/popup.js new file mode 100644 index 00000000..38eb11d1 --- /dev/null +++ b/submissions/Homework Tracker/popup.js @@ -0,0 +1,299 @@ +// Homework Tracker Chrome Extension - Main JavaScript + +class HomeworkTracker { + constructor() { + this.assignments = []; + this.currentFilter = 'all'; + this.init(); + } + + async init() { + await this.loadAssignments(); + this.setupEventListeners(); + this.renderAssignments(); + this.setTodayAsDefault(); + } + + setupEventListeners() { + // Add assignment button + document.getElementById('addBtn').addEventListener('click', () => this.addAssignment()); + + // Enter key in input fields + ['assignmentTitle', 'assignmentSubject'].forEach(id => { + document.getElementById(id).addEventListener('keypress', (e) => { + if (e.key === 'Enter') this.addAssignment(); + }); + }); + + // Filter buttons + document.querySelectorAll('.filter-btn').forEach(btn => { + btn.addEventListener('click', (e) => this.setFilter(e.target.dataset.filter)); + }); + } + + setTodayAsDefault() { + const today = new Date().toISOString().split('T')[0]; + document.getElementById('assignmentDate').value = today; + } + + async loadAssignments() { + try { + const result = await chrome.storage.local.get(['assignments']); + this.assignments = result.assignments || []; + } catch (error) { + console.error('Error loading assignments:', error); + this.assignments = []; + } + } + + async saveAssignments() { + try { + await chrome.storage.local.set({ assignments: this.assignments }); + } catch (error) { + console.error('Error saving assignments:', error); + } + } + + generateId() { + return Date.now().toString(36) + Math.random().toString(36).substr(2); + } + + async addAssignment() { + const title = document.getElementById('assignmentTitle').value.trim(); + const subject = document.getElementById('assignmentSubject').value.trim(); + const date = document.getElementById('assignmentDate').value; + const description = document.getElementById('assignmentDescription').value.trim(); + + if (!title || !subject || !date) { + this.showError('Please fill in title, subject, and due date'); + return; + } + + const assignment = { + id: this.generateId(), + title, + subject, + date, + description, + completed: false, + createdAt: new Date().toISOString() + }; + + this.assignments.push(assignment); + await this.saveAssignments(); + + // Clear form + document.getElementById('assignmentTitle').value = ''; + document.getElementById('assignmentSubject').value = ''; + document.getElementById('assignmentDescription').value = ''; + this.setTodayAsDefault(); + + this.renderAssignments(); + this.showSuccess('Assignment added successfully!'); + } + + async toggleComplete(id) { + const assignment = this.assignments.find(a => a.id === id); + if (assignment) { + assignment.completed = !assignment.completed; + await this.saveAssignments(); + this.renderAssignments(); + } + } + + async deleteAssignment(id) { + if (confirm('Are you sure you want to delete this assignment?')) { + this.assignments = this.assignments.filter(a => a.id !== id); + await this.saveAssignments(); + this.renderAssignments(); + this.showSuccess('Assignment deleted'); + } + } + + setFilter(filter) { + this.currentFilter = filter; + + // Update active filter button + document.querySelectorAll('.filter-btn').forEach(btn => { + btn.classList.toggle('active', btn.dataset.filter === filter); + }); + + this.renderAssignments(); + } + + getFilteredAssignments() { + let filtered = [...this.assignments]; + + // Apply filter + switch (this.currentFilter) { + case 'pending': + filtered = filtered.filter(a => !a.completed); + break; + case 'completed': + filtered = filtered.filter(a => a.completed); + break; + } + + // Sort by due date (earliest first) + filtered.sort((a, b) => { + if (a.completed && !b.completed) return 1; + if (!a.completed && b.completed) return -1; + return new Date(a.date) - new Date(b.date); + }); + + return filtered; + } + + formatDate(dateString) { + const date = new Date(dateString); + const today = new Date(); + const tomorrow = new Date(today); + tomorrow.setDate(tomorrow.getDate() + 1); + + // Reset time for comparison + today.setHours(0, 0, 0, 0); + tomorrow.setHours(0, 0, 0, 0); + date.setHours(0, 0, 0, 0); + + if (date.getTime() === today.getTime()) { + return 'Today'; + } else if (date.getTime() === tomorrow.getTime()) { + return 'Tomorrow'; + } else { + return date.toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + year: date.getFullYear() !== today.getFullYear() ? 'numeric' : undefined + }); + } + } + + getDateStatus(dateString) { + const date = new Date(dateString); + const today = new Date(); + const tomorrow = new Date(today); + tomorrow.setDate(tomorrow.getDate() + 1); + + // Reset time for comparison + today.setHours(0, 0, 0, 0); + tomorrow.setHours(0, 0, 0, 0); + date.setHours(0, 0, 0, 0); + + if (date < today) { + return 'overdue'; + } else if (date.getTime() === today.getTime() || date.getTime() === tomorrow.getTime()) { + return 'due-soon'; + } + return ''; + } + + renderAssignments() { + const container = document.getElementById('assignmentsList'); + const emptyState = document.getElementById('emptyState'); + const filtered = this.getFilteredAssignments(); + + if (filtered.length === 0) { + container.innerHTML = ''; + emptyState.style.display = 'block'; + return; + } + + emptyState.style.display = 'none'; + + container.innerHTML = filtered.map(assignment => { + const dateStatus = this.getDateStatus(assignment.date); + const formattedDate = this.formatDate(assignment.date); + + return ` +
+
+

${this.escapeHtml(assignment.title)}

+
+ + +
+
+
+ ${this.escapeHtml(assignment.subject)} + ${formattedDate} +
+ ${assignment.description ? `
${this.escapeHtml(assignment.description)}
` : ''} +
+ `; + }).join(''); + } + + escapeHtml(text) { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } + + showSuccess(message) { + this.showNotification(message, 'success'); + } + + showError(message) { + this.showNotification(message, 'error'); + } + + showNotification(message, type) { + // Remove existing notifications + const existing = document.querySelector('.notification'); + if (existing) existing.remove(); + + const notification = document.createElement('div'); + notification.className = `notification ${type}`; + notification.textContent = message; + + // Add styles + Object.assign(notification.style, { + position: 'fixed', + top: '20px', + left: '50%', + transform: 'translateX(-50%)', + background: type === 'success' ? '#28a745' : '#dc3545', + color: 'white', + padding: '10px 20px', + borderRadius: '8px', + fontSize: '14px', + fontWeight: '500', + zIndex: '1000', + boxShadow: '0 4px 12px rgba(0,0,0,0.15)', + animation: 'slideDown 0.3s ease-out' + }); + + // Add animation keyframes + if (!document.querySelector('#notification-styles')) { + const style = document.createElement('style'); + style.id = 'notification-styles'; + style.textContent = ` + @keyframes slideDown { + from { opacity: 0; transform: translateX(-50%) translateY(-20px); } + to { opacity: 1; transform: translateX(-50%) translateY(0); } + } + `; + document.head.appendChild(style); + } + + document.body.appendChild(notification); + + // Auto remove after 3 seconds + setTimeout(() => { + if (notification.parentNode) { + notification.style.animation = 'slideDown 0.3s ease-out reverse'; + setTimeout(() => notification.remove(), 300); + } + }, 3000); + } +} + +// Initialize the tracker when the popup loads +let tracker; +document.addEventListener('DOMContentLoaded', () => { + tracker = new HomeworkTracker(); +});