diff --git a/README.md b/README.md new file mode 100644 index 0000000..6ffa7d5 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Goose Highlighter + +Goose Highlighter is a browser extension that allows you to highlight custom words and phrases on any webpage. Organize your highlights into lists, customize their appearance, and toggle highlighting or theme modes with ease. + +## Features + +- **Multiple Highlight Lists:** Organize words into separate lists. +- **Custom Colors:** Set background and foreground for each list and individual word. +- **Bulk Add:** Paste multiple words at once. +- **Enable/Disable:** Toggle highlighting globally, per list, or per word. +- **Import/Export:** Backup or share your highlight lists as JSON files. \ No newline at end of file diff --git a/_locales/en/messages.json b/_locales/en/messages.json index b329526..e3e09ad 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -82,5 +82,8 @@ }, "add_words": { "message": "Add Words" + }, + "global_highlight_toggle": { + "message": "Enable" } } \ No newline at end of file diff --git a/_locales/ru/messages.json b/_locales/ru/messages.json index 96c9923..01a77af 100644 --- a/_locales/ru/messages.json +++ b/_locales/ru/messages.json @@ -82,5 +82,8 @@ }, "add_words": { "message": "Добавить слова" + }, + "global_highlight_toggle": { + "message": "Вкл" } } \ No newline at end of file diff --git a/content.js b/content.js index 9a24830..1039571 100644 --- a/content.js +++ b/content.js @@ -1,4 +1,5 @@ let currentLists = []; +let isGlobalHighlightEnabled = true; function escapeRegex(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); @@ -19,9 +20,18 @@ function clearHighlights() { function processNodes() { observer.disconnect(); - clearHighlights(); + // If global highlighting is disabled, skip processing + if (!isGlobalHighlightEnabled) { + observer.observe(document.body, { + childList: true, + subtree: true, + characterData: true + }); + return; + } + const textNodes = []; const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, { acceptNode: node => { @@ -35,7 +45,6 @@ function processNodes() { while (walker.nextNode()) textNodes.push(walker.currentNode); const activeWords = []; - for (const list of currentLists) { if (!list.active) continue; for (const word of list.words) { @@ -92,8 +101,12 @@ function debounce(func, wait) { } // Initial highlight on load -chrome.storage.local.get("lists", ({ lists }) => { +chrome.storage.local.get(["lists", "globalHighlightEnabled"], ({ lists, globalHighlightEnabled }) => { if (Array.isArray(lists)) setListsAndUpdate(lists); + if (globalHighlightEnabled !== undefined) { + isGlobalHighlightEnabled = globalHighlightEnabled; + } + processNodes(); // Initial processing }); // Listen for updates from the popup and re-apply highlights @@ -102,6 +115,9 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { chrome.storage.local.get("lists", ({ lists }) => { if (Array.isArray(lists)) setListsAndUpdate(lists); }); + } else if (message.type === "GLOBAL_TOGGLE_UPDATED") { + isGlobalHighlightEnabled = message.enabled; + processNodes(); } }); @@ -112,4 +128,5 @@ observer.observe(document.body, { subtree: true, characterData: true }); -window.addEventListener('scroll', debouncedProcessNodes); \ No newline at end of file + +window.addEventListener('scroll', debouncedProcessNodes); diff --git a/popup/popup.css b/popup/popup.css index 8e5cf6a..6940e2d 100644 --- a/popup/popup.css +++ b/popup/popup.css @@ -6,7 +6,7 @@ --button-bg: #222; --button-hover: #444; --button-text: white; - --accent: #ffeb3b; + --accent: #ec9c23; --accent-text: #000; --highlight-tag: #292929; --highlight-tag-border: #444; @@ -16,7 +16,7 @@ --border-radius: 12px; --section-bg: #111; --switch-bg: #444; - --checkbox-accent: #ffeb3b; + --checkbox-accent: #ec9c23; --checkbox-border: #666; } @@ -298,4 +298,86 @@ input[type="file"] { font-weight: normal; margin-left: -8px; margin-right: -8px; +} + +.header-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 16px; + background: var(--bg-color); + border-radius: 12px; + color: var(--fg-color); + font-weight: bold; + font-size: 16px; + margin-bottom: 16px; +} + +.icon-toggles { + display: flex; + gap: 12px; +} + +.icon-toggle { + cursor: pointer; + font-size: 18px; + color: #ffa500; + display: flex; + align-items: center; + transition: color 0.2s; +} + +.icon-toggle:hover { + color: #ffd580; +} + +.hidden-toggle { + display: none; +} + +.icon-toggle { + cursor: pointer; + font-size: 18px; + color: #ffa500; + display: flex; + align-items: center; + transition: color 0.2s; +} + +.icon-toggle:hover { + color: #ffd580; +} + +/* GLOBAL HIGHLIGHT ICON: toggle-on/off */ +.global-icon::before { + content: "\f204"; + /* fa-toggle-off (default) */ +} + +#globalHighlightToggle:checked+.global-icon::before { + content: "\f205"; + /* fa-toggle-on */ +} + +/* THEME ICON: sun/moon */ +.theme-icon::before { + content: "\f185"; + /* fa-sun (light mode) */ +} + +#themeToggle:checked+.theme-icon::before { + content: "\f186"; + /* fa-moon (dark mode) */ +} + +/* Font Awesome fallback settings */ +.toggle-icon { + font-family: "Font Awesome 6 Free"; + font-weight: 900; +} + +label:has(input.switch) { + display: flex; + align-items: center; + gap: 8px; } \ No newline at end of file diff --git a/popup/popup.html b/popup/popup.html index 8ff2037..2132ba6 100644 --- a/popup/popup.html +++ b/popup/popup.html @@ -12,15 +12,26 @@