diff --git a/README.md b/submissions/Screen-Time-Tracker/README.md similarity index 100% rename from README.md rename to submissions/Screen-Time-Tracker/README.md diff --git a/submissions/Screen-Time-Tracker/background.js b/submissions/Screen-Time-Tracker/background.js new file mode 100644 index 00000000..09869ad6 --- /dev/null +++ b/submissions/Screen-Time-Tracker/background.js @@ -0,0 +1,102 @@ +let currentUrl = ''; +let startTime = null; +let todayData = {}; +let isTracking = false; + +chrome.runtime.onInstalled.addListener(() => { + const today = new Date().toLocaleDateString(); + chrome.storage.local.get([today], (result) => { + todayData = result[today] || {}; + }); + + chrome.alarms.create('saveData', { periodInMinutes: 1 }); +}); + +chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { + if (changeInfo.status === 'complete' && tab.active) { + updateCurrentTab(tab); + } +}); + +chrome.tabs.onActivated.addListener(activeInfo => { + chrome.tabs.get(activeInfo.tabId, updateCurrentTab); +}); + +chrome.windows.onFocusChanged.addListener(windowId => { + if (windowId === chrome.windows.WINDOW_ID_NONE) { + saveCurrentSession(); + isTracking = false; + } else { + chrome.tabs.query({ active: true, currentWindow: true }, tabs => { + if (tabs.length > 0) { + updateCurrentTab(tabs[0]); + } + }); + } +}); + +chrome.alarms.onAlarm.addListener((alarm) => { + if (alarm.name === 'saveData') { + saveCurrentSession(); + saveTodayData(); + } +}); + +function updateCurrentTab(tab) { + if (!tab || !tab.url || tab.url.startsWith('chrome://')) { + return; + } + + saveCurrentSession(); + + currentUrl = new URL(tab.url).hostname; + startTime = Date.now(); + isTracking = true; +} + +function saveCurrentSession() { + if (!isTracking || !currentUrl || !startTime) { + return; + } + + const now = Date.now(); + const duration = now - startTime; + + if (duration > 1000) { + if (!todayData[currentUrl]) { + todayData[currentUrl] = 0; + } + todayData[currentUrl] += duration; + } + + startTime = now; +} + +function saveTodayData() { + const today = new Date().toLocaleDateString(); + chrome.storage.local.set({ [today]: todayData }); +} + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request.action === 'getStats') { + saveCurrentSession(); + + const today = new Date().toLocaleDateString(); + chrome.storage.local.get([today], (result) => { + sendResponse({ todayData: result[today] || {} }); + }); + return true; + } else if (request.action === 'getHistory') { + const dates = []; + for (let i = 0; i < 7; i++) { + const date = new Date(); + date.setDate(date.getDate() - i); + dates.push(date.toLocaleDateString()); + } + + chrome.storage.local.get(dates, (result) => { + sendResponse({ historyData: result }); + }); + return true; + } +}); diff --git a/submissions/Screen-Time-Tracker/icons/icon128.png b/submissions/Screen-Time-Tracker/icons/icon128.png new file mode 100644 index 00000000..6ba518d4 --- /dev/null +++ b/submissions/Screen-Time-Tracker/icons/icon128.png @@ -0,0 +1 @@ +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAF0WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNy4yLWMwMDAgNzkuMWI2NWE3OWI0LCAyMDIyLzA2LzE0LTIyOjA0OjE3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjQuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDMtMTlUMTQ6NDc6NDctMDQ6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMjQtMDMtMTlUMTQ6NDc6NDctMDQ6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI0LTAzLTE5VDE0OjQ3OjQ3LTA0OjAwIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjY5ZDM4ZjY5LTRhZDAtNDY0ZC1hMjA0LTNlYWRhOGU5ZjM5YyIgeG1wTU06RG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjY5ZDM4ZjY5LTRhZDAtNDY0ZC1hMjA0LTNlYWRhOGU5ZjM5YyIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjY5ZDM4ZjY5LTRhZDAtNDY0ZC1hMjA0LTNlYWRhOGU5ZjM5YyIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjY5ZDM4ZjY5LTRhZDAtNDY0ZC1hMjA0LTNlYWRhOGU5ZjM5YyIgc3RFdnQ6d2hlbj0iMjAyNC0wMy0xOVQxNDo0Nzo0Ny0wNDowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDI0LjAgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+wkzxRwAABPlJREFUeJztnVtsFFUYx3/fLqW0tKXQUqAFSgFFKqgxGBHxEjWKYowxPqgxRl80Rh+M0cQYE2OMiYmJiYkvxhh9MMYYb9EYNcYLGo3xEjWKYEBFEJBSaKGU0tK2dI8P27Wzs2d2z8zOzM7Z8/8lTbY7Z77v+5+zc+bMme98R1QVQ7okkg7ASDamgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKKaBRTAGNYgpoFFNAo5gCGsUU0CimgEYxBTSKK \ No newline at end of file diff --git a/submissions/Screen-Time-Tracker/icons/icon16.png b/submissions/Screen-Time-Tracker/icons/icon16.png new file mode 100644 index 00000000..d9010eca --- /dev/null +++ b/submissions/Screen-Time-Tracker/icons/icon16.png @@ -0,0 +1 @@ +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAABYUlEQVQ4jZ2TsUrDUBSGv5OkSZO0NaUPUBwEwUEQBEFwcHBwcHBwcHBwcHDwEQQfQhAEQRAEB0EQBEFwEARBEARBsC1Jk6RJ0qS5DsVU2qa24A/ncs7/n3O4nHPhj6cyv1jf3T842D84PDo+OT27vLrOZvP5QiaTuS0UCrf5fP4un8/fZ7PZh3Q6/RiLxZ6i0ehzOBx+DYVCuUAg8CaEyPt8vne3213weDzFdd0y27YrQoiq1+utua7b8Pl8TcuyWqZptkVRbAshukIIPyB9T5IkCiGQJAlFUVAUBVVV0TQNRVFQVRVRFNE0DU3TkGUZRVGQZRlZljEMA13XMQwDXdfRNA1d11/nOI5jWZbjOI5jWZbjOI5jWZbjOI5jWZZlWZb1E2CMsdlsxmaz2Z9Ya2HbNpPJhNFoxGg0YjweMxwOGQwG9Pt9er0evV6PTqdDu92m1WrRbDZpNBrU63VqtRrVapVKpUK5XP4CzqnHQwdXLxQAAAAASUVORK5CYII= \ No newline at end of file diff --git a/submissions/Screen-Time-Tracker/icons/icon48.png b/submissions/Screen-Time-Tracker/icons/icon48.png new file mode 100644 index 00000000..d90e1bf9 --- /dev/null +++ b/submissions/Screen-Time-Tracker/icons/icon48.png @@ -0,0 +1 @@ +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAADv0lEQVRoge2ZW2hcVRSGv7VnJslkJpNJMk3SNG2T1jS1RhNrK1VrVbygKFLFCxREEFERBB8E8UF8EHwQfBAf9MGLIj4oiKIIXvCGVuulVqPWJk1tm8Q2mWSSzEwymcs+PiRNOpk5k5wz44MW/MNmn332Wv+/z9p7nX02HMIhHMIi4P8OoKampiYajfYahvGc3+9vqaqqOr5///56v9//q2maT/l8vvZwOHwkFovV+3y+30zTfNzr9R6NRCLHYrFYvdfr/cM0zYc9Hs/xcDh8vLq6+i+fz/eQYRgnI5HIyXg8XrcgAMuyzp44ceKZbDZ7eXd3d8O2bds2nzt37sr+/v4tqVRq/alTp27KZrOXdXV1bdq+ffvG8+fPX9XX17cpnU5f0d7evimTyVze09OzcefOnRt6e3s39/f3b0mn01d2dHRs2rNnz4ZEIrElmUxe3dfXt2nv3r3rFwQgm83S2NhIMpkkkUhQKBQoFAoUi0VM00REsCwLEcE0TYrFIsVikWKxSKFQIJ/Pk8/nyeVy5HI5stks2WyWTCZDJpMhk8mQTqfJ5/Nks1kymQzpdJpcLkcul5s3gPJ/B1BbW0tra2tZfbZtMzw8TDKZnLXOtm1GRkYYGhqas862bUZHRxkcHJyzLpVKMTAwMGedZVmMjY0xMDAwZ93/BqCuro6mpqay+mzbZnx8nOHh4VnrbNtmYmKCwcHBOetu3LiRlpaWOetSqRR9fX1z1lmWxeTkJH19fXPW2bbN1NQUvb29c9YtGEBDQwONjY1l9YkIU1NTJBKJWetEhOnpaQYGBuass22b6elpEonEnHWpVIre3t4562zbZmZmhp6enjnrbNtmdnaW7u7uOesWDKCxsZGGhoay+kSEmZkZ+vv7Z60TEWZnZ+nr65uzzrZtZmdn6e/vn7MulUrR09MzZ51t2+RyObq7u+ess22bfD5PV1fXnHULBtDU1ER9fX1ZfSJCPp+nu7t71joRoVAo0NXVNW+dZVl0dnbOWZdKpejs7JyzzrZtCoUCHR0dc9bZtk2xWKS9vX3OugUDaG5uprq6uqw+EaFYLNLe3j5rnYhgWRbt7e1z1tm2jWVZtLW1zVmXSqU4e/bsnHW2bWNZFmfOnJmzzrZtLMvizJkzc9YtGEBLSwuRSKSsPhGhVCpx+vTpWetEhFKpxOnTp+ets22bUqnEqVOn5qxLpVKcPHlyzjrbtimVSpw8eXLOOtu2KZVKnDhxYs66BQNobW0lHA6X1ScilEolTp48OWudiGDbNidOnJi3zrZtbNvm+PHjc9alUimOHTs2Z51t29i2zbFjx+ass22bUqnE0aNH56w7hEM4hEU4fwO0OBnPo+UQmwAAAABJRU5ErkJggg== \ No newline at end of file diff --git a/submissions/Screen-Time-Tracker/manifest.json b/submissions/Screen-Time-Tracker/manifest.json new file mode 100644 index 00000000..cc699b13 --- /dev/null +++ b/submissions/Screen-Time-Tracker/manifest.json @@ -0,0 +1,28 @@ +{ + "manifest_version": 3, + "name": "Screen Time Tracker", + "version": "1.0", + "description": "Tracks time spent on websites and provides detailed usage statistics", + "permissions": [ + "storage", + "tabs", + "activeTab", + "alarms" + ], + "background": { + "service_worker": "background.js" + }, + "action": { + "default_popup": "popup.html", + "default_icon": { + "16": "icons/icon16.png", + "48": "icons/icon48.png", + "128": "icons/icon128.png" + } + }, + "icons": { + "16": "icons/icon16.png", + "48": "icons/icon48.png", + "128": "icons/icon128.png" + } +} diff --git a/submissions/Screen-Time-Tracker/popup.css b/submissions/Screen-Time-Tracker/popup.css new file mode 100644 index 00000000..b3e8f587 --- /dev/null +++ b/submissions/Screen-Time-Tracker/popup.css @@ -0,0 +1,171 @@ +body { + font-family: 'Segoe UI', Arial, sans-serif; + width: 350px; + margin: 0; + background: #f8f9fa; + color: #2c3e50; +} + +.container { + padding: 20px; + background: white; + border-radius: 12px; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); + margin: 8px; +} + +h1 { + font-size: 20px; + margin-top: 0; + color: #1a73e8; + text-align: center; + font-weight: 600; +} + +h2 { + font-size: 16px; + margin-top: 16px; + color: #3c4043; +} + +.tabs { + display: flex; + margin-bottom: 20px; + border-bottom: 1px solid #e0e0e0; + padding: 0 8px; +} + +.tab-button { + flex: 1; + background: none; + border: none; + padding: 12px; + cursor: pointer; + font-size: 14px; + color: #5f6368; + transition: all 0.3s ease; + position: relative; + font-weight: 500; +} + +.tab-button:hover { + color: #1a73e8; +} + +.tab-button.active { + color: #1a73e8; +} + +.tab-button.active::after { + content: ''; + position: absolute; + bottom: -1px; + left: 0; + width: 100%; + height: 2px; + background: #1a73e8; + transition: all 0.3s ease; +} + +.tab-content { + display: none; + opacity: 0; + transition: opacity 0.3s ease; +} + +.tab-content.active { + display: block; + opacity: 1; +} + +.total-time { + margin-bottom: 20px; + font-weight: 500; + background: #f1f3f4; + padding: 12px; + border-radius: 8px; + text-align: center; +} + +.stats-container { + max-height: 300px; + overflow-y: auto; + padding: 4px; +} + +.site-stat { + display: flex; + flex-direction: column; + padding: 12px; + border-radius: 8px; + background: #f8f9fa; + margin-bottom: 8px; + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.site-stat:hover { + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); +} + +.site-info { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; +} + +.site-name { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + color: #202124; + font-weight: 500; +} + +.site-time { + margin-left: 12px; + color: #5f6368; + font-weight: 500; +} + +.bar-container { + height: 6px; + width: 100%; + background-color: #e8eaed; + border-radius: 8px; + overflow: hidden; +} + +.bar { + height: 100%; + background-color: #1a73e8; + border-radius: 8px; + transition: width 0.3s ease; +} + +.stats-container::-webkit-scrollbar { + width: 8px; +} + +.stats-container::-webkit-scrollbar-track { + background: #f1f1f1; + border-radius: 4px; +} + +.stats-container::-webkit-scrollbar-thumb { + background: #c1c1c1; + border-radius: 4px; +} + +.stats-container::-webkit-scrollbar-thumb:hover { + background: #a8a8a8; +} + +#weeklyChart { + margin-top: 16px; + border-radius: 8px; + padding: 8px; + background: white; +} diff --git a/submissions/Screen-Time-Tracker/popup.html b/submissions/Screen-Time-Tracker/popup.html new file mode 100644 index 00000000..c59521c8 --- /dev/null +++ b/submissions/Screen-Time-Tracker/popup.html @@ -0,0 +1,35 @@ + + + + Screen Time Tracker + + + +
+

Screen Time Tracker

+ +
+ + +
+ +
+

Today's Activity

+
+ Total screen time: + 0m +
+
+
+ +
+

Last 7 Days

+
+ +
+
+ + + + + diff --git a/submissions/Screen-Time-Tracker/popup.js b/submissions/Screen-Time-Tracker/popup.js new file mode 100644 index 00000000..ec01ef0b --- /dev/null +++ b/submissions/Screen-Time-Tracker/popup.js @@ -0,0 +1,215 @@ +const todayTab = document.getElementById('todayTab'); +const historyTab = document.getElementById('historyTab'); +const todayView = document.getElementById('todayView'); +const historyView = document.getElementById('historyView'); +const totalTimeEl = document.getElementById('totalTime'); +const todayStatsEl = document.getElementById('todayStats'); +const historyStatsEl = document.getElementById('historyStats'); + +todayTab.addEventListener('click', () => { + todayTab.classList.add('active'); + historyTab.classList.remove('active'); + todayView.classList.add('active'); + historyView.classList.remove('active'); + + historyView.style.opacity = 0; + setTimeout(() => { + todayView.classList.add('active'); + historyView.classList.remove('active'); + requestAnimationFrame(() => { + todayView.style.opacity = 1; + }); + }, 300); + loadTodayStats(); +}); + +historyTab.addEventListener('click', () => { + historyTab.classList.add('active'); + todayTab.classList.remove('active'); + historyView.classList.add('active'); + todayView.classList.remove('active'); + + todayView.style.opacity = 0; + setTimeout(() => { + historyView.classList.add('active'); + todayView.classList.remove('active'); + requestAnimationFrame(() => { + historyView.style.opacity = 1; + }); + }, 300); + loadHistoryStats(); +}); + +function formatTime(ms) { + const seconds = Math.floor(ms / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + + if (hours > 0) { + return `${hours}h ${minutes % 60}m`; + } else if (minutes > 0) { + return `${minutes}m ${seconds % 60}s`; + } else { + return `${seconds}s`; + } +} + +function loadTodayStats() { + chrome.runtime.sendMessage({ action: 'getStats' }, (response) => { + const data = response.todayData; + todayStatsEl.innerHTML = ''; + + if (!data || Object.keys(data).length === 0) { + todayStatsEl.innerHTML = '

No data recorded today.

'; + totalTimeEl.textContent = '0m'; + return; + } + + let totalTime = 0; + let maxTime = 0; + + Object.values(data).forEach(time => { + totalTime += time; + if (time > maxTime) maxTime = time; + }); + + totalTimeEl.textContent = formatTime(totalTime); + + const sortedSites = Object.entries(data) + .sort((a, b) => b[1] - a[1]); + + sortedSites.forEach(([site, time], index) => { + const percentage = (time / maxTime) * 100; + + const siteEl = document.createElement('div'); + siteEl.className = 'site-stat'; + siteEl.style.opacity = '0'; + siteEl.style.transform = 'translateY(10px)'; + siteEl.innerHTML = ` +
+
${site}
+
${formatTime(time)}
+
+
+
+
+ `; + + todayStatsEl.appendChild(siteEl); + + setTimeout(() => { + siteEl.style.opacity = '1'; + siteEl.style.transform = 'translateY(0)'; + siteEl.querySelector('.bar').style.width = `${percentage}%`; + }, index * 100); + }); + }); +} + +function loadHistoryStats() { + chrome.runtime.sendMessage({ action: 'getHistory' }, (response) => { + const historyData = response.historyData; + historyStatsEl.innerHTML = ''; + + if (!historyData || Object.keys(historyData).length === 0) { + historyStatsEl.innerHTML = '

No historical data available.

'; + return; + } + + const dates = []; + const dailyTotals = []; + + const allSites = new Set(); + Object.values(historyData).forEach(dayData => { + Object.keys(dayData).forEach(site => allSites.add(site)); + }); + + const orderedDates = Object.keys(historyData).sort((a, b) => { + return new Date(b) - new Date(a); + }); + + const siteTotals = {}; + allSites.forEach(site => { + siteTotals[site] = 0; + orderedDates.forEach(date => { + if (historyData[date] && historyData[date][site]) { + siteTotals[site] += historyData[date][site]; + } + }); + }); + + const top5Sites = Object.entries(siteTotals) + .sort((a, b) => b[1] - a[1]) + .slice(0, 5); + + historyStatsEl.innerHTML = '

Top Sites (7 days)

'; + + top5Sites.forEach(([site, totalTime]) => { + const siteEl = document.createElement('div'); + siteEl.className = 'site-stat'; + siteEl.innerHTML = ` +
${site}
+
${formatTime(totalTime)}
+ `; + historyStatsEl.appendChild(siteEl); + }); + + orderedDates.reverse().forEach(date => { + const formattedDate = new Date(date).toLocaleDateString('en-US', { + month: 'short', + day: 'numeric' + }); + dates.push(formattedDate); + + let dailyTotal = 0; + if (historyData[date]) { + Object.values(historyData[date]).forEach(time => { + dailyTotal += time; + }); + } + + dailyTotals.push(dailyTotal / (1000 * 60 * 60)); + }); + + if (typeof Chart !== 'undefined') { + const ctx = document.getElementById('weeklyChart').getContext('2d'); + + if (window.screenTimeChart) { + window.screenTimeChart.destroy(); + } + + window.screenTimeChart = new Chart(ctx, { + type: 'bar', + data: { + labels: dates, + datasets: [{ + label: 'Screen Time (hours)', + data: dailyTotals, + backgroundColor: '#4285f4' + }] + }, + options: { + responsive: true, + scales: { + y: { + beginAtZero: true, + title: { + display: true, + text: 'Hours' + } + } + } + } + }); + } else { + const chartEl = document.getElementById('weeklyChart'); + chartEl.style.display = 'none'; + + const message = document.createElement('p'); + message.textContent = 'Chart.js is required for the weekly chart.'; + historyStatsEl.appendChild(message); + } + }); +} + +document.addEventListener('DOMContentLoaded', loadTodayStats);