bluesky viewer in the terminal
1package ui
2
3import (
4 "encoding/json"
5 "fmt"
6 "os"
7
8 "github.com/stormlightlabs/skypanel/cli/internal/store"
9)
10
11// DisplayProfileHeader shows a formatted profile summary
12func DisplayProfileHeader(profile *store.ActorProfile) {
13 Titleln("@%s", profile.Handle)
14 if profile.DisplayName != "" {
15 Subtitleln("%s", profile.DisplayName)
16 }
17 if profile.Description != "" {
18 fmt.Printf(" %s\n", profile.Description)
19 }
20 Infoln(" Followers: %d | Following: %d | Posts: %d", profile.FollowersCount, profile.FollowsCount, profile.PostsCount)
21
22 fmt.Println()
23}
24
25// DisplayFeed shows a formatted list of posts from a feed
26func DisplayFeed(feed []store.FeedViewPost, cursor string) {
27 if len(feed) == 0 {
28 Infoln("No posts found.")
29 return
30 }
31
32 for i, item := range feed {
33 post := item.Post
34 if post == nil {
35 continue
36 }
37
38 Subtitleln("[%d] Post by @%s", i+1, post.Author.Handle)
39 Infoln(" URI: %s", post.Uri)
40
41 if recordMap, ok := post.Record.(map[string]any); ok {
42 if text, ok := recordMap["text"].(string); ok {
43 displayText := text
44 if len(displayText) > 200 {
45 displayText = displayText[:200] + "..."
46 }
47 fmt.Printf(" %s\n", displayText)
48 }
49 }
50
51 Infoln(" ❤️ %d | 🔁 %d | 💬 %d", post.LikeCount, post.RepostCount, post.ReplyCount)
52
53 if item.Reason != nil && item.Reason.By != nil {
54 Infoln(" ↻ Reposted by @%s", item.Reason.By.Handle)
55 }
56
57 Infoln(" Indexed: %s", post.IndexedAt)
58 fmt.Println()
59 }
60
61 Successln("Showing %d post(s)", len(feed))
62 if cursor != "" {
63 Infoln("Next cursor: %s", cursor)
64 }
65}
66
67// DisplayJSON marshals and prints data as JSON
68func DisplayJSON(data any) error {
69 encoder := json.NewEncoder(os.Stdout)
70 encoder.SetIndent("", " ")
71 return encoder.Encode(data)
72}