this repo has no description
1package pages 2 3import ( 4 "fmt" 5 "html" 6 "html/template" 7 "log" 8 "path/filepath" 9 "reflect" 10 "strings" 11 12 "github.com/dustin/go-humanize" 13) 14 15func funcMap() template.FuncMap { 16 return template.FuncMap{ 17 "split": func(s string) []string { 18 return strings.Split(s, "\n") 19 }, 20 "truncateAt30": func(s string) string { 21 if len(s) <= 30 { 22 return s 23 } 24 return s[:30] + "…" 25 }, 26 "splitOn": func(s, sep string) []string { 27 return strings.Split(s, sep) 28 }, 29 "add": func(a, b int) int { 30 return a + b 31 }, 32 "sub": func(a, b int) int { 33 return a - b 34 }, 35 "cond": func(cond interface{}, a, b string) string { 36 if cond == nil { 37 return b 38 } 39 40 if boolean, ok := cond.(bool); boolean && ok { 41 return a 42 } 43 44 return b 45 }, 46 "didOrHandle": func(did, handle string) string { 47 if handle != "" { 48 return fmt.Sprintf("@%s", handle) 49 } else { 50 return did 51 } 52 }, 53 "assoc": func(values ...string) ([][]string, error) { 54 if len(values)%2 != 0 { 55 return nil, fmt.Errorf("invalid assoc call, must have an even number of arguments") 56 } 57 pairs := make([][]string, 0) 58 for i := 0; i < len(values); i += 2 { 59 pairs = append(pairs, []string{values[i], values[i+1]}) 60 } 61 return pairs, nil 62 }, 63 "append": func(s []string, values ...string) []string { 64 s = append(s, values...) 65 return s 66 }, 67 "timeFmt": humanize.Time, 68 "byteFmt": humanize.Bytes, 69 "length": func(slice any) int { 70 v := reflect.ValueOf(slice) 71 if v.Kind() == reflect.Slice || v.Kind() == reflect.Array { 72 return v.Len() 73 } 74 return 0 75 }, 76 "splitN": func(s, sep string, n int) []string { 77 return strings.SplitN(s, sep, n) 78 }, 79 "escapeHtml": func(s string) template.HTML { 80 if s == "" { 81 return template.HTML("<br>") 82 } 83 return template.HTML(s) 84 }, 85 "unescapeHtml": func(s string) string { 86 return html.UnescapeString(s) 87 }, 88 "nl2br": func(text string) template.HTML { 89 return template.HTML(strings.Replace(template.HTMLEscapeString(text), "\n", "<br>", -1)) 90 }, 91 "unwrapText": func(text string) string { 92 paragraphs := strings.Split(text, "\n\n") 93 94 for i, p := range paragraphs { 95 lines := strings.Split(p, "\n") 96 paragraphs[i] = strings.Join(lines, " ") 97 } 98 99 return strings.Join(paragraphs, "\n\n") 100 }, 101 "sequence": func(n int) []struct{} { 102 return make([]struct{}, n) 103 }, 104 "subslice": func(slice any, start, end int) any { 105 v := reflect.ValueOf(slice) 106 if v.Kind() != reflect.Slice && v.Kind() != reflect.Array { 107 return nil 108 } 109 if start < 0 || start > v.Len() || end > v.Len() || start > end { 110 return nil 111 } 112 return v.Slice(start, end).Interface() 113 }, 114 "markdown": func(text string) template.HTML { 115 return template.HTML(renderMarkdown(text)) 116 }, 117 "isNil": func(t any) bool { 118 // returns false for other "zero" values 119 return t == nil 120 }, 121 "list": func(args ...any) []any { 122 return args 123 }, 124 "i": func(name string, classes ...string) template.HTML { 125 data, err := icon(name, classes) 126 if err != nil { 127 log.Printf("icon %s does not exist", name) 128 data, _ = icon("airplay", classes) 129 } 130 return template.HTML(data) 131 }, 132 } 133} 134 135func icon(name string, classes []string) (template.HTML, error) { 136 iconPath := filepath.Join("static", "icons", name) 137 138 if filepath.Ext(name) == "" { 139 iconPath += ".svg" 140 } 141 142 data, err := Files.ReadFile(iconPath) 143 if err != nil { 144 return "", fmt.Errorf("icon %s not found: %w", name, err) 145 } 146 147 // Convert SVG data to string 148 svgStr := string(data) 149 150 svgTagEnd := strings.Index(svgStr, ">") 151 if svgTagEnd == -1 { 152 return "", fmt.Errorf("invalid SVG format for icon %s", name) 153 } 154 155 classTag := ` class="` + strings.Join(classes, " ") + `"` 156 157 modifiedSVG := svgStr[:svgTagEnd] + classTag + svgStr[svgTagEnd:] 158 return template.HTML(modifiedSVG), nil 159}