From ac019810594f717d11123e4a087e37b8d8bd0cd6 Mon Sep 17 00:00:00 2001 From: Praveen kumar <168343716+Praveenkushinpi@users.noreply.github.com> Date: Wed, 11 Jun 2025 12:31:40 +0530 Subject: [PATCH 01/12] Create popup.html --- submissions/Calculator/popup.html | 1 + 1 file changed, 1 insertion(+) create mode 100644 submissions/Calculator/popup.html diff --git a/submissions/Calculator/popup.html b/submissions/Calculator/popup.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/submissions/Calculator/popup.html @@ -0,0 +1 @@ + From 7a122db30626b6aafe7b40528b5b00985571e0c8 Mon Sep 17 00:00:00 2001 From: Praveen kumar <168343716+Praveenkushinpi@users.noreply.github.com> Date: Wed, 11 Jun 2025 12:32:18 +0530 Subject: [PATCH 02/12] Add files via upload --- submissions/Calculator/Readme.md | 2 + submissions/Calculator/icon128.png | Bin 0 -> 2787 bytes submissions/Calculator/icon16.png | Bin 0 -> 2787 bytes submissions/Calculator/icon48.png | Bin 0 -> 2787 bytes submissions/Calculator/manifest.json | 16 +++ submissions/Calculator/popup.css | 144 ++++++++++++++++++++ submissions/Calculator/popup.html | 48 ++++++- submissions/Calculator/popup.js | 191 +++++++++++++++++++++++++++ 8 files changed, 400 insertions(+), 1 deletion(-) create mode 100644 submissions/Calculator/Readme.md create mode 100644 submissions/Calculator/icon128.png create mode 100644 submissions/Calculator/icon16.png create mode 100644 submissions/Calculator/icon48.png create mode 100644 submissions/Calculator/manifest.json create mode 100644 submissions/Calculator/popup.css create mode 100644 submissions/Calculator/popup.js diff --git a/submissions/Calculator/Readme.md b/submissions/Calculator/Readme.md new file mode 100644 index 00000000..96ae1ae1 --- /dev/null +++ b/submissions/Calculator/Readme.md @@ -0,0 +1,2 @@ +#CALCULATOR +## this is a brutalism designed calculator but in 90's style \ No newline at end of file diff --git a/submissions/Calculator/icon128.png b/submissions/Calculator/icon128.png new file mode 100644 index 0000000000000000000000000000000000000000..8bd5050f3dbc9d937f61756598f82baad3f07b4e GIT binary patch literal 2787 zcmcguSy)p^7QTrgf{9?FNQ}X>fq(*H(4Yor37e3xgh5%9?b?6=SsQG2Fa!oc76lQM zwlyvcU;+kEh_WTnf`WoTXiXza0|8kC2_i0tbD5rpd7OFZd8n_xbL!rzQ>V^<{y)>% z$#&xg{00C3HZtt2T>t=vh6Y?233*WIQ)AEsi*m8G1S-1-Q;>mRTR2((K-C4*%1I^2 zR*A4X9t8lZt!o3;9$w}T02^W%))vQNecle5hZEYjaTbb<^0_FF1L8rF{iha%s03%| zlFpOkw6g%dIuh!W2I36%Oc2#EXC2GoV)Bv16{z3ydzLpfA41)$vBi3>75`cH)FE>#y z-K&=;goeG^`DUJ2Ox{v-Vo=jA5~*|H(+%;xI8)kYOkU4Nha>Y{{?w}-fr-&UhmBWr zKHqhvnAq6=Hc&M#%fG|$Pevc=BRcp~4_{*Mb&|gw7t~_P6W6|YwEQ~)ZZV~%qmcIq zqZi8j*PL@hry1A3-hU2Q_7fe(Wm!k3)P`IS@3_1H$yYfx*d>`^p1X~eya}sd#?*x7 zrZDk2rPa$z!u&s!O>lx;&g`0~+*R<0bS*LPZsYBn zW?w&0--LGPzC6r|pAZ_HYuq^XI_#<+52G+BWNDn;+uBDQZ|?hcmAHOq1~`7)fEB;J z*XPr-73IK!4;}2@)jnfd+@j%=z=9_7(;5%egzXc!!23P1ddtM-4Pgl`)2-}Z;U9(6 z%<_GD3~LZ zp5=d*J{xp&J9I= z(Y%jGtD2@n%4PYq>W&kXSLXqFRFVO>2Nz!tPoUa9-yJB~1ZWlw+XPESlxTFE z!XUbKPZbvJZcgA_7@L0A$E0}qeo@+l)R%a$P2mV~&Y<9P1!5iDqnCV;pR6y5h|@!j zO!sP!fIuLU3zJ^t4-f>1RK7Mn*6Z~gNX7xhC;#}&{4hlDaoyIOqVj?{cB<)s!eYMU z{rb&OW*Yhuz_L&$k1#)M)c#tOy1M&tRd@$Yhp3GcO2HmsasHH%U24u9Z6GR6&)wTtyYuXACwLHTypBk zhZ4IL#Vgm_o(&nTL+Ma#d2^=*WcDoB${iPp-6gx|x|hjbj7=)ydrX8@_bAbQbA$Po zU91;tYfu42z8V0HVTkWufoIMaLVxevLZ@?4Z6U5z^^K>J5j=kjC9Uos+|=n}u1edi z08SS%)!IT(EqCF{zU7ib&G$x;Re;{D`(T6*>=!DB%!V+=G!}}zLFsn=1EvAz{315nEUTnmcAy>5Ym1|Z zNO0-7MGyih#TL-(2%;zqCSJqKFr^akCzv#=20T;e78iWbdA}1kPY2^}!@);lv%5ll zq$p|L5-5BGOn1gpJiLLW0CQYj6ST+ameZ78?a>ZpXFs=8Ni?GDAYU>f++21Ls;8|H zyj6jc-!CBWfV~&Tx1Ug^Kle~MQfwW<;2?$AYX(H zV}kLvO{gN(euh0ailG41^-vQ&5JM3Kp#pOsrownMh*ylcFnSIMIBVem>3?O0{<|D) zu0MtziqihT-7L}Y_JWk4MgQd%c`zX~$}2crm#yF}_Y%5uz(j5C-!!3x`hnmH(Qik_ z%D1T9_<8JM6&dz_;Da^dY0mzn^_I|Zz*borZ(8Wov#^;aSfyoZ@0roF$dhCd8tFlMrLn8R65+>zyYGw^_lek}W!aJh^%*ZfH zS|COtc!Pn!q~7m>o=~X7O`tM(Cl)uI(H|jmnibw0Q(qPc>yUvjzPo% zbuF!;0Zf%9x|U3j^9r~9HJXwZs^W})Ie_^QlihgloM0aZJDarBMmWy?9yi%Za@)pX zCD>X;ji)Vv%6zogl*mW@sGi*uI~`!IBp#l&^ir}iJm0RjE+UwEJ>JthqZ7<1J?hDO zns~PT8Zy-tIg&fy|96pUdVw>Yw>w(3X}@h3O|5OnJ-lH@2jD1-p`J;0pFDR+EnR2~ z6HKe=4AqhL`#`a~m?b(x%o+HlZ+itjeV8@1NZa)=kZP(!w1-9+Hd@3!~nhXrg@@ zA{5;!0H2fu8nkCAg5IxR^aC{Xvz&j}8Gy7hytQzzkEreIO~P|_7KAAZ;hYUkXuqZey7FmVO`*V*$&rNhw?(ryc1PVp5fb9 z6ZT@&5c5+D<=4=Ljs6I(rsPT-~Ll>>p7_j m4w%*ZdK?S%Tl{6B?8DiDqJhXq@)m7Km;wwNC+kW}ko!-HW~(9q literal 0 HcmV?d00001 diff --git a/submissions/Calculator/icon16.png b/submissions/Calculator/icon16.png new file mode 100644 index 0000000000000000000000000000000000000000..8bd5050f3dbc9d937f61756598f82baad3f07b4e GIT binary patch literal 2787 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 literal 0 HcmV?d00001 diff --git a/submissions/Calculator/icon48.png b/submissions/Calculator/icon48.png new file mode 100644 index 0000000000000000000000000000000000000000..8bd5050f3dbc9d937f61756598f82baad3f07b4e GIT binary patch literal 2787 zcmcguSy)p^7QTrgf{9?FNQ}X>fq(*H(4Yor37e3xgh5%9?b?6=SsQG2Fa!oc76lQM zwlyvcU;+kEh_WTnf`WoTXiXza0|8kC2_i0tbD5rpd7OFZd8n_xbL!rzQ>V^<{y)>% z$#&xg{00C3HZtt2T>t=vh6Y?233*WIQ)AEsi*m8G1S-1-Q;>mRTR2((K-C4*%1I^2 zR*A4X9t8lZt!o3;9$w}T02^W%))vQNecle5hZEYjaTbb<^0_FF1L8rF{iha%s03%| zlFpOkw6g%dIuh!W2I36%Oc2#EXC2GoV)Bv16{z3ydzLpfA41)$vBi3>75`cH)FE>#y z-K&=;goeG^`DUJ2Ox{v-Vo=jA5~*|H(+%;xI8)kYOkU4Nha>Y{{?w}-fr-&UhmBWr zKHqhvnAq6=Hc&M#%fG|$Pevc=BRcp~4_{*Mb&|gw7t~_P6W6|YwEQ~)ZZV~%qmcIq zqZi8j*PL@hry1A3-hU2Q_7fe(Wm!k3)P`IS@3_1H$yYfx*d>`^p1X~eya}sd#?*x7 zrZDk2rPa$z!u&s!O>lx;&g`0~+*R<0bS*LPZsYBn zW?w&0--LGPzC6r|pAZ_HYuq^XI_#<+52G+BWNDn;+uBDQZ|?hcmAHOq1~`7)fEB;J z*XPr-73IK!4;}2@)jnfd+@j%=z=9_7(;5%egzXc!!23P1ddtM-4Pgl`)2-}Z;U9(6 z%<_GD3~LZ zp5=d*J{xp&J9I= z(Y%jGtD2@n%4PYq>W&kXSLXqFRFVO>2Nz!tPoUa9-yJB~1ZWlw+XPESlxTFE z!XUbKPZbvJZcgA_7@L0A$E0}qeo@+l)R%a$P2mV~&Y<9P1!5iDqnCV;pR6y5h|@!j zO!sP!fIuLU3zJ^t4-f>1RK7Mn*6Z~gNX7xhC;#}&{4hlDaoyIOqVj?{cB<)s!eYMU z{rb&OW*Yhuz_L&$k1#)M)c#tOy1M&tRd@$Yhp3GcO2HmsasHH%U24u9Z6GR6&)wTtyYuXACwLHTypBk zhZ4IL#Vgm_o(&nTL+Ma#d2^=*WcDoB${iPp-6gx|x|hjbj7=)ydrX8@_bAbQbA$Po zU91;tYfu42z8V0HVTkWufoIMaLVxevLZ@?4Z6U5z^^K>J5j=kjC9Uos+|=n}u1edi z08SS%)!IT(EqCF{zU7ib&G$x;Re;{D`(T6*>=!DB%!V+=G!}}zLFsn=1EvAz{315nEUTnmcAy>5Ym1|Z zNO0-7MGyih#TL-(2%;zqCSJqKFr^akCzv#=20T;e78iWbdA}1kPY2^}!@);lv%5ll zq$p|L5-5BGOn1gpJiLLW0CQYj6ST+ameZ78?a>ZpXFs=8Ni?GDAYU>f++21Ls;8|H zyj6jc-!CBWfV~&Tx1Ug^Kle~MQfwW<;2?$AYX(H zV}kLvO{gN(euh0ailG41^-vQ&5JM3Kp#pOsrownMh*ylcFnSIMIBVem>3?O0{<|D) zu0MtziqihT-7L}Y_JWk4MgQd%c`zX~$}2crm#yF}_Y%5uz(j5C-!!3x`hnmH(Qik_ z%D1T9_<8JM6&dz_;Da^dY0mzn^_I|Zz*borZ(8Wov#^;aSfyoZ@0roF$dhCd8tFlMrLn8R65+>zyYGw^_lek}W!aJh^%*ZfH zS|COtc!Pn!q~7m>o=~X7O`tM(Cl)uI(H|jmnibw0Q(qPc>yUvjzPo% zbuF!;0Zf%9x|U3j^9r~9HJXwZs^W})Ie_^QlihgloM0aZJDarBMmWy?9yi%Za@)pX zCD>X;ji)Vv%6zogl*mW@sGi*uI~`!IBp#l&^ir}iJm0RjE+UwEJ>JthqZ7<1J?hDO zns~PT8Zy-tIg&fy|96pUdVw>Yw>w(3X}@h3O|5OnJ-lH@2jD1-p`J;0pFDR+EnR2~ z6HKe=4AqhL`#`a~m?b(x%o+HlZ+itjeV8@1NZa)=kZP(!w1-9+Hd@3!~nhXrg@@ zA{5;!0H2fu8nkCAg5IxR^aC{Xvz&j}8Gy7hytQzzkEreIO~P|_7KAAZ;hYUkXuqZey7FmVO`*V*$&rNhw?(ryc1PVp5fb9 z6ZT@&5c5+D<=4=Ljs6I(rsPT-~Ll>>p7_j m4w%*ZdK?S%Tl{6B?8DiDqJhXq@)m7Km;wwNC+kW}ko!-HW~(9q literal 0 HcmV?d00001 diff --git a/submissions/Calculator/manifest.json b/submissions/Calculator/manifest.json new file mode 100644 index 00000000..1520985c --- /dev/null +++ b/submissions/Calculator/manifest.json @@ -0,0 +1,16 @@ +{ + "manifest_version": 3, + "name": "CALCULATOR", + "version": "1.0", + "description": "A brutalist-style calculator extension", + "action": { + "default_popup": "popup.html", + "default_title": "CALCULATOR" + }, + "icons": { + "16": "icon16.png", + "48": "icon48.png", + "128": "icon128.png" + }, + "permissions": [] +} diff --git a/submissions/Calculator/popup.css b/submissions/Calculator/popup.css new file mode 100644 index 00000000..7e524697 --- /dev/null +++ b/submissions/Calculator/popup.css @@ -0,0 +1,144 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'MS Sans Serif', 'Segoe UI', sans-serif; + font-size: 11px; + background: #c0c0c0; + width: 280px; + height: 350px; + overflow: hidden; +} + +.window { + background: #c0c0c0; + border: 2px outset #c0c0c0; + width: 100%; + height: 100%; +} + +.title-bar { + background: linear-gradient(90deg, #000080 0%, #000060 100%); + color: white; + padding: 3px 6px; + font-weight: bold; + font-size: 11px; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.content { + padding: 8px; + height: calc(100% - 22px); + display: flex; + flex-direction: column; +} + +.display { + background: white; + border: 2px inset #c0c0c0; + padding: 4px 8px; + text-align: right; + font-family: 'Courier New', monospace; + font-size: 16px; + font-weight: bold; + margin-bottom: 8px; + height: 36px; + display: flex; + align-items: center; + justify-content: flex-end; + overflow: hidden; + word-break: break-all; +} + +.memory-display { + font-size: 9px; + color: #666; + margin-bottom: 2px; + text-align: right; + height: 12px; + font-family: 'Courier New', monospace; +} + +.buttons { + display: grid; + grid-template-columns: repeat(4, 1fr); + grid-template-rows: repeat(5, 1fr); + gap: 3px; + flex: 1; +} + +.btn { + background: #c0c0c0; + border: 2px outset #c0c0c0; + font-family: 'MS Sans Serif', 'Segoe UI', sans-serif; + font-size: 12px; + font-weight: bold; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + min-height: 32px; + user-select: none; + transition: none; +} + +.btn:hover { + background: #d4d4d4; +} + +.btn:active { + border: 2px inset #c0c0c0; + background: #b8b8b8; +} + +.btn.operator { + background: #dfdfdf; + color: #000; +} + +.btn.operator:hover { + background: #e8e8e8; +} + +.btn.clear { + background: #ff9999; + color: #000; +} + +.btn.clear:hover { + background: #ffaaaa; +} + +.btn.clear:active { + background: #ff8888; +} + +.btn.equals { + background: #99ff99; + color: #000; + grid-row: span 2; +} + +.btn.equals:hover { + background: #aaffaa; +} + +.btn.equals:active { + background: #88ff88; +} + +.btn.zero { + grid-column: span 2; +} + +.btn.number { + background: #c0c0c0; +} + +.btn.number:hover { + background: #d4d4d4; +} diff --git a/submissions/Calculator/popup.html b/submissions/Calculator/popup.html index 8b137891..35f73c4b 100644 --- a/submissions/Calculator/popup.html +++ b/submissions/Calculator/popup.html @@ -1 +1,47 @@ - + + + + + + + CALCULATOR + + + +
+
+ CALCULATOR +
+
+
+
0
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + diff --git a/submissions/Calculator/popup.js b/submissions/Calculator/popup.js new file mode 100644 index 00000000..bf8d8143 --- /dev/null +++ b/submissions/Calculator/popup.js @@ -0,0 +1,191 @@ +class BrutalistCalculator { + constructor() { + this.display = document.getElementById('display'); + this.memoryDisplay = document.getElementById('memory'); + this.currentInput = '0'; + this.operator = null; + this.previousInput = null; + this.waitingForNewInput = false; + + this.initializeEventListeners(); + } + + initializeEventListeners() { + + document.querySelectorAll('.btn').forEach(button => { + button.addEventListener('click', (e) => { + e.preventDefault(); + this.handleButtonClick(button); + }); + }); + + document.addEventListener('keydown', (e) => { + this.handleKeyPress(e); + }); + } + + handleButtonClick(button) { + const action = button.dataset.action; + const value = button.dataset.value; + + button.style.transform = 'scale(0.95)'; + setTimeout(() => { + button.style.transform = 'scale(1)'; + }, 100); + + switch (action) { + case 'number': + this.inputNumber(value); + break; + case 'operator': + this.inputOperator(value); + break; + case 'equals': + this.calculate(); + break; + case 'decimal': + this.inputDecimal(); + break; + case 'clear-all': + this.clearAll(); + break; + case 'clear-entry': + this.clearEntry(); + break; + } + } + + handleKeyPress(e) { + e.preventDefault(); + + if (e.key >= '0' && e.key <= '9') { + this.inputNumber(e.key); + } else if (e.key === '.') { + this.inputDecimal(); + } else if (['+', '-', '*', '/'].includes(e.key)) { + this.inputOperator(e.key); + } else if (e.key === 'Enter' || e.key === '=') { + this.calculate(); + } else if (e.key === 'Escape') { + this.clearAll(); + } else if (e.key === 'Delete' || e.key === 'Backspace') { + this.clearEntry(); + } + } + + updateDisplay() { + let displayValue = this.currentInput; + + + if (displayValue.length > 12) { + const num = parseFloat(displayValue); + displayValue = num.toExponential(6); + } + + this.display.textContent = displayValue; + } + + updateMemory() { + if (this.previousInput !== null && this.operator !== null) { + this.memoryDisplay.textContent = `${this.previousInput} ${this.operator}`; + } else { + this.memoryDisplay.textContent = ''; + } + } + + inputNumber(num) { + if (this.waitingForNewInput) { + this.currentInput = num; + this.waitingForNewInput = false; + } else { + this.currentInput = this.currentInput === '0' ? num : this.currentInput + num; + } + this.updateDisplay(); + } + + inputDecimal() { + if (this.waitingForNewInput) { + this.currentInput = '0.'; + this.waitingForNewInput = false; + } else if (!this.currentInput.includes('.')) { + this.currentInput += '.'; + } + this.updateDisplay(); + } + + inputOperator(op) { + if (this.previousInput !== null && this.operator !== null && !this.waitingForNewInput) { + this.calculate(); + } + + this.previousInput = this.currentInput; + this.operator = op; + this.waitingForNewInput = true; + this.updateMemory(); + } + + calculate() { + if (this.previousInput === null || this.operator === null) return; + + const prev = parseFloat(this.previousInput); + const current = parseFloat(this.currentInput); + let result; + + switch (this.operator) { + case '+': + result = prev + current; + break; + case '-': + result = prev - current; + break; + case '*': + result = prev * current; + break; + case '/': + if (current === 0) { + this.currentInput = 'ERROR'; + this.previousInput = null; + this.operator = null; + this.waitingForNewInput = true; + this.updateDisplay(); + this.updateMemory(); + return; + } + result = prev / current; + break; + default: + return; + } + + if (isNaN(result) || !isFinite(result)) { + this.currentInput = 'ERROR'; + } else { + this.currentInput = result.toString(); + } + + this.previousInput = null; + this.operator = null; + this.waitingForNewInput = true; + this.updateDisplay(); + this.updateMemory(); + } + + clearEntry() { + this.currentInput = '0'; + this.updateDisplay(); + } + + clearAll() { + this.currentInput = '0'; + this.previousInput = null; + this.operator = null; + this.waitingForNewInput = false; + this.updateDisplay(); + this.updateMemory(); + } +} + + +document.addEventListener('DOMContentLoaded', () => { + new BrutalistCalculator(); +}); \ No newline at end of file From 1ea5457f4a8e943ab89c174dea524c2cfc90f8b8 Mon Sep 17 00:00:00 2001 From: Praveen kumar <168343716+Praveenkushinpi@users.noreply.github.com> Date: Fri, 13 Jun 2025 07:29:56 +0530 Subject: [PATCH 03/12] Create popup.html --- submissions/Movio/popup.html | 1 + 1 file changed, 1 insertion(+) create mode 100644 submissions/Movio/popup.html diff --git a/submissions/Movio/popup.html b/submissions/Movio/popup.html new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/submissions/Movio/popup.html @@ -0,0 +1 @@ + From e14acd381f1bdc39d341bc24487505f4c23d38f9 Mon Sep 17 00:00:00 2001 From: Praveen kumar <168343716+Praveenkushinpi@users.noreply.github.com> Date: Fri, 13 Jun 2025 07:31:42 +0530 Subject: [PATCH 04/12] Add files via upload --- submissions/Movio/icon.png | Bin 0 -> 3036 bytes submissions/Movio/manifest.json | 14 ++ submissions/Movio/ng.js | 46 ++++++ submissions/Movio/popup.css | 261 ++++++++++++++++++++++++++++++++ submissions/Movio/popup.html | 25 ++- submissions/Movio/popup.js | 43 ++++++ 6 files changed, 388 insertions(+), 1 deletion(-) create mode 100644 submissions/Movio/icon.png create mode 100644 submissions/Movio/manifest.json create mode 100644 submissions/Movio/ng.js create mode 100644 submissions/Movio/popup.css create mode 100644 submissions/Movio/popup.js diff --git a/submissions/Movio/icon.png b/submissions/Movio/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fbefe2c29bc976791f83e2bc5f69afb2baf39ab2 GIT binary patch literal 3036 zcmcgu`#%%vAEzed(#CNrDWz{w8moY}lqG+fQ2T|Xc9VDXVvaJof znttPfE} zM)md2CfgiVa#cn~>4p;=>UkS8Ggu$CZ(@J*97|s}7$R|2`0lxV$t{}k=7?s$jNjE3 zf>qTv(X(aX%~DWQd5v62>hb+o4|z;J!{19eVG^Nd2|u^B4fip~)Jkk!aB~BeF7m!E z@0>WFP&nJXU}M`pxGs158!Yz&t3BpT^+c6b#Fs94mfT&hVxg=|9|&SEE7O-uN_OXPl%?ml(K6mxx*Htx>cnk(7lK zR;lCHFWV-xuGW&FZf`mFjr9%v!GB?NhXK&j$gOYth^M&H^zN@k3j!3rCQKD~Qr&a( zqA<}y8OP7+-ZVSVxE%QUXmLEQnyG54NkoLrq`bh;n}*h@39Zbrn`{&QSxvN?GN17s zC7D{@PKfUoba}G8@&@}g-ntVneZJ?9o~#6b%lidG+WMR<+ceg^qnvT{GhxFQY!J!N zt_(w0%~O-J;=qnrkj`|4TY5)%2b+C&F0m&xXBawbGqMXlP4B|y2hHA|hkl7a!pVxj zg@F%wZ#Rb07SZ0hxAhgp`_h`$IazWXk&M97p3o;a^gxyzk`K61m239NW<>M zGZ$@rHaoPA>yvQ>+^$kdVt!>ILqQDWAj5OiLu26V!~*W)&ZqdP!{i8M6!<_SYnLNC z9ZG0?y#s%WY`V?myJHbE-I09;tGI>dh~^Z;ioZLZ&!WOCB&A1s_HgkUMd?1!$g1vI+o9t048_={FUS&bT0E zMTmXKVeh@aY{DGTG)MMHy=a0_rI zOSx@58G}=$I+VtXzTBh@ij}BSObtE%2Y2Y3Gz(8nnrc>N4cEl5skXEKamn*~RsvQf zHjq-z<@^nuOme0z3LZb^WsSoJDw3QP#P)qCmpg^}0v+$LOd6MSi=|#BJ$L(RuCI@B zY2VY@5?8h=ka5@q-Fme8`GL?SKLFvk<=q3pl@-n9drrF9Iv)H7L-bPEMaBz$P3%4Hl}Cc;9~Hz#Kg7Xw zF7m0wSp0LCsg}U<%r8qyov0iSDxN+9Vt_bk7vc(k^h885&+>pk6I#vXP`?o{4{~{$ zY1q6!CE~7Y^fcsvRs#qy1?XqejG!0SvDXbJ=?A93+sGR60fgiR&%*;Nfybv5FF!u$ zZS=hd6~&>5`LK7`4AWRUhSR6GiraMLbceLWS&pI zGu+dkb%KOfwYZ0+6%3-B1{|f8z42h7SKrI0O*#L7S>L8y{aRwnJ|lX)`hZJ?vE$7z z?qg}A&V-;@%Gc%UwgOXa#p!Wy!`OJ5T{MB9)AVZmhCiGlB zI}__w;9YacN6y(tA-W4+d1G@QL;3u%wKOju^srWy zggrQv#a%jI6?;WQk4h;v@LT)9wfLM8_haPY_#?0Sy7J&L`RhQ>(G1ZpQRJPK!n*gE zD#Hss)Pp5&{D0J3{-I8YzTp3I*xNLT2m)xV3fii5bmmJ|D3p}|Upz#qu!I$TnNq~m zxMfa4<+P9dr&BP!$}qO^wP!>6g5#p5C42W}ZJp`I))3yVzsjO1XIOet^q8SLRsj z$fAnC{S%DPiHugrQqxAcT$wwxLm^9til$F=+*ctd$M{%pox4`I0-wcvZXHyLsahRU z&$e542+&<=i<^}r)834U!#{dP3x&(EHxj_Q*=H zv1{LkJ-5um0AP6ouK3hIaAdgaEauI!<##m$GG#jzMR-!ITc%LhyqN9PM~3L3FED#hHb=O1)6F$yX}_ zp*Z}Ar;d)*ov>V(7|*-(D?)zioAnScji^)RRK)c~hu2q{m#W>(t96RKLK6kYT#KRG zzQd^>O%r!15Rki`BC=uGLGO$8-^u?}N~~M|OlV;LWQSDr;s)G0s-8DJeZD2Wc%toN z&jD+j;x01p|Nn~fw}A=KGZj%DI(ckx{raZA@MHPF;3n$b`Pz)t)uqBZ#{1O_i|GfS zMSHU?H&L;Rk-TFFt2-I { + if (e.key === "Enter") { + searchMovie(); + } + }); + + function searchMovie() { + const movieTitle = document.getElementById("movieInput").value.trim(); + const resultDiv = document.getElementById("result"); + + if (!movieTitle) { + resultDiv.innerHTML = '
⚠️ Please enter a movie name!
'; + return; + } + + // Show loading state + resultDiv.innerHTML = '
Searching...
'; + + fetch(`https://www.omdbapi.com/?apikey=${apiKey}&t=${encodeURIComponent(movieTitle)}`) + .then(response => response.json()) + .then(data => { + if (data.Response === "True") { + resultDiv.innerHTML = ` +

${data.Title} (${data.Year})

+
+ ${data.Poster !== "N/A" ? `Movie Poster` : ''} +

Genre: ${data.Genre || 'N/A'}

+

Director: ${data.Director || 'N/A'}

+

Actors: ${data.Actors || 'N/A'}

+

Plot: ${data.Plot || 'N/A'}

+

IMDb: ${data.imdbRating || 'N/A'}/10

+

Runtime: ${data.Runtime || 'N/A'}

+
+ `; + } else { + resultDiv.innerHTML = '
❌ Movie not found! Try another title.
'; + } + }) + .catch(err => { + resultDiv.innerHTML = '
🔥 Error fetching data. Check your connection!
'; + console.error(err); + }); + } \ No newline at end of file diff --git a/submissions/Movio/popup.css b/submissions/Movio/popup.css new file mode 100644 index 00000000..2dd2d9d6 --- /dev/null +++ b/submissions/Movio/popup.css @@ -0,0 +1,261 @@ + * { + margin: 0; + padding: 0; + box-sizing: border-box; + } + + body { + font-family: 'Courier New', monospace; + width: 380px; + background: linear-gradient(135deg, #4ecdc4 0%, #ff6b6b 100%); + color: #000; + overflow-x: hidden; + } + + .container { + padding: 20px; + position: relative; + } + + .container::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 8px; + background: repeating-linear-gradient( + 90deg, + #000 0px, + #000 20px, + #fff 20px, + #fff 40px + ); + } + + h2 { + font-size: 28px; + font-weight: 900; + text-transform: uppercase; + letter-spacing: 2px; + margin-bottom: 25px; + text-align: center; + background: #000; + color: #fff; + padding: 15px; + border: 4px solid #fff; + box-shadow: 8px 8px 0px #333; + transform: rotate(-1deg); + position: relative; + z-index: 2; + } + + h2::after { + content: '⚡'; + position: absolute; + top: -10px; + right: -10px; + background: #ff6b6b; + color: #fff; + width: 30px; + height: 30px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + border: 3px solid #000; + } + + .input-container { + position: relative; + margin-bottom: 20px; + } + + input { + width: 100%; + padding: 15px 20px; + font-size: 16px; + font-family: 'Courier New', monospace; + font-weight: bold; + border: 4px solid #000; + background: #fff; + color: #000; + text-transform: uppercase; + letter-spacing: 1px; + box-shadow: 6px 6px 0px #000; + transition: all 0.2s ease; + } + + input:focus { + outline: none; + transform: translate(-2px, -2px); + box-shadow: 8px 8px 0px #000; + background: #ffff00; + } + + input::placeholder { + color: #666; + text-transform: uppercase; + letter-spacing: 1px; + } + + button { + width: 100%; + padding: 18px; + font-size: 18px; + font-family: 'Courier New', monospace; + font-weight: 900; + text-transform: uppercase; + letter-spacing: 2px; + background: #000; + color: #fff; + border: 4px solid #fff; + cursor: pointer; + box-shadow: 6px 6px 0px #333; + transition: all 0.2s ease; + position: relative; + overflow: hidden; + margin-bottom: 25px; + } + + button:hover { + background: #ff6b6b; + transform: translate(-2px, -2px); + box-shadow: 8px 8px 0px #333; + } + + button:active { + transform: translate(2px, 2px); + box-shadow: 2px 2px 0px #333; + } + + button::before { + content: '🎬'; + position: absolute; + left: -30px; + top: 50%; + transform: translateY(-50%); + font-size: 20px; + transition: all 0.3s ease; + } + + button:hover::before { + left: 10px; + } + + #result { + background: #fff; + border: 4px solid #000; + min-height: 100px; + padding: 20px; + box-shadow: 6px 6px 0px #000; + position: relative; + margin-top: 10px; + } + + #result:empty { + display: none; + } + + #result h3 { + font-size: 20px; + font-weight: 900; + text-transform: uppercase; + letter-spacing: 1px; + margin-bottom: 15px; + color: #000; + background: #ffff00; + padding: 10px; + border: 3px solid #000; + display: inline-block; + transform: rotate(1deg); + } + + #result img { + width: 120px; + height: 180px; + object-fit: cover; + border: 4px solid #000; + box-shadow: 4px 4px 0px #333; + float: left; + margin: 0 20px 20px 0; + transition: transform 0.3s ease; + } + + #result img:hover { + transform: scale(1.05) rotate(-2deg); + } + + #result p { + font-size: 14px; + font-weight: bold; + line-height: 1.6; + margin-bottom: 12px; + color: #000; + text-transform: uppercase; + letter-spacing: 0.5px; + } + + #result strong { + background: #000; + color: #fff; + padding: 2px 6px; + margin-right: 8px; + font-size: 12px; + letter-spacing: 1px; + } + + .error { + color: #ff0000; + font-weight: 900; + text-align: center; + font-size: 16px; + text-transform: uppercase; + letter-spacing: 1px; + background: #fff; + padding: 15px; + border: 4px solid #ff0000; + box-shadow: 4px 4px 0px #333; + } + + .loading { + display: flex; + justify-content: center; + align-items: center; + padding: 40px; + font-size: 18px; + font-weight: bold; + text-transform: uppercase; + letter-spacing: 2px; + } + + .loading::after { + content: ''; + width: 20px; + height: 20px; + border: 3px solid #000; + border-top: 3px solid #ff6b6b; + border-radius: 50%; + animation: spin 1s linear infinite; + margin-left: 10px; + } + + @keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } + } + + + .container::after { + content: ''; + position: absolute; + bottom: 10px; + right: 10px; + width: 0; + height: 0; + border-left: 20px solid transparent; + border-right: 20px solid transparent; + border-bottom: 20px solid #000; + transform: rotate(45deg); + } diff --git a/submissions/Movio/popup.html b/submissions/Movio/popup.html index 8b137891..7792263a 100644 --- a/submissions/Movio/popup.html +++ b/submissions/Movio/popup.html @@ -1 +1,24 @@ - + + + + + + Movio + + + +
+

🎬 Movie Search

+
+ +
+ + + +
+
+ + + + + \ No newline at end of file diff --git a/submissions/Movio/popup.js b/submissions/Movio/popup.js new file mode 100644 index 00000000..a6187930 --- /dev/null +++ b/submissions/Movio/popup.js @@ -0,0 +1,43 @@ +const apiKey = "1fe8889c"; + +document.getElementById("searchBtn").addEventListener("click", searchMovie); +document.getElementById("movieInput").addEventListener("keypress", (e) => { + if (e.key === "Enter") { + searchMovie(); + } +}); + +function searchMovie() { + const movieTitle = document.getElementById("movieInput").value.trim(); + const resultDiv = document.getElementById("result"); + if (!movieTitle) { + resultDiv.innerHTML = '
⚠️ Please enter a movie name!
'; + return; + } + resultDiv.innerHTML = '
Getting You Movie ......
'; + + fetch(`https://www.omdbapi.com/?apikey=${apiKey}&t=${encodeURIComponent(movieTitle)}`) + .then(response => response.json()) + .then(data => { + if (data.Response === "True") { + resultDiv.innerHTML = ` +

${data.Title} (${data.Year})

+
+ ${data.Poster !== "N/A" ? `Movie Poster` : ''} +

Genre: ${data.Genre || 'N/A'}

+

Director: ${data.Director || 'N/A'}

+

Actors: ${data.Actors || 'N/A'}

+

Plot: ${data.Plot || 'N/A'}

+

IMDb: ${data.imdbRating || 'N/A'}/10

+

Runtime: ${data.Runtime || 'N/A'}

+
+ `; + } else { + resultDiv.innerHTML = '
Movie not found
'; + } + }) + .catch(err => { + resultDiv.innerHTML = '
🔥 Error fetching data. Check your connection!
'; + console.error(err); + }); +} \ No newline at end of file From de579eeb6809b61cbf36ceb4f86214815c64ccec Mon Sep 17 00:00:00 2001 From: Praveen kumar <168343716+Praveenkushinpi@users.noreply.github.com> Date: Sun, 29 Jun 2025 18:45:54 +0530 Subject: [PATCH 05/12] Delete submissions/Calculator/popup.js --- submissions/Calculator/popup.js | 191 -------------------------------- 1 file changed, 191 deletions(-) delete mode 100644 submissions/Calculator/popup.js diff --git a/submissions/Calculator/popup.js b/submissions/Calculator/popup.js deleted file mode 100644 index bf8d8143..00000000 --- a/submissions/Calculator/popup.js +++ /dev/null @@ -1,191 +0,0 @@ -class BrutalistCalculator { - constructor() { - this.display = document.getElementById('display'); - this.memoryDisplay = document.getElementById('memory'); - this.currentInput = '0'; - this.operator = null; - this.previousInput = null; - this.waitingForNewInput = false; - - this.initializeEventListeners(); - } - - initializeEventListeners() { - - document.querySelectorAll('.btn').forEach(button => { - button.addEventListener('click', (e) => { - e.preventDefault(); - this.handleButtonClick(button); - }); - }); - - document.addEventListener('keydown', (e) => { - this.handleKeyPress(e); - }); - } - - handleButtonClick(button) { - const action = button.dataset.action; - const value = button.dataset.value; - - button.style.transform = 'scale(0.95)'; - setTimeout(() => { - button.style.transform = 'scale(1)'; - }, 100); - - switch (action) { - case 'number': - this.inputNumber(value); - break; - case 'operator': - this.inputOperator(value); - break; - case 'equals': - this.calculate(); - break; - case 'decimal': - this.inputDecimal(); - break; - case 'clear-all': - this.clearAll(); - break; - case 'clear-entry': - this.clearEntry(); - break; - } - } - - handleKeyPress(e) { - e.preventDefault(); - - if (e.key >= '0' && e.key <= '9') { - this.inputNumber(e.key); - } else if (e.key === '.') { - this.inputDecimal(); - } else if (['+', '-', '*', '/'].includes(e.key)) { - this.inputOperator(e.key); - } else if (e.key === 'Enter' || e.key === '=') { - this.calculate(); - } else if (e.key === 'Escape') { - this.clearAll(); - } else if (e.key === 'Delete' || e.key === 'Backspace') { - this.clearEntry(); - } - } - - updateDisplay() { - let displayValue = this.currentInput; - - - if (displayValue.length > 12) { - const num = parseFloat(displayValue); - displayValue = num.toExponential(6); - } - - this.display.textContent = displayValue; - } - - updateMemory() { - if (this.previousInput !== null && this.operator !== null) { - this.memoryDisplay.textContent = `${this.previousInput} ${this.operator}`; - } else { - this.memoryDisplay.textContent = ''; - } - } - - inputNumber(num) { - if (this.waitingForNewInput) { - this.currentInput = num; - this.waitingForNewInput = false; - } else { - this.currentInput = this.currentInput === '0' ? num : this.currentInput + num; - } - this.updateDisplay(); - } - - inputDecimal() { - if (this.waitingForNewInput) { - this.currentInput = '0.'; - this.waitingForNewInput = false; - } else if (!this.currentInput.includes('.')) { - this.currentInput += '.'; - } - this.updateDisplay(); - } - - inputOperator(op) { - if (this.previousInput !== null && this.operator !== null && !this.waitingForNewInput) { - this.calculate(); - } - - this.previousInput = this.currentInput; - this.operator = op; - this.waitingForNewInput = true; - this.updateMemory(); - } - - calculate() { - if (this.previousInput === null || this.operator === null) return; - - const prev = parseFloat(this.previousInput); - const current = parseFloat(this.currentInput); - let result; - - switch (this.operator) { - case '+': - result = prev + current; - break; - case '-': - result = prev - current; - break; - case '*': - result = prev * current; - break; - case '/': - if (current === 0) { - this.currentInput = 'ERROR'; - this.previousInput = null; - this.operator = null; - this.waitingForNewInput = true; - this.updateDisplay(); - this.updateMemory(); - return; - } - result = prev / current; - break; - default: - return; - } - - if (isNaN(result) || !isFinite(result)) { - this.currentInput = 'ERROR'; - } else { - this.currentInput = result.toString(); - } - - this.previousInput = null; - this.operator = null; - this.waitingForNewInput = true; - this.updateDisplay(); - this.updateMemory(); - } - - clearEntry() { - this.currentInput = '0'; - this.updateDisplay(); - } - - clearAll() { - this.currentInput = '0'; - this.previousInput = null; - this.operator = null; - this.waitingForNewInput = false; - this.updateDisplay(); - this.updateMemory(); - } -} - - -document.addEventListener('DOMContentLoaded', () => { - new BrutalistCalculator(); -}); \ No newline at end of file From dbde3f1d7cf9d6204ab3582a5394dd3032dcd04d Mon Sep 17 00:00:00 2001 From: Praveen kumar <168343716+Praveenkushinpi@users.noreply.github.com> Date: Sun, 29 Jun 2025 18:46:07 +0530 Subject: [PATCH 06/12] Delete submissions/Calculator/popup.css --- submissions/Calculator/popup.css | 144 ------------------------------- 1 file changed, 144 deletions(-) delete mode 100644 submissions/Calculator/popup.css diff --git a/submissions/Calculator/popup.css b/submissions/Calculator/popup.css deleted file mode 100644 index 7e524697..00000000 --- a/submissions/Calculator/popup.css +++ /dev/null @@ -1,144 +0,0 @@ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: 'MS Sans Serif', 'Segoe UI', sans-serif; - font-size: 11px; - background: #c0c0c0; - width: 280px; - height: 350px; - overflow: hidden; -} - -.window { - background: #c0c0c0; - border: 2px outset #c0c0c0; - width: 100%; - height: 100%; -} - -.title-bar { - background: linear-gradient(90deg, #000080 0%, #000060 100%); - color: white; - padding: 3px 6px; - font-weight: bold; - font-size: 11px; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.content { - padding: 8px; - height: calc(100% - 22px); - display: flex; - flex-direction: column; -} - -.display { - background: white; - border: 2px inset #c0c0c0; - padding: 4px 8px; - text-align: right; - font-family: 'Courier New', monospace; - font-size: 16px; - font-weight: bold; - margin-bottom: 8px; - height: 36px; - display: flex; - align-items: center; - justify-content: flex-end; - overflow: hidden; - word-break: break-all; -} - -.memory-display { - font-size: 9px; - color: #666; - margin-bottom: 2px; - text-align: right; - height: 12px; - font-family: 'Courier New', monospace; -} - -.buttons { - display: grid; - grid-template-columns: repeat(4, 1fr); - grid-template-rows: repeat(5, 1fr); - gap: 3px; - flex: 1; -} - -.btn { - background: #c0c0c0; - border: 2px outset #c0c0c0; - font-family: 'MS Sans Serif', 'Segoe UI', sans-serif; - font-size: 12px; - font-weight: bold; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - min-height: 32px; - user-select: none; - transition: none; -} - -.btn:hover { - background: #d4d4d4; -} - -.btn:active { - border: 2px inset #c0c0c0; - background: #b8b8b8; -} - -.btn.operator { - background: #dfdfdf; - color: #000; -} - -.btn.operator:hover { - background: #e8e8e8; -} - -.btn.clear { - background: #ff9999; - color: #000; -} - -.btn.clear:hover { - background: #ffaaaa; -} - -.btn.clear:active { - background: #ff8888; -} - -.btn.equals { - background: #99ff99; - color: #000; - grid-row: span 2; -} - -.btn.equals:hover { - background: #aaffaa; -} - -.btn.equals:active { - background: #88ff88; -} - -.btn.zero { - grid-column: span 2; -} - -.btn.number { - background: #c0c0c0; -} - -.btn.number:hover { - background: #d4d4d4; -} From bc16debc235bf043637725be25c5ca6989dc6b4b Mon Sep 17 00:00:00 2001 From: Praveen kumar <168343716+Praveenkushinpi@users.noreply.github.com> Date: Sun, 29 Jun 2025 18:46:21 +0530 Subject: [PATCH 07/12] Delete submissions/Calculator/icon128.png --- submissions/Calculator/icon128.png | Bin 2787 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 submissions/Calculator/icon128.png diff --git a/submissions/Calculator/icon128.png b/submissions/Calculator/icon128.png deleted file mode 100644 index 8bd5050f3dbc9d937f61756598f82baad3f07b4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2787 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 From 93552313019f727dd5e736f92a51a8fa9aa3b70e Mon Sep 17 00:00:00 2001 From: Praveen kumar <168343716+Praveenkushinpi@users.noreply.github.com> Date: Sun, 29 Jun 2025 18:46:32 +0530 Subject: [PATCH 08/12] Delete submissions/Calculator/icon16.png --- submissions/Calculator/icon16.png | Bin 2787 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 submissions/Calculator/icon16.png diff --git a/submissions/Calculator/icon16.png b/submissions/Calculator/icon16.png deleted file mode 100644 index 8bd5050f3dbc9d937f61756598f82baad3f07b4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2787 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 From 08e1535d901fbe19a531d030fad64999d10745cc Mon Sep 17 00:00:00 2001 From: Praveen kumar <168343716+Praveenkushinpi@users.noreply.github.com> Date: Sun, 29 Jun 2025 18:46:42 +0530 Subject: [PATCH 09/12] Delete submissions/Calculator/icon48.png --- submissions/Calculator/icon48.png | Bin 2787 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 submissions/Calculator/icon48.png diff --git a/submissions/Calculator/icon48.png b/submissions/Calculator/icon48.png deleted file mode 100644 index 8bd5050f3dbc9d937f61756598f82baad3f07b4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2787 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 From db8898458b686920f7b4d806d5341d9b31eb34ac Mon Sep 17 00:00:00 2001 From: Praveen kumar <168343716+Praveenkushinpi@users.noreply.github.com> Date: Sun, 29 Jun 2025 18:48:59 +0530 Subject: [PATCH 10/12] Add files via upload --- submissions/Calculator/Readme.md | 5 +- submissions/Calculator/background.js | 501 +++++++++++++++++++++++ submissions/Calculator/content.css | 314 ++++++++++++++ submissions/Calculator/content.js | 104 +++++ submissions/Calculator/manifest.json | 45 +- submissions/Calculator/popup.html | 364 +++++++++++++++-- submissions/Calculator/popup.js | 590 +++++++++++++++++++++++++++ 7 files changed, 1877 insertions(+), 46 deletions(-) create mode 100644 submissions/Calculator/background.js create mode 100644 submissions/Calculator/content.css create mode 100644 submissions/Calculator/content.js create mode 100644 submissions/Calculator/popup.js diff --git a/submissions/Calculator/Readme.md b/submissions/Calculator/Readme.md index 96ae1ae1..5eacaaf2 100644 --- a/submissions/Calculator/Readme.md +++ b/submissions/Calculator/Readme.md @@ -1,2 +1,3 @@ -#CALCULATOR -## this is a brutalism designed calculator but in 90's style \ No newline at end of file +# TAB ORG +## Yes a browser tab organiser and more than that +### a tab organiser which also track how much time you spent on the each group along with custom groups and personalization \ No newline at end of file diff --git a/submissions/Calculator/background.js b/submissions/Calculator/background.js new file mode 100644 index 00000000..32b68696 --- /dev/null +++ b/submissions/Calculator/background.js @@ -0,0 +1,501 @@ +class BackgroundTabManager { + constructor() { + this.tabGroups = {}; + this.timeTracking = {}; + this.currentMode = 'work'; + this.activeTabStartTime = {}; + this.timeTrackingInterval = null; + this.init(); + } + + async init() { + try { + await this.loadData(); + this.setupMessageListener(); + this.setupTabListeners(); + this.startTimeTracking(); + } catch (error) { + console.error('Failed to initialize BackgroundTabManager:', error); + } + } + + async loadData() { + try { + const result = await chrome.storage.sync.get(['tabGroups', 'currentMode', 'timeTracking']); + this.tabGroups = result.tabGroups || {}; + this.currentMode = result.currentMode || 'work'; + this.timeTracking = result.timeTracking || {}; + } catch (error) { + console.error('Failed to load data:', error); + this.tabGroups = {}; + this.currentMode = 'work'; + this.timeTracking = {}; + } + } + + async saveData() { + try { + await chrome.storage.sync.set({ + tabGroups: this.tabGroups, + currentMode: this.currentMode, + timeTracking: this.timeTracking + }); + } catch (error) { + console.error('Failed to save data:', error); + } + } + + setupMessageListener() { + chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + this.handleMessage(message, sender, sendResponse); + return true; + }); + } + + setupTabListeners() { + chrome.tabs.onActivated.addListener((activeInfo) => { + this.handleTabActivated(activeInfo).catch(error => { + console.error('Error handling tab activation:', error); + }); + }); + + + chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { + if (changeInfo.status === 'complete') { + this.updateTabInGroups(tab).catch(error => { + console.error('Error updating tab in groups:', error); + }); + } + }); + + chrome.tabs.onRemoved.addListener((tabId) => { + this.removeTabFromGroups(tabId).catch(error => { + console.error('Error removing tab from groups:', error); + }); + }); + + chrome.windows.onFocusChanged.addListener((windowId) => { + if (windowId !== chrome.windows.WINDOW_ID_NONE) { + this.handleWindowFocusChanged(windowId).catch(error => { + console.error('Error handling window focus change:', error); + }); + } + }); + } + + async handleMessage(message, sender, sendResponse) { + try { + switch (message.action) { + case 'switchMode': + await this.switchMode(message.mode); + sendResponse({ success: true }); + break; + + case 'addTabToGroup': + await this.addTabToGroup(message.tabId, message.groupKey, message.groupName, message.groupColor); + sendResponse({ success: true }); + break; + + case 'openGroupTabs': + await this.openGroupTabs(message.tabs); + sendResponse({ success: true }); + break; + + case 'closeGroupTabs': + await this.closeGroupTabs(message.groupKey); + sendResponse({ success: true }); + break; + + case 'getTimeTracking': + sendResponse({ timeTracking: this.timeTracking }); + break; + + case 'trackPageTime': + await this.trackPageTime(message.url, message.title, message.timeSpent); + sendResponse({ success: true }); + break; + + case 'getTabGroups': + sendResponse({ tabGroups: this.tabGroups, currentMode: this.currentMode }); + break; + + case 'deleteTabGroup': + await this.deleteTabGroup(message.groupKey); + sendResponse({ success: true }); + break; + + default: + sendResponse({ success: false, error: 'Unknown action' }); + } + } catch (error) { + console.error('Error handling message:', error); + sendResponse({ success: false, error: error.message }); + } + } + + async deleteTabGroup(groupKey) { + try { + if (!this.tabGroups[groupKey]) { + console.log(`Group ${groupKey} not found`); + return; + } + + + const tabs = await chrome.tabs.query({ currentWindow: true }); + + + const groups = await chrome.tabGroups.query({}); + const targetGroup = groups.find(group => group.title === this.tabGroups[groupKey].name); + + if (targetGroup) { + + const groupTabs = tabs.filter(tab => tab.groupId === targetGroup.id); + + if (groupTabs.length > 0) { + + const tabIds = groupTabs.map(tab => tab.id); + await chrome.tabs.ungroup(tabIds); + } + } + delete this.tabGroups[groupKey]; + await this.saveData(); + + console.log(`Successfully deleted group: ${groupKey}`); + } catch (error) { + console.error('Error deleting tab group:', error); + throw error; + } + } + + async switchMode(mode) { + try { + this.currentMode = mode; + await this.saveData(); + await this.organizeTabsByMode(mode); + } catch (error) { + console.error('Error switching mode:', error); + throw error; + } + } + + async organizeTabsByMode(mode) { + try { + const tabs = await chrome.tabs.query({ currentWindow: true }); + const modeKeywords = { + work: ['linkedin', 'email', 'slack', 'teams', 'zoom', 'calendar', 'docs', 'sheets', 'office', 'notion'], + code: ['github', 'stackoverflow', 'codepen', 'repl', 'dev.to', 'coding', 'programming', 'vscode', 'ide'], + creativity: ['dribbble', 'behance', 'figma', 'canva', 'adobe', 'design', 'art', 'creative'], + fun: ['youtube', 'netflix', 'gaming', 'reddit', 'social', 'entertainment', 'memes', 'twitter', 'instagram'] + }; + + const keywords = modeKeywords[mode] || []; + + for (const tab of tabs) { + const tabUrl = (tab.url || '').toLowerCase(); + const tabTitle = (tab.title || '').toLowerCase(); + + const isRelevant = keywords.some(keyword => + tabUrl.includes(keyword) || tabTitle.includes(keyword) + ); + + if (isRelevant) { + const groupColors = { + work: '#3b82f6', + code: '#10b981', + creativity: '#8b5cf6', + fun: '#f59e0b' + }; + + await this.addTabToGroup( + tab.id, + mode, + mode.charAt(0).toUpperCase() + mode.slice(1), + groupColors[mode] || '#3b82f6' + ); + } + } + } catch (error) { + console.error('Error organizing tabs by mode:', error); + } + } + + async addTabToGroup(tabId, groupKey, groupName, groupColor) { + try { + const tab = await chrome.tabs.get(tabId); + let groupId = await this.getOrCreateTabGroup(groupName, groupColor); + await chrome.tabs.group({ tabIds: [tabId], groupId: groupId }); + if (!this.tabGroups[groupKey]) { + this.tabGroups[groupKey] = { + tabs: [], + color: groupColor, + name: groupName, + created: Date.now() + }; + } + + const existingIndex = this.tabGroups[groupKey].tabs.findIndex(t => t.id === tabId); + + if (existingIndex === -1) { + this.tabGroups[groupKey].tabs.push({ + id: tabId, + url: tab.url, + title: tab.title, + favIconUrl: tab.favIconUrl, + added: Date.now() + }); + } else { + this.tabGroups[groupKey].tabs[existingIndex] = { + ...this.tabGroups[groupKey].tabs[existingIndex], + url: tab.url, + title: tab.title, + favIconUrl: tab.favIconUrl + }; + } + + await this.saveData(); + } catch (error) { + console.error('Error adding tab to group:', error); + throw error; + } + } + + async getOrCreateTabGroup(groupName, groupColor) { + try { + const groups = await chrome.tabGroups.query({}); + let existingGroup = groups.find(group => group.title === groupName); + + if (existingGroup) { + return existingGroup.id; + } + const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true }); + if (!activeTab) { + throw new Error('No active tab to create group with'); + } + + const groupId = await chrome.tabs.group({ tabIds: [activeTab.id] }); + + await chrome.tabGroups.update(groupId, { + title: groupName, + color: this.getGroupColor(groupColor) + }); + + return groupId; + } catch (error) { + console.error('Error creating/getting tab group:', error); + throw error; + } + } + + getGroupColor(hexColor) { + const colorMap = { + '#3b82f6': 'blue', + '#10b981': 'green', + '#f59e0b': 'yellow', + '#ef4444': 'red', + '#8b5cf6': 'purple', + '#06b6d4': 'cyan', + '#ec4899': 'pink', + '#64748b': 'grey' + }; + + return colorMap[hexColor] || 'blue'; + } + + async openGroupTabs(tabs) { + try { + for (const tabData of tabs) { + await chrome.tabs.create({ + url: tabData.url, + active: false + }); + } + } catch (error) { + console.error('Error opening group tabs:', error); + throw error; + } + } + + async closeGroupTabs(groupKey) { + try { + if (!this.tabGroups[groupKey]) return; + + const tabIds = this.tabGroups[groupKey].tabs.map(tab => tab.id); + + for (const tabId of tabIds) { + try { + await chrome.tabs.remove(tabId); + } catch (error) { + console.log('Tab already closed:', tabId); + } + } + + this.tabGroups[groupKey].tabs = []; + await this.saveData(); + } catch (error) { + console.error('Error closing group tabs:', error); + throw error; + } + } + + async handleTabActivated(activeInfo) { + try { + const tab = await chrome.tabs.get(activeInfo.tabId); + this.activeTabStartTime[activeInfo.tabId] = Date.now(); + const groupKey = this.findTabGroup(activeInfo.tabId); + if (groupKey) { + this.currentMode = groupKey; + await this.saveData(); + } + } catch (error) { + console.error('Error handling tab activation:', error); + } + } + + findTabGroup(tabId) { + for (const [groupKey, group] of Object.entries(this.tabGroups)) { + if (group.tabs && group.tabs.some(tab => tab.id === tabId)) { + return groupKey; + } + } + return null; + } + + async updateTabInGroups(tab) { + try { + let updated = false; + + for (const [groupKey, group] of Object.entries(this.tabGroups)) { + if (!group.tabs) continue; + + const tabIndex = group.tabs.findIndex(t => t.id === tab.id); + if (tabIndex !== -1) { + this.tabGroups[groupKey].tabs[tabIndex] = { + ...this.tabGroups[groupKey].tabs[tabIndex], + url: tab.url, + title: tab.title, + favIconUrl: tab.favIconUrl, + updated: Date.now() + }; + updated = true; + } + } + + if (updated) { + await this.saveData(); + } + } catch (error) { + console.error('Error updating tab in groups:', error); + } + } + + async removeTabFromGroups(tabId) { + try { + let removed = false; + + for (const [groupKey, group] of Object.entries(this.tabGroups)) { + if (!group.tabs) continue; + + const originalLength = group.tabs.length; + this.tabGroups[groupKey].tabs = group.tabs.filter(tab => tab.id !== tabId); + + if (this.tabGroups[groupKey].tabs.length !== originalLength) { + removed = true; + } + } + delete this.activeTabStartTime[tabId]; + + if (removed) { + await this.saveData(); + } + } catch (error) { + console.error('Error removing tab from groups:', error); + } + } + + async trackPageTime(url, title, timeSpent) { + try { + const domain = new URL(url).hostname; + + if (!this.timeTracking.pages) { + this.timeTracking.pages = {}; + } + + if (!this.timeTracking.pages[domain]) { + this.timeTracking.pages[domain] = { + totalTime: 0, + visits: 0, + title: title + }; + } + + this.timeTracking.pages[domain].totalTime += timeSpent; + this.timeTracking.pages[domain].visits += 1; + this.timeTracking.pages[domain].lastVisit = Date.now(); + + await this.saveData(); + } catch (error) { + console.error('Error tracking page time:', error); + } + } + + startTimeTracking() { + if (this.timeTrackingInterval) { + clearInterval(this.timeTrackingInterval); + } + + + this.timeTrackingInterval = setInterval(async () => { + try { + const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true }); + + if (activeTab) { + const groupKey = this.findTabGroup(activeTab.id) || this.currentMode; + if (groupKey) { + if (!this.timeTracking.groups) { + this.timeTracking.groups = {}; + } + + this.timeTracking.groups[groupKey] = (this.timeTracking.groups[groupKey] || 0) + 1; + await this.saveData(); + } + } + } catch (error) { + console.error('Error in time tracking interval:', error); + } + }, 60000); + } + + async handleWindowFocusChanged(windowId) { + try { + if (windowId !== chrome.windows.WINDOW_ID_NONE) { + const [activeTab] = await chrome.tabs.query({ active: true, windowId: windowId }); + if (activeTab) { + this.activeTabStartTime[activeTab.id] = Date.now(); + } + } + } catch (error) { + console.error('Error handling window focus change:', error); + } + } + + cleanup() { + if (this.timeTrackingInterval) { + clearInterval(this.timeTrackingInterval); + this.timeTrackingInterval = null; + } + } +} + +let backgroundManager; + +try { + backgroundManager = new BackgroundTabManager(); +} catch (error) { + console.error('Failed to initialize BackgroundTabManager:', error); +} + +chrome.runtime.onSuspend.addListener(() => { + if (backgroundManager) { + backgroundManager.cleanup(); + } +}); \ No newline at end of file diff --git a/submissions/Calculator/content.css b/submissions/Calculator/content.css new file mode 100644 index 00000000..bef33418 --- /dev/null +++ b/submissions/Calculator/content.css @@ -0,0 +1,314 @@ +/* Tab Persona Content Styles */ + +/* Global mood-based animations */ +:root { + --animation-speed: 1; + --animation-style: ease; + --tab-persona-primary: #667eea; +} + +/* Smooth transitions for all mood changes */ +* { + transition-duration: calc(0.3s * var(--animation-speed)) !important; + transition-timing-function: var(--animation-style) !important; +} + +/* Motivational overlay base styles */ +#tab-persona-motivational { + font-feature-settings: "liga" 1, "kern" 1; + letter-spacing: 0.3px; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); +} + +/* Focus timer styles */ +#focus-timer { + cursor: pointer; + user-select: none; +} + +#focus-timer:hover { + transform: scale(1.05); + background: rgba(255, 107, 107, 1) !important; +} + +/* Chill mode styles */ +.tab-persona-chill * { + transition-duration: 0.4s !important; +} + +.tab-persona-chill a:hover { + color: var(--tab-persona-primary) !important; + text-shadow: 0 0 8px rgba(102, 126, 234, 0.3); +} + +.tab-persona-chill button:hover { + box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2) !important; +} + +/* Hyperfocus mode styles */ +.tab-persona-hyperfocus { + position: relative; +} + +.tab-persona-hyperfocus::before { + content: ''; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: radial-gradient( + circle at center, + transparent 40%, + rgba(0, 0, 0, 0.05) 70%, + rgba(0, 0, 0, 0.1) 100% + ); + pointer-events: none; + z-index: 1; +} + +.tab-persona-hyperfocus * { + transition-duration: 0.1s !important; +} + +.tab-persona-hyperfocus .advertisement, +.tab-persona-hyperfocus .ads, +.tab-persona-hyperfocus [class*="ad-"], +.tab-persona-hyperfocus [id*="ad-"] { + filter: blur(2px) !important; + opacity: 0.1 !important; +} + +/* Playful mode styles */ +.tab-persona-playful button { + overflow: hidden; + position: relative; +} + +.tab-persona-playful button::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; + background: radial-gradient(circle, rgba(255, 255, 255, 0.3) 0%, transparent 70%); + transition: width 0.6s, height 0.6s; + transform: translate(-50%, -50%); + border-radius: 50%; +} + +.tab-persona-playful button:hover::before { + width: 300px; + height: 300px; +} + +.tab-persona-playful h1, +.tab-persona-playful h2, +.tab-persona-playful h3 { + position: relative; + overflow: hidden; +} + +/* Zen mode styles */ +.tab-persona-zen { + font-smoothing: antialiased; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.tab-persona-zen * { + transition-duration: 0.5s !important; + transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94) !important; +} + +.tab-persona-zen p, +.tab-persona-zen div, +.tab-persona-zen span { + line-height: 1.7 !important; +} + +.tab-persona-zen h1, +.tab-persona-zen h2, +.tab-persona-zen h3 { + font-weight: 300 !important; + letter-spacing: 1px !important; +} + +/* Breathing reminder animation */ +@keyframes breathe { + 0%, 100% { + transform: translate(-50%, -50%) scale(1); + opacity: 0.9; + } + 50% { + transform: translate(-50%, -50%) scale(1.1); + opacity: 1; + } +} + +/* Tab persona indicator pulse */ +@keyframes indicatorPulse { + 0%, 100% { + opacity: 0.1; + transform: scale(1); + } + 50% { + opacity: 0.3; + transform: scale(1.1); + } +} + +/* Scroll-triggered focus reminder */ +.tab-persona-scroll-reminder { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: rgba(255, 107, 107, 0.95); + color: white; + padding: 15px 20px; + border-radius: 25px; + font-size: 14px; + z-index: 10002; + animation: fadeInScale 0.3s ease-out; + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.2); +} + +@keyframes fadeInScale { + from { + opacity: 0; + transform: translate(-50%, -50%) scale(0.8); + } + to { + opacity: 1; + transform: translate(-50%, -50%) scale(1); + } +} + +/* Custom scrollbar for different moods */ +.tab-persona-chill ::-webkit-scrollbar { + width: 8px; +} + +.tab-persona-chill ::-webkit-scrollbar-track { + background: linear-gradient(180deg, #667eea, #764ba2); + border-radius: 4px; +} + +.tab-persona-chill ::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.3); + border-radius: 4px; +} + +.tab-persona-hyperfocus ::-webkit-scrollbar { + width: 4px; +} + +.tab-persona-hyperfocus ::-webkit-scrollbar-track { + background: #ff6b6b; +} + +.tab-persona-hyperfocus ::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.5); +} + +.tab-persona-playful ::-webkit-scrollbar { + width: 12px; +} + +.tab-persona-playful ::-webkit-scrollbar-track { + background: linear-gradient(45deg, #feca57, #ff9ff3); +} + +.tab-persona-playful ::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.4); + border-radius: 6px; +} + +.tab-persona-zen ::-webkit-scrollbar { + width: 6px; +} + +.tab-persona-zen ::-webkit-scrollbar-track { + background: #74b9ff; +} + +.tab-persona-zen ::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.2); + border-radius: 3px; +} + +/* Selection colors based on mood */ +.tab-persona-chill ::selection { + background: rgba(102, 126, 234, 0.3); +} + +.tab-persona-hyperfocus ::selection { + background: rgba(255, 107, 107, 0.3); +} + +.tab-persona-playful ::selection { + background: rgba(254, 202, 87, 0.3); +} + +.tab-persona-zen ::selection { + background: rgba(116, 185, 255, 0.3); +} + +/* Responsive adjustments */ +@media (max-width: 768px) { + #tab-persona-motivational { + right: 10px !important; + top: 10px !important; + max-width: 200px !important; + font-size: 11px !important; + } + + #focus-timer { + right: 10px !important; + top: 40px !important; + font-size: 10px !important; + } +} + +/* Accessibility improvements */ +@media (prefers-reduced-motion: reduce) { + .tab-persona-playful button::before, + .tab-persona-playful h1, + .tab-persona-playful h2, + .tab-persona-playful h3 { + animation: none !important; + } + + * { + transition-duration: 0.1s !important; + } +} + +/* High contrast mode support */ +@media (prefers-contrast: high) { + #tab-persona-motivational { + background: rgba(0, 0, 0, 0.95) !important; + border: 2px solid white !important; + } + + #focus-timer { + background: rgba(255, 0, 0, 0.95) !important; + border: 1px solid white !important; + } +} + +/* Dark mode adjustments */ +@media (prefers-color-scheme: dark) { + .tab-persona-zen p, + .tab-persona-zen div, + .tab-persona-zen span { + color: rgba(255, 255, 255, 0.8) !important; + } + + .tab-persona-zen a { + border-bottom-color: rgba(116, 185, 255, 0.5) !important; + } +} \ No newline at end of file diff --git a/submissions/Calculator/content.js b/submissions/Calculator/content.js new file mode 100644 index 00000000..b66b5659 --- /dev/null +++ b/submissions/Calculator/content.js @@ -0,0 +1,104 @@ +class TabDragDropManager { + constructor() { + this.init(); + } + + init() { + this.trackPageTime(); + } + + showNotification(message) { + const notification = document.createElement('div'); + notification.style.cssText = ` + position: fixed !important; + top: 20px !important; + right: 20px !important; + background: #000000 !important; + color: #ffffff !important; + padding: 20px 25px !important; + border: 4px solid #ffffff !important; + font-family: 'Courier New', monospace !important; + font-size: 16px !important; + font-weight: 900 !important; + text-transform: uppercase !important; + letter-spacing: 2px !important; + box-shadow: 8px 8px 0px #ffffff !important; + z-index: 999997 !important; + transform: translateX(500px) !important; + transition: all 0.4s ease !important; + white-space: nowrap !important; + `; + + notification.textContent = `◼ ${message.toUpperCase()}`; + + document.body.appendChild(notification); + + setTimeout(() => { + notification.style.transform = 'translateX(0)'; + }, 100); + + setTimeout(() => { + notification.style.transform = 'translateX(500px)'; + setTimeout(() => { + if (document.body.contains(notification)) { + document.body.removeChild(notification); + } + }, 400); + }, 3000); + } + + trackPageTime() { + let startTime = Date.now(); + let isVisible = true; + + document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'hidden') { + if (isVisible) { + const timeSpent = Date.now() - startTime; + try { + if (typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.sendMessage) { + chrome.runtime.sendMessage({ + action: 'trackPageTime', + url: window.location.href, + title: document.title, + timeSpent: timeSpent + }); + } + } catch (error) { + console.log(`Page time: ${timeSpent}ms on ${document.title}`); + } + isVisible = false; + } + } else { + startTime = Date.now(); + isVisible = true; + } + }); + + window.addEventListener('beforeunload', () => { + if (isVisible) { + const timeSpent = Date.now() - startTime; + try { + if (typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.sendMessage) { + chrome.runtime.sendMessage({ + action: 'trackPageTime', + url: window.location.href, + title: document.title, + timeSpent: timeSpent + }); + } + } catch (error) { + console.log(`Page time on unload: ${timeSpent}ms on ${document.title}`); + } + } + }); + } +} + +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', () => { + new TabDragDropManager(); + }); +} else { + new TabDragDropManager(); +} \ No newline at end of file diff --git a/submissions/Calculator/manifest.json b/submissions/Calculator/manifest.json index 1520985c..4ddcc70f 100644 --- a/submissions/Calculator/manifest.json +++ b/submissions/Calculator/manifest.json @@ -1,16 +1,43 @@ { "manifest_version": 3, - "name": "CALCULATOR", + "name": "Smart Tab Organizer", "version": "1.0", - "description": "A brutalist-style calculator extension", + "description": "Organize tabs into groups with time tracking and productivity modes", + + "permissions": [ + "tabs", + "tabGroups", + "storage", + "activeTab" + ], + + "background": { + "service_worker": "background.js" + }, + "action": { "default_popup": "popup.html", - "default_title": "CALCULATOR" + "default_title": "Smart Tab Organizer", + "default_icon": { + "16": "icons/icon16.png", + "32": "icons/icon128.png", + "48": "icons/icon48.png", + "128": "icons/icon128.png" + } }, + + "content_scripts": [ + { + "matches": [""], + "js": ["content.js"], + "run_at": "document_start" + } + ], + "icons": { - "16": "icon16.png", - "48": "icon48.png", - "128": "icon128.png" - }, - "permissions": [] -} + "16": "icons/icon16.png", + "32": "icons/icon128.png", + "48": "icons/icon48.png", + "128": "icons/icon128.png" + } +} \ No newline at end of file diff --git a/submissions/Calculator/popup.html b/submissions/Calculator/popup.html index 35f73c4b..7188521b 100644 --- a/submissions/Calculator/popup.html +++ b/submissions/Calculator/popup.html @@ -1,47 +1,341 @@ - - CALCULATOR - + Smart Tab Organizer + -
-
- CALCULATOR +
+

TAB ORGANIZER

+

ORGANIZE • TRACK • FOCUS

+
+ +
+
MODES
+
+ + + +
-
-
-
0
-
- - - - - - - - - - - - - - - - - - - - - - -
+
+ +
+
GROUPS
+
+
+ +
+ + +
+ +
+
TODAY: 0M • TABS: 0
+
+ - - + \ No newline at end of file diff --git a/submissions/Calculator/popup.js b/submissions/Calculator/popup.js new file mode 100644 index 00000000..5fd46347 --- /dev/null +++ b/submissions/Calculator/popup.js @@ -0,0 +1,590 @@ +class TabOrganizer { + constructor() { + this.groups = {}; + this.currentMode = 'work'; + this.timeTracking = {}; + this.init(); + } + + async init() { + try { + await this.loadData(); + this.setupEventListeners(); + this.renderGroups(); + this.updateStats(); + this.startTimeTracking(); + } catch (error) { + console.error('Initialization error:', error); + this.showNotification('INITIALIZATION ERROR'); + } + } + + showNotification(message) { + const existingNotifications = document.querySelectorAll('.tab-organizer-notification'); + existingNotifications.forEach(notification => notification.remove()); + + const notification = document.createElement('div'); + notification.className = 'tab-organizer-notification'; + notification.style.cssText = ` + position: fixed; + top: 20px; + right: 20px; + background: #000000; + color: #ffffff; + border: 3px solid #ffffff; + padding: 12px 16px; + font-family: 'Courier New', monospace; + font-weight: 900; + font-size: 14px; + text-transform: uppercase; + z-index: 10000; + transform: translateX(400px); + transition: all 0.3s ease; + border-radius: 4px; + box-shadow: 0 4px 12px rgba(0,0,0,0.3); + `; + notification.textContent = message; + + document.body.appendChild(notification); + + setTimeout(() => { + notification.style.transform = 'translateX(0)'; + }, 100); + + + setTimeout(() => { + if (notification.parentNode) { + notification.style.transform = 'translateX(400px)'; + setTimeout(() => { + if (notification.parentNode) { + notification.remove(); + } + }, 100); + } + }, 1000); + } + + async loadData() { + try { + + if (!chrome || !chrome.storage || !chrome.storage.sync) { + throw new Error('Chrome storage API not available'); + } + + const result = await chrome.storage.sync.get(['tabGroups', 'currentMode', 'timeTracking']); + + + this.groups = result.tabGroups || {}; + + + const defaultGroups = { + WORK: { name: 'WORK', tabs: [], color: '#ffffff', created: Date.now() }, + CODE: { name: 'CODE', tabs: [], color: '#ffffff', created: Date.now() }, + CREATIVITY: { name: 'CREATIVE', tabs: [], color: '#ffffff', created: Date.now() }, + FUN: { name: 'FUN', tabs: [], color: '#ffffff', created: Date.now() } + }; + + for (const [key, defaultGroup] of Object.entries(defaultGroups)) { + if (!this.groups[key]) { + this.groups[key] = { ...defaultGroup }; + } + } + + this.currentMode = result.currentMode || 'work'; + this.timeTracking = result.timeTracking || {}; + + + await this.saveData(); + } catch (error) { + console.error('Error loading data:', error); + this.initializeDefaults(); + } + } + + initializeDefaults() { + this.groups = { + WORK: { name: 'WORK', tabs: [], color: '#ffffff', created: Date.now() }, + CODE: { name: 'CODE', tabs: [], color: '#ffffff', created: Date.now() }, + CREATIVITY: { name: 'CREATIVE', tabs: [], color: '#ffffff', created: Date.now() }, + FUN: { name: 'FUN', tabs: [], color: '#ffffff', created: Date.now() } + }; + this.currentMode = 'work'; + this.timeTracking = {}; + } + + async saveData() { + try { + if (chrome && chrome.storage && chrome.storage.sync) { + await chrome.storage.sync.set({ + tabGroups: this.groups, + currentMode: this.currentMode, + timeTracking: this.timeTracking + }); + } + } catch (error) { + console.error('Error saving data:', error); + } + } + + setupEventListeners() { + + const modeButtons = document.querySelectorAll('.mode-btn'); + modeButtons.forEach(btn => { + btn.addEventListener('click', (e) => { + const mode = e.target.dataset.mode; + if (mode) { + this.switchMode(mode); + } + }); + }); + + + const addGroupBtn = document.getElementById('add-group-btn'); + if (addGroupBtn) { + addGroupBtn.addEventListener('click', () => { + this.createNewGroup(); + }); + } + + const newGroupInput = document.getElementById('new-group-name'); + if (newGroupInput) { + newGroupInput.addEventListener('keypress', (e) => { + if (e.key === 'Enter') { + this.createNewGroup(); + } + }); + } + + this.updateModeDisplay(); + } + + async switchMode(mode) { + if (!mode || !this.groups[mode]) { + console.error('Invalid mode:', mode); + return; + } + + this.currentMode = mode; + await this.saveData(); + this.updateModeDisplay(); + + try { + if (chrome && chrome.runtime) { + chrome.runtime.sendMessage({ + action: 'switchMode', + mode: mode + }); + } + } catch (error) { + console.error('Error sending message to background script:', error); + } + + this.showNotification(`SWITCHED TO ${mode.toUpperCase()} MODE`); + } + + updateModeDisplay() { + const modeButtons = document.querySelectorAll('.mode-btn'); + modeButtons.forEach(btn => { + btn.classList.remove('active'); + if (btn.dataset.mode === this.currentMode) { + btn.classList.add('active'); + } + }); + } + + async createNewGroup() { + const input = document.getElementById('new-group-name'); + if (!input) { + console.error('New group input not found'); + return; + } + + const groupName = input.value.trim().toUpperCase(); + + if (!groupName) { + this.showNotification('PLEASE ENTER A GROUP NAME'); + return; + } + + if (groupName.length > 20) { + this.showNotification('GROUP NAME TOO LONG'); + return; + } + + const groupKey = groupName.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''); + + if (this.groups[groupKey]) { + this.showNotification('GROUP ALREADY EXISTS!'); + return; + } + + this.groups[groupKey] = { + name: groupName, + tabs: [], + color: '#ffffff', + created: Date.now() + }; + + await this.saveData(); + this.renderGroups(); + input.value = ''; + + + this.showNotification(`GROUP "${groupName}" CREATED`); + } + + async renderGroups() { + const container = document.getElementById('groups-container'); + if (!container) { + console.error('Groups container not found'); + return; + } + + container.innerHTML = ''; + + for (const [key, group] of Object.entries(this.groups)) { + try { + const groupElement = this.createGroupElement(key, group); + container.appendChild(groupElement); + } catch (error) { + console.error('Error creating group element:', error); + } + } + } + + createGroupElement(key, group) { + const div = document.createElement('div'); + div.className = 'group-item'; + + const groupName = group.name || key.toUpperCase(); + const tabCount = Array.isArray(group.tabs) ? group.tabs.length : 0; + const timeSpent = this.formatTime(this.timeTracking[key] || 0); + + div.innerHTML = ` +
+
${this.escapeHtml(groupName)}
+
${tabCount}
+
+
TIME: ${timeSpent}
+
+ DROP TABS HERE +
+
+ + + +
+ `; + + this.setupGroupActions(div, key); + return div; + } + + escapeHtml(text) { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } + + setupGroupActions(element, groupKey) { + + const actionButtons = element.querySelectorAll('.action-btn'); + actionButtons.forEach(btn => { + btn.addEventListener('click', (e) => { + e.preventDefault(); + const action = e.target.dataset.action; + if (action) { + this.handleGroupAction(action, groupKey); + } + }); + }); + + + const dropZone = element.querySelector('.drop-zone'); + if (!dropZone) return; + + dropZone.addEventListener('click', () => { + this.addCurrentTabToGroup(groupKey); + }); + + dropZone.addEventListener('dragover', (e) => { + e.preventDefault(); + dropZone.classList.add('drag-over'); + }); + + dropZone.addEventListener('dragleave', () => { + dropZone.classList.remove('drag-over'); + }); + + dropZone.addEventListener('drop', (e) => { + e.preventDefault(); + dropZone.classList.remove('drag-over'); + this.handleTabDrop(e, groupKey); + }); + } + + async addCurrentTabToGroup(groupKey) { + try { + if (!chrome || !chrome.tabs) { + throw new Error('Chrome tabs API not available'); + } + + const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); + + if (!tab) { + this.showNotification('NO ACTIVE TAB FOUND'); + return; + } + + if (!this.groups[groupKey]) { + console.error('Group not found:', groupKey); + return; + } + + + if (!Array.isArray(this.groups[groupKey].tabs)) { + this.groups[groupKey].tabs = []; + } + + + const existingTab = this.groups[groupKey].tabs.find(t => t.id === tab.id || t.url === tab.url); + if (existingTab) { + this.showNotification('TAB ALREADY IN GROUP'); + return; + } + + this.groups[groupKey].tabs.push({ + id: tab.id, + url: tab.url, + title: tab.title || 'Untitled', + favIconUrl: tab.favIconUrl || '', + added: Date.now() + }); + + await this.saveData(); + + + try { + if (chrome && chrome.runtime) { + chrome.runtime.sendMessage({ + action: 'addTabToGroup', + tabId: tab.id, + groupKey: groupKey, + groupName: this.groups[groupKey].name || groupKey, + groupColor: this.groups[groupKey].color + }); + } + } catch (error) { + console.error('Error sending message to background:', error); + } + + this.renderGroups(); + this.showNotification(`TAB ADDED TO ${this.groups[groupKey].name || groupKey.toUpperCase()}`); + } catch (error) { + console.error('Error adding tab to group:', error); + this.showNotification('ERROR ADDING TAB'); + } + } + + async handleGroupAction(action, groupKey) { + if (!this.groups[groupKey]) { + console.error('Group not found:', groupKey); + return; + } + + const isDefaultGroup = ['work', 'code', 'creativity', 'fun'].includes(groupKey); + + try { + switch (action) { + case 'open': + if (this.groups[groupKey] && Array.isArray(this.groups[groupKey].tabs) && this.groups[groupKey].tabs.length > 0) { + if (chrome && chrome.runtime) { + chrome.runtime.sendMessage({ + action: 'openGroupTabs', + groupKey: groupKey, + tabs: this.groups[groupKey].tabs + }); + } + this.showNotification(`OPENED ${this.groups[groupKey].name || groupKey.toUpperCase()} TABS`); + } else { + this.showNotification('NO TABS IN GROUP'); + } + break; + + case 'close': + if (chrome && chrome.runtime) { + chrome.runtime.sendMessage({ + action: 'closeGroupTabs', + groupKey: groupKey + }); + } + this.groups[groupKey].tabs = []; + await this.saveData(); + this.renderGroups(); + this.showNotification(`CLOSED ${this.groups[groupKey].name || groupKey.toUpperCase()} TABS`); + break; + + case 'delete': + if (isDefaultGroup) { + this.showNotification('CANNOT DELETE DEFAULT GROUPS'); + return; + } + + if (confirm(`DELETE GROUP "${this.groups[groupKey].name || groupKey.toUpperCase()}"?\n\nNote: Tabs will remain open, only the group will be removed.`)) { + + if (chrome && chrome.runtime) { + chrome.runtime.sendMessage({ + action: 'deleteTabGroup', + groupKey: groupKey, + groupName: this.groups[groupKey].name || groupKey, + tabIds: this.groups[groupKey].tabs.map(tab => tab.id) + }); + } + + + delete this.groups[groupKey]; + delete this.timeTracking[groupKey]; + + + if (this.currentMode === groupKey) { + this.currentMode = 'work'; + } + + await this.saveData(); + this.renderGroups(); + this.updateModeDisplay(); + this.showNotification('GROUP PERMANENTLY DELETED'); + } + break; + + default: + console.error('Unknown action:', action); + } + } catch (error) { + console.error('Error handling group action:', error); + this.showNotification('ACTION FAILED'); + } + } + + async handleTabDrop(event, groupKey) { + try { + const tabData = event.dataTransfer.getData('text/plain'); + if (tabData) { + const tab = JSON.parse(tabData); + await this.addTabToGroup(tab, groupKey); + } + } catch (error) { + console.error('Error parsing dropped tab data:', error); + this.showNotification('INVALID TAB DATA'); + } + } + + async addTabToGroup(tab, groupKey) { + if (!this.groups[groupKey] || !tab) { + return; + } + + // Ensure tabs array exists + if (!Array.isArray(this.groups[groupKey].tabs)) { + this.groups[groupKey].tabs = []; + } + + // Check if tab already exists + const existingTab = this.groups[groupKey].tabs.find(t => t.id === tab.id || t.url === tab.url); + if (!existingTab) { + this.groups[groupKey].tabs.push({ + id: tab.id, + url: tab.url, + title: tab.title || 'Untitled', + favIconUrl: tab.favIconUrl || '', + added: Date.now() + }); + + await this.saveData(); + this.renderGroups(); + this.showNotification(`TAB ADDED TO ${this.groups[groupKey].name || groupKey.toUpperCase()}`); + } + } + + startTimeTracking() { + if (this.timeTrackingInterval) { + clearInterval(this.timeTrackingInterval); + } + + this.timeTrackingInterval = setInterval(async () => { + if (this.currentMode && this.groups[this.currentMode]) { + this.timeTracking[this.currentMode] = (this.timeTracking[this.currentMode] || 0) + 1; + await this.saveData(); + this.updateTimeDisplay(); + } + }, 60000); + } + + updateTimeDisplay() { + + Object.keys(this.groups).forEach(mode => { + const timeEl = document.getElementById(`${mode}-time`); + if (timeEl) { + timeEl.textContent = this.formatTime(this.timeTracking[mode] || 0); + } + }); + } + + async updateStats() { + try { + let totalTabs = 0; + if (chrome && chrome.tabs) { + const tabs = await chrome.tabs.query({}); + totalTabs = tabs.length; + } + + const totalTime = Object.values(this.timeTracking).reduce((sum, time) => sum + (time || 0), 0); + + const totalTimeEl = document.getElementById('total-time'); + const activeTabsEl = document.getElementById('active-tabs'); + + if (totalTimeEl) { + totalTimeEl.textContent = this.formatTime(totalTime); + } + if (activeTabsEl) { + activeTabsEl.textContent = totalTabs; + } + } catch (error) { + console.error('Error updating stats:', error); + } + } + + formatTime(minutes) { + const mins = parseInt(minutes) || 0; + if (mins < 60) { + return `${mins}m`; + } else { + const hours = Math.floor(mins / 60); + const remainingMins = mins % 60; + return `${hours}h ${remainingMins}m`; + } + } + + + destroy() { + if (this.timeTrackingInterval) { + clearInterval(this.timeTrackingInterval); + } + } +} + + +document.addEventListener('DOMContentLoaded', () => { + try { + window.tabOrganizer = new TabOrganizer(); + } catch (error) { + console.error('Failed to initialize TabOrganizer:', error); + } +}); + + +window.addEventListener('beforeunload', () => { + if (window.tabOrganizer && window.tabOrganizer.destroy) { + window.tabOrganizer.destroy(); + } +}); \ No newline at end of file From 10197dc3cff6ac9eca97a694a2015b2c55689dce Mon Sep 17 00:00:00 2001 From: Praveen kumar <168343716+Praveenkushinpi@users.noreply.github.com> Date: Sun, 29 Jun 2025 18:49:42 +0530 Subject: [PATCH 11/12] Create icon16.png --- submissions/Calculator/icons/icon16.png | 1 + 1 file changed, 1 insertion(+) create mode 100644 submissions/Calculator/icons/icon16.png diff --git a/submissions/Calculator/icons/icon16.png b/submissions/Calculator/icons/icon16.png new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/submissions/Calculator/icons/icon16.png @@ -0,0 +1 @@ + From a27fa63bfc3178899945f2df8dba33d59b3e41b8 Mon Sep 17 00:00:00 2001 From: Praveen kumar <168343716+Praveenkushinpi@users.noreply.github.com> Date: Sun, 29 Jun 2025 18:50:00 +0530 Subject: [PATCH 12/12] Add files via upload --- submissions/Calculator/icons/icon128.png | Bin 0 -> 3822 bytes submissions/Calculator/icons/icon16.png | Bin 1 -> 3822 bytes submissions/Calculator/icons/icon48.png | Bin 0 -> 3822 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 submissions/Calculator/icons/icon128.png create mode 100644 submissions/Calculator/icons/icon48.png diff --git a/submissions/Calculator/icons/icon128.png b/submissions/Calculator/icons/icon128.png new file mode 100644 index 0000000000000000000000000000000000000000..0b6badfa1f8c9f4798051b40ad237a3ebd7aecff GIT binary patch literal 3822 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 U=@QZb+)+U;PVSC0`?ELy1q{wI6#xJL literal 0 HcmV?d00001 diff --git a/submissions/Calculator/icons/icon16.png b/submissions/Calculator/icons/icon16.png index 8b137891791fe96927ad78e64b0aad7bded08bdc..0b6badfa1f8c9f4798051b40ad237a3ebd7aecff 100644 GIT binary patch literal 3822 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 U=@QZb+)+U;PVSC0`?ELy1q{wI6#xJL literal 1 Icmd-A000XB3jhEB diff --git a/submissions/Calculator/icons/icon48.png b/submissions/Calculator/icons/icon48.png new file mode 100644 index 0000000000000000000000000000000000000000..0b6badfa1f8c9f4798051b40ad237a3ebd7aecff GIT binary patch literal 3822 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 U=@QZb+)+U;PVSC0`?ELy1q{wI6#xJL literal 0 HcmV?d00001