Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nazal #10

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Nazal #10

wants to merge 4 commits into from

Conversation

nazalnihad
Copy link

@nazalnihad nazalnihad commented Nov 2, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced the "Useless Projects Extension" to enhance user experience with interactive prompts.
    • Added an overlay that encourages users to take breaks when visiting productive sites.
    • Created an options page for managing productive and distracting sites.
    • Implemented a popup with functionality to start the extension and access settings.
  • Bug Fixes

    • Ensured overlays do not duplicate on the same page.
  • Documentation

    • Added a manifest file detailing extension metadata and permissions.
  • Style

    • Introduced new CSS styles for the options page to improve user interface consistency.

Copy link

coderabbitai bot commented Nov 2, 2024

Walkthrough

The pull request introduces a new browser extension named "Useless Projects Extension," which includes several new files. A manifest.json file defines the extension's metadata and permissions. The background.js file adds an event listener for installation notifications. The content.js file implements an overlay prompting users to take breaks on productive sites while alerting them on distracting sites. Additional files include an options page (options.html), its corresponding JavaScript (options.js), and CSS (options.css), as well as a popup page (popup.html) and its script (popup.js).

Changes

File Path Change Summary
.gitignore New file added: walk.py
pinne-cheyyam/background.js Added event listener for chrome.runtime.onInstalled to log installation message.
pinne-cheyyam/content.js Added functions createOverlay() and checkSiteType() to manage overlay display based on site type.
pinne-cheyyam/manifest.json New manifest file created for the extension, defining metadata, permissions, background scripts, and content scripts.
pinne-cheyyam/options/options.css New CSS file added for styling the options page with resets and specific styles for various elements.
pinne-cheyyam/options/options.html New HTML file created for the options page, allowing management of productive and distracting sites.
pinne-cheyyam/options/options.js New JavaScript file added with functions updateSiteList, addSite, and removeSite for managing site lists.
pinne-cheyyam/popup/popup.html New HTML file created for the popup interface of the extension, including buttons for interaction.
pinne-cheyyam/popup/popup.js Added event listeners in the popup for starting the annoying process and opening the options page.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Popup
    participant Options
    participant Background
    participant Content

    User->>Popup: Click "Start Annoying"
    Popup->>Background: Log "Annoying started!"
    User->>Popup: Click "Settings"
    Popup->>Options: Open options page
    User->>Content: Visit productive site
    Content->>Content: Check site type
    Content->>User: Show overlay
    User->>Content: Click close button
    Content->>Content: Remove overlay
Loading

🐰 "In the land of code, where changes bloom,
A new extension brings joy, dispelling gloom.
With overlays and options, all set to play,
Let's take a break, hop along the way!
Click and explore, let the fun begin,
In the world of 'Useless Projects,' let’s dive in!" 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Outside diff range and nitpick comments (4)
pinne-cheyyam/popup/popup.js (1)

1-8: Add JSDoc documentation and initialization checks

The file lacks documentation about its purpose and proper initialization checks for the Chrome extension APIs.

Consider adding documentation and checks:

+/**
+ * Popup script for the Useless Projects Extension
+ * Handles user interactions in the extension popup
+ */
+
+// Ensure we're running in a Chrome extension context
+if (!chrome?.runtime?.openOptionsPage) {
+  console.error('This script must be run in a Chrome extension context');
+  throw new Error('Chrome extension APIs not available');
+}
+
 const startButton = document.getElementById('start');
pinne-cheyyam/manifest.json (1)

2-8: Consider migrating to Manifest V3.

Chrome is deprecating Manifest V2, and it's recommended to use Manifest V3 for new extensions to ensure future compatibility.

Add additional icon sizes.

The extension only includes a 48px icon. Consider adding more sizes (16, 32, 128) for better display across different contexts:

 "icons": {
+    "16": "icons/icon16.png",
+    "32": "icons/icon32.png",
   "48": "icons/icon.png",
+    "128": "icons/icon128.png"
 }
pinne-cheyyam/options/options.html (1)

15-15: Add ARIA roles to the site lists.

The unordered lists should have ARIA roles for better accessibility.

Apply these changes:

-    <ul id="productiveList"></ul>
+    <ul id="productiveList" role="list" aria-label="List of productive sites"></ul>

-    <ul id="distractingList"></ul>
+    <ul id="distractingList" role="list" aria-label="List of distracting sites"></ul>

Also applies to: 22-22

pinne-cheyyam/options/options.js (1)

1-57: Consider architectural improvements for better maintainability.

  1. Separate the storage logic into a dedicated service class to improve testability and reuse.
  2. Consider using TypeScript for better type safety and developer experience.
  3. Implement a centralized error handling strategy.
  4. Add JSDoc comments for better documentation.

Here's a sketch of the suggested architecture:

/**
 * @typedef {Object} SiteStorageService
 * @property {function(string): Promise<string[]>} getSites
 * @property {function(string, string): Promise<void>} addSite
 * @property {function(string, number): Promise<void>} removeSite
 */

/**
 * @typedef {'productiveSites' | 'distractingSites'} SiteType
 */

class SiteStorageService {
    async getSites(type) {
        // Storage logic
    }
    async addSite(type, site) {
        // Add site logic
    }
    async removeSite(type, index) {
        // Remove site logic
    }
}

class UIManager {
    constructor(storageService) {
        this.storage = storageService;
    }
    
    async updateUI() {
        // UI update logic
    }
}

Would you like me to help implement this improved architecture?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5b21649 and 0e4c590.

⛔ Files ignored due to path filters (1)
  • pinne-cheyyam/icons/icon.png is excluded by !**/*.png
📒 Files selected for processing (10)
  • .gitignore (1 hunks)
  • pinne-cheyyam/background.js (1 hunks)
  • pinne-cheyyam/content.js (1 hunks)
  • pinne-cheyyam/manifest.json (1 hunks)
  • pinne-cheyyam/options/options.css (1 hunks)
  • pinne-cheyyam/options/options.html (1 hunks)
  • pinne-cheyyam/options/options.js (1 hunks)
  • pinne-cheyyam/popup/popup.css (1 hunks)
  • pinne-cheyyam/popup/popup.html (1 hunks)
  • pinne-cheyyam/popup/popup.js (1 hunks)
✅ Files skipped from review due to trivial changes (5)
  • .gitignore
  • pinne-cheyyam/background.js
  • pinne-cheyyam/options/options.css
  • pinne-cheyyam/popup/popup.css
  • pinne-cheyyam/popup/popup.html
🔇 Additional comments (6)
pinne-cheyyam/manifest.json (4)

9-13: LGTM! Permissions are appropriate.

The requested permissions align with the extension's functionality:

  • storage: Required for saving user preferences
  • tabs & activeTab: Needed for monitoring site visits

18-23: ⚠️ Potential issue

Consider restricting content script matches.

The "<all_urls>" match pattern grants the content script access to all websites, which might be broader than necessary. Consider restricting it to only the domains where the extension needs to function.

 "content_scripts": [
   {
-    "matches": ["<all_urls>"],
+    "matches": [
+      "*://*.google.com/*",
+      "*://*.github.com/*"
+      // Add other productive sites as needed
+    ],
     "js": ["content.js"]
   }
 ]

Verify content script implementation.

#!/bin/bash
# Verify content.js exists and contains overlay implementation
fd -t f "content.js" --exec rg -l "overlay|break"

24-29: Verify popup and options pages.

The configuration looks correct, but let's ensure the referenced files exist.

#!/bin/bash
# Verify popup and options pages exist
echo "Checking popup HTML:"
fd -t f "popup.html" -p "popup"

echo "Checking options HTML:"
fd -t f "options.html" -p "options"

14-17: Verify background.js implementation.

The background script configuration looks good, using non-persistent mode for better performance.

✅ Verification successful

Background script implementation verified and approved

The background script exists at pinne-cheyyam/background.js and contains the required installation handler. The implementation is minimal and correct, using the non-persistent mode as specified in the manifest.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify background.js exists and contains installation handler
fd -t f "background.js" --exec rg -l "chrome.runtime.onInstalled"

Length of output: 357


Script:

#!/bin/bash
# First verify if background.js exists
fd -t f "background.js"

# If it exists, let's examine its content
fd -t f "background.js" --exec cat {}

Length of output: 198

pinne-cheyyam/options/options.html (2)

1-7: LGTM! Document structure follows best practices.

The HTML document is well-structured with proper DOCTYPE declaration, language attribute, character encoding, and external resource links.


25-25: Verify script dependencies.

The options.js file is loaded without any error handling. Consider adding error handling and ensuring all required functionality is available.

Let's verify the script file exists and check its content:

Comment on lines +5 to +8
document.getElementById('openOptions').addEventListener('click', () => {
// Opens the options page
chrome.runtime.openOptionsPage();
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling for options button

Similar to the start button, this needs proper error handling for the DOM element lookup.

Apply this improvement:

-document.getElementById('openOptions').addEventListener('click', () => {
-  // Opens the options page
-  chrome.runtime.openOptionsPage();
-});
+const optionsButton = document.getElementById('openOptions');
+if (optionsButton) {
+  optionsButton.addEventListener('click', () => {
+    chrome.runtime.openOptionsPage();
+  });
+} else {
+  console.error('Options button not found in popup');
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
document.getElementById('openOptions').addEventListener('click', () => {
// Opens the options page
chrome.runtime.openOptionsPage();
});
const optionsButton = document.getElementById('openOptions');
if (optionsButton) {
optionsButton.addEventListener('click', () => {
chrome.runtime.openOptionsPage();
});
} else {
console.error('Options button not found in popup');
}

Comment on lines +1 to +8
document.getElementById('start').addEventListener('click', () => {
console.log('Annoying started!');
});

document.getElementById('openOptions').addEventListener('click', () => {
// Opens the options page
chrome.runtime.openOptionsPage();
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Missing implementation for 'start' functionality

The background script currently only handles installation events and lacks any implementation for the 'start' functionality referenced in popup.js. The click handler in popup.js only logs a message without any actual integration with the background script.

Required changes:

  • Implement message passing between popup and background script for the 'start' functionality
  • Add corresponding message handler in background.js to process the 'start' action
🔗 Analysis chain

Verify integration with background script

The 'start' functionality seems to be missing its core implementation. We should verify if there's corresponding handling in the background script.

Let's check for related background script implementations:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Look for background script handling of the 'start' functionality

# Check for background script files
echo "Checking for background script files:"
fd -e js -e ts background

# Look for message handling related to 'start' functionality
echo -e "\nChecking for message handlers:"
rg -l "chrome\.(runtime|extension)\.onMessage" 

Length of output: 266


Script:

#!/bin/bash
# Let's examine the content of the background script and look for any start-related functionality
echo "Content of background.js:"
cat pinne-cheyyam/background.js

# Also check for any other potential message passing or start functionality implementations
echo -e "\nChecking for any start-related functionality across the codebase:"
rg -i "start" --type js -C 2

Length of output: 600

Comment on lines +1 to +3
document.getElementById('start').addEventListener('click', () => {
console.log('Annoying started!');
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling and remove console.log

The current implementation has two issues:

  1. Missing error handling for the DOM element lookup
  2. Console.log statement should not be in production code

Consider implementing proper error handling and actual functionality:

-document.getElementById('start').addEventListener('click', () => {
-  console.log('Annoying started!');
-});
+const startButton = document.getElementById('start');
+if (startButton) {
+  startButton.addEventListener('click', () => {
+    // TODO: Implement the actual start functionality
+  });
+} else {
+  console.error('Start button not found in popup');
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
document.getElementById('start').addEventListener('click', () => {
console.log('Annoying started!');
});
const startButton = document.getElementById('start');
if (startButton) {
startButton.addEventListener('click', () => {
// TODO: Implement the actual start functionality
});
} else {
console.error('Start button not found in popup');
}

Comment on lines +13 to +14
<input type="text" id="productiveInput" placeholder="Add a productive site URL">
<button id="addProductive">Add</button>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Enhance input validation and accessibility.

The input fields and buttons need improvements for better accessibility and user experience:

  1. Add aria-label attributes to inputs for screen readers
  2. Add pattern validation for URL inputs
  3. Add disabled state handling for the Add buttons

Apply these changes:

-    <input type="text" id="productiveInput" placeholder="Add a productive site URL">
-    <button id="addProductive">Add</button>
+    <input 
+      type="url" 
+      id="productiveInput" 
+      placeholder="Add a productive site URL"
+      aria-label="Enter productive site URL"
+      pattern="https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)"
+    >
+    <button id="addProductive" aria-label="Add productive site">Add</button>

-    <input type="text" id="distractingInput" placeholder="Add a distracting site URL">
-    <button id="addDistracting">Add</button>
+    <input 
+      type="url" 
+      id="distractingInput" 
+      placeholder="Add a distracting site URL"
+      aria-label="Enter distracting site URL"
+      pattern="https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)"
+    >
+    <button id="addDistracting" aria-label="Add distracting site">Add</button>

Also applies to: 20-21

Comment on lines +11 to +23
<div>
<h2>Productive Sites</h2>
<input type="text" id="productiveInput" placeholder="Add a productive site URL">
<button id="addProductive">Add</button>
<ul id="productiveList"></ul>
</div>

<div>
<h2>Distracting Sites</h2>
<input type="text" id="distractingInput" placeholder="Add a distracting site URL">
<button id="addDistracting">Add</button>
<ul id="distractingList"></ul>
</div>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding form elements for better user interaction.

Wrap the input sections in <form> elements to enable submit-on-enter functionality and proper form handling.

Apply these changes:

-  <div>
+  <form id="productiveForm">
     <h2>Productive Sites</h2>
     <!-- ... input and button ... -->
     <ul id="productiveList"></ul>
-  </div>
+  </form>

-  <div>
+  <form id="distractingForm">
     <h2>Distracting Sites</h2>
     <!-- ... input and button ... -->
     <ul id="distractingList"></ul>
-  </div>
+  </form>

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +40 to +48
function removeSite(type, index) {
chrome.storage.sync.get([type], (result) => {
const sites = result[type] || [];
sites.splice(index, 1);
chrome.storage.sync.set({ [type]: sites }, () => {
updateSiteList(type, type === 'productiveSites' ? 'productiveList' : 'distractingList');
});
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve error handling and use constants for list IDs.

The removeSite function needs improvements:

  1. Add error handling.
  2. Use constants for list IDs.
  3. Validate index before removal.

Here's the suggested implementation:

+const LIST_IDS = {
+    productiveSites: 'productiveList',
+    distractingSites: 'distractingList'
+};
+
 function removeSite(type, index) {
+    if (!['productiveSites', 'distractingSites'].includes(type)) {
+        console.error('Invalid site type:', type);
+        return;
+    }
     chrome.storage.sync.get([type], (result) => {
+        if (chrome.runtime.lastError) {
+            console.error('Storage error:', chrome.runtime.lastError);
+            return;
+        }
         const sites = result[type] || [];
+        if (index < 0 || index >= sites.length) {
+            console.error('Invalid index:', index);
+            return;
+        }
         sites.splice(index, 1);
         chrome.storage.sync.set({ [type]: sites }, () => {
-            updateSiteList(type, type === 'productiveSites' ? 'productiveList' : 'distractingList');
+            if (chrome.runtime.lastError) {
+                console.error('Storage error:', chrome.runtime.lastError);
+                return;
+            }
+            updateSiteList(type, LIST_IDS[type]);
         });
     });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function removeSite(type, index) {
chrome.storage.sync.get([type], (result) => {
const sites = result[type] || [];
sites.splice(index, 1);
chrome.storage.sync.set({ [type]: sites }, () => {
updateSiteList(type, type === 'productiveSites' ? 'productiveList' : 'distractingList');
});
});
}
const LIST_IDS = {
productiveSites: 'productiveList',
distractingSites: 'distractingList'
};
function removeSite(type, index) {
if (!['productiveSites', 'distractingSites'].includes(type)) {
console.error('Invalid site type:', type);
return;
}
chrome.storage.sync.get([type], (result) => {
if (chrome.runtime.lastError) {
console.error('Storage error:', chrome.runtime.lastError);
return;
}
const sites = result[type] || [];
if (index < 0 || index >= sites.length) {
console.error('Invalid index:', index);
return;
}
sites.splice(index, 1);
chrome.storage.sync.set({ [type]: sites }, () => {
if (chrome.runtime.lastError) {
console.error('Storage error:', chrome.runtime.lastError);
return;
}
updateSiteList(type, LIST_IDS[type]);
});
});
}

Comment on lines +24 to +37
function addSite(type, inputId, listId) {
const inputElement = document.getElementById(inputId);
const site = inputElement.value.trim();
if (site) {
chrome.storage.sync.get([type], (result) => {
const sites = result[type] || [];
sites.push(site);
chrome.storage.sync.set({ [type]: sites }, () => {
updateSiteList(type, listId);
inputElement.value = '';
});
});
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Enhance input validation and add duplicate checking.

The addSite function needs improvements:

  1. Validate URLs before adding.
  2. Prevent duplicate entries.
  3. Add a reasonable limit to the number of sites.
  4. Include error handling.

Here's the suggested implementation:

 function addSite(type, inputId, listId) {
     const inputElement = document.getElementById(inputId);
     const site = inputElement.value.trim();
-    if (site) {
+    try {
+        // Validate URL format
+        new URL(site);
+    } catch (e) {
+        alert('Please enter a valid URL');
+        return;
+    }
+
+    if (site) {
         chrome.storage.sync.get([type], (result) => {
+            if (chrome.runtime.lastError) {
+                console.error('Storage error:', chrome.runtime.lastError);
+                return;
+            }
             const sites = result[type] || [];
+            
+            // Check for duplicates
+            if (sites.includes(site)) {
+                alert('This site is already in the list');
+                return;
+            }
+            
+            // Limit number of sites
+            if (sites.length >= 50) {
+                alert('Maximum number of sites reached');
+                return;
+            }
             sites.push(site);
             chrome.storage.sync.set({ [type]: sites }, () => {
+                if (chrome.runtime.lastError) {
+                    console.error('Storage error:', chrome.runtime.lastError);
+                    return;
+                }
                 updateSiteList(type, listId);
                 inputElement.value = '';
             });
         });
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function addSite(type, inputId, listId) {
const inputElement = document.getElementById(inputId);
const site = inputElement.value.trim();
if (site) {
chrome.storage.sync.get([type], (result) => {
const sites = result[type] || [];
sites.push(site);
chrome.storage.sync.set({ [type]: sites }, () => {
updateSiteList(type, listId);
inputElement.value = '';
});
});
}
}
function addSite(type, inputId, listId) {
const inputElement = document.getElementById(inputId);
const site = inputElement.value.trim();
try {
// Validate URL format
new URL(site);
} catch (e) {
alert('Please enter a valid URL');
return;
}
if (site) {
chrome.storage.sync.get([type], (result) => {
if (chrome.runtime.lastError) {
console.error('Storage error:', chrome.runtime.lastError);
return;
}
const sites = result[type] || [];
// Check for duplicates
if (sites.includes(site)) {
alert('This site is already in the list');
return;
}
// Limit number of sites
if (sites.length >= 50) {
alert('Maximum number of sites reached');
return;
}
sites.push(site);
chrome.storage.sync.set({ [type]: sites }, () => {
if (chrome.runtime.lastError) {
console.error('Storage error:', chrome.runtime.lastError);
return;
}
updateSiteList(type, listId);
inputElement.value = '';
});
});
}
}

Comment on lines +1 to +46
function createOverlay() {
// Check if the overlay already exists
if (document.getElementById("productive-overlay")) return;

// Create the overlay div
const overlay = document.createElement("div");
overlay.id = "productive-overlay";
overlay.style.position = "fixed";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.width = "100%";
overlay.style.height = "100%";
overlay.style.backgroundColor = "rgba(0, 0, 0, 0.8)";
overlay.style.zIndex = "10000";
overlay.style.display = "flex";
overlay.style.justifyContent = "center";
overlay.style.alignItems = "center";
overlay.style.color = "white";
overlay.style.fontSize = "24px";
overlay.style.textAlign = "center";

// Message content
overlay.innerHTML = `
<div>
<p>You are on a productive site! Take a break?</p>
<button id="close-overlay" style="
margin-top: 20px;
padding: 10px 20px;
font-size: 18px;
background-color: #176B87;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
">Close</button>
</div>
`;

// Append overlay to body
document.body.appendChild(overlay);

// Close overlay button functionality
document.getElementById("close-overlay").addEventListener("click", () => {
overlay.remove();
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor overlay implementation for better maintainability and extensibility.

The overlay implementation has several areas for improvement:

  1. Move styles to a separate CSS file
  2. Externalize text for internationalization
  3. Clean up event listeners properly

Consider refactoring the code as follows:

+const OVERLAY_TEXT = chrome.i18n.getMessage('overlayText') || 'You are on a productive site! Take a break?';
+const CLOSE_BUTTON_TEXT = chrome.i18n.getMessage('closeButton') || 'Close';

 function createOverlay() {
     if (document.getElementById("productive-overlay")) return;
 
     const overlay = document.createElement("div");
     overlay.id = "productive-overlay";
-    overlay.style.position = "fixed";
-    // ... remove all inline styles
+    overlay.classList.add('productive-overlay');
     
     overlay.innerHTML = `
       <div>
-        <p>You are on a productive site! Take a break?</p>
-        <button id="close-overlay" style="...">Close</button>
+        <p>${OVERLAY_TEXT}</p>
+        <button id="close-overlay" class="overlay-button">${CLOSE_BUTTON_TEXT}</button>
       </div>
     `;
 
     document.body.appendChild(overlay);
 
-    document.getElementById("close-overlay").addEventListener("click", () => {
+    const closeButton = document.getElementById("close-overlay");
+    const handleClose = () => {
+      closeButton.removeEventListener("click", handleClose);
       overlay.remove();
-    });
+    };
+    closeButton.addEventListener("click", handleClose);
 }

Add a new CSS file:

.productive-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.8);
  z-index: var(--overlay-z-index, 10000);
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
  font-size: 24px;
  text-align: center;
}

.overlay-button {
  margin-top: 20px;
  padding: 10px 20px;
  font-size: 18px;
  background-color: var(--button-bg-color, #176B87);
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

Comment on lines +68 to +69
// Run the function when the page loads
window.addEventListener('load', checkSiteType);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve event handling for URL checks.

The current implementation might miss URL changes in single-page applications (SPAs) and could potentially run multiple times.

Consider using the following approach:

-window.addEventListener('load', checkSiteType);
+// Check on initial load
+checkSiteType();
+
+// Listen for URL changes (for SPAs)
+const observer = new MutationObserver(() => {
+  if (document.location.href !== lastUrl) {
+    lastUrl = document.location.href;
+    checkSiteType();
+  }
+});
+
+let lastUrl = document.location.href;
+observer.observe(document, { subtree: true, childList: true });
+
+// Cleanup when the content script is unloaded
+window.addEventListener('unload', () => {
+  observer.disconnect();
+});

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +48 to +66
function checkSiteType() {
const currentUrl = window.location.href;

// Retrieve the site lists from storage
chrome.storage.sync.get(['productiveSites', 'distractingSites'], (data) => {
const productiveSites = data.productiveSites || [];
const distractingSites = data.distractingSites || [];

// Check if the current URL matches any productive site
if (productiveSites.some(site => currentUrl.includes(site))) {
createOverlay(); // Display the overlay for productive sites
}

// Check if the current URL matches any distracting site
if (distractingSites.some(site => currentUrl.includes(site))) {
alert("You are on a distracting site!");
}
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve URL matching and error handling in site type checking.

The current implementation has several potential issues:

  1. Simple string inclusion for URL matching could lead to false positives
  2. Missing error handling for storage access
  3. Alert dialogs can be intrusive

Consider implementing these improvements:

 function checkSiteType() {
     const currentUrl = window.location.href;
+    const urlObj = new URL(currentUrl);
+    const domain = urlObj.hostname;
 
     // Retrieve the site lists from storage
     chrome.storage.sync.get(['productiveSites', 'distractingSites'], (data) => {
+      if (chrome.runtime.lastError) {
+        console.error('Error accessing storage:', chrome.runtime.lastError);
+        return;
+      }
+
       const productiveSites = data.productiveSites || [];
       const distractingSites = data.distractingSites || [];
 
       // Check if the current URL matches any productive site
-      if (productiveSites.some(site => currentUrl.includes(site))) {
+      if (productiveSites.some(site => domain.endsWith(site))) {
         createOverlay();
       }
 
       // Check if the current URL matches any distracting site
-      if (distractingSites.some(site => currentUrl.includes(site))) {
-        alert("You are on a distracting site!");
+      if (distractingSites.some(site => domain.endsWith(site))) {
+        // Use a less intrusive notification method
+        chrome.runtime.sendMessage({
+          type: 'showNotification',
+          message: 'You are on a distracting site!'
+        });
       }
     });
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function checkSiteType() {
const currentUrl = window.location.href;
// Retrieve the site lists from storage
chrome.storage.sync.get(['productiveSites', 'distractingSites'], (data) => {
const productiveSites = data.productiveSites || [];
const distractingSites = data.distractingSites || [];
// Check if the current URL matches any productive site
if (productiveSites.some(site => currentUrl.includes(site))) {
createOverlay(); // Display the overlay for productive sites
}
// Check if the current URL matches any distracting site
if (distractingSites.some(site => currentUrl.includes(site))) {
alert("You are on a distracting site!");
}
});
}
function checkSiteType() {
const currentUrl = window.location.href;
const urlObj = new URL(currentUrl);
const domain = urlObj.hostname;
// Retrieve the site lists from storage
chrome.storage.sync.get(['productiveSites', 'distractingSites'], (data) => {
if (chrome.runtime.lastError) {
console.error('Error accessing storage:', chrome.runtime.lastError);
return;
}
const productiveSites = data.productiveSites || [];
const distractingSites = data.distractingSites || [];
// Check if the current URL matches any productive site
if (productiveSites.some(site => domain.endsWith(site))) {
createOverlay();
}
// Check if the current URL matches any distracting site
if (distractingSites.some(site => domain.endsWith(site))) {
// Use a less intrusive notification method
chrome.runtime.sendMessage({
type: 'showNotification',
message: 'You are on a distracting site!'
});
}
});
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (3)
pinne-cheyyam/popup/popup.html (3)

14-14: Add width and height attributes to the img tag.

While you've set the dimensions via CSS classes, explicitly setting width and height attributes helps prevent layout shifts during image loading.

-      <img src="../icons/icon.png" alt="Pinne-Cheyyam Logo" class="w-16 h-16 mb-2">
+      <img src="../icons/icon.png" alt="Pinne-Cheyyam Logo" width="64" height="64" class="w-16 h-16 mb-2">

20-22: Add aria-label attributes to buttons for better accessibility.

While the button text is descriptive, adding aria-labels can provide additional context for screen readers.

-      <button id="start" class="bg-yellow-500 hover:bg-yellow-600 text-white font-bold py-2 px-4 rounded-full mb-4 transition duration-300 ease-in-out shadow-md">
+      <button id="start" aria-label="Start annoying mode" class="bg-yellow-500 hover:bg-yellow-600 text-white font-bold py-2 px-4 rounded-full mb-4 transition duration-300 ease-in-out shadow-md">
         Start Annoying
       </button>
-      <button id="openOptions" class="bg-transparent border border-yellow-500 hover:bg-yellow-500 hover:text-white text-yellow-500 font-bold py-2 px-4 rounded-full transition duration-300 ease-in-out shadow-md">
+      <button id="openOptions" aria-label="Open extension settings" class="bg-transparent border border-yellow-500 hover:bg-yellow-500 hover:text-white text-yellow-500 font-bold py-2 px-4 rounded-full transition duration-300 ease-in-out shadow-md">
         Settings
       </button>

Also applies to: 24-26


1-32: Consider adding meta viewport tag for better mobile compatibility.

While this is a browser extension popup, adding viewport meta tag ensures proper rendering on different screen sizes.

Add this line in the head section:

   <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Pinne-Cheyyam</title>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 0e4c590 and 1b099b8.

⛔ Files ignored due to path filters (1)
  • pinne-cheyyam/icons/icon.png is excluded by !**/*.png
📒 Files selected for processing (1)
  • pinne-cheyyam/popup/popup.html (1 hunks)
🔇 Additional comments (2)
pinne-cheyyam/popup/popup.html (2)

11-12: LGTM! Nice use of Tailwind's backdrop filters.

The gradient background with backdrop blur creates a modern, frosted glass effect. The responsive flex layout ensures proper centering.


29-29: Verify the popup.js file location and add error handling.

Ensure that popup.js exists and consider adding error handling for script loading.

Comment on lines +7 to +8
<!-- Link to your local Tailwind CSS file -->
<script src="../tailwind.js"></script>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consider using a CDN or proper build process for Tailwind CSS.

Loading Tailwind directly via a script tag is not recommended for production. Consider using either:

  • A CDN link for development
  • A proper build process to generate optimized CSS
-  <!-- Link to your local Tailwind CSS file -->
-  <script src="../tailwind.js"></script>
+  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">

Committable suggestion skipped: line range outside the PR's diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants