Signed-off-by: Anirudh Oppiliappan anirudh@tangled.sh
+14
-7
appview/db/timeline.go
+14
-7
appview/db/timeline.go
···
18
18
// optional: populate only if event is Follow
19
19
*Profile
20
20
*FollowStats
21
+
*FollowStatus
21
22
}
22
23
23
24
// TODO: this gathers heterogenous events from different sources and aggregates
24
25
// them in code; if we did this entirely in sql, we could order and limit and paginate easily
25
-
func MakeTimeline(e Execer, limit int) ([]TimelineEvent, error) {
26
+
func MakeTimeline(e Execer, limit int, loggedInUserDid string) ([]TimelineEvent, error) {
26
27
var events []TimelineEvent
27
28
28
29
repos, err := getTimelineRepos(e, limit)
···
35
36
return nil, err
36
37
}
37
38
38
-
follows, err := getTimelineFollows(e, limit)
39
+
follows, err := getTimelineFollows(e, limit, loggedInUserDid)
39
40
if err != nil {
40
41
return nil, err
41
42
}
···
129
130
return events, nil
130
131
}
131
132
132
-
func getTimelineFollows(e Execer, limit int) ([]TimelineEvent, error) {
133
+
func getTimelineFollows(e Execer, limit int, loggedInUserDid string) ([]TimelineEvent, error) {
133
134
follows, err := GetFollows(e, limit)
134
135
if err != nil {
135
136
return nil, err
···
159
160
profile, _ := profiles[f.SubjectDid]
160
161
followStatMap, _ := followStatMap[f.SubjectDid]
161
162
163
+
followStatus := IsNotFollowing
164
+
if loggedInUserDid != "" {
165
+
followStatus = GetFollowStatus(e, loggedInUserDid, f.SubjectDid)
166
+
}
167
+
162
168
events = append(events, TimelineEvent{
163
-
Follow: &f,
164
-
Profile: profile,
165
-
FollowStats: &followStatMap,
166
-
EventAt: f.FollowedAt,
169
+
Follow: &f,
170
+
Profile: profile,
171
+
FollowStats: &followStatMap,
172
+
FollowStatus: &followStatus,
173
+
EventAt: f.FollowedAt,
167
174
})
168
175
}
169
176
+33
-24
appview/pages/templates/timeline/fragments/timeline.html
+33
-24
appview/pages/templates/timeline/fragments/timeline.html
···
17
17
{{ else if .Star }}
18
18
{{ template "timeline/fragments/starEvent" (list $ .Star) }}
19
19
{{ else if .Follow }}
20
-
{{ template "timeline/fragments/followEvent" (list $ .Follow .Profile .FollowStats) }}
20
+
{{ template "timeline/fragments/followEvent" (list $ .) }}
21
21
{{ end }}
22
22
</div>
23
23
{{ end }}
···
77
77
78
78
{{ define "timeline/fragments/followEvent" }}
79
79
{{ $root := index . 0 }}
80
-
{{ $follow := index . 1 }}
81
-
{{ $profile := index . 2 }}
82
-
{{ $stat := index . 3 }}
80
+
{{ $event := index . 1 }}
81
+
{{ $follow := $event.Follow }}
82
+
{{ $profile := $event.Profile }}
83
+
{{ $stat := $event.FollowStats }}
83
84
84
85
{{ $userHandle := resolve $follow.UserDid }}
85
86
{{ $subjectHandle := resolve $follow.SubjectDid }}
···
89
90
{{ template "user/fragments/picHandleLink" $subjectHandle }}
90
91
<span class="text-gray-700 dark:text-gray-400 text-xs">{{ template "repo/fragments/time" $follow.FollowedAt }}</span>
91
92
</div>
92
-
<div class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800 flex items-center gap-4">
93
-
<div class="flex-shrink-0 max-h-full w-24 h-24">
94
-
<img alt="" class="object-cover rounded-full p-2" src="{{ fullAvatar $subjectHandle }}" />
95
-
</div>
93
+
<div class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800 flex flex-col md:flex-row md:items-center gap-4">
94
+
<div class="flex items-center gap-4 flex-1">
95
+
<div class="flex-shrink-0 max-h-full w-24 h-24">
96
+
<img alt="" class="object-cover rounded-full p-2" src="{{ fullAvatar $subjectHandle }}" />
97
+
</div>
96
98
97
-
<div class="flex-1 min-h-0 justify-around flex flex-col">
98
-
<a href="/{{ $subjectHandle }}">
99
-
<span class="font-bold dark:text-white overflow-hidden text-ellipsis whitespace-nowrap max-w-full">{{ $subjectHandle | truncateAt30 }}</span>
100
-
</a>
101
-
{{ with $profile }}
102
-
{{ with .Description }}
103
-
<p class="text-sm pb-2 md:pb-2">{{.}}</p>
99
+
<div class="flex-1 min-h-0 justify-around flex flex-col">
100
+
<a href="/{{ $subjectHandle }}">
101
+
<span class="font-bold dark:text-white overflow-hidden text-ellipsis whitespace-nowrap max-w-full">{{ $subjectHandle | truncateAt30 }}</span>
102
+
</a>
103
+
{{ with $profile }}
104
+
{{ with .Description }}
105
+
<p class="text-sm pb-2 md:pb-2">{{.}}</p>
106
+
{{ end }}
104
107
{{ end }}
105
-
{{ end }}
106
-
{{ with $stat }}
107
-
<div class="text-sm flex items-center gap-2 my-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full">
108
-
<span class="flex-shrink-0">{{ i "users" "size-4" }}</span>
109
-
<span id="followers"><a href="/{{ $subjectHandle }}?tab=followers">{{ .Followers }} followers</a></span>
110
-
<span class="select-none after:content-['·']"></span>
111
-
<span id="following"><a href="/{{ $subjectHandle }}?tab=following">{{ .Following }} following</a></span>
112
-
</div>
113
-
{{ end }}
108
+
{{ with $stat }}
109
+
<div class="text-sm flex items-center gap-2 my-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full">
110
+
<span class="flex-shrink-0">{{ i "users" "size-4" }}</span>
111
+
<span id="followers"><a href="/{{ $subjectHandle }}?tab=followers">{{ .Followers }} followers</a></span>
112
+
<span class="select-none after:content-['·']"></span>
113
+
<span id="following"><a href="/{{ $subjectHandle }}?tab=following">{{ .Following }} following</a></span>
114
+
</div>
115
+
{{ end }}
116
+
</div>
114
117
</div>
118
+
119
+
{{ if and $root.LoggedInUser (ne $event.FollowStatus.String "IsSelf") }}
120
+
<div class="flex-shrink-0 w-fit ml-auto">
121
+
{{ template "user/fragments/follow" (dict "UserDid" $follow.SubjectDid "FollowStatus" $event.FollowStatus) }}
122
+
</div>
123
+
{{ end }}
115
124
</div>
116
125
{{ end }}
+2
-2
appview/pages/templates/user/fragments/follow.html
+2
-2
appview/pages/templates/user/fragments/follow.html
···
1
1
{{ define "user/fragments/follow" }}
2
2
<button id="{{ normalizeForHtmlId .UserDid }}"
3
-
class="btn mt-2 w-full flex gap-2 items-center group"
3
+
class="btn mt-2 flex gap-2 items-center group"
4
4
5
5
{{ if eq .FollowStatus.String "IsNotFollowing" }}
6
6
hx-post="/follow?subject={{.UserDid}}"
···
12
12
hx-target="#{{ normalizeForHtmlId .UserDid }}"
13
13
hx-swap="outerHTML"
14
14
>
15
-
{{ if eq .FollowStatus.String "IsNotFollowing" }}Follow{{ else }}Unfollow{{ end }}
15
+
{{ if eq .FollowStatus.String "IsNotFollowing" }}{{ i "user-round-plus" "w-4 h-4" }} follow{{ else }}{{ i "user-round-minus" "w-4 h-4" }} unfollow{{ end }}
16
16
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
17
17
</button>
18
18
{{ end }}
+6
-2
appview/state/state.go
+6
-2
appview/state/state.go
···
203
203
func (s *State) Timeline(w http.ResponseWriter, r *http.Request) {
204
204
user := s.oauth.GetUser(r)
205
205
206
-
timeline, err := db.MakeTimeline(s.db, 50)
206
+
var userDid string
207
+
if user != nil {
208
+
userDid = user.Did
209
+
}
210
+
timeline, err := db.MakeTimeline(s.db, 50, userDid)
207
211
if err != nil {
208
212
log.Println(err)
209
213
s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.")
···
224
228
}
225
229
226
230
func (s *State) Home(w http.ResponseWriter, r *http.Request) {
227
-
timeline, err := db.MakeTimeline(s.db, 15)
231
+
timeline, err := db.MakeTimeline(s.db, 15, "")
228
232
if err != nil {
229
233
log.Println(err)
230
234
s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.")