From 8e0a40079cd4f15c1ec82c6ee3b0d4b96af24b80 Mon Sep 17 00:00:00 2001 From: montylion Date: Sun, 22 Aug 2021 16:37:51 +0200 Subject: [PATCH 1/6] Add auto locale detection and custom locale selection (preference saved to cookie) --- package-lock.json | 33 +++++++++++++++++++++ package.json | 2 ++ public/assets/css/main.css | 3 ++ public/assets/js/locale-dropdown-handler.js | 11 +++++++ src/routers/home.js | 8 +++-- src/routers/progress.js | 10 +++++-- src/server.js | 23 ++++++++++++++ views/layouts/main.handlebars | 3 ++ views/partials/header.handlebars | 7 +++++ 9 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 public/assets/js/locale-dropdown-handler.js diff --git a/package-lock.json b/package-lock.json index e0a5d6b..ae41cbf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,10 @@ "license": "ISC", "dependencies": { "colors": "^1.4.0", + "cookie-parser": "^1.4.5", "express": "^4.17.1", "express-handlebars": "^4.0.4", + "express-locale": "^2.0.0", "fs-extra": "^9.1.0", "ioredis": "^4.26.0", "morgan": "^1.10.0", @@ -156,6 +158,18 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", + "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", + "dependencies": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -287,6 +301,11 @@ "node": ">=0.10" } }, + "node_modules/express-locale": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/express-locale/-/express-locale-2.0.0.tgz", + "integrity": "sha512-SUwsgOTV8lplAkgyfKSwKH3ZVSKUrAa+b48acPGXpwWX211WZ/BYWX2WcZO57+xLOqPYb6rSNpWCFnhGrt0moA==" + }, "node_modules/finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -1114,6 +1133,15 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" }, + "cookie-parser": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", + "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", + "requires": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6" + } + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -1224,6 +1252,11 @@ "promise": "^8.1.0" } }, + "express-locale": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/express-locale/-/express-locale-2.0.0.tgz", + "integrity": "sha512-SUwsgOTV8lplAkgyfKSwKH3ZVSKUrAa+b48acPGXpwWX211WZ/BYWX2WcZO57+xLOqPYb6rSNpWCFnhGrt0moA==" + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", diff --git a/package.json b/package.json index 1ccbbd2..cb99e41 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,10 @@ "homepage": "https://github.com/PretendoNetwork/website#readme", "dependencies": { "colors": "^1.4.0", + "cookie-parser": "^1.4.5", "express": "^4.17.1", "express-handlebars": "^4.0.4", + "express-locale": "^2.0.0", "fs-extra": "^9.1.0", "ioredis": "^4.26.0", "morgan": "^1.10.0", diff --git a/public/assets/css/main.css b/public/assets/css/main.css index c659843..347bd49 100644 --- a/public/assets/css/main.css +++ b/public/assets/css/main.css @@ -80,6 +80,9 @@ header nav a { text-decoration: none; } +.locale-dropdown { + margin-left: auto; +} /* Misc */ .purple-circle { diff --git a/public/assets/js/locale-dropdown-handler.js b/public/assets/js/locale-dropdown-handler.js new file mode 100644 index 0000000..a3b561c --- /dev/null +++ b/public/assets/js/locale-dropdown-handler.js @@ -0,0 +1,11 @@ +function setFormDefaultLocale(localeString) { + try { + document.querySelector(`option[value=${localeString}`).selected = true; + } catch {} // If the locale isn't listed +} + +function localeFormHandler() { + const selectedLocale = document.querySelector("#locale-dropdown").value; + document.cookie = `preferredLocale=${selectedLocale};max-age=31536000`; + window.location.reload(); +} diff --git a/src/routers/home.js b/src/routers/home.js index 84dba26..8d02c6b 100644 --- a/src/routers/home.js +++ b/src/routers/home.js @@ -5,12 +5,16 @@ const router = new Router(); const { getTrelloCache } = require('../trello'); router.get('/', async (request, response) => { - const tmpLocale = util.getLocale('US', 'en'); + + const reqLocale = request.locale + const locale = util.getLocale(reqLocale.region, reqLocale.language); + const cache = await getTrelloCache(); response.render('home', { layout: 'main', - locale: tmpLocale, + locale, + localeString: reqLocale.toString(), featuredFeatureList: cache.sections[0] }); }); diff --git a/src/routers/progress.js b/src/routers/progress.js index 6d590f4..b7ed205 100644 --- a/src/routers/progress.js +++ b/src/routers/progress.js @@ -5,12 +5,18 @@ const router = new Router(); const { getTrelloCache } = require('../trello'); router.get('/', async (request, response) => { - const tmpLocale = util.getLocale('US', 'en'); + + const reqLocale = request.locale + const locale = util.getLocale(reqLocale.region, reqLocale.language); + + const localeString = reqLocale.toString() + const cache = await getTrelloCache(); response.render('progress', { layout: 'main', - locale: tmpLocale, + locale, + localeString, progressLists: cache }); }); diff --git a/src/server.js b/src/server.js index 9136623..ae3e41d 100644 --- a/src/server.js +++ b/src/server.js @@ -3,6 +3,8 @@ process.title = 'Pretendo - Website'; const express = require('express'); const handlebars = require('express-handlebars'); const morgan = require('morgan'); +const expressLocale = require('express-locale'); +const cookieParser = require('cookie-parser') const logger = require('./logger'); const util = require('./util'); const config = require('../config.json'); @@ -23,6 +25,27 @@ const routers = { progress: require('./routers/progress') }; +app.use(cookieParser()) + +// Locale express middleware setup +app.use(expressLocale({ + "priority": ["cookie", "accept-language", "map", "default"], + cookie: {name: 'preferredLocale'}, + // fallbacks for browsers that don't send a region code, but only a language + map: { + de: 'de-DE', + es: 'es-ES', + fr: 'fr-FR', + it: 'it-IT', + ko: 'ko-KR', + ru: 'ru-RU', + }, + "default": "en-US" +})) + + + + app.use('/', routers.home); app.use('/faq', routers.faq); app.use('/progress', routers.progress); diff --git a/views/layouts/main.handlebars b/views/layouts/main.handlebars index 267ebab..fac0f27 100644 --- a/views/layouts/main.handlebars +++ b/views/layouts/main.handlebars @@ -40,5 +40,8 @@ + + + \ No newline at end of file diff --git a/views/partials/header.handlebars b/views/partials/header.handlebars index 384efe3..cda76c7 100644 --- a/views/partials/header.handlebars +++ b/views/partials/header.handlebars @@ -30,4 +30,11 @@ {{ locale.nav.credits }} {{ locale.nav.progress }} + + + \ No newline at end of file From 84b1e09bc631363e61ede11dd8cfac3c0ab04cd2 Mon Sep 17 00:00:00 2001 From: montylion Date: Sun, 22 Aug 2021 18:56:54 +0200 Subject: [PATCH 2/6] Update function names for consistency --- public/assets/js/locale-dropdown-handler.js | 4 ++-- views/layouts/main.handlebars | 2 +- views/partials/header.handlebars | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/assets/js/locale-dropdown-handler.js b/public/assets/js/locale-dropdown-handler.js index a3b561c..6ed72cb 100644 --- a/public/assets/js/locale-dropdown-handler.js +++ b/public/assets/js/locale-dropdown-handler.js @@ -1,10 +1,10 @@ -function setFormDefaultLocale(localeString) { +function setDefaultDropdownLocale(localeString) { try { document.querySelector(`option[value=${localeString}`).selected = true; } catch {} // If the locale isn't listed } -function localeFormHandler() { +function localeDropdownHandler() { const selectedLocale = document.querySelector("#locale-dropdown").value; document.cookie = `preferredLocale=${selectedLocale};max-age=31536000`; window.location.reload(); diff --git a/views/layouts/main.handlebars b/views/layouts/main.handlebars index fac0f27..e49b00e 100644 --- a/views/layouts/main.handlebars +++ b/views/layouts/main.handlebars @@ -41,7 +41,7 @@ - + \ No newline at end of file diff --git a/views/partials/header.handlebars b/views/partials/header.handlebars index cda76c7..0731b40 100644 --- a/views/partials/header.handlebars +++ b/views/partials/header.handlebars @@ -31,7 +31,7 @@ {{ locale.nav.progress }} - From d0dd10519bd6b70069170407b8bf084560c77648 Mon Sep 17 00:00:00 2001 From: montylion Date: Sun, 22 Aug 2021 21:37:45 +0200 Subject: [PATCH 3/6] Added dropdown menu by @mrjvs Co-Authored-By: mrjvs --- public/assets/css/dropdown.css | 93 +++++++++++++++++++++ public/assets/css/main.css | 15 +++- public/assets/icons/down-arrow.svg | 1 + public/assets/js/locale-dropdown-handler.js | 59 +++++++++++-- views/layouts/main.handlebars | 9 ++ views/partials/header.handlebars | 38 +++++++-- 6 files changed, 201 insertions(+), 14 deletions(-) create mode 100644 public/assets/css/dropdown.css create mode 100644 public/assets/icons/down-arrow.svg diff --git a/public/assets/css/dropdown.css b/public/assets/css/dropdown.css new file mode 100644 index 0000000..edf782a --- /dev/null +++ b/public/assets/css/dropdown.css @@ -0,0 +1,93 @@ +.select-box { + display: flex; + width: 200px; + flex-direction: column; + position: relative; +} + +.select-box > * { + box-sizing: border-box; +} + +.select-box .options-container { + max-height: 0; + width: calc(100% - 12px); + opacity: 0; + transition: all 0.4s; + overflow: hidden; + border-radius: 5px; + background-color: var(--btn-secondary); + order: 1; + position: absolute; + top: 50px; +} + +.selected-locale { + margin-bottom: 8px; + position: relative; + width: 188px; + height: 45px; + border-radius: 5px; + display: flex; + align-items: center; + background-color: var(--btn-secondary); + color: white; + order: 0; +} + +.selected-locale::after { + content: url("/assets/icons/down-arrow.svg"); + position: absolute; + right: 15px; + top: 50%; + transition: transform 150ms; + transform: translateY(-50%); +} + +.select-box .option .item { + color: #afb5dd; +} + +.select-box .options-container.active { + max-height: 240px; + opacity: 1; + overflow-y: scroll; +} + +.select-box .options-container.active + .selected-locale::after { + transform: translateY(-50%) rotateX(180deg); +} + +.select-box .options-container::-webkit-scrollbar { + width: 8px; + background: #0d141f; + background: #81878f; + background: #f1f2f3; + border-radius: 0 5px 5px 0; +} + +.select-box .options-container::-webkit-scrollbar-thumb { + background: #525861; + background: #81878f; + border-radius: 0 5px 5px 0; +} +.select-box .option, +.selected-locale { + padding: 12px 15px; + cursor: pointer; +} + +.select-box .option:hover { + background: #2f345b; +} +.select-box .option:hover .item { + color: white; +} + +.select-box label { + cursor: pointer; +} + +.select-box .option .radio { + display: none; +} diff --git a/public/assets/css/main.css b/public/assets/css/main.css index 347bd49..2f0eb88 100644 --- a/public/assets/css/main.css +++ b/public/assets/css/main.css @@ -4,6 +4,7 @@ --text: white; --text-secondary: #A1A8D9; --btn: #673DB6; + --btn-secondary: #333960; --theme: var(--btn); --text-secondary-2: #8990C1; } @@ -82,6 +83,7 @@ header nav a { .locale-dropdown { margin-left: auto; + z-index: 2; } /* Misc */ @@ -117,7 +119,7 @@ header nav a { left: 50%; transform: translate(-50%, -50%); margin-left: -40px; - z-index: 3; + z-index: 1; } .light-purple-circle .deco { position: absolute; @@ -127,6 +129,15 @@ header nav a { z-index: -2; } +/* Twemoji */ + +img.emoji { + height: 1em; + width: 1em; + margin: 0 .05em 0 .1em; + vertical-align: -0.1em; + } + /* Title business */ .sect .title[id] { padding-top: 100px; @@ -220,7 +231,7 @@ header nav a { background: var(--btn); } .button.secondary { - background: #333960; + background: var(--btn-secondary); } .button.secondary.discord svg { margin-bottom: -1px; diff --git a/public/assets/icons/down-arrow.svg b/public/assets/icons/down-arrow.svg new file mode 100644 index 0000000..619f62a --- /dev/null +++ b/public/assets/icons/down-arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/js/locale-dropdown-handler.js b/public/assets/js/locale-dropdown-handler.js index 6ed72cb..7e8dc6d 100644 --- a/public/assets/js/locale-dropdown-handler.js +++ b/public/assets/js/locale-dropdown-handler.js @@ -1,11 +1,56 @@ function setDefaultDropdownLocale(localeString) { - try { - document.querySelector(`option[value=${localeString}`).selected = true; - } catch {} // If the locale isn't listed + const selected = document.querySelector(".selected-locale"); + selected.innerHTML = document.querySelector(`label[for=${localeString}`).innerHTML } -function localeDropdownHandler() { - const selectedLocale = document.querySelector("#locale-dropdown").value; - document.cookie = `preferredLocale=${selectedLocale};max-age=31536000`; - window.location.reload(); +function localeDropdownHandler(selectedLocale) { + document.cookie = `preferredLocale=${selectedLocale};max-age=31536000`; + window.location.reload(); } + +const dropdowns = document.querySelectorAll("*[data-dropdown]"); +const dropdownOptions = document.querySelectorAll( + "*[data-dropdown] .options-container" +); + +dropdowns.forEach((el) => { + const selected = el.querySelector(".selected-locale"); + const optionsContainer = el.querySelector(".options-container"); + const optionsList = el.querySelectorAll(".option"); + + // click dropdown element will open dropdown + selected.addEventListener("click", () => { + optionsContainer.classList.toggle("active"); + }); + + // clicking on any option will close dropdown and change value + optionsList.forEach((option) => { + option.addEventListener("click", () => { + selected.innerHTML = option.querySelector("label").innerHTML; + optionsContainer.classList.remove("active"); + const selectedLocale = option.querySelector("label").getAttribute("for"); + localeDropdownHandler(selectedLocale); + }); + }); +}); + +// close all dropdowns on scroll +document.addEventListener("scroll", () => { + dropdownOptions.forEach((el) => el.classList.remove("active")); +}); + +// click outside of dropdown will close all dropdowns +document.addEventListener("click", (e) => { + const targetElement = e.target; + + // check if target is from a dropdown + let found = false; + dropdowns.forEach((v) => { + if (v == targetElement || v.contains(targetElement)) found = true; + }); + + if (found) return; + + // click outside of dropdowns + dropdownOptions.forEach((el) => el.classList.remove("active")); +}); diff --git a/views/layouts/main.handlebars b/views/layouts/main.handlebars index e49b00e..eb50001 100644 --- a/views/layouts/main.handlebars +++ b/views/layouts/main.handlebars @@ -28,11 +28,20 @@ Pretendo + + + + +
diff --git a/views/partials/header.handlebars b/views/partials/header.handlebars index 0731b40..fbfbd4d 100644 --- a/views/partials/header.handlebars +++ b/views/partials/header.handlebars @@ -31,10 +31,38 @@ {{ locale.nav.progress }} - +
+
+
+ + +
+ +
+ + +
+ +
+ + +
+
+ + +
+
+
+
English
+
+
\ No newline at end of file From 2bf633e1277ff94fff9762550f820d8dcec110f7 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Sun, 22 Aug 2021 21:58:07 +0200 Subject: [PATCH 4/6] layout shift fix + centered chevron --- public/assets/css/dropdown.css | 16 ++++++++++++++-- views/partials/header.handlebars | 10 +++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/public/assets/css/dropdown.css b/public/assets/css/dropdown.css index edf782a..99dce10 100644 --- a/public/assets/css/dropdown.css +++ b/public/assets/css/dropdown.css @@ -36,22 +36,34 @@ } .selected-locale::after { - content: url("/assets/icons/down-arrow.svg"); + content: ""; + width: 1.2rem; + height: 1.2rem; + background: url("/assets/icons/down-arrow.svg"); position: absolute; right: 15px; top: 50%; transition: transform 150ms; transform: translateY(-50%); + background-size: contain; + background-position: center; } .select-box .option .item { color: #afb5dd; } +.select-box .lang { + width: 1.3rem; + height: 1rem; + margin-right: .2rem; + display: inline-block; +} + .select-box .options-container.active { max-height: 240px; opacity: 1; - overflow-y: scroll; + overflow-y: auto; } .select-box .options-container.active + .selected-locale::after { diff --git a/views/partials/header.handlebars b/views/partials/header.handlebars index fbfbd4d..a032235 100644 --- a/views/partials/header.handlebars +++ b/views/partials/header.handlebars @@ -36,32 +36,32 @@
-
English
+
From 59904bea790bb80b8035df257ffc28d63e0115c3 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Sun, 22 Aug 2021 22:00:13 +0200 Subject: [PATCH 5/6] disallow selecting dropdown --- public/assets/css/dropdown.css | 1 + 1 file changed, 1 insertion(+) diff --git a/public/assets/css/dropdown.css b/public/assets/css/dropdown.css index 99dce10..1d842fa 100644 --- a/public/assets/css/dropdown.css +++ b/public/assets/css/dropdown.css @@ -3,6 +3,7 @@ width: 200px; flex-direction: column; position: relative; + user-select: none; } .select-box > * { From 6ff919b2fb432b1d6a2e7e1b3882ff5e14114faf Mon Sep 17 00:00:00 2001 From: montylion Date: Sun, 22 Aug 2021 22:10:21 +0200 Subject: [PATCH 6/6] Add Turkish locale to dropdown --- src/server.js | 1 + views/partials/header.handlebars | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/server.js b/src/server.js index ae3e41d..24cf770 100644 --- a/src/server.js +++ b/src/server.js @@ -39,6 +39,7 @@ app.use(expressLocale({ it: 'it-IT', ko: 'ko-KR', ru: 'ru-RU', + tr: 'tr-TR' }, "default": "en-US" })) diff --git a/views/partials/header.handlebars b/views/partials/header.handlebars index a032235..de64dbf 100644 --- a/views/partials/header.handlebars +++ b/views/partials/header.handlebars @@ -59,6 +59,12 @@
🇷🇺Pусский
+
+ + +