diff --git a/fonts/NotoSansJP-Regular.otf b/fonts/NotoSansJP-Regular.otf new file mode 100644 index 0000000..5791298 Binary files /dev/null and b/fonts/NotoSansJP-Regular.otf differ diff --git a/index.html b/index.html index 1a731fd..c56debd 100644 --- a/index.html +++ b/index.html @@ -2,30 +2,53 @@ - Change this you moron + Memory Helper + - -
-

{{title}}

-
-

-
- @Klemek - Github Repository - {{currentYear}} +

Memory Helper

+
+
Status : {{ done.length }}/{{ available.length }}
+
+
🎉
+
+
Reset
+
+
+
+
{{question}}
+
{{showAnswer ? answer : '???'}}
+
+
Show
+
✔
+
✘
+
+
+ +
+
+
+
+

List {{showConfig ? 'â–¼' : 'â–²'}}

+ + + + + + + + + + + +
+
+ @Klemek - Github Repository - {{currentYear}}
diff --git a/libs/lz-string.min.js b/libs/lz-string.min.js new file mode 100644 index 0000000..2d1900a --- /dev/null +++ b/libs/lz-string.min.js @@ -0,0 +1 @@ +var LZString=function(){function o(o,r){if(!t[o]){t[o]={};for(var n=0;ne;e++){var s=r.charCodeAt(e);n[2*e]=s>>>8,n[2*e+1]=s%256}return n},decompressFromUint8Array:function(o){if(null===o||void 0===o)return i.decompress(o);for(var n=new Array(o.length/2),e=0,t=n.length;t>e;e++)n[e]=256*o[2*e]+o[2*e+1];var s=[];return n.forEach(function(o){s.push(r(o))}),i.decompress(s.join(""))},compressToEncodedURIComponent:function(o){return null==o?"":i._compress(o,6,function(o){return e.charAt(o)})},decompressFromEncodedURIComponent:function(r){return null==r?"":""==r?null:(r=r.replace(/ /g,"+"),i._decompress(r.length,32,function(n){return o(e,r.charAt(n))}))},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(o,r,n){if(null==o)return"";var e,t,i,s={},p={},u="",c="",a="",l=2,f=3,h=2,d=[],m=0,v=0;for(i=0;ie;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++),s[c]=f++,a=String(u)}if(""!==a){if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;for(;;){if(m<<=1,v==r-1){d.push(n(m));break}v++}return d.join("")},decompress:function(o){return null==o?"":""==o?null:i._decompress(o.length,32768,function(r){return o.charCodeAt(r)})},_decompress:function(o,n,e){var t,i,s,p,u,c,a,l,f=[],h=4,d=4,m=3,v="",w=[],A={val:e(0),position:n,index:1};for(i=0;3>i;i+=1)f[i]=i;for(p=0,c=Math.pow(2,2),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(t=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 2:return""}for(f[3]=l,s=l,w.push(l);;){if(A.index>o)return"";for(p=0,c=Math.pow(2,m),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(l=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 2:return w.join("")}if(0==h&&(h=Math.pow(2,m),m++),f[l])v=f[l];else{if(l!==d)return null;v=s+s.charAt(0)}w.push(v),f[d++]=s+v.charAt(0),h--,s=v,0==h&&(h=Math.pow(2,m),m++)}}};return i}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module&&(module.exports=LZString); diff --git a/main.js b/main.js index 5dd8606..8e5b0db 100644 --- a/main.js +++ b/main.js @@ -1,109 +1,139 @@ /* exported app, utils */ const utils = { - ajax: { - proxy: 'cors-anywhere.herokuapp.com', - /** - * Define a get HTTP request to be executed with .then/.catch - * @param {string} url - * @param {Object} data - * @param {boolean} proxy - use cors proxy - * @returns {Promise} return JSON parsed data or string - */ - get: (url, data, proxy = false) => { - return new Promise((resolve, reject) => { - if (data && Object.keys(data).length) { - url += '?' + Object.keys(data) - .map(k => k + '=' + encodeURIComponent(data[k])) - .join('&') - .replace(/%20/g, '+'); - } - const xhr = new XMLHttpRequest(); - if (proxy) { - const http = (window.location.protocol === 'http:' ? 'http:' : 'https:'); - url = `${http}//${utils.ajax.proxy}/${url}`; - } - xhr.open('GET', url); - xhr.onload = () => { - try { - resolve(JSON.parse(xhr.responseText)); - } catch (ignored) { - resolve(xhr.responseText); - } - }; - xhr.onerror = () => reject(xhr); - xhr.send(); - }); - }, - }, - cookies: { - /** - * Save a value in a cookie - * @param {string} name - * @param {string} value - * @param {number | undefined} days - */ - set: function (name, value, days = undefined) { - const maxAge = !days ? undefined : days * 864e2; - document.cookie = `${name}=${encodeURIComponent(value)}${maxAge ? `;max-age=${maxAge};` : ''}`; - }, - /** - * Get a value from a cookie - * @param {string} name - * @return {string} value from cookie or empty if not found - */ - get: function (name) { - return document.cookie.split('; ').reduce(function (r, v) { - const parts = v.split('='); - return parts[0] === name ? decodeURIComponent(parts[1]) : r; - }, ''); - }, - /** - * Delete a cookie - * @param {string} name - */ - delete: function (name) { - this.set(name, '', -1); - }, - /** - * Clear all cookies - */ - clear: function () { - const cookies = document.cookie.split(';'); - for (let i = 0; i < cookies.length; i++) { - const cookie = cookies[i]; - const eqPos = cookie.indexOf('='); - const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; - document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT`; - } - }, - }, + cloneObject: function (obj) { + return JSON.parse(JSON.stringify(obj)); + }, + serialize: function (list) { + return LZString.compressToBase64(JSON.stringify(list)); + }, + deserialize: function (rawData) { + return JSON.parse(LZString.decompressFromBase64(rawData)); + }, + randint: function (min, max) { + return Math.floor(Math.random() * (max - min)) + min; + }, + randindex: function (array, ...toIgnore) { + let index; + do { + index = this.randint(0, array.length); + } while (this.contains(toIgnore, index)); + return index; + }, + randitem: function (array) { + return array[this.randindex(array)]; + }, + randindexes: function (array, number, ...toIgnore) { + const output = []; + for (let i = 0; i < number; i++) { + output.push(this.randindex(array, ...output, ...toIgnore)); + } + return output; + }, + shuffle: function (array) { + const output = [...array]; + for (let i = 0; i < array.length; i++) { + const i1 = this.randindex(array); + const i2 = this.randindex(array, i1); + [output[i1], output[i2]] = [output[i2], output[i1]]; + } + return output; + }, + contains: function (array, item) { + return array.indexOf(item) >= 0; + }, }; let app = { - data() { - return { - title: 'Vue-Boilerplate', - content: 'Fill this page with whatever you\'re going to develop.
Then enjoy!', - }; + data() { + return { + question: "", + answer: "", + showAnswer: false, + available: [], + current: [], + failed: [], + done: [], + newRow: ["", ""], + showConfig: true, + }; + }, + computed: { + currentYear() { + return new Date().getFullYear(); }, - computed: { - currentYear() { - return new Date().getFullYear(); - }, + }, + methods: { + showApp() { + document.getElementById("app").setAttribute("style", ""); }, - methods: { - showApp() { - document.getElementById('app').setAttribute('style', ''); - }, + show() { + this.showAnswer = true; }, - mounted: function () { - console.log('app mounted'); - setTimeout(this.showApp); + right() { + this.done.push(this.current.shift()); + console.log(this.current); + this.nextQuestion(); }, + wrong() { + this.failed.push(this.current.shift()); + console.log(this.current); + this.nextQuestion(); + }, + deleteRow(i) { + this.available.pop(i); + this.updateData(); + }, + addRow() { + if (this.newRow[0] && this.newRow[1]) { + this.available.push(utils.cloneObject(this.newRow)); + this.newRow = ["", ""]; + } + this.updateData(); + }, + updateData() { + const data = utils.serialize(this.available); + const url = new URL(window.location); + if (url.searchParams.get("d") !== data) { + url.searchParams.set("d", data); + window.history.pushState({}, "", url); + } + this.reset(); + }, + reset() { + this.current = utils.shuffle(utils.cloneObject(this.available)); + this.done = []; + this.failed = []; + this.nextQuestion(); + }, + nextQuestion() { + this.showAnswer = false; + + if (this.current.length === 0 && this.failed.length > 0) { + this.current = utils.shuffle(utils.cloneObject(this.failed)); + this.failed = []; + } + + if (this.current.length > 0) { + this.question = this.current[0][0]; + this.answer = this.current[0][1]; + } + }, + }, + beforeMount() { + const url = new URL(window.location); + if (url.searchParams.get("d")) { + this.available = utils.deserialize(url.searchParams.get("d")); + this.showConfig = false; + this.reset(); + } + }, + mounted: function () { + setTimeout(this.showApp); + }, }; window.onload = () => { - app = Vue.createApp(app); - app.mount('#app'); + app = Vue.createApp(app); + app.mount("#app"); }; diff --git a/style.css b/style.css index 85ce010..bc4f6dc 100644 --- a/style.css +++ b/style.css @@ -1,42 +1,148 @@ -* { - box-sizing: border-box; - font-family: Verdana, serif; - color: #424242; +/* noto-sans-regular - latin */ +@font-face { + font-family: "Noto Sans"; + font-style: normal; + font-weight: 400; + src: url("fonts/NotoSansJP-Regular.otf"); } -html, body { - margin: 0; - padding: 0; - height: 100vh; - max-width: 100%; +* { + box-sizing: border-box; + font-family: "Noto Sans", Verdana, serif; + color: #424242; +} + +html, +body { + margin: 0; + padding: 0; + height: 100vh; + max-width: 100%; } body { - background-color: #F5F5F5; + background-color: #f5f5f5; } main { - padding: 1.5rem; - margin: auto; - background-color: #EEEEEE; - min-height: 100%; + padding: 1.5rem; + margin: auto; + background-color: #eeeeee; + min-height: 100%; } h1 { - margin-bottom: .5em; -} - -table{ - border-collapse: collapse; - width:100%; - font-size: .9em; + margin-bottom: 0.5em; } @media only screen and (min-width: 768px) { - main { - max-width: 42rem; - } - table{ - font-size:inherit; - } + main { + max-width: 42rem; + } +} + +.main { + text-align: center; + font-size: 2em; +} + +.main > span { + line-height: 1.5em; +} + +#question { + font-weight: bold; +} + +#answer { + color: #616161; +} + +.button-container { + text-align: center; +} + +.button { + font-size: 1.5em; + width: 6em; + height: 2.3em; + text-align: center; + padding: 0; + margin: 0.2em; + border: 1px solid #424242; + border-radius: 0.1em; + display: inline-block; + line-height: 2em; + cursor: pointer; + background-color: #fafafa; + color: #424242; + user-select: none; +} + +.button.long { + width: 12em; +} + +.button.right { + background-color: #8bc34a; + color: #eeeeee; +} + +.button.wrong { + background-color: #e53935; + color: #eeeeee; +} + +.button:active { + background-color: #757575; + color: #eeeeee; +} + +.button.right:active { + background-color: #558b2f; + color: #eeeeee; +} + +.button.wrong:active { + background-color: #c62828; + color: #eeeeee; +} + +@media (hover: hover) { + .button:hover { + background-color: #e0e0e0; + color: #424242; + } + + .button.right:hover { + background-color: #7cb342; + color: #eeeeee; + } + + .button.wrong:hover { + background-color: #d32f2f; + color: #eeeeee; + } +} + +table.config { + border-collapse: collapse; +} + +table.config td { + padding: 0.2em; + max-width: 30%; +} + +table.config td button { + width: 100%; +} + +table.config td input { + width: 15em; +} + +.expand { + cursor: pointer; + user-select: none; }