fierj
PublicTiny personal git forge
{{template "head" .}}
{{define "title"}}{{.Thread.Title}} - {{.Repo}} - fierj{{end}}
{{template "repo-header" .}}
{{template "repo-tabs" .}}
<div class="thread-detail">
<div class="thread-detail-header">
<h2>{{.Thread.Title}}</h2>
<span class="thread-state thread-state-{{.Thread.State}}">{{.Thread.State}}</span>
</div>
<p class="thread-meta-line">
<strong>{{.Thread.AuthorName}}</strong> opened this thread · {{timeAgo .Thread.Created}}
</p>
</div>
<!-- Original post -->
<div class="thread-comment" id="reply-root">
<div class="thread-comment-header">
<strong>{{.Thread.AuthorName}}</strong>
<span>{{timeAgo .Thread.Created}}</span>
</div>
<div class="thread-comment-body markdown-body">{{.Thread.Body}}</div>
</div>
<!-- Replies: one linear, chronological conversation. A reply only points -->
<!-- back at an earlier message when it isn't simply continuing the line -->
<!-- right above it — that's the rare, explicit callback worth calling out. -->
{{if .ReplyViews}}
<div class="thread-replies">
{{range .ReplyViews}}
<div class="thread-reply" id="reply-{{.ID}}">
{{if .ShowParent}}
<button type="button" class="reply-pointer" data-jump="{{.ParentID}}">↩ replying to
{{.ParentAuthor}}</button>
{{end}}
<div class="thread-reply-header">
<strong>{{.AuthorName}}</strong>
<time>{{timeAgo .Created}}</time>
</div>
<div class="thread-reply-body markdown-body">{{.Body}}</div>
<div class="thread-reply-actions">
<button type="button" class="reply-link" data-reply-id="{{.ID}}"
data-reply-author="{{.AuthorName}}">Reply</button>
</div>
</div>
{{end}}
</div>
{{end}}
<!-- Participate -->
<div class="participate">
{{if not .User}}
<div class="participate-tabs" role="tablist">
<button type="button" class="participate-tab active" data-panel="web" onclick="fjTab(this)">On the
web</button>
{{if .APEnabled}}
<button type="button" class="participate-tab" data-panel="mastodon" onclick="fjTab(this)">From
Mastodon</button>
{{end}}
<button type="button" class="participate-tab" data-panel="email" onclick="fjTab(this)">By email</button>
</div>
{{end}}
<div class="participate-panel" data-panel="web">
<form method="POST" action="/{{.Repo}}/threads/{{.Thread.ID}}/reply" id="reply-form">
<input type="hidden" name="csrf_token" value="{{.CSRF}}">
<input type="hidden" name="parent_id" id="parent_id" value="">
<div class="replying-to" id="replying-to">
<span>Replying to <strong id="replying-to-name"></strong></span>
<button type="button" id="cancel-target" aria-label="Reply to the thread instead">✕</button>
</div>
{{if not .User}}
<div class="form-group">
<input type="text" id="guest_name" name="guest_name" placeholder="Your name (optional)"
maxlength="60" class="guest-name-field">
</div>
{{end}}
<div class="form-group">
<textarea name="body" id="reply-body" rows="4" placeholder="Leave a comment..."></textarea>
</div>
<div class="thread-actions">
{{if eq .Thread.State "open"}}
<button type="submit" class="btn btn-primary">Comment</button>
<button type="submit" formaction="/{{.Repo}}/threads/{{.Thread.ID}}/close"
class="btn btn-secondary">Close
thread</button>
{{else}}
<button type="submit" class="btn btn-primary">Comment</button>
<button type="submit" formaction="/{{.Repo}}/threads/{{.Thread.ID}}/reopen"
class="btn btn-secondary">Reopen
thread</button>
{{end}}
</div>
</form>
{{if not .User}}
<p class="participate-hint">Posting without an account attributes your comment to "Anonymous" unless you give
a name above. <a href="/login">Sign in</a> for a verified identity.</p>
{{end}}
</div>
{{if and (not .User) .APEnabled}}
<div class="participate-panel" data-panel="mastodon" hidden>
<p class="participate-hint">Follow this repository from Mastodon (or any ActivityPub app) to see new threads
and replies in your feed. Reply there — to the thread or to any specific message — and your comment
appears here automatically, no fierj account needed.</p>
<div class="fediverse-handle">
<span class="fediverse-icon" aria-hidden="true">🐘</span>
<code>@{{.Repo}}@{{.Host}}</code>
</div>
<form class="remote-follow-form" data-actor-url="{{.ActorURL}}" onsubmit="return fjRemoteFollow(this)">
<input type="text" name="instance" placeholder="your-instance.social"
aria-label="Your Mastodon instance domain">
<button type="submit" class="btn btn-subtle">Follow from my instance</button>
</form>
</div>
{{end}}
{{if not .User}}
<div class="participate-panel" data-panel="email" hidden>
<p class="participate-hint">Get a one-time link by email so you can comment without creating an account.
<span class="badge-soon">Coming soon</span>
</p>
<div class="email-magic-form">
<input type="email" placeholder="you@example.com" disabled>
<button type="button" class="btn btn-subtle" disabled>Email me a link</button>
</div>
</div>
{{end}}
</div>
<script>
function fjSetReplyTarget(id, author) {
document.getElementById('parent_id').value = id;
document.getElementById('replying-to-name').textContent = author;
document.getElementById('replying-to').classList.add('on');
const webTab = document.querySelector('.participate-tab[data-panel="web"]');
if (webTab) fjTab(webTab);
const ta = document.getElementById('reply-body');
ta.scrollIntoView({ behavior: 'smooth', block: 'center' });
ta.focus();
}
document.querySelectorAll('.reply-link[data-reply-id]').forEach(btn => {
btn.addEventListener('click', () => fjSetReplyTarget(btn.dataset.replyId, btn.dataset.replyAuthor));
});
const cancelBtn = document.getElementById('cancel-target');
if (cancelBtn) cancelBtn.addEventListener('click', () => {
document.getElementById('parent_id').value = '';
document.getElementById('replying-to').classList.remove('on');
});
function fjJumpTo(id) {
const el = document.getElementById('reply-' + id) || document.getElementById('reply-root');
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
el.classList.add('flash');
setTimeout(() => el.classList.remove('flash'), 900);
}
document.querySelectorAll('.reply-pointer[data-jump]').forEach(btn => {
btn.addEventListener('click', () => fjJumpTo(btn.dataset.jump));
});
</script>
{{template "foot" .}}