3eb04572048b77b6a748f06175f131a2d3586016
[bloat] / renderer / renderer.go
1 package renderer
2
3 import (
4         "context"
5         "io"
6         "strconv"
7         "strings"
8         "text/template"
9         "time"
10
11         "mastodon"
12 )
13
14 type Renderer interface {
15         RenderErrorPage(ctx context.Context, writer io.Writer, err error)
16         RenderHomePage(ctx context.Context, writer io.Writer) (err error)
17         RenderSigninPage(ctx context.Context, writer io.Writer) (err error)
18         RenderTimelinePage(ctx context.Context, writer io.Writer, data *TimelinePageTemplateData) (err error)
19         RenderThreadPage(ctx context.Context, writer io.Writer, data *ThreadPageTemplateData) (err error)
20         RenderNotificationPage(ctx context.Context, writer io.Writer, data *NotificationPageTemplateData) (err error)
21         RenderUserPage(ctx context.Context, writer io.Writer, data *UserPageTemplateData) (err error)
22 }
23
24 type renderer struct {
25         template *template.Template
26 }
27
28 func NewRenderer(templateGlobPattern string) (r *renderer, err error) {
29         t := template.New("default")
30         t, err = t.Funcs(template.FuncMap{
31                 "WithEmojis":              WithEmojis,
32                 "DisplayInteractionCount": DisplayInteractionCount,
33                 "TimeSince":               TimeSince,
34                 "FormatTimeRFC3339":       FormatTimeRFC3339,
35         }).ParseGlob(templateGlobPattern)
36         if err != nil {
37                 return
38         }
39         return &renderer{
40                 template: t,
41         }, nil
42 }
43
44 func (r *renderer) RenderErrorPage(ctx context.Context, writer io.Writer, err error) {
45         r.template.ExecuteTemplate(writer, "error.tmpl", err)
46         return
47 }
48
49 func (r *renderer) RenderHomePage(ctx context.Context, writer io.Writer) (err error) {
50         return r.template.ExecuteTemplate(writer, "homepage.tmpl", nil)
51 }
52
53 func (r *renderer) RenderSigninPage(ctx context.Context, writer io.Writer) (err error) {
54         return r.template.ExecuteTemplate(writer, "signin.tmpl", nil)
55 }
56
57 func (r *renderer) RenderTimelinePage(ctx context.Context, writer io.Writer, data *TimelinePageTemplateData) (err error) {
58         return r.template.ExecuteTemplate(writer, "timeline.tmpl", data)
59 }
60
61 func (r *renderer) RenderThreadPage(ctx context.Context, writer io.Writer, data *ThreadPageTemplateData) (err error) {
62         return r.template.ExecuteTemplate(writer, "thread.tmpl", data)
63 }
64
65 func (r *renderer) RenderNotificationPage(ctx context.Context, writer io.Writer, data *NotificationPageTemplateData) (err error) {
66         return r.template.ExecuteTemplate(writer, "notification.tmpl", data)
67 }
68
69 func (r *renderer) RenderUserPage(ctx context.Context, writer io.Writer, data *UserPageTemplateData) (err error) {
70         return r.template.ExecuteTemplate(writer, "user.tmpl", data)
71 }
72
73 func WithEmojis(content string, emojis []mastodon.Emoji) string {
74         var emojiNameContentPair []string
75         for _, e := range emojis {
76                 emojiNameContentPair = append(emojiNameContentPair, ":"+e.ShortCode+":", "<img class=\"status-emoji\" src=\""+e.URL+"\" alt=\""+e.ShortCode+"\" />")
77         }
78         return strings.NewReplacer(emojiNameContentPair...).Replace(content)
79 }
80
81 func DisplayInteractionCount(c int64) string {
82         if c > 0 {
83                 return strconv.Itoa(int(c))
84         }
85         return ""
86 }
87
88 func TimeSince(t time.Time) string {
89         dur := time.Since(t)
90
91         s := dur.Seconds()
92         if s < 60 {
93                 return strconv.Itoa(int(s)) + "s"
94         }
95
96         m := dur.Minutes()
97         if m < 60 {
98                 return strconv.Itoa(int(m)) + "m"
99         }
100
101         h := dur.Hours()
102         if h < 24 {
103                 return strconv.Itoa(int(h)) + "h"
104         }
105
106         d := h / 24
107         if d < 30 {
108                 return strconv.Itoa(int(d)) + "d"
109         }
110
111         mo := d / 30
112         if mo < 12 {
113                 return strconv.Itoa(int(mo)) + "mo"
114         }
115
116         y := mo / 12
117         return strconv.Itoa(int(y)) + "y"
118 }
119
120 func FormatTimeRFC3339(t time.Time) string {
121         return t.Format(time.RFC3339)
122 }