nodebb-theme-persona 11.3.40 → 11.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,10 @@
1
- {
2
- "mobile-menu-side": "Switch which side each mobile menu is on"
1
+ {
2
+ "settings.title": "Theme settings",
3
+ "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.)",
4
+ "settings.mobile-menu-side": "Switch which side each mobile menu is on",
5
+ "settings.autoHidingNavbar": "Automatically hide the navbar on scroll",
6
+ "settings.autoHidingNavbar-xs": "Very small screens (e.g. phones in portrait mode)",
7
+ "settings.autoHidingNavbar-sm": "Smaller screens (e.g. phones, some tablets)",
8
+ "settings.autoHidingNavbar-md": "Medium sized screens (e.g. tablets in landscape mode)",
9
+ "settings.autoHidingNavbar-lg": "Larger screens (e.g. desktop computers)"
3
10
  }
package/less/account.less CHANGED
@@ -32,7 +32,7 @@
32
32
  margin-bottom: 1em;
33
33
  background-origin: content-box;
34
34
  width: 100%;
35
- top: calc(var(--panel-offset) + @navbar-height);
35
+ top: calc(var(--panel-offset) - 20px);
36
36
  position: absolute;
37
37
  left: auto;
38
38
  right: 0px;
@@ -166,6 +166,12 @@
166
166
  }
167
167
  }
168
168
 
169
+ @media (min-width: @screen-lg-min) {
170
+ .cover {
171
+ top: calc(var(--panel-offset) + @navbar-height);
172
+ }
173
+ }
174
+
169
175
  @media (min-width: @screen-md-min) {
170
176
  margin-top: 300px;
171
177
 
package/less/header.less CHANGED
@@ -1,4 +1,8 @@
1
1
  .header, .slideout-menu {
2
+ .notifications .dropdown-menu {
3
+ padding: 0;
4
+ }
5
+
2
6
  .notification-list {
3
7
  overflow-x: hidden;
4
8
  overflow-y: auto;
@@ -173,14 +177,12 @@
173
177
  }
174
178
 
175
179
  .notif-dropdown-link {
176
- // margin-top: 1em;
177
180
  border-top: 1px solid rgba(163, 163, 163, 0.5);
178
- padding: 0 5px 0 5px;
179
181
 
180
182
  a {
181
183
  display: block;
182
184
  text-align: center;
183
- padding: 0.5em 0;
185
+ padding: 0.5em 0.5em;
184
186
  font-weight: 600;
185
187
  }
186
188
  }
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+
3
+ const accountHelpers = require.main.require('./src/controllers/accounts/helpers');
4
+ const helpers = require.main.require('./src/controllers/helpers');
5
+
6
+ const Controllers = module.exports;
7
+
8
+ Controllers.renderAdminPage = (req, res) => {
9
+ res.render('admin/plugins/persona', {});
10
+ };
11
+
12
+ Controllers.renderThemeSettings = async (req, res, next) => {
13
+ const userData = await accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, req.query);
14
+ if (!userData) {
15
+ return next();
16
+ }
17
+
18
+ userData.title = '[[persona:settings.title]]';
19
+ userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: `/user/${userData.userslug}` }, { text: '[[persona:settings.title]]' }]);
20
+
21
+ res.render('account/theme', userData);
22
+ };
package/library.js CHANGED
@@ -2,15 +2,23 @@
2
2
 
3
3
  const meta = require.main.require('./src/meta');
4
4
  const user = require.main.require('./src/user');
5
+ const translator = require.main.require('./src/translator');
6
+
7
+ const controllers = require('./lib/controllers');
5
8
 
6
9
  const library = module.exports;
7
10
 
8
11
  library.init = async function (params) {
9
12
  const { router, middleware } = params;
10
13
  const routeHelpers = require.main.require('./src/routes/helpers');
11
- routeHelpers.setupAdminPageRoute(router, '/admin/plugins/persona', middleware, [], (req, res) => {
12
- res.render('admin/plugins/persona', {});
13
- });
14
+ routeHelpers.setupAdminPageRoute(router, '/admin/plugins/persona', middleware, [], controllers.renderAdminPage);
15
+
16
+ routeHelpers.setupPageRoute(router, '/user/:userslug/theme', middleware, [
17
+ middleware.exposeUid,
18
+ middleware.ensureLoggedIn,
19
+ middleware.canViewUsers,
20
+ middleware.checkAccountPermissions,
21
+ ], controllers.renderThemeSettings);
14
22
  };
15
23
 
16
24
  library.addAdminNavigation = async function (header) {
@@ -22,6 +30,24 @@ library.addAdminNavigation = async function (header) {
22
30
  return header;
23
31
  };
24
32
 
33
+ library.addProfileItem = async (data) => {
34
+ data.links.push({
35
+ id: 'theme',
36
+ route: 'theme',
37
+ icon: 'fa-paint-brush',
38
+ name: await translator.translate('[[persona:settings.title]]'),
39
+ visibility: {
40
+ self: true,
41
+ other: false,
42
+ moderator: false,
43
+ globalMod: false,
44
+ admin: false,
45
+ },
46
+ });
47
+
48
+ return data;
49
+ };
50
+
25
51
  library.defineWidgetAreas = async function (areas) {
26
52
  const locations = ['header', 'sidebar', 'footer'];
27
53
  const templates = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-theme-persona",
3
- "version": "11.3.40",
3
+ "version": "11.4.2",
4
4
  "nbbpm": {
5
5
  "compatibility": "^1.18.0"
6
6
  },
package/plugin.json CHANGED
@@ -5,10 +5,12 @@
5
5
  { "hook": "filter:config.get", "method": "getThemeConfig" },
6
6
  { "hook": "static:app.load", "method": "init" },
7
7
  { "hook": "filter:admin.header.build", "method": "addAdminNavigation" },
8
+ { "hook": "filter:user.profileMenu", "method": "addProfileItem" },
8
9
  { "hook": "filter:topic.build", "method": "addUserToTopic" }
9
10
  ],
10
11
  "scripts": [
11
12
  "public/persona.js",
13
+ "public/settings.js",
12
14
  "public/modules/autohidingnavbar.js",
13
15
  "public/modules/quickreply.js"
14
16
  ],
package/public/persona.js CHANGED
@@ -46,7 +46,14 @@ $(document).ready(function () {
46
46
  return;
47
47
  }
48
48
 
49
- require(['hooks'], (hooks) => {
49
+ require(['hooks', 'storage'], (hooks, Storage) => {
50
+ let preference = ['xs', 'sm'];
51
+
52
+ try {
53
+ preference = JSON.parse(Storage.getItem('persona:navbar:autohide')) || preference;
54
+ } catch (e) {
55
+ console.warn('[persona/settings] Unable to parse value for navbar autohiding');
56
+ }
50
57
  var env = utils.findBootstrapEnvironment();
51
58
  // if env didn't change don't destroy and recreate
52
59
  if (env === lastBSEnv) {
@@ -58,7 +65,7 @@ $(document).ready(function () {
58
65
  navbarEl.css('top', '');
59
66
 
60
67
  hooks.fire('filter:persona.configureNavbarHiding', {
61
- resizeEnvs: ['xs', 'sm'],
68
+ resizeEnvs: preference,
62
69
  }).then(({ resizeEnvs }) => {
63
70
  if (resizeEnvs.includes(env)) {
64
71
  navbarEl.autoHidingNavbar({
@@ -372,33 +379,6 @@ $(document).ready(function () {
372
379
  in: config.searchDefaultInQuick,
373
380
  },
374
381
  });
375
-
376
-
377
- // add a checkbox in the user settings page
378
- // so users can swap the sides the menus appear on
379
-
380
- function setupSetting() {
381
- if (ajaxify.data.template['account/settings'] && !document.getElementById('persona:menus:legacy-layout')) {
382
- require(['translator'], function (translator) {
383
- translator.translate('[[persona:mobile-menu-side]]', function (translated) {
384
- $('<div class="well checkbox"><label><input type="checkbox" id="persona:menus:legacy-layout"/><strong>' + translated + '</strong></label></div>')
385
- .appendTo('#content .account > .row > div:first-child')
386
- .find('input')
387
- .prop('checked', Storage.getItem('persona:menus:legacy-layout', 'true'))
388
- .change(function (e) {
389
- if (e.target.checked) {
390
- Storage.setItem('persona:menus:legacy-layout', 'true');
391
- } else {
392
- Storage.removeItem('persona:menus:legacy-layout');
393
- }
394
- });
395
- });
396
- });
397
- }
398
- }
399
-
400
- $(window).on('action:ajaxify.end', setupSetting);
401
- setupSetting();
402
382
  });
403
383
  }
404
384
 
@@ -0,0 +1,53 @@
1
+ 'use strict';
2
+
3
+ define('forum/account/theme', ['forum/account/header', 'storage', 'settings', 'alerts'], function (header, Storage, settings, alerts) {
4
+ const Theme = {};
5
+
6
+ Theme.init = () => {
7
+ header.init();
8
+ Theme.setupForm();
9
+ };
10
+
11
+ Theme.setupForm = () => {
12
+ const saveEl = document.getElementById('save');
13
+ const formEl = document.getElementById('theme-settings');
14
+ const [sidebarSwapped, autohideNavbarEnvs] = [
15
+ !!Storage.getItem('persona:menus:legacy-layout'),
16
+ Storage.getItem('persona:navbar:autohide'),
17
+ ];
18
+
19
+ document.getElementById('persona:menus:legacy-layout').checked = sidebarSwapped;
20
+ try {
21
+ const parsed = JSON.parse(autohideNavbarEnvs);
22
+ parsed.forEach((env) => {
23
+ const optionEl = document.getElementById('persona:navbar:autohide').querySelector(`option[value="${env}"]`);
24
+ optionEl.selected = true;
25
+ });
26
+ } catch (e) {
27
+ console.warn(e);
28
+ }
29
+
30
+ if (saveEl) {
31
+ saveEl.addEventListener('click', () => {
32
+ const themeSettings = settings.helper.serializeForm($(formEl));
33
+ Object.keys(themeSettings).forEach((key) => {
34
+ if (key === 'persona:menus:legacy-layout') {
35
+ if (themeSettings[key] === 'on') {
36
+ Storage.setItem('persona:menus:legacy-layout', 'true');
37
+ } else {
38
+ Storage.removeItem('persona:menus:legacy-layout');
39
+ }
40
+
41
+ return;
42
+ }
43
+
44
+ Storage.setItem(key, themeSettings[key]);
45
+ });
46
+
47
+ alerts.success('[[success:settings-saved]]');
48
+ });
49
+ }
50
+ };
51
+
52
+ return Theme;
53
+ });
@@ -0,0 +1,27 @@
1
+ <div class="account">
2
+ <!-- IMPORT partials/account/header.tpl -->
3
+
4
+ <p>[[persona:settings.intro]]</p>
5
+
6
+ <hr />
7
+
8
+ <form id="theme-settings" role="form">
9
+ <div class="checkbox">
10
+ <label>
11
+ <input type="checkbox" id="persona:menus:legacy-layout" name="persona:menus:legacy-layout"> <strong>[[persona:settings.mobile-menu-side]]</strong>
12
+ </label>
13
+ </div><br />
14
+
15
+ <div class="form-group">
16
+ <label for="persona:navbar:autohide">[[persona:settings.autoHidingNavbar]]</label>
17
+ <select multiple class="form-control" name="persona:navbar:autohide" id="persona:navbar:autohide">
18
+ <option value="xs">[[persona:settings.autoHidingNavbar-xs]]</option>
19
+ <option value="sm">[[persona:settings.autoHidingNavbar-sm]]</option>
20
+ <option value="md">[[persona:settings.autoHidingNavbar-md]]</option>
21
+ <option value="lg">[[persona:settings.autoHidingNavbar-lg]]</option>
22
+ </select>
23
+ </div>
24
+
25
+ <button id="save" type="button" class="btn btn-primary">[[global:save_changes]]</button>
26
+ </form>
27
+ </div>
@@ -1,18 +1,18 @@
1
- </div><!-- /.container#content -->
2
- </main>
3
- <!-- IF !isSpider -->
4
- <div component="toaster/tray" class="alert-window">
5
- <div id="reconnect-alert" class="alert alert-dismissable alert-warning clearfix hide" component="toaster/toast">
6
- <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
7
- <p>[[global:reconnecting-message, {config.siteTitle}]]</p>
8
- </div>
9
- </div>
10
- <!-- ENDIF !isSpider -->
11
-
12
- <div class="hide">
13
- <!-- IMPORT 500-embed.tpl -->
14
- </div>
15
-
16
- <!-- IMPORT partials/footer/js.tpl -->
17
- </body>
18
- </html>
1
+ </div><!-- /.container#content -->
2
+ </main>
3
+ <!-- IF !isSpider -->
4
+ <div component="toaster/tray" class="alert-window">
5
+ <div id="reconnect-alert" class="alert alert-dismissable alert-warning clearfix hide" component="toaster/toast">
6
+ <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
7
+ <p>[[global:reconnecting-message, {config.siteTitle}]]</p>
8
+ </div>
9
+ </div>
10
+ <!-- ENDIF !isSpider -->
11
+
12
+ <div class="hide">
13
+ <!-- IMPORT 500-embed.tpl -->
14
+ </div>
15
+
16
+ <!-- IMPORT partials/footer/js.tpl -->
17
+ </body>
18
+ </html>
@@ -1,34 +1,34 @@
1
- <!-- IF rooms.length -->
2
- {{{each rooms}}}
3
- <li class="<!-- IF ../unread -->unread<!-- ENDIF ../unread -->" data-roomid="{rooms.roomId}">
4
- <strong class="room-name">
5
- <!-- IF !rooms.lastUser.uid -->
6
- <span>[[modules:chat.no-users-in-room]]</span>
7
- <!-- ELSE -->
8
- <!-- IF rooms.roomName -->{rooms.roomName}<!-- ELSE -->{rooms.usernames}<!-- ENDIF rooms.roomName -->
9
- <!-- ENDIF !rooms.lastUser.uid -->
10
- </strong>
11
- <div class="avatar-placeholder"></div>
12
- {{{each rooms.users}}}
13
- <!-- IF @first -->
14
- <div class="main-avatar">
15
- <!-- IMPORT partials/chats/user.tpl -->
16
- </div>
17
- <!-- ENDIF @first -->
18
- {{{end}}}
19
-
20
- <ul class="members">
21
- {{{each rooms.users}}}
22
- <li>
23
- <!-- IMPORT partials/chats/user.tpl -->
24
- </li>
25
- {{{end}}}
26
- </ul>
27
-
28
- <span class="teaser-content"><strong class="teaser-username">{rooms.teaser.user.username}:</strong> {rooms.teaser.content}</span>
29
- <span class="teaser-timestamp pull-right">{rooms.teaser.timeago}</span>
30
- </li>
31
- {{{end}}}
32
- <!-- ELSE -->
33
- <li class="no_active"><a href="#">[[modules:chat.no_active]]</a></li>
1
+ <!-- IF rooms.length -->
2
+ {{{each rooms}}}
3
+ <li class="<!-- IF ../unread -->unread<!-- ENDIF ../unread -->" data-roomid="{rooms.roomId}">
4
+ <strong class="room-name">
5
+ <!-- IF !rooms.lastUser.uid -->
6
+ <span>[[modules:chat.no-users-in-room]]</span>
7
+ <!-- ELSE -->
8
+ <!-- IF rooms.roomName -->{rooms.roomName}<!-- ELSE -->{rooms.usernames}<!-- ENDIF rooms.roomName -->
9
+ <!-- ENDIF !rooms.lastUser.uid -->
10
+ </strong>
11
+ <div class="avatar-placeholder"></div>
12
+ {{{each rooms.users}}}
13
+ <!-- IF @first -->
14
+ <div class="main-avatar">
15
+ <!-- IMPORT partials/chats/user.tpl -->
16
+ </div>
17
+ <!-- ENDIF @first -->
18
+ {{{end}}}
19
+
20
+ <ul class="members">
21
+ {{{each rooms.users}}}
22
+ <li>
23
+ <!-- IMPORT partials/chats/user.tpl -->
24
+ </li>
25
+ {{{end}}}
26
+ </ul>
27
+
28
+ <span class="teaser-content"><strong class="teaser-username">{rooms.teaser.user.username}:</strong> {rooms.teaser.content}</span>
29
+ <span class="teaser-timestamp pull-right">{rooms.teaser.timeago}</span>
30
+ </li>
31
+ {{{end}}}
32
+ <!-- ELSE -->
33
+ <li class="no_active"><a href="#">[[modules:chat.no_active]]</a></li>
34
34
  <!-- ENDIF rooms.length -->
@@ -1,25 +1,25 @@
1
- <li component="chat/recent/room" data-roomid="{rooms.roomId}" class="<!-- IF rooms.unread -->unread<!-- ENDIF rooms.unread -->">
2
- <strong class="room-name">
3
- <!-- IF !rooms.lastUser.uid -->
4
- <span>[[modules:chat.no-users-in-room]]</span>
5
- <!-- ELSE -->
6
- <span component="chat/title"><!-- IF rooms.roomName -->{rooms.roomName}<!-- ELSE -->{rooms.usernames}<!-- ENDIF rooms.roomName --></span>
7
- <!-- ENDIF !rooms.lastUser.uid -->
8
- </strong>
9
- <div class="avatar-placeholder"></div>
10
- {{{each rooms.users}}}
11
- <!-- IF @first -->
12
- <div class="main-avatar">
13
- <!-- IMPORT partials/chats/user.tpl -->
14
- </div>
15
- <!-- ENDIF @first -->
16
- {{{end}}}
17
-
18
- <ul class="members">
19
- {{{each rooms.users}}}
20
- <li>
21
- <!-- IMPORT partials/chats/user.tpl -->
22
- </li>
23
- {{{end}}}
24
- </ul>
1
+ <li component="chat/recent/room" data-roomid="{rooms.roomId}" class="<!-- IF rooms.unread -->unread<!-- ENDIF rooms.unread -->">
2
+ <strong class="room-name">
3
+ <!-- IF !rooms.lastUser.uid -->
4
+ <span>[[modules:chat.no-users-in-room]]</span>
5
+ <!-- ELSE -->
6
+ <span component="chat/title"><!-- IF rooms.roomName -->{rooms.roomName}<!-- ELSE -->{rooms.usernames}<!-- ENDIF rooms.roomName --></span>
7
+ <!-- ENDIF !rooms.lastUser.uid -->
8
+ </strong>
9
+ <div class="avatar-placeholder"></div>
10
+ {{{each rooms.users}}}
11
+ <!-- IF @first -->
12
+ <div class="main-avatar">
13
+ <!-- IMPORT partials/chats/user.tpl -->
14
+ </div>
15
+ <!-- ENDIF @first -->
16
+ {{{end}}}
17
+
18
+ <ul class="members">
19
+ {{{each rooms.users}}}
20
+ <li>
21
+ <!-- IMPORT partials/chats/user.tpl -->
22
+ </li>
23
+ {{{end}}}
24
+ </ul>
25
25
  </li>
@@ -9,28 +9,34 @@
9
9
  </span>
10
10
  <br/>
11
11
 
12
+ <!-- IF section_online -->
13
+ <div class="lastonline">
14
+ <span class="timeago" title="{users.lastonlineISO}"></span>
15
+ </div>
16
+ <!-- ENDIF section_online -->
17
+
12
18
  <!-- IF section_joindate -->
13
- <div title="joindate" class="joindate">
19
+ <div class="joindate">
14
20
  <span class="timeago" title="{users.joindateISO}"></span>
15
21
  </div>
16
22
  <!-- ENDIF section_joindate -->
17
23
 
18
24
  <!-- IF section_sort-reputation -->
19
- <div title="reputation" class="reputation">
25
+ <div class="reputation">
20
26
  <i class="fa fa-star"></i>
21
27
  <span class="formatted-number">{users.reputation}</span>
22
28
  </div>
23
29
  <!-- ENDIF section_sort-reputation -->
24
30
 
25
31
  <!-- IF section_sort-posts -->
26
- <div title="post count" class="post-count">
32
+ <div class="post-count">
27
33
  <i class="fa fa-pencil"></i>
28
34
  <span class="formatted-number">{users.postcount}</span>
29
35
  </div>
30
36
  <!-- ENDIF section_sort-posts -->
31
37
 
32
38
  <!-- IF section_flagged -->
33
- <div title="flag count" class="flag-count">
39
+ <div class="flag-count">
34
40
  <i class="fa fa-flag"></i>
35
41
  <span><a class="formatted-number" href="{config.relative_path}/flags?targetUid={users.uid}">{users.flags}</a></span>
36
42
  </div>