Implement replies in post header

This commit is contained in:
Dominic Ferrando
2025-04-19 16:40:43 -04:00
parent 656595e47e
commit 34d3ec5366
5 changed files with 82 additions and 24 deletions
+22 -13
View File
@@ -8,27 +8,36 @@ import (
func EnrichPost(body string) string { func EnrichPost(body string) string {
var b strings.Builder var b strings.Builder
for _, raw := range strings.Split(body, "\n") { for _, rawLine := range strings.Split(body, "\n") {
var out string var outLine string
switch {
case strings.HasPrefix(raw, ">>"): for i, rawWord := range strings.Split(rawLine, " ") {
postId := strings.TrimPrefix(raw, ">>") var outWord string
esc := template.HTMLEscapeString(raw) if strings.HasPrefix(rawWord, ">>") {
out = fmt.Sprintf( postId := strings.TrimPrefix(rawWord, ">>")
esc := template.HTMLEscapeString(rawWord)
outWord = fmt.Sprintf(
`<a onclick="onReplyLinkClick(event)" `<a onclick="onReplyLinkClick(event)"
onmouseover="highlightPost(%[1]s, event)" `+ onmouseover="highlightPost(%[1]s, event)" `+
`onmouseleave="highlightPost(%[1]s, event, false)" `+ `onmouseleave="highlightPost(%[1]s, event, false)" `+
`href="#post-%[1]s" class="reply-link">%s</a>`, `href="#post-%[1]s" class="reply-link">%s</a>`,
postId, esc, postId, esc,
) )
case strings.HasPrefix(raw, ">"): } else {
esc := template.HTMLEscapeString(raw) outWord = template.HTMLEscapeString(rawWord)
out = `<span class="greentext">` + esc + `</span>`
default:
out = template.HTMLEscapeString(raw)
} }
b.WriteString(out) if i != 0 {
outLine += " "
}
outLine += outWord
}
if strings.HasPrefix(rawLine, ">") && !strings.HasPrefix(rawLine, ">>") {
outLine = `<span class="greentext">` + outLine + `</span>`
}
b.WriteString(outLine)
b.WriteString("<br/>") b.WriteString("<br/>")
} }
return b.String() return b.String()
+15 -2
View File
@@ -146,12 +146,13 @@ body {
.thread-subject { .thread-subject {
font-weight: bold; font-weight: bold;
color: #b294bb; color: #0F0C5D;
margin-right: 5px; margin-right: 5px;
} }
.post-op { .post-op {
margin-bottom: 10px; margin-bottom: 10px;
font-size: 14px;
} }
.post { .post {
@@ -159,8 +160,9 @@ body {
margin: 5x; margin: 5x;
padding: 10px; padding: 10px;
background-color: #D6DAF0; background-color: #D6DAF0;
border: 1px solid #282a2e; border: 1px solid #B7C5D9;
margin-bottom: 10px; margin-bottom: 10px;
font-size: 14px;
} }
.post-highlighted { .post-highlighted {
@@ -211,6 +213,17 @@ body {
cursor: pointer; cursor: pointer;
} }
.reply-link-header {
color: rgb(52, 52, 92);
text-decoration: underline;
cursor: pointer;
margin-left: 8px;
}
.reply-link-header:hover {
color: #D00;
}
/* GENERAL LAYOUT */ /* GENERAL LAYOUT */
.container { .container {
+34
View File
@@ -0,0 +1,34 @@
const posts = Array.from(document.querySelectorAll("article"));
const replies = {};
for (const post of posts) {
const postId = +post.id.split("-")[1];
const postBody = post.querySelector("p").textContent;
const replyLinkIds = [...postBody.matchAll(/(?:^|\s)>>(\d+)\b/g)].map(m => parseInt(m[1]));
for (const replyLinkId of replyLinkIds) {
replies[replyLinkId] = replies[replyLinkId] ?
replies[replyLinkId].add(postId) :
replies[replyLinkId] = new Set([postId]);
}
}
for (const postId in replies) {
const post = $(`post-${postId}`);
const postRepliesContainer = post.querySelector(".post-replies");
const replyIds = Array.from(replies[postId]);
for (const replyId of replyIds) {
const replyLink = document.createElement("a");
replyLink.textContent = `>>${replyId}`;
replyLink.classList.add("reply-link-header");
replyLink.setAttribute("href", `#post-${replyId}`);
replyLink.onmouseover = (e) => highlightPost(+replyId, e);
replyLink.onmouseleave = (e) => highlightPost(+replyId, e, false);
replyLink.onclick = onReplyLinkClick;
postRepliesContainer.append(replyLink);
}
}
+1 -1
View File
@@ -8,7 +8,7 @@ templ Layout() {
<title>Comfychan</title> <title>Comfychan</title>
<script src="https://unpkg.com/htmx.org@2.0.4"></script> <script src="https://unpkg.com/htmx.org@2.0.4"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.14"></script> <script src="https://unpkg.com/hyperscript.org@0.9.14"></script>
<script src="/static/index.js" defer></script> <script src="/static/index.js"></script>
<link rel="stylesheet" href="/static/reset.css"/> <link rel="stylesheet" href="/static/reset.css"/>
<link rel="stylesheet" href="/static/index.css"/> <link rel="stylesheet" href="/static/index.css"/>
</head> </head>
+2
View File
@@ -36,6 +36,7 @@ templ ThreadPost(post database.Post, thread *database.Thread) {
> >
No.{ strconv.Itoa(post.Id) } No.{ strconv.Itoa(post.Id) }
</span> </span>
<div class="post-replies"></div>
</header> </header>
<p> <p>
@templ.Raw(util.EnrichPost(post.Body)) @templ.Raw(util.EnrichPost(post.Body))
@@ -52,6 +53,7 @@ templ ThreadPosts(posts []database.Post) {
templ Thread(board database.Board, thread database.Thread, posts []database.Post) { templ Thread(board database.Board, thread database.Thread, posts []database.Post) {
@shared.Layout() { @shared.Layout() {
<script src="/static/thread.js" defer></script>
@BoardHeader(board) @BoardHeader(board)
<div class="new-post-container"> <div class="new-post-container">
<form <form