1package tinyclient23import (4 "fmt"5 "net/url"6 "strings"7 "time"8)910type repoCrumb struct{ Label, URL string }1112func repoURL(query url.Values, view, path string) string {13 values := url.Values{"owner": {query.Get("owner")}, "repo": {query.Get("repo")}, "ref": {query.Get("ref")}, "view": {view}}14 if path != "" {15 if view == "issue" || view == "pr" {16 values.Set("id", path)17 } else {18 values.Set("path", path)19 }20 }21 return "/repo?" + values.Encode()22}2324func repoCommitURL(query url.Values, oid string) string {25 values := url.Values{"owner": {query.Get("owner")}, "repo": {query.Get("repo")}, "ref": {oid}}26 return repoURL(values, "commit", "")27}2829func hasNextOffset(value any) bool {30 switch offset := value.(type) {31 case int:32 return offset >= 033 case float64:34 return offset >= 035 default:36 return false37 }38}3940func repoBreadcrumbs(query url.Values) []repoCrumb {41 crumbs := []repoCrumb{{Label: query.Get("repo"), URL: repoURL(query, "tree", "")}}42 if query.Get("path") == "" {43 return crumbs44 }45 parts := strings.Split(query.Get("path"), "/")46 for index, label := range parts {47 crumbs = append(crumbs, repoCrumb{Label: label, URL: repoURL(query, "tree", strings.Join(parts[:index+1], "/"))})48 }49 crumbs[len(crumbs)-1].URL = ""50 return crumbs51}5253func browsePageURL(route string, query url.Values, field string, value any) string {54 values := make(url.Values, len(query)+1)55 for name, items := range query {56 values[name] = append([]string(nil), items...)57 }58 values.Set(field, fmt.Sprint(value))59 return route + "?" + values.Encode()60}6162func shortID(value any) string {63 text, ok := value.(string)64 if !ok {65 return ""66 }67 if len(text) > 12 {68 return text[:12]69 }70 return text71}7273func repoDate(value any) string {74 var seconds int6475 switch value := value.(type) {76 case float64:77 seconds = int64(value)78 case int64:79 seconds = value80 }81 if seconds == 0 {82 return ""83 }84 return time.Unix(seconds, 0).UTC().Format("Jan. 2, 2006")85}