nodebb-theme-harmony 2.2.72 → 3.0.0-beta.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.
Files changed (60) hide show
  1. package/package.json +3 -3
  2. package/public/harmony.js +9 -11
  3. package/scss/harmony.scss +0 -2
  4. package/templates/account/blocks.tpl +1 -1
  5. package/templates/account/categories.tpl +1 -1
  6. package/templates/account/consent.tpl +3 -1
  7. package/templates/account/info.tpl +7 -7
  8. package/templates/account/profile.tpl +4 -4
  9. package/templates/account/settings.tpl +6 -6
  10. package/templates/account/tags.tpl +1 -1
  11. package/templates/account/uploads.tpl +1 -1
  12. package/templates/category.tpl +5 -5
  13. package/templates/header.tpl +2 -2
  14. package/templates/notifications.tpl +1 -1
  15. package/templates/partials/account/category-item.tpl +2 -2
  16. package/templates/partials/account/header.tpl +2 -2
  17. package/templates/partials/account/session-list.tpl +1 -1
  18. package/templates/partials/account/sidebar-left.tpl +1 -1
  19. package/templates/partials/breadcrumbs-json-ld.tpl +1 -1
  20. package/templates/partials/breadcrumbs.tpl +1 -1
  21. package/templates/partials/buttons/newTopic.tpl +1 -1
  22. package/templates/partials/categories/item.tpl +2 -2
  23. package/templates/partials/categories/lastpost.tpl +2 -2
  24. package/templates/partials/categories/link.tpl +2 -2
  25. package/templates/partials/cookie-consent.tpl +2 -2
  26. package/templates/partials/mobile-nav.tpl +3 -3
  27. package/templates/partials/notifications_list.tpl +3 -3
  28. package/templates/partials/posts_list_item.tpl +3 -3
  29. package/templates/partials/quick-category-search-results.tpl +2 -2
  30. package/templates/partials/quick-search-results.tpl +1 -1
  31. package/templates/partials/search-filters.tpl +2 -2
  32. package/templates/partials/search-results.tpl +3 -4
  33. package/templates/partials/sidebar/drafts.tpl +8 -3
  34. package/templates/partials/sidebar/user-menu.tpl +1 -1
  35. package/templates/partials/sidebar-left.tpl +4 -4
  36. package/templates/partials/tags_list.tpl +3 -3
  37. package/templates/partials/topic/event.tpl +2 -2
  38. package/templates/partials/topic/navigation-post.tpl +2 -2
  39. package/templates/partials/topic/necro-post.tpl +1 -1
  40. package/templates/partials/topic/post.tpl +12 -15
  41. package/templates/partials/topic/quickreply.tpl +1 -1
  42. package/templates/partials/topic/sort.tpl +1 -1
  43. package/templates/partials/topic-list-bar.tpl +1 -1
  44. package/templates/partials/topics_list.tpl +5 -5
  45. package/templates/partials/users/item.tpl +1 -1
  46. package/templates/topic.tpl +2 -18
  47. package/templates/world.tpl +5 -5
  48. package/scss/groups.scss +0 -20
  49. package/scss/modules/cover.scss +0 -104
  50. package/templates/groups/details.tpl +0 -92
  51. package/templates/groups/list.tpl +0 -58
  52. package/templates/groups/members.tpl +0 -10
  53. package/templates/partials/groups/admin.tpl +0 -90
  54. package/templates/partials/groups/badge.tpl +0 -1
  55. package/templates/partials/groups/invited.tpl +0 -33
  56. package/templates/partials/groups/list.tpl +0 -17
  57. package/templates/partials/groups/memberlist.tpl +0 -47
  58. package/templates/partials/groups/pending.tpl +0 -29
  59. package/templates/partials/groups/sidebar-left.tpl +0 -27
  60. package/templates/partials/toast.tpl +0 -19
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "nodebb-theme-harmony",
3
- "version": "2.2.72",
3
+ "version": "3.0.0-beta.2",
4
4
  "nbbpm": {
5
- "compatibility": "^4.12.0"
5
+ "compatibility": "^4.14.0"
6
6
  },
7
7
  "description": "Harmony theme for NodeBB",
8
8
  "main": "library.js",
@@ -45,7 +45,7 @@
45
45
  "@fontsource/poppins": "5.2.7"
46
46
  },
47
47
  "devDependencies": {
48
- "eslint": "10.4.1",
48
+ "eslint": "10.5.0",
49
49
  "eslint-config-nodebb": "^2.0.2"
50
50
  }
51
51
  }
package/public/harmony.js CHANGED
@@ -141,7 +141,7 @@ $(document).ready(function () {
141
141
  }
142
142
 
143
143
  function setupDrafts() {
144
- require(['composer/drafts', 'bootbox'], function (drafts, bootbox) {
144
+ require(['composer/drafts', 'bootbox', 'api'], function (drafts, bootbox, api) {
145
145
  const draftsEl = $('[component="sidebar/drafts"]');
146
146
  const bottomBarDraftsEl = $('[component="bottombar"] [component="sidebar/drafts"]');
147
147
  function updateBadgeCount() {
@@ -159,17 +159,15 @@ $(document).ready(function () {
159
159
  draftListEl.find('.draft-item-container').html('');
160
160
  return;
161
161
  }
162
- draftItems.reverse().forEach((draft) => {
163
- if (draft) {
164
- if (draft.title) {
165
- draft.title = utils.escapeHTML(String(draft.title));
166
- }
167
- draft.text = utils.escapeHTML(
168
- draft.text
169
- ).replace(/(?:\r\n|\r|\n)/g, '<br>');
162
+ draftItems.reverse();
163
+ await Promise.all(draftItems.map(async (item) => {
164
+ const cid = String(item.cid);
165
+ if (item && item.action === 'topics.post' && cid !== '0') {
166
+ const categoryUrl = cid !== '-1' ?
167
+ `/api/category/${encodeURIComponent(cid)}` : `/api/world`;
168
+ item.category = await api.get(categoryUrl, {});
170
169
  }
171
- });
172
-
170
+ }));
173
171
  const html = await app.parseAndTranslate('partials/sidebar/drafts', 'drafts', { drafts: draftItems });
174
172
  draftListEl.find('.no-drafts').addClass('hidden');
175
173
  draftListEl.find('.placeholder-wave').addClass('hidden');
package/scss/harmony.scss CHANGED
@@ -10,7 +10,6 @@
10
10
  @import "mobilebar";
11
11
  @import "status";
12
12
  @import "account";
13
- @import "groups";
14
13
  @import "world";
15
14
  @import "modals";
16
15
 
@@ -19,7 +18,6 @@
19
18
  @import "modules/user-menu";
20
19
  @import "modules/topic-navigator";
21
20
  @import "modules/topics-list";
22
- @import "modules/cover";
23
21
  @import "modules/nprogress";
24
22
  @import "modules/paginator";
25
23
  @import "modules/filters";
@@ -17,7 +17,7 @@
17
17
  <li component="blocks/search/match">
18
18
  <div class="dropdown-item rounded-1 d-flex flex-nowrap gap-4 justify-content-between align-items-center" role="menuitem">
19
19
  <div class="text-truncate">
20
- <a href="{config.relative_path}/uid/{./uid}" class="text-decoration-none">{buildAvatar(edit, "24px", true)} {./username}</a>
20
+ <a href="{config.relative_path}/uid/{./uid}" class="text-decoration-none">{{buildAvatar(edit, "24px", true)}} {./username}</a>
21
21
  </div>
22
22
 
23
23
  <button class="btn btn-sm btn-outline-danger text-nowrap {{{ if ./isBlocked }}}hidden{{{ end }}}" data-uid="{./uid}" data-action="block">[[user:block-user]]</button>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <div class="d-flex justify-content-between align-items-center mb-3">
4
4
  <div class="d-flex gap-1">
5
- <h3 class="fw-semibold fs-5 mb-0">{title}</h3>
5
+ <h3 class="fw-semibold fs-5 mb-0">{tx(title)}</h3>
6
6
  </div>
7
7
 
8
8
  <div class="d-flex gap-1">
@@ -54,7 +54,8 @@
54
54
 
55
55
  <hr />
56
56
 
57
- <div class="btn-group-vertical d-grid">
57
+ {{{ if canExport }}}
58
+ <div class="d-grid gap-2">
58
59
  <a data-action="export-profile" class="btn btn-outline-secondary">
59
60
  <i class="fa fa-download"></i> [[user:consent.export-profile]]
60
61
  </a>
@@ -65,6 +66,7 @@
65
66
  <i class="fa fa-download"></i> [[user:consent.export-uploads]]
66
67
  </a>
67
68
  </div>
69
+ {{{ end }}}
68
70
  </div>
69
71
  </div>
70
72
  </div>
@@ -15,7 +15,7 @@
15
15
  <div class="mb-4 pb-3 border-bottom">
16
16
  <h6>[[user:info.invited-by]]</h6>
17
17
  <div class="d-flex align-items-center gap-2">
18
- <a href="">{buildAvatar(invitedBy, "24px", true)}</a>
18
+ <a href="">{{buildAvatar(invitedBy, "24px", true)}}</a>
19
19
  <a href="">{invitedBy.username}</a>
20
20
  </div>
21
21
  </div>
@@ -43,7 +43,7 @@
43
43
  <div>
44
44
  {{{ if ./byUid }}}
45
45
  <a class="lh-1" href="{{{ if ./byUser.userslug }}}{config.relative_path}/user/{./byUser.userslug}{{{ else }}}#{{{ end }}}">
46
- {buildAvatar(./byUser, "18px", true)}</a>
46
+ {{buildAvatar(./byUser, "18px", true)}}</a>
47
47
  {{{ end }}}
48
48
  <span class="timeago text-sm text-secondary lh-1 align-middle" title="{./timestampISO}"></span>
49
49
  </div>
@@ -63,7 +63,7 @@
63
63
  <div>
64
64
  {{{ if ./byUid }}}
65
65
  <a class="lh-1" href="{{{ if ./byUser.userslug }}}{config.relative_path}/user/{./byUser.userslug}{{{ else }}}#{{{ end }}}">
66
- {buildAvatar(./byUser, "18px", true)}</a>
66
+ {{buildAvatar(./byUser, "18px", true)}}</a>
67
67
  {{{ end }}}
68
68
  <span class="timeago text-sm text-secondary lh-1 align-middle" title="{./timestampISO}"></span>
69
69
  </div>
@@ -107,7 +107,7 @@
107
107
  <span class="text-sm">[[user:info.reported-by]]</span>
108
108
  <div class="d-flex text-nowrap">
109
109
  {{{ each ./reports }}}
110
- <a style="width: 18px; z-index: 3;" class="text-decoration-none" href="{config.relative_path}/user/{./reporter.userslug}">{buildAvatar(./reporter, "24px", true)}</a>
110
+ <a style="width: 18px; z-index: 3;" class="text-decoration-none" href="{config.relative_path}/user/{./reporter.userslug}">{{buildAvatar(./reporter, "24px", true)}}</a>
111
111
  {{{ end }}}
112
112
  </div>
113
113
  </div>
@@ -138,7 +138,7 @@
138
138
  <li class="mb-4 border-bottom">
139
139
  <div class="mb-1 d-flex align-items-center justify-content-between">
140
140
  <div>
141
- <a href="{config.relative_path}/user/{./user.userslug}">{buildAvatar(./user, "24px", true)}</a>
141
+ <a href="{config.relative_path}/user/{./user.userslug}">{{buildAvatar(./user, "24px", true)}}</a>
142
142
  <strong>
143
143
  <a href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}" itemprop="author" data-username="{./user.username}" data-uid="{./user.uid}">{./user.username}</a>
144
144
  </strong>
@@ -192,7 +192,7 @@
192
192
  <li class="mb-4 border-bottom">
193
193
  <div class="mb-1 d-flex align-items-center justify-content-between">
194
194
  <div>
195
- <a href="{config.relative_path}/user/{./user.userslug}">{buildAvatar(./user, "24px", true)}</a>
195
+ <a href="{config.relative_path}/user/{./user.userslug}">{{buildAvatar(./user, "24px", true)}}</a>
196
196
  <strong>
197
197
  <a href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}" itemprop="author" data-username="{./user.username}" data-uid="{./user.uid}">{./user.username}</a>
198
198
  </strong>
@@ -240,7 +240,7 @@
240
240
 
241
241
  <div data-id="{./id}">
242
242
  <div class="d-flex align-items-baseline gap-1 mb-1">
243
- <a href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}">{buildAvatar(./user, "24px", true)}</a>
243
+ <a href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}">{{buildAvatar(./user, "24px", true)}}</a>
244
244
 
245
245
  <a href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}" class="fw-bold" itemprop="author" data-username="{./user.username}" data-uid="{./user.uid}">{./user.username}</a>
246
246
 
@@ -3,21 +3,21 @@
3
3
  {{{ if widgets.profile-aboutme-before.length }}}
4
4
  <div data-widget-area="profile-aboutme-before">
5
5
  {{{each widgets.profile-aboutme-before}}}
6
- {./html}
6
+ {{./html}}
7
7
  {{{end}}}
8
8
  </div>
9
9
  {{{ end }}}
10
10
 
11
11
  {{{ if aboutme }}}
12
12
  <div component="aboutme" class="text-sm text-break">
13
- {aboutmeParsed}
13
+ {{txEscape(aboutmeParsed)}}
14
14
  </div>
15
15
  {{{ end }}}
16
16
 
17
17
  {{{ if widgets.profile-aboutme-after.length }}}
18
18
  <div data-widget-area="profile-aboutme-after">
19
19
  {{{each widgets.profile-aboutme-after}}}
20
- {./html}
20
+ {{./html}}
21
21
  {{{end}}}
22
22
  </div>
23
23
  {{{ end }}}
@@ -76,7 +76,7 @@
76
76
  {{{ if ./value }}}
77
77
  <div class="stat">
78
78
  <div class="align-items-center justify-content-center card card-header p-3 border-0 rounded-1 h-100 gap-2">
79
- <span class="stat-label text-xs fw-semibold"><span><i class="text-muted {./icon}"></i> {./name}</span></span>
79
+ <span class="stat-label text-xs fw-semibold"><span><i class="text-muted {./icon}"></i> {tx(./name)}</span></span>
80
80
  {{{ if (./type == "input-link") }}}
81
81
  <a class="text-center text-break w-100 px-2 ff-secondary text-underline text-reset" href="{./value}" rel="nofollow noreferrer">{./linkValue}</a>
82
82
  {{{ else }}}
@@ -10,7 +10,7 @@
10
10
  <label for="bootswatchSkin" class="form-label fw-bold">[[user:select-skin]]</label>
11
11
  <select class="form-select form-select-sm" id="bootswatchSkin" data-property="bootswatchSkin">
12
12
  {{{each bootswatchSkinOptions}}}
13
- <option value="{bootswatchSkinOptions.value}" {{{ if bootswatchSkinOptions.selected }}}selected{{{ end }}}>{bootswatchSkinOptions.name}</option>
13
+ <option value="{bootswatchSkinOptions.value}" {{{ if bootswatchSkinOptions.selected }}}selected{{{ end }}}>{tx(bootswatchSkinOptions.name)}</option>
14
14
  {{{end}}}
15
15
  </select>
16
16
 
@@ -67,7 +67,7 @@
67
67
  <div component="chat/allow/list" class="d-flex flex-wrap gap-2 mb-2">
68
68
  {{{ each settings.chatAllowListUsers }}}
69
69
  <div component="chat/allow/list/user" data-uid="{./uid}" class="d-flex px-2 py-1 rounded-1 text-bg-light gap-2 align-items-center text-sm">
70
- {buildAvatar(@value, "16px", true)} {./username}
70
+ {{buildAvatar(@value, "16px", true)}} {./username}
71
71
  <button component="chat/allow/delete" data-uid="{./uid}" class="btn btn-light btn-sm py-0"><i class="fa fa-times fa-xs text-danger"></i></button>
72
72
  </div>
73
73
  {{{ end }}}
@@ -82,7 +82,7 @@
82
82
  <div component="chat/deny/list" class="d-flex flex-wrap gap-2 mb-2">
83
83
  {{{ each settings.chatDenyListUsers }}}
84
84
  <div component="chat/deny/list/user" data-uid="{./uid}" class="d-flex px-2 py-1 rounded-1 text-bg-light gap-2 align-items-center text-sm">
85
- {buildAvatar(@value, "16px", true)} {./username}
85
+ {{buildAvatar(@value, "16px", true)}} {./username}
86
86
  <button component="chat/deny/delete" data-uid="{./uid}" class="btn btn-light btn-sm py-0"><i class="fa fa-times fa-xs text-danger"></i></button>
87
87
  </div>
88
88
  {{{ end }}}
@@ -177,7 +177,7 @@
177
177
  <label class="form-label text-sm" for="dailyDigestFreq">[[user:digest-label]]</label>
178
178
  <select class="form-select form-select-sm" id="dailyDigestFreq" data-property="dailyDigestFreq" autocomplete="off">
179
179
  {{{each dailyDigestFreqOptions}}}
180
- <option value="{./value}" {{{ if ./selected }}}selected="1"{{{ end }}}>{./name}</option>
180
+ <option value="{./value}" {{{ if ./selected }}}selected="1"{{{ end }}}>{tx(./name)}</option>
181
181
  {{{end}}}
182
182
  </select>
183
183
  <p class="form-text text-xs">[[user:digest-description]]</p>
@@ -189,7 +189,7 @@
189
189
  <hr/>
190
190
  <h6 class="fw-bold">{./title}</h6>
191
191
  <div>
192
- {./content}
192
+ {{./content}}
193
193
  </div>
194
194
  {{{end}}}
195
195
  <hr class="d-block d-md-none"/>
@@ -271,7 +271,7 @@
271
271
  <tr component="notification/setting" class="align-middle">
272
272
  <td style="width:100%;">
273
273
  <div class="align-items-center">
274
- <label class="text-sm tracking-tight" for="{./name}">{./label}</label>
274
+ <label class="text-sm tracking-tight" for="{./name}">{tx(./label)}</label>
275
275
  <input type="hidden" data-property="{./name}" value="{./value}">
276
276
  </div>
277
277
  </td>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <div class="d-flex justify-content-between align-items-center mb-3">
4
4
  <div class="d-flex gap-1">
5
- <h3 class="fw-semibold fs-5 mb-0">{title}</h3>
5
+ <h3 class="fw-semibold fs-5 mb-0">{tx(title)}</h3>
6
6
  </div>
7
7
  </div>
8
8
 
@@ -1,6 +1,6 @@
1
1
  <!-- IMPORT partials/account/header.tpl -->
2
2
 
3
- <h3 class="fw-semibold fs-5">{title}</h3>
3
+ <h3 class="fw-semibold fs-5">{tx(title)}</h3>
4
4
 
5
5
  <div class="alert alert-info text-center">
6
6
  {{{ if privateUploads }}}[[uploads:private-uploads-info]]{{{ else }}}[[uploads:public-uploads-info]]{{{ end }}}
@@ -5,9 +5,9 @@
5
5
 
6
6
  <div class="category-header d-flex flex-column gap-2">
7
7
  <div class="d-flex gap-3 align-items-center mb-1 {{{ if config.theme.centerHeaderElements }}}justify-content-center flex-column{{{ end }}}">
8
- {buildCategoryIcon(@value, "60px", "rounded-1 flex-shrink-0")}
8
+ {{buildCategoryIcon(@value, "60px", "rounded-1 flex-shrink-0")}}
9
9
  <div class="d-flex flex-column gap-1">
10
- <h1 class="tracking-tight fs-3 fw-semibold mb-0">{./name}</h1>
10
+ <h1 class="tracking-tight fs-3 fw-semibold mb-0">{tx(./name)}</h1>
11
11
  <div class="d-flex flex-wrap gap-2 align-items-center {{{ if config.theme.centerHeaderElements }}}justify-content-center{{{ end }}}">
12
12
  <span class="badge text-body border border-gray-300 stats text-xs">
13
13
  <span title="{formattedNumber(totalTopicCount)}" class="fw-bold">{humanReadableNumber(totalTopicCount)}</span>
@@ -18,7 +18,7 @@
18
18
  <span class="text-lowercase fw-normal">[[global:posts]]</span>
19
19
  </span>
20
20
  {{{ if !isNumber(cid) }}}
21
- <a href="{escape(./url)}" class="badge text-body border border-gray-300 text-xs" data-ajaxify="false">
21
+ <a href="{./url}" class="badge text-body border border-gray-300 text-xs" data-ajaxify="false">
22
22
  <span class="fw-normal">View Original</span>
23
23
  <i class="fa fa-external-link"></i>
24
24
  </a>
@@ -31,12 +31,12 @@
31
31
  </div>
32
32
  {{{ if ./descriptionParsed }}}
33
33
  <div class="description text-secondary text-sm lh-sm w-100 {{{ if config.theme.centerHeaderElements }}}text-center{{{ end }}} line-clamp-4 clamp-fade-sm-4">
34
- {./descriptionParsed}
34
+ {{./descriptionParsed}}
35
35
  </div>
36
36
  {{{ end }}}
37
37
  {{{ if ./handleFull }}}
38
38
  <p class="text-secondary text-sm fst-italic mb-0 {{{ if config.theme.centerHeaderElements }}}text-center{{{ end }}}">
39
- [[category:handle.description, {txEscape(handleFull)}]]
39
+ [[category:handle.description, {handleFull}]]
40
40
  <a href="#" class="link-secondary" data-action="copy" data-clipboard-text="{handleFull}"><i class="fa fa-fw fa-copy" aria-hidden="true"></i></a>
41
41
  </p>
42
42
  {{{ end }}}
@@ -2,9 +2,9 @@
2
2
  <html lang="{localeToHTML(userLang, defaultLang)}" {{{if languageDirection}}}data-dir="{languageDirection}" style="direction: {languageDirection};"{{{end}}}>
3
3
  <head>
4
4
  <title>{browserTitle}</title>
5
- {{{each metaTags}}}{buildMetaTag(@value)}{{{end}}}
5
+ {{{each metaTags}}}{{buildMetaTag(@value)}}{{{end}}}
6
6
  <link rel="stylesheet" type="text/css" href="{relative_path}/assets/client{{{if bootswatchSkin}}}-{bootswatchSkin}{{{end}}}{{{ if (languageDirection=="rtl") }}}-rtl{{{ end }}}.css?{config.cache-buster}" />
7
- {{{each linkTags}}}{buildLinkTag(@value)}{{{end}}}
7
+ {{{each linkTags}}}{{buildLinkTag(@value)}}{{{end}}}
8
8
 
9
9
  <script>
10
10
  var config = JSON.parse('{{configJSON}}');
@@ -10,7 +10,7 @@
10
10
  <hr/>
11
11
  {{{ else }}}
12
12
  <a class="btn btn-ghost d-flex gap-2 text-start align-items-baseline text-sm ff-secondary fw-semibold {{{ if ./selected }}}active{{{ end }}}" href="{config.relative_path}/notifications?filter={./filter}">
13
- <div class="flex-grow-1">{filters.name}</div>
13
+ <div class="flex-grow-1">{tx(filters.name)}</div>
14
14
  {{{ if ./filter }}}
15
15
  <span class="flex-shrink-0 text-xs" title="{./count}">{humanReadableNumber(./count)}</span>
16
16
  {{{ end }}}
@@ -3,14 +3,14 @@
3
3
  <div class="content depth-{./depth} d-flex gap-2">
4
4
  <div class="flex-grow-1 align-items-start d-flex gap-2">
5
5
  <div>
6
- {buildCategoryIcon(@value, "24px", "rounded-1")}
6
+ {{buildCategoryIcon(@value, "24px", "rounded-1")}}
7
7
  </div>
8
8
  <div class="d-grid gap-0">
9
9
  <div class="title fw-semibold">
10
10
  <!-- IMPORT partials/categories/link.tpl -->
11
11
  </div>
12
12
  {{{ if ./descriptionParsed }}}
13
- <div class="description text-muted text-xs w-100 line-clamp-sm-5">{./descriptionParsed}</div>
13
+ <div class="description text-muted text-xs w-100 line-clamp-sm-5">{{./descriptionParsed}}</div>
14
14
  {{{ end }}}
15
15
  </div>
16
16
  </div>
@@ -1,5 +1,5 @@
1
1
  <div class="account w-100 mx-auto">
2
- <div class="cover position-absolute start-0 top-0 w-100" component="account/cover" style="background-image: url({escape(cover:url)}); background-position: {cover:position};">
2
+ <div class="cover position-absolute start-0 top-0 w-100" component="account/cover" style="background-image: url({cover:url}); background-position: {cover:position};">
3
3
  <div class="container">
4
4
  {{{ if (allowCoverPicture && canEdit) }}}
5
5
  <div class="controls text-center">
@@ -15,7 +15,7 @@
15
15
 
16
16
  <div class="d-flex flex-column flex-md-row gap-2 w-100 pb-4 mb-4 mt-2 border-bottom">
17
17
  <div {{{ if (allowProfilePicture && isSelfOrAdminOrGlobalModerator)}}}component="profile/change/picture"{{{ end }}} class="avatar-wrapper bg-body rounded-circle position-relative align-self-center align-self-md-start hover-parent" style="margin-top: -75px; padding: 4px;">
18
- {buildAvatar(@value, "142px", true)}
18
+ {{buildAvatar(@value, "142px", true)}}
19
19
  {{{ if (allowProfilePicture && isSelfOrAdminOrGlobalModerator)}}}
20
20
  <a href="#" component="profile/change/picture" class="d-none d-md-block pointer p-2 rounded-1 text-bg-light position-absolute top-50 start-50 translate-middle hover-opacity-75">
21
21
  <span class="upload"><i class="fa fa-fw fa-upload"></i></span>
@@ -6,7 +6,7 @@
6
6
  <button class="btn btn-sm btn-outline-secondary" type="button" data-action="revokeSession">[[user:revoke-session]]</button>
7
7
  {{{ end }}}
8
8
  {{{ end }}}
9
- {userAgentIcons(@value)}
9
+ {{userAgentIcons(@value)}}
10
10
  <i class="fa fa-circle text-{{{ if ./current }}}success{{{ else }}}muted{{{ end }}}"></i>
11
11
  </div>
12
12
  [[user:browser-version-on-platform, {./browser}, {./version}, {./platform}]]<br />
@@ -119,7 +119,7 @@
119
119
 
120
120
  {{{ each profile_links }}}
121
121
  <a href="{config.relative_path}/user/{userslug}/{./route}" class="btn btn-ghost btn-sm ff-secondary text-xs text-start plugin-link {{{ if ./public }}}public{{{ else }}}private{{{ end }}} {{{ if (url == ./url) }}}active{{{ end }}}" id="{./id}">
122
- <div class="flex-grow-1">{./name}</div>
122
+ <div class="flex-grow-1">{tx(./name)}</div>
123
123
  </a>
124
124
  {{{end}}}
125
125
  </div>
@@ -10,7 +10,7 @@
10
10
  {{{ each breadcrumbs }}}{{{ if !@first}}},{
11
11
  "@type": "ListItem",
12
12
  "position": {increment(@index, "1")},
13
- "name": "{stripTags(./text)}"
13
+ "name": "{stripTags(tx(./text))}"
14
14
  {{{ if !@last }}},"item": "{./url}"{{{ end }}}
15
15
  }{{{ end }}}{{{ end }}}
16
16
  ]}</script>
@@ -4,7 +4,7 @@
4
4
  <li{{{ if @last }}} component="breadcrumb/current"{{{ end }}} itemscope="itemscope" itemprop="itemListElement" itemtype="http://schema.org/ListItem" class="breadcrumb-item {{{ if @last }}}active{{{ end }}}">
5
5
  <meta itemprop="position" content="{increment(@index, "1")}" />
6
6
  {{{ if ./url }}}<a href="{./url}" itemprop="item">{{{ end }}}
7
- <span class="fw-semibold" itemprop="name">{./text}</span>
7
+ <span class="fw-semibold" itemprop="name">{tx(./text)}</span>
8
8
  {{{ if ./url }}}</a>{{{ end }}}
9
9
  </li>
10
10
  {{{ end }}}
@@ -10,7 +10,7 @@
10
10
  <a role="menu-item" href="{config.relative_path}/compose?cid={categories.cid}">{categories.level}
11
11
  <span component="category-markup">
12
12
  <div class="category-item d-inline-block">
13
- {buildCategoryIcon(@value, "24px", "rounded-circle")}
13
+ {{buildCategoryIcon(@value, "24px", "rounded-circle")}}
14
14
  {categories.name}
15
15
  </div>
16
16
  </span>
@@ -3,7 +3,7 @@
3
3
 
4
4
  <div class="d-flex col-lg-7 gap-2 gap-lg-3">
5
5
  <div class="flex-shrink-0">
6
- {buildCategoryIcon(@value, "40px", "rounded-1")}
6
+ {{buildCategoryIcon(@value, "40px", "rounded-1")}}
7
7
  </div>
8
8
  <div class="flex-grow-1 d-flex flex-wrap gap-1 me-0 me-lg-2">
9
9
  <h2 class="title text-break fs-4 fw-semibold m-0 tracking-tight w-100">
@@ -11,7 +11,7 @@
11
11
  </h2>
12
12
  {{{ if ./descriptionParsed }}}
13
13
  <div class="description text-muted text-sm w-100 line-clamp-sm-5">
14
- {./descriptionParsed}
14
+ {{./descriptionParsed}}
15
15
  </div>
16
16
  {{{ end }}}
17
17
  {{{ if !./link }}}
@@ -3,12 +3,12 @@
3
3
  {{{ if @first }}}
4
4
  <div component="category/posts" class="ps-2 text-xs d-flex flex-column h-100 gap-1">
5
5
  <div class="text-nowrap text-truncate">
6
- <a class="text-decoration-none avatar-tooltip" title="{./user.displayname}" href="{config.relative_path}/user/{./user.userslug}">{buildAvatar(posts.user, "18px", true)}</a>
6
+ <a class="text-decoration-none avatar-tooltip" title="{./user.displayname}" href="{config.relative_path}/user/{./user.userslug}">{{buildAvatar(posts.user, "18px", true)}}</a>
7
7
  <a class="permalink text-muted timeago text-xs" href="{config.relative_path}/topic/{./topic.slug}{{{ if ./index }}}/{./index}{{{ end }}}" title="{./timestampISO}" aria-label="[[global:lastpost]]"></a>
8
8
  </div>
9
9
  <div class="post-content text-xs text-break line-clamp-sm-2 lh-sm position-relative flex-fill">
10
10
  <a class="stretched-link" tabindex="-1" href="{config.relative_path}/topic/{./topic.slug}{{{ if ./index }}}/{./index}{{{ end }}}" aria-label="[[global:lastpost]]"></a>
11
- {./content}
11
+ {{./content}}
12
12
  </div>
13
13
  </div>
14
14
  {{{ end }}}
@@ -1,5 +1,5 @@
1
1
  {{{ if ./isSection }}}
2
- {./name}
2
+ {tx(./name)}
3
3
  {{{ else }}}
4
- <a class="text-reset" href="{{{ if ./link }}}{./link}{{{ else }}}{config.relative_path}/category/{./slug}{{{ end }}}" itemprop="url">{../name}</a>
4
+ <a class="text-reset" href="{{{ if ./link }}}{./link}{{{ else }}}{config.relative_path}/category/{./slug}{{{ end }}}" itemprop="url">{tx(./name)}</a>
5
5
  {{{ end }}}
@@ -1,6 +1,6 @@
1
1
  <div class="position-fixed bottom-0 w-100 px-3 px-md-0 pb-5 mb-5 pb-lg-0 mb-lg-0" style="z-index: 2;">
2
2
  <div class="cookie-consent d-flex flex-column flex-lg-row gap-2 text-bg-info col-12 col-sm-8 col-lg-6 p-3 mx-auto rounded mb-5 mb-md-3 justify-content-between align-items-center">
3
- <span>{message} <a class="fw-bold" target="_blank" rel="noopener" href="{link_url}">{link}</a></span>
4
- <button class="btn btn-primary text-nowrap">{dismiss}</button>
3
+ <span>{tx(message)} <a class="fw-bold" target="_blank" rel="noopener" href="{link_url}">{tx(link)}</a></span>
4
+ <button class="btn btn-primary text-nowrap">{tx(dismiss)}</button>
5
5
  </div>
6
6
  </div>
@@ -10,14 +10,14 @@
10
10
  <ul class="navigation-dropdown dropdown-menu" role="menu">
11
11
  {{{ each navigation }}}
12
12
  {{{ if displayMenuItem(@root, @index) }}}
13
- <li class="nav-item {./class}{{{ if ./dropdown }}} dropend{{{ end }}}" title="{./title}">
13
+ <li class="nav-item {./class}{{{ if ./dropdown }}} dropend{{{ end }}}" title="{tx(./title)}">
14
14
  <a class="nav-link navigation-link px-3 py-2 {{{ if ./dropdown }}}dropdown-toggle{{{ end }}}" {{{ if ./dropdown }}} href="#" role="button" data-bs-toggle="collapse" data-bs-target="#collapse-target-{@index}" onclick="event.stopPropagation();" {{{ else }}} href="{./route}"{{{ end }}} {{{ if ./id }}}id="{./id}"{{{ end }}}{{{ if ./targetBlank }}} target="_blank"{{{ end }}}>
15
15
  <span class="d-inline-flex justify-content-between align-items-center w-100">
16
16
  <span class="text-nowrap">
17
17
  {{{ if ./iconClass }}}
18
18
  <i class="fa fa-fw {./iconClass}" data-content="{./content}"></i>
19
19
  {{{ end }}}
20
- {{{ if ./text }}}<span class="nav-text px-2 fw-semibold">{./text}</span>{{{ end }}}
20
+ {{{ if ./text }}}<span class="nav-text px-2 fw-semibold">{tx(./text)}</span>{{{ end }}}
21
21
  </span>
22
22
  <span component="navigation/count" class="badge rounded-1 bg-primary {{{ if !./content }}}hidden{{{ end }}}">{./content}</span>
23
23
  </span>
@@ -25,7 +25,7 @@
25
25
  {{{ if ./dropdown }}}
26
26
  <div class="ps-3">
27
27
  <ul id="collapse-target-{@index}" class="collapse list-unstyled ps-3">
28
- {./dropdownContent}
28
+ {{./dropdownContent}}
29
29
  </ul>
30
30
  </div>
31
31
  {{{ end }}}
@@ -9,7 +9,7 @@
9
9
  <div class="btn btn-ghost btn-sm d-flex gap-2 flex-grow-1 align-items-start text-start">
10
10
  <a class="flex-grow-0 flex-shrink-0" href="{{{ if ./user.userslug}}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}">
11
11
  {{{ if ./user }}}
12
- {buildAvatar(./user, "32px", true)}
12
+ {{buildAvatar(./user, "32px", true)}}
13
13
  {{{ else }}}
14
14
  {{{ if ./icon }}}
15
15
  <div class="avatar avatar-rounded" style="--avatar-size: 32px;"><i class="text-secondary fa {./icon}"></i></div>
@@ -23,11 +23,11 @@
23
23
 
24
24
  <div class="d-flex flex-grow-1 flex-column gap-1 align-items-start position-relative">
25
25
  <a href="{./path}" class="text-decoration-none d-inline-block text-reset text-break text-sm ff-sans stretched-link" component="notifications/item/link">
26
- {./bodyShort}
26
+ {{./bodyShort}}
27
27
  </a>
28
28
  {{{ if ./bodyLong}}}
29
29
  <div class="text-secondary text-sm line-clamp-2 text-contain hidden-blockquote hidden-pre hidden-first-child-br">
30
- {./bodyLong}
30
+ {{./bodyLong}}
31
31
  </div>
32
32
  {{{ end }}}
33
33
  <div class="text-xs text-muted">{{{ if ./timeagoLong }}}{./timeagoLong}{{{ else }}}<span class="timeago" title="{./datetimeISO}"></span>{{{ end }}}</div>
@@ -7,18 +7,18 @@
7
7
  <div class="post-body d-flex flex-column gap-1 mb-2">
8
8
  <div class="d-flex gap-2 post-info text-sm align-items-center">
9
9
  <div class="post-author d-flex align-items-center gap-1">
10
- <a class="lh-1 text-decoration-none" href="{config.relative_path}/user/{./user.userslug}">{buildAvatar(./user, "16px", true, "not-responsive")}</a>
10
+ <a class="lh-1 text-decoration-none" href="{config.relative_path}/user/{./user.userslug}">{{buildAvatar(./user, "16px", true, "not-responsive")}}</a>
11
11
  <a class="lh-1 fw-semibold" href="{config.relative_path}/user/{./user.userslug}">{../user.displayname}</a>
12
12
  </div>
13
13
  <span class="timeago text-muted lh-1" title="{./timestampISO}"></span>
14
14
  </div>
15
15
 
16
16
  <div component="post/content" class="content text-sm text-break">
17
- {./content}
17
+ {{./content}}
18
18
  </div>
19
19
  </div>
20
20
  <div class="mb-3 d-flex flex-wrap gap-1 w-100">
21
- {buildCategoryLabel(./category, "a", "border")}
21
+ {{buildCategoryLabel(./category, "a", "border")}}
22
22
  <span data-tid="{./topic.tid}" component="topic/tags" class="lh-1 tag-list d-flex flex-wrap gap-1 {{{ if !./topic.tags.length }}}hidden{{{ end }}}">
23
23
  {{{ each ./topic.tags }}}
24
24
  <a href="{config.relative_path}/tags/{./valueEncoded}"><span class="badge border border-gray-300 fw-normal tag tag-class-{./class}" data-tag="{./value}">{./valueEscaped}</span></a>
@@ -11,7 +11,7 @@
11
11
  {{{ each categories }}}
12
12
  <li data-cid="{./cid}" class="d-flex flex-column gap-1">
13
13
  <div class="btn btn-ghost btn-sm ff-secondary d-flex gap-2 align-items-center rounded-1 text-start text-reset d-block text-truncate px-2 py-1 position-relative">
14
- <div class="flex-shrink-0">{buildCategoryIcon(@value, "40px", "rounded-1")}</div>
14
+ <div class="flex-shrink-0">{{buildCategoryIcon(@value, "40px", "rounded-1")}}</div>
15
15
  <div class="flex-grow-1" style="min-width: 0;">
16
16
  <a class="stretched-link" href="{config.relative_path}/category/{./slug}"></a>
17
17
  <span class="quick-search-title fw-semibold text-sm">
@@ -22,7 +22,7 @@
22
22
  </span>
23
23
  <br/>
24
24
  <div class="snippet text-xs text-break text-wrap mb-0 text-sm text-secondary line-clamp-1">
25
- {./descriptionParsed}
25
+ {{./descriptionParsed}}
26
26
  </div>
27
27
  </div>
28
28
  </div>
@@ -21,7 +21,7 @@
21
21
  </a>
22
22
  <div class="d-flex gap-2 post-info px-2 text-xs">
23
23
  <div class="category-item d-inline-block ff-secondary">
24
- {buildCategoryLabel(posts.category, "span")}
24
+ {{buildCategoryLabel(posts.category, "span")}}
25
25
  </div>
26
26
  <span class="timeago text-muted" title="{posts.timestampISO}"></span>
27
27
  </div>
@@ -69,7 +69,7 @@
69
69
  <div component="user/filter/selected" class="d-flex flex-wrap gap-2">
70
70
  {{{ each userFilterSelected }}}
71
71
  <div class="d-flex px-2 py-1 rounded-1 text-bg-primary gap-2 align-items-center text-sm">
72
- {buildAvatar(@value, "16px", true)} {./username}
72
+ {{buildAvatar(@value, "16px", true)}} {./username}
73
73
  <button component="user/filter/delete" data-uid="{./uid}" class="btn btn-primary btn-sm py-0"><i class="fa fa-times fa-xs"></i></button>
74
74
  </div>
75
75
  {{{ end }}}
@@ -77,7 +77,7 @@
77
77
  <hr class="my-2"/>
78
78
  <div component="user/filter/results" class="d-flex flex-wrap gap-2">
79
79
  {{{ each userFilterResults }}}
80
- <button class="btn btn-light btn-sm border" data-uid="{./uid}" data-username="{./username}">{buildAvatar(@value, "16px", true)} {./username}</button>
80
+ <button class="btn btn-light btn-sm border" data-uid="{./uid}" data-username="{./username}">{{buildAvatar(@value, "16px", true)}} {./username}</button>
81
81
  {{{ end }}}
82
82
  </div>
83
83
  </li>