1diff --git a/pkg/service/filesystem.go b/pkg/service/filesystem.go
2index 2e4b51099efa02ec811011baa731bd4f4ae2795e..b4479ea3d5cea80dddb58e09f5265d3469f1964e 100644
3--- a/pkg/service/filesystem.go
4+++ b/pkg/service/filesystem.go
5@@ -6,6 +6,7 @@ "io/fs"
6 "net/url"
7 "path"
8 "strings"
9+ "syscall"
10
11 "git.sr.ht/~gabrielgio/img/pkg/database/repository"
12 "git.sr.ht/~gabrielgio/img/pkg/list"
13@@ -32,6 +33,20 @@ History []*DirectoryParam
14 Files []*FileParam
15 }
16 )
17+
18+func (f *FileParam) GetUid() int {
19+ if stat, ok := f.Info.Sys().(*syscall.Stat_t); ok {
20+ return int(stat.Uid)
21+ }
22+ return 0
23+}
24+
25+func (f *FileParam) GetGid() int {
26+ if stat, ok := f.Info.Sys().(*syscall.Stat_t); ok {
27+ return int(stat.Gid)
28+ }
29+ return 0
30+}
31
32 func NewFileSystemController(
33 fsRepository repository.FileSystemRepository,
34diff --git a/pkg/view/filesystem.go b/pkg/view/filesystem.go
35index 7fd7331c7b306a61afbadee990e5a9c0293d51d1..6a011171eef0c61a0385600ec638b4dcc18f672c 100644
36--- a/pkg/view/filesystem.go
37+++ b/pkg/view/filesystem.go
38@@ -3,10 +3,10 @@
39 import (
40 "github.com/valyala/fasthttp"
41
42- "git.sr.ht/~gabrielgio/img"
43 "git.sr.ht/~gabrielgio/img/pkg/database/repository"
44 "git.sr.ht/~gabrielgio/img/pkg/ext"
45 "git.sr.ht/~gabrielgio/img/pkg/service"
46+ "git.sr.ht/~gabrielgio/img/templates"
47 )
48
49 type (
50@@ -45,17 +45,12 @@ if err != nil {
51 return err
52 }
53
54- err = img.Render(ctx, "fs.html", &img.HTMLView[*FilePage]{
55- Title: pathValue,
56- Data: &FilePage{
57- Page: page,
58- ShowMode: settings.ShowMode,
59- ShowOwner: settings.ShowOwner,
60- },
61+ templates.WritePageTemplate(ctx, &templates.FilePage{
62+ Page: page,
63+ ShowMode: settings.ShowMode,
64+ ShowOwner: settings.ShowOwner,
65 })
66- if err != nil {
67- return err
68- }
69+
70 return nil
71 }
72
73diff --git a/static.go b/static.go
74index 1c6a086b026205651a0d837e10588b65c5df8aaf..06f1459520097997f642ad087301207e4892f2db 100644
75--- a/static.go
76+++ b/static.go
77@@ -2,33 +2,9 @@ package img
78
79 import (
80 "embed"
81- "fmt"
82- "html/template"
83- "io"
84 )
85
86 var (
87- //go:embed templates/*.html
88- TemplateFS embed.FS
89-
90 //go:embed static/*
91 StaticFS embed.FS
92-
93- Template *template.Template
94 )
95-
96-type HTMLView[T any] struct {
97- Title string
98- Username string
99- Data T
100-}
101-
102-func Render[T any](w io.Writer, page string, view *HTMLView[T]) error {
103- pageFile := fmt.Sprintf("templates/%s", page)
104- tmpl, err := template.New("").ParseFS(TemplateFS, "templates/layout.html", pageFile)
105- if err != nil {
106- return err
107- }
108-
109- return tmpl.ExecuteTemplate(w, page, view)
110-}
111diff --git a/templates/base.qtpl b/templates/base.qtpl
112index cbde3552fcaa1f580d3f4afad03bece2aac529a2..0c0578234dc0fcf545c94664b8c4304cc67ed23b 100644
113--- a/templates/base.qtpl
114+++ b/templates/base.qtpl
115@@ -22,13 +22,13 @@ </head>
116 <body>
117 <nav class="navbar">
118 <div class="navbar-start">
119- <a href="/fs" class="navbar-item">
120+ <a href="/fs/" class="navbar-item">
121 files
122 </a>
123- <a href="/media" class="navbar-item">
124+ <a href="/media/" class="navbar-item">
125 media
126 </a>
127- <a href="/settings" class="navbar-item">
128+ <a href="/settings/" class="navbar-item">
129 settings
130 </a>
131 </div>
132diff --git a/templates/fs.html b/templates/fs.html
133deleted file mode 100644
134index a44d78f441b53a2e1229120696a4c081908679dd..0000000000000000000000000000000000000000
135--- a/templates/fs.html
136+++ /dev/null
137@@ -1,29 +0,0 @@
138-{{template "layout.html" .}}
139-{{define "title"}} {{.Title}} {{end}}
140-{{define "content"}}
141-<div class="panel">
142- <div class="panel-block">
143- <div class="columns file-row is-gapless is-mobile">
144- <div id="path" class="container-fluid">
145- <small>{{range .Data.Page.History}}<a href="/fs?path={{.UrlEncodedPath}}" >{{.Name}}/</a>{{end}}</small>
146- </div>
147- </div>
148- </div>
149- {{range .Data.Page.Files}}
150- <div class="panel-block">
151- <div class="columns wide-column is-mono is-gapless is-mobile">
152- <div class="column">
153- {{if $.Data.ShowMode}}{{.Info.Mode}} {{end}}
154- {{if $.Data.ShowOwner}}{{.Info.Sys.Gid}}:{{.Info.Sys.Uid}} {{end}}
155- {{if .Info.IsDir}}
156- <a href="/?path={{.UrlEncodedPath}}">{{.Info.Name}}/</a>
157- {{else}}
158- {{.Info.Name}}
159- {{end}}
160- </div>
161- <div class="column has-text-right">{{.Info.Size}} B</div>
162- </div>
163- </div>
164- {{end}}
165-</div>
166-{{end}}
167diff --git a/templates/fs.qtpl b/templates/fs.qtpl
168new file mode 100644
169index 0000000000000000000000000000000000000000..489f79fc1ab56f05e95f5e240e2250d5f456f9f4
170--- /dev/null
171+++ b/templates/fs.qtpl
172@@ -0,0 +1,41 @@
173+{% import "git.sr.ht/~gabrielgio/img/pkg/service" %}
174+
175+{% code
176+type FilePage struct {
177+ Page *service.Page
178+ ShowMode bool
179+ ShowOwner bool
180+ }%}
181+
182+{% func (p *FilePage) Title() %}Files{% endfunc %}
183+
184+{% func (p *FilePage) Content() %}
185+<div class="panel">
186+ <div class="panel-block">
187+ <div class="columns file-row is-gapless is-mobile">
188+ <div id="path" class="container-fluid">
189+ <small>{% for _, h := range p.Page.History %}<a href="/fs?path={%s h.UrlEncodedPath %}" >{%s h.Name %}/</a>{% endfor %}</small>
190+ </div>
191+ </div>
192+ </div>
193+ {% for _, f := range p.Page.Files %}
194+ <div class="panel-block">
195+ <div class="columns wide-column is-mono is-gapless is-mobile">
196+ <div class="column">
197+ {% if p.ShowMode %}{%s f.Info.Mode().String() %} {% endif %}
198+ {% if p.ShowOwner %}{%d f.GetGid() %}:{%d f.GetUid() %} {% endif %}
199+ {% if f.Info.IsDir() %}
200+ <a href="/?path={%s f.UrlEncodedPath %}">{%s f.Info.Name() %}/</a>
201+ {% else %}
202+ {%s f.Info.Name() %}
203+ {% endif %}
204+ </div>
205+ <div class="column has-text-right">{%dl f.Info.Size() %} B</div>
206+ </div>
207+ </div>
208+ {% endfor %}
209+</div>
210+{% endfunc %}
211+
212+{% func (p *FilePage) Script() %}
213+{% endfunc %}
214diff --git a/templates/layout.html b/templates/layout.html
215deleted file mode 100644
216index bbf1558ff080063b0610a80f4d9846a8a9cad9ce..0000000000000000000000000000000000000000
217--- a/templates/layout.html
218+++ /dev/null
219@@ -1,29 +0,0 @@
220-<!DOCTYPE html>
221-<html lang="en">
222- <head>
223- <meta charset="utf-8">
224- <title>img | {{block "title" .}} noop {{end}}</title>
225- <link rel="stylesheet" href="/static/main.css">
226- <link rel="icon" href="/static/square.svg" sizes="any" type="image/svg+xml">
227- <meta name="viewport" content="width=device-width, initial-scale=1" />
228- </head>
229- <body>
230- <nav class="navbar">
231- <div class="navbar-start">
232- <a href="/fs" class="navbar-item">
233- files
234- </a>
235- <a href="/media" class="navbar-item">
236- media
237- </a>
238- <a href="/settings" class="navbar-item">
239- settings
240- </a>
241- </div>
242- </nav>
243- <div class="container">
244- {{block "content" .}}noop{{end}}
245- </div>
246- </body>
247- {{block "script" .}}{{end}}
248-</html>