forked from tangled.org/core
Monorepo for Tangled

clean up timeline

Changed files
+89 -51
appview
+5 -5
appview/db/follow.go
··· 8 8 type Follow struct { 9 9 UserDid string 10 10 SubjectDid string 11 - FollowedAt *time.Time 11 + FollowedAt time.Time 12 12 RKey string 13 13 } 14 14 ··· 33 33 followedAtTime, err := time.Parse(time.RFC3339, followedAt) 34 34 if err != nil { 35 35 log.Println("unable to determine followed at time") 36 - follow.FollowedAt = nil 36 + follow.FollowedAt = time.Now() 37 37 } else { 38 - follow.FollowedAt = &followedAtTime 38 + follow.FollowedAt = followedAtTime 39 39 } 40 40 41 41 return &follow, nil ··· 110 110 followedAtTime, err := time.Parse(time.RFC3339, followedAt) 111 111 if err != nil { 112 112 log.Println("unable to determine followed at time") 113 - follow.FollowedAt = nil 113 + follow.FollowedAt = time.Now() 114 114 } else { 115 - follow.FollowedAt = &followedAtTime 115 + follow.FollowedAt = followedAtTime 116 116 } 117 117 118 118 follows = append(follows, follow)
+9 -10
appview/db/repos.go
··· 10 10 Name string 11 11 Knot string 12 12 Rkey string 13 - Created *time.Time 13 + Created time.Time 14 14 } 15 15 16 16 func (d *DB) GetAllRepos() ([]Repo, error) { 17 17 var repos []Repo 18 18 19 - rows, err := d.db.Query(`select * from repos`) 19 + rows, err := d.db.Query(`select did, name, knot, rkey, created from repos`) 20 20 if err != nil { 21 21 return nil, err 22 22 } ··· 24 24 25 25 for rows.Next() { 26 26 var repo Repo 27 - err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, repo.Created) 27 + err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Created) 28 28 if err != nil { 29 29 return nil, err 30 30 } ··· 41 41 func (d *DB) GetAllReposByDid(did string) ([]Repo, error) { 42 42 var repos []Repo 43 43 44 - rows, err := d.db.Query(`select did, name, knot, created from repos where did = ?`, did) 44 + rows, err := d.db.Query(`select did, name, knot, rkey, created from repos where did = ?`, did) 45 45 if err != nil { 46 46 return nil, err 47 47 } ··· 49 49 50 50 for rows.Next() { 51 51 var repo Repo 52 - err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, repo.Created) 52 + err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Created) 53 53 if err != nil { 54 54 return nil, err 55 55 } ··· 73 73 return nil, err 74 74 } 75 75 createdAtTime, _ := time.Parse(time.RFC3339, createdAt) 76 - repo.Created = &createdAtTime 76 + repo.Created = createdAtTime 77 77 78 78 return &repo, nil 79 79 } ··· 107 107 108 108 for rows.Next() { 109 109 var repo Repo 110 - err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, repo.Created) 110 + err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Created) 111 111 if err != nil { 112 112 return nil, err 113 113 } ··· 129 129 130 130 createdAtTime, err := time.Parse(time.RFC3339, createdAt) 131 131 if err != nil { 132 - now := time.Now() 133 - created = &now 132 + *created = time.Now() 134 133 } else { 135 - created = &createdAtTime 134 + *created = createdAtTime 136 135 } 137 136 138 137 return nil
+4 -2
appview/db/timeline.go
··· 1 1 package db 2 2 3 3 import ( 4 + "log" 4 5 "sort" 5 6 "time" 6 7 ) ··· 8 9 type TimelineEvent struct { 9 10 *Repo 10 11 *Follow 11 - EventAt *time.Time 12 + EventAt time.Time 12 13 } 13 14 14 15 func (d *DB) MakeTimeline() ([]TimelineEvent, error) { ··· 25 26 } 26 27 27 28 for _, repo := range repos { 29 + log.Println(repo.Created) 28 30 events = append(events, TimelineEvent{ 29 31 Repo: &repo, 30 32 Follow: nil, ··· 41 43 } 42 44 43 45 sort.Slice(events, func(i, j int) bool { 44 - return events[i].EventAt.After(*events[j].EventAt) 46 + return events[i].EventAt.After(events[j].EventAt) 45 47 }) 46 48 47 49 return events, nil
+1
appview/pages/pages.go
··· 176 176 type TimelineParams struct { 177 177 LoggedInUser *auth.User 178 178 Timeline []db.TimelineEvent 179 + DidHandleMap map[string]string 179 180 } 180 181 181 182 func (p *Pages) Timeline(w io.Writer, params TimelineParams) error {
+12 -7
appview/pages/templates/layouts/topbar.html
··· 13 13 <a href="/repo/new" hx-boost="true" class="{{ $linkstyle }}"> 14 14 <i class="w-6 h-6" data-lucide="plus"></i> 15 15 </a> 16 - <a href="/{{ didOrHandle .Did .Handle }}" hx-boost="true" class="{{ $linkstyle }}"> 17 - {{ didOrHandle .Did .Handle }} 18 - </a> 19 - <a href="/logout"class="{{ $linkstyle }}"> 20 - (logout) 21 - </a> 16 + <details class="relative inline-block text-left"> 17 + <summary class="{{ $linkstyle }} cursor-pointer list-none"> 18 + {{ didOrHandle .Did .Handle }} 19 + </summary> 20 + <div class="absolute flex flex-col right-0 mt-4 p-2 w-48 bg-white border border-black z-50"> 21 + <a href="/{{ didOrHandle .Did .Handle }}"class="{{ $linkstyle }}">profile</a> 22 + <a href="/knots"class="{{ $linkstyle }}">knots</a> 23 + <a href="/settings"class="{{ $linkstyle }}">settings</a> 24 + <a href="/logout" class="text-red-400 hover:text-red-700 no-underline">logout</a> 25 + </div> 26 + </details> 22 27 {{ else }} 23 - <a href="/login" hx-boost="true" class="{{ $linkstyle }}"> 28 + <a href="/login" class="{{ $linkstyle }}"> 24 29 login 25 30 </a> 26 31 {{ end }}
+35 -26
appview/pages/templates/timeline.html
··· 4 4 <h1>Timeline</h1> 5 5 6 6 {{ range .Timeline }} 7 + <div class="relative 8 + px-4 9 + py-2 10 + border-l 11 + border-black 12 + before:content-[''] 13 + before:absolute 14 + before:w-1 15 + before:h-1 16 + before:bg-black 17 + before:rounded-full 18 + before:left-[-2.2px] 19 + before:top-1/2 20 + before:-translate-y-1/2 21 + "> 7 22 {{ if .Repo }} 8 - <div class="border border-black p-4 m-2 bg-white w-1/2"> 9 - <div class="flex items-center"> 10 - <div class="text-sm text-gray-600"> 11 - {{ .Repo.Did }} created 12 - </div> 13 - <div class="px-3">{{ .Repo.Name }}</div> 14 - </div> 15 - 16 - <time class="text-sm text-gray-700" 17 - >{{ .Repo.Created | timeFmt }}</time 18 - > 19 - </div> 23 + {{ $userHandle := index $.DidHandleMap .Repo.Did }} 24 + <div class="flex items-center"> 25 + <p class="text-gray-600"> 26 + <a href="/{{ $userHandle }}" class="no-underline hover:underline">{{ $userHandle }}</a> 27 + created 28 + <a href="/{{ $userHandle }}/{{ .Repo.Name }}" class="no-underline hover:underline">{{ .Repo.Name }}</a> 29 + <time class="text-gray-700">{{ .Repo.Created | timeFmt }}</time> 30 + </p> 31 + </div> 20 32 {{ else if .Follow }} 21 - <div class="border border-black p-4 m-2 bg-white w-1/2"> 22 - <div class="flex items-center"> 23 - <div class="text-sm text-gray-600"> 24 - {{ .Follow.UserDid }} followed 25 - </div> 26 - <div class="text-sm text-gray-800"> 27 - {{ .Follow.SubjectDid }} 28 - </div> 29 - </div> 30 - 31 - <time class="text-sm text-gray-700" 32 - >{{ .Follow.FollowedAt | timeFmt }}</time 33 - > 34 - </div> 33 + {{ $userHandle := index $.DidHandleMap .Follow.UserDid }} 34 + {{ $subjectHandle := index $.DidHandleMap .Follow.SubjectDid }} 35 + <div class="flex items-center"> 36 + <p class="text-gray-600"> 37 + <a href="/{{ $userHandle }}" class="no-underline hover:underline">{{ $userHandle }}</a> 38 + followed 39 + <a href="/{{ $subjectHandle }}" class="no-underline hover:underline">{{ $subjectHandle }}</a> 40 + <time class="text-gray-700">{{ .Follow.FollowedAt | timeFmt }}</time> 41 + </p> 42 + </div> 35 43 {{ end }} 44 + </div> 36 45 {{ end }} 37 46 38 47 {{ end }}
+1 -1
appview/pages/templates/user/profile.html
··· 24 24 <div class="text-sm mb-4"> 25 25 <span>{{ .ProfileStats.Followers }} followers</span> 26 26 <div class="inline-block px-1 select-none after:content-['·']"></div> 27 - <span>following {{ .ProfileStats.Following }}</span> 27 + <span>{{ .ProfileStats.Following }} following</span> 28 28 </div> 29 29 <p class="text-xs font-bold py-2">REPOS</p> 30 30 <div id="repos" class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
+22
appview/state/state.go
··· 165 165 s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") 166 166 } 167 167 168 + var didsToResolve []string 169 + for _, ev := range timeline { 170 + if ev.Repo != nil { 171 + didsToResolve = append(didsToResolve, ev.Repo.Did) 172 + } 173 + if ev.Follow != nil { 174 + didsToResolve = append(didsToResolve, ev.Follow.UserDid) 175 + didsToResolve = append(didsToResolve, ev.Follow.SubjectDid) 176 + } 177 + } 178 + 179 + resolvedIds := s.resolver.ResolveIdents(r.Context(), didsToResolve) 180 + didHandleMap := make(map[string]string) 181 + for _, identity := range resolvedIds { 182 + if !identity.Handle.IsInvalidHandle() { 183 + didHandleMap[identity.DID.String()] = fmt.Sprintf("@%s", identity.Handle.String()) 184 + } else { 185 + didHandleMap[identity.DID.String()] = identity.DID.String() 186 + } 187 + } 188 + 168 189 s.pages.Timeline(w, pages.TimelineParams{ 169 190 LoggedInUser: user, 170 191 Timeline: timeline, 192 + DidHandleMap: didHandleMap, 171 193 }) 172 194 173 195 return