Improve comment threads and reply syntax

* On Forums and photo comment threads: display the poster's username
  below their display name, if their username differs. If they do not
  have a distinct display name, a small @ appears in front of their
  display name instead.
* On Quote & Reply, wrap the @mention with a Markdown hyperlink to the
  specific comment ID.
This commit is contained in:
Noah Petherbridge 2024-11-23 12:55:13 -08:00
parent c1cf5df70e
commit 39398a1f78
5 changed files with 63 additions and 18 deletions

View File

@ -109,7 +109,14 @@ func NewPost() http.HandlerFunc {
if len(quoteCommentID) > 0 { if len(quoteCommentID) > 0 {
if i, err := strconv.Atoi(quoteCommentID); err == nil { if i, err := strconv.Atoi(quoteCommentID); err == nil {
if comment, err := models.GetComment(uint64(i)); err == nil { if comment, err := models.GetComment(uint64(i)); err == nil {
message = markdown.Quotify(comment.Message) + "\n\n"
// Prefill the message with the @mention and quoted post.
message = fmt.Sprintf(
"[@%s](/go/comment?id=%d)\n\n%s\n\n",
comment.User.Username,
comment.ID,
markdown.Quotify(comment.Message),
)
} }
} }
} }

View File

@ -8,13 +8,20 @@ document.addEventListener('DOMContentLoaded', function() {
// at the page header instead of going to the dedicated comment page. // at the page header instead of going to the dedicated comment page.
(document.querySelectorAll(".nonshy-quote-button") || []).forEach(node => { (document.querySelectorAll(".nonshy-quote-button") || []).forEach(node => {
const message = node.dataset.quoteBody, const message = node.dataset.quoteBody,
replyTo = node.dataset.replyTo; replyTo = node.dataset.replyTo,
commentID = node.dataset.commentId;
// If we have a comment ID, have the at-mention link to it.
let atMention = "@" + replyTo;
if (commentID) {
atMention = `[@${replyTo}](/go/comment?id=${commentID})`;
}
node.addEventListener("click", (e) => { node.addEventListener("click", (e) => {
e.preventDefault(); e.preventDefault();
if (replyTo) { if (replyTo) {
$message.value += "@" + replyTo + "\n\n"; $message.value += atMention + "\n\n";
} }
// Prepare the quoted message. // Prepare the quoted message.
@ -30,11 +37,18 @@ document.addEventListener('DOMContentLoaded', function() {
}); });
(document.querySelectorAll(".nonshy-reply-button") || []).forEach(node => { (document.querySelectorAll(".nonshy-reply-button") || []).forEach(node => {
const replyTo = node.dataset.replyTo; const replyTo = node.dataset.replyTo,
commentID = node.dataset.commentId;
// If we have a comment ID, have the at-mention link to it.
let atMention = "@" + replyTo;
if (commentID) {
atMention = `[@${replyTo}](/go/comment?id=${commentID})`;
}
node.addEventListener("click", (e) => { node.addEventListener("click", (e) => {
e.preventDefault(); e.preventDefault();
$message.value += "@" + replyTo + "\n\n"; $message.value += atMention + "\n\n";
$message.scrollIntoView(); $message.scrollIntoView();
$message.focus(); $message.focus();
}); });

View File

@ -1,7 +1,6 @@
{{define "title"}}Untitled{{end}} {{define "title"}}Untitled{{end}}
{{define "content"}}{{end}} {{define "content"}}{{end}}
{{define "scripts"}}{{end}} {{define "scripts"}}{{end}}
{{define "head-scripts"}}{{end}}
{{define "base"}} {{define "base"}}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
@ -10,18 +9,17 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="/static/css/bulma.min.css?build={{.BuildHash}}"> <link rel="stylesheet" type="text/css" href="/static/css/bulma.min.css?build={{.BuildHash}}">
<!-- Bulma theme CSS --> <!-- Bulma theme CSS -->
{{if eq .WebsiteTheme "light"}} {{- if eq .WebsiteTheme "light" -}}
<link rel="stylesheet" type="text/css" href="/static/css/bulma-no-dark-mode.min.css?build={{.BuildHash}}"> <link rel="stylesheet" type="text/css" href="/static/css/bulma-no-dark-mode.min.css?build={{.BuildHash}}">
{{else if eq .WebsiteTheme "dark"}} {{- else if eq .WebsiteTheme "dark" -}}
<link rel="stylesheet" type="text/css" href="/static/css/bulma-dark-theme.css?build={{.BuildHash}}"> <link rel="stylesheet" type="text/css" href="/static/css/bulma-dark-theme.css?build={{.BuildHash}}">
{{else}} {{- else -}}
<link rel="stylesheet" type="text/css" href="/static/css/nonshy-prefers-dark.css?build={{.BuildHash}}"> <link rel="stylesheet" type="text/css" href="/static/css/nonshy-prefers-dark.css?build={{.BuildHash}}">
{{end}} {{- end -}}
<link rel="stylesheet" href="/static/fontawesome-free-6.6.0-web/css/all.css"> <link rel="stylesheet" href="/static/fontawesome-free-6.6.0-web/css/all.css">
<link rel="stylesheet" href="/static/css/theme.css?build={{.BuildHash}}"> <link rel="stylesheet" href="/static/css/theme.css?build={{.BuildHash}}">
<link rel="manifest" href="/manifest.json"> <link rel="manifest" href="/manifest.json">
<title>{{template "title" .}} - {{ .Title }}</title> <title>{{template "title" .}} - {{ .Title }}</title>
{{template "head-scripts" .}}
</head> </head>
<body class="has-navbar-fixed-top"> <body class="has-navbar-fixed-top">
<nav class="navbar is-fixed-top" role="navigation" aria-label="main navigation"> <nav class="navbar is-fixed-top" role="navigation" aria-label="main navigation">

View File

@ -140,16 +140,29 @@
</div> </div>
[unavailable] [unavailable]
{{else}} {{else}}
<!-- User has no display name distinct from their username? -->
{{ $NoDisplayName := eq $c.User.NameOrUsername $c.User.Username }}
<div> <div>
<a href="/u/{{$c.User.Username}}"> <a href="/u/{{$c.User.Username}}">
{{template "avatar-96x96" $c.User}} {{template "avatar-96x96" $c.User}}
</a> </a>
</div> </div>
<a href="/u/{{$c.User.Username}}">{{$c.User.NameOrUsername}}</a> <a href="/u/{{$c.User.Username}}">
{{- if $NoDisplayName}}<small class="is-size-7">@</small>{{end -}}
{{$c.User.NameOrUsername}}
</a>
<!-- Username if the display name wasn't identical -->
{{if not $NoDisplayName}}
<div class="is-size-7">
@{{$c.User.Username}}
</div>
{{end}}
{{end}} {{end}}
{{if $c.User.IsAdmin}} {{if $c.User.IsAdmin}}
<div class="is-size-7 mt-1"> <div class="is-size-7 mt-2">
<span class="tag is-danger is-light"> <span class="tag is-danger is-light">
<span class="icon"><i class="fa fa-peace"></i></span> <span class="icon"><i class="fa fa-peace"></i></span>
<span>Admin</span> <span>Admin</span>
@ -306,14 +319,14 @@
{{if not $Root.Thread.NoReply}} {{if not $Root.Thread.NoReply}}
<div class="column is-narrow"> <div class="column is-narrow">
<a href="/forum/post?to={{$Root.Forum.Fragment}}&thread={{$Root.Thread.ID}}&quote={{.ID}}" <a href="/forum/post?to={{$Root.Forum.Fragment}}&thread={{$Root.Thread.ID}}&quote={{.ID}}"
class="has-text-dark nonshy-quote-button" data-quote-body="{{.Message}}" data-reply-to="{{.User.Username}}"> class="has-text-dark nonshy-quote-button" data-quote-body="{{.Message}}" data-reply-to="{{.User.Username}}" data-comment-id="{{.ID}}">
<span class="icon"><i class="fa fa-quote-right"></i></span> <span class="icon"><i class="fa fa-quote-right"></i></span>
<span>Quote</span> <span>Quote</span>
</a> </a>
</div> </div>
<div class="column is-narrow"> <div class="column is-narrow">
<a href="/forum/post?to={{$Root.Forum.Fragment}}&thread={{$Root.Thread.ID}}" <a href="/forum/post?to={{$Root.Forum.Fragment}}&thread={{$Root.Thread.ID}}"
class="has-text-dark nonshy-reply-button" data-reply-to="{{.User.Username}}"> class="has-text-dark nonshy-reply-button" data-reply-to="{{.User.Username}}" data-comment-id="{{.ID}}">
<span class="icon"><i class="fa fa-reply"></i></span> <span class="icon"><i class="fa fa-reply"></i></span>
<span>Reply</span> <span>Reply</span>
</a> </a>

View File

@ -280,12 +280,25 @@
<div class="box has-background-link-light has-text-dark" id="p{{.ID}}"> <div class="box has-background-link-light has-text-dark" id="p{{.ID}}">
<div class="columns"> <div class="columns">
<div class="column is-2 has-text-centered"> <div class="column is-2 has-text-centered">
<!-- User has no display name distinct from their username? -->
{{ $NoDisplayName := eq .User.NameOrUsername .User.Username }}
<div> <div>
<a href="/u/{{.User.Username}}"> <a href="/u/{{.User.Username}}">
{{template "avatar-96x96" .User}} {{template "avatar-96x96" .User}}
</a> </a>
</div> </div>
<a href="/u/{{.User.Username}}">{{.User.NameOrUsername}}</a> <a href="/u/{{.User.Username}}">
{{- if $NoDisplayName}}<small class="is-size-7">@</small>{{end -}}
{{.User.NameOrUsername}}
</a>
<!-- Username if the display name wasn't identical -->
{{if not $NoDisplayName}}
<div class="is-size-7">
@{{.User.Username}}
</div>
{{end}}
</div> </div>
<div class="column content"> <div class="column content">
@ -341,14 +354,14 @@
<div class="column is-narrow"> <div class="column is-narrow">
<a href="#" <a href="#"
class="has-text-dark nonshy-quote-button" data-quote-body="{{.Message}}" data-reply-to="{{.User.Username}}"> class="has-text-dark nonshy-quote-button" data-quote-body="{{.Message}}" data-reply-to="{{.User.Username}}" data-comment-id="{{.ID}}">
<span class="icon"><i class="fa fa-quote-right"></i></span> <span class="icon"><i class="fa fa-quote-right"></i></span>
<span>Quote</span> <span>Quote</span>
</a> </a>
</div> </div>
<div class="column is-narrow"> <div class="column is-narrow">
<a href="#" <a href="#"
class="has-text-dark nonshy-reply-button" data-reply-to="{{.User.Username}}"> class="has-text-dark nonshy-reply-button" data-reply-to="{{.User.Username}}" data-comment-id="{{.ID}}">
<span class="icon"><i class="fa fa-reply"></i></span> <span class="icon"><i class="fa fa-reply"></i></span>
<span>Reply</span> <span>Reply</span>
</a> </a>