Skip to content

Commit

Permalink
Merge pull request #19 from aiden2480/settings
Browse files Browse the repository at this point in the history
Add settings functionality
  • Loading branch information
aiden2480 authored May 1, 2022
2 parents b77cb68 + 4477a44 commit 202896a
Show file tree
Hide file tree
Showing 17 changed files with 798 additions and 109 deletions.
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Project custom
local/
.env

# Development JS libs
js/libs/image.js
# Editor settings folders
.vscode/
.vs/

23 changes: 14 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,17 @@ $ curl -L http://kanjithing-backend.chocolatejade42.repl.co/kanji/車
```

## :memo: Future features
- [ ] Able to star/favourite kanji to add them quickly to a custom set.
- [ ] Make the user guess readings of kanji in words
- [ ] Add a check for `loadKanjiDetails` in case the user has loaded a new kanji by the time info loads
- [ ] Index page
- Version links and details
- [ ] Help page
- How to use the extention, info about tooltips, etc
- Open on the first install
- [ ] Settings page
- Load custom kanji sets
- Log in to save
- Change the speed with which the drawing guide video is played
- [x] Settings page
- [ ] `customsets` -> `sets`
- [ ] Use the `var { sets } = ...` thing
- [ ] Ability to toggle starred/all kanji
- [ ] Fall back to default set if the set we are trying to load is deleted
- [ ] Show alert to confirm settings were saved
- [ ] Flashcard thing where you get the meaning of the kanji and sample words and have to draw it
- [ ] Custom flashcards to remember kanji/words
- Import from quizlet
Expand All @@ -78,9 +78,8 @@ $ curl -L http://kanjithing-backend.chocolatejade42.repl.co/kanji/車
- [Available on GitHub](https://github.com/kanjialive/kanji-data-media/blob/master/kanji-animations/stroke_timings) with timestamps
- [ ] Grey loading screen should only appear after a certain amount of time to account for cached requests that resolve quickly
- To prevent grey/white flashes that occur when the next character loads quickly
- [ ] Fix whatever weirdness broke the dynamic browser icon
- [ ] Able to star/favourite kanji to add them quickly to a custom set.
- [ ] Right click to remove drawing (all connected strokes)
- [ ] Add tooltip banner when extension updates
- [x] Keybinds to navigate the application via keyboard
- Up/down arrow to navigate between kanji sets
- Left/right arrow to navigate between kanji in the currently selected set
Expand All @@ -91,3 +90,9 @@ $ curl -L http://kanjithing-backend.chocolatejade42.repl.co/kanji/車
- S to star/unstar selected kanji
- Keybinds visible in tooltips
- [ ] Use static assets for the emojis to keep design consistent between operating systems
- [ ] Event listener on the popup script to determine when the set storage has changed
- [ ] Use data from the KanjiAlive API to do pronuncation/sounds
- [ ] Make CSS for buttons/inputs be consistent throughout the popup/settings/index pages
- [ ] Fix overlap interaction with especially long word descriptions (同 kanji)
- [ ] Use a RapidAPI key in the application to fetch data (Replit downtime)
- [ ] Unspaghettify everything
120 changes: 109 additions & 11 deletions background.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@
/* Save the current kanji */
var current;
var defaultsets = [
{"Unit one": "学校名前父母生高姉妹兄弟住所色"},
{"Unit two": "好同手紙英語何年私友行毎教場"},
{"Unit three": "早新家入出思来島午後朝夜牛魚族"},
{"Unit four": "会社持待道近町番屋店駅神様区"},
{"Unit five": "時間国先長話見言休聞今食勉強"},
{"Unit six": "帰買電車左右目口書物飲肉昼乗"},
{"Unit seven": "曜気分多少元半使天病心楽方作文"},
{"Unit eight": "週夏立自赤外西川旅州晩洗持活去"},
{"Unit nine": "正冬着安広海古寺東京都北市県"},
{"Unit ten": "森山知雪雨字読急洋服動止院漢和"},
{"Unit eleven": "春秋花南田売耳青白仕事銀犬飯"},
{"Unit twelve": "林黒羊地夕次体発馬才鳥茶歩鉄"}
];

/* Set up a listener so we can receive messages from the console */
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {

/* Set up a listener so we can receive messages from the console
Because chrome is incredibly dumb and stupid, they won't allow
the listener to be an async function, so we have to instead put
the async code inside an immediately invoked function, and then
return true so that chrome knows to wait for a callback to complete
before continuing. The wrapper looks really ugly but it's the best
I can do without weird indentation so it's the lesser of two evils
*/
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {(async () => {
// {type: ..., data: ...}

switch (message.type) {
Expand All @@ -12,21 +34,77 @@ chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
case "setIcon":
setBrowserIcon(message.data);
break;
default:
case "resetKanjiSets":
await chrome.storage.local.remove("customsets");
await createKanjiSets();
sendResponse();
break;
case "ensureDefaultConfig":
await ensureDefaultConfiguration();
sendResponse();
break;
}
});

/* Set up a listener for when the extension is installed */
chrome.runtime.onInstalled.addListener(reason => {
})(); return true});

/* Set up a listener for when the extension is installed/chrome restarts */
chrome.runtime.onInstalled.addListener(async reason => {
console.log("Install event fired with", reason);
chrome.runtime.setUninstallURL("https://kanjithing-backend.chocolatejade42.repl.co/uninstall");

if ((await chrome.management.getSelf()).installType !== "development")
chrome.runtime.setUninstallURL("https://kanjithing-backend.chocolatejade42.repl.co/uninstall");

await ensureDefaultConfiguration();
await ensureCorrectKanjiIcon();
await ensureBetaBadge();
});

chrome.runtime.onStartup.addListener(async () => {
await ensureDefaultConfiguration();
await ensureCorrectKanjiIcon();
await ensureBetaBadge();
});

chrome.storage.onChanged.addListener(async (changes, namespace) => {
// Console log when storage values change
if ((await chrome.management.getSelf()).installType !== "development") return;

for (let [key, { oldValue, newValue }] of Object.entries(changes)) {
console.debug(`${key} : ${oldValue} -> ${newValue}`);
}
});

/* Configuration functions called above */
async function ensureCorrectKanjiIcon() {
var { customsets, selectedset, selectedkanji } = await chrome.storage.local.get();
if ([ customsets, selectedset, selectedkanji ].includes(undefined)) return;

setBrowserIcon(customsets[selectedset].kanji[selectedkanji], bypass=true);
}

async function ensureBetaBadge() {
// Ensure that the "Beta" badge is present if necessary

if ((await chrome.management.getSelf()).installType === "development") {
chrome.action.setBadgeText({ text: "B" });
chrome.action.setBadgeBackgroundColor({ color: "#304db6" });
}
}

async function ensureDefaultConfiguration() {
// Create default sets
var sets = (await chrome.storage.local.get("customsets")).customsets;
(sets === undefined) && await createKanjiSets();

// Create default settings
var { config } = await chrome.storage.local.get("config");
(config === undefined) && await createDefaultConfig();
}

/* Script to change the browser icon */
function setBrowserIcon(kanji) {
function setBrowserIcon(kanji, bypass=false) {
// https://jsfiddle.net/1u37ovj9/
if (current === kanji) return;
if (current === kanji && !bypass) return;

var canvas = new OffscreenCanvas(64, 64);
var context = canvas.getContext("2d");
Expand All @@ -43,5 +121,25 @@ function setBrowserIcon(kanji) {

current = kanji;
var imageData = context.getImageData(0, 0, 64, 64);
chrome.action.setIcon({imageData}, () => console.log(`Set browser icon to %c${kanji}`, "color: #7289da"));
};
chrome.action.setIcon({ imageData }, () => console.log(`Set browser icon to %c${kanji}`, "color: #7289da"));
}

/* Creates defult configuration as required by ensureDefaultConfiguration */
async function createKanjiSets() {
// {id: ..., name: ..., kanji: ..., enabled: ...}

var customsets = defaultsets.map((item, index) => {
var name = Object.keys(item)[0];
var value = Object.values(item)[0];

return {id: index, name: name, kanji: value, enabled: true}
});

await chrome.storage.local.set({ customsets });
}

async function createDefaultConfig() {
var { videoSpeed, settingsbtn } = await chrome.storage.local.get(["videoSpeed", "settingsbtn"]);
(videoSpeed !== undefined) || await chrome.storage.local.set({ videoSpeed: 0.8 });
(settingsbtn !== undefined) || await chrome.storage.local.set({ settingsbtn: true });
}
64 changes: 64 additions & 0 deletions css/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
body {
color: #7289da;
background-color: #36393e;
font-family: "Segoe UI", Tahoma, sans-serif;
}

/* Header with image and title */
header {
margin: auto;
width: fit-content;
display: flex;
align-items: center;
}

header * {
vertical-align: middle;
float: left;
}

header h1 {
margin-left: 10px;
font-size: 600%;
}

/* Install button */
#installbutton {
position: fixed;
right: 10px;
top: 10px;

min-width: fit-content;
font-size: 2.75vh;
color: white;
background-color: #7289da;

border: none;
border-radius: 5px;
margin: auto;
display: flex;
align-items: center;
padding: 0.75vh 1vw;

opacity: 0;
transition: opacity 300ms ease-in-out 500ms, color 300ms ease-in-out;
}

#installbutton:hover {
color: #36393e;
}

#installbutton img {
vertical-align: middle;
margin-right: 0.25vw;
}

#installbutton.available {
opacity: 1;
cursor: pointer;
}

div#itemdescription {
text-align: center;
display: block;
}
23 changes: 23 additions & 0 deletions css/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,26 @@ div#infosection #exampleslist * {
#popup-inner span {
margin: 15px;
}

#noscript {
font-size: 300%;
display: block;
}

#settings {
position: fixed;
right: 4px;
bottom: 4px;

height: 4ch;
vertical-align: middle;
cursor: pointer;
border: none;
border-radius: 5px;
background-color: #4e5259;
transition: background-color 300ms ease-in-out;
}

#settings:hover {
background-color: #36393e;
}
78 changes: 78 additions & 0 deletions css/settings.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
body {
max-width: 550px;
margin: auto;
zoom: 2vh;
}

#setscontainer {
display: table;
max-width: 500px;
margin: auto;
}

#setscontainer div {
display: table-row;
}

#setscontainer div * {
display: table-cell;
}

#setscontainer div :is(b, span) {
border: none;
text-indent: 0.5em;
padding-right: 0.5em;
cursor: default;
}

#setscontainer div button {
cursor: pointer;
border: none;
border-radius: 5px;
background-color: #4e5259;
margin: 0.75px;
transition: background-color 300ms ease-in-out;
}

#setscontainer div button:hover {
background-color: #36393e;
}

#setscontainer div span {
max-width: 50ch;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

#setscontainer div [contentEditable=true] {
border-radius: 5px;
border-bottom: 2px solid #7289da;
background-color: #4e5259;
border-radius: 5px 5px 0px 0px;
outline: none;
cursor: text;
}

#setsconfig input[type=button] {
border: none;
border-bottom: 3px solid #7289da;
border-radius: 5px 0px;
margin-top: 5px;
background-color: #4e5259;
color: #7289da;
cursor: pointer;
transition: background-color 300ms ease-in-out;
}

#setsconfig input[type=button]:hover {
background-color: #36393e;
}

code {
padding: 0 5px 0 5px;
background: #2F3136;
border-radius: 5px;
font-family: monospace;
font-weight: bold;
}
Loading

0 comments on commit 202896a

Please sign in to comment.