New Sign in

fierj

Public

Tiny personal git forge

← fierj / templates / thread_view.html
{{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" .}}