Move some MastodonComments logic to Alpine
This commit is contained in:
parent
328e84ccc7
commit
d85522e4e6
2 changed files with 185 additions and 199 deletions
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "gallery.badmanners.xyz",
|
||||
"type": "module",
|
||||
"version": "1.10.1",
|
||||
"version": "1.10.2",
|
||||
"scripts": {
|
||||
"postinstall": "astro sync",
|
||||
"dev": "astro dev",
|
||||
|
|
|
@ -18,34 +18,39 @@ const { link, instance, user, postId, blacklistedComments } = Astro.props;
|
|||
id="comments-section"
|
||||
class="px-2 font-serif"
|
||||
aria-describedby="title-comments-section"
|
||||
data-link={link}
|
||||
data-instance={instance}
|
||||
data-user={user}
|
||||
data-post-id={postId}
|
||||
data-blacklisted={(blacklistedComments ?? []).join(",")}
|
||||
x-data={`{ link: ${JSON.stringify(link)}, instance: ${JSON.stringify(instance)}, user: ${JSON.stringify(user)}, postId: ${JSON.stringify(postId)}, blacklistedComments: ${JSON.stringify(blacklistedComments ?? [])}, comments: null, commentsLoading: false, commentsError: null }`}
|
||||
@mastodon-comments.window="comments = $event.detail.comments; commentsLoading = false"
|
||||
@mastodon-comments-error.window="commentsError = $event.detail.error"
|
||||
>
|
||||
<h2 id="title-comments-section" class="py-2 font-serif text-xl font-semibold text-stone-800 dark:text-stone-100">
|
||||
Comments
|
||||
</h2>
|
||||
<p id="comments-description" class="my-1 text-stone-800 dark:text-stone-100">
|
||||
<span data-noscript
|
||||
<span x-show="false"
|
||||
><a class="u-syndication text-link underline" href={link} target="_blank">View comments on Mastodon</a>.</span
|
||||
>
|
||||
<span hidden data-no-comments
|
||||
<template x-if="commentsError === null && comments !== null && comments.length == 0">
|
||||
<span
|
||||
>No comments yet. <a class="text-link underline" href={link} target="_blank"
|
||||
>Be the first to join the conversation on Mastodon</a
|
||||
>.</span
|
||||
>
|
||||
<span hidden data-comments
|
||||
>Join the conversation <a class="text-link underline" href={link} target="_blank">by replying on Mastodon</a
|
||||
</template>
|
||||
<template x-if="commentsError === null && comments !== null && comments.length > 0"
|
||||
><span>
|
||||
Join the conversation <a class="text-link underline" href={link} target="_blank">by replying on Mastodon</a
|
||||
>.</span
|
||||
></template
|
||||
>
|
||||
<span hidden data-error>Unable to load comments. Please try again later.</span>
|
||||
<template x-if="commentsError">
|
||||
<span>Unable to load comments. Please try again later.</span>
|
||||
</template>
|
||||
</p>
|
||||
<template x-if="comments === null && !commentsError">
|
||||
<button
|
||||
hidden
|
||||
class="group mx-auto w-64 rounded-lg bg-bm-300 px-4 py-1 text-stone-800 disabled:bg-bm-400 dark:bg-green-800 dark:text-stone-100 dark:disabled:bg-green-900"
|
||||
id="load-comments-button"
|
||||
@click="if (!$el.disabled) { $el.disabled = true; commentsLoading = true; $dispatch('retrieveComments', { link, instance, user, postId, blacklistedComments })}"
|
||||
>
|
||||
<span class="block hover:underline group-focus:underline group-disabled:hidden">Click to load comments</span>
|
||||
<span class="hidden group-disabled:block">
|
||||
|
@ -66,7 +71,12 @@ const { link, instance, user, postId, blacklistedComments } = Astro.props;
|
|||
Loading...
|
||||
</span>
|
||||
</button>
|
||||
<div id="comments" hidden></div>
|
||||
</template>
|
||||
<div id="comments" x-show="comments !== null && comments.length > 0">
|
||||
<template x-for="comment in comments">
|
||||
<div x-html="comment"></div>
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<template id="template-comment-emoji">
|
||||
|
@ -111,14 +121,14 @@ const { link, instance, user, postId, blacklistedComments } = Astro.props;
|
|||
>
|
||||
</div>
|
||||
<div class="ml-1 flex flex-row pb-2 pt-1">
|
||||
<div class="flex" aria-label="Favorites">
|
||||
<span aria-label="Favorites">
|
||||
<span data-favorites></span>
|
||||
<IconStar width="1.25rem" height="1.25rem" class="ml-2" />
|
||||
</div>
|
||||
<div class="ml-4 flex" aria-label="Reblogs">
|
||||
<IconStar width="1.25rem" height="1.25rem" class="ml-1 inline align-text-bottom" />
|
||||
</span>
|
||||
<span aria-label="Reblogs" class="ml-6">
|
||||
<span data-reblogs></span>
|
||||
<IconRetweet width="1.25rem" height="1.25rem" class="ml-2" />
|
||||
</div>
|
||||
<IconRetweet width="1.25rem" height="1.25rem" class="ml-1 inline align-text-bottom" />
|
||||
</span>
|
||||
</div>
|
||||
<div data-comment-thread class="-mb-2" aria-hidden="true" aria-label="Replies"></div>
|
||||
</div>
|
||||
|
@ -165,9 +175,16 @@ const { link, instance, user, postId, blacklistedComments } = Astro.props;
|
|||
descendants: Status[];
|
||||
}
|
||||
|
||||
async function renderComments(section: Element, post: MastodonPost, blacklistedComments: Set<string>) {
|
||||
const commentsDescription = section.querySelector<HTMLElementTagNameMap["p"]>("p#comments-description")!;
|
||||
const loadCommentsButton = section.querySelector<HTMLElementTagNameMap["button"]>("button#load-comments-button")!;
|
||||
type RetrieveCommentsEvent = CustomEvent<{
|
||||
link: string;
|
||||
instance: string;
|
||||
user: string;
|
||||
postId: string;
|
||||
blacklistedComments: string[];
|
||||
}>;
|
||||
|
||||
if (document.querySelector("#comments-section")) {
|
||||
async function renderComments(post: MastodonPost, blacklistedComments: Set<string>) {
|
||||
try {
|
||||
const response = await fetch(`https://${post.instance}/api/v1/statuses/${post.postId}/context`);
|
||||
if (!response.ok) {
|
||||
|
@ -264,7 +281,7 @@ const { link, instance, user, postId, blacklistedComments } = Astro.props;
|
|||
if (comment.in_reply_to_id === post.postId || !(comment.in_reply_to_id in commentMap)) {
|
||||
commentMap[comment.id] = commentsList.length;
|
||||
commentsList.push(commentBox);
|
||||
} else if (commentMap[comment.in_reply_to_id]) {
|
||||
} else if (comment.in_reply_to_id in commentMap) {
|
||||
const commentsIndex = commentMap[comment.in_reply_to_id]!;
|
||||
commentMap[comment.id] = commentsIndex;
|
||||
const parentThreadDiv =
|
||||
|
@ -273,58 +290,27 @@ const { link, instance, user, postId, blacklistedComments } = Astro.props;
|
|||
parentThreadDiv.appendChild(commentBox);
|
||||
}
|
||||
});
|
||||
if (commentsList.length) {
|
||||
const fragment = document.createDocumentFragment();
|
||||
commentsList.forEach((comment) => fragment.appendChild(comment));
|
||||
commentsDescription.querySelector<HTMLElementTagNameMap["span"]>("span[data-comments]")!.hidden = false;
|
||||
const commentsDiv = section.querySelector<HTMLElementTagNameMap["div"]>("div#comments")!;
|
||||
commentsDiv.appendChild(fragment);
|
||||
commentsDiv.hidden = false;
|
||||
} else {
|
||||
commentsDescription.querySelector<HTMLElementTagNameMap["span"]>("span[data-no-comments]")!.hidden = false;
|
||||
}
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("mastodon-comments", {
|
||||
detail: {
|
||||
comments: commentsList.map((fragment) => {
|
||||
const div = document.createElement("div");
|
||||
div.appendChild(fragment);
|
||||
return div.innerHTML;
|
||||
}),
|
||||
},
|
||||
}),
|
||||
);
|
||||
console.log(commentsList);
|
||||
} catch (e) {
|
||||
console.error("Fetch Mastodon comments error", e);
|
||||
commentsDescription.querySelector<HTMLElementTagNameMap["span"]>("span[data-error]")!.hidden = false;
|
||||
} finally {
|
||||
loadCommentsButton.hidden = true;
|
||||
loadCommentsButton.blur();
|
||||
commentsDescription.hidden = false;
|
||||
window.dispatchEvent(new CustomEvent("mastodon-comments-error", { detail: { error: e } }));
|
||||
}
|
||||
}
|
||||
|
||||
function initCommentSection() {
|
||||
const commentSection = document.querySelector<HTMLElementTagNameMap["section"]>("section#comments-section");
|
||||
if (!commentSection) {
|
||||
return;
|
||||
document.addEventListener("retrieveComments", (e) => {
|
||||
const { link, instance, user, postId, blacklistedComments } = (e as RetrieveCommentsEvent).detail;
|
||||
renderComments({ link, instance, user, postId }, new Set(blacklistedComments));
|
||||
});
|
||||
}
|
||||
const post = {
|
||||
link: commentSection.dataset.link,
|
||||
instance: commentSection.dataset.instance,
|
||||
user: commentSection.dataset.user,
|
||||
postId: commentSection.dataset.postId,
|
||||
};
|
||||
if (!post.link || !post.instance || !post.user || !post.postId) {
|
||||
return;
|
||||
}
|
||||
const blacklisted = commentSection.dataset.blacklisted;
|
||||
const blacklistedComments = new Set(blacklisted ? blacklisted.split(",") : undefined);
|
||||
const loadCommentsButton =
|
||||
commentSection.querySelector<HTMLElementTagNameMap["button"]>("button#load-comments-button")!;
|
||||
loadCommentsButton.addEventListener(
|
||||
"click",
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
loadCommentsButton.disabled = true;
|
||||
renderComments(commentSection, post as MastodonPost, blacklistedComments);
|
||||
},
|
||||
{ once: true },
|
||||
);
|
||||
const commentsDescription = commentSection.querySelector<HTMLElementTagNameMap["p"]>("p#comments-description")!;
|
||||
commentsDescription.hidden = true;
|
||||
commentsDescription.querySelector<HTMLElementTagNameMap["span"]>("span[data-noscript]")!.hidden = true;
|
||||
loadCommentsButton.hidden = false;
|
||||
}
|
||||
|
||||
initCommentSection();
|
||||
</script>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue