+22
appview/pages/pages.go
+22
appview/pages/pages.go
···
71
return s
72
},
73
"timeFmt": humanize.Time,
74
+
"byteFmt": humanize.Bytes,
75
"length": func(v []string) int {
76
return len(v)
77
},
···
294
BaseTreeLink string
295
BaseBlobLink string
296
types.RepoTreeResponse
297
+
}
298
+
299
+
type RepoTreeStats struct {
300
+
NumFolders uint64
301
+
NumFiles uint64
302
+
}
303
+
304
+
func (r RepoTreeParams) TreeStats() RepoTreeStats {
305
+
numFolders, numFiles := 0, 0
306
+
for _, f := range r.Files {
307
+
if !f.IsFile {
308
+
numFolders += 1
309
+
} else if f.IsFile {
310
+
numFiles += 1
311
+
}
312
+
}
313
+
314
+
return RepoTreeStats{
315
+
NumFolders: uint64(numFolders),
316
+
NumFiles: uint64(numFiles),
317
+
}
318
}
319
320
func (p *Pages) RepoTree(w io.Writer, params RepoTreeParams) error {
+1
-1
appview/pages/templates/layouts/base.html
+1
-1
appview/pages/templates/layouts/base.html
+16
-5
appview/pages/templates/repo/blob.html
+16
-5
appview/pages/templates/repo/blob.html
···
5
{{ $code_number_style := "text-gray-400 left-0 bg-white text-right mr-2 select-none" }}
6
{{ $linkstyle := "no-underline hover:underline" }}
7
<div class="pb-2 text-base">
8
-
{{ range $idx, $value := .BreadCrumbs }}
9
-
{{ if ne $idx (sub (len $.BreadCrumbs) 1) }}
10
<a href="{{ index . 1}}" class="text-bold text-gray-500 {{ $linkstyle }}">{{ index . 0 }}</a> /
11
-
{{ else }}
12
<span class="text-bold text-gray-500">{{ index . 0 }}</span>
13
-
{{ end }}
14
-
{{ end }}
15
</div>
16
17
···
5
{{ $code_number_style := "text-gray-400 left-0 bg-white text-right mr-2 select-none" }}
6
{{ $linkstyle := "no-underline hover:underline" }}
7
<div class="pb-2 text-base">
8
+
<div class="flex justify-between">
9
+
<div id="breadcrumbs">
10
+
{{ range $idx, $value := .BreadCrumbs }}
11
+
{{ if ne $idx (sub (len $.BreadCrumbs) 1) }}
12
<a href="{{ index . 1}}" class="text-bold text-gray-500 {{ $linkstyle }}">{{ index . 0 }}</a> /
13
+
{{ else }}
14
<span class="text-bold text-gray-500">{{ index . 0 }}</span>
15
+
{{ end }}
16
+
{{ end }}
17
+
</div>
18
+
<div id="file-info">
19
+
<span class="text-gray-500 text-xs">
20
+
{{ .Lines }} lines
21
+
·
22
+
{{ byteFmt .SizeHint }}
23
+
</span>
24
+
</div>
25
+
</div>
26
</div>
27
28
+1
-1
appview/pages/templates/repo/index.html
+1
-1
appview/pages/templates/repo/index.html
+27
-6
appview/pages/templates/repo/tree.html
+27
-6
appview/pages/templates/repo/tree.html
···
5
{{ $linkstyle := "no-underline hover:underline" }}
6
7
<div class="pb-2 text-base">
8
-
{{ range .BreadCrumbs }}
9
-
<a href="{{ index . 1}}" class="text-bold text-gray-500 {{ $linkstyle }}">{{ index . 0 }}</a> /
10
-
{{ end }}
11
</div>
12
13
{{ range .Files }}
···
19
<i class="w-3 h-3 fill-current" data-lucide="folder"></i>{{ .Name }}
20
</div>
21
</a>
22
</div>
23
-
<time class="text-xs text-gray-500">{{ timeFmt .LastCommit.Author.When }}</time>
24
</div>
25
{{ end }}
26
{{ end }}
···
28
{{ range .Files }}
29
{{ if .IsFile }}
30
<div class="{{ $containerstyle }}">
31
-
32
<div class="flex justify-between items-center">
33
<a href="/{{ $.BaseBlobLink }}/{{ .Name }}" class="{{ $linkstyle }}">
34
<div class="flex items-center gap-2">
35
<i class="w-3 h-3" data-lucide="file"></i>{{ .Name }}
36
</div>
37
</a>
38
-
39
<time class="text-xs text-gray-500">{{ timeFmt .LastCommit.Author.When }}</time>
40
</div>
41
</div>
···
5
{{ $linkstyle := "no-underline hover:underline" }}
6
7
<div class="pb-2 text-base">
8
+
<div class="flex justify-between">
9
+
<div id="breadcrumbs">
10
+
{{ range .BreadCrumbs }}
11
+
<a href="{{ index . 1}}" class="text-bold text-gray-500 {{ $linkstyle }}">{{ index . 0 }}</a> /
12
+
{{ end }}
13
+
</div>
14
+
<div id="dir-info">
15
+
<span class="text-gray-500 text-xs">
16
+
{{ $stats := .TreeStats }}
17
+
18
+
{{ if eq $stats.NumFolders 1 }}
19
+
{{ $stats.NumFolders }} folder
20
+
·
21
+
{{ else if gt $stats.NumFolders 1 }}
22
+
{{ $stats.NumFolders }} folders
23
+
·
24
+
{{ end }}
25
+
26
+
{{ if eq $stats.NumFiles 1 }}
27
+
{{ $stats.NumFiles }} file
28
+
{{ else if gt $stats.NumFiles 1 }}
29
+
{{ $stats.NumFiles }} files
30
+
{{ end }}
31
+
</span>
32
+
</div>
33
+
</div>
34
</div>
35
36
{{ range .Files }}
···
42
<i class="w-3 h-3 fill-current" data-lucide="folder"></i>{{ .Name }}
43
</div>
44
</a>
45
+
<time class="text-xs text-gray-500">{{ timeFmt .LastCommit.Author.When }}</time>
46
</div>
47
</div>
48
{{ end }}
49
{{ end }}
···
51
{{ range .Files }}
52
{{ if .IsFile }}
53
<div class="{{ $containerstyle }}">
54
<div class="flex justify-between items-center">
55
<a href="/{{ $.BaseBlobLink }}/{{ .Name }}" class="{{ $linkstyle }}">
56
<div class="flex items-center gap-2">
57
<i class="w-3 h-3" data-lucide="file"></i>{{ .Name }}
58
</div>
59
</a>
60
<time class="text-xs text-gray-500">{{ timeFmt .LastCommit.Author.When }}</time>
61
</div>
62
</div>
+4
-1
knotserver/routes.go
+4
-1
knotserver/routes.go
···
215
return
216
}
217
218
+
bytes := []byte(contents)
219
+
safe := string(sanitize(bytes))
220
+
sizeHint := len(bytes)
221
222
resp := types.RepoBlobResponse{
223
Ref: ref,
224
Contents: string(safe),
225
Path: treePath,
226
IsBinary: isBinaryFile,
227
+
SizeHint: uint64(sizeHint),
228
}
229
230
h.showFile(resp, w, l)
+2
-1
types/repo.go
+2
-1
types/repo.go