From 3847f603db31053ed5b069a4bb87cc9e156833db Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 14 Feb 2022 17:15:24 -0500 Subject: [PATCH] refactor: move persona settings to dedicated user page --- languages/en-GB/persona.json | 9 +++++- lib/controllers.js | 22 +++++++++++++++ library.js | 32 ++++++++++++++++++++-- plugin.json | 2 ++ public/persona.js | 11 ++++++-- public/settings.js | 53 ++++++++++++++++++++++++++++++++++++ templates/account/theme.tpl | 27 ++++++++++++++++++ 7 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 lib/controllers.js create mode 100644 public/settings.js create mode 100644 templates/account/theme.tpl diff --git a/languages/en-GB/persona.json b/languages/en-GB/persona.json index ffbe507..e7d1945 100644 --- a/languages/en-GB/persona.json +++ b/languages/en-GB/persona.json @@ -1,3 +1,10 @@ { - "mobile-menu-side": "Switch which side each mobile menu is on" + "settings.title": "Theme settings", + "settings.intro": "You can customise your theme settings here. Settings are stored on a per-device basis, so you are able to have different settings on different devices (phone, tablet, desktop, etc.)", + "settings.mobile-menu-side": "Switch which side each mobile menu is on", + "settings.autoHidingNavbar": "Automatically hide the navbar on scroll", + "settings.autoHidingNavbar-xs": "Very small screens (e.g. phones in portrait mode)", + "settings.autoHidingNavbar-sm": "Smaller screens (e.g. phones, some tablets)", + "settings.autoHidingNavbar-md": "Medium sized screens (e.g. tablets in landscape mode)", + "settings.autoHidingNavbar-lg": "Larger screens (e.g. desktop computers)" } \ No newline at end of file diff --git a/lib/controllers.js b/lib/controllers.js new file mode 100644 index 0000000..338bb7a --- /dev/null +++ b/lib/controllers.js @@ -0,0 +1,22 @@ +'use strict'; + +const accountHelpers = require.main.require('./src/controllers/accounts/helpers'); +const helpers = require.main.require('./src/controllers/helpers'); + +const Controllers = module.exports; + +Controllers.renderAdminPage = (req, res) => { + res.render('admin/plugins/persona', {}); +}; + +Controllers.renderThemeSettings = async (req, res, next) => { + const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query); + if (!userData) { + return next(); + } + + userData.title = '[[persona:settings.title]]'; + userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: `/user/${userData.userslug}` }, { text: '[[persona:settings.title]]' }]); + + res.render('account/theme', userData); +}; diff --git a/library.js b/library.js index d8bb36f..e7b7b6c 100644 --- a/library.js +++ b/library.js @@ -2,15 +2,23 @@ const meta = require.main.require('./src/meta'); const user = require.main.require('./src/user'); +const translator = require.main.require('./src/translator'); + +const controllers = require('./lib/controllers'); const library = module.exports; library.init = async function (params) { const { router, middleware } = params; const routeHelpers = require.main.require('./src/routes/helpers'); - routeHelpers.setupAdminPageRoute(router, '/admin/plugins/persona', middleware, [], (req, res) => { - res.render('admin/plugins/persona', {}); - }); + routeHelpers.setupAdminPageRoute(router, '/admin/plugins/persona', middleware, [], controllers.renderAdminPage); + + routeHelpers.setupPageRoute(router, '/user/:userslug/theme', middleware, [ + middleware.exposeUid, + middleware.ensureLoggedIn, + middleware.canViewUsers, + middleware.checkAccountPermissions, + ], controllers.renderThemeSettings); }; library.addAdminNavigation = async function (header) { @@ -22,6 +30,24 @@ library.addAdminNavigation = async function (header) { return header; }; +library.addProfileItem = async (data) => { + data.links.push({ + id: 'theme', + route: 'theme', + icon: 'fa-paint-brush', + name: await translator.translate('[[persona:settings.title]]'), + visibility: { + self: true, + other: false, + moderator: false, + globalMod: false, + admin: false, + }, + }); + + return data; +}; + library.defineWidgetAreas = async function (areas) { const locations = ['header', 'sidebar', 'footer']; const templates = [ diff --git a/plugin.json b/plugin.json index 9a1a01b..ab1d379 100644 --- a/plugin.json +++ b/plugin.json @@ -5,10 +5,12 @@ { "hook": "filter:config.get", "method": "getThemeConfig" }, { "hook": "static:app.load", "method": "init" }, { "hook": "filter:admin.header.build", "method": "addAdminNavigation" }, + { "hook": "filter:user.profileMenu", "method": "addProfileItem" }, { "hook": "filter:topic.build", "method": "addUserToTopic" } ], "scripts": [ "public/persona.js", + "public/settings.js", "public/modules/autohidingnavbar.js", "public/modules/quickreply.js" ], diff --git a/public/persona.js b/public/persona.js index 7875617..2749c7c 100644 --- a/public/persona.js +++ b/public/persona.js @@ -46,7 +46,14 @@ $(document).ready(function () { return; } - require(['hooks'], (hooks) => { + require(['hooks', 'storage'], (hooks, Storage) => { + let preference = ['xs', 'sm']; + + try { + preference = JSON.parse(Storage.getItem('persona:navbar:autohide')); + } catch (e) { + console.warn('[persona/settings] Unable to parse value for navbar autohiding'); + } var env = utils.findBootstrapEnvironment(); // if env didn't change don't destroy and recreate if (env === lastBSEnv) { @@ -58,7 +65,7 @@ $(document).ready(function () { navbarEl.css('top', ''); hooks.fire('filter:persona.configureNavbarHiding', { - resizeEnvs: ['xs', 'sm'], + resizeEnvs: preference, }).then(({ resizeEnvs }) => { if (resizeEnvs.includes(env)) { navbarEl.autoHidingNavbar({ diff --git a/public/settings.js b/public/settings.js new file mode 100644 index 0000000..ae38497 --- /dev/null +++ b/public/settings.js @@ -0,0 +1,53 @@ +'use strict'; + +define('forum/account/theme', ['forum/account/header', 'storage', 'settings', 'alerts'], function (header, Storage, settings, alerts) { + const Theme = {}; + + Theme.init = () => { + header.init(); + Theme.setupForm(); + }; + + Theme.setupForm = () => { + const saveEl = document.getElementById('save'); + const formEl = document.getElementById('theme-settings'); + const [sidebarSwapped, autohideNavbarEnvs] = [ + !!Storage.getItem('persona:menus:legacy-layout'), + Storage.getItem('persona:navbar:autohide'), + ]; + + document.getElementById('persona:menus:legacy-layout').checked = sidebarSwapped; + try { + const parsed = JSON.parse(autohideNavbarEnvs); + parsed.forEach((env) => { + const optionEl = document.getElementById('persona:navbar:autohide').querySelector(`option[value="${env}"]`); + optionEl.selected = true; + }); + } catch (e) { + console.warn(e); + } + + if (saveEl) { + saveEl.addEventListener('click', () => { + const themeSettings = settings.helper.serializeForm($(formEl)); + Object.keys(themeSettings).forEach((key) => { + if (key === 'persona:menus:legacy-layout') { + if (themeSettings[key] === 'on') { + Storage.setItem('persona:menus:legacy-layout', 'true'); + } else { + Storage.removeItem('persona:menus:legacy-layout'); + } + + return; + } + + Storage.setItem(key, themeSettings[key]); + }); + + alerts.success('[[success:settings-saved]]'); + }); + } + }; + + return Theme; +}); diff --git a/templates/account/theme.tpl b/templates/account/theme.tpl new file mode 100644 index 0000000..0205e42 --- /dev/null +++ b/templates/account/theme.tpl @@ -0,0 +1,27 @@ +
+ + +

[[persona:settings.intro]]

+ +
+ +
+
+ +

+ +
+ + +
+ + +
+
\ No newline at end of file