├── cats ├── ace.gif ├── air.gif ├── black.gif ├── blue.gif ├── calico.gif ├── colourful.gif ├── dave.gif ├── earth.gif ├── fancy.gif ├── fire.gif ├── ghetto.gif ├── ghost.gif ├── gray.gif ├── holiday.gif ├── jess.gif ├── kina.gif ├── kuramecha.gif ├── lucky.gif ├── lucy.gif ├── marmalade.gif ├── mermaid.gif ├── mike.gif ├── moka.gif ├── neon.gif ├── oneko.gif ├── orange.gif ├── peach.gif ├── pink.gif ├── rainbow.gif ├── robot.gif ├── rose.gif ├── royal.gif ├── silver.gif ├── silversky.gif ├── socks.gif ├── spirit.gif ├── spooky.gif ├── usa.gif ├── valentine.gif └── water.gif ├── icon128.png ├── icon16.png ├── icon32.png ├── icon48.png ├── manifest.json ├── oneko.gif ├── oneko.js ├── options.html ├── options.js ├── options ├── ace.gif ├── air.gif ├── black.gif ├── blue.gif ├── calico.gif ├── colourful.gif ├── dave.gif ├── earth.gif ├── fancy.gif ├── fire.gif ├── ghetto.gif ├── ghost.gif ├── gray.gif ├── holiday.gif ├── jess.gif ├── kina.gif ├── kuramecha.gif ├── lucky.gif ├── lucy.gif ├── marmalade.gif ├── mermaid.gif ├── mike.gif ├── moka.gif ├── neon.gif ├── oneko.gif ├── orange.gif ├── peach.gif ├── pink.gif ├── rainbow.gif ├── robot.gif ├── rose.gif ├── royal.gif ├── silver.gif ├── silversky.gif ├── socks.gif ├── spirit.gif ├── spooky.gif ├── usa.gif ├── valentine.gif └── water.gif ├── popup.html ├── popup.js ├── privacy.md └── readme.md /cats/ace.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/ace.gif -------------------------------------------------------------------------------- /cats/air.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/air.gif -------------------------------------------------------------------------------- /cats/black.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/black.gif -------------------------------------------------------------------------------- /cats/blue.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/blue.gif -------------------------------------------------------------------------------- /cats/calico.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/calico.gif -------------------------------------------------------------------------------- /cats/colourful.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/colourful.gif -------------------------------------------------------------------------------- /cats/dave.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/dave.gif -------------------------------------------------------------------------------- /cats/earth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/earth.gif -------------------------------------------------------------------------------- /cats/fancy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/fancy.gif -------------------------------------------------------------------------------- /cats/fire.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/fire.gif -------------------------------------------------------------------------------- /cats/ghetto.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/ghetto.gif -------------------------------------------------------------------------------- /cats/ghost.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/ghost.gif -------------------------------------------------------------------------------- /cats/gray.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/gray.gif -------------------------------------------------------------------------------- /cats/holiday.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/holiday.gif -------------------------------------------------------------------------------- /cats/jess.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/jess.gif -------------------------------------------------------------------------------- /cats/kina.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/kina.gif -------------------------------------------------------------------------------- /cats/kuramecha.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/kuramecha.gif -------------------------------------------------------------------------------- /cats/lucky.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/lucky.gif -------------------------------------------------------------------------------- /cats/lucy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/lucy.gif -------------------------------------------------------------------------------- /cats/marmalade.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/marmalade.gif -------------------------------------------------------------------------------- /cats/mermaid.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/mermaid.gif -------------------------------------------------------------------------------- /cats/mike.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/mike.gif -------------------------------------------------------------------------------- /cats/moka.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/moka.gif -------------------------------------------------------------------------------- /cats/neon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/neon.gif -------------------------------------------------------------------------------- /cats/oneko.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/oneko.gif -------------------------------------------------------------------------------- /cats/orange.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/orange.gif -------------------------------------------------------------------------------- /cats/peach.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/peach.gif -------------------------------------------------------------------------------- /cats/pink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/pink.gif -------------------------------------------------------------------------------- /cats/rainbow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/rainbow.gif -------------------------------------------------------------------------------- /cats/robot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/robot.gif -------------------------------------------------------------------------------- /cats/rose.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/rose.gif -------------------------------------------------------------------------------- /cats/royal.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/royal.gif -------------------------------------------------------------------------------- /cats/silver.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/silver.gif -------------------------------------------------------------------------------- /cats/silversky.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/silversky.gif -------------------------------------------------------------------------------- /cats/socks.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/socks.gif -------------------------------------------------------------------------------- /cats/spirit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/spirit.gif -------------------------------------------------------------------------------- /cats/spooky.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/spooky.gif -------------------------------------------------------------------------------- /cats/usa.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/usa.gif -------------------------------------------------------------------------------- /cats/valentine.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/valentine.gif -------------------------------------------------------------------------------- /cats/water.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/cats/water.gif -------------------------------------------------------------------------------- /icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/icon128.png -------------------------------------------------------------------------------- /icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/icon16.png -------------------------------------------------------------------------------- /icon32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/icon32.png -------------------------------------------------------------------------------- /icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/icon48.png -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "car-paglu", 4 | "version": "1.0.3", 5 | "description": "Adds a cute car that follows your cursor around", 6 | "content_scripts": [ 7 | { 8 | "js": ["oneko.js"], 9 | "matches": [""] 10 | } 11 | ], 12 | "action": { 13 | "default_icon": { 14 | "16": "icon16.png", 15 | "32": "icon32.png", 16 | "48": "icon48.png", 17 | "128": "icon128.png" 18 | }, 19 | "default_popup": "popup.html" 20 | }, 21 | "icons": { 22 | "16": "icon16.png", 23 | "32": "icon32.png", 24 | "48": "icon48.png", 25 | "128": "icon128.png" 26 | }, 27 | "options_ui": { 28 | "page": "options.html", 29 | "open_in_tab": false 30 | }, 31 | "permissions": ["tabs", "storage"], 32 | "web_accessible_resources": [ 33 | { 34 | "resources": [ 35 | "oneko.gif", 36 | "options/*.gif" 37 | ], 38 | "matches": [""] 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /oneko.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/oneko.gif -------------------------------------------------------------------------------- /oneko.js: -------------------------------------------------------------------------------- 1 | (function oneko() { 2 | let nekoEl = null; 3 | let nekoPosX = 32; 4 | let nekoPosY = 32; 5 | let mousePosX = 0; 6 | let mousePosY = 0; 7 | let frameCount = 0; 8 | let idleTime = 0; 9 | let idleAnimation = null; 10 | let idleAnimationFrame = 0; 11 | let lastFrameTimestamp; 12 | let animationFrameRequest = null; 13 | const currentHostname = window.location.hostname; 14 | 15 | const nekoSpeed = 10; 16 | const spriteSets = { 17 | idle: [[-3, -3]], 18 | alert: [[-7, -3]], 19 | scratchSelf: [ 20 | [-5, 0], 21 | [-6, 0], 22 | [-7, 0], 23 | ], 24 | scratchWallN: [ 25 | [0, 0], 26 | [0, -1], 27 | ], 28 | scratchWallS: [ 29 | [-7, -1], 30 | [-6, -2], 31 | ], 32 | scratchWallE: [ 33 | [-2, -2], 34 | [-2, -3], 35 | ], 36 | scratchWallW: [ 37 | [-4, 0], 38 | [-4, -1], 39 | ], 40 | tired: [[-3, -2]], 41 | sleeping: [ 42 | [-2, 0], 43 | [-2, -1], 44 | ], 45 | N: [ 46 | [-1, -2], 47 | [-1, -3], 48 | ], 49 | NE: [ 50 | [0, -2], 51 | [0, -3], 52 | ], 53 | E: [ 54 | [-3, 0], 55 | [-3, -1], 56 | ], 57 | SE: [ 58 | [-5, -1], 59 | [-5, -2], 60 | ], 61 | S: [ 62 | [-6, -3], 63 | [-7, -2], 64 | ], 65 | SW: [ 66 | [-5, -3], 67 | [-6, -1], 68 | ], 69 | W: [ 70 | [-4, -2], 71 | [-4, -3], 72 | ], 73 | NW: [ 74 | [-1, 0], 75 | [-1, -1], 76 | ], 77 | }; 78 | 79 | function createNeko(catTheme) { 80 | // Remove previous neko if it exists 81 | if (nekoEl && nekoEl.isConnected) { 82 | nekoEl.remove(); 83 | } 84 | 85 | // Reset animation values 86 | nekoPosX = 32; 87 | nekoPosY = 32; 88 | frameCount = 0; 89 | idleTime = 0; 90 | idleAnimation = null; 91 | idleAnimationFrame = 0; 92 | lastFrameTimestamp = null; 93 | 94 | // Create new neko 95 | nekoEl = document.createElement("div"); 96 | nekoEl.id = "oneko"; 97 | nekoEl.ariaHidden = true; 98 | nekoEl.style.width = "32px"; 99 | nekoEl.style.height = "32px"; 100 | nekoEl.style.position = "fixed"; 101 | nekoEl.style.pointerEvents = "none"; 102 | nekoEl.style.imageRendering = "pixelated"; 103 | nekoEl.style.left = `${nekoPosX - 16}px`; 104 | nekoEl.style.top = `${nekoPosY - 16}px`; 105 | nekoEl.style.zIndex = 2147483647; 106 | 107 | // Use the selected cat theme 108 | let nekoFile; 109 | if (catTheme === 'oneko') { 110 | nekoFile = chrome.runtime.getURL("oneko.gif"); 111 | } else { 112 | nekoFile = chrome.runtime.getURL(`options/${catTheme}.gif`); 113 | } 114 | 115 | nekoEl.style.backgroundImage = `url(${nekoFile})`; 116 | document.body.appendChild(nekoEl); 117 | 118 | // Start animation if not already running 119 | if (!animationFrameRequest) { 120 | animationFrameRequest = window.requestAnimationFrame(onAnimationFrame); 121 | } 122 | } 123 | 124 | function setSprite(name, frame) { 125 | if (!nekoEl || !nekoEl.isConnected) return; 126 | const sprite = spriteSets[name][frame % spriteSets[name].length]; 127 | nekoEl.style.backgroundPosition = `${sprite[0] * 32}px ${sprite[1] * 32}px`; 128 | } 129 | 130 | function resetIdleAnimation() { 131 | idleAnimation = null; 132 | idleAnimationFrame = 0; 133 | } 134 | 135 | function idle() { 136 | idleTime += 1; 137 | 138 | // every ~ 20 seconds 139 | if ( 140 | idleTime > 10 && 141 | Math.floor(Math.random() * 200) == 0 && 142 | idleAnimation == null 143 | ) { 144 | let avalibleIdleAnimations = ["sleeping", "scratchSelf"]; 145 | if (nekoPosX < 32) { 146 | avalibleIdleAnimations.push("scratchWallW"); 147 | } 148 | if (nekoPosY < 32) { 149 | avalibleIdleAnimations.push("scratchWallN"); 150 | } 151 | if (nekoPosX > window.innerWidth - 32) { 152 | avalibleIdleAnimations.push("scratchWallE"); 153 | } 154 | if (nekoPosY > window.innerHeight - 32) { 155 | avalibleIdleAnimations.push("scratchWallS"); 156 | } 157 | idleAnimation = 158 | avalibleIdleAnimations[ 159 | Math.floor(Math.random() * avalibleIdleAnimations.length) 160 | ]; 161 | } 162 | 163 | switch (idleAnimation) { 164 | case "sleeping": 165 | if (idleAnimationFrame < 8) { 166 | setSprite("tired", 0); 167 | break; 168 | } 169 | setSprite("sleeping", Math.floor(idleAnimationFrame / 4)); 170 | if (idleAnimationFrame > 192) { 171 | resetIdleAnimation(); 172 | } 173 | break; 174 | case "scratchWallN": 175 | case "scratchWallS": 176 | case "scratchWallE": 177 | case "scratchWallW": 178 | case "scratchSelf": 179 | setSprite(idleAnimation, idleAnimationFrame); 180 | if (idleAnimationFrame > 9) { 181 | resetIdleAnimation(); 182 | } 183 | break; 184 | default: 185 | setSprite("idle", 0); 186 | return; 187 | } 188 | idleAnimationFrame += 1; 189 | } 190 | 191 | function frame() { 192 | if (!nekoEl || !nekoEl.isConnected) return; 193 | 194 | frameCount += 1; 195 | const diffX = nekoPosX - mousePosX; 196 | const diffY = nekoPosY - mousePosY; 197 | const distance = Math.sqrt(diffX ** 2 + diffY ** 2); 198 | 199 | if (distance < nekoSpeed || distance < 48) { 200 | idle(); 201 | return; 202 | } 203 | 204 | idleAnimation = null; 205 | idleAnimationFrame = 0; 206 | 207 | if (idleTime > 1) { 208 | setSprite("alert", 0); 209 | // count down after being alerted before moving 210 | idleTime = Math.min(idleTime, 7); 211 | idleTime -= 1; 212 | return; 213 | } 214 | 215 | let direction; 216 | direction = diffY / distance > 0.5 ? "N" : ""; 217 | direction += diffY / distance < -0.5 ? "S" : ""; 218 | direction += diffX / distance > 0.5 ? "W" : ""; 219 | direction += diffX / distance < -0.5 ? "E" : ""; 220 | setSprite(direction, frameCount); 221 | 222 | nekoPosX -= (diffX / distance) * nekoSpeed; 223 | nekoPosY -= (diffY / distance) * nekoSpeed; 224 | 225 | nekoPosX = Math.min(Math.max(16, nekoPosX), window.innerWidth - 16); 226 | nekoPosY = Math.min(Math.max(16, nekoPosY), window.innerHeight - 16); 227 | 228 | nekoEl.style.left = `${nekoPosX - 16}px`; 229 | nekoEl.style.top = `${nekoPosY - 16}px`; 230 | } 231 | 232 | function onAnimationFrame(timestamp) { 233 | // Stops execution if the neko element is removed from DOM 234 | if (!nekoEl || !nekoEl.isConnected) { 235 | animationFrameRequest = null; 236 | return; 237 | } 238 | if (!lastFrameTimestamp) { 239 | lastFrameTimestamp = timestamp; 240 | } 241 | if (timestamp - lastFrameTimestamp > 100) { 242 | lastFrameTimestamp = timestamp; 243 | frame(); 244 | } 245 | animationFrameRequest = window.requestAnimationFrame(onAnimationFrame); 246 | } 247 | 248 | // Initialize event listeners 249 | function init(data) { 250 | const isReducedMotion = 251 | window.matchMedia(`(prefers-reduced-motion: reduce)`) === true || 252 | window.matchMedia(`(prefers-reduced-motion: reduce)`).matches === true; 253 | 254 | if (isReducedMotion) return; 255 | 256 | // Check if this site is in the blocked list 257 | if (data.blockedSites && data.blockedSites.includes(currentHostname)) { 258 | // Remove neko if it exists 259 | if (nekoEl && nekoEl.isConnected) { 260 | nekoEl.remove(); 261 | nekoEl = null; 262 | if (animationFrameRequest) { 263 | window.cancelAnimationFrame(animationFrameRequest); 264 | animationFrameRequest = null; 265 | } 266 | } 267 | return; 268 | } 269 | 270 | // Create neko with current theme 271 | createNeko(data.catTheme || 'oneko'); 272 | 273 | // Add mouse movement tracker if not already added 274 | if (!window.onekoMouseListenerAdded) { 275 | document.addEventListener("mousemove", function (event) { 276 | mousePosX = event.clientX; 277 | mousePosY = event.clientY; 278 | }); 279 | window.onekoMouseListenerAdded = true; 280 | } 281 | } 282 | 283 | // Handle messages from popup 284 | chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) { 285 | if (message.action === "update_settings") { 286 | init(message.data); 287 | sendResponse({success: true}); 288 | } 289 | return true; 290 | }); 291 | 292 | // Initial load 293 | chrome.storage.sync.get({blockedSites: [], catTheme: 'oneko'}, init); 294 | })(); -------------------------------------------------------------------------------- /options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CatPaglu Options 5 | 169 | 170 | 171 |
172 |

CatPaglu Settings

173 | 174 |
175 |

Manage sites where you don't want the cat to appear.

176 |
177 | 178 |
179 |

Blocked Sites

180 |
No sites are currently blocked.
181 |
    182 | 183 |
    184 | 185 | 186 |
    187 | 188 |
    Settings saved!
    189 |
    190 |
    191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /options.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | const siteList = document.getElementById('site-list'); 3 | const noSitesMessage = document.getElementById('no-sites-message'); 4 | const newSiteInput = document.getElementById('new-site'); 5 | const addSiteBtn = document.getElementById('add-site-btn'); 6 | const statusText = document.getElementById('status'); 7 | 8 | // Load saved blocked sites 9 | function loadBlockedSites() { 10 | chrome.storage.sync.get({blockedSites: []}, function(data) { 11 | const blockedSites = data.blockedSites; 12 | 13 | // Clear current list 14 | siteList.innerHTML = ''; 15 | 16 | // Show/hide no sites message 17 | if (blockedSites.length === 0) { 18 | noSitesMessage.style.display = 'block'; 19 | } else { 20 | noSitesMessage.style.display = 'none'; 21 | 22 | // Add each site to the list 23 | blockedSites.forEach(function(site) { 24 | const listItem = document.createElement('li'); 25 | listItem.className = 'site-item'; 26 | 27 | const siteText = document.createElement('span'); 28 | siteText.textContent = site; 29 | 30 | const deleteBtn = document.createElement('button'); 31 | deleteBtn.className = 'delete-btn'; 32 | deleteBtn.textContent = 'Remove'; 33 | deleteBtn.addEventListener('click', function() { 34 | removeSite(site); 35 | }); 36 | 37 | listItem.appendChild(siteText); 38 | listItem.appendChild(deleteBtn); 39 | siteList.appendChild(listItem); 40 | }); 41 | } 42 | }); 43 | } 44 | 45 | // Remove a site from the blocked list 46 | function removeSite(site) { 47 | chrome.storage.sync.get({blockedSites: []}, function(data) { 48 | let blockedSites = data.blockedSites; 49 | 50 | // Remove the site 51 | blockedSites = blockedSites.filter(s => s !== site); 52 | 53 | // Save updated list 54 | chrome.storage.sync.set({blockedSites: blockedSites}, function() { 55 | showStatus('Site removed'); 56 | loadBlockedSites(); 57 | }); 58 | }); 59 | } 60 | 61 | // Add a new site to the blocked list 62 | function addSite(site) { 63 | // Basic validation - make sure it's not empty 64 | site = site.trim().toLowerCase(); 65 | 66 | if (!site) { 67 | showStatus('Please enter a valid site', 'red'); 68 | return; 69 | } 70 | 71 | // Remove http://, https://, and www. prefixes if present 72 | site = site.replace(/^https?:\/\//, '').replace(/^www\./, ''); 73 | 74 | chrome.storage.sync.get({blockedSites: []}, function(data) { 75 | let blockedSites = data.blockedSites; 76 | 77 | // Check if site already exists in the list 78 | if (blockedSites.includes(site)) { 79 | showStatus('Site already in list', 'red'); 80 | return; 81 | } 82 | 83 | // Add the site 84 | blockedSites.push(site); 85 | 86 | // Save updated list 87 | chrome.storage.sync.set({blockedSites: blockedSites}, function() { 88 | showStatus('Site added'); 89 | newSiteInput.value = ''; 90 | loadBlockedSites(); 91 | }); 92 | }); 93 | } 94 | 95 | // Show status message 96 | function showStatus(message, color = 'green') { 97 | statusText.textContent = message; 98 | statusText.style.color = color; 99 | statusText.style.display = 'block'; 100 | 101 | setTimeout(function() { 102 | statusText.style.display = 'none'; 103 | }, 1500); 104 | } 105 | 106 | // Add site button click handler 107 | addSiteBtn.addEventListener('click', function() { 108 | addSite(newSiteInput.value); 109 | }); 110 | 111 | // Enter key in input field 112 | newSiteInput.addEventListener('keypress', function(e) { 113 | if (e.key === 'Enter') { 114 | addSite(newSiteInput.value); 115 | } 116 | }); 117 | 118 | // Load blocked sites on page load 119 | loadBlockedSites(); 120 | }); -------------------------------------------------------------------------------- /options/ace.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/ace.gif -------------------------------------------------------------------------------- /options/air.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/air.gif -------------------------------------------------------------------------------- /options/black.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/black.gif -------------------------------------------------------------------------------- /options/blue.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/blue.gif -------------------------------------------------------------------------------- /options/calico.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/calico.gif -------------------------------------------------------------------------------- /options/colourful.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/colourful.gif -------------------------------------------------------------------------------- /options/dave.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/dave.gif -------------------------------------------------------------------------------- /options/earth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/earth.gif -------------------------------------------------------------------------------- /options/fancy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/fancy.gif -------------------------------------------------------------------------------- /options/fire.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/fire.gif -------------------------------------------------------------------------------- /options/ghetto.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/ghetto.gif -------------------------------------------------------------------------------- /options/ghost.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/ghost.gif -------------------------------------------------------------------------------- /options/gray.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/gray.gif -------------------------------------------------------------------------------- /options/holiday.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/holiday.gif -------------------------------------------------------------------------------- /options/jess.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/jess.gif -------------------------------------------------------------------------------- /options/kina.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/kina.gif -------------------------------------------------------------------------------- /options/kuramecha.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/kuramecha.gif -------------------------------------------------------------------------------- /options/lucky.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/lucky.gif -------------------------------------------------------------------------------- /options/lucy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/lucy.gif -------------------------------------------------------------------------------- /options/marmalade.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/marmalade.gif -------------------------------------------------------------------------------- /options/mermaid.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/mermaid.gif -------------------------------------------------------------------------------- /options/mike.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/mike.gif -------------------------------------------------------------------------------- /options/moka.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/moka.gif -------------------------------------------------------------------------------- /options/neon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/neon.gif -------------------------------------------------------------------------------- /options/oneko.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/oneko.gif -------------------------------------------------------------------------------- /options/orange.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/orange.gif -------------------------------------------------------------------------------- /options/peach.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/peach.gif -------------------------------------------------------------------------------- /options/pink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/pink.gif -------------------------------------------------------------------------------- /options/rainbow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/rainbow.gif -------------------------------------------------------------------------------- /options/robot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/robot.gif -------------------------------------------------------------------------------- /options/rose.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/rose.gif -------------------------------------------------------------------------------- /options/royal.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/royal.gif -------------------------------------------------------------------------------- /options/silver.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/silver.gif -------------------------------------------------------------------------------- /options/silversky.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/silversky.gif -------------------------------------------------------------------------------- /options/socks.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/socks.gif -------------------------------------------------------------------------------- /options/spirit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/spirit.gif -------------------------------------------------------------------------------- /options/spooky.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/spooky.gif -------------------------------------------------------------------------------- /options/usa.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/usa.gif -------------------------------------------------------------------------------- /options/valentine.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/valentine.gif -------------------------------------------------------------------------------- /options/water.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icantcodefyi/neko-extension/006cbc194bcb80631865f35b34473e643256fcef/options/water.gif -------------------------------------------------------------------------------- /popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CatPaglu Controls 5 | 456 | 457 | 458 |
    459 |

    CatPaglu Iconcar-paglu controls

    460 | 461 |
    462 |
    463 | Cat Theme 464 | 637 |
    638 | 639 |
    640 | Enable cat on this site 641 | 645 |
    646 | 647 | 648 |
    Settings saved!
    649 | 650 | 651 | 652 | 665 |
    666 |
    667 | 668 | 671 | 672 | 673 | 674 | -------------------------------------------------------------------------------- /popup.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | const enableToggle = document.getElementById('enableOnCurrentSite'); 3 | const saveButton = document.getElementById('saveButton'); 4 | const statusText = document.getElementById('status'); 5 | const toggleManageButton = document.getElementById('toggleManage'); 6 | const manageSitesSection = document.getElementById('manageSites'); 7 | const siteList = document.getElementById('site-list'); 8 | const siteListContainer = document.querySelector('.site-list-container'); 9 | const noSitesMessage = document.getElementById('no-sites-message'); 10 | const newSiteInput = document.getElementById('new-site'); 11 | const addSiteButton = document.getElementById('add-site-btn'); 12 | const themeSelect = document.querySelector('.theme-select'); 13 | const themeSelectValue = document.querySelector('.theme-select-value'); 14 | const themeSelectContent = document.querySelector('.theme-select-content'); 15 | const catPreview = document.getElementById('catPreview'); 16 | 17 | let hasUnsavedChanges = false; 18 | 19 | // Function to update save button appearance 20 | function updateSaveButton() { 21 | if (hasUnsavedChanges) { 22 | saveButton.style.backgroundColor = 'hsl(var(--destructive))'; 23 | saveButton.textContent = 'Save Changes*'; 24 | } else { 25 | saveButton.style.backgroundColor = 'hsl(var(--primary))'; 26 | saveButton.textContent = 'Save Setting'; 27 | } 28 | } 29 | 30 | // Function to mark changes as unsaved 31 | function markAsUnsaved() { 32 | hasUnsavedChanges = true; 33 | updateSaveButton(); 34 | } 35 | 36 | // Function to update cat preview 37 | function updateCatPreview(theme) { 38 | const selectedPreview = document.getElementById('selectedPreview'); 39 | selectedPreview.src = `cats/${theme}.gif`; 40 | markAsUnsaved(); 41 | } 42 | 43 | // Load current cat theme 44 | chrome.storage.sync.get(['catTheme'], function(result) { 45 | const theme = result.catTheme || 'oneko'; 46 | // Update the selected item and value text 47 | const items = document.querySelectorAll('.theme-select-item'); 48 | items.forEach(item => { 49 | if (item.dataset.value === theme) { 50 | item.dataset.selected = 'true'; 51 | themeSelectValue.textContent = item.querySelector('span').textContent; 52 | updateCatPreview(theme); 53 | } else { 54 | item.dataset.selected = 'false'; 55 | } 56 | }); 57 | hasUnsavedChanges = false; 58 | updateSaveButton(); 59 | }); 60 | 61 | // Handle theme select click 62 | themeSelect.addEventListener('click', function(e) { 63 | const isOpen = themeSelect.dataset.state === 'open'; 64 | themeSelect.dataset.state = isOpen ? 'closed' : 'open'; 65 | themeSelect.setAttribute('aria-expanded', !isOpen); 66 | e.stopPropagation(); 67 | }); 68 | 69 | // Handle theme item selection 70 | themeSelectContent.addEventListener('click', function(e) { 71 | e.stopPropagation(); // Stop event from bubbling up 72 | const item = e.target.closest('.theme-select-item'); 73 | if (!item) return; 74 | 75 | const selectedTheme = item.dataset.value; 76 | const items = document.querySelectorAll('.theme-select-item'); 77 | 78 | items.forEach(i => { 79 | i.dataset.selected = i === item ? 'true' : 'false'; 80 | }); 81 | 82 | themeSelectValue.textContent = item.querySelector('span').textContent; 83 | 84 | // Ensure dropdown is closed 85 | setTimeout(() => { 86 | themeSelect.dataset.state = 'closed'; 87 | themeSelect.setAttribute('aria-expanded', 'false'); 88 | }, 0); 89 | 90 | updateCatPreview(selectedTheme); 91 | }); 92 | 93 | // Close select when clicking outside 94 | document.addEventListener('click', function(e) { 95 | if (!themeSelect.contains(e.target)) { 96 | themeSelect.dataset.state = 'closed'; 97 | themeSelect.setAttribute('aria-expanded', 'false'); 98 | } 99 | }); 100 | 101 | // Handle keyboard navigation 102 | themeSelect.addEventListener('keydown', function(e) { 103 | if (e.key === 'Enter' || e.key === ' ') { 104 | e.preventDefault(); 105 | const isOpen = themeSelect.dataset.state === 'open'; 106 | themeSelect.dataset.state = isOpen ? 'closed' : 'open'; 107 | themeSelect.setAttribute('aria-expanded', !isOpen); 108 | } else if (e.key === 'Escape') { 109 | themeSelect.dataset.state = 'closed'; 110 | themeSelect.setAttribute('aria-expanded', 'false'); 111 | } 112 | }); 113 | 114 | // Update scroll indicators when the list scrolls 115 | function updateScrollIndicators() { 116 | if (!siteListContainer) return; 117 | 118 | const canScrollUp = siteList.scrollTop > 0; 119 | const canScrollDown = siteList.scrollTop < (siteList.scrollHeight - siteList.clientHeight); 120 | 121 | siteListContainer.classList.toggle('can-scroll-up', canScrollUp); 122 | siteListContainer.classList.toggle('can-scroll-down', canScrollDown); 123 | } 124 | 125 | // Add scroll event listener to the sites list 126 | siteList.addEventListener('scroll', updateScrollIndicators); 127 | 128 | // Helper function to normalize domain 129 | function normalizeDomain(domain) { 130 | domain = domain.toLowerCase().trim(); 131 | // Remove protocol and path 132 | domain = domain.replace(/^(https?:\/\/)?(www\.)?/i, ''); 133 | domain = domain.split('/')[0]; 134 | return domain; 135 | } 136 | 137 | // Helper function to get domain variations 138 | function getDomainVariations(domain) { 139 | const normalizedDomain = normalizeDomain(domain); 140 | return [normalizedDomain, `www.${normalizedDomain}`]; 141 | } 142 | 143 | // Helper function to get display domain 144 | function getDisplayDomain(domain) { 145 | return normalizeDomain(domain); 146 | } 147 | 148 | // Helper function to check if domain is blocked (including variations) 149 | function isDomainBlocked(domain, blockedSites) { 150 | const variations = getDomainVariations(domain); 151 | return variations.some(variation => blockedSites.includes(variation)); 152 | } 153 | 154 | // Load current site settings 155 | chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { 156 | const currentUrl = new URL(tabs[0].url); 157 | const hostname = currentUrl.hostname; 158 | 159 | chrome.storage.sync.get(['blockedSites'], function(result) { 160 | const blockedSites = result.blockedSites || []; 161 | enableToggle.checked = !isDomainBlocked(hostname, blockedSites); 162 | hasUnsavedChanges = false; 163 | updateSaveButton(); 164 | }); 165 | }); 166 | 167 | // Add change event listener to the toggle 168 | enableToggle.addEventListener('change', function() { 169 | markAsUnsaved(); 170 | }); 171 | 172 | // Toggle manage sites section 173 | toggleManageButton.addEventListener('click', function() { 174 | const isHidden = manageSitesSection.classList.contains('hidden'); 175 | manageSitesSection.classList.toggle('hidden'); 176 | toggleManageButton.textContent = isHidden ? 'Hide blocked sites' : 'Manage blocked sites'; 177 | 178 | if (!isHidden) return; // Only load sites when opening 179 | 180 | // Load and display blocked sites 181 | chrome.storage.sync.get(['blockedSites'], function(result) { 182 | const blockedSites = result.blockedSites || []; 183 | updateSitesList(blockedSites); 184 | }); 185 | }); 186 | 187 | // Save current site setting and theme 188 | saveButton.addEventListener('click', function() { 189 | const selectedTheme = document.querySelector('.theme-select-item[data-selected="true"]').dataset.value; 190 | 191 | // Save theme 192 | chrome.storage.sync.set({ catTheme: selectedTheme }); 193 | 194 | // Save site settings 195 | chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { 196 | const currentUrl = new URL(tabs[0].url); 197 | const hostname = currentUrl.hostname; 198 | const currentTab = tabs[0]; 199 | 200 | chrome.storage.sync.get(['blockedSites'], function(result) { 201 | let blockedSites = result.blockedSites || []; 202 | 203 | if (enableToggle.checked) { 204 | // Remove all variations of the domain 205 | blockedSites = blockedSites.filter(site => 206 | !getDomainVariations(hostname).includes(site) 207 | ); 208 | } else { 209 | // Add all variations if not already blocked 210 | const variations = getDomainVariations(hostname); 211 | variations.forEach(variation => { 212 | if (!blockedSites.includes(variation)) { 213 | blockedSites.push(variation); 214 | } 215 | }); 216 | } 217 | 218 | chrome.storage.sync.set({blockedSites: blockedSites}, function() { 219 | hasUnsavedChanges = false; 220 | updateSaveButton(); 221 | 222 | // Send message to content script to update in real-time 223 | chrome.tabs.sendMessage(currentTab.id, { 224 | action: "update_settings", 225 | data: { 226 | catTheme: selectedTheme, 227 | blockedSites: blockedSites 228 | } 229 | }); 230 | 231 | showStatus('Settings applied!', 2000); 232 | updateSitesList(blockedSites); 233 | }); 234 | }); 235 | }); 236 | }); 237 | 238 | // Add new site 239 | addSiteButton.addEventListener('click', function() { 240 | const newSite = newSiteInput.value.trim(); 241 | if (!newSite) return; 242 | 243 | chrome.storage.sync.get(['blockedSites', 'catTheme'], function(result) { 244 | let blockedSites = result.blockedSites || []; 245 | const catTheme = result.catTheme || 'oneko'; 246 | const variations = getDomainVariations(newSite); 247 | 248 | // Check if any variation is already blocked 249 | if (!variations.some(v => blockedSites.includes(v))) { 250 | // Add all variations 251 | variations.forEach(variation => blockedSites.push(variation)); 252 | 253 | chrome.storage.sync.set({blockedSites: blockedSites}, function() { 254 | newSiteInput.value = ''; 255 | 256 | // Notify all tabs about the change 257 | chrome.tabs.query({}, function(tabs) { 258 | tabs.forEach(tab => { 259 | chrome.tabs.sendMessage(tab.id, { 260 | action: "update_settings", 261 | data: { 262 | catTheme: catTheme, 263 | blockedSites: blockedSites 264 | } 265 | }); 266 | }); 267 | }); 268 | 269 | showStatus('Site added!'); 270 | updateSitesList(blockedSites); 271 | }); 272 | } else { 273 | showStatus('Site already blocked!'); 274 | } 275 | }); 276 | }); 277 | 278 | // Handle delete site clicks 279 | siteList.addEventListener('click', function(e) { 280 | if (!e.target.classList.contains('delete-btn')) return; 281 | 282 | const siteToDelete = e.target.dataset.site; 283 | chrome.storage.sync.get(['blockedSites', 'catTheme'], function(result) { 284 | let blockedSites = result.blockedSites || []; 285 | const catTheme = result.catTheme || 'oneko'; 286 | 287 | // Remove all variations of the domain 288 | blockedSites = blockedSites.filter(site => 289 | !getDomainVariations(siteToDelete).includes(site) 290 | ); 291 | 292 | chrome.storage.sync.set({blockedSites: blockedSites}, function() { 293 | // Notify all tabs about the change 294 | chrome.tabs.query({}, function(tabs) { 295 | tabs.forEach(tab => { 296 | chrome.tabs.sendMessage(tab.id, { 297 | action: "update_settings", 298 | data: { 299 | catTheme: catTheme, 300 | blockedSites: blockedSites 301 | } 302 | }); 303 | }); 304 | }); 305 | 306 | showStatus('Site removed!'); 307 | updateSitesList(blockedSites); 308 | }); 309 | }); 310 | }); 311 | 312 | // Helper function to update sites list UI 313 | function updateSitesList(sites) { 314 | siteList.innerHTML = ''; 315 | 316 | // Get unique normalized domains 317 | const uniqueDomains = [...new Set(sites.map(site => normalizeDomain(site)))]; 318 | noSitesMessage.style.display = uniqueDomains.length ? 'none' : 'block'; 319 | 320 | uniqueDomains.forEach(domain => { 321 | const li = document.createElement('li'); 322 | li.className = 'site-item'; 323 | li.innerHTML = ` 324 | ${domain} 325 | 326 | `; 327 | siteList.appendChild(li); 328 | }); 329 | 330 | // Update scroll indicators after updating the list 331 | updateScrollIndicators(); 332 | } 333 | 334 | // Helper function to show status message with custom duration 335 | function showStatus(message, duration = 2000) { 336 | statusText.textContent = message; 337 | statusText.style.display = 'block'; 338 | setTimeout(() => { 339 | statusText.style.display = 'none'; 340 | }, duration); 341 | } 342 | }); -------------------------------------------------------------------------------- /privacy.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy for Car-Paglu Chrome Extension 2 | 3 | ## Introduction 4 | Car-Paglu is a Chrome extension that adds a decorative car animation that follows your cursor around web pages. We are committed to protecting your privacy and being transparent about our practices. 5 | 6 | ## Data Collection and Usage 7 | Car-Paglu does not collect, store, or transmit any personal information. Specifically: 8 | 9 | - We do not collect any personal data 10 | - We do not track your browsing history 11 | - We do not store any information about your web activities 12 | - We do not use cookies 13 | - We do not share any data with third parties 14 | 15 | ## Permissions Explained 16 | 17 | ### Host Permission (``) 18 | - **Purpose**: To display the car animation on web pages you visit 19 | - **Usage**: Only used to render the car graphic and track cursor movement locally 20 | - **Data Access**: No website data is collected or transmitted 21 | 22 | ### Storage Permission 23 | - **Purpose**: To save your extension preferences 24 | - **Usage**: Stores only local settings for the car animation 25 | - **Data Storage**: All data is stored locally in your browser 26 | - **Data Type**: Only extension-specific settings (e.g., animation preferences) 27 | 28 | ### Tabs Permission 29 | - **Purpose**: To manage car animation across different browser tabs 30 | - **Usage**: Only used to properly initialize and maintain the animation 31 | - **Data Access**: No tab content or browsing data is collected -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ### carpaglu chrome extension 2 | 3 | a car which follows you all around. 4 | 5 | ### Installation Guide 6 | 7 | #### Loading the Unpacked Extension 8 | 9 | 1. Download the latest release zip file from the [Releases](https://github.com/icantcodefyi/neko-extension/releases) page 10 | 2. Extract the downloaded zip file to a folder on your computer 11 | 3. Open Google Chrome browser 12 | 4. Navigate to `chrome://extensions/` in your browser 13 | 5. Enable "Developer mode" by toggling the switch in the top right corner 14 | 6. Click on "Load unpacked" button in the top left 15 | 7. Browse to the folder where you extracted the zip file 16 | 8. Select the folder and click "Open" 17 | 18 | The extension should now appear in your Chrome browser's extension toolbar. 19 | 20 | ### Contributing 21 | 22 | Feel free to submit issues and pull requests. --------------------------------------------------------------------------------