diff --git a/CHANGELOG.md b/CHANGELOG.md index 51d6b5a..411bb1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# [Changelog v1.4.3](https://github.com/digas99/wanikani-kanji-highlighter/releases/tag/v1.4.3) + +## Popup +- Added page with information on certain features to the About page +- Added possibility to hide disabled subjects from subjects list in the Profile Page + +## Bug Fixes +- Fixed some issues with customization of the subjects list in the Profile Page + # [Changelog v1.4.2](https://github.com/digas99/wanikani-kanji-highlighter/releases/tag/v1.4.2) Released on 14/09/2024 diff --git a/README.md b/README.md index 4a729f2..ab25801 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ It works with any website, and provides detailed information about any kanji tha ## Table of contents: -1. [Latest Features](#changelog-v142) +1. [Latest Features](#changelog-v143) 2. [Usage Guide](#usage-guide) - 2.1. [WaniKani API Token](#wanikani-api-token) - 2.2. [Kanji Details](#kanji-details) @@ -31,6 +31,15 @@ It works with any website, and provides detailed information about any kanji tha - 2.7. [Settings](#settings) 3. [Pictures](#pictures) +## [Changelog v1.4.3](https://github.com/digas99/wanikani-kanji-highlighter/releases/tag/v1.4.3) + +### Popup +- Added page with information on certain features to the About page +- Added possibility to hide disabled subjects from subjects list in the Profile Page + +### Bug Fixes +- Fixed some issues with customization of the subjects list in the Profile Page + ## [Changelog v1.4.2](https://github.com/digas99/wanikani-kanji-highlighter/releases/tag/v1.4.2) ### Content diff --git a/images/features.png b/images/features.png new file mode 100644 index 0000000..97a86c4 Binary files /dev/null and b/images/features.png differ diff --git a/images/keyboard-key.png b/images/keyboard-key.png new file mode 100644 index 0000000..414e7c7 Binary files /dev/null and b/images/keyboard-key.png differ diff --git a/images/left-click.png b/images/left-click.png new file mode 100644 index 0000000..00ee0ea Binary files /dev/null and b/images/left-click.png differ diff --git a/images/right-click.png b/images/right-click.png new file mode 100644 index 0000000..cbf5912 Binary files /dev/null and b/images/right-click.png differ diff --git a/manifest.json b/manifest.json index b2c849f..a2e9fd9 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "WaniKani Kanji Highlighter", "description": "Unofficial kanji highlighter, matching kanji learned with WaniKani.", - "version": "1.4.2", + "version": "1.4.3", "manifest_version": 3, "icons": { "16": "logo/logo_bb_16x16.png", diff --git a/popup/about.html b/popup/about.html index e0de31b..22c3d62 100644 --- a/popup/about.html +++ b/popup/about.html @@ -39,6 +39,17 @@

API Key

edit + + +
+

Features Information

+
+ + features +

Click here to see usage recommendations and tips.

+
+
+
diff --git a/popup/features.html b/popup/features.html new file mode 100644 index 0000000..41dc5d1 --- /dev/null +++ b/popup/features.html @@ -0,0 +1,164 @@ + + + + + + + Features + + + + + + + + + + + + +
+
+
+

Subject Details

+

Throughout the Extension Popup, you will find Subject Tiles that can open a Subject Details Popup. Depending on which mouse button you use when clicking on it, you will open the details popup on different places. Feel free to try it on the Subject Tile bellow.

+
+
+
+ +
Left click - popup opens on the current web page you are browsing.
+
+
+ +
Right click - popup opens inside this extension popup.
+
+
+
+
+

Shortcut Keys

+

Shortcut keys available to use on the Subject Details Popup. These will collide with any existing shortcut within the web page you are visiting.

+
+
+
+
+ + X +
+
+
Close the popup.
+
+
+
+
+ + O +
+
+
Expand the popup when it is opened on the bottom right corner.
+
+
+
+
+ + L +
+
+
Lock current subject. Hovering over other kanji will not change the subject.
+
+
+
+
+ + F +
+
+
Pin popup, fixing it to the page. It will not close, even if you click outside of it.
+
+
+
+
+ + B +
+
+
Show details from the previous subject.
+
+
+
+
+ + Y +
+
+
Copy characters from current subject to clipboard.
+
+
+
+
+ + U +
+
+
Scroll back to the top of the popup.
+
+
+
+
+ + I +
+
+
Scroll to the Info section.
+
+
+
+
+ + C +
+
+
Scroll to the Cards section.
+
+
+
+
+ + S +
+
+
Scroll to the Stats section.
+
+
+
+
+ + T +
+
+
Scroll to the Timestamps section.
+
+
+
+
+ + +
+
+ + +
+
+
Scroll back and forth between the sections.
+
+
+
+
+

Subjects Data Error

+

During the process of fetching data from Wanikani servers or updating the extension, it is possible for some data from the subjects to get lost. If this ever becomes noticeable - maybe wrong highlighting, or the subject details popup doesn't load - you can Clear Subjects Data at the bottom of the Settings Page. This will trigger a fresh fetch of all data from Wanikani and hopefully fix any unwanted error.

+
+
+
+ + + + \ No newline at end of file diff --git a/popup/home.html b/popup/home.html index 7599154..1209e21 100644 --- a/popup/home.html +++ b/popup/home.html @@ -190,6 +190,8 @@
+ help + diff --git a/popup/scripts/home.js b/popup/scripts/home.js index fe4685f..079d95e 100644 --- a/popup/scripts/home.js +++ b/popup/scripts/home.js @@ -173,11 +173,22 @@ const updateHomeInterface = async (result) => { document.querySelector("#progress_legend")?.remove(); } -chrome.storage.local.get(["apiKey", "rating", ...HOME_FETCH_KEYS], result => { +chrome.storage.local.get(["apiKey", "rating", "help_button", ...HOME_FETCH_KEYS], result => { const settings = result["settings"] ? result["settings"] : defaultSettings; if (popupLoading) popupLoading.remove(); + // help button visibility + const helpButton = document.querySelector(".help-button"); + const help = result["help_button"]; + console.log(result, helpButton, help); + if (helpButton && help == false) + helpButton.remove(); + helpButton.addEventListener("click", () => { + chrome.storage.local.set({"help_button": false}); + }); + + // rating section visibility const rateStars = document.querySelector(".rate-stars"); const rating = result["rating"] || {}; if (rateStars && rating) { @@ -202,7 +213,7 @@ const kanjiListUpdate = (learned, notLearned, kanjiAssoc) => { highlightList.create(); const itemCallback = (elem, value) => { - elem.classList.add("kanjiDetails"); + elem.classList.add("subject-tile", "kanjiDetails"); if (kanjiAssoc && kanjiAssoc[value]) elem.setAttribute("data-item-id", kanjiAssoc[value]); } diff --git a/popup/scripts/profile.js b/popup/scripts/profile.js index 9c9cca4..702df95 100644 --- a/popup/scripts/profile.js +++ b/popup/scripts/profile.js @@ -11,6 +11,7 @@ chrome.storage.local.get(["apiKey", "userInfo", "settings", LEVELS_STATS.storage const apiKey = result["apiKey"]; settings = result["settings"]; menuSettings = settings && settings["profile_menus"] ? settings["profile_menus"] : defaultSettings["profile_menus"]; + console.log("Menu settings:", menuSettings); levelsStats = result[LEVELS_STATS.storage.id]; @@ -222,7 +223,7 @@ const subjectTile = (type, subject) => { subjectWrapper.classList.add(type+"_back"); subjectWrapper.title = subject["meanings"][0]; subjectWrapper.style.position = "relative"; - subjectWrapper.classList.add("clickable", "kanjiDetails"); + subjectWrapper.classList.add("subject-tile", "clickable", "kanjiDetails"); subjectWrapper.setAttribute("data-item-id", subject["id"]); if (subject["readings"]) { if (subject["readings"][0]["reading"]) @@ -399,10 +400,10 @@ const clearData = () => { // subjects progress from "All" document.querySelector(".subject-tab > span").innerText = ""; - // close arrow from "All" - let closeArrow = document.querySelector(".subject-tab > .menu-icons > div[title='Close']"); - if (closeArrow.querySelector("i").classList.contains("down")) - closeArrowAction(closeArrow, document.querySelector(".subject-types")); + // // close arrow from "All" + // let closeArrow = document.querySelector(".subject-tab > .menu-icons > div[title='Close']"); + // if (closeArrow.querySelector("i").classList.contains("down")) + // closeArrowAction(closeArrow, document.querySelector(".subject-types")); // subjects Array.from(document.querySelectorAll(".subject-types > div")).forEach(container => { @@ -411,9 +412,9 @@ const clearData = () => { // subjects tiles container.querySelector(".subject-container > ul").innerHTML = ""; // subjects close arrow - closeArrow = container.querySelector(".menu-icons > div[title='Close']"); - if (closeArrow.querySelector("i").classList.contains("down")) - closeArrowAction(closeArrow, container.querySelector(".subject-container")); + // closeArrow = container.querySelector(".menu-icons > div[title='Close']"); + // if (closeArrow.querySelector("i").classList.contains("down")) + // closeArrowAction(closeArrow, container.querySelector(".subject-container")); }); } @@ -428,7 +429,8 @@ document.addEventListener("click", e => { const title = tab.firstElementChild.innerText; let key = Object.keys(menuSettings).filter(k => title.toLowerCase().includes(k))[0]; - closeArrowAction(arrow, tab.nextElementSibling, key); + const result = closeArrowAction(arrow, tab.nextElementSibling, key); + menuSettings[key]["opened"] = result; // save changes chrome.storage.local.set({"settings": settings}); @@ -508,7 +510,7 @@ document.addEventListener("click", e => { } }); -const closeArrowAction = (arrow, subjectsContainer, key) => { +const closeArrowAction = (arrow, subjectsContainer) => { const opened = !subjectsContainer.classList.contains("hidden"); if (subjectsContainer) { if (opened) { @@ -520,9 +522,8 @@ const closeArrowAction = (arrow, subjectsContainer, key) => { subjectsContainer.classList.remove("hidden"); } - if (key) - menuSettings[key]["opened"] = !opened; - } + return !opened; + } } document.addEventListener("input", e => { @@ -555,21 +556,20 @@ const applyChanges = () => { const tab = Array.from(document.querySelectorAll(".subject-tab")).filter(tab => tab.firstElementChild.innerText.toLowerCase().includes(type))[0]; if (tab) { Object.keys(menuSettings[type]).forEach(key => { + const title = type.charAt(0).toUpperCase()+type.slice(1); if (key === "opened") { if (menuSettings[type][key] == false) { const closeArrow = tab.querySelector("div[title='Close']"); - closeArrow.click(); + closeArrowAction(closeArrow, tab.nextElementSibling, type); } } else { Object.keys(menuSettings[type][key]).forEach(property => { if (menuSettings[type][key][property] !== defaultSettings["profile_menus"][type][key][property]) { - const title = type.charAt(0).toUpperCase()+type.slice(1); let keys = [Object.keys(menuSettings).filter(k => title.toLowerCase().includes(k))[0]]; - if (title === "All") - keys = Object.keys(menuSettings); - menuActions(tab, title, key.charAt(0).toUpperCase()+key.slice(1), property, keys, menuSettings[type][key][property]); + if (title !== "All") + menuActions(tab, title, key.charAt(0).toUpperCase()+key.slice(1), property, keys, menuSettings[type][key][property]); } }); } @@ -629,6 +629,10 @@ const menuActions = (tab, subjectsType, menuTitle, property, keys, value) => { reviewsInfo(subjects, value); keys.forEach(key => menuSettings[key]["menu"]["reviews_info"] = value); break; + case "disabled_subjects": + disabledSubjects(subjects, value); + keys.forEach(key => menuSettings[key]["menu"]["disabled_subjects"] = value); + break; } break; } @@ -695,6 +699,9 @@ const menuMenu = (wrapper, defaults) => { // show reviews info wrapper.appendChild(checkbox("Reviews info", defaults["reviews_info"])); + + // show disabled subjects + wrapper.appendChild(checkbox("Disabled subjects", defaults["disabled_subjects"])); } const colorings = (subjects, type) => { @@ -767,6 +774,15 @@ const reviewsInfo = (subjects, checked) => { } } +const disabledSubjects = (subjects, checked) => { + Array.from(subjects).filter(elem => elem.dataset.hidden_at).forEach(subject => { + if (checked) + subject.style.removeProperty("display"); + else + subject.style.display = "none"; + }); +} + // FILTERS MENU const filterMenu = (wrapper, defaults) => { @@ -783,7 +799,7 @@ const filters = (subjects, srs, state) => { if (srs !== "None") { Array.from(subjects).forEach(elem => { - const srsChecker = srs !== "None" && (elem.getAttribute("data-srs") == "-1" && srs !== "Locked" || elem.getAttribute("data-srs") !== "-1" && srs !== srsStages[elem.getAttribute("data-srs")]["name"]); + const srsChecker = srs !== "None" && (elem.getAttribute("data-srs") == "-1" && srs !== "Locked" || elem.getAttribute("data-srs") !== "-1" && srs !== srsStages[elem.getAttribute("data-srs")]?.name); if (srsChecker) elem.classList.add("hidden"); }); @@ -791,7 +807,7 @@ const filters = (subjects, srs, state) => { if (state !== "None") { Array.from(subjects).forEach(elem => { - const stateChecker = state !== "None" && (state !== (elem.getElementsByClassName("passed-subject-check").length > 0 ? "Passed" : "Not Passed")); + const stateChecker = state !== "None" && (state !== (elem?.dataset.passed_at ? "Passed" : "Not Passed")); if (stateChecker) elem.classList.add("hidden"); }); diff --git a/popup/scripts/reviews-history.js b/popup/scripts/reviews-history.js index 5cec616..5102f4a 100644 --- a/popup/scripts/reviews-history.js +++ b/popup/scripts/reviews-history.js @@ -37,9 +37,9 @@ chrome.storage.local.get(["assignments_history"], result => {

${updatedAtPretty} ago

diff --git a/popup/scripts/scripts.js b/popup/scripts/scripts.js index 2de740b..29670ce 100644 --- a/popup/scripts/scripts.js +++ b/popup/scripts/scripts.js @@ -1,11 +1,12 @@ let messagePopup, blacklistedSite, atWanikani; window.onload = () => { - chrome.storage.local.get(["initialFetch", "blacklist", "contextMenuSelectedText"], async result => { + chrome.storage.local.get(["initialFetch", "blacklist", "contextMenuSelectedText", "settings"], async result => { + updateSettings(result["settings"], defaultSettings); + if (result["contextMenuSelectedText"]) { makeSearch(result["contextMenuSelectedText"]); chrome.storage.local.remove("contextMenuSelectedText"); } - const initialFetch = result["initialFetch"] || result["initialFetch"] == undefined; diff --git a/popup/scripts/search.js b/popup/scripts/search.js index 03b80db..efced56 100644 --- a/popup/scripts/search.js +++ b/popup/scripts/search.js @@ -262,7 +262,7 @@ const displayResults = (wrapper, results, lowerIndex, upperIndex, display) => { const dataWrapper = document.createElement("div"); li.appendChild(dataWrapper); dataWrapper.setAttribute('data-item-id', data["id"]); - dataWrapper.classList.add("kanjiDetails"); + dataWrapper.classList.add("subject-tile", "kanjiDetails"); const itemSpan = document.createElement("span"); itemSpan.classList.add("searchResultItem"); diff --git a/popup/styles/about.css b/popup/styles/about.css index 0a04e9e..eb1b99e 100644 --- a/popup/styles/about.css +++ b/popup/styles/about.css @@ -177,4 +177,14 @@ .footer-icons > a > img { width: 30px; +} + +.features-info { + display: flex; + align-items: center; + column-gap: 10px; +} + +.features-info img { + width: 20px; } \ No newline at end of file diff --git a/popup/styles/features.css b/popup/styles/features.css new file mode 100644 index 0000000..12a637b --- /dev/null +++ b/popup/styles/features.css @@ -0,0 +1,86 @@ +.features .section { + padding: 10px; + padding-bottom: 20px; +} + +.features .section h2 { + padding: 10px 0; +} + +.features .section p { + color: var(--font-sec-color); + font-size: 13px; +} + +.features .section > div { + margin-left: 5px; + margin-top: 20px; +} + +.keys-list { + display: flex; + flex-direction: column; + row-gap: 10px; +} + +.keys-list-entry { + display: flex; + align-items: center; + column-gap: 10px; +} + +.keys-list-entry > div:first-child { + display: flex; + align-items: center; + column-gap: 5px; +} + +.keys-list-entry .keys-list-key { + position: relative; + width: fit-content; + align-items: center; + display: flex; + text-align: center; + font-weight: bold; +} + +.keys-list-entry .keys-list-key img { + width: 25px; +} + +.keys-list-entry .keys-list-key span { + position: absolute; + left: 0; + right: 0; + color: var(--fill-color); +} + +.keys-list-description { + +} + +.subject-tile { + font-size: 30px; + color: white; +} + +.subject-details-info { + display: flex; + align-items: center; + column-gap: 20px; +} + +.subject-details-info-mouse-click { + display: flex; + align-items: center; + column-gap: 5px; +} + +.subject-details-info-mouse-click img { + width: 30px; +} + +.subject-details-info-mouse-click div { + color: var(--font-sec-color); + font-size: 12px; +} \ No newline at end of file diff --git a/popup/styles/home.css b/popup/styles/home.css index 4bbb998..ad5fd7e 100644 --- a/popup/styles/home.css +++ b/popup/styles/home.css @@ -264,4 +264,15 @@ body { .legend .legend-label { +} + +.help-button { + position: fixed; + bottom: 5px; + right: 60px; +} + +.help-button img { + width: 30px; + filter: drop-shadow(2px 2px 1px white); } \ No newline at end of file diff --git a/popup/styles/profile.css b/popup/styles/profile.css index 6dc4672..bce0417 100644 --- a/popup/styles/profile.css +++ b/popup/styles/profile.css @@ -413,6 +413,14 @@ body { min-height: 40px; } +.subject-container .kanji_back, .subject-container .radical_back { + padding: 6px 7px; +} + +.subject-container .fill-width { + grid-template-columns: repeat(auto-fill, minmax(40px, 1fr)); +} + .time-next-review-subject { font-size: 10px; background-color: #42f541; diff --git a/popup/styles/styles.css b/popup/styles/styles.css index df67099..e9a7662 100644 --- a/popup/styles/styles.css +++ b/popup/styles/styles.css @@ -241,12 +241,16 @@ i { } .simple-grid > ul li { - padding: 2px 6px; display: inline-block; margin: 2px; +} + +.subject-tile { + padding: 2px 6px; text-shadow: -1px 1px 0px #727272; box-shadow: -1px 2px 0px 1px var(--default-color); - border-radius: 6px; + border-radius: 6px; + width: fit-content; } .goTop { diff --git a/popup/styles/tiles-list.css b/popup/styles/tiles-list.css index 29f092d..073b41d 100644 --- a/popup/styles/tiles-list.css +++ b/popup/styles/tiles-list.css @@ -88,12 +88,12 @@ } .fill-width { - grid-template-columns: repeat(auto-fill,minmax(40px,1fr)); + grid-template-columns: repeat(auto-fill,minmax(35px,1fr)); display: grid; } .fill-width > li { - padding: 6px 2px !important; + padding: 6px 2px; text-align: center; } diff --git a/scripts/functions.js b/scripts/functions.js index 1cc8174..bafb1fa 100644 --- a/scripts/functions.js +++ b/scripts/functions.js @@ -832,7 +832,7 @@ const dataTile = (subjects, elem, value) => { const type = subject["subject_type"]; - elem.classList.add("kanjiDetails"); + elem.classList.add("subject-tile", "kanjiDetails"); elem.title = `${meaning} ${reading ? `| ${reading}` : ""}\x0D${type.split("_").map(word => word[0].toUpperCase() + word.slice(1)).join(" ")}`; elem.setAttribute("data-item-id", subject["id"]); @@ -1345,4 +1345,31 @@ const levelUpInfo = subjects => { subjects: kanji, initiated: initiatedKanji, }; -} \ No newline at end of file +} + +const updateSettings = (settings, defaults) => { + const updated = updateObject(settings, defaults); + if (updated) { + chrome.storage.local.set({"settings": settings}); + } +} + +const updateObject = (source, updates) => { + let changed = false; + + const deepUpdate = (src, upd) => { + for (const key in upd) { + // Check if the key doesn't exist in source + if (!(key in src)) { + src[key] = upd[key]; + changed = true; + } else if (typeof src[key] === 'object' && typeof upd[key] === 'object' && !Array.isArray(src[key]) && !Array.isArray(upd[key])) { + // Recursively handle nested objects + deepUpdate(src[key], upd[key]); + } + } + }; + + deepUpdate(source, updates); + return changed; +}; \ No newline at end of file diff --git a/scripts/static.js b/scripts/static.js index c05de32..0dc4a65 100644 --- a/scripts/static.js +++ b/scripts/static.js @@ -106,7 +106,8 @@ const defaultSettings = { "opened": true, "menu": { "color_by": "Subject Type", - "reviews_info": true + "reviews_info": true, + "disabled_subjects": true }, "filter": { "srs_stage": "None", @@ -121,7 +122,8 @@ const defaultSettings = { "opened": true, "menu": { "color_by": "Subject Type", - "reviews_info": true + "reviews_info": true, + "disabled_subjects": true }, "filter": { "srs_stage": "None", @@ -136,7 +138,8 @@ const defaultSettings = { "opened": true, "menu": { "color_by": "Subject Type", - "reviews_info": true + "reviews_info": true, + "disabled_subjects": true }, "filter": { "srs_stage": "None", @@ -151,7 +154,8 @@ const defaultSettings = { "opened": true, "menu": { "color_by": "Subject Type", - "reviews_info": true + "reviews_info": true, + "disabled_subjects": true }, "filter": { "srs_stage": "None",