[chore/frontend] Tweak threading a bit, inform about hidden replies (#3097)

* [chore/frontend] Tweak threading a bit, inform about hidden replies

* whoops

* round off bottom of replies col-header if no replies visible
This commit is contained in:
tobi 2024-07-13 12:26:16 +02:00 committed by GitHub
parent bbbdf01213
commit c83e96b8a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 90 additions and 102 deletions

View file

@ -126,8 +126,17 @@ type WebStatus struct {
// display this status in the web view. // display this status in the web view.
Indent int Indent int
// This status is the first status after // This status is the last visible status
// the "main" thread, so it and everything // in the main thread, so everything below
// can be considered "replies".
ThreadLastMain bool
// This status is the one around which
// the thread context was constructed.
ThreadContextStatus bool
// This status is the first visibile status
// after the "main" thread, so it and everything
// below it can be considered "replies". // below it can be considered "replies".
ThreadFirstReply bool ThreadFirstReply bool
} }

View file

@ -29,15 +29,16 @@ type ThreadContext struct {
} }
type WebThreadContext struct { type WebThreadContext struct {
// Parents in the thread. // Status around which this
Ancestors []*WebStatus `json:"ancestors"` // thread ctx was constructed.
Status *WebStatus
// Children in the thread. // Ordered slice of statuses
Descendants []*WebStatus `json:"descendants"` // for rendering in template.
//
// The status around which the ancestors // Includes ancestors, target
// + descendants context was constructed. // status, and descendants.
Status *WebStatus `json:"-"` Statuses []*WebStatus
// Total length of // Total length of
// the main thread. // the main thread.

View file

@ -400,8 +400,7 @@ func (p *Processor) WebContextGet(
// Start preparing web context. // Start preparing web context.
wCtx := &apimodel.WebThreadContext{ wCtx := &apimodel.WebThreadContext{
Ancestors: make([]*apimodel.WebStatus, 0, len(iCtx.ancestors)), Statuses: make([]*apimodel.WebStatus, 0, len(wholeThread)),
Descendants: make([]*apimodel.WebStatus, 0, len(iCtx.descendants)),
} }
var ( var (
@ -415,72 +414,70 @@ func (p *Processor) WebContextGet(
// ie., who created first post in the thread. // ie., who created first post in the thread.
contextAcctID = wholeThread[0].AccountID contextAcctID = wholeThread[0].AccountID
// Position of target status in wholeThread,
// we put it on top of ancestors.
targetStatusIdx = len(iCtx.ancestors)
// Position from which we should add
// to descendants and not to ancestors.
descendantsIdx = targetStatusIdx + 1
// Whether we've reached end of "main" // Whether we've reached end of "main"
// thread and are now looking at replies. // thread and are now looking at replies.
inReplies bool inReplies bool
// Index in wholeThread where // Index in wholeThread
// the "main" thread ends. // where replies begin.
firstReplyIdx int firstReplyIdx int
// We should mark the next **VISIBLE** // We should mark the next **VISIBLE**
// reply as the first reply. // reply as the first reply.
markNextVisibleAsReply bool markNextVisibleAsFirstReply bool
) )
for idx, status := range wholeThread { for idx, status := range wholeThread {
if !inReplies { if !inReplies {
// Haven't reached end // Check if we've reached replies
// of "main" thread yet. // by looking for the first status
// // that's not a self-reply, ie.,
// not a post in the "main" thread.
switch {
case idx == 0:
// First post in wholeThread can't // First post in wholeThread can't
// be a self reply, so ignore it. // be a self reply anyway because
// // it (very likely) doesn't reply
// That aside, first non-self-reply // to anything, so ignore it.
// in wholeThread means the "main"
// thread is now over. case !isSelfReply(status, contextAcctID):
if idx != 0 && !isSelfReply(status, contextAcctID) { // This is not a self-reply, which
// Jot some stuff down. // means it's a reply from another
firstReplyIdx = idx // account. So, replies start here.
inReplies = true inReplies = true
markNextVisibleAsReply = true firstReplyIdx = idx
markNextVisibleAsFirstReply = true
} }
} }
// Ensure status is actually // Ensure status is actually
// visible to just anyone. // visible to just anyone, and
// hide / don't include it if not.
v, err := p.filter.StatusVisible(ctx, nil, status) v, err := p.filter.StatusVisible(ctx, nil, status)
if err != nil || !v { if err != nil || !v {
// Skip this one.
if !inReplies { if !inReplies {
// Main thread entry hidden.
wCtx.ThreadHidden++ wCtx.ThreadHidden++
} else { } else {
// Reply hidden.
wCtx.ThreadRepliesHidden++ wCtx.ThreadRepliesHidden++
} }
continue continue
} }
// Prepare status to add to thread context. // Prepare visible status to add to thread context.
apiStatus, err := p.converter.StatusToWebStatus(ctx, status) webStatus, err := p.converter.StatusToWebStatus(ctx, status)
if err != nil { if err != nil {
continue continue
} }
if markNextVisibleAsReply { if markNextVisibleAsFirstReply {
// This is the first visible // This is the first visible
// "reply / comment", so the // "reply / comment", so the
// little "x amount of replies" // little "x amount of replies"
// header should go above this. // header should go above this.
apiStatus.ThreadFirstReply = true webStatus.ThreadFirstReply = true
markNextVisibleAsReply = false markNextVisibleAsFirstReply = false
} }
// If this is a reply, work out the indent of // If this is a reply, work out the indent of
@ -491,59 +488,47 @@ func (p *Processor) WebContextGet(
case !ok: case !ok:
// No parent with // No parent with
// indent, start at 0. // indent, start at 0.
apiStatus.Indent = 0 webStatus.Indent = 0
case isSelfReply(status, status.AccountID): case isSelfReply(status, status.AccountID):
// Self reply, so indent at same // Self reply, so indent at same
// level as own replied-to status. // level as own replied-to status.
apiStatus.Indent = parentIndent webStatus.Indent = parentIndent
case parentIndent == 5: case parentIndent == 5:
// Already indented as far as we // Already indented as far as we
// can go to keep things readable // can go to keep things readable
// on thin screens, so just keep // on thin screens, so just keep
// parent's indent. // parent's indent.
apiStatus.Indent = parentIndent webStatus.Indent = parentIndent
default: default:
// Reply to someone else who's // Reply to someone else who's
// indented, but not to TO THE MAX. // indented, but not to TO THE MAX.
// Indent by another one. // Indent by another one.
apiStatus.Indent = parentIndent + 1 webStatus.Indent = parentIndent + 1
} }
// Store the indent for this status. // Store the indent for this status.
statusIndents[status.ID] = apiStatus.Indent statusIndents[status.ID] = webStatus.Indent
} }
switch { if webStatus.ID == targetStatusID {
case idx == targetStatusIdx: // This is the og
// This is the target status itself. // thread context status.
wCtx.Status = apiStatus webStatus.ThreadContextStatus = true
wCtx.Status = webStatus
case idx < descendantsIdx:
// Haven't reached descendants yet,
// so this must be an ancestor.
wCtx.Ancestors = append(
wCtx.Ancestors,
apiStatus,
)
default:
// We're in descendants town now.
wCtx.Descendants = append(
wCtx.Descendants,
apiStatus,
)
} }
wCtx.Statuses = append(wCtx.Statuses, webStatus)
} }
// Now we've gone through the whole // Now we've gone through the whole
// thread, we can add some additional info. // thread, we can add some additional info.
// Length of the "main" thread. If there are // Length of the "main" thread. If there are
// replies then it's up to where the replies // visible replies then it's up to where the
// start, otherwise it's the whole thing. // replies start, else it's the whole thing.
if inReplies { if inReplies {
wCtx.ThreadLength = firstReplyIdx wCtx.ThreadLength = firstReplyIdx
} else { } else {
@ -553,6 +538,9 @@ func (p *Processor) WebContextGet(
// Jot down number of hidden posts so template doesn't have to do it. // Jot down number of hidden posts so template doesn't have to do it.
wCtx.ThreadShown = wCtx.ThreadLength - wCtx.ThreadHidden wCtx.ThreadShown = wCtx.ThreadLength - wCtx.ThreadHidden
// Mark the last "main" visible status.
wCtx.Statuses[wCtx.ThreadShown-1].ThreadLastMain = true
// Number of replies is equal to number // Number of replies is equal to number
// of statuses in the thread that aren't // of statuses in the thread that aren't
// part of the "main" thread. // part of the "main" thread.

View file

@ -1014,6 +1014,8 @@ func (suite *InternalToFrontendTestSuite) TestStatusToWebStatus() {
"PollOptions": null, "PollOptions": null,
"Local": false, "Local": false,
"Indent": 0, "Indent": 0,
"ThreadLastMain": false,
"ThreadContextStatus": false,
"ThreadFirstReply": false "ThreadFirstReply": false
}`, string(b)) }`, string(b))
} }

View file

@ -42,6 +42,15 @@
h2 { h2 {
margin-right: auto; margin-right: auto;
} }
&.replies.hidden-only {
/*
No visible replies below this column
header, so round off the bottom.
*/
border-bottom-left-radius: $br;
border-bottom-right-radius: $br;
}
} }
.status { .status {

View file

@ -20,7 +20,7 @@
{{- define "repliesSummary" -}} {{- define "repliesSummary" -}}
{{- if .context.ThreadRepliesShown -}} {{- if .context.ThreadRepliesShown -}}
{{- if .context.ThreadRepliesHidden -}} {{- if .context.ThreadRepliesHidden -}}
{{- if eq .context.ThreadReplies 1 -}} {{- if eq .context.ThreadRepliesShown 1 -}}
{{- /* Some replies are hidden. */ -}} {{- /* Some replies are hidden. */ -}}
{{ .context.ThreadRepliesShown }} visible reply {{ .context.ThreadRepliesShown }} visible reply
{{- else if gt .context.ThreadRepliesShown 1 -}} {{- else if gt .context.ThreadRepliesShown 1 -}}
@ -35,6 +35,8 @@
{{ .context.ThreadReplies }} replies {{ .context.ThreadReplies }} replies
{{- end -}} {{- end -}}
{{- end -}} {{- end -}}
{{- else -}}
{{- .context.ThreadRepliesHidden }} {{ if eq .context.ThreadRepliesHidden 1 }}reply{{ else }}replies{{ end }} hidden or not public
{{- end -}} {{- end -}}
{{- end -}} {{- end -}}
@ -60,7 +62,7 @@
{{- with . }} {{- with . }}
</section> </section>
<section class="thread thread-replies" aria-labelledby="replies" open> <section class="thread thread-replies" aria-labelledby="replies" open>
<div class="col-header replies"> <div class="col-header replies{{- if not .context.ThreadRepliesShown }} hidden-only{{- end -}}">
<h2 id="replies">{{- template "repliesSummary" . -}}</h2> <h2 id="replies">{{- template "repliesSummary" . -}}</h2>
<a href="#thread-summary">back to top</a> <a href="#thread-summary">back to top</a>
</div> </div>
@ -77,41 +79,18 @@
{{- end }} {{- end }}
</div> </div>
{{- range $thisStatus := .context.Ancestors }} {{- range $status := .context.Statuses }}
{{- if $thisStatus.ThreadFirstReply }} <article
class="status{{- if $status.ThreadContextStatus }} expanded{{- end -}}{{- if $status.Indent }} indent-{{ $status.Indent }}{{- end -}}"
{{- includeAttr "status_attributes.tmpl" $status | indentAttr 3 }}
>
{{- include "status.tmpl" $status | indent 3 }}
</article>
{{- if and $status.ThreadLastMain $.context.ThreadReplies }}
{{- include "repliesStart" $ | indent 1 }} {{- include "repliesStart" $ | indent 1 }}
{{- end }} {{- end }}
<article
class="status{{- if $thisStatus.Indent }} indent-{{ $thisStatus.Indent }}{{- end -}}"
{{- includeAttr "status_attributes.tmpl" $thisStatus | indentAttr 3 }}
>
{{- include "status.tmpl" $thisStatus | indent 3 }}
</article>
{{- end }} {{- end }}
{{- with $thisStatus := .context.Status }}
{{- if $thisStatus.ThreadFirstReply }}
{{- include "repliesStart" $ | indent 1 }}
{{- end }}
<article
class="status expanded{{- if $thisStatus.Indent }} indent-{{ $thisStatus.Indent }}{{- end -}}"
{{- includeAttr "status_attributes.tmpl" $thisStatus | indentAttr 3 }}
>
{{- include "status.tmpl" $thisStatus | indent 3 }}
</article>
{{- end }}
{{- range $thisStatus := .context.Descendants }}
{{- if $thisStatus.ThreadFirstReply }}
{{- include "repliesStart" $ | indent 1 }}
{{- end }}
<article
class="status{{- if $thisStatus.Indent }} indent-{{ $thisStatus.Indent }}{{- end -}}"
{{- includeAttr "status_attributes.tmpl" $thisStatus | indentAttr 3 }}
>
{{- include "status.tmpl" $thisStatus | indent 3 }}
</article>
{{- end }}
{{- if .context.ThreadReplies }} {{- if .context.ThreadReplies }}
</section> </section>
{{- end }} {{- end }}