website/web/templates/forum/thread.html
Noah 8085e092bc Forum Reply Enhancements + Better Pagers
* Enhance user experience replying to a forum thread. An inline reply textarea
  is added to page footers, "Quote" buttons on posts will quote the markdown
  source and focus the reply textarea, and "Reply" buttons will put an
  "@ mention" and focus the reply textarea. Users with scripts disabled will
  still be sent to the regular reply page as before.
* Improve all pagers by adding a "QueryPlus" template function that merges the
  page number with other current query parameters.
* Fix private profile picture avatars not displaying in your Notifications for
  profile pics you're allowed to see.
2022-09-10 12:09:46 -07:00

318 lines
12 KiB
HTML

{{define "title"}}{{.Thread.Title}} - {{.Forum.Title}}{{end}}
{{define "content"}}
<div class="block">
<section class="hero is-light is-success">
<div class="hero-body">
<div class="container">
<h1 class="title">
<a href="/f/{{.Forum.Fragment}}" class="has-text-light">
<span class="icon mr-4"><i class="fa fa-comments"></i></span>
<span>{{.Forum.Title}}</span>
</a>
</h1>
</div>
</div>
</section>
</div>
{{$Root := .}}
<div class="block px-4">
<div class="columns">
<div class="column">
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
<li><a href="/forum">Forums</a></li>
<li><a href="/f/{{.Forum.Fragment}}">{{.Forum.Title}}</a></Li>
<li class="is-active">
<a href="{{.Request.URL.Path}}" aria-current="page">{{or .Thread.Title "Untitled Thread"}}</a>
</li>
</ul>
</nav>
</div>
<div class="column is-narrow">
{{if not .Thread.NoReply}}
<a href="/forum/post?to={{.Forum.Fragment}}&thread={{.Thread.ID}}" class="button is-link">
<span class="icon"><i class="fa fa-reply"></i></span>
<span>Add Reply</span>
</a>
{{end}}
</div>
</div>
</div>
<h1 class="title px-4">
{{if .Thread.Pinned}}<sup class="fa fa-thumbtack has-text-success mr-2 is-size-5" title="Pinned"></sup>{{end}}
{{or .Thread.Title "Untitled Thread"}}
</h1>
<div class="px-4">
{{if .Thread.Pinned}}
<span class="tag is-success is-light mr-2">
<span class="icon"><i class="fa fa-thumbtack"></i></span>
<span>Pinned</span>
</span>
{{end}}
{{if .Thread.Explicit}}
<span class="tag is-danger is-light mr-2">
<span class="icon"><i class="fa fa-fire"></i></span>
<span>NSFW</span>
</span>
{{end}}
{{if .Thread.NoReply}}
<span class="tag is-warning is-light mr-2" title="This thread can not be replied to.">
<span class="icon"><i class="fa fa-ban"></i></span>
<span>No Reply</span>
</span>
{{end}}
<span class="tag is-grey is-light mr-2" title="This thread can not be replied to.">
<span class="icon"><i class="fa fa-eye"></i></span>
<span>{{.Thread.Views}} View{{PluralizeU64 .Thread.Views}}</span>
</span>
<em title="{{.Thread.UpdatedAt.Format "2006-01-02 15:04:05"}}">
Updated {{SincePrettyCoarse .Thread.UpdatedAt}} ago
</em>
</div>
<p class="block p-4 mb-0">
Found <strong>{{.Pager.Total}}</strong> post{{Pluralize64 .Pager.Total}} on this thread
(page {{.Pager.Page}} of {{.Pager.Pages}}).
</p>
<p class="block px-4 mb-4">
<a href="/comments/subscription?table_name=threads&table_id={{.Thread.ID}}&next={{UrlEncode .Request.URL.String}}&subscribe={{if not .IsSubscribed}}true{{else}}false{{end}}">
<span class="icon"><i class="fa fa-bell{{if not .IsSubscribed}}-slash{{end}}"></i></span>
<span>
{{if .IsSubscribed}}
Disable notifications about this thread
{{else}}
Enable notifications about this thread
{{end}}
</span>
</a>
</p>
<div class="block p-2">
<nav class="pagination" role="navigation" aria-label="pagination">
<a class="pagination-previous{{if not .Pager.HasPrevious}} is-disabled{{end}}" title="Previous"
href="{{.Request.URL.Path}}?{{QueryPlus "page" .Pager.Previous}}">Previous</a>
<a class="pagination-next{{if not .Pager.HasNext}} is-disabled{{end}}" title="Next"
href="{{.Request.URL.Path}}?{{QueryPlus "page" .Pager.Next}}">Next page</a>
<ul class="pagination-list">
{{$Root := .}}
{{range .Pager.Iter}}
<li>
<a class="pagination-link{{if .IsCurrent}} is-current{{end}}"
aria-label="Page {{.Page}}"
href="{{$Root.Request.URL.Path}}?{{QueryPlus "page" .Page}}">
{{.Page}}
</a>
</li>
{{end}}
</ul>
</nav>
</div>
{{$Root := .}}
<div class="block p-2">
{{range .Comments}}
<div class="box has-background-link-light">
<div class="columns">
<div class="column is-2 has-text-centered">
<div>
<a href="/u/{{.User.Username}}">
{{template "avatar-96x96" .User}}
</a>
</div>
<a href="/u/{{.User.Username}}">{{.User.Username}}</a>
{{if .User.IsAdmin}}
<div class="is-size-7 mt-1">
<span class="tag is-danger is-light">
<span class="icon"><i class="fa fa-gavel"></i></span>
<span>Admin</span>
</span>
</div>
{{end}}
</div>
<div class="column content">
{{ToMarkdown .Message}}
{{if .IsEdited}}
<div class="mt-4">
<em title="{{.UpdatedAt.Format "2006-01-02 15:04:05"}}">
<small>Edited {{SincePrettyCoarse .UpdatedAt}} ago</small>
</em>
</div>
{{end}}
<hr class="has-background-grey mb-2">
<div class="columns is-mobile is-multiline is-size-7 mb-0">
<div class="column is-narrow">
<span title="{{.CreatedAt.Format "2006-01-02 15:04:05"}}">
{{SincePrettyCoarse .CreatedAt}} ago
</span>
</div>
<div class="column is-narrow">
{{$Like := $Root.LikeMap.Get .ID}}
<a href="#" class="has-text-dark nonshy-like-button"
data-table-name="comments" data-table-id="{{.ID}}"
title="Like">
<span class="icon{{if $Like.UserLikes}} has-text-danger{{end}}"><i class="fa fa-heart"></i></span>
<span class="nonshy-likes">
Like
{{if gt $Like.Count 0}}
({{$Like.Count}})
{{end}}
</span>
</a>
</div>
<div class="column is-narrow">
<a href="/contact?intent=report&subject=report.comment&id={{.ID}}" class="has-text-dark">
<span class="icon"><i class="fa fa-flag"></i></span>
<span>Report</span>
</a>
</div>
{{if not $Root.Thread.NoReply}}
<div class="column is-narrow">
<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}}">
<span class="icon"><i class="fa fa-quote-right"></i></span>
<span>Quote</span>
</a>
</div>
<div class="column is-narrow">
<a href="/forum/post?to={{$Root.Forum.Fragment}}&thread={{$Root.Thread.ID}}"
class="has-text-dark nonshy-reply-button" data-reply-to="{{.User.Username}}">
<span class="icon"><i class="fa fa-reply"></i></span>
<span>Reply</span>
</a>
</div>
{{end}}
{{if or $Root.CurrentUser.IsAdmin (eq $Root.CurrentUser.ID .User.ID)}}
<div class="column is-narrow">
<a href="/forum/post?to={{$Root.Forum.Fragment}}&thread={{$Root.Thread.ID}}&edit={{.ID}}" class="has-text-dark">
<span class="icon"><i class="fa fa-edit"></i></span>
<span>Edit</span>
</a>
</div>
<div class="column is-narrow">
<a href="/forum/post?to={{$Root.Forum.Fragment}}&thread={{$Root.Thread.ID}}&edit={{.ID}}&delete=true" onclick="return confirm('Are you sure you want to delete this comment?')" class="has-text-dark">
<span class="icon"><i class="fa fa-trash"></i></span>
<span>Delete</span>
</a>
</div>
{{end}}
</div>
{{if $Root.CurrentUser.IsAdmin}}
<div>
<span class="tag is-primary is-light">
<span class="icon"><i class="fa fa-database"></i></span>
<span>ID: {{.ID}}</span>
</span>
</div>
{{end}}
</div>
</div>
</div>
{{end}}
</div>
{{if .Thread.NoReply}}
<div class="block notification is-warning is-light">
<i class="fa fa-ban pr-2"></i>
This thread is not accepting any new replies.
</div>
{{else}}
<div class="block p-2" id="reply">
<div class="card">
<header class="card-header has-background-link">
<p class="card-header-title has-text-light">
<i class="fa fa-comment mr-2"></i>
Reply to Thread
</p>
</header>
<div class="card-content">
<form action="/forum/post?to={{.Forum.Fragment}}&thread={{.Thread.ID}}" method="POST">
{{InputCSRF}}
<div class="field block">
<label for="message" class="label">Message</label>
<textarea class="textarea" cols="80" rows="6"
name="message"
id="message"
required
placeholder="Message"></textarea>
<p class="help">
Markdown formatting supported.
</p>
</div>
<div class="field has-text-centered">
<button type="submit"
name="intent"
value="preview"
class="button is-link">
Preview
</button>
<button type="submit"
name="intent"
value="submit"
class="button is-success">
Post Message
</button>
</div>
</form>
</div>
</div>
</div>
{{end}}
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
const $message = document.querySelector("#message");
// Enhance the in-post Quote and Reply buttons to activate the reply field
// at the page footer instead of going to the dedicated comment page.
(document.querySelectorAll(".nonshy-quote-button") || []).forEach(node => {
const message = node.dataset.quoteBody;
node.addEventListener("click", (e) => {
e.preventDefault();
// Prepare the quoted message.
var lines = [];
for (let line of message.split("\n")) {
lines.push("> " + line);
}
$message.value += lines.join("\n") + "\n\n";
$message.scrollIntoView();
$message.focus();
});
});
(document.querySelectorAll(".nonshy-reply-button") || []).forEach(node => {
const replyTo = node.dataset.replyTo;
node.addEventListener("click", (e) => {
e.preventDefault();
$message.value += "@" + replyTo + "\n\n";
$message.scrollIntoView();
$message.focus();
});
});
});
</script>
{{end}}