mirror of
https://hk.gh-proxy.com/https://github.com/NodeBB/nodebb-theme-harmony.git
synced 2025-10-03 05:01:05 +08:00
feat: init 🎉
Harmony starts here Blank slate for now; bye bye styles Let us now begin.
This commit is contained in:
commit
5f176cfeaa
137 changed files with 6330 additions and 0 deletions
3
.eslintrc
Normal file
3
.eslintrc
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "nodebb"
|
||||
}
|
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
*.css
|
||||
!less/bootstrap-flipped.css
|
||||
npm-debug.log
|
||||
sftp-config.json
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.idea
|
||||
.vscode
|
||||
node_modules/
|
6
.npmignore
Normal file
6
.npmignore
Normal file
|
@ -0,0 +1,6 @@
|
|||
*.css
|
||||
!less/bootstrap-flipped.css
|
||||
npm-debug.log
|
||||
sftp-config.json
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
8
README.md
Normal file
8
README.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
Harmony theme for NodeBB
|
||||
====================
|
||||
|
||||
The Harmony theme is the default theme for NodeBB for versions spanning v3.0.0 onwards.
|
||||
|
||||
## Issues
|
||||
|
||||
Issues are tracked in [the main project issue tracker](https://github.com/NodeBB/NodeBB/issues?q=is%3Aopen+is%3Aissue+label%3Athemes).
|
7
lib/controllers.js
Normal file
7
lib/controllers.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const Controllers = module.exports;
|
||||
|
||||
Controllers.renderAdminPage = (req, res) => {
|
||||
res.render('admin/plugins/harmony', {});
|
||||
};
|
51
library.js
Normal file
51
library.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
'use strict';
|
||||
|
||||
const controllers = require('./lib/controllers');
|
||||
|
||||
const library = module.exports;
|
||||
|
||||
library.init = async function (params) {
|
||||
const { router } = params;
|
||||
const routeHelpers = require.main.require('./src/routes/helpers');
|
||||
|
||||
routeHelpers.setupAdminPageRoute(router, '/admin/plugins/harmony', [], controllers.renderAdminPage);
|
||||
};
|
||||
|
||||
library.addAdminNavigation = async function (header) {
|
||||
header.plugins.push({
|
||||
route: '/plugins/harmony',
|
||||
icon: 'fa-paint-brush',
|
||||
name: 'Harmony Theme',
|
||||
});
|
||||
return header;
|
||||
};
|
||||
|
||||
library.defineWidgetAreas = async function (areas) {
|
||||
// const locations = ['header', 'sidebar', 'footer'];
|
||||
// const templates = [
|
||||
// 'categories.tpl', 'category.tpl', 'topic.tpl', 'users.tpl',
|
||||
// 'unread.tpl', 'recent.tpl', 'popular.tpl', 'top.tpl', 'tags.tpl', 'tag.tpl',
|
||||
// 'login.tpl', 'register.tpl',
|
||||
// ];
|
||||
// function capitalizeFirst(str) {
|
||||
// return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
// }
|
||||
// templates.forEach((template) => {
|
||||
// locations.forEach((location) => {
|
||||
// areas.push({
|
||||
// name: `${capitalizeFirst(template.split('.')[0])} ${capitalizeFirst(location)}`,
|
||||
// template: template,
|
||||
// location: location,
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
// areas = areas.concat([
|
||||
// {
|
||||
// name: 'Account Header',
|
||||
// template: 'account/profile.tpl',
|
||||
// location: 'header',
|
||||
// },
|
||||
// ]);
|
||||
return areas;
|
||||
};
|
45
package.json
Normal file
45
package.json
Normal file
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"name": "nodebb-theme-harmony",
|
||||
"version": "0.0.0",
|
||||
"nbbpm": {
|
||||
"compatibility": "^3.0.0"
|
||||
},
|
||||
"description": "Harmony theme for NodeBB",
|
||||
"main": "library.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/NodeBB/nodebb-theme-harmony"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"keywords": [
|
||||
"nodebb",
|
||||
"theme",
|
||||
"forum",
|
||||
"bootstrap",
|
||||
"responsive"
|
||||
],
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Julian Lam",
|
||||
"email": "julian@nodebb.org",
|
||||
"url": "https://github.com/julianlam"
|
||||
},
|
||||
{
|
||||
"name": "Barış Soner Uşaklı",
|
||||
"email": "baris@nodebb.org",
|
||||
"url": "https://github.com/barisusakli"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/NodeBB/nodebb-theme-harmony/issues"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-nodebb": "^0.0.2",
|
||||
"eslint-plugin-import": "^2.24.2"
|
||||
}
|
||||
}
|
11
plugin.json
Normal file
11
plugin.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"id": "nodebb-theme-harmony",
|
||||
"hooks": [
|
||||
{ "hook": "static:app.load", "method": "init" },
|
||||
{ "hook": "filter:admin.header.build", "method": "addAdminNavigation" },
|
||||
{ "hook": "filter:widgets.getAreas", "method": "defineWidgetAreas" }
|
||||
],
|
||||
"modules": {
|
||||
"../admin/plugins/harmony.js": "public/admin.js"
|
||||
}
|
||||
}
|
3
public/.eslintrc
Normal file
3
public/.eslintrc
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "nodebb/public"
|
||||
}
|
15
public/admin.js
Normal file
15
public/admin.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
'use strict';
|
||||
|
||||
define('admin/plugins/harmony', ['settings'], function (Settings) {
|
||||
var ACP = {};
|
||||
|
||||
ACP.init = function () {
|
||||
Settings.load('harmony', $('.harmony-settings'));
|
||||
|
||||
$('#save').on('click', function () {
|
||||
Settings.save('harmony', $('.harmony-settings'));
|
||||
});
|
||||
};
|
||||
|
||||
return ACP;
|
||||
});
|
3
scss/harmony.scss
Normal file
3
scss/harmony.scss
Normal file
|
@ -0,0 +1,3 @@
|
|||
// @import "variables";
|
||||
// @import "style";
|
||||
// @import "mixins";
|
1
scss/overrides.scss
Normal file
1
scss/overrides.scss
Normal file
|
@ -0,0 +1 @@
|
|||
// only overrides to bs5 variables here
|
1
templates/account/best.tpl
Normal file
1
templates/account/best.tpl
Normal file
|
@ -0,0 +1 @@
|
|||
<!-- IMPORT account/posts.tpl -->
|
33
templates/account/blocks.tpl
Normal file
33
templates/account/blocks.tpl
Normal file
|
@ -0,0 +1,33 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
<h1>[[pages:account/blocks, {username}]]</h1>
|
||||
<div class="row justify-content-end mb-2">
|
||||
<div class="col-3">
|
||||
<div class="dropdown">
|
||||
<input class="form-control" type="text" id="user-search" placeholder="[[users:enter_username]]" data-bs-toggle="dropdown" autocomplete="off"/>
|
||||
|
||||
<ul class="dropdown-menu block-edit list-unstyled">
|
||||
<li><a href="#" class="dropdown-item">[[admin/menu:search.start-typing]]</a></li>
|
||||
{{{ each edit }}}
|
||||
<li class="">
|
||||
<div class="dropdown-item d-flex flex-nowrap gap-2 justify-content-between">
|
||||
<div class="text-truncate">
|
||||
<a href="{config.relative_path}/uid/{../uid}">{buildAvatar(edit, "24px", true)} {../username}</a>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-primary text-nowrap" data-uid="{../uid}" data-action="toggle">[[user:block_toggle]]</button>
|
||||
</div>
|
||||
</li>
|
||||
{{{ end }}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="users row">
|
||||
<div class="col-12">
|
||||
<!-- IMPORT partials/users_list.tpl -->
|
||||
<div class="alert alert-warning text-center"<!-- IF users.length --> style="display: none;"<!-- END -->>[[user:has_no_blocks]]</div>
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
1
templates/account/bookmarks.tpl
Normal file
1
templates/account/bookmarks.tpl
Normal file
|
@ -0,0 +1 @@
|
|||
<!-- IMPORT account/posts.tpl -->
|
28
templates/account/categories.tpl
Normal file
28
templates/account/categories.tpl
Normal file
|
@ -0,0 +1,28 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<div class="row">
|
||||
<h1>{title}</h1>
|
||||
<div class="col-lg-12 mb-2">
|
||||
<div class="btn-group bottom-sheet" component="category/watch/all">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" type="button">
|
||||
<span>[[user:change_all]]</span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#" component="category/watching" data-state="watching"><i class="fa fa-fw fa-inbox"></i> [[category:watching]]<p class="help-text"><small>[[category:watching.description]]</small></p></a></li>
|
||||
<li><a class="dropdown-item" href="#" component="category/notwatching" data-state="notwatching"><i class="fa fa-fw fa-clock-o"></i> [[category:not-watching]]<p class="help-text"><small>[[category:not-watching.description]]</small></p></a></li>
|
||||
<li><a class="dropdown-item" href="#" component="category/ignoring" data-state="ignoring"><i class="fa fa-fw fa-eye-slash"></i> [[category:ignoring]]<p class="help-text"><small>[[category:ignoring.description]]</small></p></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<ul class="categories list-unstyled" itemscope itemtype="http://www.schema.org/ItemList">
|
||||
{{{each categories}}}
|
||||
<!-- IMPORT partials/account/category-item.tpl -->
|
||||
{{{end}}}
|
||||
</ul>
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
69
templates/account/consent.tpl
Normal file
69
templates/account/consent.tpl
Normal file
|
@ -0,0 +1,69 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
<h2>[[user:consent.title]]</h2>
|
||||
<p class="lead">[[user:consent.lead]]</p>
|
||||
<p>[[user:consent.intro]]</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<!-- IF gdpr_consent -->
|
||||
<div class="alert alert-success">
|
||||
<i class="fa fa-check float-end fa-3x"></i>
|
||||
[[user:consent.received]]
|
||||
</div>
|
||||
<!-- ELSE -->
|
||||
<div class="alert alert-warning">
|
||||
[[user:consent.not_received]]
|
||||
<br /><br />
|
||||
<div class="text-center">
|
||||
<button class="btn btn-warning" data-action="consent">[[user:consent.give]]</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END -->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p>[[user:consent.email_intro]]</p>
|
||||
<!-- IF digest.enabled -->
|
||||
<p>[[user:consent.digest_frequency, {digest.frequency}]]</p>
|
||||
<!-- ELSE -->
|
||||
[[user:consent.digest_off]]
|
||||
<!-- END -->
|
||||
|
||||
<div class="text-center">
|
||||
<a class="btn btn-outline-secondary" href="./settings">
|
||||
<i class="fa fa-cog"></i>
|
||||
[[pages:account/settings]]
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p><strong>[[user:consent.right_of_access]]</strong></p>
|
||||
<p>[[user:consent.right_of_access_description]]</p>
|
||||
<p><strong>[[user:consent.right_to_rectification]]</strong></p>
|
||||
<p>[[user:consent.right_to_rectification_description]]</p>
|
||||
<p><strong>[[user:consent.right_to_erasure]]</strong></p>
|
||||
<p>[[user:consent.right_to_erasure_description]]</p>
|
||||
<p><strong>[[user:consent.right_to_data_portability]]</strong></p>
|
||||
<p>[[user:consent.right_to_data_portability_description]]</p>
|
||||
|
||||
<div class="btn-group-vertical d-grid">
|
||||
<a data-action="export-profile" class="btn btn-outline-secondary">
|
||||
<i class="fa fa-download"></i> [[user:consent.export_profile]]
|
||||
</a>
|
||||
<a data-action="export-posts" class="btn btn-outline-secondary">
|
||||
<i class="fa fa-download"></i> [[user:consent.export_posts]]
|
||||
</a>
|
||||
<a data-action="export-uploads" class="btn btn-outline-secondary">
|
||||
<i class="fa fa-download"></i> [[user:consent.export_uploads]]
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
1
templates/account/controversial.tpl
Normal file
1
templates/account/controversial.tpl
Normal file
|
@ -0,0 +1 @@
|
|||
<!-- IMPORT account/posts.tpl -->
|
1
templates/account/downvoted.tpl
Normal file
1
templates/account/downvoted.tpl
Normal file
|
@ -0,0 +1 @@
|
|||
<!-- IMPORT account/posts.tpl -->
|
135
templates/account/edit.tpl
Normal file
135
templates/account/edit.tpl
Normal file
|
@ -0,0 +1,135 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
<!-- IF sso.length --><div><!-- ENDIF sso.length -->
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-sm-4">
|
||||
<div class="account-picture-block text-center">
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 hidden-xs">
|
||||
<!-- IF picture -->
|
||||
<img id="user-current-picture" class="avatar avatar-rounded" style="--avatar-size: 128px;" src="{picture}" />
|
||||
<!-- ELSE -->
|
||||
<div class="avatar avatar-rounded" style="background-color: {icon:bgColor}; --avatar-size: 128px;">{icon:text}</div>
|
||||
<!-- ENDIF picture -->
|
||||
</div>
|
||||
</div>
|
||||
<ul class="list-group mb-3">
|
||||
<!-- IF allowProfilePicture -->
|
||||
<a id="changePictureBtn" href="#" class="list-group-item">[[user:change_picture]]</a>
|
||||
<!-- ENDIF allowProfilePicture -->
|
||||
<!-- IF !username:disableEdit -->
|
||||
<a href="{config.relative_path}/user/{userslug}/edit/username" class="list-group-item">[[user:change_username]]</a>
|
||||
<!-- ENDIF !username:disableEdit -->
|
||||
<!-- IF !email:disableEdit -->
|
||||
<a href="{config.relative_path}/user/{userslug}/edit/email" class="list-group-item">[[user:change_email]]</a>
|
||||
<!-- ENDIF !email:disableEdit -->
|
||||
<!-- IF canChangePassword -->
|
||||
<a href="{config.relative_path}/user/{userslug}/edit/password" class="list-group-item">[[user:change_password]]</a>
|
||||
<!-- ENDIF canChangePassword -->
|
||||
{{{each editButtons}}}
|
||||
<a href="{config.relative_path}{editButtons.link}" class="list-group-item">{editButtons.text}</a>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
|
||||
<!-- IF config.requireEmailConfirmation -->
|
||||
<!-- IF email -->
|
||||
<!-- IF isSelf -->
|
||||
<a id="confirm-email" href="#" class="btn btn-warning <!-- IF email:confirmed -->hide<!-- ENDIF email:confirmed -->">[[user:confirm_email]]</a><br/><br/>
|
||||
<!-- ENDIF isSelf -->
|
||||
<!-- ENDIF email -->
|
||||
<!-- ENDIF config.requireEmailConfirmation -->
|
||||
|
||||
<!-- IF allowAccountDelete -->
|
||||
<!-- IF isSelf -->
|
||||
<a id="deleteAccountBtn" href="#" class="btn btn-danger">[[user:delete_account]]</a><br/><br/>
|
||||
<!-- ENDIF isSelf -->
|
||||
<!-- ENDIF allowAccountDelete -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="<!-- IF !sso.length -->col-md-9 col-sm-8<!-- ELSE -->col-md-5 col-sm-4<!-- ENDIF !sso.length -->">
|
||||
<form role="form" component="profile/edit/form">
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold" for="fullname">[[user:fullname]]</label>
|
||||
<input class="form-control" type="text" id="fullname" name="fullname" placeholder="[[user:fullname]]" value="{fullname}">
|
||||
</div>
|
||||
<!-- IF allowWebsite -->
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold" for="website">[[user:website]]</label>
|
||||
<input class="form-control" type="text" id="website" name="website" placeholder="http://..." value="{website}">
|
||||
</div>
|
||||
<!-- ENDIF allowWebsite -->
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold" for="location">[[user:location]]</label>
|
||||
<input class="form-control" type="text" id="location" name="location" placeholder="[[user:location]]" value="{location}">
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold" for="birthday">[[user:birthday]]</label>
|
||||
<input class="form-control" type="date" id="birthday" name="birthday" value="{birthday}" placeholder="mm/dd/yyyy">
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold" for="groupTitle">[[user:grouptitle]]</label>
|
||||
|
||||
<select class="form-select" id="groupTitle" name="groupTitle" <!-- IF allowMultipleBadges --> size="{groupSelectSize}" multiple<!-- ENDIF allowMultipleBadges -->>
|
||||
<option value="">[[user:no-group-title]]</option>
|
||||
{{{each groups}}}
|
||||
<!-- IF groups.userTitleEnabled -->
|
||||
<option value="{groups.displayName}" <!-- IF groups.selected -->selected<!-- ENDIF groups.selected -->>{groups.userTitle}</option>
|
||||
<!-- ENDIF groups.userTitleEnabled -->
|
||||
{{{end}}}
|
||||
</select>
|
||||
<!-- IF allowMultipleBadges -->
|
||||
<span>[[user:group-order-help]]</span>
|
||||
<i role="button" component="group/order/up" class="fa fa-chevron-up"></i> <i role="button" component="group/order/down" class="fa fa-chevron-down"></i>
|
||||
<!-- ENDIF -->
|
||||
</div>
|
||||
|
||||
<!-- IF allowAboutMe -->
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold" for="aboutme">[[user:aboutme]]</label> <small><label id="aboutMeCharCountLeft"></label></small>
|
||||
<textarea class="form-control" id="aboutme" name="aboutme" rows="5">{aboutme}</textarea>
|
||||
</div>
|
||||
<!-- ENDIF allowAboutMe -->
|
||||
|
||||
<!-- IF allowSignature -->
|
||||
<!-- IF !disableSignatures -->
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold" for="signature">[[user:signature]]</label> <small><label id="signatureCharCountLeft"></label></small>
|
||||
<textarea class="form-control" id="signature" name="signature" rows="5">{signature}</textarea>
|
||||
</div>
|
||||
<!-- ENDIF !disableSignatures -->
|
||||
<!-- ENDIF allowSignature -->
|
||||
|
||||
<a id="submitBtn" href="#" class="btn btn-primary">[[global:save_changes]]</a>
|
||||
</form>
|
||||
|
||||
<hr class="visible-xs visible-sm"/>
|
||||
</div>
|
||||
|
||||
<!-- IF sso.length -->
|
||||
<div class="col-md-4 col-sm-4">
|
||||
<label>[[user:sso.title]]</label>
|
||||
<div class="list-group">
|
||||
{{{each sso}}}
|
||||
<div class="list-group-item">
|
||||
<!-- IF ../deauthUrl -->
|
||||
<a data-component="{../component}" class="btn btn-outline-secondary btn-sm float-end" href="{../deauthUrl}">[[user:sso.dissociate]]</a>
|
||||
<!-- END -->
|
||||
<a data-component="{../component}" href="{../url}" target="<!-- IF ../associated -->_blank<!-- ELSE -->_top<!-- ENDIF ../associated -->">
|
||||
<!-- IF ../icon --><i class="fa {../icon}"></i><!-- ENDIF ../icon -->
|
||||
<!-- IF ../associated -->[[user:sso.associated]]<!-- ELSE -->[[user:sso.not-associated]]<!-- ENDIF ../associated -->
|
||||
{../name}
|
||||
</a>
|
||||
</div>
|
||||
{{{end}}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF sso.length -->
|
||||
</div>
|
||||
<!-- IF sso.length --></div><!-- ENDIF sso.length -->
|
||||
</div>
|
||||
|
30
templates/account/edit/password.tpl
Normal file
30
templates/account/edit/password.tpl
Normal file
|
@ -0,0 +1,30 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<form class="edit-form">
|
||||
<!-- disables autocomplete on FF --><input type="password" style="display:none">
|
||||
|
||||
<!-- IF isSelf -->
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold" for="inputCurrentPassword">[[user:current_password]]</label>
|
||||
<input autocomplete="off" class="form-control" type="password" id="inputCurrentPassword" placeholder="[[user:current_password]]" value=""<!-- IF !hasPassword --> disabled<!-- ENDIF !hasPassword -->>
|
||||
</div>
|
||||
<!-- ENDIF isSelf -->
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold" for="inputNewPassword">[[user:new_password]]</label>
|
||||
<input class="form-control" type="password" id="inputNewPassword" placeholder="[[user:password]]" value="">
|
||||
<span class="form-feedback" id="password-notify"></span>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold" for="inputNewPasswordAgain">[[user:confirm_password]]</label>
|
||||
<input class="form-control" type="password" id="inputNewPasswordAgain" placeholder="[[user:confirm_password]]" value="">
|
||||
<span class="form-feedback" id="password-confirm-notify"></span>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button id="changePasswordBtn" class="btn btn-primary btn-block"><i class="hide fa fa-spinner fa-spin"></i> [[user:change_password]]</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
26
templates/account/edit/username.tpl
Normal file
26
templates/account/edit/username.tpl
Normal file
|
@ -0,0 +1,26 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<form class="form-horizontal edit-form">
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold" for="inputNewUsername">[[user:username]]</label>
|
||||
<input class="form-control" type="text" id="inputNewUsername" placeholder="[[user:username]]" value="{username}">
|
||||
</div>
|
||||
|
||||
<!-- disables autocomplete on FF --><input type="password" style="display:none">
|
||||
|
||||
<!-- IF isSelf -->
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold" for="inputCurrentPassword">[[user:current_password]]</label>
|
||||
<input autocomplete="off" class="form-control" type="password" id="inputCurrentPassword" placeholder="[[user:current_password]]" value=""<!-- IF !hasPassword --> disabled<!-- ENDIF !hasPassword -->>
|
||||
</div>
|
||||
<!-- ENDIF isSelf -->
|
||||
|
||||
<input type="hidden" name="uid" id="inputUID" value="{uid}" />
|
||||
|
||||
<br/>
|
||||
<div class="form-actions">
|
||||
<button id="submitBtn" class="btn btn-primary btn-block"><i class="hide fa fa-spinner fa-spin"></i> [[user:change_username]]</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
17
templates/account/followers.tpl
Normal file
17
templates/account/followers.tpl
Normal file
|
@ -0,0 +1,17 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<div class="users row">
|
||||
<div class="col-12">
|
||||
<h1>[[pages:{template.name}, {username}]]</h1>
|
||||
|
||||
<!-- IMPORT partials/users_list.tpl -->
|
||||
|
||||
<!-- IF !users.length -->
|
||||
<div class="alert alert-warning text-center">[[user:has_no_follower]]</div>
|
||||
<!-- ENDIF !users.length -->
|
||||
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
17
templates/account/following.tpl
Normal file
17
templates/account/following.tpl
Normal file
|
@ -0,0 +1,17 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<div class="users row">
|
||||
<div class="col-12">
|
||||
<h1>[[pages:{template.name}, {username}]]</h1>
|
||||
|
||||
<!-- IMPORT partials/users_list.tpl -->
|
||||
|
||||
<!-- IF !users.length -->
|
||||
<div class="alert alert-warning text-center">[[user:follows_no_one]]</div>
|
||||
<!-- ENDIF !users.length -->
|
||||
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
17
templates/account/groups.tpl
Normal file
17
templates/account/groups.tpl
Normal file
|
@ -0,0 +1,17 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<div class="row">
|
||||
<h1>[[pages:{template.name}, {username}]]</h1>
|
||||
|
||||
<div class="col-12 groups list">
|
||||
<div component="groups/container" id="groups-list" class="row">
|
||||
<!-- IF !groups.length -->
|
||||
<div class="alert alert-warning text-center">[[groups:no_groups_found]]</div>
|
||||
<!-- ELSE -->
|
||||
<!-- IMPORT partials/groups/list.tpl -->
|
||||
<!-- ENDIF !groups.length -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
1
templates/account/ignored.tpl
Normal file
1
templates/account/ignored.tpl
Normal file
|
@ -0,0 +1 @@
|
|||
<!-- IMPORT account/topics.tpl -->
|
226
templates/account/info.tpl
Normal file
226
templates/account/info.tpl
Normal file
|
@ -0,0 +1,226 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<!-- IF sessions.length -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-12">
|
||||
<h4>[[global:sessions]]</h4>
|
||||
<ul class="list-group" component="user/sessions">
|
||||
{{{each sessions}}}
|
||||
<li class="list-group-item" data-uuid="{../uuid}">
|
||||
<div class="float-end">
|
||||
<!-- IF isSelfOrAdminOrGlobalModerator -->
|
||||
<!-- IF !../current -->
|
||||
<button class="btn btn-sm btn-outline-secondary" type="button" data-action="revokeSession">Revoke Session</button>
|
||||
<!-- ENDIF !../current -->
|
||||
<!-- ENDIF isSelfOrAdminOrGlobalModerator -->
|
||||
{function.userAgentIcons}
|
||||
<i class="fa fa-circle text-<!-- IF ../current -->success<!-- ELSE -->muted<!-- ENDIF ../current -->"></i>
|
||||
</div>
|
||||
{../browser} {../version} on {../platform}<br />
|
||||
<small class="timeago text-muted" title="{../datetimeISO}"></small>
|
||||
<ul>
|
||||
<li><strong>[[global:ip_address]]</strong>: {../ip}</li>
|
||||
</ul>
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF sessions.length -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="card mb-3">
|
||||
<h5 class="card-header">
|
||||
[[global:recentips]]
|
||||
</h5>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
{{{each ips}}}
|
||||
<li>{@value}</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<h5 class="card-header">
|
||||
[[user:info.username-history]]
|
||||
</h5>
|
||||
<div class="card-body">
|
||||
<ul class="list-group">
|
||||
{{{each usernames}}}
|
||||
<li class="list-group-item">
|
||||
{../value}
|
||||
<small class="float-end"><span class="timeago" title="{../timestampISO}"></span></small>
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
[[user:info.email-history]]
|
||||
</h5>
|
||||
<div class="card-body">
|
||||
<ul class="list-group">
|
||||
{{{each emails}}}
|
||||
<li class="list-group-item">
|
||||
{../value}
|
||||
<small class="float-end"><span class="timeago" title="{../timestampISO}"></span></small>
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="card mb-3">
|
||||
<h5 class="card-header">
|
||||
[[user:info.latest-flags]]
|
||||
</h5>
|
||||
<div class="card-body">
|
||||
<!-- IF history.flags.length -->
|
||||
<ul class="recent-flags list-unstyled">
|
||||
{{{each history.flags}}}
|
||||
<li>
|
||||
<p>
|
||||
{{{ if history.flags.targetPurged }}}
|
||||
<div>[[flags:target-purged]]</div>
|
||||
{{{ else }}}
|
||||
<a class="title" href="{config.relative_path}/post/{../pid}">{../title}</a><br />
|
||||
{{{ end }}}
|
||||
<span class="timestamp">[[flags:flagged-timeago-readable, {../timestampISO}, {../timestampReadable}]]</span>
|
||||
</p>
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
<!-- ELSE -->
|
||||
<div class="alert alert-success">[[user:info.no-flags]]</div>
|
||||
<!-- ENDIF history.flags.length -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<h5 class="card-header">
|
||||
[[user:info.ban-history]]
|
||||
|
||||
<!-- IF !banned -->
|
||||
<!-- IF !isSelf -->
|
||||
<button class="btn btn-sm float-end btn-danger" component="account/ban">[[user:ban_account]]</button>
|
||||
<!-- ENDIF !isSelf -->
|
||||
<!-- ELSE -->
|
||||
<!-- IF !isSelf -->
|
||||
<button class="btn btn-sm float-end btn-success" component="account/unban">[[user:unban_account]]</button>
|
||||
<!-- ENDIF !isSelf -->
|
||||
<!-- ENDIF !banned -->
|
||||
</h5>
|
||||
<div class="card-body">
|
||||
<!-- IF history.bans.length -->
|
||||
<ul class="ban-history list-unstyled">
|
||||
{{{each history.bans}}}
|
||||
<li>
|
||||
<p>
|
||||
<a href="{config.relative_path}/user/{history.bans.user.userslug}">{buildAvatar(history.bans.user, "24px", true)}</a>
|
||||
<strong>
|
||||
<a href="<!-- IF history.bans.user.userslug -->{config.relative_path}/user/{history.bans.user.userslug}<!-- ELSE -->#<!-- ENDIF history.bans.user.userslug -->" itemprop="author" data-username="{history.bans.user.username}" data-uid="{history.bans.user.uid}">{history.bans.user.username}</a>
|
||||
</strong>
|
||||
<span class="timestamp timeago" title="{../timestampISO}"></span> — {../timestampReadable}<br />
|
||||
<!-- IF ../until -->
|
||||
<span class="expiry">[[user:info.banned-until, {../untilReadable}]]</span><br />
|
||||
<!-- ELSE -->
|
||||
<span class="expiry">[[user:info.banned-permanently]]</span><br />
|
||||
<!-- ENDIF ../until -->
|
||||
<span class="reason"><strong>[[user:info.banned-reason-label]]</strong>: {../reason}</span>
|
||||
</p>
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
<!-- ELSE -->
|
||||
<div class="alert alert-success">[[user:info.no-ban-history]]</div>
|
||||
<!-- ENDIF history.bans.length -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<h5 class="card-header">
|
||||
[[user:info.mute-history]]
|
||||
|
||||
{{{ if !muted }}}
|
||||
{{{ if !isSelf }}}
|
||||
<button class="btn btn-sm float-end btn-danger" component="account/mute">[[user:mute_account]]</button>
|
||||
{{{ end }}}
|
||||
{{{ else }}}
|
||||
{{{ if !isSelf }}}
|
||||
<button class="btn btn-sm float-end btn-success" component="account/unmute">[[user:unmute_account]]</button>
|
||||
{{{ end }}}
|
||||
{{{ end }}}
|
||||
</h5>
|
||||
<div class="card-body">
|
||||
{{{ if history.mutes.length }}}
|
||||
<ul class="ban-history list-unstyled">
|
||||
{{{ each history.mutes }}}
|
||||
<li>
|
||||
<p>
|
||||
<a href="{config.relative_path}/user/{history.mutes.user.userslug}">{buildAvatar(history.mutes.user, "24px", true)}</a>
|
||||
<strong>
|
||||
<a href="<!-- IF history.mutes.user.userslug -->{config.relative_path}/user/{history.mutes.user.userslug}<!-- ELSE -->#<!-- ENDIF history.mutes.user.userslug -->" itemprop="author" data-username="{history.mutes.user.username}" data-uid="{history.mutes.user.uid}">{history.mutes.user.username}</a>
|
||||
</strong>
|
||||
<span class="timestamp timeago" title="{../timestampISO}"></span> — {../timestampReadable}<br />
|
||||
{{{ if ../until }}}
|
||||
<span class="expiry">[[user:info.muted-until, {../untilReadable}]]</span><br />
|
||||
{{{ end }}}
|
||||
|
||||
<span class="reason"><strong>[[user:info.banned-reason-label]]</strong>: {../reason}</span>
|
||||
</p>
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
{{{ else }}}
|
||||
<div class="alert alert-success">[[user:info.no-mute-history]]</div>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- IF isAdminOrGlobalModerator -->
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
[[user:info.moderation-note]]
|
||||
</h5>
|
||||
<div class="card-body">
|
||||
<textarea component="account/moderation-note" class="form-control"></textarea>
|
||||
<br/>
|
||||
<button class="btn btn-sm float-end btn-success" component="account/save-moderation-note">[[user:info.moderation-note.add]]</button>
|
||||
<br/>
|
||||
<div component="account/moderation-note/list">
|
||||
{{{each moderationNotes}}}
|
||||
<hr/>
|
||||
|
||||
<div class="clearfix">
|
||||
<div class="float-start">
|
||||
<a href="<!-- IF moderationNotes.user.userslug -->{config.relative_path}/user/{moderationNotes.user.userslug}<!-- ELSE -->#<!-- ENDIF moderationNotes.user.userslug -->">{buildAvatar(moderationNotes.user, "24px", true)}</a>
|
||||
<strong>
|
||||
<a href="<!-- IF moderationNotes.user.userslug -->{config.relative_path}/user/{moderationNotes.user.userslug}<!-- ELSE -->#<!-- ENDIF moderationNotes.user.userslug -->" itemprop="author" data-username="{moderationNotes.user.username}" data-uid="{moderationNotes.user.uid}">{moderationNotes.user.username}</a>
|
||||
</strong>
|
||||
|
||||
<div class="visible-xs-inline-block visible-sm-inline-block visible-md-inline-block visible-lg-inline-block">
|
||||
<span class="timeago" title="{moderationNotes.timestampISO}"></span>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div class="content">
|
||||
{moderationNotes.note}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{{end}}}
|
||||
</div>
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF isAdminOrGlobalModerator -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
19
templates/account/posts.tpl
Normal file
19
templates/account/posts.tpl
Normal file
|
@ -0,0 +1,19 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<div class="row">
|
||||
<h1>{title}</h1>
|
||||
|
||||
<!-- IF !posts.length -->
|
||||
<div class="alert alert-warning text-center">{noItemsFoundKey}</div>
|
||||
<!-- ENDIF !posts.length -->
|
||||
|
||||
<div class="col-12">
|
||||
<!-- IMPORT partials/posts_list.tpl -->
|
||||
|
||||
<!-- IF config.usePagination -->
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
<!-- ENDIF config.usePagination -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
166
templates/account/profile.tpl
Normal file
166
templates/account/profile.tpl
Normal file
|
@ -0,0 +1,166 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<div class="profile row">
|
||||
<h1 class="fullname"><!-- IF fullname -->{fullname}<!-- ELSE -->{username}<!-- ENDIF fullname --></h1>
|
||||
<h2 class="username"><!-- IF !banned -->@{username}<!-- ELSE -->[[user:banned]]<!-- ENDIF !banned --></h2>
|
||||
<!-- IF isAdminOrGlobalModeratorOrModerator -->
|
||||
<!-- IF banned -->
|
||||
<div class="text-center">
|
||||
<!-- IF banned_until -->
|
||||
[[user:info.banned-until, {banned_until_readable}]]
|
||||
<!-- ELSE -->
|
||||
[[user:info.banned-permanently]]
|
||||
<!-- ENDIF banned_until -->
|
||||
</div>
|
||||
<!-- ENDIF banned -->
|
||||
<!-- ENDIF isAdminOrGlobalModeratorOrModerator -->
|
||||
|
||||
<!-- IF selectedGroup.length -->
|
||||
<div class="text-center">
|
||||
{{{each selectedGroup}}}
|
||||
<!-- IF selectedGroup.slug -->
|
||||
<!-- IMPORT partials/groups/badge.tpl -->
|
||||
<!-- ENDIF selectedGroup.slug -->
|
||||
{{{end}}}
|
||||
</div>
|
||||
<br/>
|
||||
<!-- ENDIF selectedGroup.length -->
|
||||
|
||||
<!-- IF aboutme -->
|
||||
<span component="aboutme" class="text-center aboutme">{aboutmeParsed}</span>
|
||||
<!-- ENDIF aboutme -->
|
||||
|
||||
<div class="account-stats">
|
||||
<!-- IF !reputation:disabled -->
|
||||
<div class="stat">
|
||||
<div class="human-readable-number" title="{reputation}">{reputation}</div>
|
||||
<span class="stat-label">[[global:reputation]]</span>
|
||||
</div>
|
||||
<!-- ENDIF !reputation:disabled -->
|
||||
|
||||
<div class="stat">
|
||||
<div class="human-readable-number" title="{profileviews}">{profileviews}</div>
|
||||
<span class="stat-label">[[user:profile_views]]</span>
|
||||
</div>
|
||||
|
||||
<div class="stat">
|
||||
<div><a class="human-readable-number" title="{counts.posts}" href="{config.relative_path}/user/{userslug}/posts">{counts.posts}</a></div>
|
||||
<span class="stat-label">[[global:posts]]</span>
|
||||
</div>
|
||||
|
||||
<div class="stat">
|
||||
<div><a class="human-readable-number" title="{counts.followers}" href="{config.relative_path}/user/{userslug}/followers">{counts.followers}</a></div>
|
||||
<span class="stat-label">[[user:followers]]</span>
|
||||
</div>
|
||||
|
||||
<div class="stat">
|
||||
<div><a class="human-readable-number" title="{counts.following}" href="{config.relative_path}/user/{userslug}/following">{counts.following}</a></div>
|
||||
<span class="stat-label">[[user:following]]</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center profile-meta">
|
||||
<span>[[user:joined]]</span>
|
||||
<strong class="timeago" title="{joindateISO}"></strong>
|
||||
|
||||
<span>[[user:lastonline]]</span>
|
||||
<strong class="timeago" title="{lastonlineISO}"></strong><br />
|
||||
|
||||
<!-- IF email -->
|
||||
<span>[[user:email]]</span>
|
||||
<strong><i class="fa fa-eye-slash {emailClass}" title="[[user:email_hidden]]"></i> {email}</strong>
|
||||
<!-- ENDIF email -->
|
||||
|
||||
<!-- IF websiteName -->
|
||||
<span>[[user:website]]</span>
|
||||
<strong><a href="{websiteLink}" rel="nofollow noopener noreferrer">{websiteName}</a></strong>
|
||||
<!-- ENDIF websiteName -->
|
||||
|
||||
<!-- IF location -->
|
||||
<span>[[user:location]]</span>
|
||||
<strong>{location}</strong>
|
||||
<!-- ENDIF location -->
|
||||
|
||||
<!-- IF age -->
|
||||
<span>[[user:age]]</span>
|
||||
<strong>{age}</strong>
|
||||
<!-- ENDIF age -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 account-block hidden">
|
||||
<div class="account-picture-block text-center">
|
||||
<span>
|
||||
<span class="account-username"> {username}</span>
|
||||
</span>
|
||||
|
||||
<!-- IF !isSelf -->
|
||||
<a component="account/unfollow" href="#" class="btn btn-outline-secondary{{{ if !isFollowing }}} hide{{{ end }}}">[[user:unfollow]]</a>
|
||||
<a component="account/follow" href="#" class="btn btn-primary{{{ if isFollowing }}} hide{{{ end }}}">[[user:follow]]</a>
|
||||
<!-- ENDIF !isSelf -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- IF groups.length -->
|
||||
<div class="row">
|
||||
<div class="col-12 hidden">
|
||||
{{{each groups}}}
|
||||
<a href="{config.relative_path}/groups/{groups.slug}"><span class="label group-label inline-block" style="background-color: {groups.labelColor};"><!-- IF groups.icon --><i class="fa {groups.icon}"></i> <!-- ENDIF groups.icon -->{groups.userTitle}</span></a>
|
||||
{{{end}}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF groups.length -->
|
||||
|
||||
<!-- IF ips.length -->
|
||||
<div class="row">
|
||||
<div class="col-12 hidden">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
[[global:recentips]]
|
||||
</h5>
|
||||
<div class="card-body">
|
||||
{{{each ips}}}
|
||||
<div>{ips}</div>
|
||||
{{{end}}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF ips.length -->
|
||||
|
||||
<div class="row">
|
||||
{{{ if bestPosts.length }}}
|
||||
<div class="col-lg-12 col-12">
|
||||
<h1>[[pages:account/best, {username}]]</h1>
|
||||
|
||||
<div class="col-12">
|
||||
<ul component="posts" class="posts-list list-unstyled">
|
||||
{{{each bestPosts}}}
|
||||
<!-- IMPORT partials/posts_list_item.tpl -->
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
{{{ if latestPosts.length}}}
|
||||
<div class="col-lg-12 col-12">
|
||||
<h1>[[pages:account/latest-posts, {username}]]</h1>
|
||||
<div class="col-12">
|
||||
<ul component="posts" class="posts-list list-unstyled">
|
||||
{{{each latestPosts}}}
|
||||
<!-- IMPORT partials/posts_list_item.tpl -->
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
|
||||
<div id="user-action-alert" class="alert alert-success hide"></div>
|
||||
</div>
|
32
templates/account/sessions.tpl
Normal file
32
templates/account/sessions.tpl
Normal file
|
@ -0,0 +1,32 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<!-- IF sessions.length -->
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-12">
|
||||
<p class="lead">[[user:sessions.description]]</p>
|
||||
<hr />
|
||||
<ul class="list-group" component="user/sessions">
|
||||
{{{each sessions}}}
|
||||
<li class="list-group-item" data-uuid="{../uuid}">
|
||||
<div class="float-end">
|
||||
<!-- IF isSelfOrAdminOrGlobalModerator -->
|
||||
<!-- IF !../current -->
|
||||
<button class="btn btn-sm btn-outline-secondary" type="button" data-action="revokeSession">Revoke Session</button>
|
||||
<!-- ENDIF !../current -->
|
||||
<!-- ENDIF isSelfOrAdminOrGlobalModerator -->
|
||||
{function.userAgentIcons}
|
||||
<i class="fa fa-circle text-<!-- IF ../current -->success<!-- ELSE -->muted<!-- ENDIF ../current -->"></i>
|
||||
</div>
|
||||
{../browser} {../version} on {../platform}<br />
|
||||
<small class="timeago text-muted" title="{../datetimeISO}"></small>
|
||||
<ul>
|
||||
<li><strong>[[global:ip_address]]</strong>: {../ip}</li>
|
||||
</ul>
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF sessions.length -->
|
||||
</div>
|
229
templates/account/settings.tpl
Normal file
229
templates/account/settings.tpl
Normal file
|
@ -0,0 +1,229 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6">
|
||||
<!-- IF !disableCustomUserSkins -->
|
||||
<h4>[[user:select-skin]]</h4>
|
||||
<div class="card card-body mb-3">
|
||||
<select class="form-select" id="bootswatchSkin" data-property="bootswatchSkin">
|
||||
{{{each bootswatchSkinOptions}}}
|
||||
<option value="{bootswatchSkinOptions.value}" <!-- IF bootswatchSkinOptions.selected -->selected<!-- ENDIF bootswatchSkinOptions.selected -->>{bootswatchSkinOptions.name}</option>
|
||||
{{{end}}}
|
||||
</select>
|
||||
</div>
|
||||
<!-- ENDIF !disableCustomUserSkins -->
|
||||
|
||||
<!-- IF allowUserHomePage -->
|
||||
<h4>[[user:select-homepage]]</h4>
|
||||
<div class="card card-body mb-3">
|
||||
<div class="mb-2">
|
||||
<label for="homePageRoute">[[user:homepage]]</label>
|
||||
<select class="form-select" id="homePageRoute" data-property="homePageRoute">
|
||||
<option value="none">None</option>
|
||||
{{{each homePageRoutes}}}
|
||||
<option value="{homePageRoutes.route}" <!-- IF homePageRoutes.selected -->selected="1"<!-- ENDIF homePageRoutes.selected -->>{homePageRoutes.name}</option>
|
||||
{{{end}}}
|
||||
</select>
|
||||
<p class="form-text">[[user:homepage_description]]</p>
|
||||
</div>
|
||||
<div id="homePageCustom" class="mb-2" style="display: none;">
|
||||
<label for="homePageCustom">[[user:custom_route]]</label>
|
||||
<input type="text" class="form-control" data-property="homePageCustom" id="homePageCustom" value="{settings.homePageRoute}"/>
|
||||
<p class="form-text">[[user:custom_route_help]]</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF allowUserHomePage -->
|
||||
|
||||
<h4>[[global:privacy]]</h4>
|
||||
<div class="card card-body mb-3">
|
||||
<!-- IF !hideEmail -->
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" data-property="showemail" <!-- IF settings.showemail -->checked <!-- ENDIF settings.showemail -->/>
|
||||
<strong>
|
||||
<label class="form-check-label">[[user:show_email]]</label>
|
||||
</strong>
|
||||
</div>
|
||||
<!-- ENDIF !hideEmail -->
|
||||
|
||||
<!-- IF !hideFullname -->
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" data-property="showfullname" <!-- IF settings.showfullname -->checked<!-- ENDIF settings.showfullname -->/>
|
||||
<strong>
|
||||
<label class="form-check-label">[[user:show_fullname]]</label>
|
||||
</strong>
|
||||
</div>
|
||||
<!-- ENDIF !hideFullname -->
|
||||
<!-- IF !config.disableChat -->
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" data-property="restrictChat" <!-- IF settings.restrictChat -->checked<!-- ENDIF settings.restrictChat -->/>
|
||||
<strong>
|
||||
<label class="form-check-label">[[user:restrict_chats]]</label>
|
||||
</strong>
|
||||
</div>
|
||||
<!-- ENDIF !config.disableChat -->
|
||||
</div>
|
||||
|
||||
<h4>[[user:browsing]]</h4>
|
||||
<div class="card card-body mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" data-property="openOutgoingLinksInNewTab" <!-- IF settings.openOutgoingLinksInNewTab -->checked<!-- ENDIF settings.openOutgoingLinksInNewTab -->/>
|
||||
<strong>
|
||||
<label class="form-check-label">[[user:open_links_in_new_tab]]</label>
|
||||
</strong>
|
||||
</div>
|
||||
<!-- IF inTopicSearchAvailable -->
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" data-property="topicSearchEnabled" <!-- IF settings.topicSearchEnabled -->checked<!-- ENDIF settings.topicSearchEnabled -->/>
|
||||
<strong>
|
||||
<label class="form-check-label">[[user:enable_topic_searching]]</label>
|
||||
</strong>
|
||||
</div>
|
||||
<p class="form-text">[[user:topic_search_help]]</p>
|
||||
<!-- ENDIF inTopicSearchAvailable -->
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" data-property="updateUrlWithPostIndex" {{{ if settings.updateUrlWithPostIndex }}}checked{{{ end }}}/>
|
||||
<strong>
|
||||
<label class="form-check-label">[[user:update_url_with_post_index]]</label>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" data-property="scrollToMyPost" <!-- IF settings.scrollToMyPost -->checked<!-- ENDIF settings.scrollToMyPost -->/>
|
||||
<strong>
|
||||
<label class="form-check-label">[[user:scroll_to_my_post]]</label>
|
||||
</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4>[[global:pagination]]</h4>
|
||||
<div class="card card-body mb-3">
|
||||
<div class="mb-2 form-check">
|
||||
<input type="checkbox" class="form-check-input" data-property="usePagination" <!-- IF settings.usePagination -->checked<!-- ENDIF settings.usePagination -->> <strong><label class="form-check-label">[[user:paginate_description]]</label></strong>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong><label class="form-label">[[user:topics_per_page]] ([[user:max_items_per_page, {maxTopicsPerPage}]])</label></strong>
|
||||
<input type="text" class="form-control" data-property="topicsPerPage" value="{settings.topicsPerPage}">
|
||||
</div>
|
||||
<div class="">
|
||||
<strong><label class="form-label">[[user:posts_per_page]] ([[user:max_items_per_page, {maxPostsPerPage}]])</label></strong>
|
||||
<input type="text" class="form-control" data-property="postsPerPage" value="{settings.postsPerPage}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- IF !disableEmailSubscriptions -->
|
||||
<h4>[[global:email]]</h4>
|
||||
<div class="card card-body mb-3">
|
||||
<div class="mb-2">
|
||||
<label for="dailyDigestFreq">[[user:digest_label]]</label>
|
||||
<select class="form-select" id="dailyDigestFreq" data-property="dailyDigestFreq" autocomplete="off">
|
||||
{{{each dailyDigestFreqOptions}}}
|
||||
<option value="{dailyDigestFreqOptions.value}" <!-- IF dailyDigestFreqOptions.selected -->selected="1"<!-- ENDIF dailyDigestFreqOptions.selected -->>{dailyDigestFreqOptions.name}</option>
|
||||
{{{end}}}
|
||||
</select>
|
||||
<p class="form-text">[[user:digest_description]]</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF !disableEmailSubscriptions -->
|
||||
|
||||
{{{each customSettings}}}
|
||||
<h4>{customSettings.title}</h4>
|
||||
<div class="card card-body mb-3">
|
||||
{customSettings.content}
|
||||
</div>
|
||||
{{{end}}}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6">
|
||||
<h4>[[global:language]]</h4>
|
||||
<div class="card card-body mb-3">
|
||||
<div class="row">
|
||||
<div class="mb-2 col-lg-12">
|
||||
<select data-property="userLang" class="form-select">
|
||||
{{{each languages}}}
|
||||
<option value="{languages.code}" <!-- IF languages.selected -->selected<!-- ENDIF languages.selected -->>{languages.name} ({languages.code})</option>
|
||||
{{{end}}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<!-- IF isAdmin -->
|
||||
<!-- IF isSelf -->
|
||||
<label>[[user:acp_language]]</label>
|
||||
<div class="row">
|
||||
<div class="mb-2 col-lg-12">
|
||||
<select data-property="acpLang" class="form-select">
|
||||
{{{each acpLanguages}}}
|
||||
<option value="{acpLanguages.code}" <!-- IF acpLanguages.selected -->selected<!-- ENDIF acpLanguages.selected -->>{acpLanguages.name} ({acpLanguages.code})</option>
|
||||
{{{end}}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF isSelf -->
|
||||
<!-- ENDIF isAdmin -->
|
||||
</div>
|
||||
|
||||
<h4>[[topic:watch]]</h4>
|
||||
<div class="card card-body mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" data-property="followTopicsOnCreate" <!-- IF settings.followTopicsOnCreate -->checked <!-- ENDIF settings.followTopicsOnCreate -->/>
|
||||
<strong>
|
||||
<label class="form-check-label">[[user:follow_topics_you_create]]</label>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" data-property="followTopicsOnReply" <!-- IF settings.followTopicsOnReply -->checked<!-- ENDIF settings.followTopicsOnReply -->/>
|
||||
<strong>
|
||||
<label class="form-check-label">[[user:follow_topics_you_reply_to]]</label>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label>[[user:default-category-watch-state]]</label>
|
||||
<select class="form-select" data-property="categoryWatchState">
|
||||
<option value="watching" <!-- IF categoryWatchState.watching -->selected<!-- ENDIF categoryWatchState.watching -->>[[category:watching]]</option>
|
||||
<option value="notwatching" <!-- IF categoryWatchState.notwatching -->selected<!-- ENDIF categoryWatchState.notwatching -->>[[category:not-watching]]</option>
|
||||
<option value="ignoring" <!-- IF categoryWatchState.ignoring -->selected<!-- ENDIF categoryWatchState.ignoring -->>[[category:ignoring]]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h4>[[user:notifications]]</h4>
|
||||
<div class="card card-body mb-3">
|
||||
{{{each notificationSettings}}}
|
||||
<div class="row mb-3">
|
||||
<div class="col-7">
|
||||
<label>{notificationSettings.label}</label>
|
||||
</div>
|
||||
<div class="mb-2 col-5">
|
||||
<select class="form-select" data-property="{notificationSettings.name}">
|
||||
<option value="none" <!-- IF notificationSettings.none -->selected<!-- ENDIF notificationSettings.none -->>[[notifications:none]]</option>
|
||||
<option value="notification" <!-- IF notificationSettings.notification -->selected<!-- ENDIF notificationSettings.notification -->>[[notifications:notification_only]]</option>
|
||||
<option value="email" <!-- IF notificationSettings.email -->selected<!-- ENDIF notificationSettings.email -->>[[notifications:email_only]]</option>
|
||||
<option value="notificationemail" <!-- IF notificationSettings.notificationemail -->selected<!-- ENDIF notificationSettings.notificationemail -->>[[notifications:notification_and_email]]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{{{end}}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-7">
|
||||
<label for="upvote-notif-freq">[[user:upvote-notif-freq]]</label>
|
||||
</div>
|
||||
<div class="mb-2 col-5">
|
||||
<select class="form-select" id="upvote-notif-freq" name="upvote-notif-freq" data-property="upvoteNotifFreq">
|
||||
{{{each upvoteNotifFreq}}}
|
||||
<option value="{upvoteNotifFreq.name}" <!-- IF upvoteNotifFreq.selected -->selected<!-- ENDIF upvoteNotifFreq.selected -->>
|
||||
[[user:upvote-notif-freq.{upvoteNotifFreq.name}]]
|
||||
</option>
|
||||
{{{end}}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<a id="submitBtn" href="#" class="btn btn-primary">[[global:save_changes]]</a>
|
||||
</div>
|
||||
</div>
|
||||
|
27
templates/account/theme.tpl
Normal file
27
templates/account/theme.tpl
Normal file
|
@ -0,0 +1,27 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<p>[[persona:settings.intro]]</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<form id="theme-settings" role="form">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" id="persona:menus:legacy-layout" name="persona:menus:legacy-layout"> <strong>[[persona:settings.mobile-menu-side]]</strong>
|
||||
</label>
|
||||
</div><br />
|
||||
|
||||
<div class="form-group">
|
||||
<label for="persona:navbar:autohide">[[persona:settings.autoHidingNavbar]]</label>
|
||||
<select multiple class="form-control" name="persona:navbar:autohide" id="persona:navbar:autohide">
|
||||
<option value="xs">[[persona:settings.autoHidingNavbar-xs]]</option>
|
||||
<option value="sm">[[persona:settings.autoHidingNavbar-sm]]</option>
|
||||
<option value="md">[[persona:settings.autoHidingNavbar-md]]</option>
|
||||
<option value="lg">[[persona:settings.autoHidingNavbar-lg]]</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button id="save" type="button" class="btn btn-primary">[[global:save_changes]]</button>
|
||||
</form>
|
||||
</div>
|
30
templates/account/topics.tpl
Normal file
30
templates/account/topics.tpl
Normal file
|
@ -0,0 +1,30 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
|
||||
<div class="row">
|
||||
<h1>{title}</h1>
|
||||
<!-- IF showSort -->
|
||||
<div class="btn-toolbar justify-content-end mb-2">
|
||||
<div class="btn-group bottom-sheet" component="thread/sort">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" type="button"><span>[[topic:sort_by]]</span> <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
{{{each sortOptions }}}
|
||||
<li><a class="dropdown-item" href="{config.relative_path}{sortOptions.url}"><i class="fa fa-fw {{{if sortOptions.selected}}}fa-check{{{end}}}"></i>{sortOptions.name}</a></li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF showSort -->
|
||||
|
||||
<!-- IF !topics.length -->
|
||||
<div class="alert alert-warning text-center">{noItemsFoundKey}</div>
|
||||
<!-- ENDIF !topics.length -->
|
||||
|
||||
<div class="category">
|
||||
<!-- IMPORT partials/topics_list.tpl -->
|
||||
<!-- IF config.usePagination -->
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
<!-- ENDIF config.usePagination -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
43
templates/account/uploads.tpl
Normal file
43
templates/account/uploads.tpl
Normal file
|
@ -0,0 +1,43 @@
|
|||
<div class="account">
|
||||
<!-- IMPORT partials/account/header.tpl -->
|
||||
<div class="row">
|
||||
<h1>{title}</h1>
|
||||
|
||||
<!-- IF privateUploads -->
|
||||
<div class="alert alert-info text-center">[[uploads:private-uploads-info]]</div>
|
||||
<!-- ELSE -->
|
||||
<div class="alert alert-info text-center">[[uploads:public-uploads-info]]</div>
|
||||
<!-- ENDIF privateUploads -->
|
||||
|
||||
<!-- IF !uploads.length -->
|
||||
<div class="alert alert-warning text-center">[[uploads:no-uploads-found]]</div>
|
||||
<!-- ENDIF !uploads.length -->
|
||||
|
||||
<div class="col-12">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{{each uploads}}}
|
||||
<tr data-name="{uploads.name}">
|
||||
<td>
|
||||
<a href="{config.relative_path}{uploads.url}">{uploads.url}</a>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group ">
|
||||
<button class="btn btn-danger btn-sm" data-action="delete"><i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{{end}}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
1
templates/account/upvoted.tpl
Normal file
1
templates/account/upvoted.tpl
Normal file
|
@ -0,0 +1 @@
|
|||
<!-- IMPORT account/posts.tpl -->
|
1
templates/account/watched.tpl
Normal file
1
templates/account/watched.tpl
Normal file
|
@ -0,0 +1 @@
|
|||
<!-- IMPORT account/topics.tpl -->
|
27
templates/admin/plugins/persona.tpl
Normal file
27
templates/admin/plugins/persona.tpl
Normal file
|
@ -0,0 +1,27 @@
|
|||
<div class="row">
|
||||
<div class="col-sm-2 col-12 settings-header">Theme Settings</div>
|
||||
<div class="col-sm-10 col-12">
|
||||
<form role="form" class="persona-settings">
|
||||
<div class="checkbox">
|
||||
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
|
||||
<input class="mdl-switch__input" type="checkbox" id="hideSubCategories" name="hideSubCategories">
|
||||
<span class="mdl-switch__label"><strong>Hide subcategories on categories view</strong></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
|
||||
<input class="mdl-switch__input" type="checkbox" id="hideCategoryLastPost" name="hideCategoryLastPost">
|
||||
<span class="mdl-switch__label"><strong>Hide last post on categories view</strong></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
|
||||
<input class="mdl-switch__input" type="checkbox" id="enableQuickReply" name="enableQuickReply">
|
||||
<span class="mdl-switch__label"><strong>Enable quick reply</strong></span>
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- IMPORT admin/partials/save_button.tpl -->
|
31
templates/categories.tpl
Normal file
31
templates/categories.tpl
Normal file
|
@ -0,0 +1,31 @@
|
|||
<!-- IMPORT partials/breadcrumbs.tpl -->
|
||||
<div data-widget-area="header">
|
||||
{{{ each widgets.header }}}
|
||||
{{widgets.header.html}}
|
||||
{{{ end }}}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="{{{ if widgets.sidebar.length }}}col-lg-9 col-sm-12{{{ else }}}col-lg-12{{{ end }}}">
|
||||
{{{ if pagination.pages.length }}}
|
||||
<div><!-- IMPORT partials/category-selector.tpl --></div>
|
||||
{{{ else }}}
|
||||
<h1 class="categories-title">[[pages:categories]]</h1>
|
||||
{{{ end }}}
|
||||
<ul class="categories" itemscope itemtype="http://www.schema.org/ItemList">
|
||||
{{{ each categories }}}
|
||||
<!-- IMPORT partials/categories/item.tpl -->
|
||||
{{{ end }}}
|
||||
</ul>
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</div>
|
||||
<div data-widget-area="sidebar" class="col-lg-3 col-sm-12 {{{ if !widgets.sidebar.length }}}hidden{{{ end }}}">
|
||||
{{{ each widgets.sidebar }}}
|
||||
{{widgets.sidebar.html}}
|
||||
{{{ end }}}
|
||||
</div>
|
||||
</div>
|
||||
<div data-widget-area="footer">
|
||||
{{{ each widgets.footer }}}
|
||||
{{widgets.footer.html}}
|
||||
{{{ end }}}
|
||||
</div>
|
63
templates/category.tpl
Normal file
63
templates/category.tpl
Normal file
|
@ -0,0 +1,63 @@
|
|||
<!-- IMPORT partials/breadcrumbs.tpl -->
|
||||
<div data-widget-area="header">
|
||||
{{{ each widgets.header }}}
|
||||
{{widgets.header.html}}
|
||||
{{{ end }}}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="category {{{if widgets.sidebar.length }}}col-lg-9 col-sm-12{{{ else }}}col-lg-12{{{ end }}}">
|
||||
<!-- IMPORT partials/category/subcategory.tpl -->
|
||||
|
||||
<div class="topic-list-header sticky-top btn-toolbar justify-content-between py-2 mb-2 flex-nowrap">
|
||||
<div class="d-flex gap-1 align-items-stretch">
|
||||
{{{ if privileges.topics:create }}}
|
||||
<a href="{config.relative_path}/compose?cid={cid}" component="category/post" id="new_topic" class="btn btn-primary text-nowrap" data-ajaxify="false" role="button">[[category:new_topic_button]]</a>
|
||||
{{{ else }}}
|
||||
{{{ if !loggedIn }}}
|
||||
<a component="category/post/guest" href="{config.relative_path}/login" class="btn btn-primary">[[category:guest-login-post]]</a>
|
||||
{{{ end }}}
|
||||
{{{ end }}}
|
||||
|
||||
<a href="{config.relative_path}/{selectedFilter.url}{querystring}" class="d-inline-block">
|
||||
<div class="alert alert-warning h-100 m-0 px-2 py-1 d-flex align-items-center hide" id="new-topics-alert"></div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="d-flex gap-1 align-items-stretch">
|
||||
<!-- IMPORT partials/category/watch.tpl -->
|
||||
<!-- IMPORT partials/category/sort.tpl -->
|
||||
<!-- IMPORT partials/category/tools.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{{ if !topics.length }}}
|
||||
{{{ if privileges.topics:create }}}
|
||||
<hr class="visible-xs" />
|
||||
<div class="alert alert-warning" id="category-no-topics">
|
||||
[[category:no_topics]]
|
||||
</div>
|
||||
{{{ end }}}
|
||||
{{{ end }}}
|
||||
|
||||
<!-- IMPORT partials/topics_list.tpl -->
|
||||
|
||||
{{{ if config.usePagination }}}
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
{{{ end }}}
|
||||
</div>
|
||||
<div data-widget-area="sidebar" class="col-lg-3 col-sm-12 {{{ if !widgets.sidebar.length }}}hidden{{{ end }}}">
|
||||
{{{ each widgets.sidebar }}}
|
||||
{{widgets.sidebar.html}}
|
||||
{{{ end }}}
|
||||
</div>
|
||||
</div>
|
||||
<div data-widget-area="footer">
|
||||
{{{each widgets.footer}}}
|
||||
{{widgets.footer.html}}
|
||||
{{{end}}}
|
||||
</div>
|
||||
|
||||
<!-- IF !config.usePagination -->
|
||||
<noscript>
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</noscript>
|
||||
<!-- ENDIF !config.usePagination -->
|
39
templates/chat.tpl
Normal file
39
templates/chat.tpl
Normal file
|
@ -0,0 +1,39 @@
|
|||
<div id="chat-modal" class="chat-modal modal hide" tabindex="-1" role="dialog" aria-labelledby="Chat" aria-hidden="true" data-backdrop="none">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header d-flex">
|
||||
<div class="fs-5 flex-grow-1" component="chat/room/name">{{{ if roomName }}}{roomName}{{{ else }}}{usernames}{{{ end }}}</div>
|
||||
<button type="button" class="btn btn-link d-none d-md-block p-2 text-muted align-text-top" data-action="maximize">
|
||||
<span aria-hidden="true"><i class="fa fa-fw fa-expand"></i></span>
|
||||
<span class="sr-only">[[modules:chat.maximize]]</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-link d-none d-md-block p-2 text-muted align-text-top" data-action="minimize">
|
||||
<span aria-hidden="true"><i class="fa fa-fw fa-minus"></i></span>
|
||||
<span class="sr-only">[[modules:chat.minimize]]</span>
|
||||
</button>
|
||||
<!-- IMPORT partials/chats/options.tpl -->
|
||||
|
||||
<button id="chat-close-btn" type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="position-relative">
|
||||
<div component="chat/messages/scroll-up-alert" class="position-absolute scroll-up-alert alert alert-info hidden w-100" role="button" style="z-index: 1;">[[modules:chat.scroll-up-alert]]</div>
|
||||
</div>
|
||||
<ul class="chat-content" component="chat/messages">
|
||||
<!-- IMPORT partials/chats/messages.tpl -->
|
||||
</ul>
|
||||
|
||||
<div component="chat/composer">
|
||||
<textarea component="chat/input" placeholder="[[modules:chat.placeholder]]" class="form-control chat-input mousetrap" rows="1"></textarea>
|
||||
<button class="btn btn-primary" type="button" data-action="send"><i class="fa fa-fw fa-2x fa-paper-plane"></i></button>
|
||||
<span component="chat/message/remaining">{maximumChatMessageLength}</span>
|
||||
<form component="chat/upload" method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="files[]" multiple class="hidden"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="imagedrop"><div>[[topic:composer.drag_and_drop_images]]</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
19
templates/chats.tpl
Normal file
19
templates/chats.tpl
Normal file
|
@ -0,0 +1,19 @@
|
|||
<div class="chats-full">
|
||||
<div component="chat/nav-wrapper" data-loaded="{{{ if roomId }}}1{{{ else }}}0{{{ end }}}">
|
||||
<div class="chat-search dropdown">
|
||||
<input class="form-control" type="text" component="chat/search" placeholder="[[users:search-user-for-chat]]" data-bs-toggle="dropdown" />
|
||||
<ul component="chat/search/list" class="dropdown-menu">
|
||||
<li><a href="#" class="dropdown-item">[[admin/menu:search.start-typing]]</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul component="chat/recent" class="chats-list list-unstyled" data-nextstart="{nextStart}">
|
||||
{{{each rooms}}}
|
||||
<!-- IMPORT partials/chats/recent_room.tpl -->
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
||||
<div component="chat/main-wrapper">
|
||||
<!-- IMPORT partials/chats/message-window.tpl -->
|
||||
</div>
|
||||
<div class="imagedrop"><div>[[topic:composer.drag_and_drop_images]]</div></div>
|
||||
</div>
|
209
templates/flags/detail.tpl
Normal file
209
templates/flags/detail.tpl
Normal file
|
@ -0,0 +1,209 @@
|
|||
<!-- IMPORT partials/breadcrumbs.tpl -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="h4">
|
||||
{target_readable}
|
||||
<small><span class="text-muted timeago" title="{datetimeISO}"></span></small>
|
||||
</h2>
|
||||
|
||||
<hr />
|
||||
|
||||
<!-- IF type_bool.post -->
|
||||
<div class="d-flex">
|
||||
<div class="flex-shrink-0">
|
||||
<a href="{config.relative_path}/user/{target.user.userslug}">{buildAvatar(target.user, "64px", true, "media-object")}</a>
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-3">
|
||||
<h4 class="media-heading"><a href="{config.relative_path}/user/{target.user.userslug}">{target.user.username}</a></h4>
|
||||
{target.content}
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF type_bool.post -->
|
||||
|
||||
<!-- IF type_bool.user -->
|
||||
<div class="d-flex">
|
||||
<div class="flex-shrink-0">
|
||||
<a href="{config.relative_path}/user/{target.userslug}">{buildAvatar(target, "64px", true, "media-object")}</a>
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-3">
|
||||
<h4 class="media-heading"><a href="{config.relative_path}/user/{target.userslug}">{target.username}</a></h4>
|
||||
<p class="lead">
|
||||
<a href="{config.relative_path}/uid/{target.uid}">[[flags:user-view]]</a> |
|
||||
<a href="{config.relative_path}/uid/{target.uid}/edit">[[flags:user-edit]]</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF type_bool.user -->
|
||||
|
||||
<!-- IF type_bool.empty -->
|
||||
<div class="alert alert-warning" role="alert">[[flags:target-purged]]</div>
|
||||
<!-- ENDIF type_bool.empty -->
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<form role="form" id="attributes">
|
||||
<div class="mb-3">
|
||||
<h2 class="h4">[[flags:reports]]</h2>
|
||||
<ul class="list-group" component="flag/reports">
|
||||
{{{ each reports }}}
|
||||
<li class="list-group-item">
|
||||
<a href="{config.relative_path}/user/{./reporter.userslug}">{buildAvatar(./reporter, "24px", true)}</a>
|
||||
– <span class="timeago" title="{./timestampISO}"></span>
|
||||
<blockquote><em>{./value}</em></blockquote>
|
||||
</li>
|
||||
{{{ end }}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<h2 class="h4" for="state">[[flags:state]]</h2>
|
||||
<select class="form-select" id="state" name="state" disabled>
|
||||
<option value="open">[[flags:state-open]]</option>
|
||||
<option value="wip">[[flags:state-wip]]</option>
|
||||
<option value="resolved">[[flags:state-resolved]]</option>
|
||||
<option value="rejected">[[flags:state-rejected]]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<h2 class="h4" for="assignee">[[flags:assignee]]</h2>
|
||||
<select class="form-control" id="assignee" name="assignee" disabled>
|
||||
<option value="">[[flags:no-assignee]]</option>
|
||||
{{{each assignees}}}
|
||||
<option value="{../uid}">{../username}</option>
|
||||
{{{end}}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="button" class="btn btn-primary" data-action="update">[[flags:update]]</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<hr />
|
||||
|
||||
<form role="form">
|
||||
<div class="mb-3">
|
||||
<h2 class="h4" for="note">[[flags:notes]]</h2>
|
||||
<textarea id="note" class="form-control"></textarea>
|
||||
<div class="d-grid">
|
||||
<button type="button" class="btn btn-block btn-primary" data-action="appendNote">[[flags:add-note]]</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div component="flag/notes">
|
||||
<!-- IF !notes.length -->
|
||||
<div class="alert alert-success text-center">[[flags:no-notes]]</div>
|
||||
<!-- ENDIF !notes.length -->
|
||||
{{{each notes}}}
|
||||
<div class="d-flex mb-3">
|
||||
<div class="flex-shrink-0">
|
||||
<a href="{config.relative_path}/user/{../user.userslug}">{buildAvatar(notes.user, "32px", true, "media-object")}</a>
|
||||
</div>
|
||||
<div class="flex-grow-1 mx-3">
|
||||
<h2 class="h5">
|
||||
<a href="{config.relative_path}/user/{../user.userslug}">{../user.username}</a>
|
||||
<small><span class="timeago" title="{../datetimeISO}"></span></small>
|
||||
</h4>
|
||||
{../content}
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
<a href="#" class="btn btn-sm btn-link" data-action="prepare-edit"><i class="fa fa-pencil"></i></a>
|
||||
<a href="#" class="btn btn-sm btn-link" data-action="delete-note"><i class="fa fa-trash text-danger"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
{{{end}}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<h2 class="h4">[[flags:quick-actions]]</h2>
|
||||
|
||||
<div class="d-grid gap-1">
|
||||
<a class="btn btn-light" href="{config.relative_path}/{type_path}/{targetId}">
|
||||
<i class="fa fa-external-link"></i>
|
||||
[[flags:go-to-target]]
|
||||
</a>
|
||||
|
||||
<a class="btn btn-light" href="#" data-action="assign">
|
||||
<i class="fa fa-id-card-o"></i>
|
||||
[[flags:assign-to-me]]
|
||||
</a>
|
||||
|
||||
{{{ if type_bool.post }}}
|
||||
{{{ if !target.deleted}}}
|
||||
<a class="btn btn-outline-danger" href="#" data-action="delete-post"><i class="fa fa-trash"></i> [[flags:delete-post]]</a>
|
||||
{{{ else }}}
|
||||
<a class="btn btn-danger" href="#" data-action="purge-post"><i class="fa fa-trash"></i> [[flags:purge-post]]</a>
|
||||
<a class="btn btn-outline-success" href="#" data-action="restore-post"><i class="fa fa-reply"></i><i class="fa fa-trash"></i> [[flags:restore-post]]</a>
|
||||
{{{ end }}}
|
||||
{{{ end }}}
|
||||
|
||||
{{{ if target.uid }}}
|
||||
<div class="btn-group" data-uid="{target.uid}">
|
||||
<button type="button" class="btn btn-light dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fa fa-street-view"></i>
|
||||
[[flags:flagged-user]]
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="{config.relative_path}/uid/{target.uid}">[[flags:view-profile]]</a></li>
|
||||
{{{ if !config.disableChat }}}
|
||||
<li><a class="dropdown-item" href="#" data-action="chat">[[flags:start-new-chat]]</a></li>
|
||||
{{{ end }}}
|
||||
<li class="dropdown-divider"></li>
|
||||
{{{ if privileges.ban }}}
|
||||
<li class="{{{ if target.user.banned }}}hidden{{{ end }}}"><a class="dropdown-item" href="#" data-action="ban">[[user:ban_account]]</a></li>
|
||||
<li class="{{{ if !target.user.banned }}}hidden{{{ end }}}"><a class="dropdown-item" href="#" data-action="unban">[[user:unban_account]]</a></li>
|
||||
{{{ end }}}
|
||||
{{{ if privileges.mute}}}
|
||||
<li class="{{{ if target.user.muted }}}hidden{{{ end }}}"><a class="dropdown-item" href="#" data-action="mute">[[user:mute_account]]</a></li>
|
||||
<li class="{{{ if !target.user.muted }}}hidden{{{ end }}}"><a class="dropdown-item" href="#" data-action="unmute">[[user:unmute_account]]</a></li>
|
||||
{{{ end }}}
|
||||
{{{ if privileges.admin:users }}}
|
||||
<li><a class="dropdown-item" href="#" data-action="delete-account">[[user:delete_account_as_admin]]</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-action="delete-content">[[user:delete_content]]</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-action="delete-all">[[user:delete_all]]</a></li>
|
||||
{{{ end }}}
|
||||
</ul>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<h2 class="h4">[[flags:history]]</h2>
|
||||
<div component="flag/history">
|
||||
<!-- IF !history.length -->
|
||||
<div class="alert alert-success text-center">[[flags:no-history]]</div>
|
||||
<!-- ENDIF !history.length -->
|
||||
{{{each history}}}
|
||||
<div class="d-flex">
|
||||
<div class="flex-shrink-0">
|
||||
<a href="{config.relative_path}/user/{../user.userslug}">{buildAvatar(history.user, "32px", true, "media-object")}</a>
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-3">
|
||||
<h4 class="media-heading">
|
||||
<a href="{config.relative_path}/user/{../user.userslug}">{../user.username}</a>
|
||||
<small><span class="timeago" title="{../datetimeISO}"></span></small>
|
||||
</h4>
|
||||
<ul>
|
||||
{{{each ./fields}}}
|
||||
<li>
|
||||
<span class="badge bg-primary">[[flags:{@key}]]</span><!-- IF @value --> → <span class="badge bg-light text-dark">{@value}</span><!-- ENDIF @value -->
|
||||
</li>
|
||||
{{{end}}}
|
||||
{{{ each ./meta }}}
|
||||
<li>
|
||||
<span class="badge bg-{{./labelClass}}">{{./key}}</span>{{{ if ./value }}} → <span class="badge bg-light text-dark">{{ ./value }}</span>{{{ end }}}
|
||||
</li>
|
||||
{{{ end }}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{{end}}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
71
templates/flags/list.tpl
Normal file
71
templates/flags/list.tpl
Normal file
|
@ -0,0 +1,71 @@
|
|||
<!-- IMPORT partials/breadcrumbs.tpl -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-4 col-md-3">
|
||||
<!-- IMPORT partials/flags/filters.tpl -->
|
||||
</div>
|
||||
<div class="col-sm-8 col-md-9">
|
||||
<!-- IF hasFilter -->
|
||||
<div class="alert alert-warning">
|
||||
<p class="float-end">
|
||||
<a href="{config.relative_path}/flags">[[flags:filter-reset]]</a>
|
||||
</p>
|
||||
[[flags:filter-active]]
|
||||
</div>
|
||||
<!-- ENDIF hasFilter -->
|
||||
|
||||
<div class="btn-group float-end" component="flags/bulk-actions">
|
||||
<button type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" autocomplete="off" aria-haspopup="true" aria-expanded="false" disabled="disabled">
|
||||
<i class="fa fa-clone"></i> [[flags:bulk-actions]] <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" class="dropdown-item" data-action="bulk-assign">[[flags:assign-to-me]]</a></li>
|
||||
<li><a href="#" class="dropdown-item" data-action="bulk-mark-resolved">[[flags:bulk-resolve]]</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<table class="table table-striped table-hover" component="flags/list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<input type="checkbox" data-action="toggle-all" autocomplete="off" />
|
||||
</th>
|
||||
<th></th>
|
||||
<th><span class="hidden-xs">[[flags:reports]] </span><i class="fa fa-user-plus"></i></th>
|
||||
<th><span class="hidden-xs">[[flags:first-reported]] </span><i class="fa fa-clock-o"></i></th>
|
||||
<th>[[flags:state]]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- IF !flags.length -->
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="alert alert-success text-center">
|
||||
[[flags:no-flags]]
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- ENDIF !flags.length -->
|
||||
{{{each flags}}}
|
||||
<tr data-flag-id="{../flagId}">
|
||||
<td>
|
||||
<input type="checkbox" autocomplete="off" />
|
||||
</td>
|
||||
<td>
|
||||
<a href="{config.relative_path}/flags/{../flagId}">
|
||||
<strong>{../target_readable}</strong>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{./heat}
|
||||
</td>
|
||||
<td><span class="timeago" title="{../datetimeISO}"></span></td>
|
||||
<td><span class="badge bg-{../labelClass}">[[flags:state-{../state}]]</span></td>
|
||||
</tr>
|
||||
{{{end}}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</div>
|
||||
</div>
|
14
templates/footer.tpl
Normal file
14
templates/footer.tpl
Normal file
|
@ -0,0 +1,14 @@
|
|||
</div><!-- /.container#content -->
|
||||
</main>
|
||||
{{{ if !isSpider }}}
|
||||
<div component="toaster/tray" class="alert-window">
|
||||
<div id="reconnect-alert" class="alert alert-dismissible alert-warning clearfix hide" component="toaster/toast">
|
||||
<button type="button" class="btn-close float-end" data-bs-dismiss="alert" aria-hidden="true"></button>
|
||||
<p>[[global:reconnecting-message, {config.siteTitle}]]</p>
|
||||
</div>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
|
||||
<!-- IMPORT partials/footer/js.tpl -->
|
||||
</body>
|
||||
</html>
|
77
templates/groups/details.tpl
Normal file
77
templates/groups/details.tpl
Normal file
|
@ -0,0 +1,77 @@
|
|||
<div component="groups/container" class="groups details row">
|
||||
<div component="groups/cover" style="background-image: url({group.cover:url}); background-position: {group.cover:position};">
|
||||
<!-- IF group.isOwner -->
|
||||
<div class="controls">
|
||||
<span class="upload"><i class="fa fa-fw fa-4x fa-upload"></i></span>
|
||||
<span class="resize"><i class="fa fa-fw fa-4x fa-arrows"></i></span>
|
||||
<span class="remove"><i class="fa fa-fw fa-4x fa-times"></i></span>
|
||||
</div>
|
||||
<div class="save">[[groups:cover-save]] <i class="fa fa-fw fa-floppy-o"></i></div>
|
||||
<div class="indicator">[[groups:cover-saving]] <i class="fa fa-fw fa-refresh fa-spin"></i></div>
|
||||
<!-- ENDIF group.isOwner -->
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<!-- IMPORT partials/breadcrumbs.tpl -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-12">
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<span class="fs-5">
|
||||
<i class="fa fa-list-ul"></i> [[groups:details.title]]
|
||||
<!-- IF group.private --><span class="badge bg-info text-dark">[[groups:details.private]]</span><!-- ENDIF group.private -->
|
||||
<!-- IF group.hidden --><span class="badge bg-info text-dark">[[groups:details.hidden]]</span> <!-- ENDIF group.hidden -->
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h2>{group.displayName}</h2>
|
||||
<p>{group.descriptionParsed}</p>
|
||||
<!-- IF isAdmin -->
|
||||
<div class="float-end">
|
||||
<a href="{config.relative_path}/admin/manage/groups/{group.nameEncoded}" target="_blank" class="btn btn-info"><i class="fa fa-gear"></i> [[user:edit]]</a>
|
||||
</div>
|
||||
<!-- ENDIF isAdmin -->
|
||||
<!-- IF loggedIn -->
|
||||
<div class="float-end">
|
||||
{function.membershipBtn, group}
|
||||
</div>
|
||||
<!-- ENDIF loggedIn -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<span class="fs-5">
|
||||
<i class="fa fa-users"></i> [[groups:details.members]]
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- IMPORT partials/groups/memberlist.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- IF group.isOwner -->
|
||||
<!-- IMPORT partials/groups/admin.tpl -->
|
||||
<!-- ENDIF group.isOwner -->
|
||||
|
||||
<div data-widget-area="left">
|
||||
{{{each widgets.left}}}
|
||||
{{widgets.left.html}}
|
||||
{{{end}}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-8 col-12">
|
||||
<div class="col-lg-11">
|
||||
<!-- IF !posts.length -->
|
||||
<div class="alert alert-info">[[groups:details.has_no_posts]]</div>
|
||||
<!-- ENDIF !posts.length -->
|
||||
<!-- IMPORT partials/posts_list.tpl -->
|
||||
</div>
|
||||
<div data-widget-area="right">
|
||||
{{{each widgets.right}}}
|
||||
{{widgets.right.html}}
|
||||
{{{end}}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
48
templates/groups/list.tpl
Normal file
48
templates/groups/list.tpl
Normal file
|
@ -0,0 +1,48 @@
|
|||
<!-- IMPORT partials/breadcrumbs.tpl -->
|
||||
<div data-widget-area="header">
|
||||
{{{each widgets.header}}}
|
||||
{{widgets.header.html}}
|
||||
{{{end}}}
|
||||
</div>
|
||||
<div class="groups list">
|
||||
<div class="row justify-content-between">
|
||||
<div class="col-lg-6">
|
||||
<!-- IF allowGroupCreation -->
|
||||
<button class="btn btn-primary" data-action="new"><i class="fa fa-plus"></i> [[groups:new_group]]</button>
|
||||
<!-- ENDIF allowGroupCreation -->
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="row justify-content-end">
|
||||
<div class="col-5 col-md-6">
|
||||
<select class="form-select" id="search-sort">
|
||||
<option value="alpha">[[groups:details.group_name]]</option>
|
||||
<option value="count">[[groups:details.member_count]]</option>
|
||||
<option value="date">[[groups:details.creation_date]]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-7 col-md-6">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" placeholder="[[global:search]]" name="query" value="" id="search-text">
|
||||
<button id="search-button" class="btn btn-primary">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div component="groups/container" class="row" id="groups-list" data-nextstart={nextStart}>
|
||||
<!-- IF groups.length -->
|
||||
<!-- IMPORT partials/groups/list.tpl -->
|
||||
<!-- ELSE -->
|
||||
<div class="col-12">
|
||||
<div class="alert alert-warning">
|
||||
[[groups:no_groups_found]]
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF groups.length -->
|
||||
</div>
|
||||
</div>
|
6
templates/groups/members.tpl
Normal file
6
templates/groups/members.tpl
Normal file
|
@ -0,0 +1,6 @@
|
|||
<!-- IMPORT partials/breadcrumbs.tpl -->
|
||||
<div class="users">
|
||||
<!-- IMPORT partials/users_list.tpl -->
|
||||
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</div>
|
47
templates/header.tpl
Normal file
47
templates/header.tpl
Normal file
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="{function.localeToHTML, userLang, defaultLang}" {{{if languageDirection}}}data-dir="{languageDirection}" style="direction: {languageDirection};"{{{end}}}>
|
||||
<head>
|
||||
<title>{browserTitle}</title>
|
||||
{{{each metaTags}}}{function.buildMetaTag}{{{end}}}
|
||||
<link rel="stylesheet" type="text/css" href="{relative_path}/assets/client{{{if bootswatchSkin}}}-{bootswatchSkin}{{{end}}}{{{ if (languageDirection=="rtl") }}}-rtl{{{ end }}}.css?{config.cache-buster}" />
|
||||
{{{each linkTags}}}{function.buildLinkTag}{{{end}}}
|
||||
|
||||
<script>
|
||||
var config = JSON.parse('{{configJSON}}');
|
||||
var app = {
|
||||
user: JSON.parse('{{userJSON}}')
|
||||
};
|
||||
|
||||
document.documentElement.style.setProperty('--panel-offset', `${localStorage.getItem('panelOffset') || 0}px`);
|
||||
</script>
|
||||
|
||||
{{{if useCustomHTML}}}
|
||||
{{customHTML}}
|
||||
{{{end}}}
|
||||
{{{if useCustomCSS}}}
|
||||
<style>{{customCSS}}</style>
|
||||
{{{end}}}
|
||||
</head>
|
||||
|
||||
<body class="{bodyClass} skin-{{{if bootswatchSkin}}}{bootswatchSkin}{{{else}}}noskin{{{end}}}">
|
||||
<nav id="menu" class="slideout-menu hidden">
|
||||
<!-- IMPORT partials/slideout-menu.tpl -->
|
||||
</nav>
|
||||
<nav id="chats-menu" class="slideout-menu hidden">
|
||||
<!-- IMPORT partials/chats-menu.tpl -->
|
||||
</nav>
|
||||
|
||||
<main id="panel" class="slideout-panel">
|
||||
<nav class="navbar sticky-top navbar-expand-lg bg-light header border-bottom" id="header-menu" component="navbar">
|
||||
<div class="container justify-content-start flex-nowrap">
|
||||
<!-- IMPORT partials/menu.tpl -->
|
||||
</div>
|
||||
</nav>
|
||||
<script>
|
||||
const rect = document.getElementById('header-menu').getBoundingClientRect();
|
||||
const offset = Math.max(0, rect.bottom);
|
||||
document.documentElement.style.setProperty('--panel-offset', offset + `px`);
|
||||
</script>
|
||||
<div class="container pt-3" id="content">
|
||||
<!-- IMPORT partials/noscript/warning.tpl -->
|
||||
<!-- IMPORT partials/noscript/message.tpl -->
|
96
templates/login.tpl
Normal file
96
templates/login.tpl
Normal file
|
@ -0,0 +1,96 @@
|
|||
<!-- IMPORT partials/breadcrumbs.tpl -->
|
||||
<div data-widget-area="header">
|
||||
{{{each widgets.header}}}
|
||||
{{widgets.header.html}}
|
||||
{{{end}}}
|
||||
</div>
|
||||
<div class="row login">
|
||||
<div class="{{{ if widgets.sidebar.length }}}col-lg-9 col-sm-12{{{ else }}}col-lg-12{{{ end }}}">
|
||||
<div class="row">
|
||||
{{{ if allowLocalLogin }}}
|
||||
<div class="{{{ if alternate_logins }}}col-md-6{{{ else }}}col-md-12{{{ end }}}">
|
||||
<div class="login-block">
|
||||
<div class="alert alert-danger alert-dismissible" id="login-error-notify" {{{ if error }}}style="display:block"{{{ else }}}style="display: none;"{{{ end }}}>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
<strong>[[login:failed_login_attempt]]</strong>
|
||||
<p>{error}</p>
|
||||
</div>
|
||||
|
||||
<form class="form-horizontal" role="form" method="post" id="login-form">
|
||||
<div class="row mb-2">
|
||||
<label for="username" class="col-lg-2 col-form-label">{allowLoginWith}</label>
|
||||
<div class="col-lg-10">
|
||||
<input class="form-control" type="text" placeholder="{allowLoginWith}" name="username" id="username" autocorrect="off" autocapitalize="off" value="{username}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label for="password" class="col-lg-2 col-form-label">[[user:password]]</label>
|
||||
<div class="col-lg-10">
|
||||
<input class="form-control" type="password" placeholder="[[user:password]]" name="password" id="password" {{{ if username }}}autocomplete="off"{{{ end }}}/>
|
||||
<p id="caps-lock-warning" class="text-danger hidden">
|
||||
<i class="fa fa-exclamation-triangle"></i> [[login:caps-lock-enabled]]
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-lg-10 offset-lg-2">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="remember" id="remember" checked /> [[login:remember_me]]
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{{each loginFormEntry}}}
|
||||
<div class="row mb-2 loginFormEntry">
|
||||
<label for="login-{loginFormEntry.styleName}" class="col-lg-2 col-form-label">{loginFormEntry.label}</label>
|
||||
<div id="login-{loginFormEntry.styleName}" class="col-lg-10">{{loginFormEntry.html}}</div>
|
||||
</div>
|
||||
{{{end}}}
|
||||
<input type="hidden" name="_csrf" value="{config.csrf_token}" />
|
||||
<input type="hidden" name="noscript" id="noscript" value="true" />
|
||||
<div class="row">
|
||||
<div class="col-lg-10 offset-lg-2">
|
||||
<button class="btn btn-primary btn-lg" id="login" type="submit">[[global:login]]</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-10 offset-lg-2">
|
||||
{{{ if allowRegistration }}}
|
||||
<span>[[login:dont_have_account]] <a href="{config.relative_path}/register">[[register:register]]</a></span>
|
||||
{{{ end }}}
|
||||
{{{ if allowPasswordReset }}}
|
||||
<a id="reset-link" href="{config.relative_path}/reset">[[login:forgot_password]]</a>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
|
||||
{{{ if alternate_logins }}}
|
||||
<div class="{{{ if allowLocalLogin }}}col-md-6{{{ else }}}col-md-12{{{ end }}}">
|
||||
<div class="alt-login-block">
|
||||
<h4>[[login:alternative_logins]]</h4>
|
||||
<ul class="alt-logins">
|
||||
{{{each authentication}}}
|
||||
<li class="{authentication.name}"><a rel="nofollow noopener noreferrer" target="_top" href="{config.relative_path}{authentication.url}"><i class="fa {authentication.icon} fa-3x"></i></a></li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
</div>
|
||||
<div data-widget-area="sidebar" class="col-lg-3 col-sm-12 {{{ if !widgets.sidebar.length }}}hidden{{{ end }}}">
|
||||
{{{each widgets.sidebar}}}
|
||||
{{widgets.sidebar.html}}
|
||||
{{{end}}}
|
||||
</div>
|
||||
</div>
|
||||
<div data-widget-area="footer">
|
||||
{{{each widgets.footer}}}
|
||||
{{widgets.footer.html}}
|
||||
{{{end}}}
|
||||
</div>
|
3
templates/modules/taskbar.tpl
Normal file
3
templates/modules/taskbar.tpl
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div id="taskbar" class="taskbar fixed-bottom">
|
||||
<div class="navbar-inner"><ul class="nav navbar-nav"></ul></div>
|
||||
</div>
|
37
templates/modules/usercard.tpl
Normal file
37
templates/modules/usercard.tpl
Normal file
|
@ -0,0 +1,37 @@
|
|||
<div class="persona-usercard">
|
||||
<a href="{config.relative_path}/user/{userslug}">
|
||||
<!-- IF picture -->
|
||||
<div class="usercard-picture" style="background-image:url({picture})"></div>
|
||||
<!-- ELSE -->
|
||||
<div class="usercard-picture" style="background-color: {icon:bgColor};">{icon:text}</div>
|
||||
<!-- ENDIF picture -->
|
||||
</a>
|
||||
<div class="usercard-body">
|
||||
<a href="{config.relative_path}/user/{userslug}">
|
||||
<span class="usercard-name"><!-- IF fullname -->{fullname}<!-- ELSE -->{username}<!-- ENDIF fullname --></span><br />
|
||||
<span class="usercard-username"><!-- IF !banned -->@{username}<!-- ELSE -->[[user:banned]]<!-- ENDIF !banned --></span>
|
||||
<!-- IF !banned -->
|
||||
<i component="user/status" class="fa fa-circle status {status}" title="[[global:{status}]]"></i>
|
||||
<!-- ENDIF !banned -->
|
||||
</a>
|
||||
|
||||
<div class="row usercard-info">
|
||||
<div class="col-4">
|
||||
<small>[[global:posts]]</small>
|
||||
<span class="human-readable-number">{postcount}</span>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<small>[[global:reputation]]</small>
|
||||
<span class="human-readable-number">{reputation}</span>
|
||||
</div>
|
||||
|
||||
<button class="btn-morph persona-fab <!-- IF banned --> hide<!-- ENDIF banned -->">
|
||||
<span>
|
||||
<span class="s1"></span>
|
||||
<span class="s2"></span>
|
||||
<span class="s3"></span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
66
templates/notifications.tpl
Normal file
66
templates/notifications.tpl
Normal file
|
@ -0,0 +1,66 @@
|
|||
|
||||
<div class="notifications">
|
||||
|
||||
<!-- IMPORT partials/breadcrumbs.tpl -->
|
||||
<div class="btn-toolbar justify-content-end" role="toolbar">
|
||||
<div class="btn-group me-2">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
||||
{{{ if selectedFilter }}}{selectedFilter.name}{{{ end}}} <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end" role="menu">
|
||||
{{{ each filters }}}
|
||||
{{{ if filters.separator }}}
|
||||
<li role="separator" class="dropdown-divider"></li>
|
||||
{{{ else }}}
|
||||
<li role="presentation" class="category">
|
||||
<a class="dropdown-item" role="menu-item" href="{config.relative_path}/notifications?filter={filters.filter}"><i class="fa fa-fw {{{ if filters.selected }}}fa-check{{{ end }}}"></i> {filters.name}</a>
|
||||
</li>
|
||||
{{{ end }}}
|
||||
{{{ end }}}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="true">
|
||||
<i class="fa fa-eye"></i>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end" role="menu" aria-labelledby="dropdownMenu1">
|
||||
<li role="presentation"><a class="dropdown-item" role="menuitem" tabindex="-1" href="#" component="notifications/mark_all">[[notifications:mark_all_read]]</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="alert alert-info {{{ if notifications.length }}}hidden{{{ end }}}">
|
||||
[[notifications:no_notifs]]
|
||||
</div>
|
||||
|
||||
<ul class="notifications-list list-unstyled" data-nextstart="{nextStart}">
|
||||
{{{each notifications}}}
|
||||
<li data-nid="{notifications.nid}" class="{notifications.readClass} {{{ if !./read}}}text-bg-warning{{{ end }}} d-flex pointer border p-3 mb-2" component="notifications/item">
|
||||
<div class="me-2">
|
||||
{{{ if notifications.from }}}
|
||||
{buildAvatar(notifications.user, "24px", true)}
|
||||
{{{ else }}}
|
||||
{{{ if notifications.image }}}
|
||||
<img width="24" height="24" src="{notifications.image}" />
|
||||
{{{ end }}}
|
||||
{{{ end }}}
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-1">
|
||||
<a class="text-reset" component="notifications/item/link" href="{notifications.path}">{notifications.bodyShort}</a>
|
||||
</p>
|
||||
<p class="timestamp">
|
||||
<span class="timeago small text-reset" title="{notifications.datetimeISO}"></span>
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</div>
|
||||
|
||||
|
9
templates/partials/acceptTos.tpl
Normal file
9
templates/partials/acceptTos.tpl
Normal file
|
@ -0,0 +1,9 @@
|
|||
<div class="form-group">
|
||||
<label for="agree-terms">[[register:terms_of_use]]</label>
|
||||
<div class="tos">{termsOfUse}</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="agree-terms" id="agree-terms"> [[register:agree_to_terms_of_use]]
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
23
templates/partials/account/category-item.tpl
Normal file
23
templates/partials/account/category-item.tpl
Normal file
|
@ -0,0 +1,23 @@
|
|||
<li component="categories/category" data-cid="{../cid}" data-parent-cid="{../parentCid}" class="row clearfix">
|
||||
<meta itemprop="name" content="{../name}">
|
||||
|
||||
<div class="content col-10 depth-{../depth}">
|
||||
<div class="float-start">
|
||||
{buildCategoryIcon(@value, "48px", "rounded-circle")}
|
||||
</div>
|
||||
|
||||
<h2 class="title">
|
||||
<!-- IMPORT partials/categories/link.tpl -->
|
||||
</h2>
|
||||
<div>
|
||||
<!-- IF ../descriptionParsed -->
|
||||
<div class="description text-muted">
|
||||
{../descriptionParsed}
|
||||
</div>
|
||||
<!-- ENDIF ../descriptionParsed -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<!-- IMPORT partials/category/watch.tpl -->
|
||||
</div>
|
||||
</li>
|
46
templates/partials/account/header.tpl
Normal file
46
templates/partials/account/header.tpl
Normal file
|
@ -0,0 +1,46 @@
|
|||
<!-- IMPORT partials/breadcrumbs.tpl -->
|
||||
|
||||
<div data-widget-area="header">
|
||||
{{{each widgets.header}}}
|
||||
{{widgets.header.html}}
|
||||
{{{end}}}
|
||||
</div>
|
||||
|
||||
<div class="cover" component="account/cover" style="background-image: url({cover:url}); background-position: {cover:position};">
|
||||
<div class="avatar-wrapper" data-uid="{uid}">
|
||||
<!-- IF picture -->
|
||||
<img src="{picture}" class="avatar avatar-rounded" style="--avatar-size: 128px;" />
|
||||
<!-- ELSE -->
|
||||
<div class="avatar avatar-rounded" style="background-color: {icon:bgColor}; --avatar-size: 128px;" title="{username}">{icon:text}</div>
|
||||
<!-- ENDIF picture -->
|
||||
<i component="user/status" class="fa fa-circle status {status}" title="[[global:{status}]]"></i>
|
||||
|
||||
<!-- IF loggedIn -->
|
||||
<!-- IF !isSelf -->
|
||||
<button class="btn-morph persona-fab <!-- IF isFollowing -->heart<!-- ELSE -->plus<!-- ENDIF isFollowing -->" title="<!-- IF isFollowing -->[[global:unfollow]]<!-- ELSE -->[[global:follow]]<!-- ENDIF isFollowing -->">
|
||||
<span>
|
||||
<span class="s1"></span>
|
||||
<span class="s2"></span>
|
||||
<span class="s3"></span>
|
||||
</span>
|
||||
</button>
|
||||
<!-- ENDIF !isSelf -->
|
||||
<!-- ENDIF loggedIn -->
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<!-- IMPORT partials/account/menu.tpl -->
|
||||
|
||||
<!-- IF allowCoverPicture -->
|
||||
<!-- IF canEdit -->
|
||||
<div class="controls">
|
||||
<span class="upload"><i class="fa fa-fw fa-4x fa-upload"></i></span>
|
||||
<span class="resize"><i class="fa fa-fw fa-4x fa-arrows"></i></span>
|
||||
<span class="remove"><i class="fa fa-fw fa-4x fa-times"></i></span>
|
||||
</div>
|
||||
<div class="save">[[groups:cover-save]] <i class="fa fa-fw fa-floppy-o"></i></div>
|
||||
<div class="indicator">[[groups:cover-saving]] <i class="fa fa-fw fa-refresh fa-spin"></i></div>
|
||||
<!-- ENDIF canEdit -->
|
||||
<!-- ENDIF allowCoverPicture -->
|
||||
</div>
|
||||
</div>
|
101
templates/partials/account/menu.tpl
Normal file
101
templates/partials/account/menu.tpl
Normal file
|
@ -0,0 +1,101 @@
|
|||
<div class="btn-group account-fab bottom-sheet">
|
||||
<button type="button" class="persona-fab dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fa fa-ellipsis-v"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end account-sub-links">
|
||||
<!-- IF loggedIn -->
|
||||
<!-- IF !isSelf -->
|
||||
<!-- IF !banned -->
|
||||
<!-- IF !config.disableChat -->
|
||||
<li class="<!-- IF !hasPrivateChat -->hidden<!-- ENDIF !hasPrivateChat -->">
|
||||
<a class="dropdown-item" component="account/chat" href="#">[[user:chat_with, {username}]]</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" component="account/new-chat" href="#">[[user:new_chat_with, {username}]]</a>
|
||||
</li>
|
||||
<!-- ENDIF !config.disableChat -->
|
||||
<li>
|
||||
<a class="dropdown-item" component="account/flag" href="#">[[user:flag-profile]]</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" component="account/block" href="#"><!-- IF !../isBlocked -->[[user:block_user]]<!-- ELSE -->[[user:unblock_user]]<!-- END --></a>
|
||||
</li>
|
||||
<li role="separator" class="dropdown-divider"></li>
|
||||
<!-- ENDIF !banned -->
|
||||
<!-- ENDIF !isSelf -->
|
||||
<!-- ENDIF loggedIn -->
|
||||
<li>
|
||||
<a class="dropdown-item" href="{config.relative_path}/user/{userslug}" class="d-inline-block" id="profile">[[user:profile]]</a>
|
||||
</li>
|
||||
<!-- IF canEdit -->
|
||||
<li><a class="dropdown-item" href="{config.relative_path}/user/{userslug}/edit">[[user:edit]]</a></li>
|
||||
<li><a class="dropdown-item" href="{config.relative_path}/user/{userslug}/settings">[[user:settings]]</a></li>
|
||||
<!-- ENDIF canEdit -->
|
||||
|
||||
<!-- IF !isSelf -->
|
||||
{{{ if (canBan || canMute) }}}
|
||||
<li role="separator" class="dropdown-divider"></li>
|
||||
<li class="dropdown-header">[[user:admin_actions_label]]</li>
|
||||
{{{ end }}}
|
||||
{{{ if canBan }}}
|
||||
<li class="<!-- IF banned -->hide<!-- ENDIF banned -->">
|
||||
<a class="dropdown-item" component="account/ban" href="#">[[user:ban_account]]</a>
|
||||
</li>
|
||||
<li class="<!-- IF !banned -->hide<!-- ENDIF !banned -->">
|
||||
<a class="dropdown-item" component="account/unban" href="#">[[user:unban_account]]</a>
|
||||
</li>
|
||||
{{{ end }}}
|
||||
{{{ if canMute }}}
|
||||
<li class="<!-- IF muted -->hide<!-- ENDIF muted -->">
|
||||
<a class="dropdown-item" component="account/mute" href="#">[[user:mute_account]]</a>
|
||||
</li>
|
||||
<li class="<!-- IF !muted -->hide<!-- ENDIF !muted -->">
|
||||
<a class="dropdown-item" component="account/unmute" href="#">[[user:unmute_account]]</a>
|
||||
</li>
|
||||
{{{ end }}}
|
||||
<!-- IF isAdmin -->
|
||||
<li>
|
||||
<a component="account/delete-account" href="#" class="dropdown-item">[[user:delete_account_as_admin]]</a>
|
||||
<a component="account/delete-content" href="#" class="dropdown-item">[[user:delete_content]]</a>
|
||||
<a component="account/delete-all" href="#" class="dropdown-item">[[user:delete_all]]</a>
|
||||
</li>
|
||||
<!-- ENDIF isAdmin -->
|
||||
<!-- ENDIF !isSelf -->
|
||||
|
||||
<li role="separator" class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/following">[[user:following]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.following}">{counts.following}</span></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/followers">[[user:followers]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.followers}">{counts.followers}</span></a></li>
|
||||
<!-- IF canEdit -->
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/blocks">[[user:blocks]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.blocks}">{counts.blocks}</span></a></li>
|
||||
<!-- ENDIF canEdit -->
|
||||
<li role="separator" class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/topics">[[global:topics]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.topics}">{counts.topics}</span></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/posts">[[global:posts]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.posts}">{counts.posts}</span></a></li>
|
||||
<!-- IF !reputation:disabled -->
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/best">[[global:best]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.best}">{counts.best}</span></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/controversial">[[global:controversial]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.controversial}">{counts.controversial}</span></a></li>
|
||||
<!-- ENDIF !reputation:disabled -->
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/groups">[[global:header.groups]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.groups}">{counts.groups}</span></a></li>
|
||||
|
||||
<!-- IF canEdit -->
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/categories">[[user:watched_categories]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.categoriesWatched}">{counts.categoriesWatched}</span></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/bookmarks">[[user:bookmarks]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.bookmarks}">{counts.bookmarks}</span></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/watched">[[user:watched]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.watched}">{counts.watched}</span></a></li>
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/ignored">[[user:ignored]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.ignored}">{counts.ignored}</span></a></li>
|
||||
<!-- IF !reputation:disabled -->
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/upvoted">[[global:upvoted]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.upvoted}">{counts.upvoted}</span></a></li>
|
||||
<!-- IF !downvote:disabled -->
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/downvoted">[[global:downvoted]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.downvoted}">{counts.downvoted}</span></a></li>
|
||||
<!-- ENDIF !downvote:disabled -->
|
||||
<!-- ENDIF !reputation:disabled -->
|
||||
<li><a class="dropdown-item d-flex justify-content-between align-items-center" href="{config.relative_path}/user/{userslug}/uploads">[[global:uploads]] <span class="badge bg-secondary formatted-number rounded-pill ms-2" title="{counts.uploaded}">{counts.uploaded}</span></a></li>
|
||||
<!-- ENDIF canEdit -->
|
||||
|
||||
{{{each profile_links}}}
|
||||
<!-- IF @first -->
|
||||
<li role="separator" class="dropdown-divider"></li>
|
||||
<!-- ENDIF @first -->
|
||||
<li id="{profile_links.id}" class="plugin-link <!-- IF profile_links.public -->public<!-- ELSE -->private<!-- ENDIF profile_links.public -->"><a class="dropdown-item" href="{config.relative_path}/user/{userslug}/{profile_links.route}"><!-- IF ../icon --><i class="fa fa-fw {profile_links.icon}"></i> <!-- END -->{profile_links.name}</a></li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
18
templates/partials/breadcrumbs.tpl
Normal file
18
templates/partials/breadcrumbs.tpl
Normal file
|
@ -0,0 +1,18 @@
|
|||
<!-- IF breadcrumbs.length -->
|
||||
<ol class="breadcrumb" itemscope="itemscope" itemprop="breadcrumb" itemtype="http://schema.org/BreadcrumbList">
|
||||
{{{each breadcrumbs}}}
|
||||
<li<!-- IF @last --> component="breadcrumb/current"<!-- ENDIF @last --> itemscope="itemscope" itemprop="itemListElement" itemtype="http://schema.org/ListItem" class="breadcrumb-item <!-- IF @last -->active<!-- ENDIF @last -->">
|
||||
<meta itemprop="position" content="{@index}" />
|
||||
{{{ if ./url }}}<a href="{breadcrumbs.url}" itemprop="item">{{{ end }}}
|
||||
<span itemprop="name">
|
||||
{breadcrumbs.text}
|
||||
<!-- IF @last -->
|
||||
<!-- IF !feeds:disableRSS -->
|
||||
<!-- IF rssFeedUrl --><a target="_blank" href="{rssFeedUrl}" itemprop="item"><i class="fa fa-rss-square"></i></a><!-- ENDIF rssFeedUrl --><!-- ENDIF !feeds:disableRSS -->
|
||||
<!-- ENDIF @last -->
|
||||
</span>
|
||||
{{{ if ./url }}}</a>{{{ end }}}
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ol>
|
||||
<!-- ENDIF breadcrumbs.length -->
|
22
templates/partials/buttons/newTopic.tpl
Normal file
22
templates/partials/buttons/newTopic.tpl
Normal file
|
@ -0,0 +1,22 @@
|
|||
<noscript><div class="dropdown" component="category-selector"></noscript>
|
||||
<button component="category/post" for="category-dropdown-check" class="btn btn-primary text-nowrap" id="new_topic" role="button">
|
||||
[[category:new_topic_button]]
|
||||
</button>
|
||||
<noscript>
|
||||
<input type="checkbox" class="hidden" id="category-dropdown-check" aria-hidden="true">
|
||||
<ul component="category/list" class="dropdown-menu category-dropdown-menu" role="menu">
|
||||
{{{each categories}}}
|
||||
<li role="presentation" class="category {{{if categories.disabledClass}}}disabled{{{end}}}">
|
||||
<a role="menu-item" href="{config.relative_path}/compose?cid={categories.cid}">{categories.level}
|
||||
<span component="category-markup">
|
||||
<div class="category-item d-inline-block">
|
||||
{buildCategoryIcon(@value, "24px", "rounded-circle")}
|
||||
{categories.name}
|
||||
</div>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
||||
</noscript>
|
60
templates/partials/categories/item.tpl
Normal file
60
templates/partials/categories/item.tpl
Normal file
|
@ -0,0 +1,60 @@
|
|||
<li component="categories/category" data-cid="{../cid}" data-numRecentReplies="1" class="row clearfix category-{../cid}">
|
||||
<meta itemprop="name" content="{../name}">
|
||||
|
||||
<div class="content col-12 <!-- IF config.hideCategoryLastPost -->col-md-10 col-sm-12<!-- ELSE -->col-md-7 col-sm-9<!-- ENDIF config.hideCategoryLastPost -->">
|
||||
<div class="float-start">
|
||||
{buildCategoryIcon(@value, "48px", "rounded-circle")}
|
||||
</div>
|
||||
<h2 class="title">
|
||||
<!-- IMPORT partials/categories/link.tpl -->
|
||||
</h2>
|
||||
<div>
|
||||
<!-- IF ../descriptionParsed -->
|
||||
<div class="description text-muted">
|
||||
{../descriptionParsed}
|
||||
</div>
|
||||
<!-- ENDIF ../descriptionParsed -->
|
||||
<!-- IF !config.hideSubCategories -->
|
||||
{{{ if ../children.length }}}
|
||||
<div class="category-children">
|
||||
{{{ each ../children }}}
|
||||
{{{ if !../isSection }}}
|
||||
<span class="category-children-item">
|
||||
{buildCategoryIcon(@value, "24px", "rounded-circle")}
|
||||
{{{ if ../link }}}
|
||||
<a href="{../link}">{../name}</a>
|
||||
{{{ else }}}
|
||||
<a href="{config.relative_path}/category/{../slug}">{../name}</a>
|
||||
{{{ end }}}
|
||||
</span>
|
||||
{{{ end }}}
|
||||
{{{ end }}}
|
||||
</div>
|
||||
{{{ end }}}
|
||||
<!-- ENDIF !config.hideSubCategories -->
|
||||
</div>
|
||||
<span class="d-block d-sm-none float-end">
|
||||
<!-- IF ../teaser.timestampISO -->
|
||||
<a class="permalink" href="{../teaser.url}">
|
||||
<small class="timeago" title="{../teaser.timestampISO}"></small>
|
||||
</a>
|
||||
<!-- ENDIF ../teaser.timestampISO -->
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- IF !../link -->
|
||||
<div class="col-md-1 d-none d-md-block stats text-muted">
|
||||
<span class="{../unread-class} human-readable-number" title="{../totalTopicCount}">{../totalTopicCount}</span><br />
|
||||
<small>[[global:topics]]</small>
|
||||
</div>
|
||||
<div class="col-md-1 d-none d-md-block stats text-muted">
|
||||
<span class="{../unread-class} human-readable-number" title="{../totalPostCount}">{../totalPostCount}</span><br />
|
||||
<small>[[global:posts]]</small>
|
||||
</div>
|
||||
<!-- IF !config.hideCategoryLastPost -->
|
||||
<div class="col-md-3 col-sm-3 teaser d-none d-sm-block" component="topic/teaser">
|
||||
<!-- IMPORT partials/categories/lastpost.tpl -->
|
||||
</div>
|
||||
<!-- ENDIF !config.hideCategoryLastPost -->
|
||||
<!-- ENDIF !../link -->
|
||||
</li>
|
26
templates/partials/categories/lastpost.tpl
Normal file
26
templates/partials/categories/lastpost.tpl
Normal file
|
@ -0,0 +1,26 @@
|
|||
<div class="lastpost background-link-container" style="border-color: {../bgColor}">
|
||||
{{{each ./posts}}}
|
||||
<!-- IF @first -->
|
||||
<div component="category/posts">
|
||||
<a class="background-link" href="{config.relative_path}/topic/{../topic.slug}<!-- IF ../index -->/{../index}<!-- ENDIF ../index -->"></a>
|
||||
<p>
|
||||
<a href="{config.relative_path}/user/{../user.userslug}">{buildAvatar(posts.user, "24px", true)}</a>
|
||||
<a class="permalink text-muted" href="{config.relative_path}/topic/{../topic.slug}<!-- IF ../index -->/{../index}<!-- ENDIF ../index -->">
|
||||
<small class="timeago" title="{../timestampISO}"></small>
|
||||
</a>
|
||||
</p>
|
||||
<div class="post-content">
|
||||
{../content}
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF @first -->
|
||||
{{{end}}}
|
||||
|
||||
<!-- IF !../posts.length -->
|
||||
<div component="category/posts">
|
||||
<div class="post-content">
|
||||
[[category:no_new_posts]]
|
||||
</div>
|
||||
</div>
|
||||
<!-- ENDIF !../posts.length -->
|
||||
</div>
|
11
templates/partials/categories/link.tpl
Normal file
11
templates/partials/categories/link.tpl
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!-- IF ../isSection -->
|
||||
{../name}
|
||||
<!-- ELSE -->
|
||||
<!-- IF ../link -->
|
||||
<a href="{../link}" itemprop="url">
|
||||
<!-- ELSE -->
|
||||
<a href="{config.relative_path}/category/{../slug}" itemprop="url">
|
||||
<!-- ENDIF ../link -->
|
||||
{../name}
|
||||
</a>
|
||||
<!-- ENDIF ../isSection -->
|
29
templates/partials/category-filter-content.tpl
Normal file
29
templates/partials/category-filter-content.tpl
Normal file
|
@ -0,0 +1,29 @@
|
|||
<button type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown">
|
||||
{{{ if selectedCategory }}}
|
||||
<span class="category-item">
|
||||
{buildCategoryIcon(selectedCategory, "24px", "rounded-circle")}
|
||||
<span class="visible-sm-inline visible-md-inline visible-lg-inline">{selectedCategory.name}</span>
|
||||
</span>
|
||||
{{{ else }}}
|
||||
<span class="visible-sm-inline visible-md-inline visible-lg-inline">[[unread:all_categories]]</span><span class="visible-xs-inline"><i class="fa fa-fw fa-list"></i></span>{{{ end }}} <span class="caret"></span>
|
||||
</button>
|
||||
<div component="category-selector-search" class="hidden position-absolute">
|
||||
<input type="text" class="form-control" autocomplete="off">
|
||||
</div>
|
||||
<ul component="category/list" class="dropdown-menu category-dropdown-menu" role="menu">
|
||||
<li role="presentation" class="category" data-all="all">
|
||||
<a class="dropdown-item" role="menu-item" href="{config.relative_path}/{allCategoriesUrl}"><i component="category/select/icon" class="fa fa-fw fa-check {{{if selectedCategory}}}invisible{{{end}}}"></i> [[unread:all_categories]]</a>
|
||||
</li>
|
||||
{{{each categoryItems}}}
|
||||
<li role="presentation" class="category {{{ if ../disabledClass }}}disabled{{{ end }}}" data-cid="{../cid}" data-parent-cid="{../parentCid}" data-name="{../name}">
|
||||
<a class="dropdown-item" role="menu-item" href="#">{../level}<i component="category/select/icon" class="fa fa-fw fa-check {{{ if !../selected }}}invisible{{{ end }}}"></i>
|
||||
<span component="category-markup" style="{{{ if ../match }}}font-weight: bold;{{{end}}}">
|
||||
<div class="category-item d-inline-block">
|
||||
{buildCategoryIcon(@value, "24px", "rounded-circle")}
|
||||
{./name}
|
||||
</div>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
3
templates/partials/category-filter-right.tpl
Normal file
3
templates/partials/category-filter-right.tpl
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div component="category/dropdown" class="btn-group right category-dropdown-container bottom-sheet">
|
||||
<!-- IMPORT partials/category-filter-content.tpl -->
|
||||
</div>
|
3
templates/partials/category-filter.tpl
Normal file
3
templates/partials/category-filter.tpl
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div component="category/dropdown" class="btn-group category-dropdown-container bottom-sheet">
|
||||
<!-- IMPORT partials/category-filter-content.tpl -->
|
||||
</div>
|
33
templates/partials/category-selector-content.tpl
Normal file
33
templates/partials/category-selector-content.tpl
Normal file
|
@ -0,0 +1,33 @@
|
|||
<button type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown">
|
||||
<span component="category-selector-selected">
|
||||
{{{ if (selectedCategory && !showCategorySelectLabel) }}}
|
||||
<span class="category-item">
|
||||
{buildCategoryIcon(selectedCategory, "24px", "rounded-circle")}
|
||||
{selectedCategory.name}
|
||||
</span>
|
||||
{{{ else }}}
|
||||
<span class="visible-sm-inline visible-md-inline visible-lg-inline">{{{ if selectCategoryLabel }}}{selectCategoryLabel}{{{ else }}}[[topic:thread_tools.select_category]]{{{ end }}}</span><span class="visible-xs-inline"><i class="fa fa-fw {{{ if selectCategoryIcon }}}{selectCategoryIcon}{{{ else }}}fa-list{{{ end }}}"></i></span>
|
||||
{{{ end }}}</span> <span class="caret"></span>
|
||||
</button>
|
||||
<div component="category-selector-search" class="hidden position-absolute">
|
||||
<input type="text" class="form-control" autocomplete="off">
|
||||
</div>
|
||||
<ul component="category/list" class="dropdown-menu category-dropdown-menu" role="menu">
|
||||
<li component="category/no-matches" role="presentation" class="category hidden">
|
||||
<a class="dropdown-item" role="menu-item">[[search:no-matches]]</a>
|
||||
</li>
|
||||
{{{each categoryItems}}}
|
||||
<li role="presentation" class="category {{{ if ../disabledClass }}}disabled {{{ end }}}" data-cid="{../cid}" data-name="{../name}" data-parent-cid="{../parentCid}">
|
||||
<a class="dropdown-item" role="menu-item">{../level}
|
||||
<span component="category-markup" style="{{{ if ../match }}}font-weight: bold;{{{end}}}">
|
||||
<div class="category-item d-inline-block">
|
||||
{{{ if ./icon }}}
|
||||
{buildCategoryIcon(@value, "24px", "rounded-circle")}
|
||||
{{{ end }}}
|
||||
{./name}
|
||||
</div>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{{{ end }}}
|
||||
</ul>
|
3
templates/partials/category-selector-right.tpl
Normal file
3
templates/partials/category-selector-right.tpl
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div component="category-selector" class="btn-group right category-dropdown-container bottom-sheet">
|
||||
<!-- IMPORT partials/category-selector-content.tpl -->
|
||||
</div>
|
3
templates/partials/category-selector.tpl
Normal file
3
templates/partials/category-selector.tpl
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div component="category-selector" class="btn-group bottom-sheet">
|
||||
<!-- IMPORT partials/category-selector-content.tpl -->
|
||||
</div>
|
15
templates/partials/category/sort.tpl
Normal file
15
templates/partials/category/sort.tpl
Normal file
|
@ -0,0 +1,15 @@
|
|||
<div class="btn-group bottom-sheet" component="thread/sort">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" type="button">
|
||||
<span class="visible-sm-inline visible-md-inline visible-lg-inline">[[topic:sort_by]]</span>
|
||||
<span class="visible-xs-inline"><i class="fa fa-fw fa-sort"></i></span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item" href="#" class="newest_to_oldest" data-sort="newest_to_oldest"><i class="fa fa-fw"></i> [[topic:newest_to_oldest]]</a></li>
|
||||
<li><a class="dropdown-item" href="#" class="oldest_to_newest" data-sort="oldest_to_newest"><i class="fa fa-fw"></i> [[topic:oldest_to_newest]]</a></li>
|
||||
<li><a class="dropdown-item" href="#" class="most_posts" data-sort="most_posts"><i class="fa fa-fw"></i> [[topic:most_posts]]</a></li>
|
||||
<li><a class="dropdown-item" href="#" class="most_votes" data-sort="most_votes"><i class="fa fa-fw"></i> [[topic:most_votes]]</a></li>
|
||||
<li><a class="dropdown-item" href="#" class="most_views" data-sort="most_views"><i class="fa fa-fw"></i> [[topic:most_views]]</a></li>
|
||||
</ul>
|
||||
</div>
|
18
templates/partials/category/subcategory.tpl
Normal file
18
templates/partials/category/subcategory.tpl
Normal file
|
@ -0,0 +1,18 @@
|
|||
{{{ if children.length }}}
|
||||
<div class="subcategory">
|
||||
{{{ if hasMoreSubCategories }}}
|
||||
<div class="mb-2"><!-- IMPORT partials/category-selector.tpl --></div>
|
||||
{{{ else }}}
|
||||
<p>[[category:subcategories]]</p>
|
||||
{{{ end }}}
|
||||
|
||||
<ul component="category/subcategory/container" class="categories list-unstyled" itemscope itemtype="http://www.schema.org/ItemList">
|
||||
{{{each children}}}
|
||||
<!-- IMPORT partials/categories/item.tpl -->
|
||||
{{{end}}}
|
||||
</ul>
|
||||
{{{ if hasMoreSubCategories}}}
|
||||
<button class="btn btn-outline-secondary mb-2" component="category/load-more-subcategories">[[category:x-more-categories, {subCategoriesLeft}]]</button>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
{{{ end }}}
|
3
templates/partials/category/tags.tpl
Normal file
3
templates/partials/category/tags.tpl
Normal file
|
@ -0,0 +1,3 @@
|
|||
{{{ each tags }}}
|
||||
<a href="{config.relative_path}/tags/{topics.tags.value}"><span class="tag-item" data-tag="{topics.tags.value}">{topics.tags.value}</span><span class="tag-topic-count human-readable-number" title="{topics.tags.score}">{topics.tags.score}</span></a>
|
||||
{{{ end }}}
|
81
templates/partials/category/tools.tpl
Normal file
81
templates/partials/category/tools.tpl
Normal file
|
@ -0,0 +1,81 @@
|
|||
<!-- IF showTopicTools -->
|
||||
<div class="btn-group thread-tools bottom-sheet">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" type="button">
|
||||
<span class="visible-sm-inline visible-md-inline visible-lg-inline">[[topic:thread_tools.title]]</span>
|
||||
<span class="visible-xs-inline"><i class="fa fa-fw fa-gear"></i></span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
<a component="topic/mark-unread-for-all" href="#" class="dropdown-item">
|
||||
<i class="fa fa-fw fa-inbox"></i> [[topic:thread_tools.markAsUnreadForAll]]
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a component="topic/pin" href="#" class="dropdown-item">
|
||||
<i class="fa fa-fw fa-thumb-tack"></i> [[topic:thread_tools.pin]]
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a component="topic/unpin" href="#" class="hidden dropdown-item">
|
||||
<i class="fa fa-fw fa-thumb-tack fa-rotate-90"></i> [[topic:thread_tools.unpin]]
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a component="topic/lock" href="#" class="dropdown-item">
|
||||
<i class="fa fa-fw fa-lock"></i> [[topic:thread_tools.lock]]
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a component="topic/unlock" href="#" class="hidden dropdown-item" >
|
||||
<i class="fa fa-fw fa-unlock"></i> [[topic:thread_tools.unlock]]
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="dropdown-divider"></li>
|
||||
|
||||
<li>
|
||||
<a component="topic/move" href="#" class="dropdown-item">
|
||||
<i class="fa fa-fw fa-arrows"></i> [[topic:thread_tools.move]]
|
||||
</a>
|
||||
</li>
|
||||
{{{if template.category}}}
|
||||
<li>
|
||||
<a component="topic/move-all" href="#" class="dropdown-item">
|
||||
<i class="fa fa-fw fa-arrows"></i> [[topic:thread_tools.move_all]]
|
||||
</a>
|
||||
</li>
|
||||
{{{end}}}
|
||||
<li>
|
||||
<a component="topic/merge" href="#" class="dropdown-item">
|
||||
<i class="fa fa-fw fa-code-fork"></i> [[topic:thread_tools.merge]]
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="dropdown-divider"></li>
|
||||
|
||||
<li>
|
||||
<a component="topic/delete" href="#" class="dropdown-item">
|
||||
<i class="fa fa-fw fa-trash-o"></i> [[topic:thread_tools.delete]]
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a component="topic/restore" href="#" class="hidden dropdown-item">
|
||||
<i class="fa fa-fw fa-history"></i> [[topic:thread_tools.restore]]
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a component="topic/purge" href="#" class="hidden dropdown-item">
|
||||
<i class="fa fa-fw fa-eraser"></i> [[topic:thread_tools.purge]]
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{{{each thread_tools}}}
|
||||
<li>
|
||||
<a href="#" class="dropdown-item {thread_tools.class}"><i class="fa fa-fw {thread_tools.icon}"></i> {thread_tools.title}</a>
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
</div>
|
||||
<!-- ENDIF showTopicTools -->
|
21
templates/partials/category/watch.tpl
Normal file
21
templates/partials/category/watch.tpl
Normal file
|
@ -0,0 +1,21 @@
|
|||
<!-- IF config.loggedIn -->
|
||||
<div class="btn-group topic-watch-dropdown bottom-sheet" component="topic/watch">
|
||||
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" type="button">
|
||||
<span component="category/watching/menu" <!-- IF !../isWatched -->class="hidden"<!-- ENDIF !../isWatched -->><i class="fa fa-fw fa-inbox"></i><span class="visible-sm-inline visible-md-inline visible-lg-inline"> [[category:watching]]</span></span>
|
||||
|
||||
<span component="category/notwatching/menu" <!-- IF !../isNotWatched -->class="hidden"<!-- ENDIF !../isNotWatched -->><i class="fa fa-fw fa-clock-o"></i><span class="visible-sm-inline visible-md-inline visible-lg-inline"> [[category:not-watching]]</span></span>
|
||||
|
||||
<span component="category/ignoring/menu" <!-- IF !../isIgnored -->class="hidden"<!-- ENDIF !../isIgnored -->><i class="fa fa-fw fa-eye-slash"></i><span class="visible-sm-inline visible-md-inline visible-lg-inline"> [[category:ignoring]]</span></span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item" href="#" component="category/watching" data-state="watching"><i component="category/watching/check" class="fa fa-fw <!-- IF ../isWatched -->fa-check<!-- ENDIF ../isWatched -->"></i><i class="fa fa-fw fa-inbox"></i> [[category:watching]]<p class="help-text"><small>[[category:watching.description]]</small></p></a></li>
|
||||
|
||||
<li><a class="dropdown-item" href="#" component="category/notwatching" data-state="notwatching"><i component="category/notwatching/check" class="fa fa-fw <!-- IF ../isNotWatched -->fa-check<!-- ENDIF ../isNotWatched -->"></i><i class="fa fa-fw fa-clock-o"></i> [[category:not-watching]]<p class="help-text"><small>[[category:not-watching.description]]</small></p></a></li>
|
||||
|
||||
<li><a class="dropdown-item" href="#" component="category/ignoring" data-state="ignoring"><i component="category/ignoring/check" class="fa fa-fw <!-- IF ../isIgnored -->fa-check<!-- ENDIF ../isIgnored -->"></i><i class="fa fa-fw fa-eye-slash"></i> [[category:ignoring]]<p class="help-text"><small>[[category:ignoring.description]]</small></p></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- ENDIF config.loggedIn -->
|
41
templates/partials/chats-menu.tpl
Normal file
41
templates/partials/chats-menu.tpl
Normal file
|
@ -0,0 +1,41 @@
|
|||
{{{ if config.loggedIn }}}
|
||||
<ul class="nav nav-pills">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#" data-bs-target="#notifications" data-bs-toggle="tab"><span class="counter unread-count" component="notifications/icon" data-content="{unreadCount.notification}"></span> <i class="fa fa-fw fa-bell"></i></a>
|
||||
</li>
|
||||
{{{ if !config.disableChat }}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#" data-bs-target="#chats" data-bs-toggle="tab"><i class="counter unread-count" component="chat/icon" data-content="{unreadCount.chat}"></i> <i class="fa fa-fw fa-comment"></i></a>
|
||||
</li>
|
||||
{{{ end }}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#" data-bs-target="#profile" data-bs-toggle="tab">
|
||||
{buildAvatar(user, "24px", true, "user-icon")}
|
||||
<i component="user/status" class="fa fa-fw fa-circle status {user.status}"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade show active" id="profile">
|
||||
<section class="menu-section" data-section="profile">
|
||||
<ul class="menu-section-list dropdown-menu show text-bg-dark w-100 border-0" component="header/usercontrol"></ul>
|
||||
</section>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="notifications">
|
||||
<section class="menu-section text-bg-dark" data-section="notifications">
|
||||
<ul class="menu-section-list notification-list-mobile" component="notifications/list"></ul>
|
||||
<p class="menu-section-list"><a href="{relative_path}/notifications">[[notifications:see_all]]</a></p>
|
||||
</section>
|
||||
</div>
|
||||
{{{ if !config.disableChat }}}
|
||||
<div class="tab-pane fade" id="chats">
|
||||
<section class="menu-section text-bg-dark" data-section="chats">
|
||||
<ul class="menu-section-list chat-list" component="chat/list">
|
||||
<a class="navigation-link" href="{relative_path}/user/{user.userslug}/chats">[[modules:chat.see_all]]</a>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
{{{ end }}}
|
38
templates/partials/chats/dropdown.tpl
Normal file
38
templates/partials/chats/dropdown.tpl
Normal file
|
@ -0,0 +1,38 @@
|
|||
<!-- IF rooms.length -->
|
||||
{{{each rooms}}}
|
||||
<li class="<!-- IF ../unread -->unread<!-- ENDIF ../unread -->" data-roomid="{rooms.roomId}">
|
||||
{{{each rooms.users}}}
|
||||
<!-- IF @first -->
|
||||
<div class="main-avatar">
|
||||
<!-- IMPORT partials/chats/user.tpl -->
|
||||
</div>
|
||||
<!-- ENDIF @first -->
|
||||
{{{end}}}
|
||||
|
||||
<ul class="members">
|
||||
{{{each rooms.users}}}
|
||||
<li>
|
||||
<!-- IMPORT partials/chats/user.tpl -->
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
|
||||
<div class="notification-chat-content">
|
||||
<strong class="room-name">
|
||||
<!-- IF !rooms.lastUser.uid -->
|
||||
<span>[[modules:chat.no-users-in-room]]</span>
|
||||
<!-- ELSE -->
|
||||
<!-- IF rooms.roomName -->{rooms.roomName}<!-- ELSE -->{rooms.usernames}<!-- ENDIF rooms.roomName -->
|
||||
<!-- ENDIF !rooms.lastUser.uid -->
|
||||
</strong>
|
||||
<span class="teaser-content">
|
||||
<strong class="teaser-username">{rooms.teaser.user.username}:</strong>
|
||||
{rooms.teaser.content}
|
||||
</span>
|
||||
</div>
|
||||
<div class="teaser-timestamp notification-chat-controls">{rooms.teaser.timeago}</div>
|
||||
</li>
|
||||
{{{end}}}
|
||||
<!-- ELSE -->
|
||||
<li class="no_active"><a href="#">[[modules:chat.no_active]]</a></li>
|
||||
<!-- ENDIF rooms.length -->
|
34
templates/partials/chats/message-window.tpl
Normal file
34
templates/partials/chats/message-window.tpl
Normal file
|
@ -0,0 +1,34 @@
|
|||
<!-- IF roomId -->
|
||||
<div component="chat/messages" class="expanded-chat" data-roomid="{roomId}">
|
||||
<div component="chat/header" class="d-flex align-items-center px-3">
|
||||
<span class="members flex-grow-1">
|
||||
[[modules:chat.chatting_with]]:
|
||||
{{{each users}}}
|
||||
<a href="{config.relative_path}/uid/{../uid}">{../username}</a><!-- IF !@last -->,<!-- END -->
|
||||
{{{end}}}
|
||||
</span>
|
||||
|
||||
<button type="button" class="btn btn-link d-none d-md-block p-2 text-muted" data-action="pop-out" aria-hidden="true" aria-label="Pop Out"><i class="fa fa-compress"></i></button>
|
||||
<!-- IMPORT partials/chats/options.tpl -->
|
||||
<button type="button" class="btn-close" aria-hidden="true" aria-label="Close" data-action="close"></button>
|
||||
</div>
|
||||
<div class="position-relative">
|
||||
<div component="chat/messages/scroll-up-alert" class="position-absolute scroll-up-alert alert alert-info hidden w-100" role="button" style="z-index: 1;">[[modules:chat.scroll-up-alert]]</div>
|
||||
</div>
|
||||
<ul class="chat-content">
|
||||
<!-- IMPORT partials/chats/messages.tpl -->
|
||||
</ul>
|
||||
<div component="chat/composer">
|
||||
<textarea component="chat/input" placeholder="[[modules:chat.placeholder]]" class="form-control chat-input mousetrap" rows="2"></textarea>
|
||||
<button class="btn btn-primary" type="button" data-action="send"><i class="fa fa-fw fa-2x fa-paper-plane"></i></button>
|
||||
<span component="chat/message/remaining">{maximumChatMessageLength}</span>
|
||||
<form component="chat/upload" method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="files[]" multiple class="hidden"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ELSE -->
|
||||
<div class="alert alert-info me-3">
|
||||
[[modules:chat.no-messages]]
|
||||
</div>
|
||||
<!-- ENDIF roomId -->
|
34
templates/partials/chats/message.tpl
Normal file
34
templates/partials/chats/message.tpl
Normal file
|
@ -0,0 +1,34 @@
|
|||
<li component="chat/message" class="chat-message mx-2 pe-2 fw-light clear<!-- IF ../deleted --> deleted<!-- END -->" data-index="{messages.index}" data-mid="{messages.messageId}" data-uid="{messages.fromuid}" data-self="{messages.self}" data-break="{messages.newSet}" data-timestamp="{messages.timestamp}">
|
||||
<div class="message-header">
|
||||
<a href="{config.relative_path}/user/{messages.fromUser.userslug}">{buildAvatar(messages.fromUser, "32px", true, "not-responsive")}</a>
|
||||
<span class="chat-user fw-bold"><a href="{config.relative_path}/user/{messages.fromUser.userslug}">{messages.fromUser.displayname}</a></span>
|
||||
<!-- IF ../fromUser.banned -->
|
||||
<span class="badge bg-danger">[[user:banned]]</span>
|
||||
<!-- END -->
|
||||
<!-- IF ../fromUser.deleted -->
|
||||
<span class="badge bg-danger">[[user:deleted]]</span>
|
||||
<!-- END -->
|
||||
<small class="chat-timestamp text-muted ms-2 timeago" title="{messages.timestampISO}"></small>
|
||||
<!-- IF messages.edited -->
|
||||
<div class="text-muted float-end" title="[[global:edited]] {messages.editedISO}"><i class="fa fa-edit"></i></span></div>
|
||||
<!-- ENDIF messages.edited -->
|
||||
</div>
|
||||
<div class="message-body-wrapper">
|
||||
<div component="chat/message/body" class="message-body">
|
||||
{messages.content}
|
||||
</div>
|
||||
|
||||
<!-- IF !config.disableChatMessageEditing -->
|
||||
<!-- IF messages.self -->
|
||||
<div class="btn-group controls">
|
||||
<button class="btn btn-sm btn-link" data-action="edit"><i class="fa fa-pencil"></i></button>
|
||||
<button class="btn btn-sm btn-link" data-action="delete"><i class="fa fa-times"></i></button>
|
||||
<button class="btn btn-sm btn-link" data-action="restore"><i class="fa fa-repeat"></i></button>
|
||||
<!-- IF isAdminOrGlobalMod -->
|
||||
<button class="btn btn-sm btn-link chat-ip" title="[[modules:chat.show-ip]]"><i class="fa fa-info-circle chat-ip-button"></i></button>
|
||||
<!-- ENDIF isAdminOrGlobalMod -->
|
||||
</div>
|
||||
<!-- ENDIF messages.self -->
|
||||
<!-- ENDIF !config.disableChatMessageEditing -->
|
||||
</div>
|
||||
</li>
|
7
templates/partials/chats/messages.tpl
Normal file
7
templates/partials/chats/messages.tpl
Normal file
|
@ -0,0 +1,7 @@
|
|||
{{{each messages}}}
|
||||
{{{ if !./system }}}
|
||||
<!-- IMPORT partials/chats/message.tpl -->
|
||||
{{{ else }}}
|
||||
<!-- IMPORT partials/chats/system-message.tpl -->
|
||||
{{{ end }}}
|
||||
{{{end}}}
|
24
templates/partials/chats/options.tpl
Normal file
24
templates/partials/chats/options.tpl
Normal file
|
@ -0,0 +1,24 @@
|
|||
<div class="dropdown">
|
||||
<button class="btn btn-link p-2 text-muted align-text-top" data-bs-toggle="dropdown" component="chat/controlsToggle"><i class="fa fa-gear"></i></button>
|
||||
<ul class="dropdown-menu dropdown-menu-end" component="chat/controls">
|
||||
<li class="dropdown-header">[[modules:chat.options]]</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="#" data-action="members"><i class="fa fa-fw fa-cog"></i> [[modules:chat.manage-room]]</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="#" data-action="rename"><i class="fa fa-fw fa-edit"></i> [[modules:chat.rename-room]]</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="#" data-action="leave"><i class="fa fa-fw fa-sign-out"></i> [[modules:chat.leave]]</a>
|
||||
</li>
|
||||
<!-- IF users.length -->
|
||||
<li role="separator" class="dropdown-divider"></li>
|
||||
<li class="dropdown-header">[[modules:chat.in-room]]</li>
|
||||
{{{each users}}}
|
||||
<li>
|
||||
<a class="dropdown-item" href="{config.relative_path}/uid/{../uid}">{buildAvatar(users, "24px", true)} {../username}</a>
|
||||
</li>
|
||||
{{{end}}}
|
||||
<!-- END -->
|
||||
</ul>
|
||||
</div>
|
31
templates/partials/chats/recent_room.tpl
Normal file
31
templates/partials/chats/recent_room.tpl
Normal file
|
@ -0,0 +1,31 @@
|
|||
<li component="chat/recent/room" data-roomid="{rooms.roomId}" class="<!-- IF rooms.unread -->unread<!-- ENDIF rooms.unread -->">
|
||||
{{{each rooms.users}}}
|
||||
<!-- IF @first -->
|
||||
<div class="main-avatar me-2">
|
||||
<!-- IMPORT partials/chats/user.tpl -->
|
||||
</div>
|
||||
<!-- ENDIF @first -->
|
||||
{{{end}}}
|
||||
|
||||
{{{ if rooms.users.length }}}
|
||||
<ul class="members">
|
||||
{{{each rooms.users}}}
|
||||
<li>
|
||||
<!-- IMPORT partials/chats/user.tpl -->
|
||||
</li>
|
||||
{{{end}}}
|
||||
</ul>
|
||||
{{{ end }}}
|
||||
|
||||
<div class="notification-chat-content flex-grow-1">
|
||||
<!-- IF !rooms.lastUser.uid -->
|
||||
<div class="p-3 text-center h-100">
|
||||
<span>[[modules:chat.no-users-in-room]]</span>
|
||||
</div>
|
||||
<!-- ELSE -->
|
||||
<strong class="room-name">
|
||||
<span component="chat/title"><!-- IF rooms.roomName -->{rooms.roomName}<!-- ELSE -->{rooms.usernames}<!-- ENDIF rooms.roomName --></span>
|
||||
</strong>
|
||||
<!-- ENDIF !rooms.lastUser.uid -->
|
||||
</div>
|
||||
</li>
|
3
templates/partials/chats/system-message.tpl
Normal file
3
templates/partials/chats/system-message.tpl
Normal file
|
@ -0,0 +1,3 @@
|
|||
<li component="chat/system-message" class="system-message fs-6 py-3 clear" data-index="{messages.index}" data-mid="{messages.messageId}" data-uid="{messages.fromuid}" data-self="{messages.self}" data-break="0" data-timestamp="{messages.timestamp}">
|
||||
[[modules:chat.system.{messages.content}, {messages.fromUser.username}]]
|
||||
</li>
|
1
templates/partials/chats/user.tpl
Normal file
1
templates/partials/chats/user.tpl
Normal file
|
@ -0,0 +1 @@
|
|||
<a href="{config.relative_path}/user/{rooms.users.userslug}">{buildAvatar(rooms.users, "28px", true)}</a>
|
4
templates/partials/cookie-consent.tpl
Normal file
4
templates/partials/cookie-consent.tpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
<div class="cookie-consent">
|
||||
<button class="float-end btn btn-primary">{dismiss}</button>
|
||||
{message} <a target="_blank" rel="noopener" href="{link_url}">{link}</a>
|
||||
</div>
|
97
templates/partials/flags/filters.tpl
Normal file
97
templates/partials/flags/filters.tpl
Normal file
|
@ -0,0 +1,97 @@
|
|||
<div class="text-center">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body collapse" id="flags-daily-wrapper" aria-expanded="false">
|
||||
<div><canvas id="flags:daily" height="150"></canvas></div>
|
||||
</div>
|
||||
<div class="card-footer" data-bs-toggle="collapse" data-bs-target="#flags-daily-wrapper" aria-controls="#flags-daily-wrapper"><small>[[flags:graph-label]]</small> <i class="fa fa-sort"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
[[flags:quick-filters]]
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li><a href="{config.relative_path}/flags?quick=mine">[[flags:filter-quick-mine]]</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
[[flags:filters]]
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form role="form" component="flags/filters">
|
||||
<fieldset>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="filter-cid">[[flags:filter-cid]]</label>
|
||||
<div class="input-group">
|
||||
<!-- IMPORT partials/category-filter.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="sort">[[flags:sort]]</label>
|
||||
<select class="form-control" id="sort" name="sort">
|
||||
<optgroup label="[[flags:sort-all]]">
|
||||
<option value="newest">[[flags:sort-newest]]</option>
|
||||
<option value="oldest">[[flags:sort-oldest]]</option>
|
||||
<option value="reports">[[flags:sort-reports]]</option>
|
||||
</optgroup>
|
||||
<optgroup label="[[flags:sort-posts-only]]">
|
||||
<option value="downvotes">[[flags:sort-downvotes]]</option>
|
||||
<option value="upvotes">[[flags:sort-upvotes]]</option>
|
||||
<option value="replies">[[flags:sort-replies]]</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="filter-state">[[flags:filter-state]]</label>
|
||||
<select class="form-control" id="filter-state" name="state">
|
||||
<option value="">[[flags:state-all]]</option>
|
||||
<option value="open">[[flags:state-open]]</option>
|
||||
<option value="wip">[[flags:state-wip]]</option>
|
||||
<option value="resolved">[[flags:state-resolved]]</option>
|
||||
<option value="rejected">[[flags:state-rejected]]</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="filter-type">[[flags:filter-type]]</label>
|
||||
<select class="form-control" id="filter-type" name="type">
|
||||
<option value="">[[flags:filter-type-all]]</option>
|
||||
<option value="post">[[flags:filter-type-post]]</option>
|
||||
<option value="user">[[flags:filter-type-user]]</option>
|
||||
</select>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="collapse{{{ if expanded }}} show{{{ end }}}" id="more-filters" aria-expanded="{expanded}">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="filter-assignee">[[flags:filter-assignee]]</label>
|
||||
<input type="text" class="form-control" id="filter-assignee" name="assignee" />
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="filter-targetUid">[[flags:filter-targetUid]]</label>
|
||||
<input type="text" class="form-control" id="filter-targetUid" name="targetUid" />
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="filter-reporterId">[[flags:filter-reporterId]]</label>
|
||||
<input type="text" class="form-control" id="filter-reporterId" name="reporterId" />
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
{{{ if expanded }}}
|
||||
<button type="button" class="btn btn-link" data-bs-toggle="collapse" data-bs-target="#more-filters" aria-controls="#more-filters" data-text-variant="[[flags:more-filters]] ">[[flags:fewer-filters]] <i class="fa fa-sort"></i></button>
|
||||
{{{ else }}}
|
||||
<button type="button" class="btn btn-link" data-bs-toggle="collapse" data-bs-target="#more-filters" aria-controls="#more-filters" data-text-variant="[[flags:fewer-filters]] ">[[flags:more-filters]] <i class="fa fa-sort"></i></button>
|
||||
{{{ end }}}
|
||||
<button type="button" id="apply-filters" class="btn btn-primary">[[flags:apply-filters]]</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
195
templates/partials/groups/admin.tpl
Normal file
195
templates/partials/groups/admin.tpl
Normal file
|
@ -0,0 +1,195 @@
|
|||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<div class="fs-5">
|
||||
<i class="fa fa-clock-o"></i> [[groups:details.pending]]
|
||||
<!-- IF group.pending.length -->
|
||||
<div class="btn-group float-end">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
[[global:more]] <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a class="dropdown-item" href="#" data-ajaxify="false" data-action="acceptAll">[[groups:pending.accept_all]]</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-ajaxify="false" data-action="rejectAll">[[groups:pending.reject_all]]</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- ENDIF group.pending.length -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table component="groups/pending" class="table table-striped table-hover">
|
||||
<!-- IF !group.pending.length -->
|
||||
<div class="alert alert-info">[[groups:pending.none]]</div>
|
||||
<!-- ENDIF !group.pending.length -->
|
||||
{{{each group.pending}}}
|
||||
<tr data-uid="{group.pending.uid}">
|
||||
<td class="p-2">
|
||||
<a href="{config.relative_path}/user/{group.pending.userslug}">{buildAvatar(group.pending, "24px", true)}</a>
|
||||
</td>
|
||||
<td class="member-name p-2">
|
||||
<a href="{config.relative_path}/user/{group.pending.userslug}">{group.pending.username}</a>
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<div class="btn-group float-end">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
[[global:more]] <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a class="dropdown-item" href="#" data-ajaxify="false" data-action="accept">[[groups:pending.accept]]</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-ajaxify="false" data-action="reject">[[groups:pending.reject]]</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{{end}}}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<span class="fs-5">
|
||||
<i class="fa fa-gift"></i> [[groups:details.invited]]
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="input-group mb-2">
|
||||
<input class="form-control" type="text" component="groups/members/invite" placeholder="[[groups:invited.search]]"/>
|
||||
<span class="input-group-text search-button"><i class="fa fa-search"></i></span>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<textarea class="form-control" component="groups/members/bulk-invite" placeholder="[[groups:bulk-invite-instructions]]"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="mb-2 clearfix">
|
||||
<button class="btn btn-outline-secondary btn-sm float-end" component="groups/members/bulk-invite-button">[[groups:bulk-invite]]</button>
|
||||
</div>
|
||||
|
||||
<table component="groups/invited" class="table table-striped table-hover">
|
||||
<!-- IF !group.invited.length -->
|
||||
<div class="alert alert-info">[[groups:invited.none]]</div>
|
||||
<!-- ENDIF !group.invited.length -->
|
||||
{{{each group.invited}}}
|
||||
<tr data-uid="{group.invited.uid}">
|
||||
<td class="p-2">
|
||||
<a href="{config.relative_path}/user/{group.invited.userslug}">{buildAvatar(group.invited, "24px", true)}</a>
|
||||
</td>
|
||||
<td class="member-name p-2">
|
||||
<a href="{config.relative_path}/user/{group.invited.userslug}">{group.invited.username}</a>
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<div class="btn-group float-end">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
[[global:more]] <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a class="dropdown-item" href="#" data-ajaxify="false" data-action="rescindInvite">[[groups:invited.uninvite]]</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{{end}}}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header pointer" data-bs-toggle="collapse" data-bs-target=".options">
|
||||
<span class="fs-5">
|
||||
<i class="fa fa-caret-down float-end"></i>
|
||||
<i class="fa fa-cogs"></i> [[groups:details.owner_options]]
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="card-body options collapse">
|
||||
<form component="groups/settings" role="form">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="name">[[groups:details.group_name]]</label>
|
||||
<input <!-- IF group.system -->readonly<!-- ENDIF group.system --> class="form-control" name="name" id="name" type="text" value="{group.displayName}" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="name">[[groups:details.description]]</label>
|
||||
<textarea class="form-control" name="description" id="description" type="text" maxlength="255">{group.description}</textarea>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="memberPostCids">[[groups:details.member-post-cids]]</label>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<input id="memberPostCids" type="text" class="form-control" value="{group.memberPostCids}">
|
||||
</div>
|
||||
<div class="col-md-6 member-post-cids-selector">
|
||||
<!-- IMPORT partials/category-selector.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="mb-3 user-title-option">
|
||||
<label class="form-label" for="userTitle">[[groups:details.badge_text]]</label>
|
||||
<input component="groups/userTitleOption" class="form-control" name="userTitle" id="userTitle" type="text" maxlength="40" value="{group.userTitleEscaped}"<!-- IF !group.userTitleEnabled --> disabled<!-- ENDIF !group.userTitleEnabled --> />
|
||||
</div>
|
||||
|
||||
<div class="mb-3 user-title-option">
|
||||
<label>[[groups:details.badge_preview]]</label><br />
|
||||
<span class="badge rounded-1 text-uppercase text-truncate rounded-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}{{{ if ./userTitle}}}me-1{{{ end }}}{{{ end }}}"></i><span class="badge-text">{{{ if group.userTitle }}}{group.userTitle}{{{ end }}}</span></span>
|
||||
|
||||
<hr/>
|
||||
<button component="groups/userTitleOption" type="button" class="btn btn-outline-secondary btn-sm" data-action="icon-select"<!-- IF !group.userTitleEnabled --> disabled<!-- ENDIF !group.userTitleEnabled -->>[[groups:details.change_icon]]</button>
|
||||
<div>
|
||||
<label class="form-label" for="labelColor" class="badge-color-label">[[groups:details.change_label_colour]]</label>
|
||||
<input component="groups/userTitleOption" type="color" name="labelColor" value="<!-- IF group.labelColor -->{group.labelColor}<!-- ENDIF group.labelColor -->" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label" for="color" class="badge-color-label">[[groups:details.change_text_colour]]</label>
|
||||
<input component="groups/userTitleOption" type="color" name="textColor" value="<!-- IF group.textColor -->{group.textColor}<!-- ENDIF group.textColor -->" />
|
||||
</div>
|
||||
<input type="hidden" name="icon" value="<!-- IF group.icon -->{group.icon}<!-- ENDIF group.icon -->" />
|
||||
|
||||
<div id="icons" class="hidden">
|
||||
<div class="icon-container">
|
||||
<div class="row nbb-fa-icons">
|
||||
<!-- IMPORT partials/fontawesome.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">[[groups:details.userTitleEnabled]]</label>
|
||||
<input class="form-check-input" name="userTitleEnabled" type="checkbox"<!-- IF group.userTitleEnabled --> checked<!-- ENDIF group.userTitleEnabled -->>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">[[groups:details.private]]</label>
|
||||
<input class="form-check-input" name="private" type="checkbox"<!-- IF group.private --> checked<!-- ENDIF group.private -->>
|
||||
<!-- IF !allowPrivateGroups -->
|
||||
<p class="form-text">
|
||||
[[groups:details.private_system_help]]
|
||||
</p>
|
||||
<!-- ENDIF !allowPrivateGroups -->
|
||||
<p class="form-text">
|
||||
[[groups:details.private_help]]
|
||||
</p>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">[[groups:details.disableJoinRequests]]</label>
|
||||
<input class="form-check-input" name="disableJoinRequests" type="checkbox"<!-- IF group.disableJoinRequests --> checked<!-- ENDIF group.disableJoinRequests -->>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">[[groups:details.disableLeave]]</label>
|
||||
<input class="form-check-input" name="disableLeave" type="checkbox"{{{if group.disableLeave}}} checked{{{end}}}>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">[[groups:details.hidden]]</label>
|
||||
<input class="form-check-input" name="hidden" type="checkbox"<!-- IF group.hidden --> checked<!-- ENDIF group.hidden -->>
|
||||
<p class="form-text">
|
||||
[[groups:details.hidden_help]]
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-link text-danger float-end" type="button" data-action="delete">[[groups:details.delete_group]]</button>
|
||||
<button class="btn btn-primary" type="button" data-action="update">[[global:save_changes]]</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
1
templates/partials/groups/badge.tpl
Normal file
1
templates/partials/groups/badge.tpl
Normal file
|
@ -0,0 +1 @@
|
|||
<a href="{config.relative_path}/groups/{./slug}" class="badge rounded-1 text-uppercase text-truncate" style="max-width: 150px;color:{./textColor};background-color: {./labelColor};"><i class="fa {{{ if ./icon }}}{./icon}{{{ if ./userTitle}}} me-1{{{ end }}}{{{else}}}hidden{{{ end }}}"></i><span class="badge-text">{{{ if ./userTitle }}}{./userTitle}{{{ end }}}</span></a>
|
21
templates/partials/groups/list.tpl
Normal file
21
templates/partials/groups/list.tpl
Normal file
|
@ -0,0 +1,21 @@
|
|||
{{{each groups}}}
|
||||
<div class="col-lg-4 col-md-6 col-sm-12 mb-3" component="groups/summary" data-slug="{groups.slug}">
|
||||
<div class="card h-100">
|
||||
<a href="{config.relative_path}/groups/{groups.slug}" class="card-header list-cover" style="<!-- IF groups.cover:thumb:url -->background-image: url({groups.cover:thumb:url});<!-- ENDIF groups.cover:thumb:url -->">
|
||||
<h5 class="card-title">{groups.displayName} <small>{groups.memberCount}</small></h5>
|
||||
</a>
|
||||
<div class="card-body">
|
||||
<ul class="members">
|
||||
{{{each groups.members}}}
|
||||
<li>
|
||||
<a href="{config.relative_path}/user/{groups.members.userslug}">{buildAvatar(groups.members, "24px", true)}</a>
|
||||
</li>
|
||||
{{{end}}}
|
||||
<!-- IF groups.truncated -->
|
||||
<li class="truncated"><i class="fa fa-ellipsis-h"></i></li>
|
||||
<!-- ENDIF groups.truncated -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{{end}}}
|
41
templates/partials/groups/memberlist.tpl
Normal file
41
templates/partials/groups/memberlist.tpl
Normal file
|
@ -0,0 +1,41 @@
|
|||
<div class="d-flex mb-3">
|
||||
<!-- IF group.isOwner -->
|
||||
<div class="flex-shrink-0">
|
||||
<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>
|
||||
</div>
|
||||
<!-- ENDIF group.isOwner -->
|
||||
<div class="flex-grow-1">
|
||||
<div class="input-group">
|
||||
<input class="form-control" type="text" component="groups/members/search" placeholder="[[global:search]]"/>
|
||||
<span class="input-group-text search-button"><i class="fa fa-search"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table component="groups/members" class="table table-striped table-hover" data-nextstart="{group.membersNextStart}">
|
||||
<tbody>
|
||||
{{{each group.members}}}
|
||||
<tr data-uid="{group.members.uid}">
|
||||
<td class="p-2">
|
||||
<a href="{config.relative_path}/user/{group.members.userslug}">{buildAvatar(group.members, "24px", true)}</a>
|
||||
</td>
|
||||
<td class="member-name p-2">
|
||||
<a class="align-text-top" href="{config.relative_path}/user/{group.members.userslug}">{group.members.username}</a>
|
||||
<i title="[[groups:owner]]" class="user-owner-icon fa fa-star align-text-top text-warning <!-- IF !group.members.isOwner -->invisible<!-- ENDIF !group.members.isOwner -->"></i>
|
||||
|
||||
<!-- IF group.isOwner -->
|
||||
<div class="owner-controls btn-group float-end">
|
||||
<a class="btn btn-sm" href="#" data-ajaxify="false" data-action="toggleOwnership" title="[[groups:details.grant]]">
|
||||
<i class="fa fa-star"></i>
|
||||
</a>
|
||||
|
||||
<a class="btn btn-sm" href="#" data-ajaxify="false" data-action="kick" title="[[groups:details.kick]]">
|
||||
<i class="fa fa-ban"></i>
|
||||
</a>
|
||||
</div>
|
||||
<!-- ENDIF group.isOwner -->
|
||||
</td>
|
||||
</tr>
|
||||
{{{end}}}
|
||||
</tbody>
|
||||
</table>
|
85
templates/partials/header/user-menu.tpl
Normal file
85
templates/partials/header/user-menu.tpl
Normal file
|
@ -0,0 +1,85 @@
|
|||
<li id="user_label" class="nav-item dropdown" title="[[global:header.profile]]">
|
||||
<label for="user-control-list-check" class="" data-bs-toggle="dropdown" id="user_dropdown" role="button">
|
||||
{buildAvatar(user, "32px", true)}
|
||||
<span id="user-header-name" class="d-block d-sm-none">{user.username}</span>
|
||||
</label>
|
||||
<input type="checkbox" class="hidden" id="user-control-list-check" aria-hidden="true">
|
||||
<ul id="user-control-list" component="header/usercontrol" class="dropdown-menu dropdown-menu-end" aria-labelledby="user_dropdown">
|
||||
<li>
|
||||
<a class="dropdown-item" component="header/profilelink" href="{relative_path}/user/{user.userslug}">
|
||||
<i component="user/status" class="fa fa-fw fa-circle status {user.status}"></i> <span component="header/username">{user.username}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation" class="dropdown-divider"></li>
|
||||
<li><h6 class="dropdown-header">[[global:status]]</h6></li>
|
||||
<li>
|
||||
<a href="#" class="dropdown-item user-status" data-status="online">
|
||||
<i class="fa fa-fw fa-circle status online"></i><span <!-- IF user.online -->class="bold"<!-- ENDIF user.online -->> [[global:online]]</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="dropdown-item user-status" data-status="away">
|
||||
<i class="fa fa-fw fa-circle status away"></i><span <!-- IF user.away -->class="bold"<!-- ENDIF user.away -->> [[global:away]]</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="dropdown-item user-status" data-status="dnd">
|
||||
<i class="fa fa-fw fa-circle status dnd"></i><span <!-- IF user.dnd -->class="bold"<!-- ENDIF user.dnd -->> [[global:dnd]]</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="dropdown-item user-status" data-status="offline">
|
||||
<i class="fa fa-fw fa-circle status offline"></i><span <!-- IF user.offline -->class="bold"<!-- ENDIF user.offline -->> [[global:invisible]]</span>
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation" class="dropdown-divider"></li>
|
||||
<li>
|
||||
<a class="dropdown-item" component="header/profilelink/edit" href="{relative_path}/user/{user.userslug}/edit">
|
||||
<i class="fa fa-fw fa-edit"></i> <span>[[user:edit-profile]]</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" component="header/profilelink/settings" href="{relative_path}/user/{user.userslug}/settings">
|
||||
<i class="fa fa-fw fa-gear"></i> <span>[[user:settings]]</span>
|
||||
</a>
|
||||
</li>
|
||||
{{{ if showModMenu }}}
|
||||
<li role="presentation" class="dropdown-divider"></li>
|
||||
<li><h6 class="dropdown-header">[[pages:moderator-tools]]</h6></li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="{relative_path}/flags">
|
||||
<i class="fa fa-fw fa-flag"></i> <span>[[pages:flagged-content]]</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="{relative_path}/post-queue">
|
||||
<i class="fa fa-fw fa-list-alt"></i> <span>[[pages:post-queue]]</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="{relative_path}/ip-blacklist">
|
||||
<i class="fa fa-fw fa-ban"></i> <span>[[pages:ip-blacklist]]</span>
|
||||
</a>
|
||||
</li>
|
||||
{{{ else }}}
|
||||
{{{ if postQueueEnabled }}}
|
||||
<li>
|
||||
<a class="dropdown-item" href="{relative_path}/post-queue">
|
||||
<i class="fa fa-fw fa-list-alt"></i> <span>[[pages:post-queue]]</span>
|
||||
</a>
|
||||
</li>
|
||||
{{{ end }}}
|
||||
{{{ end }}}
|
||||
|
||||
<li role="presentation" class="dropdown-divider"></li>
|
||||
<li component="user/logout">
|
||||
<form method="post" action="{relative_path}/logout">
|
||||
<input type="hidden" name="_csrf" value="{config.csrf_token}">
|
||||
<input type="hidden" name="noscript" value="true">
|
||||
<button type="submit" class="dropdown-item">
|
||||
<i class="fa fa-fw fa-sign-out"></i><span> [[global:logout]]</span>
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
186
templates/partials/menu.tpl
Normal file
186
templates/partials/menu.tpl
Normal file
|
@ -0,0 +1,186 @@
|
|||
<div class="d-flex align-items-center me-auto" style="min-width: 0px;">
|
||||
<button type="button" class="navbar-toggler border-0" id="mobile-menu">
|
||||
<i class="fa fa-lg fa-fw fa-bars unread-count" ></i>
|
||||
<span component="unread/icon" class="notification-icon fa fa-fw fa-book unread-count" data-content="{unreadCount.mobileUnread}" data-unread-url="{unreadCount.unreadUrl}"></span>
|
||||
</button>
|
||||
<div class="d-inline-flex align-items-center" style="min-width: 0px;">
|
||||
{{{ if brand:logo }}}
|
||||
<a class="navbar-brand" href="{{{ if brand:logo:url }}}{brand:logo:url}{{{ else }}}{relative_path}/{{{ end }}}">
|
||||
<img alt="{brand:logo:alt}" class="{brand:logo:display} forum-logo d-inline-block align-text-bottom" src="{brand:logo}?{config.cache-buster}" />
|
||||
</a>
|
||||
{{{ end }}}
|
||||
{{{ if config.showSiteTitle }}}
|
||||
<a class="navbar-brand text-truncate" href="{{{ if title:url }}}{title:url}{{{ else }}}{relative_path}/{{{ end }}}">
|
||||
{config.siteTitle}
|
||||
</a>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{{ if config.searchEnabled }}}
|
||||
<div class="navbar-search visible-xs">
|
||||
<form action="{config.relative_path}/search" method="GET">
|
||||
<button type="button" class="btn btn-link"><i class="fa fa-lg fa-fw fa-search" title="[[global:header.search]]"></i></button>
|
||||
<input autocomplete="off" type="text" class="form-control hidden" name="term" placeholder="[[global:search]]"/>
|
||||
<button class="btn btn-primary hidden" type="submit"></button>
|
||||
<input type="text" class="hidden" name="in" value="{config.searchDefaultInQuick}" />
|
||||
</form>
|
||||
<div class="quick-search-container hidden">
|
||||
<div class="quick-search-results-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
|
||||
{{{ if config.loggedIn }}}
|
||||
<button type="button" class="navbar-toggler border-0" id="mobile-chats">
|
||||
<span component="notifications/icon" class="notification-icon fa fa-fw fa-bell-o unread-count" data-content="{unreadCount.notification}"></span>
|
||||
<span component="chat/icon" class="notification-icon fa fa-fw fa-comments unread-count" data-content="{unreadCount.chat}"></span>
|
||||
{buildAvatar(user, "32px", true)}
|
||||
</button>
|
||||
{{{ end }}}
|
||||
|
||||
<div component="navbar/title" class="visible-xs hidden">
|
||||
<span></span>
|
||||
</div>
|
||||
|
||||
<div id="nav-dropdown" class="collapse navbar-collapse d-none d-lg-block">
|
||||
<ul id="main-nav" class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
{{{each navigation}}}
|
||||
<!-- IF function.displayMenuItem, @index -->
|
||||
<li class="nav-item {navigation.class}{{{ if navigation.dropdown }}} dropdown{{{ end }}}" title="{navigation.title}">
|
||||
<a class="nav-link navigation-link {{{ if navigation.dropdown }}}dropdown-toggle{{{ end }}}"
|
||||
{{{ 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 }}}>
|
||||
{{{ if navigation.iconClass }}}
|
||||
<i class="fa fa-fw {navigation.iconClass}" data-content="{navigation.content}"></i>
|
||||
{{{ end }}}
|
||||
{{{ if navigation.text }}}
|
||||
<span class="{navigation.textClass}">{navigation.text}</span>
|
||||
{{{ end }}}
|
||||
{{{ if navigation.dropdown}}}
|
||||
<i class="fa fa-caret-down"></i>
|
||||
{{{ end }}}
|
||||
</a>
|
||||
{{{ if navigation.dropdown }}}
|
||||
<ul class="dropdown-menu">
|
||||
{navigation.dropdownContent}
|
||||
</ul>
|
||||
{{{ end }}}
|
||||
</li>
|
||||
<!-- ENDIF function.displayMenuItem -->
|
||||
{{{end}}}
|
||||
</ul>
|
||||
<ul class="navbar-nav mb-2 mb-lg-0 hidden-xs">
|
||||
<li class="nav-item">
|
||||
<a href="#" id="reconnect" class="nav-link hide" title="[[global:reconnecting-message, {config.siteTitle}]]">
|
||||
<i class="fa fa-check"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{{{ if config.searchEnabled }}}
|
||||
<div class="navbar-nav mb-2 mb-lg-0 position-relative">
|
||||
<form component="search/form" id="search-form" class="d-flex justify-content-end align-items-center" role="search" method="GET">
|
||||
<div component="search/fields" class="hidden" id="search-fields">
|
||||
<div class="input-group flex-nowrap">
|
||||
<input autocomplete="off" type="text" class="form-control" placeholder="[[global:search]]" name="query" value="">
|
||||
|
||||
<button href="#" class="btn btn-outline-secondary">
|
||||
<i class="fa fa-gears fa-fw advanced-search-link"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="quick-search-container" class="quick-search-container dropdown-menu d-block mt-2 hidden">
|
||||
<div class="form-check filter-category mb-2 ms-4">
|
||||
<input class="form-check-input" type="checkbox" checked>
|
||||
<label class="form-check-label name"></label>
|
||||
</div>
|
||||
|
||||
<div class="text-center loading-indicator"><i class="fa fa-spinner fa-spin"></i></div>
|
||||
<div class="quick-search-results-container"></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-outline-secondary hide">[[global:search]]</button>
|
||||
</div>
|
||||
|
||||
<li id="" class="nav-item"><a component="search/button" id="search-button" href="#" class="nav-link"><i class="fa fa-search fa-fw" title="Search"></i></a></li>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
{{{ end }}}
|
||||
|
||||
{{{ if !maintenanceHeader }}}
|
||||
{{{ if config.loggedIn }}}
|
||||
<ul id="logged-in-menu" class="navbar-nav me-0 mb-2 mb-lg-0 align-items-center">
|
||||
<li class="nav-item notifications dropdown d-none d-sm-block" component="notifications" title="[[global:header.notifications]]">
|
||||
<a href="{relative_path}/notifications" class="nav-link" data-bs-toggle="dropdown" id="notif_dropdown" data-ajaxify="false" role="button">
|
||||
<i component="notifications/icon" class="fa fa-fw {{{ if unreadCount.notification}}}fa-bell{{{ else }}}fa-bell-o{{{ end }}} unread-count" data-content="{unreadCount.notification}"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="notif_dropdown">
|
||||
<li>
|
||||
<ul component="notifications/list" class="notification-list">
|
||||
<li class="loading-text">
|
||||
<a href="#"><i class="fa fa-refresh fa-spin"></i> [[global:notifications.loading]]</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="notif-dropdown-link">
|
||||
<div class="btn-group d-flex justify-content-center">
|
||||
<a role="button" href="#" class="btn btn-light mark-all-read"><i class="fa fa-check-double"></i> [[notifications:mark_all_read]]</a>
|
||||
<a class="btn btn-light" href="{relative_path}/notifications"><i class="fa fa-list"></i> [[notifications:see_all]]</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<!-- IF canChat -->
|
||||
<li class="nav-item chats dropdown" title="[[global:header.chats]]">
|
||||
<a class="nav-link" data-bs-toggle="dropdown" href="{relative_path}/user/{user.userslug}/chats" id="chat_dropdown" component="chat/dropdown" data-ajaxify="false" role="button">
|
||||
<i component="chat/icon" class="fa fa-comment-o fa-fw unread-count" data-content="{unreadCount.chat}"></i> <span class="d-inline d-sm-none">[[global:header.chats]]</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="chat_dropdown">
|
||||
<li>
|
||||
<ul component="chat/list" class="chat-list chats-list">
|
||||
<li class="loading-text">
|
||||
<a href="#"><i class="fa fa-refresh fa-spin"></i> [[global:chats.loading]]</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="notif-dropdown-link">
|
||||
<div class="btn-group d-flex justify-content-center">
|
||||
<a class="btn btn-light mark-all-read" href="#" component="chats/mark-all-read"><i class="fa fa-check-double"></i> [[modules:chat.mark_all_read]]</a>
|
||||
<a class="btn btn-light" href="{relative_path}/user/{user.userslug}/chats"><i class="fa fa-comments"></i> [[modules:chat.see_all]]</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<!-- ENDIF canChat -->
|
||||
|
||||
<!-- IMPORT partials/header/user-menu.tpl -->
|
||||
</ul>
|
||||
{{{ else }}}
|
||||
<ul id="logged-out-menu" class="navbar-nav me-0 mb-2 mb-lg-0 align-items-center">
|
||||
{{{ if allowRegistration }}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{relative_path}/register">
|
||||
<i class="fa fa-pencil fa-fw d-inline-block d-sm-none"></i>
|
||||
<span>[[global:register]]</span>
|
||||
</a>
|
||||
</li>
|
||||
{{{ end }}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{relative_path}/login">
|
||||
<i class="fa fa-sign-in fa-fw d-inline-block d-sm-none"></i>
|
||||
<span>[[global:login]]</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{{{ end }}}
|
||||
{{{ else }}}
|
||||
<ul class="navbar-nav me-0 mb-2 mb-lg-0"></ul>
|
||||
<li class="nav-item">
|
||||
<a href="{relative_path}/login">
|
||||
<i class="fa fa-sign-in fa-fw d-block d-sm-none"></i>
|
||||
<span>[[global:login]]</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{{{ end }}}
|
||||
</div>
|
30
templates/partials/notifications_list.tpl
Normal file
30
templates/partials/notifications_list.tpl
Normal file
|
@ -0,0 +1,30 @@
|
|||
|
||||
<!-- IF !notifications.length -->
|
||||
<li class="no-notifs"><a href="#">[[notifications:no_notifs]]</a></li>
|
||||
<!-- ENDIF !notifications.length -->
|
||||
|
||||
{{{each notifications}}}
|
||||
<li class="{notifications.readClass}" data-nid="{notifications.nid}" data-path="{notifications.path}" <!-- IF notifications.pid --> data-pid="{notifications.pid}"<!-- ENDIF notifications.pid --><!-- IF notifications.tid --> data-tid="{notifications.tid}"<!-- ENDIF notifications.tid -->>
|
||||
<!-- IF notifications.image -->
|
||||
<!-- IF notifications.from -->
|
||||
<a href="{config.relative_path}/user/{notifications.user.userslug}"><img class="float-start user-img avatar avatar-rounded" style="--avatar-size: 32px;" src="{notifications.image}" /></a>
|
||||
<!-- ENDIF notifications.from -->
|
||||
<!-- ELSE -->
|
||||
<a href="{config.relative_path}/user/{notifications.user.userslug}"><div class="float-start avatar avatar-rounded" style="--avatar-size: 32px; background-color: {notifications.user.icon:bgColor};">{notifications.user.icon:text}</div></a>
|
||||
<!-- ENDIF notifications.image -->
|
||||
|
||||
<a href="{notifications.path}" class="notification-chat-content deco-none">
|
||||
<span class="text">{notifications.bodyShort}</span>
|
||||
</a>
|
||||
|
||||
<div class="notification-chat-controls">
|
||||
{{{ if ./nid }}}
|
||||
<div class="mark-read" aria-label="Mark Read">
|
||||
<i class="unread fa fa-circle"></i>
|
||||
<i class="read fa fa-circle-o"></i>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
<span class="relTime">{notifications.timeago}</span>
|
||||
</div>
|
||||
</li>
|
||||
{{{end}}}
|
45
templates/partials/paginator.tpl
Normal file
45
templates/partials/paginator.tpl
Normal file
|
@ -0,0 +1,45 @@
|
|||
<div component="pagination" class="pagination-container<!-- IF !pagination.pages.length --> hidden<!-- ENDIF !pagination.pages.length -->">
|
||||
<ul class="pagination hidden-xs justify-content-center">
|
||||
<li class="page-item previous float-start<!-- IF !pagination.prev.active --> disabled<!-- ENDIF !pagination.prev.active -->">
|
||||
<a class="page-link" href="?{pagination.prev.qs}" data-page="{pagination.prev.page}"><i class="fa fa-chevron-left"></i> </a>
|
||||
</li>
|
||||
|
||||
{{{each pagination.pages}}}
|
||||
<!-- IF pagination.pages.separator -->
|
||||
<li component="pagination/select-page" class="page-item page select-page">
|
||||
<a class="page-link" href="#"><i class="fa fa-ellipsis-h"></i></a>
|
||||
</li>
|
||||
<!-- ELSE -->
|
||||
<li class="page-item page<!-- IF pagination.pages.active --> active<!-- ENDIF pagination.pages.active -->" >
|
||||
<a class="page-link" href="?{pagination.pages.qs}" data-page="{pagination.pages.page}">{pagination.pages.page}</a>
|
||||
</li>
|
||||
<!-- ENDIF pagination.pages.separator -->
|
||||
{{{end}}}
|
||||
|
||||
<li class="page-item next float-end<!-- IF !pagination.next.active --> disabled<!-- ENDIF !pagination.next.active -->">
|
||||
<a class="page-link" href="?{pagination.next.qs}" data-page="{pagination.next.page}"> <i class="fa fa-chevron-right"></i></a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="pagination hidden-sm hidden-md hidden-lg justify-content-center">
|
||||
<li class="page-item first<!-- IF !pagination.prev.active --> disabled<!-- ENDIF !pagination.prev.active -->">
|
||||
<a class="page-link" href="?{pagination.first.qs}" data-page="1"><i class="fa fa-fast-backward"></i> </a>
|
||||
</li>
|
||||
|
||||
<li class="page-item previous<!-- IF !pagination.prev.active --> disabled<!-- ENDIF !pagination.prev.active -->">
|
||||
<a class="page-link" href="?{pagination.prev.qs}" data-page="{pagination.prev.page}"><i class="fa fa-chevron-left"></i> </a>
|
||||
</li>
|
||||
|
||||
<li component="pagination/select-page" class="page-item page select-page">
|
||||
<a class="page-link" href="#">{pagination.currentPage} / {pagination.pageCount}</a>
|
||||
</li>
|
||||
|
||||
<li class="page-item next<!-- IF !pagination.next.active --> disabled<!-- ENDIF !pagination.next.active -->">
|
||||
<a class="page-link" href="?{pagination.next.qs}" data-page="{pagination.next.page}"> <i class="fa fa-chevron-right"></i></a>
|
||||
</li>
|
||||
|
||||
<li class="page-item last<!-- IF !pagination.next.active --> disabled<!-- ENDIF !pagination.next.active -->">
|
||||
<a class="page-link" href="?{pagination.last.qs}" data-page="{pagination.pageCount}"><i class="fa fa-fast-forward"></i> </a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
20
templates/partials/post_bar.tpl
Normal file
20
templates/partials/post_bar.tpl
Normal file
|
@ -0,0 +1,20 @@
|
|||
<div class="topic-main-buttons float-end d-inline-block">
|
||||
<span class="loading-indicator btn float-start hidden" done="0">
|
||||
<span class="hidden-xs">[[topic:loading_more_posts]]</span> <i class="fa fa-refresh fa-spin"></i>
|
||||
</span>
|
||||
|
||||
<!-- IF loggedIn -->
|
||||
<button component="topic/mark-unread" class="btn btn-sm btn-outline-secondary" title="[[topic:mark_unread]]">
|
||||
<i class="fa fa-fw fa-inbox"></i><span class="visible-sm-inline visible-md-inline visible-lg-inline"></span>
|
||||
</button>
|
||||
<!-- ENDIF loggedIn -->
|
||||
|
||||
<!-- IMPORT partials/topic/watch.tpl -->
|
||||
|
||||
<!-- IMPORT partials/topic/sort.tpl -->
|
||||
|
||||
<div class="d-inline-block">
|
||||
<!-- IMPORT partials/thread_tools.tpl -->
|
||||
</div>
|
||||
<!-- IMPORT partials/topic/reply-button.tpl -->
|
||||
</div>
|
8
templates/partials/posts_list.tpl
Normal file
8
templates/partials/posts_list.tpl
Normal file
|
@ -0,0 +1,8 @@
|
|||
<ul component="posts" class="posts-list list-unstyled" data-nextstart="{nextStart}">
|
||||
{{{each posts}}}
|
||||
<!-- IMPORT partials/posts_list_item.tpl -->
|
||||
{{{end}}}
|
||||
</ul>
|
||||
<div component="posts/loading" class="loading-indicator text-center hidden">
|
||||
<i class="fa fa-refresh fa-spin"></i>
|
||||
</div>
|
32
templates/partials/posts_list_item.tpl
Normal file
32
templates/partials/posts_list_item.tpl
Normal file
|
@ -0,0 +1,32 @@
|
|||
<li component="post" class="posts-list-item row<!-- IF ../deleted --> deleted<!-- ELSE --><!-- IF ../topic.deleted --> deleted<!-- ENDIF --><!-- ENDIF -->{{{ if ../topic.scheduled }}} scheduled{{{ end }}}" data-pid="{../pid}" data-uid="{../uid}">
|
||||
<div class="col-lg-11 col-sm-10 col-9 post-body">
|
||||
<a class="topic-title" href="{config.relative_path}/post/{../pid}">
|
||||
<!-- IF !../isMainPost -->RE: <!-- ENDIF -->{../topic.title}
|
||||
</a>
|
||||
|
||||
<div component="post/content" class="content">
|
||||
{../content}
|
||||
</div>
|
||||
|
||||
<small class="topic-category"><a href="{config.relative_path}/category/{../category.slug}">[[global:posted_in, {../category.name}]]</a></small>
|
||||
|
||||
{{{ if ../isMainPost }}}
|
||||
{{{ if ../topic.tags.length }}}
|
||||
<span class="tag-list">
|
||||
{{{ each ../topic.tags }}}
|
||||
<a href="{config.relative_path}/tags/{topic.tags.valueEncoded}"><span class="tag tag-item tag-class-{topic.tags.class}">{topic.tags.valueEscaped}</span></a>
|
||||
{{{ end }}}
|
||||
</span>
|
||||
{{{ end }}}
|
||||
{{{ end }}}
|
||||
|
||||
<div class="post-info">
|
||||
<a href="{config.relative_path}/user/{../user.userslug}">{buildAvatar(../user, "28px", true, "user-img not-responsive")}</a>
|
||||
|
||||
<div class="post-author">
|
||||
<a href="{config.relative_path}/user/{../user.userslug}">{../user.displayname}</a><br />
|
||||
<span class="timeago" title="{../timestampISO}"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
34
templates/partials/quick-search-results.tpl
Normal file
34
templates/partials/quick-search-results.tpl
Normal file
|
@ -0,0 +1,34 @@
|
|||
<ul id="quick-search-results" class="quick-search-results list-unstyled mb-0 p-0 overflow-auto" style="max-width:400px; max-height: 500px;">
|
||||
{{{each posts}}}
|
||||
<li data-tid="{posts.topic.tid}" data-pid="{posts.pid}">
|
||||
<a href="{config.relative_path}/post/{posts.pid}"
|
||||
class="text-decoration-none text-reset clearfix d-block text-truncate px-3 py-1">
|
||||
{buildAvatar(posts.user, "24px", true)}
|
||||
<span class="quick-search-title fw-bold">{posts.topic.title}</span>
|
||||
<br/>
|
||||
<p class="snippet text-break text-wrap">
|
||||
{posts.snippet}
|
||||
</p>
|
||||
<small class="post-info float-end">
|
||||
<div class="category-item d-inline-block">
|
||||
{buildCategoryIcon(./category, "24px", "rounded-circle")} {posts.category.name}
|
||||
• <span class="timeago" title="{posts.timestampISO}"></span>
|
||||
</div>
|
||||
</small>
|
||||
</a>
|
||||
</li>
|
||||
<!-- IF !@last -->
|
||||
<li role="separator" class="dropdown-divider"></li>
|
||||
<!-- ENDIF -->
|
||||
{{{end}}}
|
||||
</ul>
|
||||
<!-- IF multiplePages -->
|
||||
<div class="text-center mt-2">
|
||||
<a href="{url}">
|
||||
[[search:see-more-results, {matchCount}]]
|
||||
</a>
|
||||
</div>
|
||||
<!-- ENDIF multiplePages -->
|
||||
{{{if !posts.length}}}
|
||||
<div class="text-center no-results">[[search:no-matches]]</li>
|
||||
{{{end}}}
|
55
templates/partials/search-results.tpl
Normal file
55
templates/partials/search-results.tpl
Normal file
|
@ -0,0 +1,55 @@
|
|||
<div id="results" class="search-results col-md-12" data-search-query="{search_query}">
|
||||
{{{ if matchCount }}}
|
||||
<div class="alert alert-info">[[search:results_matching, {matchCount}, {search_query}, {time}]] </div>
|
||||
{{{ else }}}
|
||||
{{{ if search_query }}}
|
||||
<div class="alert alert-warning">[[search:no-matches]]</div>
|
||||
{{{ end }}}
|
||||
{{{ end }}}
|
||||
|
||||
{{{each posts}}}
|
||||
<div class="topic-row card clearfix mb-3">
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<a href="{config.relative_path}/user/{./user.userslug}">{buildAvatar(./user, "24px", true)}</a>
|
||||
<span class="search-result-text search-result-title"><a href="{config.relative_path}/post/{posts.pid}">{./topic.title}</a></span>
|
||||
</div>
|
||||
|
||||
{{{ if showAsPosts }}}
|
||||
<div class="search-result-text">
|
||||
{./content}
|
||||
<p class="fade-out"></p>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
|
||||
<small class="post-info float-end">
|
||||
<a href="{config.relative_path}/category/{./category.slug}">
|
||||
<div class="category-item d-inline-block">
|
||||
{buildCategoryIcon(./category, "24px", "rounded-circle")}
|
||||
{./category.name}
|
||||
</div>
|
||||
</a> •
|
||||
<span class="timeago" title="{./timestampISO}"></span>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{{{end}}}
|
||||
|
||||
{{{ if users.length }}}
|
||||
<!-- IMPORT partials/users_list.tpl -->
|
||||
{{{ end }}}
|
||||
|
||||
{{{ if tags.length }}}
|
||||
<!-- IMPORT partials/tags_list.tpl -->
|
||||
{{{ end }}}
|
||||
|
||||
{{{ if categories.length }}}
|
||||
<ul class="categories">
|
||||
{{{each categories}}}
|
||||
<!-- IMPORT partials/categories/item.tpl -->
|
||||
{{{end}}}
|
||||
</ul>
|
||||
{{{ end }}}
|
||||
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</div>
|
4
templates/partials/slideout-menu.tpl
Normal file
4
templates/partials/slideout-menu.tpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
<section class="menu-section" data-section="navigation">
|
||||
<ul class="menu-section-list text-bg-dark"></ul>
|
||||
</section>
|
||||
|
5
templates/partials/tags_list.tpl
Normal file
5
templates/partials/tags_list.tpl
Normal file
|
@ -0,0 +1,5 @@
|
|||
{{{each tags}}}
|
||||
<h5 class="float-start tag-container me-4 mb-4 fw-bold">
|
||||
<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 human-readable-number" title="{tags.score}">{tags.score}</span></a>
|
||||
</h5>
|
||||
{{{end}}}
|
8
templates/partials/thread_tools.tpl
Normal file
8
templates/partials/thread_tools.tpl
Normal file
|
@ -0,0 +1,8 @@
|
|||
{{{ if privileges.view_thread_tools }}}
|
||||
<div title="[[topic:thread_tools.title]]" class="btn-group thread-tools bottom-sheet">
|
||||
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" type="button">
|
||||
<i class="fa fa-fw fa-gear"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end"></ul>
|
||||
</div>
|
||||
{{{ end }}}
|
14
templates/partials/toast.tpl
Normal file
14
templates/partials/toast.tpl
Normal file
|
@ -0,0 +1,14 @@
|
|||
<div id="{alert_id}" role="alert" class="alert alert-dismissible alert-{type}" component="toaster/toast">
|
||||
<button type="button" class="btn-close float-end" data-bs-dismiss="alert" aria-label="close"></button>
|
||||
<!-- IF image -->
|
||||
<img src="{image}">
|
||||
<!-- ENDIF image -->
|
||||
|
||||
<!-- IF title -->
|
||||
<strong>{title}</strong>
|
||||
<!-- ENDIF title -->
|
||||
|
||||
<!-- IF message -->
|
||||
<p>{message}</p>
|
||||
<!-- ENDIF message -->
|
||||
</div>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue