14 type Renderer interface {
15 RenderErrorPage(ctx context.Context, writer io.Writer, data *ErrorData)
16 RenderHomePage(ctx context.Context, writer io.Writer, data *HomePageData) (err error)
17 RenderSigninPage(ctx context.Context, writer io.Writer, data *SigninData) (err error)
18 RenderTimelinePage(ctx context.Context, writer io.Writer, data *TimelineData) (err error)
19 RenderThreadPage(ctx context.Context, writer io.Writer, data *ThreadData) (err error)
20 RenderNotificationPage(ctx context.Context, writer io.Writer, data *NotificationData) (err error)
21 RenderUserPage(ctx context.Context, writer io.Writer, data *UserData) (err error)
22 RenderAboutPage(ctx context.Context, writer io.Writer, data *AboutData) (err error)
23 RenderEmojiPage(ctx context.Context, writer io.Writer, data *EmojiData) (err error)
24 RenderLikedByPage(ctx context.Context, writer io.Writer, data *LikedByData) (err error)
25 RenderRetweetedByPage(ctx context.Context, writer io.Writer, data *RetweetedByData) (err error)
26 RenderSearchPage(ctx context.Context, writer io.Writer, data *SearchData) (err error)
27 RenderSettingsPage(ctx context.Context, writer io.Writer, data *SettingsData) (err error)
30 type renderer struct {
31 template *template.Template
34 func NewRenderer(templateGlobPattern string) (r *renderer, err error) {
35 t := template.New("default")
36 t, err = t.Funcs(template.FuncMap{
37 "EmojiFilter": EmojiFilter,
38 "StatusContentFilter": StatusContentFilter,
39 "DisplayInteractionCount": DisplayInteractionCount,
40 "TimeSince": TimeSince,
41 "FormatTimeRFC3339": FormatTimeRFC3339,
42 }).ParseGlob(templateGlobPattern)
51 func (r *renderer) RenderErrorPage(ctx context.Context, writer io.Writer, errorData *ErrorData) {
52 r.template.ExecuteTemplate(writer, "error.tmpl", errorData)
56 func (r *renderer) RenderHomePage(ctx context.Context, writer io.Writer, homePageData *HomePageData) (err error) {
57 return r.template.ExecuteTemplate(writer, "homepage.tmpl", homePageData)
60 func (r *renderer) RenderSigninPage(ctx context.Context, writer io.Writer, signinData *SigninData) (err error) {
61 return r.template.ExecuteTemplate(writer, "signin.tmpl", signinData)
64 func (r *renderer) RenderTimelinePage(ctx context.Context, writer io.Writer, data *TimelineData) (err error) {
65 return r.template.ExecuteTemplate(writer, "timeline.tmpl", data)
68 func (r *renderer) RenderThreadPage(ctx context.Context, writer io.Writer, data *ThreadData) (err error) {
69 return r.template.ExecuteTemplate(writer, "thread.tmpl", data)
72 func (r *renderer) RenderNotificationPage(ctx context.Context, writer io.Writer, data *NotificationData) (err error) {
73 return r.template.ExecuteTemplate(writer, "notification.tmpl", data)
76 func (r *renderer) RenderUserPage(ctx context.Context, writer io.Writer, data *UserData) (err error) {
77 return r.template.ExecuteTemplate(writer, "user.tmpl", data)
80 func (r *renderer) RenderAboutPage(ctx context.Context, writer io.Writer, data *AboutData) (err error) {
81 return r.template.ExecuteTemplate(writer, "about.tmpl", data)
84 func (r *renderer) RenderEmojiPage(ctx context.Context, writer io.Writer, data *EmojiData) (err error) {
85 return r.template.ExecuteTemplate(writer, "emoji.tmpl", data)
88 func (r *renderer) RenderLikedByPage(ctx context.Context, writer io.Writer, data *LikedByData) (err error) {
89 return r.template.ExecuteTemplate(writer, "likedby.tmpl", data)
92 func (r *renderer) RenderRetweetedByPage(ctx context.Context, writer io.Writer, data *RetweetedByData) (err error) {
93 return r.template.ExecuteTemplate(writer, "retweetedby.tmpl", data)
96 func (r *renderer) RenderSearchPage(ctx context.Context, writer io.Writer, data *SearchData) (err error) {
97 return r.template.ExecuteTemplate(writer, "search.tmpl", data)
100 func (r *renderer) RenderSettingsPage(ctx context.Context, writer io.Writer, data *SettingsData) (err error) {
101 return r.template.ExecuteTemplate(writer, "settings.tmpl", data)
104 func EmojiFilter(content string, emojis []mastodon.Emoji) string {
105 var replacements []string
106 for _, e := range emojis {
107 replacements = append(replacements, ":"+e.ShortCode+":", "<img class=\"status-emoji\" src=\""+e.URL+"\" alt=\""+e.ShortCode+"\" title=\""+e.ShortCode+"\" />")
109 return strings.NewReplacer(replacements...).Replace(content)
112 func StatusContentFilter(spoiler string, content string, emojis []mastodon.Emoji, mentions []mastodon.Mention) string {
113 if len(spoiler) > 0 {
114 content = spoiler + "<br />" + content
116 var replacements []string
117 for _, e := range emojis {
118 replacements = append(replacements, ":"+e.ShortCode+":", "<img class=\"status-emoji\" src=\""+e.URL+"\" alt=\""+e.ShortCode+"\" title=\""+e.ShortCode+"\" />")
120 for _, m := range mentions {
121 replacements = append(replacements, "\""+m.URL+"\"", "\"/user/"+m.ID+"\"")
123 return strings.NewReplacer(replacements...).Replace(content)
126 func DisplayInteractionCount(c int64) string {
128 return strconv.Itoa(int(c))
133 func TimeSince(t time.Time) string {
138 return strconv.Itoa(int(s)) + "s"
143 return strconv.Itoa(int(m)) + "m"
148 return strconv.Itoa(int(h)) + "h"
153 return strconv.Itoa(int(d)) + "d"
158 return strconv.Itoa(int(mo)) + "mo"
162 return strconv.Itoa(int(y)) + "y"
165 func FormatTimeRFC3339(t time.Time) string {
166 return t.Format(time.RFC3339)