aboutsummaryrefslogtreecommitdiff
path: root/renderer/renderer.go
blob: c3d35265abe0ee80ba22c954ab4e2415e50689e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package renderer

import (
	"context"
	"io"
	"strconv"
	"strings"
	"text/template"
	"time"

	"mastodon"
)

type Renderer interface {
	RenderErrorPage(ctx context.Context, writer io.Writer, err error)
	RenderHomePage(ctx context.Context, writer io.Writer) (err error)
	RenderSigninPage(ctx context.Context, writer io.Writer) (err error)
	RenderTimelinePage(ctx context.Context, writer io.Writer, data *TimelinePageTemplateData) (err error)
	RenderThreadPage(ctx context.Context, writer io.Writer, data *ThreadPageTemplateData) (err error)
}

type renderer struct {
	template *template.Template
}

func NewRenderer(templateGlobPattern string) (r *renderer, err error) {
	t := template.New("default")
	t, err = t.Funcs(template.FuncMap{
		"WithEmojis":              WithEmojis,
		"DisplayInteractionCount": DisplayInteractionCount,
		"TimeSince":               TimeSince,
		"FormatTimeRFC3339":       FormatTimeRFC3339,
	}).ParseGlob(templateGlobPattern)
	if err != nil {
		return
	}
	return &renderer{
		template: t,
	}, nil
}

func (r *renderer) RenderErrorPage(ctx context.Context, writer io.Writer, err error) {
	r.template.ExecuteTemplate(writer, "error.tmpl", err)
	return
}

func (r *renderer) RenderHomePage(ctx context.Context, writer io.Writer) (err error) {
	return r.template.ExecuteTemplate(writer, "homepage.tmpl", nil)
}

func (r *renderer) RenderSigninPage(ctx context.Context, writer io.Writer) (err error) {
	return r.template.ExecuteTemplate(writer, "signin.tmpl", nil)
}

func (r *renderer) RenderTimelinePage(ctx context.Context, writer io.Writer, data *TimelinePageTemplateData) (err error) {
	return r.template.ExecuteTemplate(writer, "timeline.tmpl", data)
}

func (r *renderer) RenderThreadPage(ctx context.Context, writer io.Writer, data *ThreadPageTemplateData) (err error) {
	return r.template.ExecuteTemplate(writer, "thread.tmpl", data)
}

func WithEmojis(content string, emojis []mastodon.Emoji) string {
	var emojiNameContentPair []string
	for _, e := range emojis {
		emojiNameContentPair = append(emojiNameContentPair, ":"+e.ShortCode+":", "<img class=\"status-emoji\" src=\""+e.URL+"\" alt=\""+e.ShortCode+"\" />")
	}
	return strings.NewReplacer(emojiNameContentPair...).Replace(content)
}

func DisplayInteractionCount(c int64) string {
	if c > 0 {
		return strconv.Itoa(int(c))
	}
	return ""
}

func TimeSince(t time.Time) string {
	dur := time.Since(t)

	s := dur.Seconds()
	if s < 60 {
		return strconv.Itoa(int(s)) + "s"
	}

	m := dur.Minutes()
	if m < 60 {
		return strconv.Itoa(int(m)) + "m"
	}

	h := dur.Hours()
	if h < 24 {
		return strconv.Itoa(int(h)) + "h"
	}

	d := h / 24
	if d < 30 {
		return strconv.Itoa(int(d)) + "d"
	}

	mo := d / 30
	if mo < 12 {
		return strconv.Itoa(int(mo)) + "mo"
	}

	y := m / 12
	return strconv.Itoa(int(y)) + "y"
}

func FormatTimeRFC3339(t time.Time) string {
	return t.Format(time.RFC3339)
}