@okjavis/nodebb-theme-javis 3.0.3 → 3.0.6

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okjavis/nodebb-theme-javis",
3
- "version": "3.0.3",
3
+ "version": "3.0.6",
4
4
  "description": "Modern, premium NodeBB theme for JAVIS Community - Extends Harmony with custom styling",
5
5
  "main": "theme.js",
6
6
  "scripts": {
package/scss/_feed.scss CHANGED
@@ -58,11 +58,8 @@
58
58
  display: none !important;
59
59
  }
60
60
 
61
- // Hide the controls row (category dropdown, options)
62
- // The composer prompt card replaces this functionality
63
- > .row > div > .d-flex.justify-content-between.py-2.mb-2 {
64
- display: none !important;
65
- }
61
+ // The controls row is now visible but the new_topic button is hidden
62
+ // JS injects the composer prompt card before this row
66
63
  }
67
64
 
68
65
  // ===========================================================
@@ -74,7 +71,7 @@
74
71
  border-radius: $jv-radius-lg;
75
72
  padding: $jv-space-4 $jv-space-6; // 16px top/bottom, 24px left/right
76
73
  margin-top: $jv-space-4; // Align with trending tags padding-top
77
- margin-bottom: $jv-space-4;
74
+ margin-bottom: $jv-space-2; // Reduced bottom margin for tighter spacing
78
75
  box-shadow: $jv-shadow-sm;
79
76
  transition: box-shadow $jv-transition-fast, border-color $jv-transition-fast;
80
77
 
@@ -486,7 +483,7 @@
486
483
  .content[component="post/content"] {
487
484
  font-size: 15px !important; // Slightly larger for better readability
488
485
  line-height: 1.6 !important;
489
- color: $jv-text-muted;
486
+ color: #000000 !important; // Black text for feed body copy
490
487
  margin-top: $jv-space-3; // Better spacing from meta
491
488
 
492
489
  // Truncation styles (from plugin)
@@ -1001,3 +998,140 @@ ul.categories-list {
1001
998
  }
1002
999
  }
1003
1000
  }
1001
+
1002
+ // ===========================================================
1003
+ // FEED CATEGORY FILTER - LinkedIn Style
1004
+ // Minimal text-based dropdown like "Sort by: Top"
1005
+ // ===========================================================
1006
+
1007
+ // Ultra-specific override to remove pill button styling
1008
+ .feed .feed-category-filter .btn-group .btn.btn-ghost.btn-sm.dropdown-toggle,
1009
+ .feed .feed-category-filter .category-dropdown-container .btn.btn-ghost.btn-sm,
1010
+ .feed .feed-category-filter button.btn.btn-ghost.btn-sm {
1011
+ border: none !important;
1012
+ border-width: 0 !important;
1013
+ border-color: transparent !important;
1014
+ border-radius: 4px !important;
1015
+ background: transparent !important;
1016
+ box-shadow: none !important;
1017
+ }
1018
+
1019
+ .feed-category-filter {
1020
+ .category-dropdown-container,
1021
+ [component="category/dropdown"] {
1022
+ // Override the btn-group styling
1023
+ &.btn-group {
1024
+ border: none !important;
1025
+ box-shadow: none !important;
1026
+ }
1027
+
1028
+ // Target the specific button with all its classes
1029
+ .dropdown-toggle,
1030
+ .btn.btn-ghost.btn-sm.dropdown-toggle,
1031
+ button.dropdown-toggle {
1032
+ // LinkedIn style - minimal, text-based, NO border
1033
+ padding: 4px 8px !important;
1034
+ font-size: 12px !important;
1035
+ font-weight: 400 !important;
1036
+ color: $jv-text-muted !important;
1037
+ background: transparent !important;
1038
+ background-color: transparent !important;
1039
+ border: none !important;
1040
+ border-width: 0 !important;
1041
+ border-color: transparent !important;
1042
+ box-shadow: none !important;
1043
+ border-radius: 4px !important;
1044
+ min-width: auto !important;
1045
+ gap: 4px !important;
1046
+
1047
+ // Hide the category icon, show only name
1048
+ .category-item {
1049
+ gap: 4px !important;
1050
+
1051
+ // Hide category icon on compact view
1052
+ .rounded-circle,
1053
+ [component="category/icon"],
1054
+ span[style*="background"] {
1055
+ display: none !important;
1056
+ }
1057
+
1058
+ // Show category name - smaller text
1059
+ span.d-none.d-md-inline,
1060
+ .fw-semibold {
1061
+ display: inline !important;
1062
+ font-size: 12px !important;
1063
+ font-weight: 600 !important;
1064
+ color: $jv-text-main !important;
1065
+ }
1066
+ }
1067
+
1068
+ // "All Categories" state
1069
+ > i.fa-list {
1070
+ font-size: 12px !important;
1071
+ color: $jv-text-muted !important;
1072
+ }
1073
+
1074
+ // Show "All Categories" text
1075
+ > span.d-none.d-md-inline,
1076
+ > .fw-semibold {
1077
+ display: inline !important;
1078
+ font-size: 12px !important;
1079
+ font-weight: 600 !important;
1080
+ color: $jv-text-main !important;
1081
+ }
1082
+
1083
+ // Dropdown arrow - smaller
1084
+ &::after {
1085
+ font-size: 8px !important;
1086
+ margin-left: 4px !important;
1087
+ color: $jv-text-muted !important;
1088
+ border-top-width: 4px !important;
1089
+ border-right-width: 4px !important;
1090
+ border-left-width: 4px !important;
1091
+ }
1092
+
1093
+ &:hover {
1094
+ background: rgba(0, 0, 0, 0.04) !important;
1095
+ background-color: rgba(0, 0, 0, 0.04) !important;
1096
+ color: $jv-text-main !important;
1097
+ border: none !important;
1098
+ box-shadow: none !important;
1099
+ }
1100
+
1101
+ &:focus,
1102
+ &:active {
1103
+ background: transparent !important;
1104
+ border: none !important;
1105
+ box-shadow: none !important;
1106
+ outline: none !important;
1107
+ }
1108
+ }
1109
+
1110
+ // Dropdown menu styling
1111
+ .dropdown-menu {
1112
+ min-width: 180px;
1113
+ max-width: 240px;
1114
+ border-radius: $jv-radius-md !important;
1115
+ border: 1px solid $jv-border-subtle !important;
1116
+ box-shadow: $jv-shadow-card !important;
1117
+ padding: $jv-space-1 !important;
1118
+ margin-top: 4px !important;
1119
+
1120
+ .category-dropdown-menu {
1121
+ max-height: 280px;
1122
+ overflow-y: auto;
1123
+ }
1124
+
1125
+ .dropdown-item {
1126
+ font-size: 13px !important;
1127
+ padding: 6px 12px !important;
1128
+ border-radius: $jv-radius-xs !important;
1129
+ color: $jv-text-main !important;
1130
+
1131
+ &:hover {
1132
+ background: $jv-hover-bg !important;
1133
+ }
1134
+ }
1135
+ }
1136
+ }
1137
+ }
package/scss/_topic.scss CHANGED
@@ -32,9 +32,32 @@ body.template-topic {
32
32
  [component="post/header"].fs-3 {
33
33
  margin-bottom: 0;
34
34
  display: flex;
35
- align-items: flex-start;
35
+ align-items: center; // Center align items vertically
36
36
  gap: $jv-space-3;
37
37
 
38
+ // Back button styling
39
+ .topic-back-btn {
40
+ display: flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ width: 36px;
44
+ height: 36px;
45
+ border-radius: $jv-radius-sm;
46
+ color: $jv-text-muted;
47
+ text-decoration: none;
48
+ transition: background-color $jv-transition-fast, color $jv-transition-fast;
49
+ flex-shrink: 0;
50
+
51
+ &:hover {
52
+ background: $jv-hover-bg;
53
+ color: $jv-text-main;
54
+ }
55
+
56
+ i {
57
+ font-size: 18px;
58
+ }
59
+ }
60
+
38
61
  h1,
39
62
  [component="topic/title"],
40
63
  .topic-title {
@@ -142,33 +165,71 @@ body.template-topic {
142
165
  display: none !important;
143
166
  }
144
167
 
145
- // Card styling on the parent container that includes avatar
168
+ // Card styling - vertical stack layout (like feed page)
146
169
  .post-container-parent {
147
170
  background: $jv-surface;
148
171
  border-radius: $jv-radius-md;
149
172
  border: 1px solid $jv-border-subtle;
150
- padding: $jv-space-3;
151
- gap: $jv-space-2 !important; // Tighter gap
152
-
153
- // Reduce avatar size from 48px to 36px
154
- > .bg-body {
155
- // Align avatar container with the post header (username/timestamp line)
156
- align-self: flex-start;
157
- margin-top: 2px; // Fine-tune to vertically center with text
158
-
159
- [component="user/picture"],
160
- .avatar {
161
- width: 36px !important;
162
- height: 36px !important;
163
- font-size: $jv-font-size-sm !important;
164
- line-height: 36px !important;
173
+ padding: $jv-space-4;
174
+ gap: $jv-space-3 !important;
175
+ }
176
+
177
+ // Author row - avatar + username + timestamp inline
178
+ .post-author-row {
179
+ display: flex;
180
+ align-items: center;
181
+ gap: $jv-space-2;
182
+
183
+ // Avatar size 32px
184
+ [component="user/picture"],
185
+ .avatar {
186
+ width: 32px !important;
187
+ height: 32px !important;
188
+ min-width: 32px !important;
189
+ min-height: 32px !important;
190
+ font-size: $jv-font-size-sm !important;
191
+ line-height: 32px !important;
192
+ border-radius: 50% !important;
193
+ }
194
+
195
+ // Author name
196
+ .post-author-name {
197
+ font-weight: 600;
198
+ font-size: $jv-font-size-sm;
199
+ color: $jv-text-main;
200
+ text-decoration: none;
201
+
202
+ &:hover {
203
+ color: $jv-primary;
165
204
  }
166
205
  }
167
- }
168
206
 
169
- // Align the post header row with avatar (extends base .post-header)
170
- .post-header {
171
- min-height: 36px; // Match avatar height for alignment
207
+ // Timestamp
208
+ .post-timestamp {
209
+ font-size: $jv-font-size-xs;
210
+ color: $jv-text-soft;
211
+
212
+ &::before {
213
+ content: "• ";
214
+ margin-right: 2px;
215
+ }
216
+ }
217
+
218
+ // Edit indicator
219
+ .edit-icon {
220
+ font-size: $jv-font-size-xs;
221
+ }
222
+
223
+ // Post index
224
+ .post-index {
225
+ font-size: $jv-font-size-xs;
226
+ color: $jv-text-soft;
227
+ opacity: 0.6;
228
+ }
229
+
230
+ .bookmarked {
231
+ color: $jv-warning;
232
+ }
172
233
  }
173
234
 
174
235
  .post-container {
@@ -185,7 +246,7 @@ body.template-topic {
185
246
  }
186
247
 
187
248
  // ===========================================================
188
- // POST HEADER Avatar, Username, Time
249
+ // POST HEADER (legacy support for any remaining old structure)
189
250
  // ===========================================================
190
251
  .post-header {
191
252
  display: flex;
@@ -777,6 +838,22 @@ body.template-topic {
777
838
  margin-top: $jv-space-6;
778
839
  border: 1px solid $jv-border-subtle;
779
840
 
841
+ // Reduce avatar size to 32px (matching post author avatars)
842
+ [component="user/picture"],
843
+ .avatar {
844
+ width: 32px !important;
845
+ height: 32px !important;
846
+ min-width: 32px !important;
847
+ min-height: 32px !important;
848
+ font-size: $jv-font-size-sm !important;
849
+ line-height: 32px !important;
850
+ }
851
+
852
+ // Hide user status indicator (green dot)
853
+ [component="user/status"] {
854
+ display: none !important;
855
+ }
856
+
780
857
  .quick-reply-header {
781
858
  margin-bottom: $jv-space-4;
782
859
  font-weight: 600;
@@ -203,13 +203,42 @@
203
203
 
204
204
  /**
205
205
  * Initialize sidebar toggle click handler
206
- * We don't need our own handler - Harmony's handler works fine.
207
- * This function is now a no-op to avoid conflicts.
206
+ * Custom handler needed because Harmony's handler targets .sidebar but JAVIS uses .sidebar-left
208
207
  */
209
208
  function initSidebarToggle() {
210
- // Let Harmony's built-in handler manage the sidebar toggle
211
- // We just ensure the sidebar auto-expands on desktop (handled by initSidebarAutoExpand)
212
- console.log('JAVIS: Sidebar toggle - using Harmony default handler');
209
+ var $toggle = $('[component="sidebar/toggle"]');
210
+ if (!$toggle.length) {
211
+ console.log('JAVIS: Sidebar toggle element not found');
212
+ return;
213
+ }
214
+
215
+ // Remove any existing handlers to avoid duplicates, then add our handler
216
+ $toggle.off('click.javis').on('click.javis', function(e) {
217
+ e.preventDefault();
218
+ e.stopPropagation();
219
+
220
+ var $sidebar = $('.sidebar-left');
221
+ $sidebar.toggleClass('open');
222
+
223
+ console.log('JAVIS: Sidebar toggled, open:', $sidebar.hasClass('open'));
224
+
225
+ // Save preference if user is logged in
226
+ if (typeof app !== 'undefined' && app.user && app.user.uid) {
227
+ require(['api'], function(api) {
228
+ api.put('/users/' + app.user.uid + '/settings', {
229
+ settings: {
230
+ openSidebars: $sidebar.hasClass('open') ? 'on' : 'off',
231
+ },
232
+ }).catch(function(err) {
233
+ console.warn('JAVIS: Could not save sidebar preference', err);
234
+ });
235
+ });
236
+ }
237
+
238
+ $(window).trigger('action:sidebar.toggle');
239
+ });
240
+
241
+ console.log('JAVIS: Sidebar toggle initialized');
213
242
  }
214
243
 
215
244
  /**
@@ -402,7 +431,14 @@
402
431
  }
403
432
 
404
433
  // Find the existing controls row (contains New Topic button)
405
- var $controlsRow = $('.feed .d-flex.justify-content-between.py-2.mb-2').first();
434
+ // Try mb-0, mb-1 and mb-2 for compatibility
435
+ var $controlsRow = $('.feed .d-flex.justify-content-between.py-2.mb-0').first();
436
+ if (!$controlsRow.length) {
437
+ $controlsRow = $('.feed .d-flex.justify-content-between.py-2.mb-1').first();
438
+ }
439
+ if (!$controlsRow.length) {
440
+ $controlsRow = $('.feed .d-flex.justify-content-between.py-2.mb-2').first();
441
+ }
406
442
  if (!$controlsRow.length) {
407
443
  return;
408
444
  }
@@ -26,39 +26,16 @@
26
26
  <div class="col-lg-6 col-sm-12 ms-auto">
27
27
  {{{ end }}}
28
28
 
29
- <div class="d-flex justify-content-between py-2 mb-2 gap-1">
29
+ <!-- Controls row for composer prompt injection -->
30
+ <div class="d-flex justify-content-between py-2 mb-0 gap-1">
30
31
  {{{ if canPost }}}
31
- <button id="new_topic" class="btn btn-primary btn-sm">[[category:new-topic-button]]</button>
32
+ <button id="new_topic" class="btn btn-primary btn-sm d-none">[[category:new-topic-button]]</button>
32
33
  {{{ end }}}
33
- {{{ if (!loggedIn && !canPost) }}}
34
- <a href="{config.relative_path}/login" class="btn btn-primary btn-sm">[[category:guest-login-post]]</a>
35
- {{{ end }}}
36
-
37
- <div class="d-flex justify-content-end gap-1">
38
- <!-- IMPORT partials/category/filter-dropdown-right.tpl -->
34
+ </div>
39
35
 
40
- <div id="options-dropdown" class="btn-group dropdown dropdown-right bottom-sheet">
41
- <button type="button" class="btn btn-ghost btn-sm d-flex align-items-center gap-2 ff-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
42
- <i class="fa fa-fw fa-gear text-primary"></i>
43
- </button>
44
- <ul class="dropdown-menu p-1 text-sm" role="menu">
45
- <li class="py-1 px-3">
46
- <div class="form-check form-switch d-flex px-0 align-items-center justify-content-between gap-3">
47
- <label class="form-check-label text-nowrap" for="showAllPosts">[[feed:show-all-posts]]</label>
48
- <input class="form-check-input float-none m-0 pointer" type="checkbox" role="switch" id="showAllPosts" {{{ if showAllPosts }}}checked{{{ end }}}>
49
- </div>
50
- </li>
51
- {{{ if loggedIn }}}
52
- <li class="py-1 px-3">
53
- <div class="form-check form-switch d-flex px-0 align-items-center justify-content-between gap-3">
54
- <label class="form-check-label text-nowrap" for="showFollowedUsers">[[feed:followed-users-only]]</label>
55
- <input class="form-check-input float-none m-0 pointer" type="checkbox" role="switch" id="showFollowedUsers" {{{ if showFollowed }}}checked{{{ end }}}>
56
- </div>
57
- </li>
58
- {{{ end }}}
59
- </ul>
60
- </div>
61
- </div>
36
+ <!-- Category filter - LinkedIn style, right aligned, tight spacing -->
37
+ <div class="d-flex justify-content-end py-1 feed-category-filter">
38
+ <!-- IMPORT partials/category/filter-dropdown-right.tpl -->
62
39
  </div>
63
40
 
64
41
  {{{ if !posts.length }}}
@@ -70,25 +47,23 @@
70
47
  <li component="post" class="shadow-sm mb-3 rounded-2 border posts-list-item {{{ if ./deleted }}} deleted{{{ else }}}{{{ if ./topic.deleted }}} deleted{{{ end }}}{{{ end }}}{{{ if ./topic.scheduled }}} scheduled{{{ end }}}" data-pid="{./pid}" data-uid="{./uid}">
71
48
 
72
49
  <!-- 1. CONTENT (first) -->
73
- <div class="d-flex gap-2 p-3">
74
- <div class="d-none d-lg-block">
75
- <a class="lh-1 text-decoration-none" href="{config.relative_path}/user/{./user.userslug}">{buildAvatar(./user, "40px", true, "not-responsive")}</a>
76
- </div>
77
- <div class="post-body d-flex flex-column gap-2 flex-grow-1 hover-parent" style="min-width: 0px;">
50
+ <div class="p-3 feed-content-section">
51
+ <div class="post-body d-flex flex-column gap-2 flex-grow-1" style="min-width: 0px;">
52
+ <!-- Topic title (first) -->
78
53
  {{{ if ./isMainPost }}}
79
54
  <a class="lh-1 topic-title fw-semibold fs-5 text-reset text-break d-block" href="{config.relative_path}/topic/{./topic.slug}">
80
55
  {./topic.title}
81
56
  </a>
82
57
  {{{ end }}}
83
58
 
84
- <div class="d-flex gap-1 post-info text-sm align-items-center">
85
- <div class="post-author d-flex align-items-center gap-1">
86
- <a class="d-inline d-lg-none lh-1 text-decoration-none" href="{config.relative_path}/user/{./user.userslug}">{buildAvatar(./user, "16px", true, "not-responsive")}</a>
87
- <a class="lh-normal fw-semibold text-nowrap" href="{config.relative_path}/user/{./user.userslug}">{./user.displayname}</a>
88
- </div>
59
+ <!-- Author info row (second) -->
60
+ <div class="d-flex gap-2 post-info text-sm align-items-center">
61
+ <a class="lh-1 text-decoration-none" href="{config.relative_path}/user/{./user.userslug}">{buildAvatar(./user, "24px", true, "not-responsive")}</a>
62
+ <a class="lh-normal fw-semibold text-nowrap" href="{config.relative_path}/user/{./user.userslug}">{./user.displayname}</a>
89
63
  {{{ if !./isMainPost}}}{./repliedString}{{{ else }}}<span class="timeago text-muted lh-normal" title="{./timestampISO}"></span>{{{ end}}}
90
64
  </div>
91
65
 
66
+ <!-- Post content text (third) -->
92
67
  <div component="post/content" class="content text-sm text-break position-relative truncate-post-content">
93
68
  <a href="{config.relative_path}/post/{./pid}" class="stretched-link"></a>
94
69
  {./content}
@@ -101,7 +76,7 @@
101
76
 
102
77
  <!-- 2. IMAGE (second) -->
103
78
  {{{ if (showThumbs && ./topic.thumbs.length)}}}
104
- <div class="p-1 position-relative">
79
+ <div class="p-1 position-relative feed-image-section">
105
80
  <div class="overflow-hidden rounded-1" style="max-height: 300px;">
106
81
  <a href="{config.relative_path}/topic/{./topic.slug}">
107
82
  <img class="w-100" src="{./topic.thumbs.0.url}">
@@ -0,0 +1,102 @@
1
+ {{{ if (!./index && widgets.mainpost-header.length) }}}
2
+ <div data-widget-area="mainpost-header">
3
+ {{{ each widgets.mainpost-header }}}
4
+ {widgets.mainpost-header.html}
5
+ {{{ end }}}
6
+ </div>
7
+ {{{ end }}}
8
+ {{{ if (./parent && !hideParent) }}}
9
+ <!-- IMPORT partials/topic/post-parent.tpl -->
10
+ {{{ end }}}
11
+ <div class="d-flex flex-column gap-2 post-container-parent">
12
+ <!-- Author row: Avatar + Username + Timestamp -->
13
+ <div class="d-flex align-items-center gap-2 post-author-row">
14
+ <a class="d-inline-block position-relative text-decoration-none flex-shrink-0" href="{{{ if ./user.userslug }}}{config.relative_path}/user/{./user.userslug}{{{ else }}}#{{{ end }}}" aria-label="[[aria:profile-page-for, {./user.displayname}]]">
15
+ {buildAvatar(posts.user, "32px", true, "", "user/picture")}
16
+ </a>
17
+ <div class="d-flex flex-wrap align-items-center gap-1" itemprop="author" itemscope itemtype="https://schema.org/Person">
18
+ <meta itemprop="name" content="{./user.displayname}">
19
+ {{{ if ./user.userslug }}}<meta itemprop="url" content="{config.relative_path}/user/{./user.userslug}">{{{ end }}}
20
+ <a class="fw-semibold text-nowrap post-author-name" 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>
21
+ <span class="text-muted post-timestamp">{generateWrote(@value, config.timeagoCutoff)}</span>
22
+ <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>
23
+ <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>
24
+ </div>
25
+ <div class="d-flex align-items-center gap-1 ms-auto">
26
+ <span class="bookmarked opacity-0 text-primary"><i class="fa fa-bookmark-o"></i></span>
27
+ <a href="{config.relative_path}/post/{encodeURIComponent(./pid)}" class="post-index text-muted d-none d-md-inline">#{increment(./index, "1")}</a>
28
+ </div>
29
+ </div>
30
+
31
+ <!-- Post content - full width below author row -->
32
+ <div class="post-container d-flex flex-column w-100" style="min-width:0;">
33
+ <div class="content text-break" component="post/content" itemprop="text">
34
+ {posts.content}
35
+ </div>
36
+
37
+ <div component="post/footer" class="post-footer border-bottom pb-2">
38
+ {{{ if posts.user.signature }}}
39
+ <div component="post/signature" data-uid="{posts.user.uid}" class="text-xs text-muted mt-2">{posts.user.signature}</div>
40
+ {{{ end }}}
41
+
42
+ <div class="d-flex flex-wrap-reverse gap-2 {{{ if (hideReplies || !posts.replies.count) }}}justify-content-end{{{ else }}}justify-content-between{{{ end }}}">
43
+ {{{ if !hideReplies }}}
44
+ <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 }}}">
45
+ <span component="post/reply-count/avatars" class="d-flex gap-1 {{{ if posts.replies.hasMore }}}hasMore{{{ end }}}">
46
+ {{{each posts.replies.users}}}
47
+ <span>{buildAvatar(posts.replies.users, "20px", true, "avatar-tooltip")}</span>
48
+ {{{end}}}
49
+ {{{ if posts.replies.hasMore}}}
50
+ <span style="height: 20px; line-height: 20px;"><i class="fa fa-ellipsis"></i></span>
51
+ {{{ end }}}
52
+ </span>
53
+
54
+ <span class="ms-2 replies-count fw-semibold text-nowrap" component="post/reply-count/text" data-replies="{posts.replies.count}">{posts.replies.text}</span>
55
+ <span class="ms-2 replies-last hidden-xs fw-semibold">[[topic:last-reply-time]] <span class="timeago" title="{posts.replies.timestampISO}"></span></span>
56
+
57
+ <i class="fa fa-fw fa-chevron-down" component="post/replies/open"></i>
58
+ </a>
59
+ {{{ end }}}
60
+ <div component="post/actions" class="d-flex flex-grow-1 align-items-center justify-content-end gap-1 post-tools">
61
+ <!-- IMPORT partials/topic/reactions.tpl -->
62
+ <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>
63
+ <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>
64
+
65
+ {{{ if ./announces }}}
66
+ <a component="post/announce-count" href="#" class="btn btn-ghost btn-sm d-flex gap-2 align-items-center" title="[[topic:announcers]]"><i class="fa fa-share-alt text-primary"></i> {./announces}</a>
67
+ {{{ end }}}
68
+
69
+ {{{ if !reputation:disabled }}}
70
+ <div class="d-flex votes align-items-center">
71
+ <a component="post/upvote" href="#" class="btn btn-ghost btn-sm{{{ if posts.upvoted }}} upvoted{{{ end }}}" title="[[topic:upvote-post]]">
72
+ <i class="fa fa-fw fa-chevron-up text-primary"></i>
73
+ </a>
74
+
75
+ <meta itemprop="upvoteCount" content="{posts.upvotes}">
76
+ <meta itemprop="downvoteCount" content="{posts.downvotes}">
77
+ <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>
78
+
79
+ {{{ if !downvote:disabled }}}
80
+ <a component="post/downvote" href="#" class="btn btn-ghost btn-sm{{{ if posts.downvoted }}} downvoted{{{ end }}}" title="[[topic:downvote-post]]">
81
+ <i class="fa fa-fw fa-chevron-down text-primary"></i>
82
+ </a>
83
+ {{{ end }}}
84
+ </div>
85
+ {{{ end }}}
86
+
87
+ <!-- IMPORT partials/topic/post-menu.tpl -->
88
+ </div>
89
+ </div>
90
+
91
+ <div component="post/replies/container" class="my-2 col-11 border rounded-1 p-3 hidden-empty"></div>
92
+ </div>
93
+ </div>
94
+ </div>
95
+
96
+ {{{ if (!./index && widgets.mainpost-footer.length) }}}
97
+ <div data-widget-area="mainpost-footer">
98
+ {{{ each widgets.mainpost-footer }}}
99
+ {widgets.mainpost-footer.html}
100
+ {{{ end }}}
101
+ </div>
102
+ {{{ end }}}
package/theme.json CHANGED
@@ -4,5 +4,6 @@
4
4
  "description": "Modern, premium NodeBB theme for JAVIS Community",
5
5
  "url": "https://github.com/javis-admin/nodebb-community-theme",
6
6
  "screenshot": "screenshot.png",
7
- "baseTheme": "nodebb-theme-harmony"
7
+ "baseTheme": "nodebb-theme-harmony",
8
+ "templates": "templates"
8
9
  }