|
diff --git a/hfiles.go b/hfiles.go
|
| ... |
| 45 |
} |
45 |
} |
| 46 |
} |
46 |
} |
| 47 |
|
47 |
|
| 48 |
var entries []TreeEntry |
48 |
var entries []*TreeEntry |
| 49 |
for _, entry := range tree.Entries { |
49 |
for _, entry := range tree.Entries { |
| 50 |
fullPath := entry.Name |
50 |
fullPath := entry.Name |
| 51 |
if pathValue != "" { |
51 |
if pathValue != "" { |
| ... |
| 62 |
} |
62 |
} |
| 63 |
} |
63 |
} |
| 64 |
|
64 |
|
| 65 |
entries = append(entries, TreeEntry{ |
65 |
entries = append(entries, &TreeEntry{ |
| 66 |
Name: entry.Name, |
66 |
Name: entry.Name, |
| 67 |
Path: fullPath, |
67 |
Path: fullPath, |
| 68 |
IsDir: isDir, |
68 |
IsDir: isDir, |
| ... |
| 78 |
return entries[i].Name < entries[j].Name |
78 |
return entries[i].Name < entries[j].Name |
| 79 |
}) |
79 |
}) |
| 80 |
|
80 |
|
|
|
81 |
var allEntries []*TreeEntry |
|
|
82 |
fullTree, err := commit.Tree() |
|
|
83 |
if err == nil { |
|
|
84 |
allEntries = getTreeEntries(fullTree, "", 0) |
|
|
85 |
} |
|
|
86 |
|
| 81 |
data := struct { |
87 |
data := struct { |
| 82 |
*RepoContext |
88 |
*RepoContext |
| 83 |
Entries []TreeEntry |
89 |
Entries []*TreeEntry |
| 84 |
Path string |
90 |
AllEntries []*TreeEntry |
| 85 |
View string |
91 |
Path string |
|
|
92 |
View string |
| 86 |
}{ |
93 |
}{ |
| 87 |
RepoContext: ctx, |
94 |
RepoContext: ctx, |
| 88 |
Entries: entries, |
95 |
Entries: entries, |
|
|
96 |
AllEntries: allEntries, |
| 89 |
Path: pathValue, |
97 |
Path: pathValue, |
| 90 |
View: "files", |
98 |
View: "files", |
| 91 |
} |
99 |
} |
| ... |
| 128 |
return |
136 |
return |
| 129 |
} |
137 |
} |
| 130 |
|
138 |
|
|
|
139 |
var allEntries []*TreeEntry |
|
|
140 |
tree, err := commit.Tree() |
|
|
141 |
if err == nil { |
|
|
142 |
allEntries = getTreeEntries(tree, "", 0) |
|
|
143 |
} |
|
|
144 |
|
| 131 |
data := struct { |
145 |
data := struct { |
| 132 |
*RepoContext |
146 |
*RepoContext |
| 133 |
Path string |
147 |
Path string |
| 134 |
Content template.HTML |
148 |
Content template.HTML |
|
|
149 |
AllEntries []*TreeEntry |
| 135 |
}{ |
150 |
}{ |
| 136 |
RepoContext: ctx, |
151 |
RepoContext: ctx, |
| 137 |
Path: pathValue, |
152 |
Path: pathValue, |
| 138 |
Content: highlight(pathValue, content), |
153 |
Content: highlight(pathValue, content), |
|
|
154 |
AllEntries: allEntries, |
| 139 |
} |
155 |
} |
| 140 |
|
156 |
|
| 141 |
err = templates.ExecuteTemplate(w, "blob.html", data) |
157 |
err = templates.ExecuteTemplate(w, "blob.html", data) |
| ... |
| 280 |
log.Printf("Error creating archive: %v", err) |
296 |
log.Printf("Error creating archive: %v", err) |
| 281 |
} |
297 |
} |
| 282 |
} |
298 |
} |
|
|
299 |
|
|
|
300 |
func getTreeEntries(tree *object.Tree, prefix string, depth int) []*TreeEntry { |
|
|
301 |
var entries []*TreeEntry |
|
|
302 |
for _, entry := range tree.Entries { |
|
|
303 |
fullPath := entry.Name |
|
|
304 |
if prefix != "" { |
|
|
305 |
fullPath = prefix + "/" + entry.Name |
|
|
306 |
} |
|
|
307 |
|
|
|
308 |
isDir := entry.Mode.IsFile() == false |
|
|
309 |
te := &TreeEntry{ |
|
|
310 |
Name: entry.Name, |
|
|
311 |
Path: fullPath, |
|
|
312 |
IsDir: isDir, |
|
|
313 |
Mode: entry.Mode.String(), |
|
|
314 |
Depth: depth, |
|
|
315 |
} |
|
|
316 |
|
|
|
317 |
if isDir { |
|
|
318 |
subTree, err := tree.Tree(entry.Name) |
|
|
319 |
if err == nil { |
|
|
320 |
te.Children = getTreeEntries(subTree, fullPath, depth+1) |
|
|
321 |
} |
|
|
322 |
} |
|
|
323 |
entries = append(entries, te) |
|
|
324 |
} |
|
|
325 |
|
|
|
326 |
sort.Slice(entries, func(i, j int) bool { |
|
|
327 |
if entries[i].IsDir != entries[j].IsDir { |
|
|
328 |
return entries[i].IsDir |
|
|
329 |
} |
|
|
330 |
return entries[i].Name < entries[j].Name |
|
|
331 |
}) |
|
|
332 |
|
|
|
333 |
return entries |
|
|
334 |
} |
|
diff --git a/hrepo.go b/hrepo.go
|
| ... |
| 35 |
|
35 |
|
| 36 |
totalCommitsKey := ctx.Repo.Name + ":" + ctx.Hash.String() |
36 |
totalCommitsKey := ctx.Repo.Name + ":" + ctx.Hash.String() |
| 37 |
var totalCommits int |
37 |
var totalCommits int |
| 38 |
if val, ok := repoMetadataCache.Load(totalCommitsKey); ok { |
38 |
if val, ok := repoMetadataCache.Load(totalCommitsKey); ok && val.(RepoMetadata).TotalCommits > 0 { |
| 39 |
totalCommits = val.(RepoMetadata).TotalCommits |
39 |
totalCommits = val.(RepoMetadata).TotalCommits |
| 40 |
} else { |
40 |
} else { |
| 41 |
cIter, err := ctx.GitRepo.Log(&git.LogOptions{From: ctx.Hash}) |
41 |
cIter, err := ctx.GitRepo.Log(&git.LogOptions{From: ctx.Hash}) |
| ... |
|
diff --git a/static/style.css b/static/style.css
|
| ... |
| 81 |
text-decoration: underline; |
81 |
text-decoration: underline; |
| 82 |
} |
82 |
} |
| 83 |
|
83 |
|
| 84 |
pre { |
84 |
pre { |
| 85 |
margin: 0; |
85 |
margin: 0; |
| 86 |
overflow-x: auto; |
86 |
overflow-x: auto; |
| 87 |
scrollbar-width: none; |
|
|
| 88 |
white-space: pre; |
87 |
white-space: pre; |
| 89 |
} |
|
|
| 90 |
pre::-webkit-scrollbar { |
|
|
| 91 |
display: none; |
|
|
| 92 |
} |
88 |
} |
| 93 |
|
89 |
|
| 94 |
blockquote { |
90 |
blockquote { |
| ... |
| 128 |
|
124 |
|
| 129 |
.nav-main { |
125 |
.nav-main { |
| 130 |
display: flex; |
126 |
display: flex; |
|
|
127 |
justify-content: space-between; |
|
|
128 |
align-items: center; |
|
|
129 |
} |
|
|
130 |
|
|
|
131 |
.nav-main-left { |
|
|
132 |
display: flex; |
| 131 |
gap: 0.4em; |
133 |
gap: 0.4em; |
|
|
134 |
align-items: center; |
|
|
135 |
} |
|
|
136 |
|
|
|
137 |
.nav-main-right { |
|
|
138 |
display: flex; |
|
|
139 |
gap: 1em; |
|
|
140 |
font-size: small; |
| 132 |
} |
141 |
} |
| 133 |
|
142 |
|
| 134 |
.nav-repository { |
143 |
.nav-repository { |
| ... |
| 141 |
} |
150 |
} |
| 142 |
} |
151 |
} |
| 143 |
|
152 |
|
|
|
153 |
.content-layout { |
|
|
154 |
display: flex; |
|
|
155 |
gap: 1em; |
|
|
156 |
min-width: 0; |
|
|
157 |
align-items: flex-start; |
|
|
158 |
} |
|
|
159 |
|
|
|
160 |
.tree-view { |
|
|
161 |
width: 250px; |
|
|
162 |
flex-shrink: 0; |
|
|
163 |
border: 1px solid var(--border); |
|
|
164 |
font-size: small; |
|
|
165 |
padding: 0.5em 0; |
|
|
166 |
align-self: flex-start; |
|
|
167 |
} |
|
|
168 |
|
|
|
169 |
.tree-entry { |
|
|
170 |
display: block; |
|
|
171 |
padding: 2px 10px; |
|
|
172 |
white-space: nowrap; |
|
|
173 |
overflow: hidden; |
|
|
174 |
text-overflow: ellipsis; |
|
|
175 |
color: #000000; |
|
|
176 |
text-decoration: none; |
|
|
177 |
} |
|
|
178 |
|
|
|
179 |
.tree-entry:hover { |
|
|
180 |
background: var(--table-row-hover-bg); |
|
|
181 |
text-decoration: none; |
|
|
182 |
} |
|
|
183 |
|
|
|
184 |
.tree-entry.active { |
|
|
185 |
font-weight: bold; |
|
|
186 |
background: var(--bg); |
|
|
187 |
color: var(--link); |
|
|
188 |
} |
|
|
189 |
|
|
|
190 |
.tree-entry.directory { |
|
|
191 |
color: #000000; |
|
|
192 |
} |
|
|
193 |
|
|
|
194 |
.code-container { |
|
|
195 |
flex-grow: 1; |
|
|
196 |
display: flex; |
|
|
197 |
flex-direction: column; |
|
|
198 |
border: 1px solid var(--border); |
|
|
199 |
min-width: 0; |
|
|
200 |
} |
|
|
201 |
|
|
|
202 |
.code-header { |
|
|
203 |
display: flex; |
|
|
204 |
justify-content: space-between; |
|
|
205 |
align-items: center; |
|
|
206 |
padding: 0.5em 1em; |
|
|
207 |
background: var(--table-header-bg); |
|
|
208 |
border-bottom: 1px solid var(--border); |
|
|
209 |
position: sticky; |
|
|
210 |
top: 0; |
|
|
211 |
z-index: 10; |
|
|
212 |
font-size: small; |
|
|
213 |
font-family: monospace; |
|
|
214 |
} |
|
|
215 |
|
| 144 |
.code-view { |
216 |
.code-view { |
| 145 |
border: 1px solid var(--border); |
217 |
border: none; |
|
|
218 |
} |
|
|
219 |
|
|
|
220 |
.code-view pre { background: none !important; } |
|
|
221 |
|
|
|
222 |
.code-view code > span > span:first-child { |
|
|
223 |
color: var(--ln-fg); |
|
|
224 |
background: var(--ln-bg); |
|
|
225 |
border-right: 1px solid var(--border); |
|
|
226 |
font-size: smaller; |
| 146 |
} |
227 |
} |
| 147 |
|
228 |
|
| 148 |
.diff-table { |
229 |
.files-view { |
| 149 |
table-layout: fixed; |
230 |
flex-grow: 1; |
|
|
231 |
overflow: auto; |
|
|
232 |
min-width: 0; |
|
|
233 |
|
|
|
234 |
a { color: initial; } |
|
|
235 |
} |
|
|
236 |
|
|
|
237 |
.diff-table { |
| 150 |
width: 100%; |
238 |
width: 100%; |
| 151 |
border-collapse: collapse; |
239 |
border-collapse: collapse; |
| 152 |
font-family: monospace; |
240 |
font-family: monospace; |
| 153 |
|
241 |
|
| 154 |
td { |
242 |
td { |
| 155 |
padding: 0 2px; |
243 |
padding: 0 2px; |
| 156 |
border: 0; |
244 |
border: 0; |
| 157 |
overflow: hidden; |
245 |
overflow: hidden; |
| ... |
| 182 |
.diff-add { background-color: var(--diff-add-bg); color: var(--diff-add-fg); } |
270 |
.diff-add { background-color: var(--diff-add-bg); color: var(--diff-add-fg); } |
| 183 |
.diff-del { background-color: var(--diff-del-bg); color: var(--diff-del-fg); } |
271 |
.diff-del { background-color: var(--diff-del-bg); color: var(--diff-del-fg); } |
| 184 |
.diff-mod { background-color: var(--diff-mod-bg); color: var(--diff-mod-fg); } |
272 |
.diff-mod { background-color: var(--diff-mod-bg); color: var(--diff-mod-fg); } |
| 185 |
.diff-gap { |
273 |
.diff-gap { |
| 186 |
background-color: var(--diff-gap-bg); |
274 |
background-color: var(--diff-gap-bg); |
| 187 |
color: var(--diff-gap-fg); |
275 |
color: var(--diff-gap-fg); |
| 188 |
border-top: 1px solid var(--border); |
276 |
border-top: 1px solid var(--border); |
| 189 |
border-bottom: 1px solid var(--border); |
277 |
border-bottom: 1px solid var(--border); |
| 190 |
} |
278 |
} |
| 191 |
.diff-fname { |
279 |
.diff-fname { |
| 192 |
background-color: var(--diff-fname-bg); |
280 |
background-color: var(--diff-fname-bg); |
| 193 |
color: var(--diff-fname-fg); |
281 |
color: var(--diff-fname-fg); |
| 194 |
border-top: 1px solid var(--border); |
282 |
border-top: 1px solid var(--border); |
| ... |
| 199 |
} |
287 |
} |
| 200 |
} |
288 |
} |
| 201 |
|
289 |
|
|
|
290 |
.tree-view details summary { |
|
|
291 |
list-style: none; |
|
|
292 |
cursor: pointer; |
|
|
293 |
outline: none; |
|
|
294 |
} |
|
|
295 |
|
|
|
296 |
.tree-view details summary::-webkit-details-marker { |
|
|
297 |
display: none; |
|
|
298 |
} |
|
|
299 |
|
|
|
300 |
.tree-view details summary::before { |
|
|
301 |
content: "▸"; |
|
|
302 |
display: inline-block; |
|
|
303 |
width: 1em; |
|
|
304 |
color: #000000; |
|
|
305 |
} |
|
|
306 |
|
|
|
307 |
.tree-view details[open] > summary::before { |
|
|
308 |
content: "▾"; |
|
|
309 |
} |
|
|
310 |
|
|
|
311 |
.tree-view details { |
|
|
312 |
display: block; |
|
|
313 |
} |
|
|
314 |
|
| 202 |
.file-diffs { |
315 |
.file-diffs { |
| 203 |
display: flex; |
316 |
display: flex; |
| 204 |
flex-direction: column; |
317 |
flex-direction: column; |
| ... |
| 223 |
color: var(--fg-muted); |
336 |
color: var(--fg-muted); |
| 224 |
font-size: small; |
337 |
font-size: small; |
| 225 |
user-select: none; |
338 |
user-select: none; |
| 226 |
} |
|
|
| 227 |
} |
|
|
| 228 |
|
|
|
| 229 |
.code-view { |
|
|
| 230 |
pre { background: none !important; } |
|
|
| 231 |
code > span > span:first-child { |
|
|
| 232 |
color: var(--ln-fg); |
|
|
| 233 |
background: var(--ln-bg); |
|
|
| 234 |
border-right: 1px solid var(--border); |
|
|
| 235 |
font-size: smaller; |
|
|
| 236 |
} |
339 |
} |
| 237 |
} |
340 |
} |
| 238 |
|
341 |
|
| ... |
| 367 |
color: var(--fg-muted); |
470 |
color: var(--fg-muted); |
| 368 |
} |
471 |
} |
| 369 |
|
472 |
|
| 370 |
footer { |
473 |
.footer { |
| 371 |
display: flex; |
474 |
margin-top: 2em; |
| 372 |
justify-content: space-between; |
475 |
padding-top: 1em; |
| 373 |
align-items: center; |
476 |
text-align: center; |
| 374 |
color: var(--fg-muted); |
477 |
color: var(--fg-muted); |
| 375 |
font-size: small; |
478 |
font-size: small; |
| 376 |
|
|
|
| 377 |
.footer-rss { |
|
|
| 378 |
display: flex; |
|
|
| 379 |
gap: 1em; |
|
|
| 380 |
} |
|
|
| 381 |
} |
479 |
} |
| 382 |
|
|
|
|
diff --git a/templates.go b/templates.go
|
| ... |
| 42 |
"float64": func(i int) float64 { |
42 |
"float64": func(i int) float64 { |
| 43 |
return float64(i) |
43 |
return float64(i) |
| 44 |
}, |
44 |
}, |
|
|
45 |
"int": func(f float64) int { |
|
|
46 |
return int(f) |
|
|
47 |
}, |
| 45 |
"multiply": func(a, b float64) float64 { |
48 |
"multiply": func(a, b float64) float64 { |
| 46 |
return a * b |
49 |
return a * b |
| 47 |
}, |
50 |
}, |
| ... |
| 50 |
return 0 |
53 |
return 0 |
| 51 |
} |
54 |
} |
| 52 |
return a / b |
55 |
return a / b |
|
|
56 |
}, |
|
|
57 |
"hasPrefix": strings.HasPrefix, |
|
|
58 |
"dict": func(values ...interface{}) (map[string]interface{}, error) { |
|
|
59 |
if len(values)%2 != 0 { |
|
|
60 |
return nil, fmt.Errorf("invalid dict call") |
|
|
61 |
} |
|
|
62 |
dict := make(map[string]interface{}, len(values)/2) |
|
|
63 |
for i := 0; i < len(values); i += 2 { |
|
|
64 |
key, ok := values[i].(string) |
|
|
65 |
if !ok { |
|
|
66 |
return nil, fmt.Errorf("dict keys must be strings") |
|
|
67 |
} |
|
|
68 |
dict[key] = values[i+1] |
|
|
69 |
} |
|
|
70 |
return dict, nil |
| 53 |
}, |
71 |
}, |
| 54 |
"humanize": func(size int64) string { |
72 |
"humanize": func(size int64) string { |
| 55 |
const unit = 1024 |
73 |
const unit = 1024 |
| ... |
|
diff --git a/views/blob.html b/views/blob.html
|
| ... |
| 11 |
<main> |
11 |
<main> |
| 12 |
{{template "nav-repository.html" .}} |
12 |
{{template "nav-repository.html" .}} |
| 13 |
|
13 |
|
| 14 |
<div class="breadcrumbs"> |
14 |
<div class="content-layout"> |
| 15 |
<span>Path:</span> |
15 |
<div class="tree-view"> |
| 16 |
<a href="/r/{{.Repo.Name}}/files/?ref={{.CurrentRef}}">{{.Repo.Name}}</a> |
16 |
{{template "tree" dict "Entries" .AllEntries "RepoName" .Repo.Name "CurrentRef" .CurrentRef "CurrentPath" .Path}} |
| 17 |
{{$parts := split .Path "/"}} |
17 |
</div> |
| 18 |
{{$path := ""}} |
18 |
<div class="code-container"> |
| 19 |
{{range $i, $part := $parts}} |
19 |
<div class="code-header"> |
| 20 |
/ |
20 |
<span class="file-path">{{.Path}}</span> |
| 21 |
{{$path = join $path $part}} |
21 |
<a href="/r/{{.Repo.Name}}/raw/{{.Path}}?ref={{.CurrentRef}}" class="raw-link">raw</a> |
| 22 |
{{if eq (add $i 1) (len $parts)}} |
22 |
</div> |
| 23 |
{{$part}} |
23 |
<div class="code-view">{{.Content}}</div> |
| 24 |
(<a href="/r/{{$.Repo.Name}}/raw/{{$.Path}}?ref={{$.CurrentRef}}">raw</a>) |
24 |
</div> |
| 25 |
{{else}} |
|
|
| 26 |
<a href="/r/{{$.Repo.Name}}/files/{{$path}}?ref={{$.CurrentRef}}">{{$part}}</a> |
|
|
| 27 |
{{end}} |
|
|
| 28 |
{{end}} |
|
|
| 29 |
</div> |
|
|
| 30 |
|
|
|
| 31 |
<div class="blob-content"> |
|
|
| 32 |
<div class="code-view">{{.Content}}</div> |
|
|
| 33 |
</div> |
25 |
</div> |
| 34 |
</main> |
26 |
</main> |
| 35 |
|
|
|
| 36 |
{{template "footer.html" .}} |
27 |
{{template "footer.html" .}} |
| 37 |
</body> |
28 |
</body> |
| 38 |
</html> |
29 |
</html> |
|
|
30 |
|
|
diff --git a/views/files.html b/views/files.html
|
| ... |
| 11 |
<main> |
11 |
<main> |
| 12 |
{{template "nav-repository.html" .}} |
12 |
{{template "nav-repository.html" .}} |
| 13 |
|
13 |
|
| 14 |
<div class="breadcrumbs"> |
14 |
<div class="content-layout"> |
| 15 |
<span>Path:</span> |
15 |
<div class="tree-view"> |
| 16 |
{{if .Path}} |
16 |
{{template "tree" dict "Entries" .AllEntries "RepoName" .Repo.Name "CurrentRef" .CurrentRef "CurrentPath" .Path}} |
| 17 |
<a href="/r/{{.Repo.Name}}/files/?ref={{.CurrentRef}}">{{.Repo.Name}}</a> |
17 |
</div> |
| 18 |
{{$parts := split .Path "/"}} |
|
|
| 19 |
{{$path := ""}} |
|
|
| 20 |
{{range $i, $part := $parts}} |
|
|
| 21 |
/ |
|
|
| 22 |
{{$path = join $path $part}} |
|
|
| 23 |
{{if eq (add $i 1) (len $parts)}} |
|
|
| 24 |
{{$part}} |
|
|
| 25 |
(<a href="/r/{{$.Repo.Name}}/archive/{{$.Path}}?ref={{$.CurrentRef}}">download</a>) |
|
|
| 26 |
{{else}} |
|
|
| 27 |
<a href="/r/{{$.Repo.Name}}/files/{{$path}}?ref={{$.CurrentRef}}">{{$part}}</a> |
|
|
| 28 |
{{end}} |
|
|
| 29 |
{{end}} |
|
|
| 30 |
{{else}} |
|
|
| 31 |
{{.Repo.Name}} |
|
|
| 32 |
{{end}} |
|
|
| 33 |
</div> |
|
|
| 34 |
|
18 |
|
| 35 |
<table> |
19 |
<div class="files-view"> |
| 36 |
<thead> |
20 |
<table> |
| 37 |
<tr> |
21 |
<thead> |
| 38 |
<th width="20"></th> |
22 |
<tr> |
| 39 |
<th>Name</th> |
23 |
<th width="20"></th> |
| 40 |
<th width="100" class="text-right">Mode</th> |
24 |
<th>Name</th> |
| 41 |
<th width="100" class="text-right">Size</th> |
25 |
<th width="100" class="text-right">Mode</th> |
| 42 |
<th width="50" class="text-center">Raw</th> |
26 |
<th width="100" class="text-right">Size</th> |
| 43 |
</tr> |
27 |
<th width="50" class="text-center">Raw</th> |
| 44 |
</thead> |
28 |
</tr> |
| 45 |
<tbody> |
29 |
</thead> |
| 46 |
{{if .Path}} |
30 |
<tbody> |
| 47 |
<tr> |
31 |
{{if .Path}} |
| 48 |
<td></td> |
32 |
<tr> |
| 49 |
<td colspan="4"><a href="/r/{{.Repo.Name}}/files/{{parent .Path}}?ref={{.CurrentRef}}">..</a></td> |
33 |
<td></td> |
| 50 |
</tr> |
34 |
<td colspan="4"><a href="/r/{{.Repo.Name}}/files/{{parent .Path}}?ref={{.CurrentRef}}">..</a></td> |
| 51 |
{{end}} |
35 |
</tr> |
| 52 |
{{range .Entries}} |
36 |
{{end}} |
| 53 |
<tr> |
37 |
{{range .Entries}} |
| 54 |
<td class="filetype text-center">{{if .IsDir}}d{{else}}f{{end}}</td> |
38 |
<tr> |
| 55 |
<td> |
39 |
<td class="filetype text-center">{{if .IsDir}}{{template "icon-directory" .}}{{else}}{{template "icon-file" .}}{{end}}</td> |
| 56 |
{{if .IsDir}} |
40 |
<td> |
| 57 |
<a href="/r/{{$.Repo.Name}}/files/{{.Path}}?ref={{$.CurrentRef}}">{{.Name}}/</a> |
41 |
{{if .IsDir}} |
| 58 |
{{else}} |
42 |
<a href="/r/{{$.Repo.Name}}/files/{{.Path}}?ref={{$.CurrentRef}}">{{.Name}}/</a> |
| 59 |
<a href="/r/{{$.Repo.Name}}/blob/{{.Path}}?ref={{$.CurrentRef}}">{{.Name}}</a> |
43 |
{{else}} |
|
|
44 |
<a href="/r/{{$.Repo.Name}}/blob/{{.Path}}?ref={{$.CurrentRef}}">{{.Name}}</a> |
|
|
45 |
{{end}} |
|
|
46 |
</td> |
|
|
47 |
<td class="text-right"><code>{{.Mode}}</code></td> |
|
|
48 |
<td class="text-right">{{if not .IsDir}}<code>{{humanize .Size}}</code>{{end}}</td> |
|
|
49 |
<td class="text-center">{{if not .IsDir}}<a href="/r/{{$.Repo.Name}}/raw/{{.Path}}?ref={{$.CurrentRef}}">raw</a>{{end}}</td> |
|
|
50 |
</tr> |
| 60 |
{{end}} |
51 |
{{end}} |
| 61 |
</td> |
52 |
</tbody> |
| 62 |
<td class="text-right"><code>{{.Mode}}</code></td> |
53 |
</table> |
| 63 |
<td class="text-right">{{if not .IsDir}}<code>{{humanize .Size}}</code>{{end}}</td> |
54 |
</div> |
| 64 |
<td class="text-center">{{if not .IsDir}}<a href="/r/{{$.Repo.Name}}/raw/{{.Path}}?ref={{$.CurrentRef}}">raw</a>{{end}}</td> |
55 |
</div> |
| 65 |
</tr> |
|
|
| 66 |
{{end}} |
|
|
| 67 |
</tbody> |
|
|
| 68 |
</table> |
|
|
| 69 |
</main> |
56 |
</main> |
| 70 |
|
|
|
| 71 |
{{template "footer.html" .}} |
57 |
{{template "footer.html" .}} |
| 72 |
</body> |
58 |
</body> |
| 73 |
</html> |
59 |
</html> |
|
|
60 |
|
|
diff --git a/views/nav-main.html b/views/nav-main.html
|
| 1 |
<nav class="nav-main"> |
1 |
<nav class="nav-main"> |
| 2 |
<a href="/">Repositories</a> |
2 |
<div class="nav-main-left"> |
|
|
3 |
<a href="/">Repositories</a> |
|
|
4 |
{{if .Repo}} |
|
|
5 |
<span>»</span> |
|
|
6 |
<div><span class="text-bold">{{.Repo.Name}}</span>: {{.Repo.Description}}</div> |
|
|
7 |
{{end}} |
|
|
8 |
</div> |
| 3 |
{{if .Repo}} |
9 |
{{if .Repo}} |
| 4 |
<span>»</span> |
10 |
<div class="nav-main-right"> |
| 5 |
<div><span class="text-bold">{{.Repo.Name}}</span>: {{.Repo.Description}}</div> |
11 |
<a href="/r/{{.Repo.Name}}/commits.rss?ref={{.CurrentRef}}" title="Commits RSS">Commits RSS</a> |
|
|
12 |
<a href="/r/{{.Repo.Name}}/tags.rss" title="Tags RSS">Tags RSS</a> |
|
|
13 |
</div> |
| 6 |
{{end}} |
14 |
{{end}} |
| 7 |
</nav> |
15 |
</nav> |
|
diff --git a/views/repository.html b/views/repository.html
|
| ... |
| 40 |
<tr> |
40 |
<tr> |
| 41 |
<th width="110">Date</th> |
41 |
<th width="110">Date</th> |
| 42 |
<th>Commit message</th> |
42 |
<th>Commit message</th> |
|
|
43 |
<th width="70"></th> |
| 43 |
<th width="200">Author</th> |
44 |
<th width="200">Author</th> |
| 44 |
<th width="90" class="text-right">Lines</th> |
45 |
<th width="90" class="text-right">Lines</th> |
| 45 |
</tr> |
46 |
</tr> |
| ... |
| 49 |
<tr> |
50 |
<tr> |
| 50 |
<td>{{.AuthorDate.Format "2006-01-02"}}</td> |
51 |
<td>{{.AuthorDate.Format "2006-01-02"}}</td> |
| 51 |
<td><a href="/r/{{$.Repo.Name}}/c/{{.Hash}}">{{truncate .Message 80}}</a></td> |
52 |
<td><a href="/r/{{$.Repo.Name}}/c/{{.Hash}}">{{truncate .Message 80}}</a></td> |
|
|
53 |
<td class="text-center"> |
|
|
54 |
<a href="/r/{{$.Repo.Name}}/files/?ref={{.Hash}}" title="Browse repository at this point">browse</a> |
|
|
55 |
</td> |
| 52 |
<td>{{.AuthorName}}</td> |
56 |
<td>{{.AuthorName}}</td> |
| 53 |
<td class="text-right"> |
57 |
<td class="text-right"> |
| 54 |
<span class="stats-add">+{{.Additions}}</span>/<span class="stats-del">-{{.Deletions}}</span> |
58 |
<span class="stats-add">+{{.Additions}}</span>/<span class="stats-del">-{{.Deletions}}</span> |
| ... |
| 56 |
</tr> |
60 |
</tr> |
| 57 |
{{else}} |
61 |
{{else}} |
| 58 |
<tr> |
62 |
<tr> |
| 59 |
<td colspan="4">No commits found.</td> |
63 |
<td colspan="5">No commits found.</td> |
| 60 |
</tr> |
64 |
</tr> |
| 61 |
{{end}} |
65 |
{{end}} |
| 62 |
</tbody> |
66 |
</tbody> |
| ... |
| 86 |
</div> |
90 |
</div> |
| 87 |
{{end}} |
91 |
{{end}} |
| 88 |
</main> |
92 |
</main> |
| 89 |
|
|
|
| 90 |
{{template "footer.html" .}} |
93 |
{{template "footer.html" .}} |
| 91 |
</body> |
94 |
</body> |
| 92 |
</html> |
95 |
</html> |
|
|
96 |
|
|
diff --git a/views/tree.html b/views/tree.html
|
|
|
1 |
{{define "icon-file"}}<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 512 512" style="vertical-align: middle; margin-right: 4px;"><path fill="#000000" d="M334.627 16H48v480h424V153.373ZM440 166.627V168H320V48h1.373ZM80 464V48h208v152h152v264Z"/></svg>{{end}} |
|
|
2 |
{{define "icon-directory"}}<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 512 512" style="vertical-align: middle; margin-right: 4px;"><path fill="#000000" d="M472 472H40a24.03 24.03 0 0 1-24-24V64a24.03 24.03 0 0 1 24-24h186.667a23.935 23.935 0 0 1 22.154 14.77L269.333 104H472a24.03 24.03 0 0 1 24 24v320a24.03 24.03 0 0 1-24 24M48 440h416V136H248l-26.667-64H48Z"/></svg>{{end}} |
|
|
3 |
|
|
|
4 |
{{define "tree"}} |
|
|
5 |
{{range .Entries}} |
|
|
6 |
{{if .IsDir}} |
|
|
7 |
<details class="tree-directory" {{if hasPrefix $.CurrentPath .Path}}open{{end}}> |
|
|
8 |
<summary class="tree-entry directory" style="padding-left: {{add (int (multiply (float64 .Depth) 15.0)) 10}}px"> |
|
|
9 |
<a href="/r/{{$.RepoName}}/files/{{.Path}}?ref={{$.CurrentRef}}" class="text-reset">{{template "icon-directory" .}} {{.Name}}</a> |
|
|
10 |
</summary> |
|
|
11 |
{{template "tree" dict "Entries" .Children "RepoName" $.RepoName "CurrentRef" $.CurrentRef "CurrentPath" $.CurrentPath}} |
|
|
12 |
</details> |
|
|
13 |
{{else}} |
|
|
14 |
<a href="/r/{{$.RepoName}}/blob/{{.Path}}?ref={{$.CurrentRef}}" |
|
|
15 |
class="tree-entry {{if eq .Path $.CurrentPath}}active{{end}}" |
|
|
16 |
style="padding-left: {{add (int (multiply (float64 .Depth) 15.0)) 25}}px"> |
|
|
17 |
{{template "icon-file" .}} {{.Name}} |
|
|
18 |
</a> |
|
|
19 |
{{end}} |
|
|
20 |
{{end}} |
|
|
21 |
{{end}} |