commit c4a56c0a8e7accfd981a9b7b19515d5f3302c278 from: Matt Streatfield date: Thu Apr 17 14:02:44 2025 UTC Display most appropriate channel data Improve channel styling commit - 93ff9d7f210e985d4d61bdb8dda1ea69c2b2cb43 commit + c4a56c0a8e7accfd981a9b7b19515d5f3302c278 blob - e03df411766d7530d1f97f11d077a14853a3aee0 blob + 99641078e9a491a9611743912649a41225603666 --- internal/service/handlers.go +++ internal/service/handlers.go @@ -11,8 +11,13 @@ type TemplateData struct { Results []rss.Channel } +var templateFuncs = template.FuncMap{ + "timeAgo": timeAgo, +} + func render(w http.ResponseWriter, name string, data any) { - tmpl := template.Must(template.ParseGlob("internal/templates/*.tmpl")) + tmpl := template.New("").Funcs(templateFuncs) + tmpl = template.Must(tmpl.ParseGlob("internal/templates/*.tmpl")) tmpl.ExecuteTemplate(w, name, data) } blob - /dev/null blob + b207f5c5d52efde9845648e85728ecb33f499fb8 (mode 644) --- /dev/null +++ internal/service/util.go @@ -0,0 +1,39 @@ +package service + +import ( + "fmt" + "time" +) + +func timeAgo(t time.Time) string { + duration := time.Since(t) + + switch { + case duration < time.Minute: + return "just now" + case duration < time.Hour: + mins := int(duration.Minutes()) + if mins == 1 { + return "1 minute ago" + } + return fmt.Sprintf("%d minutes ago", mins) + case duration < 24*time.Hour: + hrs := int(duration.Hours()) + if hrs == 1 { + return "1 hour ago" + } + return fmt.Sprintf("%d hours ago", hrs) + case duration < 365*24*time.Hour: + days := int(duration.Hours()) / 24 + if days == 1 { + return "1 day ago" + } + return fmt.Sprintf("%d days ago", days) + default: + years := int(duration.Hours()) / 24 / 365 + if years == 1 { + return "1 year ago" + } + return fmt.Sprintf("%d years ago", years) + } +} blob - d74a5939f20dbb31284e8318c329c0f2bace4fc1 blob + 19559976b5fedec3fdbb7b5a905a98abe09800a9 --- internal/templates/results.tmpl +++ internal/templates/results.tmpl @@ -2,21 +2,33 @@
{{ range . }}
- +
-

{{ .Title }}

+
+

{{ .Title }}

+ +

{{ .Description }}

- {{ range .Link }} - {{ . }} - {{ end }} - -
PubDate - {{ .PubDate }}
-
Items - {{ len .Items }}
- {{ range .Categories }} -
Category - {{ .Text }}
- {{ end }} -
Owner - {{ .Owner.Email }}
- +
+ {{ if gt (len .Link) 0 }} + + + + + + {{ end }} + + + + + + + {{ range .Categories }} + #{{ .Text }} + {{ end }} +
{{ end }} blob - b3c398b78b58e18fc417a6119e785b66f98aa4f5 blob + f49b78523709356d5ea4991e57b1a5c47965d94c --- web/style.css +++ web/style.css @@ -4,6 +4,7 @@ --pink: #ee8695; --blue: #57c2ff; --dark-blue: #468fb9; + --light-gray: #919191; --gray: #35343d; --dark-gray: #292831; --black: #1c1b1e; @@ -86,7 +87,7 @@ main { &.search-area { margin: 0 auto; width: 100%; - max-width: 700px; + max-width: 900px; } } @@ -230,9 +231,48 @@ main:has(.result)>hgroup.search-animation { margin-bottom: 1rem; img { - width: 200px; - height: 200px; border-radius: 2rem; margin-right: 1rem; + } + + hgroup { + margin-bottom: 0.5rem; + + h2 { + margin-bottom: 0; + } + + time { + color: var(--light-gray); + font-size: .8em; + } + } + + a { + font-size: .9em; + } + + .tag-line { + display: flex; + align-items: center; + + a.button { + margin-right: .5rem; + display: block; + color: var(--black); + padding: 4px; + border-radius: 100px; + line-height: 0; + background-color: white; + } + + a.category { + margin-right: .5rem; + background-color: var(--dark-blue); + color: white; + font-size: .6em; + padding: .2rem .4rem; + border-radius: 1rem; + } } } \ No newline at end of file