mirror of
https://github.com/PretendoNetwork/website.git
synced 2026-04-24 15:37:12 -05:00
feat: add user popout to navbar
This commit is contained in:
parent
0fe9aabaae
commit
f1c18efe35
|
|
@ -79,27 +79,6 @@
|
|||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1064px) {
|
||||
.selected-locale .locale-names {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.selected-locale {
|
||||
width: 80px;
|
||||
margin-left: auto;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.locale-dropdown {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.select-box .options-container {
|
||||
width: 150px;
|
||||
right: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 946px) {
|
||||
header nav a:not(.keep-on-mobile) {
|
||||
display: none;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
.select-box {
|
||||
display: flex;
|
||||
width: 188px;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
|
|
@ -12,7 +11,7 @@
|
|||
|
||||
.select-box .options-container {
|
||||
max-height: 0;
|
||||
width: 100%;
|
||||
width: fit-content;
|
||||
opacity: 0;
|
||||
transition: all 0.4s;
|
||||
overflow: hidden;
|
||||
|
|
@ -20,34 +19,8 @@
|
|||
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: "";
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
background: url("/assets/images/down-arrow.svg");
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 50%;
|
||||
transition: transform 150ms;
|
||||
transform: translateY(-50%);
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
top: 48px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.select-box .option .item {
|
||||
|
|
@ -67,25 +40,21 @@
|
|||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.select-box .options-container.active + .selected-locale::after {
|
||||
.select-box .options-container.active + .locale-dropdown-toggle::after {
|
||||
transform: translateY(-50%) rotateX(180deg);
|
||||
}
|
||||
|
||||
.select-box .options-container::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
background: #0d141f;
|
||||
background: #81878f;
|
||||
background: #f1f2f3;
|
||||
background: var(--btn-secondary);
|
||||
border-radius: 0 5px 5px 0;
|
||||
}
|
||||
|
||||
.select-box .options-container::-webkit-scrollbar-thumb {
|
||||
background: #525861;
|
||||
background: #81878f;
|
||||
background: var(--text-secondary);
|
||||
border-radius: 0 5px 5px 0;
|
||||
}
|
||||
.select-box .option,
|
||||
.selected-locale {
|
||||
.select-box .option {
|
||||
padding: 12px 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,10 +94,108 @@ header nav a:hover {
|
|||
transition: color 50ms ease-in-out;
|
||||
}
|
||||
|
||||
.locale-dropdown {
|
||||
header .right-section {
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-gap: 24px;
|
||||
margin-left: auto;
|
||||
z-index: 2;
|
||||
height: 45px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
header .locale-dropdown-toggle {
|
||||
width: fit-content;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: auto;
|
||||
transition: color 150ms;
|
||||
cursor: pointer;
|
||||
}
|
||||
header .locale-dropdown-toggle:hover,
|
||||
header .locale-dropdown-toggle.active {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
header .user-widget-wrapper {
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
header .user-widget-wrapper a.login-link {
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
transition: color 150ms;
|
||||
}
|
||||
header .user-widget-wrapper a.login-link:hover {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
header .user-widget-wrapper.logged-in {
|
||||
position: relative;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
header .user-widget-wrapper.logged-in .user-widget-toggle {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: var(--text-secondary-2);
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
}
|
||||
header .user-widget-wrapper .user-widget-toggle img,
|
||||
header .user-widget .user-avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
header .user-widget {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
|
||||
box-sizing: border-box;
|
||||
transition: max-height 300ms, padding 200ms, opacity 150ms;
|
||||
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 48px;
|
||||
padding: 0;
|
||||
background: #2a2f50;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
|
||||
box-shadow: 0 0 10px -2px #111531;
|
||||
}
|
||||
header .user-widget.active {
|
||||
max-height: 100vh;
|
||||
padding: 36px;
|
||||
opacity: 1;
|
||||
}
|
||||
header .user-widget .user-avatar {
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
margin: auto;
|
||||
background: var(--text-secondary-2);
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
header .user-widget .user-info {
|
||||
margin-top: 12px;
|
||||
}
|
||||
header .user-widget .user-info .mii-name {
|
||||
color: var(--text);
|
||||
}
|
||||
header .user-widget .buttons {
|
||||
margin-top: 12px;
|
||||
}
|
||||
header .user-widget .button {
|
||||
margin-top: 12px;
|
||||
width: 100%;
|
||||
padding: 8px 60px;
|
||||
cursor: pointer;
|
||||
}
|
||||
header .user-widget .button.logout {
|
||||
background: #383f6b;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* Misc */
|
||||
|
|
@ -1118,25 +1216,6 @@ footer div.discord-server-card svg {
|
|||
margin: auto !important;
|
||||
}
|
||||
|
||||
.selected-locale .locale-names {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.selected-locale {
|
||||
width: 80px;
|
||||
margin-left: auto;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.locale-dropdown {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.select-box .options-container {
|
||||
width: 150px;
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
footer {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: repeat(4, fit-content(100%));
|
||||
|
|
@ -1168,13 +1247,3 @@ footer div.discord-server-card svg {
|
|||
margin: 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 330px) {
|
||||
.locale-dropdown .selected-locale {
|
||||
width: 50px;
|
||||
}
|
||||
.locale-dropdown .selected-locale::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
85
public/assets/js/header-handler.js
Normal file
85
public/assets/js/header-handler.js
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/* eslint-disable no-undef, no-unused-vars */
|
||||
|
||||
// Account widget handler
|
||||
const userWidgetToggle = document.querySelector('.user-widget-toggle') ;
|
||||
const userWidget = document.querySelector('.user-widget');
|
||||
|
||||
// Open widget on click, close locale dropdown
|
||||
userWidgetToggle?.addEventListener('click', () => {
|
||||
userWidget.classList.toggle('active');
|
||||
localeOptionsContainer.classList.toggle('active');
|
||||
localeDropdownToggle.classList.toggle('active');
|
||||
});
|
||||
|
||||
// Locale dropdown handler
|
||||
function localeDropdownHandler(selectedLocale) {
|
||||
document.cookie = `preferredLocale=${selectedLocale};max-age=31536000`;
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
const localeDropdown = document.querySelector(
|
||||
'.locale-dropdown[data-dropdown]'
|
||||
);
|
||||
const localeDropdownOptions = document.querySelectorAll(
|
||||
'.locale-dropdown[data-dropdown] .options-container'
|
||||
);
|
||||
const localeDropdownToggle = document.querySelector('.locale-dropdown-toggle');
|
||||
|
||||
const localeOptionsContainer = localeDropdown.querySelector('.options-container');
|
||||
const localeOptionsList = localeDropdown.querySelectorAll('.option');
|
||||
|
||||
// click dropdown element will open dropdown
|
||||
localeDropdownToggle.addEventListener('click', () => {
|
||||
localeOptionsContainer.classList.toggle('active');
|
||||
localeDropdownToggle.classList.toggle('active');
|
||||
});
|
||||
|
||||
// clicking on any option will close dropdown and change value
|
||||
localeOptionsList.forEach((option) => {
|
||||
option.addEventListener('click', () => {
|
||||
localeDropdownToggle.classList.remove('active');
|
||||
localeOptionsContainer.classList.remove('active');
|
||||
const selectedLocale = option.querySelector('label').getAttribute('for');
|
||||
localeDropdownHandler(selectedLocale);
|
||||
});
|
||||
});
|
||||
|
||||
// close all dropdowns on scroll
|
||||
document.addEventListener('scroll', () => {
|
||||
localeDropdownOptions.forEach((el) => el.classList.remove('active'));
|
||||
localeDropdownToggle.classList.remove('active');
|
||||
|
||||
userWidget.classList.remove('active');
|
||||
});
|
||||
|
||||
// click outside of dropdown will close all dropdowns
|
||||
document.addEventListener('click', (e) => {
|
||||
const targetElement = e.target;
|
||||
|
||||
let found = false;
|
||||
if (
|
||||
localeDropdown == targetElement ||
|
||||
localeDropdown.contains(targetElement)
|
||||
) {
|
||||
found = true;
|
||||
userWidget.classList.remove('active');
|
||||
}
|
||||
|
||||
if (
|
||||
userWidget == targetElement ||
|
||||
userWidget.contains(targetElement) ||
|
||||
userWidgetToggle == targetElement ||
|
||||
userWidgetToggle.contains(targetElement)
|
||||
) {
|
||||
found = true;
|
||||
localeDropdownToggle.classList.remove('active');
|
||||
localeOptionsContainer.classList.remove('active');
|
||||
}
|
||||
|
||||
if (found) return;
|
||||
|
||||
// click outside of dropdowns
|
||||
userWidget.classList.remove('active');
|
||||
localeDropdownToggle.classList.remove('active');
|
||||
localeOptionsContainer.classList.remove('active');
|
||||
});
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
/* eslint-disable no-undef, no-unused-vars */
|
||||
function setDefaultDropdownLocale(localeString) {
|
||||
try {
|
||||
const selected = document.querySelector('.selected-locale');
|
||||
let item = document.querySelector(`label[for=${localeString}`);
|
||||
if (!item) { // if locale can't be found, default to en-US
|
||||
localeString = 'en-US';
|
||||
item = document.querySelector(`label[for=${localeString}`);
|
||||
}
|
||||
selected.innerHTML = item.innerHTML;
|
||||
} catch (e) {} // If it errors it's probably because there isn't a navbar in the view
|
||||
}
|
||||
|
||||
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'));
|
||||
});
|
||||
|
|
@ -193,6 +193,8 @@ router.get('/', async (request, response) => {
|
|||
renderData.discordAuthURL = discordAuthURL;
|
||||
}
|
||||
|
||||
renderData.isLoggedIn = request.cookies.access_token && request.cookies.refresh_token && request.cookies.ph;
|
||||
|
||||
response.render('account/account', renderData);
|
||||
});
|
||||
|
||||
|
|
@ -297,6 +299,15 @@ router.post('/register', async (request, response) => {
|
|||
response.redirect('/account');
|
||||
});
|
||||
|
||||
router.get('/logout', async(_request, response) => {
|
||||
response.clearCookie('refresh_token', { domain: '.pretendo.network' });
|
||||
response.clearCookie('access_token', { domain: '.pretendo.network' });
|
||||
response.clearCookie('token_type', { domain: '.pretendo.network' });
|
||||
response.clearCookie('ph', { domain: '.pretendo.network' });
|
||||
|
||||
response.redirect('/');
|
||||
});
|
||||
|
||||
router.get('/connect/discord', async (request, response) => {
|
||||
let tokens;
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -4,14 +4,20 @@ const router = new Router();
|
|||
|
||||
router.get('/', async (request, response) => {
|
||||
|
||||
const reqLocale = request.locale;
|
||||
const locale = util.getLocale(reqLocale.region, reqLocale.language);
|
||||
|
||||
response.render('aprilfools', {
|
||||
const renderData = {
|
||||
layout: 'main',
|
||||
locale,
|
||||
localeString: reqLocale.toString(),
|
||||
});
|
||||
locale: util.getLocale(request.locale.region, request.locale.language),
|
||||
localeString: request.locale.toString(),
|
||||
};
|
||||
|
||||
renderData.isLoggedIn = request.cookies.access_token && request.cookies.refresh_token && request.cookies.ph;
|
||||
|
||||
if (renderData.isLoggedIn) {
|
||||
const account = await util.getAccount(request, response);
|
||||
renderData.account = account;
|
||||
}
|
||||
|
||||
response.render('aprilfools', renderData);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
|
|
@ -36,18 +36,21 @@ const postList = () => {
|
|||
};
|
||||
|
||||
router.get('/', async (request, response) => {
|
||||
|
||||
const reqLocale = request.locale;
|
||||
const locale = util.getLocale(reqLocale.region, reqLocale.language);
|
||||
|
||||
const localeString = reqLocale.toString();
|
||||
|
||||
response.render('blog/blog', {
|
||||
const renderData = {
|
||||
layout: 'main',
|
||||
locale,
|
||||
localeString,
|
||||
postList
|
||||
});
|
||||
locale: util.getLocale(request.locale.region, request.locale.language),
|
||||
localeString: request.locale.toString(),
|
||||
postList,
|
||||
};
|
||||
|
||||
renderData.isLoggedIn = request.cookies.access_token && request.cookies.refresh_token && request.cookies.ph;
|
||||
|
||||
if (renderData.isLoggedIn) {
|
||||
const account = await util.getAccount(request, response);
|
||||
renderData.account = account;
|
||||
}
|
||||
|
||||
response.render('blog/blog', renderData);
|
||||
});
|
||||
|
||||
// RSS feed
|
||||
|
|
@ -69,10 +72,19 @@ router.get('/feed.xml', async (request, response) => {
|
|||
|
||||
router.get('/:slug', async (request, response, next) => {
|
||||
|
||||
const reqLocale = request.locale;
|
||||
const locale = util.getLocale(reqLocale.region, reqLocale.language);
|
||||
const renderData = {
|
||||
layout: 'blog-opengraph',
|
||||
locale: util.getLocale(request.locale.region, request.locale.language),
|
||||
localeString: request.locale.toString(),
|
||||
postList,
|
||||
};
|
||||
|
||||
const localeString = reqLocale.toString();
|
||||
renderData.isLoggedIn = request.cookies.access_token && request.cookies.refresh_token && request.cookies.ph;
|
||||
|
||||
if (renderData.isLoggedIn) {
|
||||
const account = await util.getAccount(request, response);
|
||||
renderData.account = account;
|
||||
}
|
||||
|
||||
// Get the name of the post from the URL
|
||||
const postName = request.params.slug;
|
||||
|
|
@ -89,6 +101,7 @@ router.get('/:slug', async (request, response, next) => {
|
|||
// Convert the post info into JSON and separate it and the content
|
||||
// eslint-disable-next-line prefer-const
|
||||
let { data: postInfo, content } = matter(rawPost);
|
||||
renderData.postInfo = postInfo;
|
||||
|
||||
// Replace [yt-iframe](videoID) with the full <iframe />
|
||||
content = content
|
||||
|
|
@ -97,14 +110,9 @@ router.get('/:slug', async (request, response, next) => {
|
|||
|
||||
// Convert the content into HTML
|
||||
const htmlPost = marked.parse(content);
|
||||
renderData.htmlPost = htmlPost;
|
||||
|
||||
response.render('blog/blogpost', {
|
||||
layout: 'blog-opengraph',
|
||||
locale,
|
||||
localeString,
|
||||
postInfo,
|
||||
htmlPost,
|
||||
});
|
||||
response.render('blog/blogpost', renderData);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
|
|
@ -11,32 +11,45 @@ router.get('/', async (request, response) => {
|
|||
});
|
||||
|
||||
router.get('/search', async (request, response) => {
|
||||
const reqLocale = request.locale;
|
||||
const locale = util.getLocale(reqLocale.region, reqLocale.language);
|
||||
|
||||
const localeString = reqLocale.toString();
|
||||
|
||||
response.render('docs/search', {
|
||||
const renderData = {
|
||||
layout: 'main',
|
||||
locale,
|
||||
localeString,
|
||||
locale: util.getLocale(request.locale.region, request.locale.language),
|
||||
localeString: request.locale.toString(),
|
||||
currentPage: request.params.slug,
|
||||
});
|
||||
};
|
||||
|
||||
renderData.isLoggedIn = request.cookies.access_token && request.cookies.refresh_token && request.cookies.ph;
|
||||
|
||||
if (renderData.isLoggedIn) {
|
||||
const account = await util.getAccount(request, response);
|
||||
renderData.account = account;
|
||||
}
|
||||
|
||||
response.render('docs/search', renderData);
|
||||
});
|
||||
|
||||
router.get('/:slug', async (request, response, next) => {
|
||||
const reqLocale = request.locale;
|
||||
const locale = util.getLocale(reqLocale.region, reqLocale.language);
|
||||
const renderData = {
|
||||
layout: 'main',
|
||||
locale: util.getLocale(request.locale.region, request.locale.language),
|
||||
localeString: request.locale.toString(),
|
||||
currentPage: request.params.slug,
|
||||
};
|
||||
|
||||
const localeString = reqLocale.toString();
|
||||
renderData.isLoggedIn = request.cookies.access_token && request.cookies.refresh_token && request.cookies.ph;
|
||||
|
||||
if (renderData.isLoggedIn) {
|
||||
const account = await util.getAccount(request, response);
|
||||
renderData.account = account;
|
||||
}
|
||||
|
||||
// Get the name of the page from the URL
|
||||
const pageName = request.params.slug;
|
||||
|
||||
let markdownLocale = localeString;
|
||||
let markdownLocale = renderData.localeString;
|
||||
let missingInLocale = false;
|
||||
// Check if the MD file exists in the user's locale, if not try en-US and show notice, or finally log error and show 404.
|
||||
if (fs.existsSync(path.join('docs', localeString, `${pageName}.md`))) {
|
||||
if (fs.existsSync(path.join('docs', renderData.localeString, `${pageName}.md`))) {
|
||||
null;
|
||||
} else if (fs.existsSync(path.join('docs', 'en-US', `${pageName}.md`))) {
|
||||
markdownLocale = 'en-US';
|
||||
|
|
@ -45,6 +58,7 @@ router.get('/:slug', async (request, response, next) => {
|
|||
next();
|
||||
return;
|
||||
}
|
||||
renderData.missingInLocale = missingInLocale;
|
||||
|
||||
let content;
|
||||
// Get the markdown file corresponding to the page.
|
||||
|
|
@ -57,22 +71,16 @@ router.get('/:slug', async (request, response, next) => {
|
|||
|
||||
// Convert the content into HTML
|
||||
content = marked.parse(content);
|
||||
renderData.content = content;
|
||||
|
||||
// A boolean to show the quick links grid or not.
|
||||
let showQuickLinks = false;
|
||||
if (pageName === 'welcome') {
|
||||
showQuickLinks = true;
|
||||
}
|
||||
renderData.showQuickLinks = showQuickLinks;
|
||||
|
||||
response.render('docs/docs', {
|
||||
layout: 'main',
|
||||
locale,
|
||||
localeString,
|
||||
content,
|
||||
currentPage: request.params.slug,
|
||||
missingInLocale,
|
||||
showQuickLinks
|
||||
});
|
||||
response.render('docs/docs', renderData);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
|
|
@ -7,15 +7,26 @@ const { getTrelloCache } = require('../trello');
|
|||
|
||||
router.get('/', async (request, response) => {
|
||||
|
||||
const reqLocale = request.locale;
|
||||
const locale = util.getLocale(reqLocale.region, reqLocale.language);
|
||||
|
||||
const renderData = {
|
||||
layout: 'main',
|
||||
boards,
|
||||
locale: util.getLocale(request.locale.region, request.locale.language),
|
||||
localeString: request.locale.toString(),
|
||||
};
|
||||
|
||||
renderData.isLoggedIn = request.cookies.access_token && request.cookies.refresh_token && request.cookies.ph;
|
||||
|
||||
if (renderData.isLoggedIn) {
|
||||
const account = await util.getAccount(request, response);
|
||||
renderData.account = account;
|
||||
}
|
||||
|
||||
const cache = await getTrelloCache();
|
||||
|
||||
// Builds the arrays of people for the special thanks section
|
||||
|
||||
// Shuffles the special thanks people
|
||||
let specialThanksPeople = locale.specialThanks.people.slice();
|
||||
const specialThanksPeople = renderData.locale.specialThanks.people.slice();
|
||||
function shuffleArray(array) {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
|
|
@ -29,7 +40,7 @@ router.get('/', async (request, response) => {
|
|||
const specialThanksSecondRow = specialThanksPeople.slice(3, 7);
|
||||
|
||||
// Builds the final array to be sent to the view, and triples each row.
|
||||
specialThanksPeople = {
|
||||
renderData.specialThanksPeople = {
|
||||
first: specialThanksFirstRow.concat(specialThanksFirstRow).concat(specialThanksFirstRow),
|
||||
second: specialThanksSecondRow.concat(specialThanksSecondRow).concat(specialThanksSecondRow)
|
||||
};
|
||||
|
|
@ -74,14 +85,9 @@ router.get('/', async (request, response) => {
|
|||
// Calculates global completion percentage
|
||||
totalProgress.percent = Math.round(totalProgress._calc.percentageSum / cache.sections.length * 100);
|
||||
|
||||
response.render('home', {
|
||||
layout: 'main',
|
||||
featuredFeatureList: totalProgress,
|
||||
boards,
|
||||
locale,
|
||||
localeString: reqLocale.toString(),
|
||||
specialThanksPeople
|
||||
});
|
||||
renderData.featuredFeatureList = totalProgress;
|
||||
|
||||
response.render('home', renderData);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
|
|
@ -3,15 +3,20 @@ const util = require('../util');
|
|||
const router = new Router();
|
||||
|
||||
router.get('/', async (request, response) => {
|
||||
|
||||
const reqLocale = request.locale;
|
||||
const locale = util.getLocale(reqLocale.region, reqLocale.language);
|
||||
|
||||
response.render('localization', {
|
||||
const renderData = {
|
||||
layout: 'main',
|
||||
locale,
|
||||
localeString: reqLocale.toString(),
|
||||
});
|
||||
locale: util.getLocale(request.locale.region, request.locale.language),
|
||||
localeString: request.locale.toString(),
|
||||
};
|
||||
|
||||
renderData.isLoggedIn = request.cookies.access_token && request.cookies.refresh_token && request.cookies.ph;
|
||||
|
||||
if (renderData.isLoggedIn) {
|
||||
const account = await util.getAccount(request, response);
|
||||
renderData.account = account;
|
||||
}
|
||||
|
||||
response.render('localization', renderData);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
|
|
@ -6,19 +6,24 @@ const router = new Router();
|
|||
const { getTrelloCache } = require('../trello');
|
||||
|
||||
router.get('/', async (request, response) => {
|
||||
|
||||
const reqLocale = request.locale;
|
||||
const locale = util.getLocale(reqLocale.region, reqLocale.language);
|
||||
|
||||
const cache = await getTrelloCache();
|
||||
|
||||
response.render('progress', {
|
||||
const renderData = {
|
||||
layout: 'main',
|
||||
boards,
|
||||
locale,
|
||||
localeString: reqLocale.toString(),
|
||||
progressLists: cache
|
||||
});
|
||||
locale: util.getLocale(request.locale.region, request.locale.language),
|
||||
localeString: request.locale.toString(),
|
||||
};
|
||||
|
||||
renderData.isLoggedIn = request.cookies.access_token && request.cookies.refresh_token && request.cookies.ph;
|
||||
|
||||
if (renderData.isLoggedIn) {
|
||||
const account = await util.getAccount(request, response);
|
||||
renderData.account = account;
|
||||
}
|
||||
|
||||
const cache = await getTrelloCache();
|
||||
renderData.cache = cache;
|
||||
|
||||
response.render('progress', renderData);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
43
src/util.js
43
src/util.js
|
|
@ -174,6 +174,46 @@ async function handleStripeEvent(event) {
|
|||
}
|
||||
}
|
||||
|
||||
async function getAccount(request, response) {
|
||||
// Attempt to get user data
|
||||
let apiResponse = await apiGetRequest('/v1/user', {
|
||||
'Authorization': `${request.cookies.token_type} ${request.cookies.access_token}`
|
||||
});
|
||||
|
||||
if (apiResponse.statusCode !== 200) {
|
||||
// Assume expired, refresh and retry request
|
||||
apiResponse = await apiPostGetRequest('/v1/login', {}, {
|
||||
refresh_token: request.cookies.refresh_token,
|
||||
grant_type: 'refresh_token'
|
||||
});
|
||||
|
||||
if (apiResponse.statusCode !== 200) {
|
||||
// TODO: Error message
|
||||
return response.status(apiResponse.statusCode).json({
|
||||
error: 'Bad'
|
||||
});
|
||||
}
|
||||
|
||||
const tokens = apiResponse.body;
|
||||
|
||||
apiResponse = await apiGetRequest('/v1/user', {
|
||||
'Authorization': `${tokens.token_type} ${tokens.access_token}`
|
||||
});
|
||||
}
|
||||
|
||||
// If still failed, something went horribly wrong
|
||||
if (apiResponse.statusCode !== 200) {
|
||||
// TODO: Error message
|
||||
return response.status(apiResponse.statusCode).json({
|
||||
error: 'Bad'
|
||||
});
|
||||
}
|
||||
|
||||
// Return user account info
|
||||
const account = apiResponse.body;
|
||||
return account;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fullUrl,
|
||||
getLocale,
|
||||
|
|
@ -181,5 +221,6 @@ module.exports = {
|
|||
apiPostGetRequest,
|
||||
apiDeleteGetRequest,
|
||||
nintendoPasswordHash,
|
||||
handleStripeEvent
|
||||
handleStripeEvent,
|
||||
getAccount
|
||||
};
|
||||
|
|
@ -70,7 +70,6 @@
|
|||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.5.1/dist/chart.min.js"></script>
|
||||
<script src="/assets/js/progress-charts.js"></script>
|
||||
<script src="/assets/js/locale-dropdown-handler.js"></script>
|
||||
<script>setDefaultDropdownLocale("{{localeString}}")</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -67,8 +67,6 @@
|
|||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.5.1/dist/chart.min.js"></script>
|
||||
<script src="/assets/js/progress-charts.js"></script>
|
||||
<script src="/assets/js/locale-dropdown-handler.js"></script>
|
||||
<script>setDefaultDropdownLocale("{{localeString}}")</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -33,101 +33,140 @@
|
|||
<a href="/blog" class="keep-on-mobile">{{ localeHelper locale "nav" "blog" }}</a>
|
||||
</nav>
|
||||
|
||||
<!-- Ordered the locales in the same way Google orders them -->
|
||||
<div class="select-box locale-dropdown" data-dropdown>
|
||||
<div class="options-container">
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="en-US" name="category" />
|
||||
<label for="en-US">
|
||||
<div class="item"><span class="lang">🇺🇸</span><span class="locale-names">English</span></div>
|
||||
</label>
|
||||
<div class="right-section">
|
||||
<!-- Ordered the locales in the same way Google orders them -->
|
||||
<div class="select-box locale-dropdown" data-dropdown>
|
||||
<div class="options-container">
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="en-US" name="category" />
|
||||
<label for="en-US">
|
||||
<div class="item"><span class="locale-names">English</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="de-DE" name="category" />
|
||||
<label for="de-DE">
|
||||
<div class="item"><span class="locale-names">Deutsch</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="es-ES" name="category" />
|
||||
<label for="es-ES">
|
||||
<div class="item"><span class="locale-names">Español</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="fr-FR" name="category" />
|
||||
<label for="fr-FR">
|
||||
<div class="item"><span class="locale-names">Français</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="it-IT" name="category" />
|
||||
<label for="it-IT">
|
||||
<div class="item"><span class="locale-names">Italiano</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="nl-NL" name="category" />
|
||||
<label for="nl-NL">
|
||||
<div class="item"><span class="locale-names">Nederlands</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="nb-NO" name="category" />
|
||||
<label for="nb-NO">
|
||||
<div class="item"><span class="locale-names">Norsk</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="pl-PL" name="category" />
|
||||
<label for="pl-PL">
|
||||
<div class="item"><span class="locale-names">Polski</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="pt-BR" name="category" />
|
||||
<label for="pt-BR">
|
||||
<div class="item"><span class="locale-names">Português</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="ro-RO" name="category" />
|
||||
<label for="ro-RO">
|
||||
<div class="item"><span class="locale-names">Română</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="tr-TR" name="category" />
|
||||
<label for="tr-TR">
|
||||
<div class="item"><span class="locale-names">Türkçe</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="ru-RU" name="category" />
|
||||
<label for="ru-RU">
|
||||
<div class="item"><span class="locale-names">Pусский</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="ar-AR" name="category" />
|
||||
<label for="ar-AR">
|
||||
<div class="item"><span class="locale-names">اَلْعَرَبِيَّةُ</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="ja-JP" name="category" />
|
||||
<label for="ja-JP">
|
||||
<div class="item"><span class="locale-names">日本語</span></div>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="ko-KR" name="category" />
|
||||
<label for="ko-KR">
|
||||
<div class="item"><span class="locale-names">한국어</span></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="de-DE" name="category" />
|
||||
<label for="de-DE">
|
||||
<div class="item"><span class="lang">🇩🇪</span><span class="locale-names">Deutsch</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="es-ES" name="category" />
|
||||
<label for="es-ES">
|
||||
<div class="item"><span class="lang">🇪🇸</span><span class="locale-names">Español</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="fr-FR" name="category" />
|
||||
<label for="fr-FR">
|
||||
<div class="item"><span class="lang">🇫🇷</span><span class="locale-names">Français</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="it-IT" name="category" />
|
||||
<label for="it-IT">
|
||||
<div class="item"><span class="lang">🇮🇹</span><span class="locale-names">Italiano</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="nl-NL" name="category" />
|
||||
<label for="nl-NL">
|
||||
<div class="item"><span class="lang">🇳🇱</span><span class="locale-names">Nederlands</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="nb-NO" name="category" />
|
||||
<label for="nb-NO">
|
||||
<div class="item"><span class="lang">🇳🇴</span><span class="locale-names">Norsk</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="pl-PL" name="category" />
|
||||
<label for="pl-PL">
|
||||
<div class="item"><span class="lang">🇵🇱</span><span class="locale-names">Polski</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="pt-BR" name="category" />
|
||||
<label for="pt-BR">
|
||||
<div class="item"><span class="lang">🇧🇷</span><span class="locale-names">Português</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="ro-RO" name="category" />
|
||||
<label for="ro-RO">
|
||||
<div class="item"><span class="lang">🇷🇴</span><span class="locale-names">Română</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="tr-TR" name="category" />
|
||||
<label for="tr-TR">
|
||||
<div class="item"><span class="lang">🇹🇷</span><span class="locale-names">Türkçe</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="ru-RU" name="category" />
|
||||
<label for="ru-RU">
|
||||
<div class="item"><span class="lang">🇷🇺</span><span class="locale-names">Pусский</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="ar-AR" name="category" />
|
||||
<label for="ar-AR">
|
||||
<div class="item"><span class="lang">🇸🇦</span><span class="locale-names">اَلْعَرَبِيَّةُ</span></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="ja-JP" name="category" />
|
||||
<label for="ja-JP">
|
||||
<div class="item"><span class="lang">🇯🇵</span><span class="locale-names">日本語</span></div>
|
||||
</div>
|
||||
<div class="option">
|
||||
<input type="radio" class="radio" id="ko-KR" name="category" />
|
||||
<label for="ko-KR">
|
||||
<div class="item"><span class="lang">🇰🇷</span><span class="locale-names">한국어</span></div>
|
||||
</label>
|
||||
<div class="locale-dropdown-toggle">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-globe"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="selected-locale">
|
||||
<div class="item"><span class="lang"></span></div>
|
||||
</div>
|
||||
|
||||
{{#if isLoggedIn}}
|
||||
<div class="user-widget-wrapper logged-in">
|
||||
<div class="user-widget-toggle">
|
||||
<img src="{{ account.mii.image_url }}" alt="{{ account.mii.name }}" />
|
||||
</div>
|
||||
<div class="user-widget">
|
||||
<div class="user-avatar">
|
||||
<img src="{{ account.mii.image_url }}" alt="{{ account.mii.name }}" />
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<div class="mii-name">{{ account.mii.name }}</div>
|
||||
<div class="pnid">{{ account.username }}</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<a href="/account">
|
||||
<button class="button primary">
|
||||
Settings
|
||||
</button>
|
||||
</a>
|
||||
<a href="/account/logout">
|
||||
<button class="button logout">
|
||||
Logout
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="user-widget-wrapper">
|
||||
<a class="login-link" href="/account/login">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-user"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<script src="/assets/js/header-handler.js"></script>
|
||||
Loading…
Reference in New Issue
Block a user