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