Skip to content

Commit e7dcc2d

Browse files
committed
Comments: Moved to tab UI, Converted tabs component to ts
1 parent 099f610 commit e7dcc2d

File tree

8 files changed

+115
-53
lines changed

8 files changed

+115
-53
lines changed

app/Activity/Tools/CommentTree.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function enabled(): bool
2828

2929
public function empty(): bool
3030
{
31-
return count($this->tree) === 0;
31+
return count($this->getActive()) === 0;
3232
}
3333

3434
public function count(): int
@@ -41,11 +41,21 @@ public function getActive(): array
4141
return array_filter($this->tree, fn (CommentTreeNode $node) => !$node->comment->archived);
4242
}
4343

44+
public function activeThreadCount(): int
45+
{
46+
return count($this->getActive());
47+
}
48+
4449
public function getArchived(): array
4550
{
4651
return array_filter($this->tree, fn (CommentTreeNode $node) => $node->comment->archived);
4752
}
4853

54+
public function archivedThreadCount(): int
55+
{
56+
return count($this->getArchived());
57+
}
58+
4959
public function getCommentNodeForId(int $commentId): ?CommentTreeNode
5060
{
5161
foreach ($this->tree as $node) {

lang/en/entities.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,9 +392,10 @@
392392
'comment' => 'Comment',
393393
'comments' => 'Comments',
394394
'comment_add' => 'Add Comment',
395-
'comment_archived' => ':count Archived Comment|:count Archived Comments',
395+
'comment_none' => 'No comments to display',
396396
'comment_placeholder' => 'Leave a comment here',
397-
'comment_count' => '{0} No Comments|{1} 1 Comment|[2,*] :count Comments',
397+
'comment_thread_count' => ':count Comment Thread|:count Comment Threads',
398+
'comment_archived_count' => ':count Archived',
398399
'comment_save' => 'Save Comment',
399400
'comment_new' => 'New Comment',
400401
'comment_created' => 'commented :createDiff',

resources/js/components/page-comment.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ export class PageComment extends Component {
140140
const action = isArchived ? 'unarchive' : 'archive';
141141

142142
const response = await window.$http.put(`/comment/${this.commentId}/${action}`);
143-
this.$emit(action, {new_thread_dom: htmlToDom(response.data as string)});
144143
window.$events.success(this.archiveText);
144+
this.$emit(action, {new_thread_dom: htmlToDom(response.data as string)});
145145
this.container.closest('.comment-branch')?.remove();
146146
}
147147

resources/js/components/page-comments.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {Component} from './component';
22
import {getLoading, htmlToDom} from '../services/dom.ts';
33
import {buildForInput} from '../wysiwyg-tinymce/config';
4+
import {Tabs} from "./tabs";
45

56
export interface CommentReplyEvent extends Event {
67
detail: {
@@ -21,7 +22,8 @@ export class PageComments extends Component {
2122
private pageId: number;
2223
private container: HTMLElement;
2324
private commentCountBar: HTMLElement;
24-
private commentsTitle: HTMLElement;
25+
private activeTab: HTMLElement;
26+
private archivedTab: HTMLElement;
2527
private addButtonContainer: HTMLElement;
2628
private archiveContainer: HTMLElement;
2729
private replyToRow: HTMLElement;
@@ -37,6 +39,7 @@ export class PageComments extends Component {
3739
private wysiwygEditor: any = null;
3840
private createdText: string;
3941
private countText: string;
42+
private archivedCountText: string;
4043
private parentId: number | null = null;
4144
private contentReference: string = '';
4245
private formReplyText: string = '';
@@ -48,7 +51,8 @@ export class PageComments extends Component {
4851
// Element references
4952
this.container = this.$refs.commentContainer;
5053
this.commentCountBar = this.$refs.commentCountBar;
51-
this.commentsTitle = this.$refs.commentsTitle;
54+
this.activeTab = this.$refs.activeTab;
55+
this.archivedTab = this.$refs.archivedTab;
5256
this.addButtonContainer = this.$refs.addButtonContainer;
5357
this.archiveContainer = this.$refs.archiveContainer;
5458
this.replyToRow = this.$refs.replyToRow;
@@ -67,6 +71,7 @@ export class PageComments extends Component {
6771
// Translations
6872
this.createdText = this.$opts.createdText;
6973
this.countText = this.$opts.countText;
74+
this.archivedCountText = this.$opts.archivedCountText;
7075

7176
this.formReplyText = this.formReplyLink?.textContent || '';
7277

@@ -85,10 +90,12 @@ export class PageComments extends Component {
8590

8691
this.elem.addEventListener('page-comment-archive', (event: ArchiveEvent) => {
8792
this.archiveContainer.append(event.detail.new_thread_dom);
93+
setTimeout(() => this.updateCount(), 1);
8894
});
8995

9096
this.elem.addEventListener('page-comment-unarchive', (event: ArchiveEvent) => {
91-
this.container.append(event.detail.new_thread_dom)
97+
this.container.append(event.detail.new_thread_dom);
98+
setTimeout(() => this.updateCount(), 1);
9299
});
93100

94101
if (this.form) {
@@ -136,8 +143,10 @@ export class PageComments extends Component {
136143
}
137144

138145
protected updateCount(): void {
139-
const count = this.getCommentCount();
140-
this.commentsTitle.textContent = window.$trans.choice(this.countText, count);
146+
const activeCount = this.getActiveThreadCount();
147+
this.activeTab.textContent = window.$trans.choice(this.countText, activeCount);
148+
const archivedCount = this.getArchivedThreadCount();
149+
this.archivedTab.textContent = window.$trans.choice(this.archivedCountText, archivedCount);
141150
}
142151

143152
protected resetForm(): void {
@@ -155,12 +164,18 @@ export class PageComments extends Component {
155164
this.addButtonContainer.toggleAttribute('hidden', true);
156165
this.formContainer.scrollIntoView({behavior: 'smooth', block: 'nearest'});
157166
this.loadEditor();
167+
168+
// Ensure the active comments tab is displaying
169+
const tabs = window.$components.firstOnElement(this.elem, 'tabs');
170+
if (tabs instanceof Tabs) {
171+
tabs.show('comment-tab-panel-active');
172+
}
158173
}
159174

160175
protected hideForm(): void {
161176
this.resetForm();
162177
this.formContainer.toggleAttribute('hidden', true);
163-
if (this.getCommentCount() > 0) {
178+
if (this.getActiveThreadCount() > 0) {
164179
this.elem.append(this.addButtonContainer);
165180
} else {
166181
this.commentCountBar.append(this.addButtonContainer);
@@ -198,8 +213,12 @@ export class PageComments extends Component {
198213
}
199214
}
200215

201-
protected getCommentCount(): number {
202-
return this.container.querySelectorAll('[component="page-comment"]').length;
216+
protected getActiveThreadCount(): number {
217+
return this.container.querySelectorAll(':scope > .comment-branch:not([hidden])').length;
218+
}
219+
220+
protected getArchivedThreadCount(): number {
221+
return this.archiveContainer.querySelectorAll(':scope > .comment-branch').length;
203222
}
204223

205224
protected setReply(commentLocalId, commentElement): void {
Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,25 @@ import {Component} from './component';
1919
*/
2020
export class Tabs extends Component {
2121

22+
protected container: HTMLElement;
23+
protected tabList: HTMLElement;
24+
protected tabs: HTMLElement[];
25+
protected panels: HTMLElement[];
26+
27+
protected activeUnder: number;
28+
protected active: null|boolean = null;
29+
2230
setup() {
2331
this.container = this.$el;
24-
this.tabList = this.container.querySelector('[role="tablist"]');
32+
this.tabList = this.container.querySelector('[role="tablist"]') as HTMLElement;
2533
this.tabs = Array.from(this.tabList.querySelectorAll('[role="tab"]'));
2634
this.panels = Array.from(this.container.querySelectorAll(':scope > [role="tabpanel"], :scope > * > [role="tabpanel"]'));
2735
this.activeUnder = this.$opts.activeUnder ? Number(this.$opts.activeUnder) : 10000;
28-
this.active = null;
2936

3037
this.container.addEventListener('click', event => {
31-
const tab = event.target.closest('[role="tab"]');
32-
if (tab && this.tabs.includes(tab)) {
33-
this.show(tab.getAttribute('aria-controls'));
38+
const tab = (event.target as HTMLElement).closest('[role="tab"]');
39+
if (tab instanceof HTMLElement && this.tabs.includes(tab)) {
40+
this.show(tab.getAttribute('aria-controls') || '');
3441
}
3542
});
3643

@@ -40,7 +47,7 @@ export class Tabs extends Component {
4047
this.updateActiveState();
4148
}
4249

43-
show(sectionId) {
50+
public show(sectionId: string): void {
4451
for (const panel of this.panels) {
4552
panel.toggleAttribute('hidden', panel.id !== sectionId);
4653
}
@@ -54,7 +61,7 @@ export class Tabs extends Component {
5461
this.$emit('change', {showing: sectionId});
5562
}
5663

57-
updateActiveState() {
64+
protected updateActiveState(): void {
5865
const active = window.innerWidth < this.activeUnder;
5966
if (active === this.active) {
6067
return;
@@ -69,13 +76,13 @@ export class Tabs extends Component {
6976
this.active = active;
7077
}
7178

72-
activate() {
79+
protected activate(): void {
7380
const panelToShow = this.panels.find(p => !p.hasAttribute('hidden')) || this.panels[0];
7481
this.show(panelToShow.id);
7582
this.tabList.toggleAttribute('hidden', false);
7683
}
7784

78-
deactivate() {
85+
protected deactivate(): void {
7986
for (const panel of this.panels) {
8087
panel.removeAttribute('hidden');
8188
}

resources/sass/_components.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,13 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
802802
display: block;
803803
}
804804

805+
.comment-container .empty-state {
806+
display: none;
807+
}
808+
.comment-container:not(:has([component="page-comment"])) .empty-state {
809+
display: block;
810+
}
811+
805812
.comment-container-compact .comment-box {
806813
margin-bottom: vars.$xs;
807814
.meta {

resources/views/comments/comments.blade.php

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,73 @@
1-
<section component="page-comments"
1+
<section components="page-comments tabs"
22
option:page-comments:page-id="{{ $page->id }}"
33
option:page-comments:created-text="{{ trans('entities.comment_created_success') }}"
4-
option:page-comments:count-text="{{ trans('entities.comment_count') }}"
4+
option:page-comments:count-text="{{ trans('entities.comment_thread_count') }}"
5+
option:page-comments:archived-count-text="{{ trans('entities.comment_archived_count') }}"
56
option:page-comments:wysiwyg-language="{{ $locale->htmlLang() }}"
67
option:page-comments:wysiwyg-text-direction="{{ $locale->htmlDirection() }}"
7-
class="comments-list"
8+
class="comments-list tab-container"
89
aria-label="{{ trans('entities.comments') }}">
910

10-
<div refs="page-comments@comment-count-bar" class="grid half left-focus v-center no-row-gap">
11-
<h5 refs="page-comments@comments-title">{{ trans_choice('entities.comment_count', $commentTree->count(), ['count' => $commentTree->count()]) }}</h5>
11+
<div refs="page-comments@comment-count-bar" class="flex-container-row items-center">
12+
<div role="tablist" class="flex">
13+
<button type="button"
14+
role="tab"
15+
id="comment-tab-active"
16+
aria-controls="comment-tab-panel-active"
17+
refs="page-comments@active-tab"
18+
aria-selected="true">{{ trans_choice('entities.comment_thread_count', $commentTree->activeThreadCount()) }}</button>
19+
<button type="button"
20+
role="tab"
21+
id="comment-tab-archived"
22+
aria-controls="comment-tab-panel-archived"
23+
refs="page-comments@archived-tab"
24+
aria-selected="false">{{ trans_choice('entities.comment_archived_count', count($commentTree->getArchived())) }}</button>
25+
</div>
1226
@if ($commentTree->empty() && userCan('comment-create-all'))
13-
<div class="text-m-right" refs="page-comments@add-button-container">
27+
<div class="ml-m" refs="page-comments@add-button-container">
1428
<button type="button"
1529
refs="page-comments@add-comment-button"
16-
class="button outline">{{ trans('entities.comment_add') }}</button>
30+
class="button outline mb-m">{{ trans('entities.comment_add') }}</button>
1731
</div>
1832
@endif
1933
</div>
2034

21-
<div refs="page-comments@comment-container" class="comment-container">
22-
@foreach($commentTree->getActive() as $branch)
23-
@include('comments.comment-branch', ['branch' => $branch, 'readOnly' => false])
24-
@endforeach
25-
</div>
35+
<div id="comment-tab-panel-active"
36+
tabindex="0"
37+
role="tabpanel"
38+
aria-labelledby="comment-tab-active"
39+
class="comment-container">
40+
<div refs="page-comments@comment-container">
41+
@foreach($commentTree->getActive() as $branch)
42+
@include('comments.comment-branch', ['branch' => $branch, 'readOnly' => false])
43+
@endforeach
44+
</div>
2645

27-
@if(userCan('comment-create-all'))
28-
@include('comments.create')
29-
@if (!$commentTree->empty())
30-
<div refs="page-comments@addButtonContainer" class="flex-container-row">
31-
32-
<button type="button"
33-
refs="page-comments@show-archived-button"
34-
class="text-button hover-underline">{{ trans_choice('entities.comment_archived', count($commentTree->getArchived())) }}</button>
46+
<p class="text-center text-muted italic empty-state">{{ trans('entities.comment_none') }}</p>
3547

36-
<button type="button"
37-
refs="page-comments@add-comment-button"
38-
class="button outline ml-auto">{{ trans('entities.comment_add') }}</button>
39-
</div>
48+
@if(userCan('comment-create-all'))
49+
@include('comments.create')
50+
@if (!$commentTree->empty())
51+
<div refs="page-comments@addButtonContainer" class="flex-container-row">
52+
<button type="button"
53+
refs="page-comments@add-comment-button"
54+
class="button outline ml-auto">{{ trans('entities.comment_add') }}</button>
55+
</div>
56+
@endif
4057
@endif
41-
@endif
58+
</div>
4259

43-
<div refs="page-comments@archive-container" class="comment-container">
60+
<div refs="page-comments@archive-container"
61+
id="comment-tab-panel-archived"
62+
tabindex="0"
63+
role="tabpanel"
64+
aria-labelledby="comment-tab-archived"
65+
hidden="hidden"
66+
class="comment-container">
4467
@foreach($commentTree->getArchived() as $branch)
4568
@include('comments.comment-branch', ['branch' => $branch, 'readOnly' => false])
4669
@endforeach
70+
<p class="text-center text-muted italic empty-state">{{ trans('entities.comment_none') }}</p>
4771
</div>
4872

4973
@if(userCan('comment-create-all') || $commentTree->canUpdateAny())

resources/views/pages/show.blade.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,6 @@ class="page-content clearfix">
2828
@include('entities.sibling-navigation', ['next' => $next, 'previous' => $previous])
2929

3030
@if ($commentTree->enabled())
31-
@if(($previous || $next))
32-
<div class="px-xl print-hidden">
33-
<hr class="darker">
34-
</div>
35-
@endif
36-
3731
<div class="comments-container mb-l print-hidden">
3832
@include('comments.comments', ['commentTree' => $commentTree, 'page' => $page])
3933
<div class="clearfix"></div>

0 commit comments

Comments
 (0)