forked from tangled.org/core
Monorepo for Tangled

clean up timeline

Changed files
+89 -51
appview
+5 -5
appview/db/follow.go
··· 8 type Follow struct { 9 UserDid string 10 SubjectDid string 11 - FollowedAt *time.Time 12 RKey string 13 } 14 ··· 33 followedAtTime, err := time.Parse(time.RFC3339, followedAt) 34 if err != nil { 35 log.Println("unable to determine followed at time") 36 - follow.FollowedAt = nil 37 } else { 38 - follow.FollowedAt = &followedAtTime 39 } 40 41 return &follow, nil ··· 110 followedAtTime, err := time.Parse(time.RFC3339, followedAt) 111 if err != nil { 112 log.Println("unable to determine followed at time") 113 - follow.FollowedAt = nil 114 } else { 115 - follow.FollowedAt = &followedAtTime 116 } 117 118 follows = append(follows, follow)
··· 8 type Follow struct { 9 UserDid string 10 SubjectDid string 11 + FollowedAt time.Time 12 RKey string 13 } 14 ··· 33 followedAtTime, err := time.Parse(time.RFC3339, followedAt) 34 if err != nil { 35 log.Println("unable to determine followed at time") 36 + follow.FollowedAt = time.Now() 37 } else { 38 + follow.FollowedAt = followedAtTime 39 } 40 41 return &follow, nil ··· 110 followedAtTime, err := time.Parse(time.RFC3339, followedAt) 111 if err != nil { 112 log.Println("unable to determine followed at time") 113 + follow.FollowedAt = time.Now() 114 } else { 115 + follow.FollowedAt = followedAtTime 116 } 117 118 follows = append(follows, follow)
+9 -10
appview/db/repos.go
··· 10 Name string 11 Knot string 12 Rkey string 13 - Created *time.Time 14 } 15 16 func (d *DB) GetAllRepos() ([]Repo, error) { 17 var repos []Repo 18 19 - rows, err := d.db.Query(`select * from repos`) 20 if err != nil { 21 return nil, err 22 } ··· 24 25 for rows.Next() { 26 var repo Repo 27 - err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, repo.Created) 28 if err != nil { 29 return nil, err 30 } ··· 41 func (d *DB) GetAllReposByDid(did string) ([]Repo, error) { 42 var repos []Repo 43 44 - rows, err := d.db.Query(`select did, name, knot, created from repos where did = ?`, did) 45 if err != nil { 46 return nil, err 47 } ··· 49 50 for rows.Next() { 51 var repo Repo 52 - err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, repo.Created) 53 if err != nil { 54 return nil, err 55 } ··· 73 return nil, err 74 } 75 createdAtTime, _ := time.Parse(time.RFC3339, createdAt) 76 - repo.Created = &createdAtTime 77 78 return &repo, nil 79 } ··· 107 108 for rows.Next() { 109 var repo Repo 110 - err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, repo.Created) 111 if err != nil { 112 return nil, err 113 } ··· 129 130 createdAtTime, err := time.Parse(time.RFC3339, createdAt) 131 if err != nil { 132 - now := time.Now() 133 - created = &now 134 } else { 135 - created = &createdAtTime 136 } 137 138 return nil
··· 10 Name string 11 Knot string 12 Rkey string 13 + Created time.Time 14 } 15 16 func (d *DB) GetAllRepos() ([]Repo, error) { 17 var repos []Repo 18 19 + rows, err := d.db.Query(`select did, name, knot, rkey, created from repos`) 20 if err != nil { 21 return nil, err 22 } ··· 24 25 for rows.Next() { 26 var repo Repo 27 + err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Created) 28 if err != nil { 29 return nil, err 30 } ··· 41 func (d *DB) GetAllReposByDid(did string) ([]Repo, error) { 42 var repos []Repo 43 44 + rows, err := d.db.Query(`select did, name, knot, rkey, created from repos where did = ?`, did) 45 if err != nil { 46 return nil, err 47 } ··· 49 50 for rows.Next() { 51 var repo Repo 52 + err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Created) 53 if err != nil { 54 return nil, err 55 } ··· 73 return nil, err 74 } 75 createdAtTime, _ := time.Parse(time.RFC3339, createdAt) 76 + repo.Created = createdAtTime 77 78 return &repo, nil 79 } ··· 107 108 for rows.Next() { 109 var repo Repo 110 + err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Created) 111 if err != nil { 112 return nil, err 113 } ··· 129 130 createdAtTime, err := time.Parse(time.RFC3339, createdAt) 131 if err != nil { 132 + *created = time.Now() 133 } else { 134 + *created = createdAtTime 135 } 136 137 return nil
+4 -2
appview/db/timeline.go
··· 1 package db 2 3 import ( 4 "sort" 5 "time" 6 ) ··· 8 type TimelineEvent struct { 9 *Repo 10 *Follow 11 - EventAt *time.Time 12 } 13 14 func (d *DB) MakeTimeline() ([]TimelineEvent, error) { ··· 25 } 26 27 for _, repo := range repos { 28 events = append(events, TimelineEvent{ 29 Repo: &repo, 30 Follow: nil, ··· 41 } 42 43 sort.Slice(events, func(i, j int) bool { 44 - return events[i].EventAt.After(*events[j].EventAt) 45 }) 46 47 return events, nil
··· 1 package db 2 3 import ( 4 + "log" 5 "sort" 6 "time" 7 ) ··· 9 type TimelineEvent struct { 10 *Repo 11 *Follow 12 + EventAt time.Time 13 } 14 15 func (d *DB) MakeTimeline() ([]TimelineEvent, error) { ··· 26 } 27 28 for _, repo := range repos { 29 + log.Println(repo.Created) 30 events = append(events, TimelineEvent{ 31 Repo: &repo, 32 Follow: nil, ··· 43 } 44 45 sort.Slice(events, func(i, j int) bool { 46 + return events[i].EventAt.After(events[j].EventAt) 47 }) 48 49 return events, nil
+1
appview/pages/pages.go
··· 176 type TimelineParams struct { 177 LoggedInUser *auth.User 178 Timeline []db.TimelineEvent 179 } 180 181 func (p *Pages) Timeline(w io.Writer, params TimelineParams) error {
··· 176 type TimelineParams struct { 177 LoggedInUser *auth.User 178 Timeline []db.TimelineEvent 179 + DidHandleMap map[string]string 180 } 181 182 func (p *Pages) Timeline(w io.Writer, params TimelineParams) error {
+12 -7
appview/pages/templates/layouts/topbar.html
··· 13 <a href="/repo/new" hx-boost="true" class="{{ $linkstyle }}"> 14 <i class="w-6 h-6" data-lucide="plus"></i> 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> 22 {{ else }} 23 - <a href="/login" hx-boost="true" class="{{ $linkstyle }}"> 24 login 25 </a> 26 {{ end }}
··· 13 <a href="/repo/new" hx-boost="true" class="{{ $linkstyle }}"> 14 <i class="w-6 h-6" data-lucide="plus"></i> 15 </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> 27 {{ else }} 28 + <a href="/login" class="{{ $linkstyle }}"> 29 login 30 </a> 31 {{ end }}
+35 -26
appview/pages/templates/timeline.html
··· 4 <h1>Timeline</h1> 5 6 {{ range .Timeline }} 7 {{ 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> 20 {{ 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> 35 {{ end }} 36 {{ end }} 37 38 {{ end }}
··· 4 <h1>Timeline</h1> 5 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 + "> 22 {{ if .Repo }} 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> 32 {{ else if .Follow }} 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> 43 {{ end }} 44 + </div> 45 {{ end }} 46 47 {{ end }}
+1 -1
appview/pages/templates/user/profile.html
··· 24 <div class="text-sm mb-4"> 25 <span>{{ .ProfileStats.Followers }} followers</span> 26 <div class="inline-block px-1 select-none after:content-['·']"></div> 27 - <span>following {{ .ProfileStats.Following }}</span> 28 </div> 29 <p class="text-xs font-bold py-2">REPOS</p> 30 <div id="repos" class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
··· 24 <div class="text-sm mb-4"> 25 <span>{{ .ProfileStats.Followers }} followers</span> 26 <div class="inline-block px-1 select-none after:content-['·']"></div> 27 + <span>{{ .ProfileStats.Following }} following</span> 28 </div> 29 <p class="text-xs font-bold py-2">REPOS</p> 30 <div id="repos" class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
+22
appview/state/state.go
··· 165 s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") 166 } 167 168 s.pages.Timeline(w, pages.TimelineParams{ 169 LoggedInUser: user, 170 Timeline: timeline, 171 }) 172 173 return
··· 165 s.pages.Notice(w, "timeline", "Uh oh! Failed to load timeline.") 166 } 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 + 189 s.pages.Timeline(w, pages.TimelineParams{ 190 LoggedInUser: user, 191 Timeline: timeline, 192 + DidHandleMap: didHandleMap, 193 }) 194 195 return