From 499bba129c842c00c1a28d85bc044ab609aee44e Mon Sep 17 00:00:00 2001 From: Joe Mou Date: Mon, 21 Sep 2026 17:55:06 -0400 Subject: Add discussions Discussions are served from GitHub's older server-rendered HTML, with no embeddedData JSON to read, so the scraper walks the DOM the way the pull request and wiki code does. A discussion's timeline opens with its own post and continues with its comments, each carrying its replies nested inside it, which is where the recursion in _discussionComment.eta comes from. Categories, upvotes, and the answer a Q&A discussion is marked with all come along. Only what GitHub renders up front is shown: neither the next page of discussions nor the replies it hides behind a "Show N previous replies" button are fetched, so a comment says how many replies it is missing. Co-Authored-By: Claude Opus 5 --- views/_discussionComment.eta | 37 +++++++++++++++++++++++++++++++++++++ views/discussion.eta | 29 +++++++++++++++++++++++++++++ views/discussions.eta | 39 +++++++++++++++++++++++++++++++++++++++ views/layouts/repo.eta | 2 ++ 4 files changed, 107 insertions(+) create mode 100644 views/_discussionComment.eta create mode 100644 views/discussion.eta create mode 100644 views/discussions.eta (limited to 'views') diff --git a/views/_discussionComment.eta b/views/_discussionComment.eta new file mode 100644 index 0000000..9c2cc07 --- /dev/null +++ b/views/_discussionComment.eta @@ -0,0 +1,37 @@ +
<%= it.reply ? " reply" : "" %>" id="<%= it.comment.anchor %>"> +<% if (it.comment.hiddenReason) { %> +
<%= it.comment.hiddenReason %>
+<% } else { %> +
+ + <% if (it.comment.author) { %> + <%= it.comment.author %> + <% } else { %> + ghost + <% } %> + <% for (const label of it.comment.labels) { %> + <%= label %> + <% } %> + <% if (it.comment.isAnswer) { %> + Answer + <% } %> + + + <% if (it.comment.createdAt) { %> + + <% } %> + +
+ <%~ it.comment.bodyHtml %> +<% } %> +
+ +<% if (it.comment.hiddenReplies > 0) { %> +
+ <%= it.comment.hiddenReplies %> earlier + <%= it.comment.hiddenReplies === 1 ? "reply is" : "replies are" %> only on GitHub. +
+<% } %> +<% for (const reply of it.comment.replies) { %> + <%~ include("./_discussionComment.eta", { comment: reply, reply: true }) %> +<% } %> diff --git a/views/discussion.eta b/views/discussion.eta new file mode 100644 index 0000000..f87189e --- /dev/null +++ b/views/discussion.eta @@ -0,0 +1,29 @@ +<% +layout("/layouts/repo.eta") +it.path = `discussions/${it.number}` +it.searchType = "discussions" +%> + +
+

<%~ it.titleHtml %>

+ + #<%= it.number %> + <% if (it.category) { %> + in <%= it.category.name %> + <% } %> + <% if (it.answerAnchor) { %> + Answered + <% } %> +
+ +<%~ include("./_discussionComment.eta", { comment: it.body }) %> + +<% if (it.answerAnchor) { %> + +
↓ Show answer
+
+<% } %> + +<% for (const comment of it.comments) { %> + <%~ include("./_discussionComment.eta", { comment }) %> +<% } %> diff --git a/views/discussions.eta b/views/discussions.eta new file mode 100644 index 0000000..87a6903 --- /dev/null +++ b/views/discussions.eta @@ -0,0 +1,39 @@ +<% +layout("/layouts/repo.eta") +it.path = it.category ? `discussions/${it.category.slug}` : "discussions" +it.searchType = "discussions" +%> + + + +<% if (it.discussions.length === 0) { %> +
No discussions found.
+<% } else { %> + + <% for (const discussion of it.discussions) { %> + + + + + + <% } %> +
+ <% if (discussion.category) { %> + <%= discussion.category.name %> + <% } %> + + <%~ discussion.titleHtml %> + <% if (discussion.answered) { %> + Answered + <% } %> + + <% if (discussion.createdAt) { %> + + <% } %> +
+<% } %> diff --git a/views/layouts/repo.eta b/views/layouts/repo.eta index b1fb65c..6381196 100644 --- a/views/layouts/repo.eta +++ b/views/layouts/repo.eta @@ -15,6 +15,7 @@ layout("/layouts/base.eta", { Code Issues Pull requests + Discussions Releases Wiki <% if (it.branch) { %> @@ -27,6 +28,7 @@ layout("/layouts/base.eta", { + -- cgit v1.3.1