utils.gno
3.14 Kb ยท 146 lines
1package blog
2
3import (
4 "net/url"
5 "strings"
6 "time"
7
8 "gno.land/p/moul/md"
9 "gno.land/p/nt/ufmt"
10)
11
12func renderLinks(prefix, kind string, values []string, labelPrefix string) string {
13 links := make([]string, len(values))
14 for i, val := range values {
15 label := labelPrefix + val
16 href := prefix + ":" + kind + "/" + val
17 links[i] = md.Link(label, href)
18 }
19 return strings.Join(links, ", ") + "\n"
20}
21
22func hasField(fields []string, match string) bool {
23 for _, field := range fields {
24 if field == match {
25 return true
26 }
27 }
28 return false
29}
30
31func extractListingDisplay(key string, value interface{}) (label string, count int) {
32 if strings.Contains(key, "::") {
33 parts := strings.Split(key, "::")
34 if len(parts) > 1 {
35 return parts[1], value.(int)
36 }
37 }
38 return key, value.(int)
39}
40
41func renderBreadcrumb(prefix, path string) string {
42 segments := strings.Split(path, "/")
43 base := prefix
44 var parts []string
45
46 if prefix != "" {
47 parts = append(parts, md.Link(prefix, prefix))
48 }
49
50 for i, seg := range segments {
51 if seg == "" {
52 continue
53 }
54 base += ":" + seg
55 label := seg
56 if i == len(segments)-1 {
57 label = seg
58 parts = append(parts, label)
59 break
60 }
61 parts = append(parts, md.Link(label, base))
62 }
63 return strings.Join(parts, "/")
64}
65
66func formatTime(t time.Time, format string) string {
67 switch format {
68 case "relative":
69 return calculateTimeSince(t)
70 case "short":
71 return t.Format("02 Jan 2006")
72 case "full":
73 return t.Format("January 02, 2006 at 3:04 PM")
74 default:
75 return calculateTimeSince(t)
76 }
77}
78
79func calculateTimeSince(t time.Time) string {
80 duration := time.Since(t)
81 switch {
82 case duration < time.Minute:
83 return "just now"
84 case duration < time.Hour:
85 if duration < 2*time.Minute {
86 return "a minute ago"
87 }
88 return ufmt.Sprintf("%d minutes ago", int(duration.Minutes()))
89 case duration < 24*time.Hour:
90 if duration < 2*time.Hour {
91 return "an hour ago"
92 }
93 return ufmt.Sprintf("%d hours ago", int(duration.Hours()))
94 case duration < 7*24*time.Hour:
95 if duration < 2*24*time.Hour {
96 return "a day ago"
97 }
98 return ufmt.Sprintf("%d days ago", int(duration.Hours()/24))
99 case duration < 30*24*time.Hour:
100 if duration < 2*7*24*time.Hour {
101 return "a week ago"
102 }
103 return ufmt.Sprintf("%d weeks ago", int(duration.Hours()/(7*24)))
104 default:
105 if duration < 2*30*24*time.Hour {
106 return "a month ago"
107 }
108 return ufmt.Sprintf("%d months ago", int(duration.Hours()/(30*24)))
109 }
110}
111
112func tryParseFlexibleDate(s string) *time.Time {
113 formats := []string{
114 time.RFC3339, // rfc3339 format
115 "2006-01-02", // date only
116 "2006-01", // year and month
117 "2006", // year only
118 }
119 for _, format := range formats {
120 if t, err := time.Parse(format, s); err == nil {
121 return &t
122 }
123 }
124 return nil
125}
126
127func titleToSlug(title string) string {
128 slug := strings.ToLower(title)
129 slug = strings.ReplaceAll(slug, " ", "-")
130 slug = strings.Map(func(r rune) rune {
131 if r >= 'a' && r <= 'z' || r >= '0' && r <= '9' || r == '-' {
132 return r
133 }
134 return -1
135 }, slug)
136 return slug
137}
138
139func handleSlug(slug, title string) string {
140 if slug == "" {
141 slug = titleToSlug(title)
142 }
143 once := url.PathEscape(slug)
144 twice := url.PathEscape(once)
145 return twice
146}