@okjavis/nodebb-theme-javis 1.7.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugin.json +2 -1
- package/scss/_base.scss +0 -6
- package/scss/_buttons.scss +0 -10
- package/scss/_forms.scss +0 -17
- package/scss/_header.scss +281 -0
- package/scss/_sidebar.scss +24 -47
- package/scss/_topic.scss +681 -0
- package/scss/_variables.scss +10 -0
- package/templates/partials/topic/sidebar.tpl +48 -0
- package/templates/topic.tpl +133 -0
- package/theme.js +56 -0
- package/theme.scss +2 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<div id="topic-sidebar" class="topic-sidebar">
|
|
2
|
+
<div class="d-flex flex-column gap-2">
|
|
3
|
+
<div class="topic-sidebar-actions d-flex flex-column gap-2 mb-3">
|
|
4
|
+
<!-- Reply Button -->
|
|
5
|
+
<!-- IMPORT partials/topic/reply-button.tpl -->
|
|
6
|
+
|
|
7
|
+
<!-- Mark Unread Button -->
|
|
8
|
+
{{{ if loggedIn }}}
|
|
9
|
+
<button component="topic/mark-unread" class="btn btn-ghost btn-sm d-flex gap-2 align-items-center w-100 justify-content-start">
|
|
10
|
+
<i class="fa fa-fw fa-inbox"></i>
|
|
11
|
+
<span class="fw-semibold text-nowrap">[[topic:mark-unread]]</span>
|
|
12
|
+
</button>
|
|
13
|
+
{{{ end }}}
|
|
14
|
+
|
|
15
|
+
<!-- Watching/Not Watching -->
|
|
16
|
+
<!-- IMPORT partials/topic/watch.tpl -->
|
|
17
|
+
|
|
18
|
+
<!-- Sort Options -->
|
|
19
|
+
<!-- IMPORT partials/topic/sort.tpl -->
|
|
20
|
+
|
|
21
|
+
<!-- Topic Tools (for mods/admins) -->
|
|
22
|
+
<!-- IMPORT partials/topic/tools.tpl -->
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<!-- Post Navigator / Timeline -->
|
|
26
|
+
<div class="pagination-block flex-grow-1">
|
|
27
|
+
<div class="scroller-content d-flex gap-2 flex-column align-items-start">
|
|
28
|
+
<button class="btn btn-ghost btn-sm d-flex gap-2 align-items-center pagetop w-100 justify-content-start">
|
|
29
|
+
<i class="fa fa-fw fa-angle-up"></i>
|
|
30
|
+
<span class="timeago text-xs text-muted text-nowrap" title="{./timestampISO}"></span>
|
|
31
|
+
</button>
|
|
32
|
+
<div class="scroller-container position-relative w-100">
|
|
33
|
+
<div class="scroller-thumb d-flex gap-2 text-nowrap position-relative" style="height: 40px;">
|
|
34
|
+
<div class="scroller-thumb-icon rounded d-inline-block" style="width: 4px; height: 40px;"></div>
|
|
35
|
+
<div class="d-flex flex-column">
|
|
36
|
+
<span class="thumb-text small fw-semibold mb-0"></span>
|
|
37
|
+
<span class="thumb-timestamp timeago text-xs text-muted mb-0"></span>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
<button class="btn btn-ghost btn-sm d-flex gap-2 align-items-center pagebottom w-100 justify-content-start">
|
|
42
|
+
<i class="fa fa-fw fa-angle-down"></i>
|
|
43
|
+
<span class="timeago text-xs text-muted text-nowrap" title="{./lastposttimeISO}"></span>
|
|
44
|
+
</button>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<!-- IMPORT partials/breadcrumbs-json-ld.tpl -->
|
|
2
|
+
{{{ if config.theme.enableBreadcrumbs }}}
|
|
3
|
+
<!-- IMPORT partials/breadcrumbs.tpl -->
|
|
4
|
+
{{{ end }}}
|
|
5
|
+
{{{ if widgets.header.length }}}
|
|
6
|
+
<div data-widget-area="header">
|
|
7
|
+
{{{each widgets.header}}}
|
|
8
|
+
{{widgets.header.html}}
|
|
9
|
+
{{{end}}}
|
|
10
|
+
</div>
|
|
11
|
+
{{{ end }}}
|
|
12
|
+
|
|
13
|
+
<div itemid="{url}" itemscope itemtype="https://schema.org/DiscussionForumPosting">
|
|
14
|
+
<meta itemprop="headline" content="{escape(titleRaw)}">
|
|
15
|
+
<meta itemprop="text" content="{escape(titleRaw)}">
|
|
16
|
+
<meta itemprop="url" content="{url}">
|
|
17
|
+
<meta itemprop="datePublished" content="{timestampISO}">
|
|
18
|
+
<meta itemprop="dateModified" content="{lastposttimeISO}">
|
|
19
|
+
<div itemprop="author" itemscope itemtype="https://schema.org/Person">
|
|
20
|
+
<meta itemprop="name" content="{author.username}">
|
|
21
|
+
{{{ if author.userslug }}}<meta itemprop="url" content="{config.relative_path}/user/{author.userslug}">{{{ end }}}
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="d-flex flex-column gap-3">
|
|
25
|
+
<div class="d-flex flex-wrap">
|
|
26
|
+
<div class="d-flex flex-column gap-3 flex-grow-1">
|
|
27
|
+
<div class="topic-header d-flex align-items-start gap-3">
|
|
28
|
+
<a href="#" onclick="history.back(); return false;" class="topic-back-btn" title="Go back">
|
|
29
|
+
<i class="fa fa-arrow-left"></i>
|
|
30
|
+
</a>
|
|
31
|
+
<h1 component="post/header" class="tracking-tight fw-semibold fs-3 mb-0 text-break {{{ if config.theme.centerHeaderElements }}}text-center{{{ end }}}">
|
|
32
|
+
<span class="topic-title" component="topic/title">{title}</span>
|
|
33
|
+
</h1>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="topic-info d-flex gap-2 align-items-center flex-wrap {{{ if config.theme.centerHeaderElements }}}justify-content-center{{{ end }}}">
|
|
37
|
+
<span component="topic/labels" class="d-flex gap-2 {{{ if (!scheduled && (!pinned && (!locked && (!oldCid && !icons.length)))) }}}hidden{{{ end }}}">
|
|
38
|
+
<span component="topic/scheduled" class="badge badge border border-gray-300 text-body {{{ if !scheduled }}}hidden{{{ end }}}">
|
|
39
|
+
<i class="fa fa-clock-o"></i> [[topic:scheduled]]
|
|
40
|
+
</span>
|
|
41
|
+
<span component="topic/pinned" class="badge badge border border-gray-300 text-body {{{ if (scheduled || !pinned) }}}hidden{{{ end }}}">
|
|
42
|
+
<i class="fa fa-thumb-tack"></i> {{{ if !pinExpiry }}}[[topic:pinned]]{{{ else }}}[[topic:pinned-with-expiry, {isoTimeToLocaleString(./pinExpiryISO, config.userLang)}]]{{{ end }}}
|
|
43
|
+
</span>
|
|
44
|
+
<span component="topic/locked" class="badge badge border border-gray-300 text-body {{{ if !locked }}}hidden{{{ end }}}">
|
|
45
|
+
<i class="fa fa-lock"></i> [[topic:locked]]
|
|
46
|
+
</span>
|
|
47
|
+
<a component="topic/moved" href="{config.relative_path}/category/{oldCid}" class="badge badge border border-gray-300 text-body text-decoration-none {{{ if !oldCid }}}hidden{{{ end }}}">
|
|
48
|
+
<i class="fa fa-arrow-circle-right"></i> {{{ if privileges.isAdminOrMod }}}[[topic:moved-from, {oldCategory.name}]]{{{ else }}}[[topic:moved]]{{{ end }}}
|
|
49
|
+
</a>
|
|
50
|
+
{{{each icons}}}<span class="lh-1">{@value}</span>{{{end}}}
|
|
51
|
+
</span>
|
|
52
|
+
{function.buildCategoryLabel, category, "a", "border"}
|
|
53
|
+
<div data-tid="{./tid}" component="topic/tags" class="lh-1 tags tag-list d-flex flex-wrap hidden-xs hidden-empty gap-2"><!-- IMPORT partials/topic/tags.tpl --></div>
|
|
54
|
+
<div class="d-flex hidden-xs gap-2"><!-- IMPORT partials/topic/stats.tpl --></div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="d-flex gap-2 align-items-center mt-2 hidden-empty" component="topic/thumb/list"><!-- IMPORT partials/topic/thumbs.tpl --></div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div class="topic-layout d-flex gap-4 mb-4 mb-lg-0">
|
|
61
|
+
<!-- Main Content Area -->
|
|
62
|
+
<div class="topic flex-grow-1" style="min-width: 0;">
|
|
63
|
+
{{{ if merger }}}
|
|
64
|
+
<!-- IMPORT partials/topic/merged-message.tpl -->
|
|
65
|
+
{{{ end }}}
|
|
66
|
+
{{{ if forker }}}
|
|
67
|
+
<!-- IMPORT partials/topic/forked-message.tpl -->
|
|
68
|
+
{{{ end }}}
|
|
69
|
+
{{{ if !scheduled }}}
|
|
70
|
+
<!-- IMPORT partials/topic/deleted-message.tpl -->
|
|
71
|
+
{{{ end }}}
|
|
72
|
+
|
|
73
|
+
<div class="posts-container" style="min-width: 0;">
|
|
74
|
+
<ul component="topic" class="posts timeline list-unstyled mt-sm-2 p-0 py-3" style="min-width: 0;" data-tid="{tid}" data-cid="{cid}">
|
|
75
|
+
{{{ each posts }}}
|
|
76
|
+
<li component="post" class="pt-4 {{{ if posts.deleted }}}deleted{{{ end }}} {{{ if posts.selfPost }}}self-post{{{ end }}} {{{ if posts.topicOwnerPost }}}topic-owner-post{{{ end }}}" <!-- IMPORT partials/data/topic.tpl -->>
|
|
77
|
+
<a component="post/anchor" data-index="{./index}" id="{increment(./index, "1")}"></a>
|
|
78
|
+
<meta itemprop="datePublished" content="{./timestampISO}">
|
|
79
|
+
{{{ if ./editedISO }}}
|
|
80
|
+
<meta itemprop="dateModified" content="{./editedISO}">
|
|
81
|
+
{{{ end }}}
|
|
82
|
+
|
|
83
|
+
<!-- IMPORT partials/topic/post.tpl -->
|
|
84
|
+
</li>
|
|
85
|
+
{{{ if (config.topicPostSort != "most_votes") }}}
|
|
86
|
+
{{{ each ./events}}}<!-- IMPORT partials/topic/event.tpl -->{{{ end }}}
|
|
87
|
+
{{{ end }}}
|
|
88
|
+
{{{ end }}}
|
|
89
|
+
</ul>
|
|
90
|
+
{{{ if browsingUsers }}}
|
|
91
|
+
<div class="visible-xs">
|
|
92
|
+
<!-- IMPORT partials/topic/browsing-users.tpl -->
|
|
93
|
+
<hr/>
|
|
94
|
+
</div>
|
|
95
|
+
{{{ end }}}
|
|
96
|
+
{{{ if config.theme.enableQuickReply }}}
|
|
97
|
+
<!-- IMPORT partials/topic/quickreply.tpl -->
|
|
98
|
+
{{{ end }}}
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
{{{ if config.usePagination }}}
|
|
102
|
+
<!-- IMPORT partials/paginator.tpl -->
|
|
103
|
+
{{{ end }}}
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<!-- Right Sidebar with Topic Actions -->
|
|
107
|
+
<div class="topic-sidebar-container d-none d-lg-block" style="width: 200px; flex-shrink: 0;">
|
|
108
|
+
<!-- IMPORT partials/topic/sidebar.tpl -->
|
|
109
|
+
|
|
110
|
+
<!-- Additional Widgets (if any) -->
|
|
111
|
+
{{{ if widgets.sidebar.length }}}
|
|
112
|
+
<div data-widget-area="sidebar" class="mt-4">
|
|
113
|
+
{{{each widgets.sidebar}}}
|
|
114
|
+
{{widgets.sidebar.html}}
|
|
115
|
+
{{{end}}}
|
|
116
|
+
</div>
|
|
117
|
+
{{{ end }}}
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<div data-widget-area="footer">
|
|
124
|
+
{{{each widgets.footer}}}
|
|
125
|
+
{{widgets.footer.html}}
|
|
126
|
+
{{{end}}}
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
{{{ if !config.usePagination }}}
|
|
130
|
+
<noscript>
|
|
131
|
+
<!-- IMPORT partials/paginator.tpl -->
|
|
132
|
+
</noscript>
|
|
133
|
+
{{{ end }}}
|
package/theme.js
CHANGED
|
@@ -5,8 +5,64 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
+
const meta = require.main.require('./src/meta');
|
|
9
|
+
const user = require.main.require('./src/user');
|
|
10
|
+
const _ = require.main.require('lodash');
|
|
11
|
+
|
|
8
12
|
const theme = {};
|
|
9
13
|
|
|
14
|
+
// Harmony's defaults - we override openSidebars to 'on'
|
|
15
|
+
const defaults = {
|
|
16
|
+
enableQuickReply: 'on',
|
|
17
|
+
enableBreadcrumbs: 'on',
|
|
18
|
+
centerHeaderElements: 'off',
|
|
19
|
+
mobileTopicTeasers: 'off',
|
|
20
|
+
stickyToolbar: 'on',
|
|
21
|
+
topicSidebarTools: 'on',
|
|
22
|
+
topMobilebar: 'off',
|
|
23
|
+
autohideBottombar: 'on',
|
|
24
|
+
openSidebars: 'on', // JAVIS override: sidebar open by default
|
|
25
|
+
chatModals: 'off',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Load theme config - replaces Harmony's loadThemeConfig
|
|
30
|
+
* Uses JAVIS defaults (with openSidebars: 'on')
|
|
31
|
+
*/
|
|
32
|
+
async function loadThemeConfig(uid) {
|
|
33
|
+
const [themeConfig, userConfig] = await Promise.all([
|
|
34
|
+
meta.settings.get('harmony'),
|
|
35
|
+
user.getSettings(uid),
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
// 3-tier cascade: JAVIS defaults -> theme settings -> user settings
|
|
39
|
+
const config = { ...defaults, ...themeConfig, ...(_.pick(userConfig, Object.keys(defaults))) };
|
|
40
|
+
|
|
41
|
+
// Convert 'on'/'off' strings to boolean
|
|
42
|
+
config.enableQuickReply = config.enableQuickReply === 'on';
|
|
43
|
+
config.enableBreadcrumbs = config.enableBreadcrumbs === 'on';
|
|
44
|
+
config.centerHeaderElements = config.centerHeaderElements === 'on';
|
|
45
|
+
config.mobileTopicTeasers = config.mobileTopicTeasers === 'on';
|
|
46
|
+
config.stickyToolbar = config.stickyToolbar === 'on';
|
|
47
|
+
config.topicSidebarTools = config.topicSidebarTools === 'on';
|
|
48
|
+
config.autohideBottombar = config.autohideBottombar === 'on';
|
|
49
|
+
config.topMobilebar = config.topMobilebar === 'on';
|
|
50
|
+
config.openSidebars = config.openSidebars === 'on';
|
|
51
|
+
config.chatModals = config.chatModals === 'on';
|
|
52
|
+
|
|
53
|
+
return config;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Hook: filter:config.get
|
|
58
|
+
* Sets config.theme with JAVIS-specific defaults
|
|
59
|
+
*/
|
|
60
|
+
theme.getThemeConfig = async function (config) {
|
|
61
|
+
config.theme = await loadThemeConfig(config.uid);
|
|
62
|
+
config.openDraftsOnPageLoad = false;
|
|
63
|
+
return config;
|
|
64
|
+
};
|
|
65
|
+
|
|
10
66
|
theme.defineWidgetAreas = async (areas) => {
|
|
11
67
|
// Define widget areas like Harmony does
|
|
12
68
|
const locations = ['header', 'sidebar', 'footer'];
|
package/theme.scss
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
// JAVIS Custom Styles
|
|
13
13
|
@import "./scss/variables";
|
|
14
14
|
@import "./scss/base";
|
|
15
|
+
@import "./scss/header";
|
|
15
16
|
@import "./scss/buttons";
|
|
16
17
|
@import "./scss/forms";
|
|
17
18
|
@import "./scss/cards";
|
|
@@ -19,3 +20,4 @@
|
|
|
19
20
|
@import "./scss/sidebar-user";
|
|
20
21
|
@import "./scss/categories";
|
|
21
22
|
@import "./scss/feed";
|
|
23
|
+
@import "./scss/topic";
|