Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ plugins {
id 'java'
id "io.freefair.lombok" version "9.2.0"
id "com.github.node-gradle.node" version "7.1.0" apply false
id "run.halo.plugin.devtools" version "0.8.0"
id "run.halo.plugin.devtools" version "0.9.0"
}

group = 'run.halo.comment.widget'
Expand Down Expand Up @@ -141,6 +141,6 @@ tasks.named('clean') {
}

halo {
version = "2.26.0"
version = "2.27.0"
debug = true
}
10 changes: 5 additions & 5 deletions packages/comment-widget/src/base-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ export class BaseForm extends LitElement {
<button
@click=${this.handleLogout}
type="button"
class="form-logout shrink-0 text-xs text-text-3 hover:text-text-1 px-3 transition-[color,border-color,opacity] py-2 rounded-base border border-muted-3 opacity-100 hover:border-muted-4 hover:opacity-70 border-solid"
class="form-logout shrink-0 text-xs text-text-3 hover:text-text-1 px-3 transition-[color,border-color] py-2 rounded-base border border-muted-3 hover:border-muted-4 border-solid"
>
${msg('Logout')}
</button>
Expand Down Expand Up @@ -474,7 +474,7 @@ export class BaseForm extends LitElement {
<a
href=${this.loginUrl}
rel="nofollow"
class="form-login text-xs text-text-3 hover:text-text-1 px-3 transition-[color,border-color,opacity] py-2 rounded-base border border-muted-3 opacity-100 hover:border-muted-4 hover:opacity-70 border-solid"
class="form-login text-xs text-text-3 hover:text-text-1 px-3 transition-[color,border-color] py-2 rounded-base border border-muted-3 hover:border-muted-4 border-solid"
>
${msg('Login')}
</a>
Expand All @@ -500,7 +500,7 @@ export class BaseForm extends LitElement {
this.allowNotificationConfigurable,
() => html`<div class="flex items-center gap-2">
<input id="allowNotification" name="allowNotification" type="checkbox" checked />
<label for="allowNotification" class="text-xs select-none text-text-3 hover:text-text-1 transition-colors">${msg('Allow notification')}</label>
<label for="allowNotification" class="text-xs select-none text-text-3 hover:text-text-1 transition-colors">${msg('Allow Notification')}</label>
</div>`
)}

Expand All @@ -523,7 +523,7 @@ export class BaseForm extends LitElement {
<input
name="captchaCode"
type="text"
placeholder=${msg('Please enter the verification code')}
placeholder=${msg('Verification code…')}
aria-label=${msg('Please enter the verification code')}
autocomplete="off"
spellcheck="false"
Expand Down Expand Up @@ -559,7 +559,7 @@ export class BaseForm extends LitElement {
<button
.disabled=${this.busy}
type="submit"
class="form-submit outline-none focus-visible:shadow-input h-12 text-sm inline-flex border border-primary-1 border-solid items-center justify-center gap-2 bg-primary-1 text-primary-contrast px-3 rounded-base hover:opacity-80 transition-[opacity,box-shadow]"
class="form-submit outline-none focus-visible:shadow-input h-12 text-sm inline-flex border border-primary-1 border-solid items-center justify-center gap-2 bg-primary-1 text-primary-contrast px-3 rounded-base hover:brightness-95 transition-[filter,box-shadow]"
>
${when(
this.showLoading,
Expand Down
3 changes: 3 additions & 0 deletions packages/comment-widget/src/comment-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ export class CommentContent extends LitElement {
if (this.zoomedImage) void imageZoom?.close();
this.applyLinkAttributes();
this.renderRoot.querySelectorAll('.content img').forEach((image) => {
if (!image.hasAttribute('loading')) {
image.setAttribute('loading', 'lazy');
}
const anchor = image.closest('a');
if (anchor) {
// Split the link around the image, preserving linked text on both sides.
Expand Down
2 changes: 1 addition & 1 deletion packages/comment-widget/src/comment-detail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export class CommentDetail extends LitElement {
this.activeReplyItem?.closeReplyForm();
this.activeReplyItem = event.detail;
}}>
<button type="button" class="back text-sm text-primary-1" @click=${this.returnToList}>${msg('Back to comments')}</button>
<button type="button" class="back text-sm text-primary-1" @click=${this.returnToList}>${msg('Back to Comments')}</button>
${this.loading ? html`<loading-block></loading-block>` : this.error ? html`<p role="status" class="text-sm text-text-2 my-3">${this.error}</p>${this.retryable ? html`<button type="button" class="retry back text-sm text-primary-1" @click=${this.retry}>${msg('Retry')}</button>` : ''}` : keyed(this.requestId, html`<comment-item .comment=${this.comment} .detail=${true} .targetReply=${this.reply}></comment-item>`)}
</div>`;
}
Expand Down
22 changes: 20 additions & 2 deletions packages/comment-widget/src/comment-edit-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,23 @@ export class CommentEditForm extends LitElement {

override disconnectedCallback(): void {
this.removeEventListener('keydown', this.onKeydown);
window.removeEventListener('beforeunload', this.onBeforeUnload);
super.disconnectedCallback();
}

private onBeforeUnload = (event: BeforeUnloadEvent) => {
event.preventDefault();
event.returnValue = '';
};

private syncBeforeUnload() {
if (this.dirty) {
window.addEventListener('beforeunload', this.onBeforeUnload);
} else {
window.removeEventListener('beforeunload', this.onBeforeUnload);
}
}

private onKeydown = (event: KeyboardEvent) => {
if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
event.preventDefault();
Expand Down Expand Up @@ -137,6 +151,7 @@ export class CommentEditForm extends LitElement {
if (this.content === this.initialRaw) {
this.content = this.baseline;
}
this.syncBeforeUnload();
editor.setFocus();
}
}
Expand All @@ -146,6 +161,7 @@ export class CommentEditForm extends LitElement {
) {
this.content = event.detail.content;
this.errorMessage = '';
this.syncBeforeUnload();
}

private get hasContent() {
Expand Down Expand Up @@ -192,6 +208,7 @@ export class CommentEditForm extends LitElement {
}
);
this.toastManager?.success(msg('Comment updated successfully'));
window.removeEventListener('beforeunload', this.onBeforeUnload);
this.dispatchEvent(
new CustomEvent('comment-managed', {
bubbles: true,
Expand Down Expand Up @@ -230,6 +247,7 @@ export class CommentEditForm extends LitElement {
if (this.dirty && !window.confirm(msg('Discard your changes?'))) {
return;
}
window.removeEventListener('beforeunload', this.onBeforeUnload);
this.dispatchEvent(
new CustomEvent('edit-close', { bubbles: true, composed: true })
);
Expand Down Expand Up @@ -257,7 +275,7 @@ export class CommentEditForm extends LitElement {
<button
type="button"
@click=${() => void this.loadLatest()}
class="edit-form-retry outline-none focus-visible:shadow-input h-9 text-sm inline-flex items-center justify-center gap-2 bg-primary-1 text-primary-contrast px-4 rounded-base hover:opacity-80 transition-[opacity,box-shadow]"
class="edit-form-retry outline-none focus-visible:shadow-input h-9 text-sm inline-flex items-center justify-center gap-2 bg-primary-1 text-primary-contrast px-4 rounded-base hover:brightness-95 transition-[filter,box-shadow]"
>
${msg('Retry')}
</button>
Expand All @@ -282,7 +300,7 @@ export class CommentEditForm extends LitElement {
type="button"
?disabled=${!this.canSave}
@click=${this.handleSave}
class="edit-form-submit outline-none focus-visible:shadow-input h-9 text-sm inline-flex items-center justify-center gap-2 bg-primary-1 text-primary-contrast px-4 rounded-base hover:opacity-80 transition-[opacity,box-shadow] disabled:opacity-50 disabled:cursor-not-allowed"
class="edit-form-submit outline-none focus-visible:shadow-input h-9 text-sm inline-flex items-center justify-center gap-2 bg-primary-1 text-primary-contrast px-4 rounded-base hover:brightness-95 transition-[filter,box-shadow] disabled:opacity-50 disabled:cursor-not-allowed"
>
${when(this.saving, () => html`<icon-loading></icon-loading>`)}
${msg('Save')}
Expand Down
27 changes: 23 additions & 4 deletions packages/comment-widget/src/comment-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,23 @@ export class CommentItem extends LitElement {
}
}

private get repliesToggleUsesReplyForm() {
return !this.detail && !this.configMapData?.basic.withReplies;
}

private get repliesToggleExpanded() {
return this.repliesToggleUsesReplyForm
? this.showReplyForm
: this.showReplies;
}

private get repliesToggleLabel() {
if (this.repliesToggleUsesReplyForm) {
return this.showReplyForm ? msg('Cancel reply') : msg('Add Reply');
}
return this.showReplies ? msg('Hide Replies') : msg('Show Replies');
}

handleShowReplies() {
if (!this.detail && !this.configMapData?.basic.withReplies) {
this.handleToggleReplyForm();
Expand Down Expand Up @@ -192,7 +209,7 @@ export class CommentItem extends LitElement {
.private=${this.comment?.spec.hidden}
.editing=${this.showEditForm}
>
<button slot="action" class="icon-button group -ml-2" type="button" @click="${this.handleUpvote}" aria-label=${msg('Upvote')}>
<button slot="action" class="icon-button group -ml-2" type="button" @click="${this.handleUpvote}" aria-pressed=${this.upvoted}>
<div class="icon-button-icon">
${when(
this.upvoted,
Expand All @@ -202,6 +219,7 @@ export class CommentItem extends LitElement {
html`<i slot="icon" class="i-mingcute-heart-line size-4" aria-hidden="true"></i>`
)}
</div>
<span class="sr-only">${msg('Upvote')}</span>
<span class="icon-button-text">${`${this.upvoteCount || 0}`}</span>
</button>

Expand All @@ -210,22 +228,23 @@ export class CommentItem extends LitElement {
this.comment?.status?.visibleReplyCount === 0
? ''
: html`
<button slot="action" class="show-replies-button icon-button group" type="button" @click="${this.handleShowReplies}" aria-label=${msg('Show replies')}>
<button slot="action" class="show-replies-button icon-button group" type="button" @click="${this.handleShowReplies}" aria-expanded=${this.repliesToggleExpanded}>
<div class="icon-button-icon ">
<i slot="icon" class="i-tabler:message-circle size-4" aria-hidden="true"></i>
</div>
<span class="sr-only">${this.repliesToggleLabel}</span>
<span class="icon-button-text">${this.comment?.status?.visibleReplyCount || 0}</span>
</button>`
}

${when(
this.detail || this.configMapData?.basic.withReplies,
() => html`
<button slot="action" class="reply-button icon-button group" type="button" @click="${this.handleToggleReplyForm}" aria-label=${this.showReplyForm ? msg('Cancel reply') : msg('Add reply')}>
<button slot="action" class="reply-button icon-button group" type="button" @click="${this.handleToggleReplyForm}" aria-expanded=${this.showReplyForm} aria-label=${this.showReplyForm ? msg('Cancel reply') : msg('Add Reply')}>
<div class="icon-button-icon ">
<i slot="icon" class="i-tabler:message-circle-plus size-4" aria-hidden="true"></i>
</div>
<span class="icon-button-text">${this.showReplyForm ? msg('Cancel reply') : msg('Add reply')}</span>
<span class="icon-button-text">${this.showReplyForm ? msg('Cancel reply') : msg('Add Reply')}</span>
</button>
`
)}
Expand Down
65 changes: 61 additions & 4 deletions packages/comment-widget/src/comment-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,13 @@ export class CommentList extends LitElement {
@state()
loading = false;

@state()
loadFailed = false;

private requestId = 0;

private pageChangeShouldPush = false;

private activeReplyItem?: { closeReplyForm(): void };

private onReplyFormOpen(event: CustomEvent<{ closeReplyForm(): void }>) {
Expand All @@ -96,7 +101,11 @@ export class CommentList extends LitElement {
}

override disconnectedCallback(): void {
// Invalidate in-flight requests so a late response cannot rewrite the URL.
this.requestId++;
this.pageChangeShouldPush = false;
window.removeEventListener('halo:comment:created', this.onCommentCreated);
window.removeEventListener('popstate', this.onLocationChange);
this.activeReplyItem?.closeReplyForm();
this.activeReplyItem = undefined;
super.disconnectedCallback();
Expand All @@ -113,21 +122,59 @@ export class CommentList extends LitElement {
async onPageChange(e: CustomEvent) {
const data = e.detail;
this.comments.page = data.page;
this.pageChangeShouldPush = true;
await this.fetchComments({ scrollIntoView: true });
}

override connectedCallback(): void {
super.connectedCallback();
this.fetchComments();
this.fetchComments({ page: this.readPageFromUrl() });

// Handle halo:comment:created event, then reload the comment list
window.addEventListener('halo:comment:created', this.onCommentCreated);
window.addEventListener('popstate', this.onLocationChange);
}

private onCommentCreated = () => {
this.fetchComments({ page: 1, scrollIntoView: true });
};

private onLocationChange = () => {
this.pageChangeShouldPush = false;
const page = this.readPageFromUrl() ?? 1;
if (page !== this.comments.page) {
void this.fetchComments({ page, scrollIntoView: true });
}
};

private readPageFromUrl() {
const page = Number(
new URL(location.href).searchParams.get('comment-page')
);
return Number.isInteger(page) && page > 0 ? page : undefined;
}

private syncPageToUrl() {
const url = new URL(location.href);
const current = url.searchParams.get('comment-page');
const next = this.comments.page > 1 ? String(this.comments.page) : null;
if (current === next) {
this.pageChangeShouldPush = false;
return;
}
if (next === null) {
url.searchParams.delete('comment-page');
} else {
url.searchParams.set('comment-page', next);
}
if (this.pageChangeShouldPush) {
history.pushState(history.state, '', url);
} else {
history.replaceState(history.state, '', url);
}
this.pageChangeShouldPush = false;
}

async fetchComments(options?: {
page?: number;
scrollIntoView?: boolean;
Expand Down Expand Up @@ -184,9 +231,13 @@ export class CommentList extends LitElement {
}
}
if (requestId !== this.requestId) return;
this.loadFailed = false;
this.comments = data;
this.syncPageToUrl();
} catch (_error) {
if (requestId !== this.requestId) return;
this.pageChangeShouldPush = false;
this.loadFailed = true;
console.error(_error);
this.toastManager?.error(
msg('Failed to load comment list, please try again later')
Expand Down Expand Up @@ -214,9 +265,15 @@ export class CommentList extends LitElement {
? html` <loading-block></loading-block>`
: html`
<div class="comment-list-main mt-5">
<div class="comment-stats font-medium my-3 text-sm text-text-1">
<span>${msg(html`${this.comments.total} Comments`)}</span>
</div>
<h3 class="comment-stats font-medium my-3 text-sm text-text-1">
<span role="status" aria-live="polite">${msg(html`${this.comments.total} Comments`)}</span>
</h3>

${when(
this.comments.total === 0 && !this.loadFailed,
() =>
html`<p class="comment-empty text-sm text-text-3 py-4">${msg('No comments yet')}</p>`
)}

<div class="comment-list" @reply-form-open=${this.onReplyFormOpen} @comment-managed=${this.onCommentManaged}>
${repeat(
Expand Down
4 changes: 2 additions & 2 deletions packages/comment-widget/src/comment-management.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ export class CommentManagement extends LitElement {
: ''
}
<button type="button" ?disabled=${this.busy} @click=${() => this.run(this.target?.spec.approved ? 'unapprove' : 'approve')}>
${this.target.spec.approved ? msg('Cancel approval') : msg('Approve')}
${this.target.spec.approved ? msg('Cancel Approval') : msg('Approve')}
</button>
<button type="button" ?disabled=${this.busy} @click=${() => this.run(this.target?.spec.hidden ? 'unhide' : 'hide')}>
${this.target.spec.hidden ? msg('Make public') : msg('Make private')}
${this.target.spec.hidden ? msg('Make Public') : msg('Make Private')}
</button>
<button type="button" class="text-red-500" ?disabled=${this.busy} @click=${() => this.run('delete')}>
${msg('Delete')}
Expand Down
2 changes: 1 addition & 1 deletion packages/comment-widget/src/comment-replies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class CommentReplies extends LitElement {
)}
</div>`
)}
${when(this.targetOnly, () => html`<button type="button" class="replies-next-button pagination-button text-sm" aria-disabled=${this.loading} aria-busy=${this.loading} @click=${this.showAllReplies}>${msg('View all replies')}</button>`)}
${when(this.targetOnly, () => html`<button type="button" class="replies-next-button pagination-button text-sm" aria-disabled=${this.loading} aria-busy=${this.loading} @click=${this.showAllReplies}>${msg('View All Replies')}</button>`)}
${when(this.loading, () => html` <loading-block></loading-block>`)}
${when(
this.hasNext,
Expand Down
Loading
Loading