From 29e37cbf97bbe9c0645c3721a4eee8e156567105 Mon Sep 17 00:00:00 2001 From: imdj <69906094+imdj@users.noreply.github.com> Date: Thu, 1 Jun 2023 16:33:58 +0300 Subject: [PATCH] Add preferences support --- css/popup.css | 183 +++++++++++++++++++++++++++++++++++++++++++++++ manifest.v2.json | 12 +++- manifest.v3.json | 14 +++- popup.html | 56 +++++++++++++++ scripts/dom.js | 4 +- scripts/main.js | 31 +++++--- scripts/popup.js | 55 ++++++++++++++ 7 files changed, 342 insertions(+), 13 deletions(-) create mode 100644 css/popup.css create mode 100644 popup.html create mode 100644 scripts/popup.js diff --git a/css/popup.css b/css/popup.css new file mode 100644 index 0000000..aff4b30 --- /dev/null +++ b/css/popup.css @@ -0,0 +1,183 @@ +html, body { + font-family: system-ui, sans-serif; +} + +html { + max-height: 600px; + overflow-y: auto; +} +body { + width: 350px; + max-width: 100%; +} + +.relative { + position: relative; +} + +.flex { + display: flex; +} + +.h-full { + height: 100%; +} + +.w-full { + width: 100%; +} + +.flex-col { + flex-direction: column; +} + +.flex-row { + flex-direction: row; +} + +.justify-center { + justify-content: center; +} + +.justify-between { + justify-content: space-between; +} + +.items-baseline { + align-items: baseline; +} + +.items-center { + align-items: center; +} + +[class~="top-0.5"] { + top: 0.125rem; +} + +.ml-2 { + margin-left: 0.5rem; +} + +.ml-4 { + margin-left: 1rem; +} + +.ml-8 { + margin-left: 2rem; +} + +.mt-2 { + margin-top: 0.5rem; +} + +.mt-3 { + margin-top: 0.75rem; +} + +.mt-8 { + margin-top: 2rem; +} + +.mb-auto { + margin-bottom: auto; +} + +.mb-0 { + margin-bottom: 0; +} + +.mb-2 { + margin-bottom: 0.5rem; +} + +.mb-4 { + margin-bottom: 1rem; +} + +.my-2 { + margin: 0.5rem 0; +} + +.my-4 { + margin: 1rem 0; +} + +.my-8 { + margin: 2rem 0; +} + +.mt-auto { + margin-top: auto; +} + +[class~="p-0.5"] { + padding: 0.125rem; +} + +p { + margin: unset; + color: rgba(0, 0, 0, .6); +} + +.btn { + display: flex; + align-items: center; + flex-direction: row; + padding: 0.25rem 0.5rem; + border-radius: 0.5rem; + border: 3px solid #E3E3E3; + cursor: pointer; + font-size: smaller; + color: #000; + background: #fff; + transition: 0.5s; + margin: 0 0.5rem; +} + +a.btn { + text-decoration: none; +} + +.btn:hover, +.btn:focus { + background: #E3E3E3; +} + +.btn svg { + margin-left: 10px; +} + +input[type="checkbox"] { + position: relative; + width: 40px; + height: 20px; + -webkit-appearance: none; + appearance: none; + background: red; + outline: none; + border-radius: 2rem; + cursor: pointer; + box-shadow: inset 0 0 5px rgb(0 0 0 / 50%); +} + +input[type="checkbox"]::before { + content: ""; + width: 18px; + height: 18px; + border-radius: 50%; + background: #fff; + position: absolute; + top: 1px; + left: 1px; + transition: 0.5s; +} + +input[type="checkbox"]:checked::before { + transform: translateX(100%); + background: #fff; +} + +input[type="checkbox"]:checked { + background: #00ed64; +} \ No newline at end of file diff --git a/manifest.v2.json b/manifest.v2.json index cd11ae0..021f71c 100644 --- a/manifest.v2.json +++ b/manifest.v2.json @@ -9,6 +9,7 @@ "128": "/assets/images/icon-128.png" }, "permissions": [ + "storage", "https://hn.algolia.com/api/*" ], "applications": { @@ -28,5 +29,14 @@ "./scripts/main.js" ] } - ] + ], + "browser_action": { + "default_icon": { + "16": "/assets/images/icon-16.png", + "48": "/assets/images/icon-48.png", + "128": "/assets/images/icon-128.png" + }, + "default_popup": "./popup.html", + "default_title": "HNRelevant" + } } diff --git a/manifest.v3.json b/manifest.v3.json index de8b136..729017f 100644 --- a/manifest.v3.json +++ b/manifest.v3.json @@ -22,5 +22,17 @@ "./scripts/main.js" ] } - ] + ], + "permissions": [ + "storage" + ], + "action": { + "default_icon": { + "16": "/assets/images/icon-16.png", + "48": "/assets/images/icon-48.png", + "128": "/assets/images/icon-128.png" + }, + "default_popup": "./popup.html", + "default_title": "HNRelevant" + } } \ No newline at end of file diff --git a/popup.html b/popup.html new file mode 100644 index 0000000..23e3b13 --- /dev/null +++ b/popup.html @@ -0,0 +1,56 @@ + + + + + HNRelevant Popup + + + + + +
+
+

Select mode

+
+ +
+ +

Fetch results automatically on every submission (no interaction required)

+
+
+
+ +
+ +

Fetch results only when requested by user manually

+
+
+
+
+

Results

+
+ + +
+
+
+ + + + \ No newline at end of file diff --git a/scripts/dom.js b/scripts/dom.js index 5a0a948..c71a6df 100644 --- a/scripts/dom.js +++ b/scripts/dom.js @@ -46,7 +46,7 @@ queryCustomizationInput.placeholder = 'Customize: ' + HN_SubmissionTitle; queryCustomizationInput.value = HN_SubmissionTitle; // Allow user to submit query by pressing enter -queryCustomizationInput.addEventListener('keydown', function(event) { +queryCustomizationInput.addEventListener('keydown', function (event) { if (event.code === 'Enter' && queryCustomizationInput === document.activeElement) { submitCustomizationButton.click(); } @@ -62,7 +62,7 @@ const numOfResultsDropdown = document.createElement('select'); numOfResultsDropdown.style.marginLeft = '5px'; numOfResultsDropdown.id = 'numOfResultsDropdown'; ['5', '10', '15', '20', '30'].forEach(num => { - numOfResultsDropdown.add(new Option(num)); + numOfResultsDropdown.add(new Option(num, num)); }); sidebarOptionsContainer.appendChild(numberOfResultsLabel); diff --git a/scripts/main.js b/scripts/main.js index ad6918c..44b1851 100644 --- a/scripts/main.js +++ b/scripts/main.js @@ -14,14 +14,27 @@ sidebar.appendChild(sidebarOptionsContainer); sidebar.appendChild(sidebarResults); HN_Content.appendChild(sidebar); -// Make sure to run this after the page has loaded -if(document.readyState !== 'complete') { - window.addEventListener('load',updateSidebarResults); -} else { - updateSidebarResults(); -} +(async () => { + // Get preferences from storage + // Mode: manual or automatic + const mode = await (chrome.storage.sync ? chrome.storage.sync.get('mode') : browser.storage.sync.get('mode')); + + // Number of results: default to 5 + const numOfResults = await (chrome.storage.sync ? chrome.storage.sync.get('results') : browser.storage.sync.get('results')); + numOfResultsDropdown.value = numOfResults ? numOfResults.results : '5'; + + // Don't run if mode is set to `manual` + if (mode.mode !== 'manual') { + // Make sure to run this after the page has loaded + if (document.readyState !== 'complete') { + window.addEventListener('load', updateSidebarResults); + } else { + updateSidebarResults(); + } + } // Run on dropdown change (changing num of results: 5, 10, 15, 20, 30) -numOfResultsDropdown.addEventListener('change', () => - updateSidebarResults() -); \ No newline at end of file + numOfResultsDropdown.addEventListener('change', () => + updateSidebarResults() + ); +})(); \ No newline at end of file diff --git a/scripts/popup.js b/scripts/popup.js new file mode 100644 index 0000000..1c8a8af --- /dev/null +++ b/scripts/popup.js @@ -0,0 +1,55 @@ +const isChrome = chrome.storage.sync ? true : false; + +// get references to the input elements +const modeRadioButtons = document.getElementsByName("mode"); +const resultsDropdown = document.getElementsByName("results")[0]; + +if (isChrome) { // load saved settings from storage in Chrome + chrome.storage.sync.get(["mode", "results"], function (settings) { + // set the input elements to the saved values + if (settings.mode) { + for (const radioButton of modeRadioButtons) { + if (radioButton.value === settings.mode) { + radioButton.checked = true; + break; + } + } + } + if (settings.results) { + resultsDropdown.value = settings.results; + } + }); +} else { // load saved settings from storage in Firefox + browser.storage.sync.get(["mode", "results"], function (settings) { + // set the input elements to the saved values + if (settings.mode) { + for (const radioButton of modeRadioButtons) { + if (radioButton.value === settings.mode) { + radioButton.checked = true; + break; + } + } + } + if (settings.results) { + resultsDropdown.value = settings.results; + } + }); +} + +// add event listeners to the input elements +for (const radioButton of modeRadioButtons) { + radioButton.addEventListener("change", function () { + if (isChrome) { // save the selected mode to storage in Chrome + chrome.storage.sync.set({mode: this.value}); + } else { // save the selected mode to storage in Firefox + browser.storage.sync.set({mode: this.value}); + } + }); +} +resultsDropdown.addEventListener("change", function () { + if (isChrome) { // save the selected results to storage in Chrome + chrome.storage.sync.set({results: this.value}); + } else { // save the selected results to storage in Firefox + browser.storage.sync.set({results: this.value}); + } +}); \ No newline at end of file