1diff --git a/pkg/view/media.go b/pkg/view/media.go
2index 6d380e25a294884a3bc8de9e9c090b1bd33bb31a..4bf8d68aa5fa4de6385a0f60bfb69e75b9d41243 100644
3--- a/pkg/view/media.go
4+++ b/pkg/view/media.go
5@@ -5,20 +5,15 @@ "strconv"
6
7 "github.com/valyala/fasthttp"
8
9- "git.sr.ht/~gabrielgio/img"
10 "git.sr.ht/~gabrielgio/img/pkg/database/repository"
11 "git.sr.ht/~gabrielgio/img/pkg/ext"
12+ "git.sr.ht/~gabrielgio/img/templates"
13 )
14
15 type (
16 MediaView struct {
17 mediaRepository repository.MediaRepository
18 userRepository repository.UserRepository
19- }
20-
21- Page struct {
22- Medias []*repository.Media
23- Next *repository.Pagination
24 }
25 )
26
27@@ -77,16 +72,16 @@ if err != nil {
28 return err
29 }
30
31- err = img.Render(ctx, "media.html", &img.HTMLView[*Page]{
32- Title: "Media",
33- Data: &Page{
34- Medias: medias,
35- Next: &repository.Pagination{
36- Size: p.Size,
37- Page: p.Page + 1,
38- },
39+ page := &templates.MediaPage{
40+ Medias: medias,
41+ Next: &repository.Pagination{
42+ Size: p.Size,
43+ Page: p.Page + 1,
44 },
45- })
46+ }
47+
48+ templates.WritePageTemplate(ctx, page)
49+
50 if err != nil {
51 return err
52 }
53diff --git a/templates/base.qtpl b/templates/base.qtpl
54new file mode 100644
55index 0000000000000000000000000000000000000000..cbde3552fcaa1f580d3f4afad03bece2aac529a2
56--- /dev/null
57+++ b/templates/base.qtpl
58@@ -0,0 +1,47 @@
59+This is a base page template. All the other template pages implement this interface.
60+
61+{% interface
62+Page {
63+ Title()
64+ Content()
65+ Script()
66+}
67+%}
68+
69+
70+Page prints a page implementing Page interface.
71+{% func PageTemplate(p Page) %}
72+<html lang="en">
73+ <head>
74+ <meta charset="utf-8">
75+ <title>img | {%= p.Title() %}</title>
76+ <link rel="stylesheet" href="/static/main.css">
77+ <link rel="icon" href="/static/square.svg" sizes="any" type="image/svg+xml">
78+ <meta name="viewport" content="width=device-width, initial-scale=1" />
79+ </head>
80+ <body>
81+ <nav class="navbar">
82+ <div class="navbar-start">
83+ <a href="/fs" class="navbar-item">
84+ files
85+ </a>
86+ <a href="/media" class="navbar-item">
87+ media
88+ </a>
89+ <a href="/settings" class="navbar-item">
90+ settings
91+ </a>
92+ </div>
93+ </nav>
94+ <div class="container">
95+ {%= p.Content() %}
96+ </div>
97+ </body>
98+ {%= p.Script() %}
99+</html>
100+{% endfunc %}
101+
102+{% code type BasePage struct {} %}
103+{% func (p *BasePage) Title() %}Empty{% endfunc %}
104+{% func (p *BasePage) Body() %}HelloWorld{% endfunc %}
105+{% func (p *BasePage) Script() %}{% endfunc %}
106diff --git a/templates/media.qtpl b/templates/media.qtpl
107new file mode 100644
108index 0000000000000000000000000000000000000000..88ce5820e3813ff1962f1ab3d4d06e311cebd231
109--- /dev/null
110+++ b/templates/media.qtpl
111@@ -0,0 +1,37 @@
112+{% import "git.sr.ht/~gabrielgio/img/pkg/database/repository" %}
113+
114+{% code
115+type MediaPage struct {
116+ Medias []*repository.Media
117+ Next *repository.Pagination
118+}
119+%}
120+
121+{% func (p *MediaPage) Title() %}
122+Media
123+{% endfunc %}
124+
125+
126+{% func (p *MediaPage) Content() %}
127+<div class="columns is-multiline">
128+{% for _, media := range p.Medias %}
129+ <div class="card-image">
130+ {% if media.IsVideo() %}
131+ <video controls muted="true" poster="/media/thumbnail?path_hash={%s media.PathHash %}" preload="none">
132+ <source src="/media/image?path_hash={%s media.PathHash %}" type="{%s media.MIMEType %}">
133+ </video>
134+ {% else %}
135+ <figure class="image is-fit">
136+ <img src="/media/thumbnail?path_hash={%s media.PathHash %}">
137+ </figure>
138+ {% endif %}
139+ </div>
140+{% endfor %}
141+</div>
142+<div class="row">
143+ <a href="/media?page={%d p.Next.Page %}" class="button is-pulled-right">next</a>
144+</div>
145+{% endfunc %}
146+
147+{% func (p *MediaPage) Script() %}
148+{% endfunc %}