diff options
| author | Sameera Sandakelum <[email protected]> | 2025-02-26 01:44:25 +0530 | 
|---|---|---|
| committer | GitHub <[email protected]> | 2025-02-26 01:44:25 +0530 | 
| commit | 971d8df95bb340959aa43adb695c072fc6ea12d0 (patch) | |
| tree | 9f61c18a3b4e6b84583cdeec6562fb31ee7acf78 | |
| parent | 2e79ce31b430b256fcdda0dd55a7ef1fdca5426a (diff) | |
| parent | fae990164e7bf69f19af4c283ab00d9c17768aec (diff) | |
Merge pull request #1 from YelehaUwU/master
New design and current site indicator.
Thanks for the contribution <3
| -rw-r--r-- | popup/popup.css | 390 | ||||
| -rw-r--r-- | popup/popup.html | 58 | ||||
| -rw-r--r-- | popup/popup.js | 242 | 
3 files changed, 594 insertions, 96 deletions
diff --git a/popup/popup.css b/popup/popup.css index 174470e..80d3ec1 100644 --- a/popup/popup.css +++ b/popup/popup.css @@ -1,53 +1,349 @@  @import url("../shared/variables.css");
 +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
 +
 +:root {
 +  --radius-sm: 6px;
 +  --radius-md: 8px;
 +  --radius-lg: 12px;
 +  --transition: all 0.2s ease;
 +  --shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
 +  --accent-color: #f98764; /* Subtle Zen-themed orange */
 +  --hover-color: #fa9475;  /* Lighter hover state */
 +  --success-color: #40c057;
 +  --warning-color: #fab005;
 +  --danger-color: #fa5252;
 +  --bg-color: #1e1e2e;
 +  --secondary-bg: #2a2a3c;
 +  --border-color: #4c4c63;
 +  --text-primary: #e2e8f0;
 +  --text-secondary: #a0a0b8;
 +}
  body {
 -  width: 350px;
 +  width: 360px;
 +  margin: 0;
 +  padding: 0;
 +  font-family: 'Inter', Arial, sans-serif;
 +  color: var(--text-primary);
 +  background-color: var(--bg-color);
 +  font-size: 14px;
 +  line-height: 1.5;
 +}
 +
 +.container {
 +  display: flex;
 +  flex-direction: column;
 +  height: 100%;
 +}
 +
 +/* Header Styles */
 +.app-header {
 +  background: linear-gradient(135deg, #2c3e50, #1a2530);
 +  color: white;
 +  padding: 16px 20px;
 +  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
 +  box-shadow: var(--shadow);
 +}
 +
 +.logo-container {
 +  display: flex;
 +  align-items: center;
 +  gap: 8px;
 +}
 +
 +.logo-img {
 +  width: 32px;
 +  height: 32px;
 +  object-fit: contain;
 +}
 +
 +.app-title {
 +  margin: 0;
 +  font-size: 20px;
 +  font-weight: 600;
 +  letter-spacing: -0.5px;
 +}
 +
 +.author {
 +  font-size: 12px;
 +  margin-top: 4px;
 +  opacity: 0.9;
 +}
 +
 +.author a {
 +  color: white;
 +  text-decoration: none;
 +  font-weight: 500;
 +}
 +
 +.author a:hover {
 +  text-decoration: underline;
 +}
 +
 +/* Main Content Styles */
 +.app-content {
 +  padding: 20px;
 +  display: flex;
 +  flex-direction: column;
 +  gap: 20px;
 +}
 +
 +/* Toggle Switch */
 +.toggle-container {
 +  display: flex;
 +  align-items: center;
 +  gap: 12px;
 +  margin-bottom: 8px;
 +}
 +
 +/* Current site toggle styling */
 +.current-site-container {
 +  background-color: var(--secondary-bg);
 +  padding: 12px;
 +  border-radius: var(--radius-md);
 +  margin-top: -12px;
 +  position: relative;
 +  animation: fadeIn 0.3s ease-in-out;
 +}
 +
 +@keyframes fadeIn {
 +  from { opacity: 0; transform: translateY(-5px); }
 +  to { opacity: 1; transform: translateY(0); }
 +}
 +
 +.toggle-switch {
 +  position: relative;
 +  display: inline-block;
 +  width: 46px;
 +  height: 24px;
 +}
 +
 +.toggle-switch input {
 +  opacity: 0;
 +  width: 0;
 +  height: 0;
 +}
 +
 +.slider {
 +  position: absolute;
 +  cursor: pointer;
 +  top: 0;
 +  left: 0;
 +  right: 0;
 +  bottom: 0;
 +  background-color: #4c4c63;
 +  transition: var(--transition);
 +  border-radius: 34px;
 +}
 +
 +.slider:before {
 +  position: absolute;
 +  content: "";
 +  height: 18px;
 +  width: 18px;
 +  left: 3px;
 +  bottom: 3px;
 +  background-color: white;
 +  transition: var(--transition);
 +  border-radius: 50%;
 +}
 +
 +input:checked + .slider {
 +  background-color: var(--accent-color);
 +}
 +
 +input:focus + .slider {
 +  box-shadow: 0 0 1px var(--accent-color);
 +}
 +
 +input:checked + .slider:before {
 +  transform: translateX(22px);
 +}
 +
 +.toggle-label {
 +  font-weight: 500;
 +}
 +
 +/* Websites List */
 +.section-title {
 +  font-size: 16px;
 +  font-weight: 600;
 +  margin: 0 0 12px 0;
 +  color: var(--text-primary);
 +}
 +
 +.websites-container {
 +  background-color: var(--secondary-bg);
 +  border-radius: var(--radius-md);
 +  padding: 16px;
 +}
 +
 +.websites-list {
 +  list-style: none;
    padding: 0;
    margin: 0;
 -  background-color: var(--transparent-background-darker);
 -  font-family: Arial, Helvetica, sans-serif;
 -  color: var(--color-text);
 -
 -  .container {
 -    display: flex;
 -    flex-direction: column;
 -    gap: 12px;
 -
 -    #extension-header {
 -      background-color: var(--color-bg);
 -      padding: 16px;
 -
 -      .headline {
 -        margin: 0;
 -      }
 -    }
 -
 -    #extension-body {
 -      padding: 16px;
 -
 -      display: flex;
 -      flex-direction: column;
 -      gap: 16px;
 -
 -      #extension-settings {
 -        .setting {
 -          display: flex;
 -          align-items: center;
 -          gap: 8px;
 -        }
 -      }
 -
 -      #extension-description {
 -        a {
 -          color: var(--color-primary);
 -          font-weight: bold;
 -          text-decoration: none;
 -
 -          &:hover {
 -            text-decoration: underline;
 -          }
 -        }
 -      }
 -    }
 -  }
 +  max-height: 150px;
 +  overflow-y: auto;
 +  border: 1px solid var(--border-color);
 +  border-radius: var(--radius-sm);
 +  background-color: var(--bg-color);
 +  
 +  /* Firefox scrollbar styling */
 +  scrollbar-width: thin;
 +  scrollbar-color: var(--accent-color) transparent;
 +}
 +
 +.websites-list li {
 +  padding: 10px 12px;
 +  border-bottom: 1px solid var(--border-color);
 +  display: flex;
 +  align-items: center;
 +  gap: 8px;
 +  color: var(--text-primary);
 +}
 +
 +.websites-list li:last-child {
 +  border-bottom: none;
 +}
 +
 +.websites-list li:before {
 +  content: "•";
 +  color: var(--accent-color);
 +  font-weight: bold;
 +  opacity: 0.9;
 +}
 +
 +/* Action Buttons */
 +.actions {
 +  display: flex;
 +  flex-direction: column;
 +  gap: 10px;
 +}
 +
 +.action-button {
 +  display: flex;
 +  align-items: center;
 +  justify-content: center;
 +  gap: 8px;
 +  padding: 10px 16px;
 +  border: none;
 +  border-radius: var(--radius-md);
 +  font-weight: 500;
 +  cursor: pointer;
 +  transition: var(--transition);
 +  outline: none;
 +}
 +
 +.action-button i {
 +  font-size: 14px;
 +}
 +
 +.action-button.primary {
 +  background-color: var(--accent-color);
 +  color: white;
 +  border: none;
 +}
 +
 +.action-button.primary:hover {
 +  background-color: var(--hover-color);
 +  box-shadow: 0 0 8px rgba(243, 156, 18, 0.5);
 +}
 +
 +.action-button.secondary {
 +  background-color: transparent;
 +  border: 1px solid var(--border-color);
 +  color: var(--text-secondary);
 +}
 +
 +.action-button.secondary:hover {
 +  background-color: rgba(255, 255, 255, 0.1);
  }
 +
 +/* Footer */
 +.app-footer {
 +  margin-top: auto;
 +  padding: 14px 20px;
 +  background-color: var(--secondary-bg);
 +  border-top: 1px solid var(--border-color);
 +  display: flex;
 +  align-items: center;
 +  justify-content: space-between;
 +}
 +
 +.footer-link {
 +  display: flex;
 +  align-items: center;
 +  gap: 6px;
 +  color: var(--text-secondary);
 +  text-decoration: none;
 +  font-size: 12px;
 +  font-weight: 500;
 +  transition: var(--transition);
 +}
 +
 +.footer-link:hover {
 +  color: var(--accent-color);
 +  opacity: 0.9;
 +}
 +
 +.footer-divider {
 +  height: 16px;
 +  width: 1px;
 +  background-color: var(--border-color);
 +}
 +
 +/* Current site highlighting */
 +.current-site {
 +  background-color: rgba(229, 152, 102, 0.1); /* Subtle orange background */
 +  border-left: 3px solid var(--accent-color); /* Orange accent bar */
 +  padding-left: 9px !important; /* Compensate for the border */
 +}
 +
 +.current-badge {
 +  display: inline-block;
 +  background-color: var(--accent-color);
 +  color: white;
 +  font-size: 10px;
 +  font-weight: 600;
 +  padding: 2px 6px;
 +  border-radius: 10px;
 +  margin-left: 6px;
 +  vertical-align: middle;
 +  text-transform: uppercase;
 +  letter-spacing: 0.5px;
 +}
 +
 +/* Ensure checkbox and label spacing */
 +.websites-list li label {
 +  display: flex;
 +  align-items: center;
 +  width: 100%;
 +}
 +
 +.websites-list li label input[type="checkbox"] {
 +  margin-right: 8px;
 +  flex-shrink: 0;
 +}
 +
 +/* Add a slight animation to the current site */
 +.current-site {
 +  animation: fadeIn 0.3s ease-in-out;
 +}
 +
 +@keyframes fadeIn {
 +  from { opacity: 0.7; }
 +  to { opacity: 1; }
 +}
 +
 +/* Make sure the text doesn't overflow */
 +.websites-list li label {
 +  overflow: hidden;
 +  text-overflow: ellipsis;
 +  white-space: nowrap;
 +}
 +
 +/* Push the badge to the right */
 +.current-badge {
 +  margin-left: auto;
 +  margin-right: 4px;
 +}
\ No newline at end of file diff --git a/popup/popup.html b/popup/popup.html index 7050511..8ccdbd4 100644 --- a/popup/popup.html +++ b/popup/popup.html @@ -1,29 +1,53 @@  <!DOCTYPE html> -<html> +<html lang="en">  <head>    <meta charset="UTF-8"> +  <meta name="viewport" content="width=device-width, initial-scale=1.0">    <link rel="stylesheet" href="popup.css"> +  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">  </head>  <body>    <div class="container"> -    <div id="extension-header"> -      <h1 class="headline">ZenInternet by @sameerasw</h1> -    </div> -    <div id="extension-body"> -      <label class="setting"> -        <input type="checkbox" id="enable-styling"> -        Enable Styling -      </label> -      <ul id="websites-list"></ul> -      <button id="refetch-css">Refetch latest styles</button> -      <button id="restart-background">Restart Background Script (optional)</button> -      <a href="https://sameerasw.github.io/my-internet/">Styles repo</a> -      <p>About: -        <a href="https://www.sameerasw.com/">sameerasw.com</a> -      </p> -    </div> +    <header class="app-header"> +      <div class="logo-container"> +        <img src="../assets/images/logo_48.png" alt="ZenInternet Logo" class="logo-img"> +        <h1 class="app-title">ZenInternet</h1> +      </div> +      <div class="author">by <a href="https://www.sameerasw.com/" target="_blank">@sameerasw</a></div> +    </header> + +    <main class="app-content"> +      <div class="toggle-container"> +        <label class="toggle-switch"> +          <input type="checkbox" id="enable-styling"> +          <span class="slider round"></span> +        </label> +        <span class="toggle-label">Enable Styling</span> +      </div> + +      <div class="websites-container"> +        <h2 class="section-title">Available Websites</h2> +        <ul id="websites-list" class="websites-list"></ul> +      </div> + +      <div class="actions"> +        <button id="refetch-css" class="action-button primary"> +          <i class="fas fa-sync-alt"></i> Refetch latest styles +        </button> +      </div> +    </main> + +    <footer class="app-footer"> +      <a href="https://sameerasw.github.io/my-internet/" class="footer-link" target="_blank"> +        <i class="fas fa-book"></i> Styles Repository +      </a> +      <div class="footer-divider"></div> +      <a href="https://github.com/sameerasw/zeninternet/" class="footer-link" target="_blank"> +        <i class="fa-brands fa-github"></i> Github Repository +      </a> +    </footer>    </div>    <script src="popup.js"></script>  </body> diff --git a/popup/popup.js b/popup/popup.js index f743179..dc4b203 100644 --- a/popup/popup.js +++ b/popup/popup.js @@ -1,33 +1,54 @@ -new (class ExtensionPopup { +new(class ExtensionPopup {    BROWSER_STORAGE_KEY = "transparentZenSettings";    browserStorageSettings = {};    enableStylingSwitch = document.getElementById("enable-styling");    refetchCSSButton = document.getElementById("refetch-css");    websitesList = document.getElementById("websites-list"); - +  currentSiteHostname = ""; +      constructor() {      this.loadSettings().then((settings) => {        if (settings) {          this.browserStorageSettings = settings; -        this.restoreSettings(); -        this.bindEvents(); +        this.getCurrentTabInfo().then(() => { +          this.restoreSettings(); +          this.bindEvents(); +        });        }      });      this.refetchCSSButton.addEventListener("click", this.refetchCSS.bind(this)); -    document -      .getElementById("restart-background") -      .addEventListener("click", this.restartBackground); -  } +    this.setupContentScriptInjection(); +  } +   +  async getCurrentTabInfo() { +    try { +      const tabs = await browser.tabs.query({ active: true, currentWindow: true }); +      if (tabs.length > 0) { +        const url = new URL(tabs[0].url); +        this.currentSiteHostname = url.hostname; +        console.info("Current site hostname:", this.currentSiteHostname); +      } +    } catch (error) { +      console.error("Error getting current tab info:", error); +    } +  } +      bindEvents() {      this.enableStylingSwitch.addEventListener("change", () => {        this.saveSettings(); +      this.updateActiveTabStyling();      }); -    this.websitesList.addEventListener("change", () => { +     +    this.websitesList.addEventListener("change", (event) => {        this.saveSettings(); +      // Update styling immediately when a checkbox changes +      if (event.target.type === 'checkbox') { +        this.updateActiveTabStyling(); +      }      });    } - +      restoreSettings() {      if (this.browserStorageSettings.enableStyling !== undefined) {        this.enableStylingSwitch.checked = @@ -35,58 +56,112 @@ new (class ExtensionPopup {      }      this.loadWebsitesList();    } - +      async loadSettings() {      const settings = await browser.storage.local.get(this.BROWSER_STORAGE_KEY);      console.info("Settings loaded", settings?.[this.BROWSER_STORAGE_KEY]);      return settings?.[this.BROWSER_STORAGE_KEY] || {};    } - +      saveSettings() {      this.browserStorageSettings.enableStyling =        this.enableStylingSwitch.checked; - +          const websiteSettings = {};      this.websitesList        .querySelectorAll("input[type=checkbox]")        .forEach((checkbox) => {          websiteSettings[checkbox.name] = checkbox.checked;        }); +          this.browserStorageSettings.websiteSettings = websiteSettings; - +          browser.storage.local.set({        [this.BROWSER_STORAGE_KEY]: this.browserStorageSettings,      }); +          console.info("Settings saved", this.browserStorageSettings);    } - +      async loadWebsitesList() {      try { -      const response = await fetch("/mapper.json", { -        headers: { -          "Cache-Control": "no-cache", -        }, -      }); -      if (!response.ok) throw new Error("Failed to fetch mapper.json"); -      const mapping = await response.json(); +      // Get the styles from storage that were fetched using refetchCSS +      const stylesData = await browser.storage.local.get("styles"); +      const styles = stylesData.styles || {}; +              this.websitesList.innerHTML = ""; -      for (const site of Object.keys(mapping)) { +       +      // Use the keys from styles object +      const websites = Object.keys(styles); +       +      if (websites.length === 0) { +        const listItem = document.createElement("li"); +        listItem.textContent = "No styles available. Click 'Refetch latest styles' to update."; +        this.websitesList.appendChild(listItem); +        return; +      } +       +      // Create array to hold all website items +      const websiteItems = []; +      let currentSiteItem = null; +       +      for (const site of websites) { +        // Remove the .css extension if present +        const displayName = site.replace(/\.css$/, ""); +                  const isChecked = -          this.browserStorageSettings.websiteSettings?.[site] ?? true; +          this.browserStorageSettings.websiteSettings?.[displayName] ?? true; +                  const listItem = document.createElement("li"); +         +        // Check if this site matches the current site +        const isCurrent = this.isCurrentSite(displayName); +        if (isCurrent) { +          listItem.classList.add("current-site"); +          currentSiteItem = listItem; // Store the current site item separately +        } +                  listItem.innerHTML = `            <label> -            <input type="checkbox" name="${site}" ${isChecked ? "checked" : ""}> -            ${site} +            <input type="checkbox" name="${displayName}" ${isChecked ? "checked" : ""}> +            ${displayName} +            ${isCurrent ? '<span class="current-badge">Current</span>' : ''}            </label>          `; -        this.websitesList.appendChild(listItem); +         +        // Add to array if not current site +        if (!isCurrent) { +          websiteItems.push(listItem); +        }        } +       +      // Add current site at the top if it exists +      if (currentSiteItem) { +        this.websitesList.appendChild(currentSiteItem); +      } +       +      // Add all other sites +      websiteItems.forEach(item => { +        this.websitesList.appendChild(item); +      });      } catch (error) {        console.error("Error loading websites list:", error); +      this.websitesList.innerHTML = "<li>Error loading websites list. Please try refetching styles.</li>";      }    } +   +  isCurrentSite(siteName) { +    if (!this.currentSiteHostname) return false; +     +    // Direct match +    if (this.currentSiteHostname === siteName) return true; +    if (this.currentSiteHostname.startsWith("www.")) { +      const nonWww = this.currentSiteHostname.replace("www.", ""); +      if (nonWww === siteName) return true; +    } +  } +      async refetchCSS() {      this.refetchCSSButton.textContent = "Fetching...";      try { @@ -101,6 +176,13 @@ new (class ExtensionPopup {        if (!response.ok) throw new Error("Failed to fetch styles.json");        const styles = await response.json();        await browser.storage.local.set({ styles }); +       +      // Reload the websites list after fetching new styles +      this.loadWebsitesList(); +       +      // Update styling on the active tab +      this.updateActiveTabStyling(); +              this.refetchCSSButton.textContent = "Done!";        setTimeout(() => {          this.refetchCSSButton.textContent = "Refetch latest styles"; @@ -114,9 +196,105 @@ new (class ExtensionPopup {        console.error("Error refetching styles:", error);      }    } - -  async restartBackground() { -    browser.runtime.reload(); -    console.info("Background script restart requested."); +   +  setupContentScriptInjection() { +    // Listen for tab updates to apply CSS when needed +    browser.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => { +      if (changeInfo.status === 'complete') { +        this.applyCSSToTab(tab); +      } +    }); +     +    // Also handle tabs that are already open when the extension starts +    this.updateAllTabs(); +  } +   +  async updateAllTabs() { +    const tabs = await browser.tabs.query({}); +    for (const tab of tabs) { +      this.applyCSSToTab(tab); +    } +  } +   +  async updateActiveTabStyling() { +    const tabs = await browser.tabs.query({ active: true, currentWindow: true }); +    if (tabs.length > 0) { +      this.applyCSSToTab(tabs[0]); +    } +  } +   +  async applyCSSToTab(tab) { +    const url = new URL(tab.url); +    const hostname = url.hostname; +     +    // First remove any existing CSS +    try { +      await browser.tabs.removeCSS(tab.id, {  +        code: "/* Placeholder for removing CSS */"  +      }); +    } catch (error) { +      // Ignore errors as the tab might not have any CSS injected +    } +     +    // Check if we should apply CSS to this site +    if (!this.shouldApplyCSS(hostname)) { +      return; +    } +     +    try { +      // Get the styles from storage +      const stylesData = await browser.storage.local.get("styles"); +      const styles = stylesData.styles || {}; +       +      // Find matching CSS for this hostname +      let cssToApply = null; +       +      // Check for direct match (with .css extension) +      if (styles[hostname + '.css']) { +        cssToApply = styles[hostname + '.css']; +      }  +      // Check for domain matches (e.g. youtube.com matches m.youtube.com) +      else { +        for (const site of Object.keys(styles)) { +          const siteName = site.replace(/\.css$/, ""); +          if (hostname.includes(siteName)) { +            cssToApply = styles[site]; +            break; +          } +        } +      } +       +      if (cssToApply) { +        await browser.tabs.insertCSS(tab.id, { code: cssToApply }); +        console.info(`Applied CSS to ${hostname}`); +      } +    } catch (error) { +      console.error(`Error applying CSS to ${hostname}:`, error); +    } +  } +   +  shouldApplyCSS(hostname) { +    // Global enable/disable switch +    if (!this.browserStorageSettings.enableStyling) { +      return false; +    } +     +    // Check website-specific settings +    const websiteSettings = this.browserStorageSettings.websiteSettings || {}; +     +    // First check for exact hostname match +    if (websiteSettings[hostname] !== undefined) { +      return websiteSettings[hostname]; +    } +     +    // Then check for domain matches (e.g. youtube.com matches m.youtube.com) +    for (const site in websiteSettings) { +      if (hostname.includes(site)) { +        return websiteSettings[site]; +      } +    } +     +    // Default to enabled if no specific setting found +    return true;    } -})(); +})();
\ No newline at end of file  | 
