Monorepo for Tangled
0

Configure Feed

Select the types of activity you want to include in your feed.

appview/pages: format profile social links

Signed-off-by: Mikael Siidorow <mikael@siidorow.com>

Mikael Siidorow (Jul 14, 2026, 6:42 PM +0200) b73f51b4 f2770fc2

+152 -2
+1
appview/pages/funcmap.go
··· 427 427 text = strings.TrimPrefix(text, "http://") 428 428 return text 429 429 }, 430 + "socialLink": socialLinkPresentation, 430 431 "isNil": func(t any) bool { 431 432 // returns false for other "zero" values 432 433 return t == nil
+87
appview/pages/social_link.go
··· 1 + package pages 2 + 3 + import ( 4 + "net/url" 5 + "strings" 6 + ) 7 + 8 + type socialLinkView struct { 9 + Icon string 10 + Label string 11 + } 12 + 13 + func socialLinkPresentation(raw string) socialLinkView { 14 + link := socialLinkView{ 15 + Icon: "link", 16 + Label: strings.TrimSuffix(trimHTTPPrefix(raw), "/"), 17 + } 18 + 19 + u, err := url.Parse(raw) 20 + if err != nil || u.Host == "" { 21 + return link 22 + } 23 + 24 + link.Label = compactURL(u) 25 + host := strings.TrimPrefix(strings.ToLower(u.Hostname()), "www.") 26 + segments := pathSegments(u.Path) 27 + 28 + switch host { 29 + case "github.com": 30 + link.Icon = "github" 31 + if len(segments) == 1 { 32 + link.Label = segments[0] 33 + } 34 + case "gitlab.com": 35 + link.Icon = "gitlab" 36 + if len(segments) == 1 { 37 + link.Label = segments[0] 38 + } 39 + case "linkedin.com": 40 + link.Icon = "linkedin" 41 + if len(segments) == 2 { 42 + link.Label = strings.Join(segments, "/") 43 + } 44 + case "bsky.app": 45 + link.Icon = "bluesky" 46 + if len(segments) == 2 && segments[0] == "profile" { 47 + link.Label = "@" + strings.TrimPrefix(segments[1], "@") 48 + } 49 + } 50 + 51 + return link 52 + } 53 + 54 + func compactURL(u *url.URL) string { 55 + host := u.Host 56 + if strings.HasPrefix(strings.ToLower(host), "www.") { 57 + host = host[len("www."):] 58 + } 59 + 60 + label := host + u.EscapedPath() 61 + if u.RawQuery != "" { 62 + label += "?" + u.RawQuery 63 + } 64 + if u.Fragment != "" { 65 + label += "#" + u.EscapedFragment() 66 + } 67 + 68 + return strings.TrimSuffix(label, "/") 69 + } 70 + 71 + func pathSegments(path string) []string { 72 + path = strings.Trim(path, "/") 73 + if path == "" { 74 + return nil 75 + } 76 + return strings.Split(path, "/") 77 + } 78 + 79 + func trimHTTPPrefix(link string) string { 80 + lower := strings.ToLower(link) 81 + for _, prefix := range []string{"https://", "http://"} { 82 + if strings.HasPrefix(lower, prefix) { 83 + return link[len(prefix):] 84 + } 85 + } 86 + return link 87 + }
+3 -2
appview/pages/templates/user/fragments/profileCard.html
··· 66 66 {{ end }} 67 67 {{ range $link := .Links }} 68 68 {{ if $link }} 69 + {{ $social := socialLink $link }} 69 70 <div class="flex items-center gap-2"> 70 - <span class="flex-shrink-0">{{ i "link" "size-4" }}</span> 71 - <a rel="nofollow me" href="{{ $link }}">{{ $link }}</a> 71 + <span class="flex-shrink-0">{{ i $social.Icon "size-4" }}</span> 72 + <a rel="nofollow me" href="{{ $link }}" title="{{ $link }}">{{ $social.Label }}</a> 72 73 </div> 73 74 {{ end }} 74 75 {{ end }}