diff --git a/.gitignore b/.gitignore index 516f77b..79904fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ bloat database +bloat.gen.conf diff --git a/INSTALL b/INSTALL index c73fd78..8f8c6d4 100644 --- a/INSTALL +++ b/INSTALL @@ -20,6 +20,7 @@ bloat looks for a file named bloat.conf in the working directory and /etc/bloat in that order. You can also specify another file by using the -f flag. Comments in the config file describe what each config value does. For most cases, you only need to change the value of "client_website". +# cp bloat.gen.conf /etc/bloat.conf # $EDITOR /etc/bloat.conf 4. Create database directory diff --git a/Makefile b/Makefile index 1b32268..c38de6b 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,10 @@ all: bloat bloat: $(SRC) $(TMPL) $(GO) build $(GOFLAGS) -o bloat main.go + sed -e "s%=database%=/var/bloat%g" \ + -e "s%=templates%=$(SHAREPATH)/templates%g" \ + -e "s%=static%=$(SHAREPATH)/static%g" \ + < bloat.conf > bloat.gen.conf install: bloat mkdir -p $(DESTDIR)$(BINPATH) \ @@ -29,10 +33,6 @@ install: bloat chmod 0644 $(DESTDIR)$(SHAREPATH)/templates/* cp -r static/* $(DESTDIR)$(SHAREPATH)/static chmod 0644 $(DESTDIR)$(SHAREPATH)/static/* - sed -e "s%=database%=/var/bloat%g" \ - -e "s%=templates%=$(SHAREPATH)/templates%g" \ - -e "s%=static%=$(SHAREPATH)/static%g" \ - < bloat.conf > /etc/bloat.conf uninstall: rm -f $(DESTDIR)$(BINPATH)/bloat @@ -40,3 +40,4 @@ uninstall: clean: rm -f bloat + rm -f bloat.gen.conf diff --git a/mastodon/accounts.go b/mastodon/accounts.go index df0a3b7..dbd0a48 100644 --- a/mastodon/accounts.go +++ b/mastodon/accounts.go @@ -189,6 +189,7 @@ type Relationship struct { Following bool `json:"following"` FollowedBy bool `json:"followed_by"` Blocking bool `json:"blocking"` + BlockedBy bool `json:"blocked_by"` Muting bool `json:"muting"` MutingNotifications bool `json:"muting_notifications"` Subscribing bool `json:"subscribing"` diff --git a/mastodon/lists.go b/mastodon/lists.go index d323b79..1b76bdc 100644 --- a/mastodon/lists.go +++ b/mastodon/lists.go @@ -90,7 +90,7 @@ func (c *Client) DeleteList(ctx context.Context, id string) error { func (c *Client) AddToList(ctx context.Context, list string, accounts ...string) error { params := url.Values{} for _, acct := range accounts { - params.Add("account_ids", string(acct)) + params.Add("account_ids[]", string(acct)) } return c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/lists/%s/accounts", url.PathEscape(string(list))), params, nil, nil) @@ -100,7 +100,7 @@ func (c *Client) AddToList(ctx context.Context, list string, accounts ...string) func (c *Client) RemoveFromList(ctx context.Context, list string, accounts ...string) error { params := url.Values{} for _, acct := range accounts { - params.Add("account_ids", string(acct)) + params.Add("account_ids[]", string(acct)) } return c.doAPI(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/lists/%s/accounts", url.PathEscape(string(list))), params, nil, nil) diff --git a/mastodon/status.go b/mastodon/status.go index 8b148b3..f860c31 100644 --- a/mastodon/status.go +++ b/mastodon/status.go @@ -56,7 +56,6 @@ type Status struct { MediaAttachments []Attachment `json:"media_attachments"` Mentions []Mention `json:"mentions"` Tags []Tag `json:"tags"` - Card *Card `json:"card"` Application Application `json:"application"` Language string `json:"language"` Pinned interface{} `json:"pinned"` @@ -77,22 +76,6 @@ type Context struct { Descendants []*Status `json:"descendants"` } -// Card hold information for mastodon card. -type Card struct { - URL string `json:"url"` - Title string `json:"title"` - Description string `json:"description"` - Image string `json:"image"` - Type string `json:"type"` - AuthorName string `json:"author_name"` - AuthorURL string `json:"author_url"` - ProviderName string `json:"provider_name"` - ProviderURL string `json:"provider_url"` - HTML string `json:"html"` - Width int64 `json:"width"` - Height int64 `json:"height"` -} - // GetFavourites return the favorite list of the current user. func (c *Client) GetFavourites(ctx context.Context, pg *Pagination) ([]*Status, error) { var statuses []*Status @@ -123,16 +106,6 @@ func (c *Client) GetStatusContext(ctx context.Context, id string) (*Context, err return &context, nil } -// GetStatusCard return status specified by id. -func (c *Client) GetStatusCard(ctx context.Context, id string) (*Card, error) { - var card Card - err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%s/card", id), nil, &card, nil) - if err != nil { - return nil, err - } - return &card, nil -} - // GetRebloggedBy returns the account list of the user who reblogged the toot of id. func (c *Client) GetRebloggedBy(ctx context.Context, id string, pg *Pagination) ([]*Account, error) { var accounts []*Account @@ -301,7 +274,7 @@ func (c *Client) DeleteStatus(ctx context.Context, id string) error { } // Search search content with query. -func (c *Client) Search(ctx context.Context, q string, qType string, limit int, resolve bool, offset int, accountID string) (*Results, error) { +func (c *Client) Search(ctx context.Context, q string, qType string, limit int, resolve bool, offset int, accountID string, following bool) (*Results, error) { var results Results params := url.Values{} params.Set("q", q) @@ -309,6 +282,7 @@ func (c *Client) Search(ctx context.Context, q string, qType string, limit int, params.Set("limit", fmt.Sprint(limit)) params.Set("resolve", fmt.Sprint(resolve)) params.Set("offset", fmt.Sprint(offset)) + params.Set("following", fmt.Sprint(following)) if len(accountID) > 0 { params.Set("account_id", accountID) } diff --git a/renderer/model.go b/renderer/model.go index 385ac7c..726cee9 100644 --- a/renderer/model.go +++ b/renderer/model.go @@ -62,6 +62,19 @@ type TimelineData struct { PrevLink string } +type ListsData struct { + *CommonData + Lists []*mastodon.List +} + +type ListData struct { + *CommonData + List *mastodon.List + Accounts []*mastodon.Account + Q string + SearchAccounts []*mastodon.Account +} + type ThreadData struct { *CommonData Statuses []*mastodon.Status diff --git a/renderer/renderer.go b/renderer/renderer.go index f50e185..50fced7 100644 --- a/renderer/renderer.go +++ b/renderer/renderer.go @@ -1,11 +1,11 @@ package renderer import ( + "html/template" "io" "regexp" "strconv" "strings" - "text/template" "time" "bloat/mastodon" @@ -19,6 +19,8 @@ const ( NavPage = "nav.tmpl" RootPage = "root.tmpl" TimelinePage = "timeline.tmpl" + ListsPage = "lists.tmpl" + ListPage = "list.tmpl" ThreadPage = "thread.tmpl" QuickReplyPage = "quickreply.tmpl" StatusPopup = "status.tmpl" @@ -53,10 +55,7 @@ func emojiFilter(content string, emojis []mastodon.Emoji) string { var quoteRE = regexp.MustCompile("(?mU)(^|> *|\n)(>.*)( 0 { - content = spoiler + "
" + content - } +func statusContentFilter(content string, emojis []mastodon.Emoji, mentions []mastodon.Mention) string { content = quoteRE.ReplaceAllString(content, `$1$2$3`) var replacements []string for _, e := range emojis { @@ -75,45 +74,41 @@ func displayInteractionCount(c int64) string { return "" } -func DurToStr(dur time.Duration) string { - s := dur.Seconds() +func durUnit(s int64) (dur int64, unit string) { if s < 60 { - return strconv.Itoa(int(s)) + "s" + if s < 0 { + s = 0 + } + return s, "s" } - m := dur.Minutes() - if m < 60*2 { - return strconv.Itoa(int(m)) + "m" - } - h := dur.Hours() - if h < 24*2 { - return strconv.Itoa(int(h)) + "h" + m := s / 60 + h := m / 60 + if h < 2 { + return m, "m" } d := h / 24 - if d < 30*2 { - return strconv.Itoa(int(d)) + "d" + if d < 2 { + return h, "h" } mo := d / 30 - if mo < 12*2 { - return strconv.Itoa(int(mo)) + "mo" + if mo < 2 { + return d, "d" } - y := mo / 12 - return strconv.Itoa(int(y)) + "y" + y := d / 365 + if y < 2 { + return mo, "mo" + } + return y, "y" } func timeSince(t time.Time) string { - d := time.Since(t) - if d < 0 { - d = 0 - } - return DurToStr(d) + d, u := durUnit(time.Now().Unix() - t.Unix()) + return strconv.FormatInt(d, 10) + u } func timeUntil(t time.Time) string { - d := time.Until(t) - if d < 0 { - d = 0 - } - return DurToStr(d) + d, u := durUnit(t.Unix() - time.Now().Unix()) + return strconv.FormatInt(d, 10) + u } func formatTimeRFC3339(t time.Time) string { @@ -128,6 +123,14 @@ func withContext(data interface{}, ctx *Context) TemplateData { return TemplateData{data, ctx} } +func raw(s string) template.HTML { + return template.HTML(s) +} + +func rawCSS(s string) template.CSS { + return template.CSS(s) +} + type Renderer interface { Render(ctx *Context, writer io.Writer, page string, data interface{}) (err error) } @@ -147,6 +150,9 @@ func NewRenderer(templateGlobPattern string) (r *renderer, err error) { "FormatTimeRFC3339": formatTimeRFC3339, "FormatTimeRFC822": formatTimeRFC822, "WithContext": withContext, + "HTML": template.HTMLEscapeString, + "Raw": raw, + "RawCSS": rawCSS, }).ParseGlob(templateGlobPattern) if err != nil { return diff --git a/service/service.go b/service/service.go index c56114c..8bccd45 100644 --- a/service/service.go +++ b/service/service.go @@ -163,8 +163,8 @@ func (s *service) NavPage(c *client) (err error) { return s.renderer.Render(c.rctx, c.w, renderer.NavPage, data) } -func (s *service) TimelinePage(c *client, tType string, instance string, - maxID string, minID string) (err error) { +func (s *service) TimelinePage(c *client, tType, instance, listId, maxID, + minID string) (err error) { var nextLink, prevLink, title string var statuses []*mastodon.Status @@ -179,24 +179,46 @@ func (s *service) TimelinePage(c *client, tType string, instance string, return errInvalidArgument case "home": statuses, err = c.GetTimelineHome(c.ctx, &pg) + if err != nil { + return err + } title = "Timeline" case "direct": statuses, err = c.GetTimelineDirect(c.ctx, &pg) + if err != nil { + return err + } title = "Direct Timeline" case "local": statuses, err = c.GetTimelinePublic(c.ctx, true, "", &pg) + if err != nil { + return err + } title = "Local Timeline" case "remote": if len(instance) > 0 { statuses, err = c.GetTimelinePublic(c.ctx, false, instance, &pg) + if err != nil { + return err + } } title = "Remote Timeline" case "twkn": statuses, err = c.GetTimelinePublic(c.ctx, false, "", &pg) + if err != nil { + return err + } title = "The Whole Known Network" - } - if err != nil { - return err + case "list": + statuses, err = c.GetTimelineList(c.ctx, listId, &pg) + if err != nil { + return err + } + list, err := c.GetList(c.ctx, listId) + if err != nil { + return err + } + title = "List Timeline - " + list.Title } for i := range statuses { @@ -211,6 +233,9 @@ func (s *service) TimelinePage(c *client, tType string, instance string, if len(instance) > 0 { v.Set("instance", instance) } + if len(listId) > 0 { + v.Set("list", listId) + } prevLink = "/timeline/" + tType + "?" + v.Encode() } @@ -220,6 +245,9 @@ func (s *service) TimelinePage(c *client, tType string, instance string, if len(instance) > 0 { v.Set("instance", instance) } + if len(listId) > 0 { + v.Set("list", listId) + } nextLink = "/timeline/" + tType + "?" + v.Encode() } @@ -252,6 +280,70 @@ func addToReplyMap(m map[string][]mastodon.ReplyInfo, key interface{}, m[keyStr] = append(m[keyStr], mastodon.ReplyInfo{val, number}) } +func (s *service) ListsPage(c *client) (err error) { + lists, err := c.GetLists(c.ctx) + if err != nil { + return + } + + cdata := s.cdata(c, "Lists", 0, 0, "") + data := renderer.ListsData{ + Lists: lists, + CommonData: cdata, + } + return s.renderer.Render(c.rctx, c.w, renderer.ListsPage, data) +} + +func (s *service) AddList(c *client, title string) (err error) { + _, err = c.CreateList(c.ctx, title) + return err +} + +func (s *service) RemoveList(c *client, id string) (err error) { + return c.DeleteList(c.ctx, id) +} + +func (s *service) RenameList(c *client, id, title string) (err error) { + _, err = c.RenameList(c.ctx, id, title) + return err +} + +func (s *service) ListPage(c *client, id string, q string) (err error) { + list, err := c.GetList(c.ctx, id) + if err != nil { + return + } + accounts, err := c.GetListAccounts(c.ctx, id) + if err != nil { + return + } + var searchAccounts []*mastodon.Account + if len(q) > 0 { + result, err := c.Search(c.ctx, q, "accounts", 20, true, 0, id, true) + if err != nil { + return err + } + searchAccounts = result.Accounts + } + cdata := s.cdata(c, "List "+list.Title, 0, 0, "") + data := renderer.ListData{ + List: list, + Accounts: accounts, + Q: q, + SearchAccounts: searchAccounts, + CommonData: cdata, + } + return s.renderer.Render(c.rctx, c.w, renderer.ListPage, data) +} + +func (s *service) ListAddUser(c *client, id string, uid string) (err error) { + return c.AddToList(c.ctx, id, uid) +} + +func (s *service) ListRemoveUser(c *client, id string, uid string) (err error) { + return c.RemoveFromList(c.ctx, id, uid) +} + func (s *service) ThreadPage(c *client, id string, reply bool) (err error) { var pctx model.PostContext @@ -616,7 +708,7 @@ func (s *service) UserSearchPage(c *client, var results *mastodon.Results if len(q) > 0 { - results, err = c.Search(c.ctx, q, "statuses", 20, true, offset, id) + results, err = c.Search(c.ctx, q, "statuses", 20, true, offset, id, false) if err != nil { return err } @@ -627,7 +719,7 @@ func (s *service) UserSearchPage(c *client, if len(results.Statuses) == 20 { offset += 20 nextLink = fmt.Sprintf("/usersearch/%s?q=%s&offset=%d", id, - url.QueryEscape(q), offset) + q, offset) } if len(q) > 0 { @@ -674,7 +766,7 @@ func (s *service) SearchPage(c *client, var results *mastodon.Results if len(q) > 0 { - results, err = c.Search(c.ctx, q, qType, 20, true, offset, "") + results, err = c.Search(c.ctx, q, qType, 20, true, offset, "", false) if err != nil { return err } @@ -686,7 +778,7 @@ func (s *service) SearchPage(c *client, (qType == "statuses" && len(results.Statuses) == 20) { offset += 20 nextLink = fmt.Sprintf("/search?q=%s&type=%s&offset=%d", - url.QueryEscape(q), qType, offset) + q, qType, offset) } if len(q) > 0 { diff --git a/service/transport.go b/service/transport.go index 02e6106..1fbce99 100644 --- a/service/transport.go +++ b/service/transport.go @@ -169,9 +169,10 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { tType, _ := mux.Vars(c.r)["type"] q := c.r.URL.Query() instance := q.Get("instance") + list := q.Get("list") maxID := q.Get("max_id") minID := q.Get("min_id") - return s.TimelinePage(c, tType, instance, maxID, minID) + return s.TimelinePage(c, tType, instance, list, maxID, minID) }, SESSION, HTML) defaultTimelinePage := handle(func(c *client) error { @@ -606,6 +607,72 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { return nil }, CSRF, HTML) + listsPage := handle(func(c *client) error { + return s.ListsPage(c) + }, SESSION, HTML) + + addList := handle(func(c *client) error { + title := c.r.FormValue("title") + err := s.AddList(c, title) + if err != nil { + return err + } + redirect(c, c.r.FormValue("referrer")) + return nil + }, CSRF, HTML) + + removeList := handle(func(c *client) error { + id, _ := mux.Vars(c.r)["id"] + err := s.RemoveList(c, id) + if err != nil { + return err + } + redirect(c, c.r.FormValue("referrer")) + return nil + }, CSRF, HTML) + + renameList := handle(func(c *client) error { + id, _ := mux.Vars(c.r)["id"] + title := c.r.FormValue("title") + err := s.RenameList(c, id, title) + if err != nil { + return err + } + redirect(c, c.r.FormValue("referrer")) + return nil + }, CSRF, HTML) + + listPage := handle(func(c *client) error { + id, _ := mux.Vars(c.r)["id"] + q := c.r.URL.Query() + sq := q.Get("q") + return s.ListPage(c, id, sq) + }, SESSION, HTML) + + listAddUser := handle(func(c *client) error { + id, _ := mux.Vars(c.r)["id"] + q := c.r.URL.Query() + uid := q.Get("uid") + err := s.ListAddUser(c, id, uid) + if err != nil { + return err + } + redirect(c, c.r.FormValue("referrer")) + return nil + }, CSRF, HTML) + + listRemoveUser := handle(func(c *client) error { + id, _ := mux.Vars(c.r)["id"] + q := c.r.URL.Query() + uid := q.Get("uid") + err := s.ListRemoveUser(c, id, uid) + if err != nil { + return err + } + redirect(c, c.r.FormValue("referrer")) + return nil + }, CSRF, HTML) + signout := handle(func(c *client) error { s.Signout(c) setSessionCookie(c.w, "", 0) @@ -699,6 +766,13 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { r.HandleFunc("/unbookmark/{id}", unBookmark).Methods(http.MethodPost) r.HandleFunc("/filter", filter).Methods(http.MethodPost) r.HandleFunc("/unfilter/{id}", unFilter).Methods(http.MethodPost) + r.HandleFunc("/lists", listsPage).Methods(http.MethodGet) + r.HandleFunc("/list", addList).Methods(http.MethodPost) + r.HandleFunc("/list/{id}", listPage).Methods(http.MethodGet) + r.HandleFunc("/list/{id}/remove", removeList).Methods(http.MethodPost) + r.HandleFunc("/list/{id}/rename", renameList).Methods(http.MethodPost) + r.HandleFunc("/list/{id}/adduser", listAddUser).Methods(http.MethodPost) + r.HandleFunc("/list/{id}/removeuser", listRemoveUser).Methods(http.MethodPost) r.HandleFunc("/signout", signout).Methods(http.MethodPost) r.HandleFunc("/fluoride/like/{id}", fLike).Methods(http.MethodPost) r.HandleFunc("/fluoride/unlike/{id}", fUnlike).Methods(http.MethodPost) diff --git a/static/fluoride.js b/static/fluoride.js index 279483f..e6624d1 100644 --- a/static/fluoride.js +++ b/static/fluoride.js @@ -152,6 +152,7 @@ function replyToLinkLocal(a) { var copy = status.cloneNode(true); copy.id = "reply-to-popup"; var ract = event.target.getBoundingClientRect(); + copy.style["max-width"] = (window.innerWidth - ract.left - 32) + "px"; if (ract.top > window.innerHeight / 2) { copy.style.bottom = (window.innerHeight - window.scrollY - ract.top) + "px"; @@ -245,6 +246,7 @@ function handleReplyLink(a) { var copy = status.cloneNode(true); copy.id = "reply-popup"; var ract = event.target.getBoundingClientRect(); + copy.style["max-width"] = (window.innerWidth - 98) + "px"; if (ract.left > window.innerWidth / 2) { copy.style.right = (window.innerWidth - ract.right - 12) + "px"; @@ -334,6 +336,20 @@ function handleImgPreview(a) { } } +function onPaste(e) { + if (!e.clipboardData.files) + return; + var fp = document.querySelector("#post-file-picker") + var dt = new DataTransfer(); + for (var i = 0; i < fp.files.length; i++) { + dt.items.add(fp.files[i]); + } + for (var i = 0; i < e.clipboardData.files.length; i++) { + dt.items.add(e.clipboardData.files[i]); + } + fp.files = dt.files; +} + document.addEventListener("DOMContentLoaded", function() { checkCSRFToken(); checkAntiDopamineMode(); @@ -363,7 +379,7 @@ document.addEventListener("DOMContentLoaded", function() { } } - var links = document.querySelectorAll(".user-profile-decription a"); + var links = document.querySelectorAll(".user-profile-decription a, .user-fields a"); for (var j = 0; j < links.length; j++) { links[j].target = "_blank"; } @@ -372,6 +388,10 @@ document.addEventListener("DOMContentLoaded", function() { for (var j = 0; j < links.length; j++) { handleImgPreview(links[j]); } + + var pf = document.querySelector(".post-form") + if (pf) + pf.addEventListener("paste", onPaste); }); // @license-end diff --git a/static/style.css b/static/style.css index 4e2a196..19cceab 100644 --- a/static/style.css +++ b/static/style.css @@ -194,11 +194,14 @@ textarea { border-color: #777777; } -.notification-container.favourite .status-container, -.notification-container.reblog .status-container { +.notification-container .status-container { opacity: 0.6; } +.notification-container.mention .status-container { + opacity: unset; +} + .notification-info-text span { vertical-align: middle; } @@ -277,7 +280,8 @@ textarea { margin-top: 2px; } -.user-profile-decription { +.user-profile-decription, +.user-fields { overflow-wrap: break-word; margin: 8px 0; } @@ -286,10 +290,22 @@ textarea { margin: 0; } +.user-profile-decription img { + height: auto; + width: auto; + max-height: 240px; + max-width: 280px; + object-fit: contain; +} + .d-inline { display: inline; } +.p-0 { + padding: 0; +} + .btn-link { border: none; outline: none; @@ -354,10 +370,6 @@ a:hover, display: none; } -.post-form-field>* { - vertical-align: middle; -} - .emoji-item-container { width: 220px; display: inline-block; @@ -422,9 +434,6 @@ img.emoji { margin-right: 2px; } -.user-list-container { -} - .user-list-item { overflow: auto; margin: 0 0 12px 0; @@ -441,6 +450,10 @@ img.emoji { overflow: auto; } +.user-list-action { + margin: 0 12px; +} + #settings-form { margin: 8px 0; } @@ -449,10 +462,6 @@ img.emoji { margin: 4px 0; } -.settings-form-field>* { - vertical-align: middle; -} - #settings-form button[type=submit] { margin-top: 8px; } diff --git a/templates/about.tmpl b/templates/about.tmpl index 54316cf..0e4d001 100644 --- a/templates/about.tmpl +++ b/templates/about.tmpl @@ -46,11 +46,11 @@ 6 - Settings + Lists 7 - Signout + Settings 8 diff --git a/templates/emoji.tmpl b/templates/emoji.tmpl index ee84522..4b07e81 100644 --- a/templates/emoji.tmpl +++ b/templates/emoji.tmpl @@ -6,7 +6,7 @@ {{range .Emojis}}
- {{.ShortCode}} + {{.ShortCode}} :{{.ShortCode}}:
diff --git a/templates/header.tmpl b/templates/header.tmpl index 8eb53f6..8a1b0ca 100644 --- a/templates/header.tmpl +++ b/templates/header.tmpl @@ -17,7 +17,7 @@ {{if .RefreshInterval}} {{end}} - {{if gt .Count 0}}({{.Count}}){{end}} {{.Title | html}} + {{if gt .Count 0}}({{.Count}}){{end}} {{.Title}} {{if .CustomCSS}} @@ -26,7 +26,7 @@ {{end}} {{if $.Ctx.UserCSS}} - + {{end}} diff --git a/templates/list.tmpl b/templates/list.tmpl new file mode 100644 index 0000000..dcc6ee8 --- /dev/null +++ b/templates/list.tmpl @@ -0,0 +1,63 @@ +{{with .Data}} +{{template "header.tmpl" (WithContext .CommonData $.Ctx)}} +
List {{.List.Title}}
+ +
+ + + + +
+ +
Users
+{{if .Accounts}} + +{{range .Accounts}} + + + + +{{end}} +
{{template "userlistitem.tmpl" (WithContext . $.Ctx)}} +
+ + + +
+
+{{else}} +
No data found
+{{end}} + +
Add user
+
+ + + + + +
+ +{{if .Q}} +{{if .SearchAccounts}} + +{{range .SearchAccounts}} + + + + +{{end}} +
{{template "userlistitem.tmpl" (WithContext . $.Ctx)}} +
+ + + +
+
+{{else}} +
No data found
+{{end}} +{{end}} + +{{template "footer.tmpl"}} +{{end}} diff --git a/templates/lists.tmpl b/templates/lists.tmpl new file mode 100644 index 0000000..27979cb --- /dev/null +++ b/templates/lists.tmpl @@ -0,0 +1,35 @@ +{{with .Data}} +{{template "header.tmpl" (WithContext .CommonData $.Ctx)}} +
Lists
+ +{{range .Lists}} +
+ {{.Title}} timeline + - +
+ +
+ - +
+ + + +
+
+{{else}} +
No data found
+{{end}} + +
Add list
+
+ + + + + + + +
+ +{{template "footer.tmpl"}} +{{end}} diff --git a/templates/nav.tmpl b/templates/nav.tmpl index ea18a5f..db88aa0 100644 --- a/templates/nav.tmpl +++ b/templates/nav.tmpl @@ -8,7 +8,7 @@
- settings + lists + settings
- +
about
diff --git a/templates/notification.tmpl b/templates/notification.tmpl index a7f88a7..f62726b 100644 --- a/templates/notification.tmpl +++ b/templates/notification.tmpl @@ -28,7 +28,7 @@
- {{EmojiFilter (html .Account.DisplayName) .Account.Emojis}} + {{EmojiFilter (HTML .Account.DisplayName) .Account.Emojis | Raw}} followed you - @@ -48,7 +48,7 @@
- {{EmojiFilter (html .Account.DisplayName) .Account.Emojis}} + {{EmojiFilter (HTML .Account.DisplayName) .Account.Emojis | Raw}} wants to follow you - diff --git a/templates/postform.tmpl b/templates/postform.tmpl index 35171a4..0af50fb 100644 --- a/templates/postform.tmpl +++ b/templates/postform.tmpl @@ -5,7 +5,7 @@ {{if .ReplyContext}} - + {{else}} {{end}} diff --git a/templates/requestlist.tmpl b/templates/requestlist.tmpl index d9b2b0a..1a51e31 100644 --- a/templates/requestlist.tmpl +++ b/templates/requestlist.tmpl @@ -9,7 +9,7 @@
-
{{EmojiFilter (html .DisplayName) .Emojis}}
+
{{EmojiFilter (HTML .DisplayName) .Emojis | Raw}}
@{{.Acct}}
diff --git a/templates/search.tmpl b/templates/search.tmpl index 7338cad..0473d4a 100644 --- a/templates/search.tmpl +++ b/templates/search.tmpl @@ -5,7 +5,7 @@
- + diff --git a/templates/status.tmpl b/templates/status.tmpl index dda1d79..5ada84e 100644 --- a/templates/status.tmpl +++ b/templates/status.tmpl @@ -5,7 +5,7 @@ avatar - {{EmojiFilter (html .Account.DisplayName) .Account.Emojis}} + {{EmojiFilter (HTML .Account.DisplayName) .Account.Emojis | Raw}} @{{.Account.Acct}} @@ -23,7 +23,7 @@
- {{EmojiFilter (html .Account.DisplayName) .Account.Emojis}} + {{EmojiFilter (HTML .Account.DisplayName) .Account.Emojis | Raw}} @{{.Account.Acct}} @@ -91,7 +91,10 @@ {{end}}
{{if (or .Content .SpoilerText)}} -
{{StatusContentFilter (html .SpoilerText) .Content .Emojis .Mentions}}
+
+ {{if .SpoilerText}}{{EmojiFilter (HTML .SpoilerText) .Emojis | Raw}}
{{end}} + {{StatusContentFilter .Content .Emojis .Mentions | Raw}} +
{{end}} {{if .MediaAttachments}}
@@ -100,7 +103,7 @@ {{if eq .Type "image"}} {{if $.Ctx.HideAttachments}} - {{if .Description}}[{{.Description}}]{{else}}[image]{{end}} + [image{{if $s.Sensitive}}/nsfw{{end}}{{if .Description}}: {{.Description}}{{end}}] {{else}} @@ -114,7 +117,7 @@ {{else if eq .Type "audio"}} {{if $.Ctx.HideAttachments}} - {{if .Description}}[{{.Description}}]{{else}}[audio]{{end}} + [audio{{if $s.Sensitive}}/nsfw{{end}}{{if .Description}}: {{.Description}}{{end}}] {{else}}
diff --git a/templates/userlist.tmpl b/templates/userlist.tmpl index b8e0e5d..f206397 100644 --- a/templates/userlist.tmpl +++ b/templates/userlist.tmpl @@ -1,19 +1,7 @@ {{with .Data}}
{{range .}} -
- -
-
{{EmojiFilter (html .DisplayName) .Emojis}}
- -
@{{.Acct}}
-
-
-
+ {{template "userlistitem.tmpl" (WithContext . $.Ctx)}} {{else}}
No data found
{{end}} diff --git a/templates/userlistitem.tmpl b/templates/userlistitem.tmpl new file mode 100644 index 0000000..50b9d0c --- /dev/null +++ b/templates/userlistitem.tmpl @@ -0,0 +1,15 @@ +{{with .Data}} +
+
+ + avatar + +
+
+
{{EmojiFilter (HTML .DisplayName) .Emojis | Raw}}
+ +
@{{.Acct}}
+
+
+
+{{end}} diff --git a/templates/usersearch.tmpl b/templates/usersearch.tmpl index e95129c..78fa7b8 100644 --- a/templates/usersearch.tmpl +++ b/templates/usersearch.tmpl @@ -1,11 +1,11 @@ {{with .Data}} {{template "header.tmpl" (WithContext .CommonData $.Ctx)}} -
Search {{EmojiFilter (html .User.DisplayName) .User.Emojis}}'s statuses
+
Search {{EmojiFilter (HTML .User.DisplayName) .User.Emojis | Raw}}'s statuses
- - +