nodebb-theme-harmony 2.0.0-pre.40 → 2.0.0-pre.41

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/README.md CHANGED
@@ -10,6 +10,9 @@ Issues are tracked in [the main project issue tracker](https://github.com/NodeBB
10
10
  ## Screenshots
11
11
 
12
12
  ### Categories
13
+
14
+ _The cards in the header are added by the recent cards plugin. https://github.com/NodeBB-Community/nodebb-plugin-recent-cards_
15
+
13
16
  <img height="450" src="screenshots/categories.png">
14
17
 
15
18
  ### Recent
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-theme-harmony",
3
- "version": "2.0.0-pre.40",
3
+ "version": "2.0.0-pre.41",
4
4
  "nbbpm": {
5
5
  "compatibility": "^3.7.0"
6
6
  },
package/public/harmony.js CHANGED
@@ -254,20 +254,18 @@ $(document).ready(function () {
254
254
  return;
255
255
  }
256
256
  ['notifications', 'chat'].forEach((type) => {
257
- const countEl = document.querySelector(`[component="${type}/count"]`);
258
- if (!countEl) {
257
+ const countEl = $(`nav.sidebar [component="${type}/count"]`).first();
258
+ if (!countEl.length) {
259
259
  return;
260
260
  }
261
- const count = parseInt(countEl.innerText, 10);
261
+ const count = parseInt(countEl.text(), 10);
262
262
  if (count > 1) {
263
- const listEls = document.querySelectorAll(`[component="${type}/list"]`);
264
- listEls.forEach((listEl) => {
265
- const placeholder = listEl.querySelector('*');
266
- if (placeholder) {
267
- for (let x = 0; x < count - 1; x++) {
268
- const cloneEl = placeholder.cloneNode(true);
269
- listEl.insertBefore(cloneEl, placeholder);
270
- }
263
+ const listEls = $(`.dropdown-menu [component="${type}/list"]`);
264
+ listEls.each((index, el) => {
265
+ const placeholder = $(el).children().first();
266
+ for (let x = 0; x < count - 1; x++) {
267
+ const cloneEl = placeholder.clone(true);
268
+ cloneEl.insertAfter(placeholder);
271
269
  }
272
270
  });
273
271
  }
package/scss/harmony.scss CHANGED
@@ -15,7 +15,6 @@
15
15
  @import "modules/breadcrumbs";
16
16
  @import "modules/tags";
17
17
  @import "modules/user-menu";
18
- @import "modules/bottom-sheet";
19
18
  @import "modules/topic-navigator";
20
19
  @import "modules/topics-list";
21
20
  @import "modules/cover";
@@ -1,7 +1,7 @@
1
1
  ul.topics-list, ul.categories-list {
2
2
  li {
3
3
  &.deleted {
4
- .meta, .topic-thumbs { display: none!important; }
4
+ .meta, .topic-thumbs { visibility: hidden!important; }
5
5
  opacity: 0.65;
6
6
  }
7
7
 
package/scss/topic.scss CHANGED
@@ -9,11 +9,6 @@ body.template-topic {
9
9
  }
10
10
 
11
11
  .posts {
12
- // fixes code blocks pushing content out on mobile
13
- @include media-breakpoint-down(md) {
14
- max-width: calc(100vw - $grid-gutter-width);
15
- }
16
-
17
12
  &.timeline {
18
13
  @include timeline-style;
19
14
  }
@@ -27,10 +22,6 @@ body.template-topic {
27
22
  }
28
23
  }
29
24
 
30
- > [component="post"] > [component="post/footer"] {
31
- margin-left: calc($spacer * 2.5);
32
- }
33
-
34
25
  [component="post"] {
35
26
  &.selected .post-container {
36
27
  background-color: mix($body-bg, $body-color, 90%);
@@ -101,6 +92,7 @@ body.template-topic {
101
92
  &:last-of-type {
102
93
  padding-bottom: 0;
103
94
  .post-footer {
95
+ padding-bottom: 0!important;
104
96
  border-bottom: none !important;
105
97
  }
106
98
  }
@@ -113,7 +105,7 @@ body.template-topic {
113
105
  }
114
106
  }
115
107
 
116
- @include media-breakpoint-up(sm) {
108
+ @include media-breakpoint-up(lg) {
117
109
  body.template-topic {
118
110
  .topic .posts {
119
111
  [component="post"] {
@@ -129,7 +121,7 @@ body.template-topic {
129
121
  opacity: 1;
130
122
  }
131
123
  &:hover {
132
- > .post-footer > [component="post/actions"] {
124
+ > div > .post-container > [component="post/footer"] > div > [component="post/actions"] {
133
125
  opacity: 1;
134
126
  }
135
127
  }
@@ -29,6 +29,26 @@
29
29
  <input class="form-control" type="date" id="birthday" name="birthday" value="{birthday}" placeholder="mm/dd/yyyy">
30
30
  </div>
31
31
 
32
+ {{{ each customUserFields }}}
33
+ <div class="mb-3">
34
+ <label class="form-label fw-bold" for="{./key}">{./name}</label>
35
+ {{{ if ((./type == "input-text") || (./type == "input-link")) }}}
36
+ <input class="form-control" type="text" id="{./key}" name="{./key}" value="{./value}">
37
+ {{{ end }}}
38
+
39
+ {{{ if (./type == "input-number") }}}
40
+ <input class="form-control" type="number" id="{./key}" name="{./key}" value="{./value}">
41
+ {{{ end }}}
42
+ {{{ if (./type == "select") }}}
43
+ <select class="form-select" id="{./key}" name="{./key}">
44
+ {{{ each ./select-options}}}
45
+ <option value="{./value}" {{{ if ./selected }}}selected{{{ end }}}>{./value}</option>
46
+ {{{ end }}}
47
+ </select>
48
+ {{{ end }}}
49
+ </div>
50
+ {{{ end }}}
51
+
32
52
  <div class="mb-3">
33
53
  <label class="form-label fw-bold" for="groupTitle">[[user:grouptitle]]</label>
34
54
 
@@ -23,7 +23,7 @@
23
23
  {{{ end }}}
24
24
 
25
25
  <div class="account-stats container">
26
- <div class="row row-cols-2 row-cols-xl-3 row-cols-xxl-4 g-2">
26
+ <div class="row row-cols-2 row-cols-xl-3 row-cols-xxl-4 g-2 mb-5">
27
27
  {{{ if !reputation:disabled }}}
28
28
  <div class="stat">
29
29
  <div class="align-items-center justify-content-center card card-header px-0 py-3 border-0 rounded-1 h-100">
@@ -89,6 +89,21 @@
89
89
  </div>
90
90
  </div>
91
91
  {{{ end }}}
92
+
93
+ {{{ each customUserFields }}}
94
+ {{{ if ./value }}}
95
+ <div class="stat">
96
+ <div class="align-items-center justify-content-center card card-header px-0 py-3 border-0 rounded-1 h-100 gap-2">
97
+ <span class="stat-label text-xs fw-semibold"><span><i class="text-muted {./icon}"></i> {./name}</span></span>
98
+ {{{ if (./type == "input-link") }}}
99
+ <a class="text-sm text-center text-break w-100 px-2 ff-secondary text-underline text-reset" href="{./value}" rel="nofollow noreferrer me">{./value}</a>
100
+ {{{ else }}}
101
+ <span class="text-center fs-6 ff-secondary">{./value}</span>
102
+ {{{ end }}}
103
+ </div>
104
+ </div>
105
+ {{{ end }}}
106
+ {{{ end }}}
92
107
  </div>
93
108
  </div>
94
109
 
@@ -68,11 +68,11 @@
68
68
  {{{ if (loggedIn && (!isSelf && !banned)) }}}
69
69
  <hr class="w-100 my-2"/>
70
70
 
71
- <a {{{if flagId }}}hidden{{{end}}} href="#" component="account/flag" class="btn btn-ghost btn-sm ff-secondary d-flex align-items-center gap-2 text-start">
71
+ <a href="#" component="account/flag" class="btn btn-ghost btn-sm ff-secondary d-flex align-items-center gap-2 text-start {{{if flagId }}}hidden{{{end}}}">
72
72
  <i class="flex-shrink-0 fa-solid fa-flag text-danger"></i>
73
73
  <div class="flex-grow-1 text-nowrap">[[user:flag-profile]]</div>
74
74
  </a>
75
- <a {{{if !flagId }}}hidden{{{end}}} href="#" component="account/already-flagged" class="btn btn-ghost btn-sm ff-secondary d-flex align-items-center gap-2 text-start" data-flag-id="{flagId}">
75
+ <a href="#" component="account/already-flagged" class="btn btn-ghost btn-sm ff-secondary d-flex align-items-center gap-2 text-start {{{if !flagId }}}hidden{{{end}}}" data-flag-id="{flagId}">
76
76
  <i class="flex-shrink-0 fa-solid fa-flag text-danger"></i>
77
77
  <div class="flex-grow-1 text-nowrap">[[user:profile-flagged]]</div>
78
78
  </a>
@@ -20,8 +20,8 @@
20
20
  {{{ each ./children }}}
21
21
  {{{ if !./isSection }}}
22
22
  <span class="category-children-item small">
23
- <div class="d-flex align-items-center gap-1">
24
- <i class="fa fa-fw fa-caret-right text-primary align-self-start" style="line-height: var(--bs-body-line-height);"></i>
23
+ <div class="d-flex gap-1">
24
+ <i class="fa fa-fw fa-caret-right text-primary" style="line-height: var(--bs-body-line-height);"></i>
25
25
  <a href="{{{ if ./link }}}{./link}{{{ else }}}{config.relative_path}/category/{./slug}{{{ end }}}" class="text-reset fw-semibold">{./name}</a>
26
26
  </div>
27
27
  </span>
@@ -1,6 +1,7 @@
1
- {{{ if (brand:logo || config.showSiteTitle)}}}
1
+ {{{ if (brand:logo || (config.showSiteTitle || widgets.brand-header.length)) }}}
2
2
  <div class="container-lg px-md-4 brand-container">
3
3
  <div class="col-12 d-flex border-bottom pb-3 {{{ if config.theme.centerHeaderElements }}}justify-content-center{{{ end }}}">
4
+ {{{ if (brand:logo || config.showSiteTitle) }}}
4
5
  <div component="brand/wrapper" class="d-flex align-items-center gap-3 p-2 rounded-1 align-content-stretch ">
5
6
  {{{ if brand:logo }}}
6
7
  <a component="brand/anchor" href="{{{ if brand:logo:url }}}{brand:logo:url}{{{ else }}}{relative_path}/{{{ end }}}" title="[[global:header.brand-logo]]">
@@ -14,6 +15,7 @@
14
15
  </a>
15
16
  {{{ end }}}
16
17
  </div>
18
+ {{{ end }}}
17
19
  {{{ if widgets.brand-header.length }}}
18
20
  <div data-widget-area="brand-header" class="flex-fill gap-3 p-2 align-self-center">
19
21
  {{{each widgets.brand-header}}}
@@ -4,6 +4,7 @@
4
4
  <span class="menu-icon"><i class="fa fa-fw text-secondary fa-pencil"></i></span> [[topic:edit]]
5
5
  </a>
6
6
  </li>
7
+ {{{ if posts.display_delete_tools }}}
7
8
  <li {{{ if posts.deleted }}}hidden{{{ end }}}>
8
9
  <a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/delete" role="menuitem" href="#" class="{{{ if posts.deleted }}}hidden{{{ end }}}">
9
10
  <span class="menu-icon"><i class="fa fa-fw text-secondary fa-trash-o"></i></span> [[topic:delete]]
@@ -14,6 +15,7 @@
14
15
  <span class="menu-icon"><i class="fa fa-fw text-secondary fa-history"></i></span> [[topic:restore]]
15
16
  </a>
16
17
  </li>
18
+ {{{ end }}}
17
19
  {{{ if posts.display_purge_tools }}}
18
20
  <li {{{ if !posts.deleted }}}hidden{{{ end }}}>
19
21
  <a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/purge" role="menuitem" href="#" class="{{{ if !posts.deleted }}}hidden{{{ end }}}">
@@ -38,6 +40,14 @@
38
40
  </li>
39
41
  {{{ end }}}
40
42
 
43
+ {{{ if posts.display_manage_editors_tools }}}
44
+ <li>
45
+ <a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/manage-editors" role="menuitem" href="#">
46
+ <span class="menu-icon"><i class="fa fa-fw text-secondary fa-user-pen"></i></span> [[topic:manage-editors]]
47
+ </a>
48
+ </li>
49
+ {{{ end }}}
50
+
41
51
  {{{ if posts.ip }}}
42
52
  <li>
43
53
  <a class="dropdown-item rounded-1 d-flex align-items-center gap-2" component="post/copy-ip" role="menuitem" href="#" data-clipboard-text="{posts.ip}">
@@ -19,123 +19,125 @@
19
19
  {{{ end }}}
20
20
  </a>
21
21
  </div>
22
- <div class="post-container d-flex flex-grow-1 flex-column w-100" style="min-width:0;">
23
- <div class="d-flex align-items-center gap-1 flex-wrap w-100 post-header mt-1" itemprop="author" itemscope itemtype="https://schema.org/Person">
24
- <meta itemprop="name" content="{./user.username}">
25
- {{{ if ./user.userslug }}}<meta itemprop="url" content="{config.relative_path}/user/{./user.userslug}">{{{ end }}}
26
-
27
- <div class="bg-body d-sm-none">
28
- <a class="d-inline-block position-relative text-decoration-none" href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}">
29
- {buildAvatar(posts.user, "20px", true, "", "user/picture")}
30
- {{{ if ./user.isLocal }}}
31
- <span component="user/status" class="position-absolute top-100 start-100 border border-white border-2 rounded-circle status {posts.user.status}"><span class="visually-hidden">[[global:{posts.user.status}]]</span></span>
32
- {{{ else }}}
33
- <span component="user/locality" class="position-absolute top-100 start-100 lh-1 border border-white border-2 rounded-circle small" title="[[global:remote-user]]">
34
- <span class="visually-hidden">[[global:remote-user]]</span>
35
- <i class="fa fa-globe"></i>
36
- </span>
37
- {{{ end }}}
38
- </a>
39
- </div>
40
-
41
- <a class="fw-bold text-nowrap" href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}" data-username="{posts.user.username}" data-uid="{posts.user.uid}">{posts.user.displayname}</a>
42
-
43
- {{{ each posts.user.selectedGroups }}}
44
- {{{ if posts.user.selectedGroups.slug }}}
45
- <!-- IMPORT partials/groups/badge.tpl -->
46
- {{{ end }}}
47
- {{{ end }}}
22
+ <div class="post-container d-flex gap-2 flex-grow-1 flex-column w-100" style="min-width:0;">
23
+ <div class="d-flex align-items-start justify-content-between gap-1 flex-nowrap w-100 post-header" itemprop="author" itemscope itemtype="https://schema.org/Person">
24
+ <div class="d-flex gap-1 flex-wrap align-items-center">
25
+ <meta itemprop="name" content="{./user.username}">
26
+ {{{ if ./user.userslug }}}<meta itemprop="url" content="{config.relative_path}/user/{./user.userslug}">{{{ end }}}
27
+
28
+ <div class="bg-body d-sm-none">
29
+ <a class="d-inline-block position-relative text-decoration-none" href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}">
30
+ {buildAvatar(posts.user, "20px", true, "", "user/picture")}
31
+ {{{ if ./user.isLocal }}}
32
+ <span component="user/status" class="position-absolute top-100 start-100 border border-white border-2 rounded-circle status {posts.user.status}"><span class="visually-hidden">[[global:{posts.user.status}]]</span></span>
33
+ {{{ else }}}
34
+ <span component="user/locality" class="position-absolute top-100 start-100 lh-1 border border-white border-2 rounded-circle small" title="[[global:remote-user]]">
35
+ <span class="visually-hidden">[[global:remote-user]]</span>
36
+ <i class="fa fa-globe"></i>
37
+ </span>
38
+ {{{ end }}}
39
+ </a>
40
+ </div>
41
+
42
+ <a class="fw-bold text-nowrap" href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}" data-username="{posts.user.username}" data-uid="{posts.user.uid}">{posts.user.displayname}</a>
43
+
44
+ {{{ each posts.user.selectedGroups }}}
45
+ {{{ if posts.user.selectedGroups.slug }}}
46
+ <!-- IMPORT partials/groups/badge.tpl -->
47
+ {{{ end }}}
48
+ {{{ end }}}
48
49
 
49
- {{{ if posts.user.banned }}}
50
- <span class="badge bg-danger rounded-1">[[user:banned]]</span>
51
- {{{ end }}}
50
+ {{{ if posts.user.banned }}}
51
+ <span class="badge bg-danger rounded-1">[[user:banned]]</span>
52
+ {{{ end }}}
52
53
 
53
- <div class="d-flex gap-1 align-items-center">
54
- <span class="text-muted">{generateWroteReplied(@value, config.timeagoCutoff)}</span>
54
+ <div class="d-flex gap-1 align-items-center">
55
+ <span class="text-muted">{generateWroteReplied(@value, config.timeagoCutoff)}</span>
55
56
 
56
- <i component="post/edit-indicator" class="fa fa-edit text-muted{{{ if privileges.posts:history }}} pointer{{{ end }}} edit-icon {{{ if !posts.editor.username }}}hidden{{{ end }}}" title="[[global:edited-timestamp, {isoTimeToLocaleString(./editedISO, config.userLang)}]]"></i>
57
- <span data-editor="{posts.editor.userslug}" component="post/editor" class="visually-hidden">[[global:last-edited-by, {posts.editor.username}]] <span class="timeago" title="{isoTimeToLocaleString(posts.editedISO, config.userLang)}"></span></span>
58
- </div>
57
+ <i component="post/edit-indicator" class="fa fa-edit text-muted{{{ if privileges.posts:history }}} pointer{{{ end }}} edit-icon {{{ if !posts.editor.username }}}hidden{{{ end }}}" title="[[global:edited-timestamp, {isoTimeToLocaleString(./editedISO, config.userLang)}]]"></i>
58
+ <span data-editor="{posts.editor.userslug}" component="post/editor" class="visually-hidden">[[global:last-edited-by, {posts.editor.username}]] <span class="timeago" title="{isoTimeToLocaleString(posts.editedISO, config.userLang)}"></span></span>
59
+ </div>
59
60
 
60
- {{{ if posts.user.custom_profile_info.length }}}
61
- <div>
62
- <span>
63
- &#124;
64
- {{{ each posts.user.custom_profile_info }}}
65
- {posts.user.custom_profile_info.content}
66
- {{{ end }}}
67
- </span>
61
+ {{{ if posts.user.custom_profile_info.length }}}
62
+ <div>
63
+ <span>
64
+ &#124;
65
+ {{{ each posts.user.custom_profile_info }}}
66
+ {posts.user.custom_profile_info.content}
67
+ {{{ end }}}
68
+ </span>
69
+ </div>
70
+ {{{ end }}}
68
71
  </div>
69
- {{{ end }}}
70
- <div class="d-flex align-items-center gap-1 flex-grow-1 justify-content-end">
72
+ <div class="d-flex align-items-center gap-1 justify-content-end">
71
73
  <span class="bookmarked opacity-0 text-primary"><i class="fa fa-bookmark-o"></i></span>
72
74
  <a href="{config.relative_path}/post/{encodeURIComponent(./pid)}" class="post-index text-muted d-none d-md-inline">#{increment(./index, "1")}</a>
73
75
  </div>
74
76
  </div>
75
77
 
76
- <div class="content mt-2 text-break" component="post/content" itemprop="text">
78
+ <div class="content text-break" component="post/content" itemprop="text">
77
79
  {posts.content}
78
80
  </div>
79
- </div>
80
- </div>
81
-
82
- <div component="post/footer" class="post-footer border-bottom pb-2">
83
- {{{ if posts.user.signature }}}
84
- <div component="post/signature" data-uid="{posts.user.uid}" class="text-xs text-muted mt-2">{posts.user.signature}</div>
85
- {{{ end }}}
86
81
 
87
- <div class="d-flex">
88
- {{{ if !hideReplies }}}
89
- <a component="post/reply-count" data-target-component="post/replies/container" href="#" class="d-flex gap-2 align-items-center mt-2 btn btn-ghost ff-secondary border rounded-1 p-1 text-muted text-decoration-none text-xs {{{ if (!./replies || shouldHideReplyContainer(@value)) }}}hidden{{{ end }}}">
90
- <span component="post/reply-count/avatars" class="d-flex gap-1 {{{ if posts.replies.hasMore }}}hasMore{{{ end }}}">
91
- {{{each posts.replies.users}}}
92
- <span>{buildAvatar(posts.replies.users, "20px", true, "avatar-tooltip")}</span>
93
- {{{end}}}
94
- {{{ if posts.replies.hasMore}}}
95
- <span style="height: 20px; line-height: 20px;"><i class="fa fa-ellipsis"></i></span>
96
- {{{ end }}}
97
- </span>
98
-
99
- <span class="ms-2 replies-count fw-semibold" component="post/reply-count/text" data-replies="{posts.replies.count}">{posts.replies.text}</span>
100
- <span class="ms-2 replies-last hidden-xs fw-semibold">[[topic:last-reply-time]] <span class="timeago" title="{posts.replies.timestampISO}"></span></span>
82
+ <div component="post/footer" class="post-footer border-bottom pb-2">
83
+ {{{ if posts.user.signature }}}
84
+ <div component="post/signature" data-uid="{posts.user.uid}" class="text-xs text-muted mt-2">{posts.user.signature}</div>
85
+ {{{ end }}}
101
86
 
102
- <i class="fa fa-fw fa-chevron-down" component="post/replies/open"></i>
103
- </a>
104
- {{{ end }}}
105
- </div>
87
+ <div class="d-flex flex-wrap {{{ if (hideReplies || !posts.replies.count) }}}justify-content-end{{{ else }}}justify-content-between{{{ end }}}">
88
+ {{{ if !hideReplies }}}
89
+ <a component="post/reply-count" data-target-component="post/replies/container" href="#" class="d-flex gap-2 align-items-center btn btn-ghost ff-secondary border rounded-1 p-1 text-muted text-decoration-none text-xs {{{ if (!./replies || shouldHideReplyContainer(@value)) }}}hidden{{{ end }}}">
90
+ <span component="post/reply-count/avatars" class="d-flex gap-1 {{{ if posts.replies.hasMore }}}hasMore{{{ end }}}">
91
+ {{{each posts.replies.users}}}
92
+ <span>{buildAvatar(posts.replies.users, "20px", true, "avatar-tooltip")}</span>
93
+ {{{end}}}
94
+ {{{ if posts.replies.hasMore}}}
95
+ <span style="height: 20px; line-height: 20px;"><i class="fa fa-ellipsis"></i></span>
96
+ {{{ end }}}
97
+ </span>
106
98
 
107
- <div component="post/replies/container" class="my-2 col-11 border rounded-1 p-3 hidden-empty"></div>
99
+ <span class="ms-2 replies-count fw-semibold text-nowrap" component="post/reply-count/text" data-replies="{posts.replies.count}">{posts.replies.text}</span>
100
+ <span class="ms-2 replies-last hidden-xs fw-semibold">[[topic:last-reply-time]] <span class="timeago" title="{posts.replies.timestampISO}"></span></span>
108
101
 
109
- <div component="post/actions" class="d-flex justify-content-end gap-1 post-tools">
110
- <!-- IMPORT partials/topic/reactions.tpl -->
111
- <a component="post/reply" href="#" class="btn btn-ghost btn-sm {{{ if !privileges.topics:reply }}}hidden{{{ end }}}" title="[[topic:reply]]"><i class="fa fa-fw fa-reply text-primary"></i></a>
112
- <a component="post/quote" href="#" class="btn btn-ghost btn-sm {{{ if !privileges.topics:reply }}}hidden{{{ end }}}" title="[[topic:quote]]"><i class="fa fa-fw fa-quote-right text-primary"></i></a>
102
+ <i class="fa fa-fw fa-chevron-down" component="post/replies/open"></i>
103
+ </a>
104
+ {{{ end }}}
105
+ <div component="post/actions" class="d-flex flex-grow-1 justify-content-end gap-1 post-tools">
106
+ <!-- IMPORT partials/topic/reactions.tpl -->
107
+ <a component="post/reply" href="#" class="btn btn-ghost btn-sm {{{ if !privileges.topics:reply }}}hidden{{{ end }}}" title="[[topic:reply]]"><i class="fa fa-fw fa-reply text-primary"></i></a>
108
+ <a component="post/quote" href="#" class="btn btn-ghost btn-sm {{{ if !privileges.topics:reply }}}hidden{{{ end }}}" title="[[topic:quote]]"><i class="fa fa-fw fa-quote-right text-primary"></i></a>
113
109
 
114
- {{{ if ./announces }}}
115
- <a component="post/announce-count" href="#" class="btn btn-ghost btn-sm d-flex gap-2 align-items-center" title="[[activitypub:announcers]]"><i class="fa fa-share-alt text-primary"></i> {./announces}</a>
116
- {{{ end }}}
110
+ {{{ if ./announces }}}
111
+ <a component="post/announce-count" href="#" class="btn btn-ghost btn-sm d-flex gap-2 align-items-center" title="[[activitypub:announcers]]"><i class="fa fa-share-alt text-primary"></i> {./announces}</a>
112
+ {{{ end }}}
117
113
 
118
- {{{ if !reputation:disabled }}}
119
- <div class="d-flex votes align-items-center">
120
- <a component="post/upvote" href="#" class="btn btn-ghost btn-sm{{{ if posts.upvoted }}} upvoted{{{ end }}}" title="[[topic:upvote-post]]">
121
- <i class="fa fa-fw fa-chevron-up text-primary"></i>
122
- </a>
114
+ {{{ if !reputation:disabled }}}
115
+ <div class="d-flex votes align-items-center">
116
+ <a component="post/upvote" href="#" class="btn btn-ghost btn-sm{{{ if posts.upvoted }}} upvoted{{{ end }}}" title="[[topic:upvote-post]]">
117
+ <i class="fa fa-fw fa-chevron-up text-primary"></i>
118
+ </a>
119
+
120
+ <meta itemprop="upvoteCount" content="{posts.upvotes}">
121
+ <meta itemprop="downvoteCount" content="{posts.downvotes}">
122
+ <a href="#" class="px-2 mx-1 btn btn-ghost btn-sm" component="post/vote-count" data-votes="{posts.votes}" title="[[global:voters]]">{posts.votes}</a>
123
+
124
+ {{{ if !downvote:disabled }}}
125
+ <a component="post/downvote" href="#" class="btn btn-ghost btn-sm{{{ if posts.downvoted }}} downvoted{{{ end }}}" title="[[topic:downvote-post]]">
126
+ <i class="fa fa-fw fa-chevron-down text-primary"></i>
127
+ </a>
128
+ {{{ end }}}
129
+ </div>
130
+ {{{ end }}}
123
131
 
124
- <meta itemprop="upvoteCount" content="{posts.upvotes}">
125
- <meta itemprop="downvoteCount" content="{posts.downvotes}">
126
- <a href="#" class="px-2 mx-1 btn btn-ghost btn-sm" component="post/vote-count" data-votes="{posts.votes}" title="[[global:voters]]">{posts.votes}</a>
132
+ <!-- IMPORT partials/topic/post-menu.tpl -->
133
+ </div>
134
+ </div>
127
135
 
128
- {{{ if !downvote:disabled }}}
129
- <a component="post/downvote" href="#" class="btn btn-ghost btn-sm{{{ if posts.downvoted }}} downvoted{{{ end }}}" title="[[topic:downvote-post]]">
130
- <i class="fa fa-fw fa-chevron-down text-primary"></i>
131
- </a>
132
- {{{ end }}}
136
+ <div component="post/replies/container" class="my-2 col-11 border rounded-1 p-3 hidden-empty"></div>
133
137
  </div>
134
- {{{ end }}}
135
-
136
- <!-- IMPORT partials/topic/post-menu.tpl -->
137
138
  </div>
138
139
  </div>
140
+
139
141
  {{{ if (!./index && widgets.mainpost-footer.length) }}}
140
142
  <div data-widget-area="mainpost-footer">
141
143
  {{{ each widgets.mainpost-footer }}}
@@ -1,6 +1,6 @@
1
1
  <div class="{{{ if config.theme.stickyToolbar }}}sticky-tools{{{ end }}} mb-3">
2
2
  <nav class="topic-list-header d-flex flex-nowrap my-2 p-0 border-0 rounded">
3
- <div class="d-flex flex-row p-2 text-bg-light gap-1 border rounded w-100 align-items-center">
3
+ <div class="d-flex flex-row p-2 text-bg-light gap-1 border rounded w-100">
4
4
  <div component="category/controls" class="d-flex me-auto mb-0 gap-2 flex-wrap">
5
5
  {{{ if (template.category || template.world) }}}
6
6
  <!-- IMPORT partials/category/watch.tpl -->