Add reply links on thread page
This commit is contained in:
parent
e356520290
commit
d7fc7cf2f5
|
@ -10,6 +10,15 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type StatusPleroma struct {
|
||||||
|
InReplyToAccountAcct string `json:"in_reply_to_account_acct"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReplyInfo struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Number int `json:"number"`
|
||||||
|
}
|
||||||
|
|
||||||
// Status is struct to hold status.
|
// Status is struct to hold status.
|
||||||
type Status struct {
|
type Status struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
@ -38,6 +47,13 @@ type Status struct {
|
||||||
Application Application `json:"application"`
|
Application Application `json:"application"`
|
||||||
Language string `json:"language"`
|
Language string `json:"language"`
|
||||||
Pinned interface{} `json:"pinned"`
|
Pinned interface{} `json:"pinned"`
|
||||||
|
|
||||||
|
// Custom fields
|
||||||
|
Pleroma StatusPleroma `json:"pleroma"`
|
||||||
|
HideAccountInfo bool `json:"hide_account_info"`
|
||||||
|
ShowReplies bool `json:"show_replies"`
|
||||||
|
ReplyMap map[string][]ReplyInfo `json:"reply_map"`
|
||||||
|
ReplyNumber int `json:"reply_number"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context hold information for mastodon context.
|
// Context hold information for mastodon context.
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
package model
|
|
@ -36,21 +36,21 @@ func NewTimelinePageTemplateData(statuses []*mastodon.Status, hasNext bool, next
|
||||||
}
|
}
|
||||||
|
|
||||||
type ThreadPageTemplateData struct {
|
type ThreadPageTemplateData struct {
|
||||||
Status *mastodon.Status
|
Statuses []*mastodon.Status
|
||||||
Context *mastodon.Context
|
|
||||||
PostReply bool
|
PostReply bool
|
||||||
ReplyToID string
|
ReplyToID string
|
||||||
ReplyContent string
|
ReplyContent string
|
||||||
|
ReplyMap map[string][]mastodon.ReplyInfo
|
||||||
NavbarData *NavbarTemplateData
|
NavbarData *NavbarTemplateData
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewThreadPageTemplateData(status *mastodon.Status, context *mastodon.Context, postReply bool, replyToID string, replyContent string, navbarData *NavbarTemplateData) *ThreadPageTemplateData {
|
func NewThreadPageTemplateData(statuses []*mastodon.Status, postReply bool, replyToID string, replyContent string, replyMap map[string][]mastodon.ReplyInfo, navbarData *NavbarTemplateData) *ThreadPageTemplateData {
|
||||||
return &ThreadPageTemplateData{
|
return &ThreadPageTemplateData{
|
||||||
Status: status,
|
Statuses: statuses,
|
||||||
Context: context,
|
|
||||||
PostReply: postReply,
|
PostReply: postReply,
|
||||||
ReplyToID: replyToID,
|
ReplyToID: replyToID,
|
||||||
ReplyContent: replyContent,
|
ReplyContent: replyContent,
|
||||||
|
ReplyMap: replyMap,
|
||||||
NavbarData: navbarData,
|
NavbarData: navbarData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,34 +267,46 @@ func (svc *service) ServeThreadPage(ctx context.Context, client io.Writer, c *ma
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
context, err := c.GetStatusContext(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
u, err := c.GetAccountCurrentUser(ctx)
|
u, err := c.GetAccountCurrentUser(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var content string
|
var content string
|
||||||
|
var replyToID string
|
||||||
if reply {
|
if reply {
|
||||||
|
replyToID = id
|
||||||
if u.ID != status.Account.ID {
|
if u.ID != status.Account.ID {
|
||||||
content += "@" + status.Account.Acct + " "
|
content += "@" + status.Account.Acct + " "
|
||||||
}
|
}
|
||||||
for _, m := range status.Mentions {
|
for i := range status.Mentions {
|
||||||
if u.ID != m.ID {
|
if status.Mentions[i].ID != u.ID && status.Mentions[i].ID != status.Account.ID {
|
||||||
content += "@" + m.Acct + " "
|
content += "@" + status.Mentions[i].Acct + " "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context, err := c.GetStatusContext(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
statuses := append(append(context.Ancestors, status), context.Descendants...)
|
||||||
|
|
||||||
|
replyMap := make(map[string][]mastodon.ReplyInfo)
|
||||||
|
|
||||||
|
for i := range statuses {
|
||||||
|
statuses[i].ShowReplies = true
|
||||||
|
statuses[i].ReplyMap = replyMap
|
||||||
|
addToReplyMap(replyMap, statuses[i].InReplyToID, statuses[i].ID, i+1)
|
||||||
|
}
|
||||||
|
|
||||||
navbarData, err := svc.getNavbarTemplateData(ctx, client, c)
|
navbarData, err := svc.getNavbarTemplateData(ctx, client, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := renderer.NewThreadPageTemplateData(status, context, reply, id, content, navbarData)
|
data := renderer.NewThreadPageTemplateData(statuses, reply, replyToID, content, replyMap, navbarData)
|
||||||
err = svc.renderer.RenderThreadPage(ctx, client, data)
|
err = svc.renderer.RenderThreadPage(ctx, client, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -323,7 +335,7 @@ func (svc *service) ServeNotificationPage(ctx context.Context, client io.Writer,
|
||||||
switch notifications[i].Type {
|
switch notifications[i].Type {
|
||||||
case "reblog", "favourite":
|
case "reblog", "favourite":
|
||||||
if notifications[i].Status != nil {
|
if notifications[i].Status != nil {
|
||||||
notifications[i].Status.Account.ID = ""
|
notifications[i].Status.HideAccountInfo = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if notifications[i].Pleroma != nil && notifications[i].Pleroma.IsSeen {
|
if notifications[i].Pleroma != nil && notifications[i].Pleroma.IsSeen {
|
||||||
|
@ -418,3 +430,19 @@ func (svc *service) PostTweet(ctx context.Context, client io.Writer, c *mastodon
|
||||||
|
|
||||||
return s.ID, nil
|
return s.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addToReplyMap(m map[string][]mastodon.ReplyInfo, key interface{}, val string, number int) {
|
||||||
|
if key == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
keyStr, ok := key.(string)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, ok = m[keyStr]
|
||||||
|
if !ok {
|
||||||
|
m[keyStr] = []mastodon.ReplyInfo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
m[keyStr] = append(m[keyStr], mastodon.ReplyInfo{val, number})
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-content {
|
.status-content {
|
||||||
margin: 8px 0;
|
margin: 4px 0 8px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-content p {
|
.status-content p {
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
height: 48px;
|
height: 48px;
|
||||||
width: 48px;
|
width: 48px;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status {
|
.status {
|
||||||
|
@ -118,6 +119,7 @@
|
||||||
height: 24px;
|
height: 24px;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
margin-bottom: -8px;
|
margin-bottom: -8px;
|
||||||
|
margin-right: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.retweet-info .status-dname{
|
.retweet-info .status-dname{
|
||||||
|
@ -161,3 +163,26 @@
|
||||||
.notification-follow-uname {
|
.notification-follow-uname {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status-reply-to {
|
||||||
|
vertical-align: center;
|
||||||
|
font-size: 10pt
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-reply-container .icon {
|
||||||
|
font-size: 10pt;
|
||||||
|
vertical-align: sub;
|
||||||
|
margin-right: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-reply-text {
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-reply {
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-reply-info-divider {
|
||||||
|
margin: 0 4px;
|
||||||
|
}
|
||||||
|
|
|
@ -11,17 +11,30 @@
|
||||||
{{block "status" .}}
|
{{block "status" .}}
|
||||||
<div class="status-container">
|
<div class="status-container">
|
||||||
<div>
|
<div>
|
||||||
{{if ne .Account.ID ""}}
|
{{if not .HideAccountInfo}}
|
||||||
<img class="status-profile-img" src="{{.Account.AvatarStatic}}" alt="profile-avatar" />
|
<img class="status-profile-img" src="{{.Account.AvatarStatic}}" alt="profile-avatar" />
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
{{if ne .Account.ID ""}}
|
{{if not .HideAccountInfo}}
|
||||||
<div class="status-name">
|
<div class="status-name">
|
||||||
<span class="status-dname"> {{WithEmojis .Account.DisplayName .Account.Emojis}} </span>
|
<span class="status-dname"> {{WithEmojis .Account.DisplayName .Account.Emojis}} </span>
|
||||||
<span class="status-uname"> {{.Account.Acct}} </span>
|
<span class="status-uname"> {{.Account.Acct}} </span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
<div class="status-reply-container">
|
||||||
|
{{if .InReplyToID}}
|
||||||
|
<span class="icon dripicons-forward"></span>
|
||||||
|
<a class="status-reply-to" href="{{if not .ShowReplies}}/thread/{{.InReplyToID}}{{end}}#status-{{.InReplyToID}}"> reply to {{.Pleroma.InReplyToAccountAcct}} </a>
|
||||||
|
{{if index .ReplyMap .ID}} <span class="status-reply-info-divider"> - </span> {{end}}
|
||||||
|
{{end}}
|
||||||
|
{{if .ShowReplies}}
|
||||||
|
{{if index .ReplyMap .ID}} <span class="status-reply-text"> replies: </span> {{end}}
|
||||||
|
{{range index .ReplyMap .ID}}
|
||||||
|
<a class="status-reply" href="#status-{{.ID}}">#{{.Number}}</a>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
<div class="status-content"> {{WithEmojis .Content .Emojis}} </div>
|
<div class="status-content"> {{WithEmojis .Content .Emojis}} </div>
|
||||||
<div class="status-media-container">
|
<div class="status-media-container">
|
||||||
{{range .MediaAttachments}}
|
{{range .MediaAttachments}}
|
||||||
|
|
|
@ -2,12 +2,10 @@
|
||||||
{{template "navigation.tmpl" .NavbarData}}
|
{{template "navigation.tmpl" .NavbarData}}
|
||||||
<div class="page-title"> Thread </div>
|
<div class="page-title"> Thread </div>
|
||||||
|
|
||||||
{{range .Context.Ancestors}}
|
{{range .Statuses}}
|
||||||
{{template "status.tmpl" .}}
|
{{template "status.tmpl" .}}
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{template "status.tmpl" .Status}}
|
{{if eq .ID $.ReplyToID}}
|
||||||
{{if .PostReply}}
|
|
||||||
<form class="timeline-post-form" action="/post" method="POST" enctype="multipart/form-data">
|
<form class="timeline-post-form" action="/post" method="POST" enctype="multipart/form-data">
|
||||||
<input type="hidden" name="reply_to_id" value="{{.ReplyToID}}" />
|
<input type="hidden" name="reply_to_id" value="{{.ReplyToID}}" />
|
||||||
<label for="post-content"> Reply to {{.Status.Account.DisplayName}} </label>
|
<label for="post-content"> Reply to {{.Status.Account.DisplayName}} </label>
|
||||||
|
@ -20,8 +18,6 @@
|
||||||
</form>
|
</form>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{range .Context.Descendants}}
|
|
||||||
{{template "status.tmpl" .}}
|
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{template "footer.tmpl"}}
|
{{template "footer.tmpl"}}
|
||||||
|
|
Loading…
Reference in New Issue