@okjavis/nodebb-theme-javis 5.0.7 → 6.0.0
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.
- package/package.json +1 -1
- package/plugin.json +4 -1
- package/public/src/client/account/categories.js +57 -0
- package/public/src/client/category.js +148 -0
- package/public/src/client/world.js +112 -0
- package/scss/_header.scss +75 -1
- package/static/lib/theme.js +73 -0
- package/templates/account/categories.tpl +40 -0
- package/templates/account/posts.tpl +32 -0
- package/templates/account/topics.tpl +46 -0
- package/templates/admin/settings/user.tpl +369 -0
- package/templates/partials/account/sidebar-left.tpl +0 -14
- package/templates/partials/category/watch.tpl +24 -0
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -19,7 +19,10 @@
|
|
|
19
19
|
],
|
|
20
20
|
"modules": {
|
|
21
21
|
"../admin/plugins/javis.js": "public/admin.js",
|
|
22
|
-
"forum/search": "public/src/client/search.js"
|
|
22
|
+
"forum/search": "public/src/client/search.js",
|
|
23
|
+
"forum/category": "public/src/client/category.js",
|
|
24
|
+
"forum/world": "public/src/client/world.js",
|
|
25
|
+
"forum/account/categories": "public/src/client/account/categories.js"
|
|
23
26
|
},
|
|
24
27
|
"templates": "templates",
|
|
25
28
|
"screenshot": "screenshot.png",
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
define('forum/account/categories', ['forum/account/header', 'alerts', 'api'], function (header, alerts, api) {
|
|
5
|
+
const Categories = {};
|
|
6
|
+
|
|
7
|
+
Categories.init = function () {
|
|
8
|
+
header.init();
|
|
9
|
+
|
|
10
|
+
ajaxify.data.categories.forEach(function (category) {
|
|
11
|
+
handleIgnoreWatch(category.cid);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
$('[component="category/watch/all"]').find(
|
|
15
|
+
'[component="category/watching"], [component="category/tracking"]'
|
|
16
|
+
).on('click', async (e) => {
|
|
17
|
+
const cids = [];
|
|
18
|
+
const state = e.currentTarget.getAttribute('data-state');
|
|
19
|
+
const { uid } = ajaxify.data;
|
|
20
|
+
$('[data-parent-cid="0"]').each(function (index, el) {
|
|
21
|
+
cids.push($(el).attr('data-cid'));
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
let modified_cids = await Promise.all(cids.map(async cid => api.put(`/categories/${cid}/watch`, { state, uid })));
|
|
25
|
+
modified_cids = modified_cids
|
|
26
|
+
.reduce((memo, cur) => memo.concat(cur.modified), [])
|
|
27
|
+
.filter((cid, idx, arr) => arr.indexOf(cid) === idx);
|
|
28
|
+
|
|
29
|
+
updateDropdowns(modified_cids, state);
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function handleIgnoreWatch(cid) {
|
|
34
|
+
const category = $('[data-cid="' + cid + '"]');
|
|
35
|
+
category.find('[component="category/watching"]').on('click', async (e) => {
|
|
36
|
+
const isWatching = category.find('[component="category/watching/check"]').hasClass('fa-check');
|
|
37
|
+
const state = isWatching ? 'tracking' : 'watching';
|
|
38
|
+
const { uid } = ajaxify.data;
|
|
39
|
+
|
|
40
|
+
const { modified } = await api.put(`/categories/${cid}/watch`, { state, uid });
|
|
41
|
+
updateDropdowns(modified, state);
|
|
42
|
+
alerts.success('[[category:' + state + '.message]]');
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function updateDropdowns(modified_cids, state) {
|
|
47
|
+
modified_cids.forEach(function (cid) {
|
|
48
|
+
const category = $('[data-cid="' + cid + '"]');
|
|
49
|
+
const nowWatching = state === 'watching';
|
|
50
|
+
category.find('[component="category/watching/menu"]').toggleClass('hidden', !nowWatching);
|
|
51
|
+
category.find('[component="category/watching/check"]').toggleClass('fa-check', nowWatching);
|
|
52
|
+
category.find('[component="category/notwatching/menu"]').toggleClass('hidden', nowWatching);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return Categories;
|
|
57
|
+
});
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
define('forum/category', [
|
|
4
|
+
'forum/infinitescroll',
|
|
5
|
+
'navigator',
|
|
6
|
+
'topicList',
|
|
7
|
+
'sort',
|
|
8
|
+
'categorySelector',
|
|
9
|
+
'hooks',
|
|
10
|
+
'alerts',
|
|
11
|
+
'api',
|
|
12
|
+
'clipboard',
|
|
13
|
+
], function (infinitescroll, navigator, topicList, sort, categorySelector, hooks, alerts, api, clipboard) {
|
|
14
|
+
const Category = {};
|
|
15
|
+
|
|
16
|
+
$(window).on('action:ajaxify.start', function (ev, data) {
|
|
17
|
+
if (!String(data.url).startsWith('category/')) {
|
|
18
|
+
navigator.disable();
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
Category.init = function () {
|
|
23
|
+
const cid = ajaxify.data.cid;
|
|
24
|
+
|
|
25
|
+
app.enterRoom('category_' + cid);
|
|
26
|
+
|
|
27
|
+
topicList.init('category', loadTopicsAfter);
|
|
28
|
+
|
|
29
|
+
sort.handleSort('categoryTopicSort', 'category/' + ajaxify.data.slug);
|
|
30
|
+
|
|
31
|
+
if (!config.usePagination) {
|
|
32
|
+
navigator.init('[component="category/topic"]', ajaxify.data.topic_count, Category.toTop, Category.toBottom);
|
|
33
|
+
} else {
|
|
34
|
+
navigator.disable();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
handleScrollToTopicIndex();
|
|
38
|
+
|
|
39
|
+
handleIgnoreWatch(cid);
|
|
40
|
+
|
|
41
|
+
handleLoadMoreSubcategories();
|
|
42
|
+
|
|
43
|
+
handleDescription();
|
|
44
|
+
|
|
45
|
+
categorySelector.init($('[component="category-selector"]'), {
|
|
46
|
+
privilege: 'find',
|
|
47
|
+
parentCid: ajaxify.data.cid,
|
|
48
|
+
onSelect: function (category) {
|
|
49
|
+
ajaxify.go('/category/' + category.cid);
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
new clipboard('[data-clipboard-text]');
|
|
54
|
+
|
|
55
|
+
hooks.fire('action:topics.loaded', { topics: ajaxify.data.topics });
|
|
56
|
+
hooks.fire('action:category.loaded', { cid: ajaxify.data.cid });
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function handleScrollToTopicIndex() {
|
|
60
|
+
let topicIndex = ajaxify.data.topicIndex;
|
|
61
|
+
if (topicIndex && utils.isNumber(topicIndex)) {
|
|
62
|
+
topicIndex = Math.max(0, parseInt(topicIndex, 10));
|
|
63
|
+
if (topicIndex && window.location.search.indexOf('page=') === -1) {
|
|
64
|
+
navigator.scrollToElement($('[component="category/topic"][data-index="' + topicIndex + '"]'), true, 0);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function handleIgnoreWatch(cid) {
|
|
70
|
+
$('[component="category/watching"]').on('click', function () {
|
|
71
|
+
const isWatching = $('[component="category/watching/check"]').hasClass('fa-check');
|
|
72
|
+
const state = isWatching ? 'tracking' : 'watching';
|
|
73
|
+
|
|
74
|
+
api.put(`/categories/${encodeURIComponent(cid)}/watch`, { state }, (err) => {
|
|
75
|
+
if (err) {
|
|
76
|
+
return alerts.error(err);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const nowWatching = state === 'watching';
|
|
80
|
+
$('[component="category/watching/menu"]').toggleClass('hidden', !nowWatching);
|
|
81
|
+
$('[component="category/watching/check"]').toggleClass('fa-check', nowWatching);
|
|
82
|
+
$('[component="category/notwatching/menu"]').toggleClass('hidden', nowWatching);
|
|
83
|
+
|
|
84
|
+
alerts.success('[[category:' + state + '.message]]');
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function handleLoadMoreSubcategories() {
|
|
90
|
+
$('[component="category/load-more-subcategories"]').on('click', async function () {
|
|
91
|
+
const btn = $(this);
|
|
92
|
+
const { categories: data } = await api.get(`/categories/${ajaxify.data.cid}/children?start=${ajaxify.data.nextSubCategoryStart}`);
|
|
93
|
+
btn.toggleClass('hidden', !data.length || data.length < ajaxify.data.subCategoriesPerPage);
|
|
94
|
+
if (!data.length) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
app.parseAndTranslate('category', 'children', { children: data }, function (html) {
|
|
98
|
+
html.find('.timeago').timeago();
|
|
99
|
+
$('[component="category/subcategory/container"]').append(html);
|
|
100
|
+
ajaxify.data.nextSubCategoryStart += ajaxify.data.subCategoriesPerPage;
|
|
101
|
+
ajaxify.data.subCategoriesLeft -= data.length;
|
|
102
|
+
btn.toggleClass('hidden', ajaxify.data.subCategoriesLeft <= 0)
|
|
103
|
+
.translateText('[[category:x-more-categories, ' + ajaxify.data.subCategoriesLeft + ']]');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
return false;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function handleDescription() {
|
|
111
|
+
const fadeEl = document.querySelector('.description.clamp-fade-4');
|
|
112
|
+
if (!fadeEl) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
fadeEl.addEventListener('click', () => {
|
|
117
|
+
const state = fadeEl.classList.contains('line-clamp-4');
|
|
118
|
+
fadeEl.classList.toggle('line-clamp-4', !state);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
Category.toTop = function () {
|
|
123
|
+
navigator.scrollTop(0);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
Category.toBottom = async () => {
|
|
127
|
+
const { count } = await api.get(`/categories/${encodeURIComponent(ajaxify.data.category.cid)}/count`);
|
|
128
|
+
navigator.scrollBottom(count - 1);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
function loadTopicsAfter(after, direction, callback) {
|
|
132
|
+
callback = callback || function () {};
|
|
133
|
+
|
|
134
|
+
hooks.fire('action:topics.loading');
|
|
135
|
+
const params = utils.params();
|
|
136
|
+
infinitescroll.loadMore(`/categories/${encodeURIComponent(ajaxify.data.cid)}/topics`, {
|
|
137
|
+
after: after,
|
|
138
|
+
direction: direction,
|
|
139
|
+
query: params,
|
|
140
|
+
categoryTopicSort: params.sort || config.categoryTopicSort,
|
|
141
|
+
}, function (data, done) {
|
|
142
|
+
hooks.fire('action:topics.loaded', { topics: data.topics });
|
|
143
|
+
callback(data, done);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return Category;
|
|
148
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
define('forum/world', ['topicList', 'search', 'sort', 'hooks', 'alerts', 'api', 'bootbox'], function (topicList, search, sort, hooks, alerts, api, bootbox) {
|
|
4
|
+
const World = {};
|
|
5
|
+
|
|
6
|
+
World.init = function () {
|
|
7
|
+
app.enterRoom('world');
|
|
8
|
+
topicList.init('world');
|
|
9
|
+
|
|
10
|
+
sort.handleSort('categoryTopicSort', 'world');
|
|
11
|
+
|
|
12
|
+
handleIgnoreWatch(-1);
|
|
13
|
+
handleHelp();
|
|
14
|
+
handleCategories();
|
|
15
|
+
|
|
16
|
+
search.enableQuickSearch({
|
|
17
|
+
searchElements: {
|
|
18
|
+
inputEl: $('[component="category-search"]'),
|
|
19
|
+
resultEl: $('.world .quick-search-container'),
|
|
20
|
+
},
|
|
21
|
+
searchOptions: {
|
|
22
|
+
in: 'categories',
|
|
23
|
+
},
|
|
24
|
+
dropdown: {
|
|
25
|
+
maxWidth: '400px',
|
|
26
|
+
maxHeight: '350px',
|
|
27
|
+
},
|
|
28
|
+
hideOnNoMatches: false,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
hooks.fire('action:topics.loaded', { topics: ajaxify.data.topics });
|
|
32
|
+
hooks.fire('action:category.loaded', { cid: ajaxify.data.cid });
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function handleIgnoreWatch(cid) {
|
|
36
|
+
$('[component="category/watching"]').on('click', function () {
|
|
37
|
+
const isWatching = $('[component="category/watching/check"]').hasClass('fa-check');
|
|
38
|
+
const state = isWatching ? 'tracking' : 'watching';
|
|
39
|
+
|
|
40
|
+
api.put(`/categories/${cid}/watch`, { state }, (err) => {
|
|
41
|
+
if (err) {
|
|
42
|
+
return alerts.error(err);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const nowWatching = state === 'watching';
|
|
46
|
+
$('[component="category/watching/menu"]').toggleClass('hidden', !nowWatching);
|
|
47
|
+
$('[component="category/watching/check"]').toggleClass('fa-check', nowWatching);
|
|
48
|
+
$('[component="category/notwatching/menu"]').toggleClass('hidden', nowWatching);
|
|
49
|
+
|
|
50
|
+
alerts.success('[[category:' + state + '.message]]');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function handleHelp() {
|
|
56
|
+
const trigger = document.getElementById('world-help');
|
|
57
|
+
if (!trigger) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const content = [
|
|
62
|
+
'<p class="lead">[[world:help.intro]]</p>',
|
|
63
|
+
'<p>[[world:help.fediverse]]</p>',
|
|
64
|
+
'<p>[[world:help.build]]</p>',
|
|
65
|
+
'<p>[[world:help.federating]]</p>',
|
|
66
|
+
'<p>[[world:help.next-generation]]</p>',
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
trigger.addEventListener('click', () => {
|
|
70
|
+
bootbox.dialog({
|
|
71
|
+
title: '[[world:help.title]]',
|
|
72
|
+
message: content.join('\n'),
|
|
73
|
+
size: 'large',
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function handleCategories() {
|
|
79
|
+
// const optionsEl = document.getElementById('category-options');
|
|
80
|
+
// const dropdownEl = optionsEl.querySelector('ul');
|
|
81
|
+
const showEl = document.getElementById('show-categories');
|
|
82
|
+
const hideEl = document.getElementById('hide-categories');
|
|
83
|
+
const categoriesEl = document.querySelector('.categories-list');
|
|
84
|
+
if (![showEl, hideEl, categoriesEl].every(Boolean)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const update = () => {
|
|
89
|
+
showEl.classList.toggle('hidden', visibility);
|
|
90
|
+
hideEl.classList.toggle('hidden', !visibility);
|
|
91
|
+
categoriesEl.classList.toggle('hidden', !visibility);
|
|
92
|
+
localStorage.setItem('world:show-categories', visibility);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
let visibility = localStorage.getItem('world:show-categories');
|
|
96
|
+
console.log('got value', visibility);
|
|
97
|
+
visibility = visibility ? visibility === 'true' : true; // localStorage values are strings
|
|
98
|
+
update();
|
|
99
|
+
|
|
100
|
+
showEl.addEventListener('click', () => {
|
|
101
|
+
visibility = true;
|
|
102
|
+
update();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
hideEl.addEventListener('click', () => {
|
|
106
|
+
visibility = false;
|
|
107
|
+
update();
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return World;
|
|
112
|
+
});
|
package/scss/_header.scss
CHANGED
|
@@ -238,12 +238,46 @@
|
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
// ===========================================================
|
|
241
|
-
// NOTIFICATION DROPDOWN - Reduced width
|
|
241
|
+
// NOTIFICATION DROPDOWN - Reduced width with optimized text
|
|
242
242
|
// ===========================================================
|
|
243
243
|
.notifications-dropdown {
|
|
244
244
|
min-width: 300px !important;
|
|
245
245
|
max-width: 340px !important;
|
|
246
246
|
width: 300px !important;
|
|
247
|
+
padding: $jv-space-2 !important;
|
|
248
|
+
|
|
249
|
+
// Individual notification items (actual class is .unread or .read)
|
|
250
|
+
.unread, .read {
|
|
251
|
+
padding: $jv-space-2 !important;
|
|
252
|
+
|
|
253
|
+
// Make hover effect rectangular instead of pill-shaped
|
|
254
|
+
.btn, .btn-ghost {
|
|
255
|
+
border-radius: $jv-radius-sm !important;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// The link containing notification text
|
|
259
|
+
a[component="notifications/item/link"] {
|
|
260
|
+
font-size: 12px !important;
|
|
261
|
+
line-height: 1.5 !important;
|
|
262
|
+
word-wrap: break-word !important;
|
|
263
|
+
overflow-wrap: break-word !important;
|
|
264
|
+
word-break: break-word !important;
|
|
265
|
+
white-space: normal !important;
|
|
266
|
+
text-overflow: clip !important;
|
|
267
|
+
display: block !important;
|
|
268
|
+
|
|
269
|
+
strong {
|
|
270
|
+
font-size: 12px !important;
|
|
271
|
+
font-weight: 600 !important;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Timestamp
|
|
276
|
+
.text-xs.text-muted {
|
|
277
|
+
font-size: 11px !important;
|
|
278
|
+
margin-top: $jv-space-1 !important;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
247
281
|
}
|
|
248
282
|
|
|
249
283
|
// ===========================================================
|
|
@@ -315,6 +349,46 @@
|
|
|
315
349
|
min-width: 280px !important;
|
|
316
350
|
max-width: 90vw !important;
|
|
317
351
|
width: 280px !important;
|
|
352
|
+
padding: $jv-space-2 !important;
|
|
353
|
+
|
|
354
|
+
// Even smaller text on mobile for better fit
|
|
355
|
+
.notification-item,
|
|
356
|
+
[component="notifications/item"],
|
|
357
|
+
.list-group-item {
|
|
358
|
+
padding: $jv-space-2 $jv-space-3 !important;
|
|
359
|
+
font-size: 11px !important;
|
|
360
|
+
line-height: 1.3 !important;
|
|
361
|
+
|
|
362
|
+
p, .notification-text, .text-muted, div {
|
|
363
|
+
font-size: 11px !important;
|
|
364
|
+
line-height: 1.3 !important;
|
|
365
|
+
white-space: normal !important;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
time, .timeago, small {
|
|
369
|
+
font-size: 10px !important;
|
|
370
|
+
margin-top: 4px !important;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
strong, .fw-semibold, a {
|
|
374
|
+
font-size: 11px !important;
|
|
375
|
+
white-space: normal !important;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.dropdown-header {
|
|
380
|
+
padding: $jv-space-2 !important;
|
|
381
|
+
font-size: 11px !important;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.dropdown-footer,
|
|
385
|
+
.list-group-item:last-child {
|
|
386
|
+
padding: $jv-space-2 !important;
|
|
387
|
+
|
|
388
|
+
a, button {
|
|
389
|
+
font-size: 11px !important;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
318
392
|
}
|
|
319
393
|
}
|
|
320
394
|
}
|
package/static/lib/theme.js
CHANGED
|
@@ -57,6 +57,9 @@
|
|
|
57
57
|
// Fix mobile category dropdown positioning in composer
|
|
58
58
|
fixMobileComposerCategoryDropdown();
|
|
59
59
|
|
|
60
|
+
// Fix notification dropdown inline styles
|
|
61
|
+
fixNotificationDropdown();
|
|
62
|
+
|
|
60
63
|
// Initialize share button handlers
|
|
61
64
|
initShareHandlers();
|
|
62
65
|
|
|
@@ -67,6 +70,7 @@
|
|
|
67
70
|
initParentPostNavigation();
|
|
68
71
|
fixMobileFeedCategoryDropdown();
|
|
69
72
|
fixMobileComposerCategoryDropdown();
|
|
73
|
+
fixNotificationDropdown();
|
|
70
74
|
initPostHoverActions();
|
|
71
75
|
initFeedComposerPromptHandler();
|
|
72
76
|
initTopicListVoting();
|
|
@@ -884,6 +888,75 @@
|
|
|
884
888
|
console.log('JAVIS: Composer mobile fix event listener attached');
|
|
885
889
|
}
|
|
886
890
|
|
|
891
|
+
/**
|
|
892
|
+
* Fix notification dropdown width and text styling
|
|
893
|
+
* Removes Popper inline width styles and applies proper text wrapping
|
|
894
|
+
*/
|
|
895
|
+
function fixNotificationDropdown() {
|
|
896
|
+
console.log('JAVIS: fixNotificationDropdown called');
|
|
897
|
+
|
|
898
|
+
// Find the notification component
|
|
899
|
+
var $notificationComponent = $('[component="notifications"]');
|
|
900
|
+
if (!$notificationComponent.length) {
|
|
901
|
+
console.log('JAVIS: Notification component not found');
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
console.log('JAVIS: Notification component found, setting up fix');
|
|
906
|
+
|
|
907
|
+
// Listen for when dropdown is shown
|
|
908
|
+
$notificationComponent.off('shown.bs.dropdown.javisNotificationFix').on('shown.bs.dropdown.javisNotificationFix', function() {
|
|
909
|
+
console.log('JAVIS: Notification dropdown shown');
|
|
910
|
+
|
|
911
|
+
// Use requestAnimationFrame to ensure we override after Popper runs
|
|
912
|
+
requestAnimationFrame(function() {
|
|
913
|
+
var $dropdownMenu = $notificationComponent.find('.notifications-dropdown');
|
|
914
|
+
|
|
915
|
+
if ($dropdownMenu.length) {
|
|
916
|
+
// Remove width-related inline styles from dropdown
|
|
917
|
+
var currentStyle = $dropdownMenu.attr('style') || '';
|
|
918
|
+
var newStyle = currentStyle
|
|
919
|
+
.replace(/min-width:\s*[^;]+;?/gi, '')
|
|
920
|
+
.replace(/max-width:\s*[^;]+;?/gi, '')
|
|
921
|
+
.replace(/width:\s*[^;]+;?/gi, '');
|
|
922
|
+
$dropdownMenu.attr('style', newStyle);
|
|
923
|
+
|
|
924
|
+
// Apply styling to notification items (.unread and .read are the actual classes)
|
|
925
|
+
$dropdownMenu.find('.unread, .read').css({
|
|
926
|
+
'padding': '8px'
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
// Style the notification link text
|
|
930
|
+
$dropdownMenu.find('a[component="notifications/item/link"]').css({
|
|
931
|
+
'font-size': '12px',
|
|
932
|
+
'line-height': '1.5',
|
|
933
|
+
'word-wrap': 'break-word',
|
|
934
|
+
'overflow-wrap': 'break-word',
|
|
935
|
+
'word-break': 'break-word',
|
|
936
|
+
'white-space': 'normal',
|
|
937
|
+
'text-overflow': 'clip',
|
|
938
|
+
'display': 'block'
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
// Style strong tags within notifications
|
|
942
|
+
$dropdownMenu.find('a[component="notifications/item/link"] strong').css({
|
|
943
|
+
'font-size': '12px',
|
|
944
|
+
'font-weight': '600'
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
// Style timestamps
|
|
948
|
+
$dropdownMenu.find('.text-xs.text-muted').css({
|
|
949
|
+
'font-size': '11px'
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
console.log('JAVIS: Notification dropdown styling applied');
|
|
953
|
+
}
|
|
954
|
+
});
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
console.log('JAVIS: Notification dropdown fix event listener attached');
|
|
958
|
+
}
|
|
959
|
+
|
|
887
960
|
/**
|
|
888
961
|
* Initialize immediate category filter navigation on feed page
|
|
889
962
|
* When a category is selected, navigate immediately instead of waiting for dropdown close
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!-- IMPORT partials/account/header.tpl -->
|
|
2
|
+
|
|
3
|
+
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
4
|
+
<div class="d-flex gap-1">
|
|
5
|
+
<h3 class="fw-semibold fs-5 mb-0">{title}</h3>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div class="d-flex gap-1">
|
|
9
|
+
<div class="btn-group bottom-sheet" component="category/watch/all">
|
|
10
|
+
<button class="btn btn-ghost btn-sm ff-secondary fw-semibold dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" type="button">
|
|
11
|
+
<span>[[user:change-all]]</span>
|
|
12
|
+
</button>
|
|
13
|
+
<ul class="dropdown-menu p-1 text-sm dropdown-menu-end" role="menu">
|
|
14
|
+
<li>
|
|
15
|
+
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2 p-2" href="#" component="category/watching" data-state="watching" role="menuitem">
|
|
16
|
+
<i class="flex-shrink-0 fa fa-fw fa-bell text-secondary"></i>
|
|
17
|
+
<span class="fw-semibold">[[category:watching]]</span>
|
|
18
|
+
</a>
|
|
19
|
+
</li>
|
|
20
|
+
<li>
|
|
21
|
+
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2 p-2" href="#" component="category/tracking" data-state="tracking" role="menuitem">
|
|
22
|
+
<i class="flex-shrink-0 fa fa-fw fa-bell-o text-secondary"></i>
|
|
23
|
+
<span class="fw-semibold">[[category:not-watching]]</span>
|
|
24
|
+
</a>
|
|
25
|
+
</li>
|
|
26
|
+
</ul>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div>
|
|
32
|
+
<ul class="categories list-unstyled" itemscope itemtype="http://www.schema.org/ItemList">
|
|
33
|
+
{{{each categories}}}
|
|
34
|
+
<!-- IMPORT partials/account/category-item.tpl -->
|
|
35
|
+
{{{end}}}
|
|
36
|
+
</ul>
|
|
37
|
+
<!-- IMPORT partials/paginator.tpl -->
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<!-- IMPORT partials/account/footer.tpl -->
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<!-- IMPORT partials/account/header.tpl -->
|
|
2
|
+
|
|
3
|
+
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
|
4
|
+
<h3 class="fw-semibold fs-5 mb-0">[[global:posts]]</h3>
|
|
5
|
+
<div class="d-flex flex-wrap gap-1">
|
|
6
|
+
<a href="{config.relative_path}/user/{userslug}/posts" class="btn btn-ghost btn-sm ff-secondary fw-semibold {{{ if template.account/posts }}}active{{{ end }}}">[[global:header.recent]]</a>
|
|
7
|
+
{{{ if !reputation:disabled }}}
|
|
8
|
+
<a href="{config.relative_path}/user/{userslug}/best"class="btn btn-ghost btn-sm ff-secondary fw-semibold {{{ if template.account/best }}}active{{{ end }}}">[[global:best]]</a>
|
|
9
|
+
<a href="{config.relative_path}/user/{userslug}/controversial" class="btn btn-ghost btn-sm ff-secondary fw-semibold {{{ if template.account/controversial }}}active{{{ end }}}">[[global:controversial]]</a>
|
|
10
|
+
{{{ if canEdit }}}
|
|
11
|
+
<a href="{config.relative_path}/user/{userslug}/upvoted" class="btn btn-ghost btn-sm ff-secondary fw-semibold {{{ if template.account/upvoted }}}active{{{ end }}}">[[global:upvoted]]</a>
|
|
12
|
+
{{{ if !downvote:disabled }}}
|
|
13
|
+
<a href="{config.relative_path}/user/{userslug}/downvoted" class="btn btn-ghost btn-sm ff-secondary fw-semibold {{{ if template.account/downvoted }}}active{{{ end }}}">[[global:downvoted]]</a>
|
|
14
|
+
{{{ end }}}
|
|
15
|
+
{{{ end }}}
|
|
16
|
+
{{{ end }}}
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
{{{ if !posts.length }}}
|
|
21
|
+
<div class="alert alert-warning text-center">{noItemsFoundKey}</div>
|
|
22
|
+
{{{ end }}}
|
|
23
|
+
|
|
24
|
+
<div>
|
|
25
|
+
<!-- IMPORT partials/posts_list.tpl -->
|
|
26
|
+
|
|
27
|
+
{{{ if config.usePagination }}}
|
|
28
|
+
<!-- IMPORT partials/paginator.tpl -->
|
|
29
|
+
{{{ end }}}
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<!-- IMPORT partials/account/footer.tpl -->
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<!-- IMPORT partials/account/header.tpl -->
|
|
2
|
+
|
|
3
|
+
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
4
|
+
<div class="d-flex gap-1">
|
|
5
|
+
<h3 class="fw-semibold fs-5 mb-0 align-self-center">[[global:topics]]</h3>
|
|
6
|
+
{{{ if showSort }}}
|
|
7
|
+
<div class="btn-group bottom-sheet" component="thread/sort">
|
|
8
|
+
<button title="[[global:sort]]" class="btn btn-ghost btn-sm dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" type="button"><i class="fa-solid fa-arrow-up-wide-short"></i></button>
|
|
9
|
+
<ul class="dropdown-menu p-1 text-sm" role="menu">
|
|
10
|
+
{{{each sortOptions }}}
|
|
11
|
+
<li>
|
|
12
|
+
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" href="{config.relative_path}{./url}" role="menuitem">
|
|
13
|
+
<div class="flex-grow-1">{./name}</div>
|
|
14
|
+
<i class="flex-shrink-0 fa fa-fw {{{if ./selected}}}fa-check{{{end}}}"></i>
|
|
15
|
+
</a>
|
|
16
|
+
</li>
|
|
17
|
+
{{{end}}}
|
|
18
|
+
</ul>
|
|
19
|
+
</div>
|
|
20
|
+
{{{ end }}}
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div class="d-flex gap-1">
|
|
24
|
+
{{{ if canEdit }}}
|
|
25
|
+
<a href="{config.relative_path}/user/{userslug}/topics" class="btn btn-ghost btn-sm ff-secondary fw-semibold {{{ if template.account/topics }}}active{{{ end }}}">[[global:header.recent]]</a>
|
|
26
|
+
<a href="{config.relative_path}/user/{userslug}/watched" class="btn btn-ghost btn-sm ff-secondary fw-semibold {{{ if template.account/watched }}}active{{{ end }}}">[[user:watched]]</a>
|
|
27
|
+
{{{ if !reputation:disabled }}}
|
|
28
|
+
<a href="{config.relative_path}/user/{userslug}/upvoted" class="btn btn-ghost btn-sm ff-secondary fw-semibold {{{ if template.account/upvoted }}}active{{{ end }}}">[[global:upvoted]]</a>
|
|
29
|
+
{{{ end }}}
|
|
30
|
+
{{{ end }}}
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
{{{ if !topics.length }}}
|
|
36
|
+
<div class="alert alert-warning text-center">{noItemsFoundKey}</div>
|
|
37
|
+
{{{ end }}}
|
|
38
|
+
|
|
39
|
+
<div class="category">
|
|
40
|
+
<!-- IMPORT partials/topics_list.tpl -->
|
|
41
|
+
{{{ if config.usePagination }}}
|
|
42
|
+
<!-- IMPORT partials/paginator.tpl -->
|
|
43
|
+
{{{ end }}}
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<!-- IMPORT partials/account/footer.tpl -->
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
<div class="acp-page-container">
|
|
2
|
+
<!-- IMPORT admin/partials/settings/header.tpl -->
|
|
3
|
+
|
|
4
|
+
<div class="row settings m-0">
|
|
5
|
+
<div id="spy-container" class="col-12 col-md-8 px-0 mb-4" tabindex="0">
|
|
6
|
+
<div id="account-settings" class="mb-4">
|
|
7
|
+
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/user:account-settings]]</h5>
|
|
8
|
+
<div class="mb-3">
|
|
9
|
+
<label class="form-label" for="allowLoginWith">[[admin/settings/user:allow-login-with]]</label>
|
|
10
|
+
<select id="allowLoginWith" class="form-select" data-field="allowLoginWith">
|
|
11
|
+
<option value="username-email">[[admin/settings/user:allow-login-with.username-email]]</option>
|
|
12
|
+
<option value="username">[[admin/settings/user:allow-login-with.username]]</option>
|
|
13
|
+
</select>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div class="form-check form-switch mb-3">
|
|
17
|
+
<input class="form-check-input" type="checkbox" id="gdpr_enabled" data-field="gdpr_enabled">
|
|
18
|
+
<label for="gdpr_enabled" class="form-check-label">[[admin/settings/user:gdpr-enabled]]</label>
|
|
19
|
+
<p class="form-text">[[admin/settings/user:gdpr-enabled-help]]</p>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="form-check form-switch mb-3">
|
|
22
|
+
<input class="form-check-input" type="checkbox" id="username:disableEdit" data-field="username:disableEdit">
|
|
23
|
+
<label for="username:disableEdit" class="form-check-label">[[admin/settings/user:disable-username-changes]]</label>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="form-check form-switch mb-3">
|
|
26
|
+
<input class="form-check-input" type="checkbox" id="email:disableEdit" data-field="email:disableEdit">
|
|
27
|
+
<label for="email:disableEdit" class="form-check-label">[[admin/settings/user:disable-email-changes]]</label>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="form-check form-switch mb-3">
|
|
30
|
+
<input class="form-check-input" type="checkbox" id="password:disableEdit" data-field="password:disableEdit">
|
|
31
|
+
<label for="password:disableEdit" class="form-check-label">[[admin/settings/user:disable-password-changes]]</label>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="form-check form-switch mb-3">
|
|
34
|
+
<input class="form-check-input" type="checkbox" id="allowAccountDelete" data-field="allowAccountDelete" checked>
|
|
35
|
+
<label for="allowAccountDelete" class="form-check-label">[[admin/settings/user:allow-account-deletion]]</label>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="form-check form-switch mb-3">
|
|
38
|
+
<input class="form-check-input" type="checkbox" id="hideFullname" data-field="hideFullname">
|
|
39
|
+
<label for="hideFullname" class="form-check-label">[[admin/settings/user:hide-fullname]]</label>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="form-check form-switch mb-3">
|
|
42
|
+
<input class="form-check-input" type="checkbox" id="hideEmail" data-field="hideEmail">
|
|
43
|
+
<label for="hideEmail" class="form-check-label">[[admin/settings/user:hide-email]]</label>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="form-check form-switch mb-3">
|
|
46
|
+
<input class="form-check-input" type="checkbox" id="showFullnameAsDisplayName" data-field="showFullnameAsDisplayName">
|
|
47
|
+
<label for="showFullnameAsDisplayName" class="form-check-label">[[admin/settings/user:show-fullname-as-displayname]]</label>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="form-check form-switch mb-3">
|
|
50
|
+
<input class="form-check-input" type="checkbox" id="disableCustomUserSkins" data-field="disableCustomUserSkins">
|
|
51
|
+
<label for="disableCustomUserSkins" class="form-check-label">[[admin/settings/user:disable-user-skins]]</label>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<hr/>
|
|
56
|
+
|
|
57
|
+
<div id="account-protection" class="mb-4">
|
|
58
|
+
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/user:account-protection]]</h5>
|
|
59
|
+
<div class="mb-3">
|
|
60
|
+
<label class="form-label" for="adminReloginDuration">[[admin/settings/user:admin-relogin-duration]]</label>
|
|
61
|
+
<input id="adminReloginDuration" type="text" class="form-control" data-field="adminReloginDuration" placeholder="60" />
|
|
62
|
+
<p class="form-text">
|
|
63
|
+
[[admin/settings/user:admin-relogin-duration-help]]
|
|
64
|
+
</p>
|
|
65
|
+
</div>
|
|
66
|
+
<div class="mb-3">
|
|
67
|
+
<label class="form-label" for="loginAttempts">[[admin/settings/user:login-attempts]]</label>
|
|
68
|
+
<input id="loginAttempts" type="text" class="form-control" data-field="loginAttempts" placeholder="5" />
|
|
69
|
+
<p class="form-text">
|
|
70
|
+
[[admin/settings/user:login-attempts-help]]
|
|
71
|
+
</p>
|
|
72
|
+
</div>
|
|
73
|
+
<div class="mb-3">
|
|
74
|
+
<label class="form-label" for="lockoutDuration">[[admin/settings/user:lockout-duration]]</label>
|
|
75
|
+
<input id="lockoutDuration" type="text" class="form-control" data-field="lockoutDuration" placeholder="60" />
|
|
76
|
+
</div>
|
|
77
|
+
<div class="mb-3">
|
|
78
|
+
<label class="form-label" for="passwordExpiryDays">[[admin/settings/user:password-expiry-days]]</label>
|
|
79
|
+
<input id="passwordExpiryDays" type="text" class="form-control" data-field="passwordExpiryDays" placeholder="0" />
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<hr/>
|
|
84
|
+
|
|
85
|
+
<div id="session-time" class="mb-4">
|
|
86
|
+
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/user:session-time]]</h5>
|
|
87
|
+
<div class="row">
|
|
88
|
+
<div class="col-sm-6">
|
|
89
|
+
<div class="form-group mb-3">
|
|
90
|
+
<label class="form-label" for="loginDays">[[admin/settings/user:session-time-days]]</label>
|
|
91
|
+
<input id="loginDays" type="number" min="0" class="form-control" data-field="loginDays" placeholder="[[admin/settings/user:session-time-days]]" />
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
<div class="col-sm-6">
|
|
95
|
+
<div class="form-group mb-3">
|
|
96
|
+
<label class="form-label" for="loginSeconds">[[admin/settings/user:session-time-seconds]]</label>
|
|
97
|
+
<input id="loginSeconds" type="number" min="0" step="60" class="form-control" data-field="loginSeconds" placeholder="[[admin/settings/user:session-time-seconds]]" />
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
<div class="row">
|
|
102
|
+
<div class="col-12">
|
|
103
|
+
<p class="form-text">
|
|
104
|
+
[[admin/settings/user:session-time-help]]
|
|
105
|
+
</p>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<div class="form-group mb-3">
|
|
110
|
+
<label class="form-label" for="sessionDuration">[[admin/settings/user:session-duration]]</label>
|
|
111
|
+
<input id="sessionDuration" type="number" step="60" min="0" class="form-control" data-field="sessionDuration">
|
|
112
|
+
<p class="form-text">[[admin/settings/user:session-duration-help]]</p>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div class="form-group mb-3">
|
|
116
|
+
<label class="form-label" for="onlineCutoff">[[admin/settings/user:online-cutoff]]</label>
|
|
117
|
+
<input id="onlineCutoff" type="number" min="0" class="form-control" data-field="onlineCutoff">
|
|
118
|
+
<p class="form-text">[[admin/settings/user:online-cutoff-help]]</p>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<hr/>
|
|
123
|
+
|
|
124
|
+
<div id="user-registration" class="mb-4">
|
|
125
|
+
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/user:registration]]</h5>
|
|
126
|
+
<div class="mb-3">
|
|
127
|
+
<label class="form-label" for="registrationType">[[admin/settings/user:registration-type]]</label>
|
|
128
|
+
<select id="registrationType" class="form-select" data-field="registrationType">
|
|
129
|
+
<option value="normal">[[admin/settings/user:registration-type.normal]]</option>
|
|
130
|
+
<option value="invite-only">[[admin/settings/user:registration-type.invite-only]]</option>
|
|
131
|
+
<option value="admin-invite-only">[[admin/settings/user:registration-type.admin-invite-only]]</option>
|
|
132
|
+
<option value="disabled">[[admin/settings/user:registration-type.disabled]]</option>
|
|
133
|
+
</select>
|
|
134
|
+
<p class="form-text">
|
|
135
|
+
[[admin/settings/user:registration-type.help, {config.relative_path}]]
|
|
136
|
+
</p>
|
|
137
|
+
</div>
|
|
138
|
+
<div class="mb-3">
|
|
139
|
+
<label class="form-label" for="registrationApprovalType">[[admin/settings/user:registration-approval-type]]</label>
|
|
140
|
+
<select id="registrationApprovalType" class="form-select" data-field="registrationApprovalType">
|
|
141
|
+
<option value="normal">[[admin/settings/user:registration-type.normal]]</option>
|
|
142
|
+
<option value="admin-approval">[[admin/settings/user:registration-type.admin-approval]]</option>
|
|
143
|
+
<option value="admin-approval-ip">[[admin/settings/user:registration-type.admin-approval-ip]]</option>
|
|
144
|
+
</select>
|
|
145
|
+
<p class="form-text">
|
|
146
|
+
[[admin/settings/user:registration-approval-type.help, {config.relative_path}]]
|
|
147
|
+
</p>
|
|
148
|
+
</div>
|
|
149
|
+
<div class="mb-3">
|
|
150
|
+
<label class="form-label" for="autoApproveTime">[[admin/settings/user:registration-queue-auto-approve-time]]</label>
|
|
151
|
+
<input id="autoApproveTime" type="number" class="form-control" data-field="autoApproveTime" placeholder="0">
|
|
152
|
+
<p class="form-text">
|
|
153
|
+
[[admin/settings/user:registration-queue-auto-approve-time-help]]
|
|
154
|
+
</p>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<div class="form-check form-switch mb-3">
|
|
158
|
+
<input class="form-check-input" type="checkbox" id="showAverageApprovalTime" data-field="showAverageApprovalTime">
|
|
159
|
+
<label for="showAverageApprovalTime" class="form-check-label">[[admin/settings/user:registration-queue-show-average-time]]</label>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
<div class="form-check form-switch mb-3">
|
|
163
|
+
<input class="form-check-input" type="checkbox" id="requireEmailAddress" data-field="requireEmailAddress" name="requireEmailAddress" />
|
|
164
|
+
<label for="requireEmailAddress" class="form-check-label">[[admin/settings/email:require-email-address]]</label>
|
|
165
|
+
</div>
|
|
166
|
+
<p class="form-text">[[admin/settings/email:require-email-address-warning]]</p>
|
|
167
|
+
|
|
168
|
+
<div class="mb-3">
|
|
169
|
+
<label class="form-label" for="maximumInvites">[[admin/settings/user:max-invites]]</label>
|
|
170
|
+
<input id="maximumInvites" type="number" class="form-control" data-field="maximumInvites" placeholder="0">
|
|
171
|
+
<p class="form-text">
|
|
172
|
+
[[admin/settings/user:max-invites-help]]
|
|
173
|
+
</p>
|
|
174
|
+
</div>
|
|
175
|
+
<div class="mb-3">
|
|
176
|
+
<label class="form-label" for="inviteExpiration">[[admin/settings/user:invite-expiration]]</label>
|
|
177
|
+
<input id="inviteExpiration" type="number" class="form-control" data-field="inviteExpiration" placeholder="7">
|
|
178
|
+
<p class="form-text">
|
|
179
|
+
[[admin/settings/user:invite-expiration-help]]
|
|
180
|
+
</p>
|
|
181
|
+
</div>
|
|
182
|
+
<div class="mb-3">
|
|
183
|
+
<label class="form-label" for="minimumUsernameLength">[[admin/settings/user:min-username-length]]</label>
|
|
184
|
+
<input id="minimumUsernameLength" type="text" class="form-control" value="2" data-field="minimumUsernameLength">
|
|
185
|
+
</div>
|
|
186
|
+
<div class="mb-3">
|
|
187
|
+
<label class="form-label" for="maximumUsernameLength">[[admin/settings/user:max-username-length]]</label>
|
|
188
|
+
<input id="maximumUsernameLength" type="text" class="form-control" value="16" data-field="maximumUsernameLength">
|
|
189
|
+
</div>
|
|
190
|
+
<div class="mb-3">
|
|
191
|
+
<label class="form-label" for="minimumPasswordLength">[[admin/settings/user:min-password-length]]</label>
|
|
192
|
+
<input id="minimumPasswordLength" type="text" class="form-control" value="6" data-field="minimumPasswordLength">
|
|
193
|
+
</div>
|
|
194
|
+
<div class="mb-3">
|
|
195
|
+
<label class="form-label" for="minimumPasswordStrength">[[admin/settings/user:min-password-strength]]</label>
|
|
196
|
+
<select id="minimumPasswordStrength" class="form-select" data-field="minimumPasswordStrength">
|
|
197
|
+
<option value="0">0 - too guessable: risky password</option>
|
|
198
|
+
<option value="1">1 - very guessable</option>
|
|
199
|
+
<option value="2">2 - somewhat guessable</option>
|
|
200
|
+
<option value="3">3 - safely unguessable</option>
|
|
201
|
+
<option value="4">4 - very unguessable</option>
|
|
202
|
+
</select>
|
|
203
|
+
</div>
|
|
204
|
+
<div class="mb-3">
|
|
205
|
+
<label class="form-label" for="maximumAboutMeLength">[[admin/settings/user:max-about-me-length]]</label>
|
|
206
|
+
<input id="maximumAboutMeLength" type="text" class="form-control" value="500" data-field="maximumAboutMeLength">
|
|
207
|
+
</div>
|
|
208
|
+
<div class="mb-3">
|
|
209
|
+
<label class="form-label" for="termsOfUse">[[admin/settings/user:terms-of-use]]</label>
|
|
210
|
+
<textarea id="termsOfUse" class="form-control" data-field="termsOfUse"></textarea>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<hr/>
|
|
215
|
+
|
|
216
|
+
<!-- new user restrictions -->
|
|
217
|
+
<div id="new-user-restrictions" class="mb-4">
|
|
218
|
+
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/user:restrictions-new]]</h5>
|
|
219
|
+
|
|
220
|
+
<div class="mb-3">
|
|
221
|
+
<label class="form-label" for="newbieReputationThreshold">[[admin/settings/user:restrictions.rep-threshold]]</label>
|
|
222
|
+
<input id="newbieReputationThreshold" type="text" class="form-control" value="3" data-field="newbieReputationThreshold">
|
|
223
|
+
</div>
|
|
224
|
+
|
|
225
|
+
<div class="mb-3">
|
|
226
|
+
<label class="form-label" for="newbiePostDelay">[[admin/settings/user:restrictions.seconds-between-new]]</label>
|
|
227
|
+
<input id="newbiePostDelay" type="text" class="form-control" value="120" data-field="newbiePostDelay">
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
<div class="mb-3">
|
|
231
|
+
<label class="form-label" for="initialPostDelay">[[admin/settings/user:restrictions.seconds-before-new]]</label>
|
|
232
|
+
<input id="initialPostDelay" type="text" class="form-control" value="10" data-field="initialPostDelay">
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<div class="mb-3">
|
|
236
|
+
<label class="form-label" for="newbiePostEditDuration">[[admin/settings/user:restrictions.seconds-edit-after-new]]</label>
|
|
237
|
+
<input id="newbiePostEditDuration" type="text" class="form-control" value="120" data-field="newbiePostEditDuration">
|
|
238
|
+
</div>
|
|
239
|
+
|
|
240
|
+
<div class="mb-3">
|
|
241
|
+
<label class="form-label" for="newbieChatMessageDelay">[[admin/settings/user:restrictions.milliseconds-between-messages]]</label>
|
|
242
|
+
<input id="newbieChatMessageDelay" type="text" class="form-control" data-field="newbieChatMessageDelay">
|
|
243
|
+
</div>
|
|
244
|
+
|
|
245
|
+
<div class="mb-3">
|
|
246
|
+
<label class="form-label" for="groupsExemptFromNewUserRestrictions">[[admin/settings/user:restrictions.groups-exempt-from-new-user-restrictions]]</label>
|
|
247
|
+
<select id="groupsExemptFromNewUserRestrictions" class="form-select" multiple data-field="groupsExemptFromNewUserRestrictions">
|
|
248
|
+
{{{ each groupsExemptFromNewUserRestrictions }}}
|
|
249
|
+
<option value="{groupsExemptFromNewUserRestrictions.displayName}">{groupsExemptFromNewUserRestrictions.displayName}</option>
|
|
250
|
+
{{{ end }}}
|
|
251
|
+
</select>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
</div>
|
|
255
|
+
|
|
256
|
+
<hr/>
|
|
257
|
+
|
|
258
|
+
<div id="guest-settings" class="mb-4">
|
|
259
|
+
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/user:guest-settings]]</h5>
|
|
260
|
+
|
|
261
|
+
<div class="mb-3">
|
|
262
|
+
<div class="form-check form-switch mb-3">
|
|
263
|
+
<input class="form-check-input" type="checkbox" id="allowGuestHandles" data-field="allowGuestHandles">
|
|
264
|
+
<label for="allowGuestHandles" class="form-check-label">[[admin/settings/user:handles.enabled]]</label>
|
|
265
|
+
</div>
|
|
266
|
+
<p class="form-text">
|
|
267
|
+
[[admin/settings/user:handles.enabled-help]]
|
|
268
|
+
</p>
|
|
269
|
+
</div>
|
|
270
|
+
<div class="mb-3">
|
|
271
|
+
<div class="form-check form-switch mb-3">
|
|
272
|
+
<input class="form-check-input" type="checkbox" id="guestsIncrementTopicViews" data-field="guestsIncrementTopicViews">
|
|
273
|
+
<label for="guestsIncrementTopicViews" class="form-check-label">[[admin/settings/user:topic-views.enabled]]</label>
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
<div class="mb-3">
|
|
277
|
+
<div class="form-check form-switch mb-3">
|
|
278
|
+
<input class="form-check-input" type="checkbox" id="allowGuestReplyNotifications" data-field="allowGuestReplyNotifications">
|
|
279
|
+
<label for="allowGuestReplyNotifications" class="form-check-label">[[admin/settings/user:reply-notifications.enabled]]</label>
|
|
280
|
+
</div>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
|
|
284
|
+
<hr/>
|
|
285
|
+
|
|
286
|
+
<div id="default-user-settings" class="mb-4">
|
|
287
|
+
<h5 class="fw-bold tracking-tight settings-header">[[admin/settings/user:default-user-settings]]</h5>
|
|
288
|
+
<div class="form-check form-switch mb-3">
|
|
289
|
+
<input class="form-check-input" type="checkbox" id="showemail" data-field="showemail">
|
|
290
|
+
<label for="showemail" class="form-check-label">[[admin/settings/user:show-email]]</label>
|
|
291
|
+
</div>
|
|
292
|
+
|
|
293
|
+
<div class="form-check form-switch mb-3">
|
|
294
|
+
<input class="form-check-input" type="checkbox" id="showfullname" data-field="showfullname">
|
|
295
|
+
<label for="showfullname" class="form-check-label">[[admin/settings/user:show-fullname]]</label>
|
|
296
|
+
</div>
|
|
297
|
+
|
|
298
|
+
<div class="form-check form-switch mb-3">
|
|
299
|
+
<input class="form-check-input" type="checkbox" id="disableIncomingChats" data-field="disableIncomingChats">
|
|
300
|
+
<label for="disableIncomingChats" class="form-check-label">[[admin/settings/user:disable-incoming-chats]]</label>
|
|
301
|
+
</div>
|
|
302
|
+
|
|
303
|
+
<div class="form-check form-switch mb-3">
|
|
304
|
+
<input class="form-check-input" type="checkbox" id="openOutgoingLinksInNewTab" data-field="openOutgoingLinksInNewTab">
|
|
305
|
+
<label for="openOutgoingLinksInNewTab" class="form-check-label">[[admin/settings/user:outgoing-new-tab]]</label>
|
|
306
|
+
</div>
|
|
307
|
+
|
|
308
|
+
<div class="form-check form-switch mb-3">
|
|
309
|
+
<input class="form-check-input" type="checkbox" id="topicSearchEnabled" data-field="topicSearchEnabled">
|
|
310
|
+
<label for="topicSearchEnabled" class="form-check-label">[[admin/settings/user:topic-search]]</label>
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
<div class="form-check form-switch mb-3">
|
|
314
|
+
<input class="form-check-input" type="checkbox" id="updateUrlWithPostIndex" data-field="updateUrlWithPostIndex">
|
|
315
|
+
<label for="updateUrlWithPostIndex" class="form-check-label">[[admin/settings/user:update-url-with-post-index]]</label>
|
|
316
|
+
</div>
|
|
317
|
+
|
|
318
|
+
<div class="mb-3">
|
|
319
|
+
<label class="form-label" for="dailyDigestFreq">[[admin/settings/user:digest-freq]]</label>
|
|
320
|
+
<select id="dailyDigestFreq" class="form-select" data-field="dailyDigestFreq">
|
|
321
|
+
<option value="off">[[admin/settings/user:digest-freq.off]]</option>
|
|
322
|
+
<option value="day">[[admin/settings/user:digest-freq.daily]]</option>
|
|
323
|
+
<option value="week">[[admin/settings/user:digest-freq.weekly]]</option>
|
|
324
|
+
<option value="biweek">[[admin/settings/user:digest-freq.biweekly]]</option>
|
|
325
|
+
<option value="month">[[admin/settings/user:digest-freq.monthly]]</option>
|
|
326
|
+
</select>
|
|
327
|
+
</div>
|
|
328
|
+
|
|
329
|
+
<div class="form-check form-switch mb-3">
|
|
330
|
+
<input class="form-check-input" type="checkbox" id="followTopicsOnCreate" data-field="followTopicsOnCreate">
|
|
331
|
+
<label for="followTopicsOnCreate" class="form-check-label">[[admin/settings/user:follow-created-topics]]</label>
|
|
332
|
+
</div>
|
|
333
|
+
|
|
334
|
+
<div class="form-check form-switch mb-3">
|
|
335
|
+
<input class="form-check-input" type="checkbox" id="followTopicsOnReply" data-field="followTopicsOnReply">
|
|
336
|
+
<label for="followTopicsOnReply" class="form-check-label">[[admin/settings/user:follow-replied-topics]]</label>
|
|
337
|
+
</div>
|
|
338
|
+
|
|
339
|
+
<div class="mb-3">
|
|
340
|
+
<label class="form-label" for="categoryWatchState">[[admin/settings/user:categoryWatchState]]</label>
|
|
341
|
+
<select id="categoryWatchState" class="form-select" data-field="categoryWatchState">
|
|
342
|
+
<option value="tracking" selected>[[admin/settings/user:categoryWatchState.tracking]]</option>
|
|
343
|
+
<option value="watching">[[admin/settings/user:categoryWatchState.watching]]</option>
|
|
344
|
+
</select>
|
|
345
|
+
</div>
|
|
346
|
+
|
|
347
|
+
<label class="form-label mb-2">[[admin/settings/user:default-notification-settings]]</label>
|
|
348
|
+
|
|
349
|
+
{{{ each notificationSettings }}}
|
|
350
|
+
<div class="row">
|
|
351
|
+
<div class="mb-3 col-7">
|
|
352
|
+
<label class="form-label">{./label}</label>
|
|
353
|
+
</div>
|
|
354
|
+
<div class="mb-3 col-5">
|
|
355
|
+
<select class="form-select" data-field="{./name}">
|
|
356
|
+
<option value="none">[[notifications:none]]</option>
|
|
357
|
+
<option value="notification">[[notifications:notification-only]]</option>
|
|
358
|
+
<option value="email">[[notifications:email-only]]</option>
|
|
359
|
+
<option value="notificationemail">[[notifications:notification-and-email]]</option>
|
|
360
|
+
</select>
|
|
361
|
+
</div>
|
|
362
|
+
</div>
|
|
363
|
+
{{{ end }}}
|
|
364
|
+
</div>
|
|
365
|
+
</div>
|
|
366
|
+
|
|
367
|
+
<!-- IMPORT admin/partials/settings/toc.tpl -->
|
|
368
|
+
</div>
|
|
369
|
+
</div>
|
|
@@ -29,12 +29,6 @@
|
|
|
29
29
|
<span class="flex-shrink-0 text-xs" title="{counts.shares}">{humanReadableNumber(counts.shares)}</span>
|
|
30
30
|
</a>
|
|
31
31
|
|
|
32
|
-
<a href="{config.relative_path}/user/{userslug}/groups" class="btn btn-ghost btn-sm text-start ff-secondary fw-semibold d-flex gap-2 align-items-center
|
|
33
|
-
{{{ if template.account/groups }}}active{{{ end }}}">
|
|
34
|
-
<div class="flex-grow-1">[[global:header.groups]]</div>
|
|
35
|
-
<span class="flex-shrink-0 text-xs" title="{counts.groups}">{humanReadableNumber(counts.groups)}</span>
|
|
36
|
-
</a>
|
|
37
|
-
|
|
38
32
|
<a href="{config.relative_path}/user/{userslug}/followers" class="btn btn-ghost btn-sm text-start ff-secondary fw-semibold d-flex gap-2 align-items-center
|
|
39
33
|
{{{ if template.account/followers }}}active{{{ end }}}">
|
|
40
34
|
<div class="flex-grow-1">[[user:followers]]</div>
|
|
@@ -53,14 +47,6 @@
|
|
|
53
47
|
<div class="flex-grow-1">[[user:watched-categories]]</div>
|
|
54
48
|
<span class="flex-shrink-0 text-xs" title="{counts.categoriesWatched}">{counts.categoriesWatched}</span>
|
|
55
49
|
</a>
|
|
56
|
-
{{{ if isSelf }}}
|
|
57
|
-
<a href="{config.relative_path}/user/{userslug}/tags" class="btn btn-ghost btn-sm text-start ff-secondary fw-semibold d-flex gap-2 align-items-center
|
|
58
|
-
{{{ if template.account/tags }}}active{{{ end }}}">
|
|
59
|
-
<div class="flex-grow-1">[[user:watched-tags]]</div>
|
|
60
|
-
<span class="flex-shrink-0 text-xs" title="{counts.tagsWatched}">{counts.tagsWatched}</span>
|
|
61
|
-
</a>
|
|
62
|
-
{{{ end }}}
|
|
63
|
-
|
|
64
50
|
<a href="{config.relative_path}/user/{userslug}/blocks" class="btn btn-ghost btn-sm text-start ff-secondary fw-semibold d-flex gap-2 align-items-center
|
|
65
51
|
{{{ if template.account/blocks }}}active{{{ end }}}">
|
|
66
52
|
<div class="flex-grow-1">[[user:blocked-users]]</div>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{{{ if config.loggedIn }}}
|
|
2
|
+
<div class="btn-group bottom-sheet" component="topic/watch">
|
|
3
|
+
<button class="btn btn-ghost btn-sm ff-secondary dropdown-toggle" data-bs-toggle="dropdown" type="button" aria-haspopup="true" aria-expanded="false">
|
|
4
|
+
<span component="category/watching/menu" class="d-flex gap-2 align-items-center {{{ if !./isWatched }}} hidden{{{ end }}}"><i class="fa fa-fw fa-bell text-primary"></i><span class="visible-md-inline visible-lg-inline fw-semibold">[[category:watching]]</span></span>
|
|
5
|
+
|
|
6
|
+
<span component="category/notwatching/menu" class="d-flex gap-2 align-items-center {{{ if ./isWatched }}} hidden{{{ end }}}"><i class="fa fa-fw fa-bell-o text-primary"></i><span class="visible-md-inline visible-lg-inline fw-semibold">[[category:watch]]</span></span>
|
|
7
|
+
</button>
|
|
8
|
+
|
|
9
|
+
<ul class="dropdown-menu p-1 text-sm {{{ if template.account/categories }}}dropdown-menu-end{{{ end }}}" role="menu">
|
|
10
|
+
<li>
|
|
11
|
+
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2 p-2" href="#" component="category/watching" data-state="watching" role="menuitem">
|
|
12
|
+
<div class="flex-grow-1 d-flex flex-column">
|
|
13
|
+
<span class="d-flex align-items-center gap-2">
|
|
14
|
+
<i class="flex-shrink-0 fa fa-fw fa-bell text-secondary"></i>
|
|
15
|
+
<span class="flex-grow-1 fw-semibold">[[category:watching]]</span>
|
|
16
|
+
</span>
|
|
17
|
+
<div class="help-text text-secondary text-xs">[[category:watching.description]]</div>
|
|
18
|
+
</div>
|
|
19
|
+
<span class="flex-shrink-0"><i component="category/watching/check" class="fa fa-fw {{{ if ./isWatched }}}fa-check{{{ end }}}"></i></span>
|
|
20
|
+
</a>
|
|
21
|
+
</li>
|
|
22
|
+
</ul>
|
|
23
|
+
</div>
|
|
24
|
+
{{{ end }}}
|