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
+
+
+
+
Features Information
+
+
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 @@
+
+
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
-
${assignment.characters}
+
${assignment.characters}
-
${assignment.characters}
+
${assignment.characters}
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",