@okjavis/nodebb-theme-javis 3.0.5 → 3.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/scss/_cards.scss
CHANGED
|
@@ -61,25 +61,36 @@
|
|
|
61
61
|
cursor: pointer;
|
|
62
62
|
border-radius: $jv-radius-xs;
|
|
63
63
|
transition: color 0.15s ease, background-color 0.15s ease;
|
|
64
|
+
text-decoration: none;
|
|
64
65
|
|
|
65
66
|
&:hover {
|
|
66
67
|
background: rgba(0, 0, 0, 0.06);
|
|
68
|
+
text-decoration: none;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
// Upvote - orange/red on hover and when active
|
|
72
|
+
&.vote-up:hover,
|
|
73
|
+
&.vote-up.upvoted {
|
|
70
74
|
color: #ff4500; // Reddit orange-red
|
|
75
|
+
background: rgba(255, 69, 0, 0.1);
|
|
71
76
|
}
|
|
72
77
|
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
// Downvote - blue/periwinkle on hover and when active
|
|
79
|
+
&.vote-down:hover,
|
|
80
|
+
&.vote-down.downvoted {
|
|
81
|
+
color: #7193ff; // Reddit periwinkle/blue
|
|
82
|
+
background: rgba(113, 147, 255, 0.1);
|
|
75
83
|
}
|
|
76
84
|
|
|
85
|
+
// Legacy active class support
|
|
77
86
|
&.active.vote-up {
|
|
78
87
|
color: #ff4500;
|
|
88
|
+
background: rgba(255, 69, 0, 0.1);
|
|
79
89
|
}
|
|
80
90
|
|
|
81
91
|
&.active.vote-down {
|
|
82
92
|
color: #7193ff;
|
|
93
|
+
background: rgba(113, 147, 255, 0.1);
|
|
83
94
|
}
|
|
84
95
|
|
|
85
96
|
i {
|
package/static/lib/theme.js
CHANGED
|
@@ -33,6 +33,12 @@
|
|
|
33
33
|
// Initialize click handler for composer prompt card (rendered server-side in feed.tpl)
|
|
34
34
|
initFeedComposerPromptHandler();
|
|
35
35
|
|
|
36
|
+
// Initialize voting handlers for category/topics listing pages
|
|
37
|
+
initTopicListVoting();
|
|
38
|
+
|
|
39
|
+
// Initialize immediate category filter navigation on feed page
|
|
40
|
+
initFeedCategoryFilter();
|
|
41
|
+
|
|
36
42
|
// Re-initialize carousels when new posts are loaded (infinite scroll, etc.)
|
|
37
43
|
// Also handle post edits by clearing the processed flag
|
|
38
44
|
$(window).on('action:posts.loaded action:topic.loaded action:ajaxify.end', function() {
|
|
@@ -40,6 +46,8 @@
|
|
|
40
46
|
initParentPostNavigation();
|
|
41
47
|
initPostHoverActions();
|
|
42
48
|
initFeedComposerPromptHandler();
|
|
49
|
+
initTopicListVoting();
|
|
50
|
+
initFeedCategoryFilter();
|
|
43
51
|
});
|
|
44
52
|
|
|
45
53
|
// Handle post edits - need to re-process the edited post
|
|
@@ -497,4 +505,169 @@
|
|
|
497
505
|
});
|
|
498
506
|
}
|
|
499
507
|
|
|
508
|
+
/**
|
|
509
|
+
* Initialize voting handlers for topic listing pages (category, recent, etc.)
|
|
510
|
+
* NodeBB's native voting only works on topic detail pages, so we add custom handlers here
|
|
511
|
+
*/
|
|
512
|
+
function initTopicListVoting() {
|
|
513
|
+
// Only run on pages with topic listings (not on topic detail page)
|
|
514
|
+
if ($('[component="topic"]').length) {
|
|
515
|
+
// We're on a topic detail page, NodeBB handles voting natively
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Find vote columns that haven't been initialized
|
|
520
|
+
$('.vote-column:not([data-vote-initialized])').each(function() {
|
|
521
|
+
var $voteColumn = $(this);
|
|
522
|
+
$voteColumn.attr('data-vote-initialized', 'true');
|
|
523
|
+
|
|
524
|
+
var pid = $voteColumn.attr('data-pid');
|
|
525
|
+
if (!pid) return;
|
|
526
|
+
|
|
527
|
+
var $upvoteBtn = $voteColumn.find('[component="post/upvote"]');
|
|
528
|
+
var $downvoteBtn = $voteColumn.find('[component="post/downvote"]');
|
|
529
|
+
var $voteCount = $voteColumn.find('[component="post/vote-count"]');
|
|
530
|
+
|
|
531
|
+
// Upvote click handler
|
|
532
|
+
$upvoteBtn.on('click', function(e) {
|
|
533
|
+
e.preventDefault();
|
|
534
|
+
e.stopPropagation();
|
|
535
|
+
|
|
536
|
+
if (!config.loggedIn) {
|
|
537
|
+
window.location.href = config.relative_path + '/login';
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
var isUpvoted = $upvoteBtn.hasClass('upvoted');
|
|
542
|
+
var method = isUpvoted ? 'del' : 'put';
|
|
543
|
+
|
|
544
|
+
$.ajax({
|
|
545
|
+
url: config.relative_path + '/api/v3/posts/' + pid + '/vote',
|
|
546
|
+
method: method,
|
|
547
|
+
data: JSON.stringify({ delta: 1 }),
|
|
548
|
+
contentType: 'application/json',
|
|
549
|
+
headers: {
|
|
550
|
+
'x-csrf-token': config.csrf_token
|
|
551
|
+
},
|
|
552
|
+
success: function(response) {
|
|
553
|
+
// Toggle upvoted state
|
|
554
|
+
$upvoteBtn.toggleClass('upvoted');
|
|
555
|
+
// Remove downvoted if it was set
|
|
556
|
+
$downvoteBtn.removeClass('downvoted');
|
|
557
|
+
|
|
558
|
+
// Update vote count
|
|
559
|
+
if (response && response.response) {
|
|
560
|
+
var votes = response.response.post ? response.response.post.votes : response.response.votes;
|
|
561
|
+
if (votes !== undefined) {
|
|
562
|
+
$voteCount.text(votes);
|
|
563
|
+
$voteCount.attr('data-votes', votes);
|
|
564
|
+
$voteCount.attr('title', votes);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
},
|
|
568
|
+
error: function(xhr) {
|
|
569
|
+
var msg = xhr.responseJSON && xhr.responseJSON.status && xhr.responseJSON.status.message;
|
|
570
|
+
if (msg) {
|
|
571
|
+
alert(msg);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
// Downvote click handler
|
|
578
|
+
$downvoteBtn.on('click', function(e) {
|
|
579
|
+
e.preventDefault();
|
|
580
|
+
e.stopPropagation();
|
|
581
|
+
|
|
582
|
+
if (!config.loggedIn) {
|
|
583
|
+
window.location.href = config.relative_path + '/login';
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
var isDownvoted = $downvoteBtn.hasClass('downvoted');
|
|
588
|
+
var method = isDownvoted ? 'del' : 'put';
|
|
589
|
+
|
|
590
|
+
$.ajax({
|
|
591
|
+
url: config.relative_path + '/api/v3/posts/' + pid + '/vote',
|
|
592
|
+
method: method,
|
|
593
|
+
data: JSON.stringify({ delta: -1 }),
|
|
594
|
+
contentType: 'application/json',
|
|
595
|
+
headers: {
|
|
596
|
+
'x-csrf-token': config.csrf_token
|
|
597
|
+
},
|
|
598
|
+
success: function(response) {
|
|
599
|
+
// Toggle downvoted state
|
|
600
|
+
$downvoteBtn.toggleClass('downvoted');
|
|
601
|
+
// Remove upvoted if it was set
|
|
602
|
+
$upvoteBtn.removeClass('upvoted');
|
|
603
|
+
|
|
604
|
+
// Update vote count
|
|
605
|
+
if (response && response.response) {
|
|
606
|
+
var votes = response.response.post ? response.response.post.votes : response.response.votes;
|
|
607
|
+
if (votes !== undefined) {
|
|
608
|
+
$voteCount.text(votes);
|
|
609
|
+
$voteCount.attr('data-votes', votes);
|
|
610
|
+
$voteCount.attr('title', votes);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
},
|
|
614
|
+
error: function(xhr) {
|
|
615
|
+
var msg = xhr.responseJSON && xhr.responseJSON.status && xhr.responseJSON.status.message;
|
|
616
|
+
if (msg) {
|
|
617
|
+
alert(msg);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
});
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Initialize immediate category filter navigation on feed page
|
|
627
|
+
* When a category is selected, navigate immediately instead of waiting for dropdown close
|
|
628
|
+
*/
|
|
629
|
+
function initFeedCategoryFilter() {
|
|
630
|
+
// Only run on feed page
|
|
631
|
+
if (!$('.feed').length) {
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
var $categoryDropdown = $('.feed-category-filter [component="category/dropdown"]');
|
|
636
|
+
if (!$categoryDropdown.length || $categoryDropdown.attr('data-filter-initialized')) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
$categoryDropdown.attr('data-filter-initialized', 'true');
|
|
640
|
+
|
|
641
|
+
// Handle category selection - navigate immediately
|
|
642
|
+
$categoryDropdown.on('click', '[component="category/list"] [data-cid]', function(e) {
|
|
643
|
+
e.preventDefault();
|
|
644
|
+
e.stopPropagation();
|
|
645
|
+
|
|
646
|
+
var $item = $(this);
|
|
647
|
+
var cid = $item.attr('data-cid');
|
|
648
|
+
var currentParams = utils.params();
|
|
649
|
+
|
|
650
|
+
// Build the new URL
|
|
651
|
+
if (cid === 'all') {
|
|
652
|
+
delete currentParams.cid;
|
|
653
|
+
} else {
|
|
654
|
+
currentParams.cid = cid;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Remove page parameter to start from first page
|
|
658
|
+
delete currentParams.page;
|
|
659
|
+
|
|
660
|
+
var url = '/feed';
|
|
661
|
+
if (Object.keys(currentParams).length) {
|
|
662
|
+
url += '?' + $.param(currentParams);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// Close the dropdown
|
|
666
|
+
$categoryDropdown.find('.dropdown-toggle').dropdown('hide');
|
|
667
|
+
|
|
668
|
+
// Navigate to the filtered feed
|
|
669
|
+
ajaxify.go(url);
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
|
|
500
673
|
})();
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
<div class="javis-sidebar-logo">
|
|
4
4
|
<a href="{relative_path}/" class="javis-logo-link" title="JAVIS Community">
|
|
5
5
|
<!-- Icon logo (shown when collapsed) -->
|
|
6
|
-
<img src="{relative_path}/plugins/nodebb-theme-javis/static/images/logo-icon.png" alt="JAVIS" class="javis-logo-icon visible-closed" />
|
|
6
|
+
<img src="{relative_path}/plugins/@okjavis/nodebb-theme-javis/static/images/logo-icon.png" alt="JAVIS" class="javis-logo-icon visible-closed" />
|
|
7
7
|
<!-- Full logo (shown when expanded) -->
|
|
8
|
-
<img src="{relative_path}/plugins/nodebb-theme-javis/static/images/logo-full.png" alt="JAVIS Community" class="javis-logo-full visible-open" />
|
|
8
|
+
<img src="{relative_path}/plugins/@okjavis/nodebb-theme-javis/static/images/logo-full.png" alt="JAVIS Community" class="javis-logo-full visible-open" />
|
|
9
9
|
</a>
|
|
10
10
|
</div>
|
|
11
11
|
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
|
|
15
15
|
<!-- Vote Column (Reddit-style) -->
|
|
16
16
|
{{{ if !reputation:disabled }}}
|
|
17
|
-
<div class="vote-column">
|
|
18
|
-
<
|
|
17
|
+
<div class="vote-column" data-pid="{./mainPid}">
|
|
18
|
+
<a component="post/upvote" href="#" class="vote-btn vote-up{{{ if ./upvoted }}} upvoted{{{ end }}}" title="[[topic:upvote]]">
|
|
19
19
|
<i class="fa fa-chevron-up"></i>
|
|
20
|
-
</
|
|
21
|
-
<span class="vote-count" title="{./votes}">{humanReadableNumber(./votes, 0)}</span>
|
|
22
|
-
<
|
|
20
|
+
</a>
|
|
21
|
+
<span component="post/vote-count" class="vote-count" data-votes="{./votes}" title="{./votes}">{humanReadableNumber(./votes, 0)}</span>
|
|
22
|
+
<a component="post/downvote" href="#" class="vote-btn vote-down{{{ if ./downvoted }}} downvoted{{{ end }}}" title="[[topic:downvote]]">
|
|
23
23
|
<i class="fa fa-chevron-down"></i>
|
|
24
|
-
</
|
|
24
|
+
</a>
|
|
25
25
|
</div>
|
|
26
26
|
{{{ end }}}
|
|
27
27
|
|