fierj
PublicTiny personal git forge
e37b87df9af786adf6267e0a5232f821fec9df97
diff --git a/handlers.go b/handlers.go
index 7d90030..6733fb9 100644
--- a/handlers.go
+++ b/handlers.go
@@ -1,12 +1,80 @@
package main
import (
+ "embed"
+ "fmt"
"log/slog"
"net/http"
"sort"
+ "strings"
"text/template"
+ "time"
)
+type BreadcrumbItem struct {
+ Name string
+ URL string
+}
+
+//go:embed templates/*.html
+var templateFS embed.FS
+
+var funcMap = template.FuncMap{
+ "pathJoin": func(parts ...string) string {
+ var nonEmpty []string
+ for _, p := range parts {
+ if p != "" {
+ nonEmpty = append(nonEmpty, p)
+ }
+ }
+ return strings.Join(nonEmpty, "/")
+ },
+ "shortHash": func(h string) string {
+ if len(h) > 8 {
+ return h[:8]
+ }
+ return h
+ },
+ "hasSuffix": strings.HasSuffix,
+ "timeAgo": func(ts string) string {
+ t, err := time.Parse(time.RFC3339, ts)
+ if err != nil {
+ return ts
+ }
+ d := time.Since(t)
+ switch {
+ case d < time.Minute:
+ return "just now"
+ case d < time.Hour:
+ m := int(d.Minutes())
+ if m == 1 {
+ return "1 minute ago"
+ }
+ return fmt.Sprintf("%d minutes ago", m)
+ case d < 24*time.Hour:
+ h := int(d.Hours())
+ if h == 1 {
+ return "1 hour ago"
+ }
+ return fmt.Sprintf("%d hours ago", h)
+ case d < 30*24*time.Hour:
+ days := int(d.Hours() / 24)
+ if days == 1 {
+ return "1 day ago"
+ }
+ return fmt.Sprintf("%d days ago", days)
+ case d < 365*24*time.Hour:
+ months := int(d.Hours() / 24 / 30)
+ if months == 1 {
+ return "1 month ago"
+ }
+ return fmt.Sprintf("%d months ago", months)
+ default:
+ return ts[:10]
+ }
+ },
+}
+
func renderError(w http.ResponseWriter, tmpl *template.Template, code int, message string) {
w.WriteHeader(code)
tmpl.ExecuteTemplate(w, "error.html", map[string]any{
@@ -15,6 +83,23 @@ func renderError(w http.ResponseWriter, tmpl *template.Template, code int, messa
})
}
+func Breadcrumb(path string) []BreadcrumbItem {
+ if path == "" {
+ return nil
+ }
+ parts := strings.Split(path, "/")
+ items := make([]BreadcrumbItem, len(parts))
+ cumulative := ""
+ for i, p := range parts {
+ if i > 0 {
+ cumulative += "/"
+ }
+ cumulative += p
+ items[i] = BreadcrumbItem{Name: p, URL: cumulative}
+ }
+ return items
+}
+
func Repos(cfg Config, tmpl *template.Template) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
repos, err := ListRepos(cfg)
@@ -79,11 +164,11 @@ func Tree(cfg Config, tmpl *template.Template) http.HandlerFunc {
}
readme := git.Readme(ref, treePath)
tmpl.ExecuteTemplate(w, "tree.html", map[string]any{
- "Repo": git.Repo(),
- "Ref": ref,
- "Path": treePath,
- // "Breadcrumb": makeBreadcrumb(treePath),
- "Entries": fileEntries,
+ "Repo": git.Repo(),
+ "Ref": ref,
+ "Path": treePath,
+ "Breadcrumb": Breadcrumb(treePath),
+ "Entries": fileEntries,
// "CloneURL": fmt.Sprintf("%s@%s:%s.git", cfg.SSHUser, cfg.Host, repoName),
"Description": git.Description(),
"Branches": git.Branches(),
@@ -110,10 +195,10 @@ func Blob(cfg Config, tmpl *template.Template) http.HandlerFunc {
return
}
tmpl.ExecuteTemplate(w, "blob.html", map[string]any{
- "Repo": git.Repo(),
- "Ref": ref,
- "Path": filePath,
- // "Breadcrumb": makeBreadcrumb(filePath),
+ "Repo": git.Repo(),
+ "Ref": ref,
+ "Path": filePath,
+ "Breadcrumb": Breadcrumb(filePath),
"Content": content,
"Description": git.Description(),
"Branches": git.Branches(),
diff --git a/main.go b/main.go
index f6615a8..047568e 100644
--- a/main.go
+++ b/main.go
@@ -2,77 +2,15 @@ package main
import (
"context"
- "embed"
- "fmt"
"log/slog"
"net/http"
"os"
"os/signal"
- "strings"
"syscall"
"text/template"
"time"
)
-//go:embed templates/*.html
-var templateFS embed.FS
-
-var funcMap = template.FuncMap{
- "pathJoin": func(parts ...string) string {
- var nonEmpty []string
- for _, p := range parts {
- if p != "" {
- nonEmpty = append(nonEmpty, p)
- }
- }
- return strings.Join(nonEmpty, "/")
- },
- "shortHash": func(h string) string {
- if len(h) > 8 {
- return h[:8]
- }
- return h
- },
- "hasSuffix": strings.HasSuffix,
- "timeAgo": func(ts string) string {
- t, err := time.Parse(time.RFC3339, ts)
- if err != nil {
- return ts
- }
- d := time.Since(t)
- switch {
- case d < time.Minute:
- return "just now"
- case d < time.Hour:
- m := int(d.Minutes())
- if m == 1 {
- return "1 minute ago"
- }
- return fmt.Sprintf("%d minutes ago", m)
- case d < 24*time.Hour:
- h := int(d.Hours())
- if h == 1 {
- return "1 hour ago"
- }
- return fmt.Sprintf("%d hours ago", h)
- case d < 30*24*time.Hour:
- days := int(d.Hours() / 24)
- if days == 1 {
- return "1 day ago"
- }
- return fmt.Sprintf("%d days ago", days)
- case d < 365*24*time.Hour:
- months := int(d.Hours() / 24 / 30)
- if months == 1 {
- return "1 month ago"
- }
- return fmt.Sprintf("%d months ago", months)
- default:
- return ts[:10]
- }
- },
-}
-
func main() {
cfgPath := "config.json"
if len(os.Args) > 1 {