nodebb-theme-persona 15.0.0-beta.1 → 15.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-theme-persona",
3
- "version": "15.0.0-beta.1",
3
+ "version": "15.0.0-beta.2",
4
4
  "nbbpm": {
5
5
  "compatibility": "^4.14.0"
6
6
  },
package/scss/account.scss CHANGED
@@ -15,136 +15,6 @@
15
15
  margin-right: auto;
16
16
  }
17
17
 
18
- .cover {
19
- background-size: cover;
20
- background-repeat: no-repeat;
21
- height: 200px;
22
- position: relative;
23
- margin-bottom: 1em;
24
- background-origin: content-box;
25
- width: 100%;
26
- top: var(--panel-offset);
27
- position: absolute;
28
- left: auto;
29
- right: 0px;
30
-
31
- .avatar-wrapper {
32
- position: absolute;
33
- left: 50%;
34
- margin-left: -64px;
35
- top: 128px;
36
- border: 4px solid var(--bs-body-bg);
37
- background-color: var(--bs-body-bg);
38
- border-radius: 50%;
39
-
40
- .persona-fab.btn-morph {
41
- top: 93px;
42
- right: 4px;
43
- position: absolute;
44
- }
45
-
46
- .status {
47
- position: absolute;
48
- font-size: 23px;
49
- top: 17px;
50
- right: -3px;
51
- padding: 10px;
52
- }
53
-
54
- .chat, .follow {
55
- position: absolute;
56
- width: 30px;
57
- height: 30px;
58
- }
59
-
60
- .chat {
61
- left: -1px;
62
- bottom: 1px;
63
- }
64
-
65
- .follow {
66
- right: 1px;
67
- bottom: 1px;
68
- }
69
- }
70
-
71
- &:hover .controls, .controls:focus-within {
72
- opacity: 0.8;
73
- }
74
-
75
- .controls {
76
- text-align: center;
77
- height: 200px;
78
- line-height: 200px;
79
- opacity: 0;
80
- @include transition(opacity .15s linear);
81
- cursor: pointer;
82
- pointer-events: none;
83
-
84
- > * {
85
- pointer-events: all;
86
- }
87
-
88
- .fa {
89
- color: white;
90
- background-color: #333;
91
- opacity: 1;
92
- margin: 15px;
93
- padding: 5px;
94
- }
95
- }
96
-
97
- &.active {
98
- &:hover {
99
- cursor: move;
100
- }
101
-
102
- .controls {
103
- > * {
104
- display: none;
105
- }
106
- }
107
-
108
- .save {
109
- display: inline-block;
110
- }
111
- }
112
-
113
- &.saving {
114
- .save {
115
- display: none;
116
- }
117
-
118
- .indicator {
119
- display: inline-block;
120
- }
121
- }
122
-
123
- .save, .indicator {
124
- display: inline-block;
125
- position: absolute;
126
- top: 1em;
127
- right: 2em;
128
- opacity: 1;
129
- background-color: $primary;
130
- color: $gray-200;
131
- padding: 0.5em;
132
- font-weight: bold;
133
-
134
- &:hover {
135
- cursor: pointer;
136
- }
137
- }
138
-
139
- .save {
140
- display: none;
141
- }
142
-
143
- .indicator {
144
- display: none;
145
- }
146
- }
147
-
148
18
  margin-top: 200px;
149
19
 
150
20
  .container {
@@ -272,12 +142,3 @@
272
142
  }
273
143
  }
274
144
 
275
- .user-picture-label {
276
- font-size:20px;
277
- }
278
-
279
-
280
- .account-username{
281
- font-size:20px;
282
- font-weight:bold;
283
- }
package/scss/persona.scss CHANGED
@@ -9,7 +9,6 @@
9
9
  @import "header";
10
10
  @import "status";
11
11
  @import "account";
12
- @import "groups";
13
12
  @import "chats";
14
13
  @import "search";
15
14
  @import "topics_list";
@@ -2,7 +2,7 @@
2
2
 
3
3
  <div>
4
4
  <div class="d-flex justify-content-between align-items-center mb-3">
5
- <h1 class="fs-4">{title}</h1>
5
+ <h1 class="fs-4">{tx(title)}</h1>
6
6
  <div class="mb-2">
7
7
  <div class="dropdown bottom-sheet" component="category/watch/all">
8
8
  <button class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" type="button" aria-haspopup="true" aria-expanded="false">
@@ -51,6 +51,7 @@
51
51
  <p><strong>[[user:consent.right-to-data-portability]]</strong></p>
52
52
  <p>[[user:consent.right-to-data-portability-description]]</p>
53
53
 
54
+ {{{ if canExport }}}
54
55
  <div class="btn-group-vertical d-grid">
55
56
  <a data-action="export-profile" class="btn btn-outline-secondary">
56
57
  <i class="fa fa-download"></i> [[user:consent.export-profile]]
@@ -62,6 +63,7 @@
62
63
  <i class="fa fa-download"></i> [[user:consent.export-uploads]]
63
64
  </a>
64
65
  </div>
66
+ {{{ end }}}
65
67
  </div>
66
68
  </div>
67
69
  </div>
@@ -36,7 +36,7 @@
36
36
  {{{ end }}}
37
37
 
38
38
  <!-- IF aboutme -->
39
- <div component="aboutme" class="text-center aboutme text-secondary w-75 mx-auto text-center">{{aboutmeParsed}}</div>
39
+ <div component="aboutme" class="text-center aboutme text-secondary w-75 mx-auto text-center">{{txEscape(aboutmeParsed)}}</div>
40
40
  <!-- ENDIF aboutme -->
41
41
 
42
42
  <div class="account-stats fs-1 text-center mb-3">
@@ -156,28 +156,74 @@
156
156
  <!-- ENDIF ips.length -->
157
157
 
158
158
  <div class="row">
159
- {{{ if bestPosts.length }}}
160
- <div class="col-lg-12 col-12">
161
- <h1 class="fs-3">[[pages:account/best, {username}]]</h1>
162
-
163
- <div class="col-12">
164
- <ul component="posts" class="posts-list list-unstyled">
165
- {{{each bestPosts}}}
166
- <!-- IMPORT partials/posts_list_item.tpl -->
167
- {{{end}}}
168
- </ul>
169
- </div>
170
- </div>
171
- {{{ end }}}
172
- {{{ if latestPosts.length}}}
173
- <div class="col-lg-12 col-12">
174
- <h1 class="fs-3">[[pages:account/latest-posts, {username}]]</h1>
175
- <div class="col-12">
176
- <ul component="posts" class="posts-list list-unstyled">
177
- {{{each latestPosts}}}
178
- <!-- IMPORT partials/posts_list_item.tpl -->
179
- {{{end}}}
180
- </ul>
159
+ {{{ if (bestPosts.length || latestPosts.length) }}}
160
+ <div class="col-12">
161
+ <ul class="nav nav-tabs mb-3" role="tablist">
162
+ {{{ if bestPosts.length }}}
163
+ <li class="nav-item" role="presentation">
164
+ <button
165
+ class="nav-link active"
166
+ id="best-posts-tab"
167
+ data-bs-toggle="tab"
168
+ data-bs-target="#best-posts-pane"
169
+ type="button"
170
+ role="tab"
171
+ aria-controls="best-posts-pane"
172
+ aria-selected="true"
173
+ >
174
+ [[pages:account/best, {username}]]
175
+ </button>
176
+ </li>
177
+ {{{ end }}}
178
+ {{{ if latestPosts.length }}}
179
+ <li class="nav-item" role="presentation">
180
+ <button
181
+ class="nav-link {{{ if !bestPosts.length }}}active{{{ end }}}"
182
+ id="latest-posts-tab"
183
+ data-bs-toggle="tab"
184
+ data-bs-target="#latest-posts-pane"
185
+ type="button"
186
+ role="tab"
187
+ aria-controls="latest-posts-pane"
188
+ aria-selected="{{{ if !bestPosts.length }}}true{{{ else }}}false{{{ end }}}"
189
+ >
190
+ [[pages:account/latest-posts, {username}]]
191
+ </button>
192
+ </li>
193
+ {{{ end }}}
194
+ </ul>
195
+
196
+ <div class="tab-content">
197
+ {{{ if bestPosts.length }}}
198
+ <div
199
+ class="tab-pane fade show active"
200
+ id="best-posts-pane"
201
+ role="tabpanel"
202
+ aria-labelledby="best-posts-tab"
203
+ tabindex="0"
204
+ >
205
+ <ul component="posts" class="posts-list list-unstyled">
206
+ {{{each bestPosts}}}
207
+ <!-- IMPORT partials/posts_list_item.tpl -->
208
+ {{{end}}}
209
+ </ul>
210
+ </div>
211
+ {{{ end }}}
212
+ {{{ if latestPosts.length }}}
213
+ <div
214
+ class="tab-pane fade {{{ if !bestPosts.length }}}show active{{{ end }}}"
215
+ id="latest-posts-pane"
216
+ role="tabpanel"
217
+ aria-labelledby="latest-posts-tab"
218
+ tabindex="0"
219
+ >
220
+ <ul component="posts" class="posts-list list-unstyled">
221
+ {{{each latestPosts}}}
222
+ <!-- IMPORT partials/posts_list_item.tpl -->
223
+ {{{end}}}
224
+ </ul>
225
+ </div>
226
+ {{{ end }}}
181
227
  </div>
182
228
  </div>
183
229
  {{{ end }}}
@@ -8,7 +8,7 @@
8
8
  <div class="card card-body mb-3">
9
9
  <select class="form-select" id="bootswatchSkin" data-property="bootswatchSkin">
10
10
  {{{each bootswatchSkinOptions}}}
11
- <option value="{bootswatchSkinOptions.value}" <!-- IF bootswatchSkinOptions.selected -->selected<!-- ENDIF bootswatchSkinOptions.selected -->>{bootswatchSkinOptions.name}</option>
11
+ <option value="{bootswatchSkinOptions.value}" {{{ if bootswatchSkinOptions.selected }}}selected{{{ end }}}>{tx(bootswatchSkinOptions.name)}</option>
12
12
  {{{end}}}
13
13
  </select>
14
14
  </div>
@@ -165,7 +165,7 @@
165
165
  <label class="form-label" for="dailyDigestFreq">[[user:digest-label]]</label>
166
166
  <select class="form-select" id="dailyDigestFreq" data-property="dailyDigestFreq" autocomplete="off">
167
167
  {{{each dailyDigestFreqOptions}}}
168
- <option value="{dailyDigestFreqOptions.value}" <!-- IF dailyDigestFreqOptions.selected -->selected="1"<!-- ENDIF dailyDigestFreqOptions.selected -->>{dailyDigestFreqOptions.name}</option>
168
+ <option value="{./value}" {{{ if ./selected }}}selected="1"{{{ end }}}>{tx(./name)}</option>
169
169
  {{{end}}}
170
170
  </select>
171
171
  <p class="form-text">[[user:digest-description]]</p>
@@ -255,7 +255,7 @@
255
255
  <tr component="notification/setting" class="align-middle">
256
256
  <td style="width:100%;">
257
257
  <div class="align-items-center">
258
- <label class="text-sm tracking-tight" for="{./name}">{./label}</label>
258
+ <label class="text-sm tracking-tight" for="{./name}">{tx(./label)}</label>
259
259
  <input type="hidden" data-property="{./name}" value="{./value}">
260
260
  </div>
261
261
  </td>
@@ -1,6 +1,6 @@
1
1
  <!-- IMPORT partials/account/header.tpl -->
2
2
 
3
- <h1 class="fs-4">{title}</h1>
3
+ <h1 class="fs-4">{tx(title)}</h1>
4
4
  <input component="tags/watch" type="text" class="form-control">
5
5
 
6
6
  <!-- IMPORT partials/account/footer.tpl -->
@@ -1,5 +1,5 @@
1
1
  <!-- IMPORT partials/account/header.tpl -->
2
- <h1 class="fs-4">{title}</h1>
2
+ <h1 class="fs-4">{tx(title)}</h1>
3
3
  <!-- IF privateUploads -->
4
4
  <div class="alert alert-info text-center">[[uploads:private-uploads-info]]</div>
5
5
  <!-- ELSE -->
@@ -7,13 +7,13 @@
7
7
  {{{end}}}
8
8
  </div>
9
9
 
10
- <div class="cover" component="account/cover" style="background-image: url({cover:url}); background-position: {cover:position};">
11
- <div class="avatar-wrapper" data-uid="{uid}">
10
+ <div class="cover position-absolute start-0 top-0" component="account/cover" style="background-image: url({cover:url}); background-position: {cover:position};">
11
+ <div class="avatar-wrapper bg-body rounded-circle position-absolute start-50 top-100 translate-middle" data-uid="{uid}" style="padding: 4px;">
12
12
  {{buildAvatar(@value, "128px", true)}}
13
- <span component="user/status" class="position-absolute border border-white border-2 rounded-circle status {status}"><span class="visually-hidden">[[global:{status}]]</span></span>
13
+ <span component="user/status" class="fs-3 position-absolute border border-white border-2 rounded-circle status {status}" style="top: 17px; right: 3px; padding: 10px;"><span class="visually-hidden">[[global:{status}]]</span></span>
14
14
 
15
15
  {{{ if !isSelf }}}
16
- <button class="btn-morph persona-fab {{{ if isFollowing }}}heart{{{ else }}}plus{{{ end }}}" title="{{{ if isFollowing }}}[[global:unfollow]]{{{ else }}}[[global:follow]]{{{ end }}}">
16
+ <button style="top: 93px; right:4px;" class="btn-morph persona-fab position-absolute {{{ if isFollowing }}}heart{{{ else }}}plus{{{ end }}}" title="{{{ if isFollowing }}}[[global:unfollow]]{{{ else }}}[[global:follow]]{{{ end }}}">
17
17
  <span>
18
18
  <span class="s1"></span>
19
19
  <span class="s2"></span>
@@ -25,13 +25,13 @@
25
25
 
26
26
  <div class="container">
27
27
  {{{ if (allowCoverPicture && canEdit) }}}
28
- <div class="controls">
29
- <a href="#" class="upload"><i class="fa fa-fw fa-4x fa-upload"></i></a>
30
- <a href="#" class="resize"><i class="fa fa-fw fa-4x fa-arrows"></i></a>
31
- <a href="#" class="remove"><i class="fa fa-fw fa-4x fa-times"></i></a>
28
+ <div class="controls text-center">
29
+ <span class="upload p-2 m-2 rounded-1 text-bg-light opacity-75"><i class="fa fa-fw fa-upload"></i></span>
30
+ <span class="resize p-2 m-2 rounded-1 text-bg-light opacity-75"><i class="fa fa-fw fa-arrows"></i></span>
31
+ <span class="remove p-2 m-2 rounded-1 text-bg-light opacity-75"><i class="fa fa-fw fa-times"></i></span>
32
32
  </div>
33
- <a href="#" class="save">[[groups:cover-save]] <i class="fa fa-fw fa-floppy-o"></i></a>
34
- <div class="indicator">[[groups:cover-saving]] <i class="fa fa-fw fa-refresh fa-spin"></i></div>
33
+ <a href="#" class="save btn btn-primary">[[groups:cover-save]] <i class="fa fa-fw fa-floppy-o"></i></a>
34
+ <div class="indicator text-bg-primary">[[groups:cover-saving]] <i class="fa fa-fw fa-refresh fa-spin"></i></div>
35
35
  {{{ end }}}
36
36
 
37
37
  <!-- IMPORT partials/account/menu.tpl -->
@@ -1,5 +1,5 @@
1
- {{{ if ./isSection }}}
2
- {./name}
3
- {{{ else }}}
4
- <a class="text-reset" href="{{{ if ./link }}}{./link}{{{ else }}}{config.relative_path}/category/{./slug}{{{ end }}}" itemprop="url">{./name}</a>
5
- {{{ end }}}
1
+ {{{ if ./isSection }}}
2
+ {tx(./name)}
3
+ {{{ else }}}
4
+ <a class="text-reset" href="{{{ if ./link }}}{./link}{{{ else }}}{config.relative_path}/category/{./slug}{{{ end }}}" itemprop="url">{tx(./name)}</a>
5
+ {{{ end }}}
@@ -1,4 +1,4 @@
1
1
  <div class="cookie-consent">
2
- <button class="float-end btn btn-primary">{dismiss}</button>
3
- {message} <a target="_blank" rel="noopener" href="{link_url}">{link}</a>
2
+ <button class="float-end btn btn-primary">{tx(dismiss)}</button>
3
+ {tx(message)} <a target="_blank" rel="noopener" href="{link_url}">{tx(link)}</a>
4
4
  </div>
@@ -47,14 +47,14 @@
47
47
  <ul id="main-nav" class="navbar-nav me-auto mb-2 mb-lg-0">
48
48
  {{{each navigation}}}
49
49
  {{{ if displayMenuItem(@root, @index) }}}
50
- <li class="nav-item {navigation.class}{{{ if navigation.dropdown }}} dropdown{{{ end }}}" title="{navigation.title}">
50
+ <li class="nav-item {navigation.class}{{{ if navigation.dropdown }}} dropdown{{{ end }}}" title="{tx(./title)}">
51
51
  <a class="nav-link navigation-link {{{ if navigation.dropdown }}}dropdown-toggle{{{ end }}}"
52
52
  {{{ if navigation.dropdown }}} href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" {{{ else }}} href="{navigation.route}"{{{ end }}} {{{ if navigation.id }}}id="{navigation.id}"{{{ end }}}{{{ if navigation.targetBlank }}} target="_blank"{{{ end }}}>
53
53
  {{{ if navigation.iconClass }}}
54
- <i class="fa fa-fw {navigation.iconClass}" data-content="{navigation.content}"></i>
54
+ <i class="fa fa-fw {navigation.iconClass}" data-content="{./content}"></i>
55
55
  {{{ end }}}
56
- {{{ if navigation.text }}}
57
- <span class="{navigation.textClass}">{navigation.text}</span>
56
+ {{{ if ./text }}}
57
+ <span class="{./textClass}">{tx(./text)}</span>
58
58
  {{{ end }}}
59
59
  {{{ if navigation.dropdown}}}
60
60
  <i class="fa fa-caret-down"></i>
@@ -25,7 +25,7 @@
25
25
 
26
26
  <div class="d-flex flex-grow-1 flex-column gap-1 align-items-start position-relative">
27
27
  <a href="{./path}" class="text-decoration-none d-inline-block text-reset text-break text-sm ff-sans stretched-link" component="notifications/item/link">
28
- {./bodyShort}
28
+ {{./bodyShort}}
29
29
  </a>
30
30
  {{{ if ./bodyLong}}}
31
31
  <div class="text-secondary text-sm line-clamp-2 text-contain hidden-blockquote hidden-pre hidden-first-child-br">
@@ -1,6 +1,6 @@
1
1
  <div id="results" class="search-results col-md-12" data-search-query="{search_query}">
2
2
  {{{ if matchCount }}}
3
- <div class="alert alert-info">[[search:results-matching, {matchCount}, {txEscape(search_query)}, {time}]] </div>
3
+ <div class="alert alert-info">{{tx("search:results-matching", matchCount, txEscape(search_query), time)}}</div>
4
4
  {{{ else }}}
5
5
  {{{ if search_query }}}
6
6
  <div class="alert alert-warning">[[search:no-matches]]</div>
@@ -25,7 +25,7 @@
25
25
  <a href="{config.relative_path}/category/{./category.slug}">
26
26
  <div class="category-item d-inline-block">
27
27
  {{buildCategoryIcon(./category, "24px", "rounded-circle")}}
28
- {./category.name}
28
+ {tx(./category.name)}
29
29
  </div>
30
30
  </a> &bull;
31
31
  <span class="timeago" title="{./timestampISO}"></span>
@@ -1,5 +1,8 @@
1
1
  {{{each tags}}}
2
2
  <h5 class="float-start tag-container me-5 mb-5 fw-bold">
3
- <a href="{config.relative_path}/tags/{tags.valueEncoded}" data-tag="{tags.valueEscaped}"><span class="tag-item text-muted text-uppercase text-nowrap tag-class-{tags.class} me-2" data-tag="{tags.valueEscaped}">{tags.valueEscaped}</span><span class="tag-topic-count text-primary text-nowrap" title="{tags.score}">{formattedNumber(tags.score)}</span></a>
3
+ <a href="{config.relative_path}/tags/{./valueEncoded}" data-tag="{./value}">
4
+ <span class="tag-item text-muted text-uppercase text-nowrap tag-class-{tags.class} me-2" data-tag="{tags.value}">{./value}</span>
5
+ <span class="tag-topic-count text-primary text-nowrap" title="{./score}">{tx("global:x-topics", formattedNumber(./score))}</span>
6
+ </a>
4
7
  </h5>
5
8
  {{{end}}}
@@ -77,7 +77,7 @@
77
77
 
78
78
  <div class="post-footer">
79
79
  {{{ if posts.user.signature }}}
80
- <div component="post/signature" data-uid="{posts.user.uid}" class="post-signature">{{posts.user.signature}}</div>
80
+ <div component="post/signature" data-uid="{posts.user.uid}" class="post-signature">{{txEscape(posts.user.signature)}}</div>
81
81
  {{{ end }}}
82
82
 
83
83
  <div class="clearfix">
package/scss/groups.scss DELETED
@@ -1,111 +0,0 @@
1
- .groups.details {
2
- margin-top: 200px;
3
-
4
- [component="groups/cover"] {
5
- background-size: cover;
6
- background-repeat: no-repeat;
7
- background-origin: content-box;
8
-
9
- min-height: 200px;
10
- width: 100%;
11
- margin-bottom: 1em;
12
- padding-left: 0;
13
- padding-right: 0;
14
-
15
- position: absolute;
16
- top: var(--panel-offset);
17
- right: 0;
18
- left: auto;
19
-
20
- &:hover {
21
- .controls {
22
- opacity: 0.8;
23
- }
24
- }
25
-
26
- .controls {
27
- text-align: center;
28
- min-height: 200px;
29
- line-height: 200px;
30
- opacity: 0;
31
- @include transition(opacity .15s linear);
32
- cursor: pointer;
33
- pointer-events: none;
34
-
35
- > * {
36
- pointer-events: all;
37
- }
38
-
39
- .fa {
40
- color: white;
41
- background-color: #333;
42
- opacity: 1;
43
- margin: 15px;
44
- padding: 5px;
45
- }
46
- }
47
-
48
- &.active {
49
- &:hover {
50
- cursor: move;
51
- }
52
-
53
- .controls {
54
- > * {
55
- display: none;
56
- }
57
- }
58
-
59
- .save {
60
- display: inline-block;
61
- }
62
- }
63
-
64
- &.saving {
65
- .save {
66
- display: none;
67
- }
68
-
69
- .indicator {
70
- display: inline-block;
71
- }
72
- }
73
-
74
- .save, .indicator {
75
- display: inline-block;
76
- position: absolute;
77
- top: 1em;
78
- right: 2em;
79
- opacity: 1;
80
- background-color: $primary;
81
- color: $gray-200;
82
- padding: 0.5em;
83
- font-weight: bold;
84
-
85
- &:hover {
86
- cursor: pointer;
87
- }
88
- }
89
-
90
- .save {
91
- display: none;
92
- }
93
-
94
- .indicator {
95
- display: none;
96
- }
97
- }
98
-
99
- @include media-breakpoint-up(md) {
100
- margin-top: 300px;
101
-
102
- [component="groups/cover"] {
103
- min-height: 300px;
104
-
105
- .controls {
106
- min-height: 300px;
107
- line-height: 300px;
108
- }
109
- }
110
- }
111
- }
@@ -1,114 +0,0 @@
1
- <div component="groups/container" class="groups details">
2
-
3
- <div component="groups/cover" style="background-image: url({group.cover:url}?{config.cache-buster}); background-position: {group.cover:position};">
4
- {{{ if group.isOwner }}}
5
- <div class="controls">
6
- <span class="upload"><i class="fa fa-fw fa-4x fa-upload"></i></span>
7
- <span class="resize"><i class="fa fa-fw fa-4x fa-arrows"></i></span>
8
- <span class="remove"><i class="fa fa-fw fa-4x fa-times"></i></span>
9
- </div>
10
- <div class="save">[[groups:cover-save]] <i class="fa fa-fw fa-floppy-o"></i></div>
11
- <div class="indicator">[[groups:cover-saving]] <i class="fa fa-fw fa-refresh fa-spin"></i></div>
12
- {{{ end }}}
13
- </div>
14
-
15
- <div>
16
- <!-- IMPORT partials/breadcrumbs.tpl -->
17
- </div>
18
-
19
- <div class="d-flex flex-column flex-md-row justify-content-md-between pb-2 mb-4 mt-2 border-bottom gap-3">
20
- <div class="d-flex flex-column gap-2">
21
- <div class="d-flex flex-column flex-md-row align-items-md-center gap-2">
22
- <h3 class="mb-0 text-capitalize">{generateGroupDisplayName(group)}</h3>
23
- <div>
24
- {{{ if group.private }}}<span class="badge text-bg-light border border-1">[[groups:details.private]]</span>{{{ end }}}
25
- {{{ if group.hidden }}}<span class="badge text-bg-light border border-1">[[groups:details.hidden]]</span>{{{ end }}}
26
- </div>
27
- </div>
28
- <div>
29
- {{group.descriptionParsed}}
30
- </div>
31
- </div>
32
- <div class="d-flex gap-2 align-items-start">
33
- {{{ if loggedIn }}}
34
- {{membershipBtn(group)}}
35
- {{{ end }}}
36
- {{{ if isAdmin }}}
37
- <a href="{config.relative_path}/admin/manage/groups/{group.slug}" target="_blank" class="btn btn-light text-nowrap"><i class="fa fa-gear"></i> [[user:edit]]</a>
38
- {{{ end }}}
39
- </div>
40
- </div>
41
-
42
- <div class="text-sm mb-3 nav d-flex flex-row flex-wrap gap-1 justify-content-end">
43
- <button data-bs-toggle="tab" data-bs-target="#groups-posts" class="btn btn-ghost btn-sm text-start d-flex align-items-center ff-secondary fw-semibold {{{ if template.groups/details }}}active{{{ end }}}">
44
- <div class="flex-grow-1">[[global:posts]]</div>
45
- </button>
46
- <button data-bs-toggle="tab" data-bs-target="#groups-members" class="btn btn-ghost btn-sm text-start d-flex align-items-center ff-secondary fw-semibold gap-2">
47
- <div class="flex-grow-1">[[groups:members]]</div>
48
- <span component="group/member/count" class="flex-shrink-0 text-xs" title="{group.memberCount}">{humanReadableNumber(group.memberCount)}</span>
49
- </button>
50
-
51
- {{{ if group.isOwner }}}
52
- <button data-bs-toggle="tab" data-bs-target="#groups-pending" class="btn btn-ghost btn-sm text-start d-flex align-items-center ff-secondary fw-semibold gap-2">
53
- <div class="flex-grow-1">[[groups:details.pending]]</div>
54
- <span component="group/pending/count" class="flex-shrink-0 text-xs" title="{group.pending.length}">{humanReadableNumber(group.pending.length)}</span>
55
- </button>
56
-
57
- <button data-bs-toggle="tab" data-bs-target="#groups-invited" class="btn btn-ghost btn-sm text-start d-flex align-items-center ff-secondary fw-semibold gap-2">
58
- <div class="flex-grow-1">[[groups:details.invited]]</div>
59
- <span component="group/invited/count" class="flex-shrink-0 text-xs" title="{group.invited.length}">{humanReadableNumber(group.invited.length)}</span>
60
- </button>
61
-
62
- <button data-bs-toggle="tab" data-bs-target="#groups-admin" class="btn btn-ghost btn-sm text-start d-flex align-items-center ff-secondary fw-semibold">
63
- <div class="flex-grow-1">[[global:header.admin]]</div>
64
- </button>
65
- {{{ end }}}
66
- </div>
67
-
68
- <div class="d-flex flex-column flex-md-row">
69
- <div data-widget-area="left">
70
- {{{each widgets.left}}}
71
- {{widgets.left.html}}
72
- {{{end}}}
73
- </div>
74
-
75
- <div class="flex-grow-1" style="min-width:0;">
76
- <div class="tab-content">
77
- <div class="tab-pane fade show active" id="groups-posts" role="tabpanel">
78
- <h3 class="fw-semibold fs-5">[[global:posts]]</h3>
79
- {{{ if !posts.length }}}
80
- <div class="alert alert-info my-2">[[groups:details.has-no-posts]]</div>
81
- {{{ end }}}
82
- <!-- IMPORT partials/posts_list.tpl -->
83
- </div>
84
- <div class="tab-pane fade" id="groups-members" role="tabpanel">
85
- <h3 class="fw-semibold fs-5 mb-3">[[groups:details.members]]</h3>
86
-
87
- <!-- IMPORT partials/groups/memberlist.tpl -->
88
- </div>
89
- {{{ if group.isOwner }}}
90
- <div class="tab-pane fade" id="groups-pending" role="tabpanel">
91
- <h3 class="fw-semibold fs-5 mb-3">[[groups:details.pending]]</h3>
92
- <!-- IMPORT partials/groups/pending.tpl -->
93
- </div>
94
-
95
- <div class="tab-pane fade" id="groups-invited" role="tabpanel">
96
- <h3 class="fw-semibold fs-5 mb-3">[[groups:details.invited]]</h3>
97
- <!-- IMPORT partials/groups/invited.tpl -->
98
- </div>
99
-
100
- <div class="tab-pane fade" id="groups-admin" role="tabpanel">
101
- <h3 class="fw-semibold fs-5 mb-3">[[groups:details.owner-options]]</h3>
102
- <!-- IMPORT partials/groups/admin.tpl -->
103
- </div>
104
- {{{ end }}}
105
- </div>
106
- </div>
107
-
108
- <div data-widget-area="right">
109
- {{{each widgets.right}}}
110
- {{widgets.right.html}}
111
- {{{end}}}
112
- </div>
113
- </div>
114
- </div>
@@ -1,46 +0,0 @@
1
- <!-- IMPORT partials/breadcrumbs.tpl -->
2
- <div data-widget-area="header">
3
- {{{each widgets.header}}}
4
- {{widgets.header.html}}
5
- {{{end}}}
6
- </div>
7
- <div class="groups list">
8
- <div class="d-flex justify-content-between align-items-center gap-3 flex-wrap">
9
- <div>
10
- {{{ if allowGroupCreation }}}
11
- <button class="btn btn-sm btn-primary" data-action="new"><i class="fa fa-plus"></i> [[groups:new-group]]</button>
12
- {{{ end }}}
13
- </div>
14
-
15
- <div class="d-flex gap-3 align-items-center">
16
- <select class="form-select form-select-sm" id="search-sort">
17
- <option value="alpha">[[groups:details.group-name]]</option>
18
- <option value="count">[[groups:details.member-count]]</option>
19
- <option value="date">[[groups:details.creation-date]]</option>
20
- </select>
21
-
22
- <div class="input-group">
23
- <input type="text" class="form-control form-control-sm" placeholder="[[global:search]]" name="query" value="" id="search-text">
24
- <button id="search-button" class="btn btn-sm btn-primary">
25
- <i class="fa fa-search"></i>
26
- </button>
27
- </div>
28
- </div>
29
- </div>
30
-
31
- <hr />
32
-
33
- <div component="groups/container" class="row" id="groups-list">
34
- {{{ if groups.length }}}
35
- <!-- IMPORT partials/groups/list.tpl -->
36
- {{{ else }}}
37
- <div class="col-12">
38
- <div class="alert alert-warning">
39
- [[groups:no-groups-found]]
40
- </div>
41
- </div>
42
- {{{ end }}}
43
- </div>
44
-
45
- <!-- IMPORT partials/paginator.tpl -->
46
- </div>
@@ -1,6 +0,0 @@
1
- <!-- IMPORT partials/breadcrumbs.tpl -->
2
- <div class="users">
3
- <!-- IMPORT partials/users_list.tpl -->
4
-
5
- <!-- IMPORT partials/paginator.tpl -->
6
- </div>
@@ -1,96 +0,0 @@
1
- <form component="groups/settings" role="form">
2
- <div class="mb-3">
3
- <label class="form-label" for="name">[[groups:details.group-name]]</label>
4
- <input <!-- IF group.system -->readonly<!-- ENDIF group.system --> class="form-control" name="name" id="name" type="text" value="{group.displayName}" />
5
- </div>
6
- <div class="mb-3">
7
- <label class="form-label" for="description">[[groups:details.description]]</label>
8
- <textarea class="form-control" name="description" id="description" type="text" maxlength="255">{group.description}</textarea>
9
- </div>
10
-
11
- <hr />
12
- <div class="mb-3">
13
- <label class="form-label" for="memberPostCids">[[groups:details.member-post-cids]]</label>
14
- <div class="row">
15
- <div class="col-md-6">
16
- <input id="memberPostCids" type="text" class="form-control" value="{group.memberPostCids}">
17
- </div>
18
- <div class="col-md-6 member-post-cids-selector">
19
- <!-- IMPORT partials/category/selector-dropdown-left.tpl -->
20
- </div>
21
- </div>
22
- </div>
23
-
24
- <hr />
25
-
26
- <div class="mb-3 user-title-option">
27
- <label class="form-label" for="userTitle">[[groups:details.badge-text]]</label>
28
- <div class="d-flex gap-2">
29
- <input component="groups/userTitleOption" class="form-control" name="userTitle" id="userTitle" type="text" maxlength="40" value="{group.userTitle}"<!-- IF !group.userTitleEnabled --> disabled<!-- ENDIF !group.userTitleEnabled --> />
30
- <button component="groups/userTitleOption" type="button" class="btn btn-outline-secondary btn-sm text-nowrap" data-action="icon-select"<!-- IF !group.userTitleEnabled --> disabled<!-- ENDIF !group.userTitleEnabled -->>[[groups:details.change-icon]]</button>
31
- </div>
32
- </div>
33
-
34
- <div class="mb-3 user-title-option">
35
- <div class="d-flex align-items-center gap-3">
36
- <label class="form-label mb-0">[[groups:details.badge-preview]]</label>
37
- <span class="badge rounded-1 text-uppercase text-truncate rounded-1 d-flex align-items-center gap-1 {{{ if !group.userTitleEnabled }}} hide{{{ end }}}" style="max-width:150px; color: {group.textColor}; background-color: {group.labelColor}"><i class="fa {{{ if (group.icon && (group.icon != "fa-nbb-none")) }}}{group.icon}{{{ else }}}hidden{{{ end }}}"></i><span class="badge-text">{{{ if group.userTitle }}}{group.userTitle}{{{ end }}}</span></span>
38
- </div>
39
- <hr/>
40
- <div class="d-flex flex-column gap-2">
41
- <div class="d-flex align-items-center gap-2">
42
- <label class="form-label mb-0" for="labelColor" class="badge-color-label">[[groups:details.change-label-colour]]</label>
43
- <input component="groups/userTitleOption" type="color" name="labelColor" id="labelColor" value="<!-- IF group.labelColor -->{group.labelColor}<!-- ENDIF group.labelColor -->" />
44
- </div>
45
- <div class="d-flex align-items-center gap-2">
46
- <label class="form-label mb-0" for="textColor" class="badge-color-label">[[groups:details.change-text-colour]]</label>
47
- <input component="groups/userTitleOption" type="color" name="textColor" id="textColor" value="<!-- IF group.textColor -->{group.textColor}<!-- ENDIF group.textColor -->" />
48
- </div>
49
- <input type="hidden" name="icon" value="<!-- IF group.icon -->{group.icon}<!-- ENDIF group.icon -->" />
50
- </div>
51
- <div id="icons" class="hidden">
52
- <div class="icon-container">
53
- <div class="row nbb-fa-icons">
54
- <!-- IMPORT partials/fontawesome.tpl -->
55
- </div>
56
- </div>
57
- </div>
58
- </div>
59
- <hr />
60
- <div class="form-check">
61
- <label class="form-check-label" for="userTitleEnabled">[[groups:details.userTitleEnabled]]</label>
62
- <input class="form-check-input" name="userTitleEnabled" id="userTitleEnabled" type="checkbox"<!-- IF group.userTitleEnabled --> checked<!-- ENDIF group.userTitleEnabled -->>
63
- </div>
64
- <div class="form-check">
65
- <label class="form-check-label" for="private">[[groups:details.private]]</label>
66
- <input class="form-check-input" name="private" id="private" type="checkbox"<!-- IF group.private --> checked<!-- ENDIF group.private -->>
67
- <!-- IF !allowPrivateGroups -->
68
- <p class="form-text">
69
- [[groups:details.private-system-help]]
70
- </p>
71
- <!-- ENDIF !allowPrivateGroups -->
72
- <p class="form-text">
73
- [[groups:details.private-help]]
74
- </p>
75
- </div>
76
- <div class="form-check">
77
- <label class="form-check-label" for="disableJoinRequests">[[groups:details.disableJoinRequests]]</label>
78
- <input class="form-check-input" name="disableJoinRequests" id="disableJoinRequests" type="checkbox"<!-- IF group.disableJoinRequests --> checked<!-- ENDIF group.disableJoinRequests -->>
79
- </div>
80
- <div class="form-check">
81
- <label class="form-check-label" for="disableLeave">[[groups:details.disableLeave]]</label>
82
- <input class="form-check-input" name="disableLeave" id="disableLeave" type="checkbox"{{{if group.disableLeave}}} checked{{{end}}}>
83
- </div>
84
- <div class="form-check">
85
- <label class="form-check-label" for="hidden">[[groups:details.hidden]]</label>
86
- <input class="form-check-input" name="hidden" id="hidden" type="checkbox"<!-- IF group.hidden --> checked<!-- ENDIF group.hidden -->>
87
- <p class="form-text">
88
- [[groups:details.hidden-help]]
89
- </p>
90
- </div>
91
-
92
- <div class="d-flex justify-content-end gap-2">
93
- <button class="btn btn-link text-danger" type="button" data-action="delete">[[groups:details.delete-group]]</button>
94
- <button class="btn btn-primary" type="button" data-action="update">[[global:save-changes]]</button>
95
- </div>
96
- </form>
@@ -1 +0,0 @@
1
- <a href="{config.relative_path}/groups/{./slug}" class="badge rounded-1 text-uppercase text-truncate text-decoration-none d-flex align-items-center gap-1" style="line-height: normal; 150px;color:{./textColor};background-color: {./labelColor};"><i class="fa {{{ if (./icon && (./icon != "fa-nbb-none")) }}}{./icon}{{{else}}}hidden{{{ end }}}"></i><span class="badge-text">{{{ if ./userTitle }}}{./userTitle}{{{ end }}}</span></a>
@@ -1,33 +0,0 @@
1
- <label class="text-xs text-muted">[[groups:invited.search]]</label>
2
- <div class="input-group mb-2">
3
- <input class="form-control" type="text" component="groups/members/invite"/>
4
- <span class="input-group-text search-button"><i class="fa fa-search"></i></span>
5
- </div>
6
-
7
- <div class="mb-2">
8
- <label class="text-xs text-muted">[[groups:bulk-invite-instructions]]</label>
9
- <textarea class="form-control" component="groups/members/bulk-invite"></textarea>
10
- </div>
11
-
12
- <div class="mb-2 clearfix">
13
- <button type="button" class="btn btn-primary btn-sm float-end" component="groups/members/bulk-invite-button">[[groups:bulk-invite]]</button>
14
- </div>
15
-
16
- <div style="max-height: 500px; overflow: auto;">
17
- <div component="groups/invited/alert" class="alert alert-info {{{ if group.invited.length }}}hidden{{{ end }}}">[[groups:invited.none]]</div>
18
- <table component="groups/invited" class="table table-hover">
19
- <tbody>
20
- {{{ each group.invited }}}
21
- <tr data-uid="{group.invited.uid}" class="align-middle">
22
- <td class="member-name p-2 d-flex align-items-center justify-content-between">
23
- <div class="d-flex align-items-center gap-2">
24
- <a class="text-decoration-none" href="{config.relative_path}/user/{group.invited.userslug}">{{buildAvatar(group.invited, "24px", true)}}</a>
25
- <a href="{config.relative_path}/user/{group.invited.userslug}">{group.invited.username}</a>
26
- </div>
27
- <button class="btn btn-outline-secondary btn-sm text-nowrap" data-action="rescindInvite">[[groups:invited.uninvite]]</button>
28
- </td>
29
- </tr>
30
- {{{ end }}}
31
- </tbody>
32
- </table>
33
- </div>
@@ -1,21 +0,0 @@
1
- {{{each groups}}}
2
- <div class="col-lg-4 col-md-6 col-sm-12 mb-3" component="groups/summary" data-slug="{groups.slug}">
3
- <div class="card h-100">
4
- <a href="{config.relative_path}/groups/{groups.slug}" class="card-header list-cover" style="{{{ if groups.cover:thumb:url }}}background-image: url({./cover:thumb:url});background-size: cover; min-height: 125px; background-position: {./cover:position}{{{ end }}}">
5
- <h5 class="card-title d-inline-block mw-100 px-2 py-1 text-truncate text-capitalize fw-bold rounded-1" style="color: white;background-color: rgba(0,0,0,0.5);">{generateGroupDisplayName(@value)} <small>{formattedNumber(groups.memberCount)}</small></h5>
6
- </a>
7
- <div class="card-body">
8
- <p class="text-muted">
9
- {./description}
10
- </p>
11
- <ul class="members list-unstyled d-flex align-items-center gap-2 flex-wrap">
12
- {{{each groups.members}}}
13
- <li>
14
- <a href="{config.relative_path}/user/{groups.members.userslug}">{{buildAvatar(groups.members, "24px", true)}}</a>
15
- </li>
16
- {{{end}}}
17
- </ul>
18
- </div>
19
- </div>
20
- </div>
21
- {{{end}}}
@@ -1,45 +0,0 @@
1
- <div class="d-flex mb-3">
2
- <!-- IF group.isOwner -->
3
- <div class="flex-shrink-0">
4
- <button component="groups/members/add" type="button" class="btn btn-primary me-3" title="[[groups:details.add-member]]"><i class="fa fa-user-plus"></i></button>
5
- </div>
6
- <!-- ENDIF group.isOwner -->
7
- <div class="flex-grow-1">
8
- <div class="input-group">
9
- <input class="form-control" type="text" component="groups/members/search" placeholder="[[global:search]]"/>
10
- <span class="input-group-text search-button"><i class="fa fa-search"></i></span>
11
- </div>
12
- </div>
13
- </div>
14
-
15
- <div component="groups/members" data-nextstart="{group.membersNextStart}" style="max-height: 500px; overflow: auto;">
16
- <table class="table table-hover">
17
- <tbody>
18
- {{{each group.members}}}
19
- <tr class="w-100" data-uid="{group.members.uid}" data-isowner="{{{ if group.members.isOwner }}}1{{{ else }}}0{{{ end }}}">
20
- <td class="member-name p-2 w-100 ">
21
- <div class="d-flex align-items-center justify-content-between">
22
- <div class="d-flex align-items-center gap-2">
23
- <a class="text-decoration-none" href="{config.relative_path}/user/{group.members.userslug}">{{buildAvatar(group.members, "24px", true)}}</a>
24
- <a class="align-text-top" href="{config.relative_path}/user/{group.members.userslug}">{group.members.username}</a>
25
- <i component="groups/owner/icon" title="[[groups:owner]]" class="user-owner-icon fa fa-star align-text-top text-warning {{{ if !group.members.isOwner }}}invisible{{{ end }}}"></i>
26
- </div>
27
-
28
- {{{ if group.isOwner }}}
29
- <div class="owner-controls d-flex gap-1">
30
- <a class="btn btn-light btn-sm" href="#" data-action="toggleOwnership" title="[[groups:details.grant]]">
31
- <i class="fa fa-star text-warning"></i>
32
- </a>
33
-
34
- <a class="btn btn-light btn-sm" href="#" data-action="kick" title="[[groups:details.kick]]">
35
- <i class="fa fa-ban text-danger"></i>
36
- </a>
37
- </div>
38
- {{{ end }}}
39
- </div>
40
- </td>
41
- </tr>
42
- {{{end}}}
43
- </tbody>
44
- </table>
45
- </div>
@@ -1,28 +0,0 @@
1
- {{{ if group.pending.length }}}
2
- <div class="d-flex justify-content-end gap-2 mb-3">
3
- <button class="btn btn-danger btn-sm" data-action="rejectAll">[[groups:pending.reject-all]]</button>
4
- <button class="btn btn-success btn-sm" data-action="acceptAll">[[groups:pending.accept-all]]</button>
5
- </div>
6
- {{{ end }}}
7
-
8
- <div style="max-height: 500px;overflow: auto;">
9
- <div component="groups/pending/alert" class="alert alert-info {{{ if group.pending.length }}}hidden{{{ end }}}">[[groups:pending.none]]</div>
10
- <table component="groups/pending" class="table table-hover">
11
- <tbody>
12
- {{{ each group.pending }}}
13
- <tr data-uid="{group.pending.uid}" class="align-middle">
14
- <td class="member-name p-2 d-flex align-items-center justify-content-between">
15
- <div class="d-flex gap-2">
16
- <a class="text-decoration-none" href="{config.relative_path}/user/{group.pending.userslug}">{{buildAvatar(group.pending, "24px", true)}}</a>
17
- <a href="{config.relative_path}/user/{group.pending.userslug}">{group.pending.username}</a>
18
- </div>
19
- <div class="d-flex gap-2">
20
- <button class="btn btn-danger btn-sm" data-action="reject">[[groups:pending.reject]]</a></li>
21
- <button class="btn btn-success btn-sm" data-action="accept">[[groups:pending.accept]]</a></li>
22
- </div>
23
- </td>
24
- </tr>
25
- {{{ end }}}
26
- </tbody>
27
- </table>
28
- </div>
@@ -1,19 +0,0 @@
1
- <div id="{alert_id}" role="alert" class="alert alert-dismissible alert-{type} fade show" component="toaster/toast">
2
- <div class="alert-progress position-absolute top-0 start-0 bottom-0 h-100 z-0" style=" opacity:0.1;"></div>
3
- <div class="d-flex flex-wrap gap-2 position-relative">
4
- {{{ if image }}}
5
- <img src="{image}" height="80" style="width: auto;" />
6
- {{{ end }}}
7
- <div class="d-flex flex-column gap-2">
8
- {{{ if title }}}
9
- <strong>{title}</strong>
10
- {{{ end }}}
11
-
12
- {{{ if message }}}
13
- <p class="m-0">{message}</p>
14
- {{{ end }}}
15
- </div>
16
- </div>
17
-
18
- <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
19
- </div>