From ece60a35e6dae57a045362f30823fa93614742c0 Mon Sep 17 00:00:00 2001 From: dusk Date: Wed, 13 Aug 2025 06:38:27 +0300 Subject: [PATCH] appview: implement follower and following pages for users Change-Id: tlrutxlvkwovxvkutsnlykpyqtrprqso - rename Followers/Following from ProfileCard to FollowersCount/FollowingCount - in profileCard, define a single $userIdent to use instead of duplicating the didOrHandle expression fixes https://tangled.sh/@tangled.sh/core/issues/169 Signed-off-by: dusk --- appview/db/profile.go | 9 +- appview/db/timeline.go | 8 +- appview/pages/funcmap.go | 5 + appview/pages/pages.go | 38 ++++- appview/pages/templates/timeline.html | 6 +- appview/pages/templates/user/followers.html | 30 ++++ appview/pages/templates/user/following.html | 30 ++++ .../templates/user/fragments/follow.html | 4 +- .../templates/user/fragments/followCard.html | 29 ++++ .../templates/user/fragments/profileCard.html | 31 ++-- appview/state/profile.go | 158 ++++++++++++++++-- appview/state/router.go | 2 + appview/strings/strings.go | 14 +- 13 files changed, 308 insertions(+), 56 deletions(-) create mode 100644 appview/pages/templates/user/followers.html create mode 100644 appview/pages/templates/user/following.html create mode 100644 appview/pages/templates/user/fragments/followCard.html diff --git a/appview/db/profile.go b/appview/db/profile.go index 4d3a733..894d890 100644 --- a/appview/db/profile.go +++ b/appview/db/profile.go @@ -348,7 +348,7 @@ func UpsertProfile(tx *sql.Tx, profile *Profile) error { return tx.Commit() } -func GetProfiles(e Execer, filters ...filter) ([]Profile, error) { +func GetProfiles(e Execer, filters ...filter) (map[string]*Profile, error) { var conditions []string var args []any for _, filter := range filters { @@ -448,12 +448,7 @@ func GetProfiles(e Execer, filters ...filter) ([]Profile, error) { idxs[did] = idx + 1 } - var profiles []Profile - for _, p := range profileMap { - profiles = append(profiles, *p) - } - - return profiles, nil + return profileMap, nil } func GetProfile(e Execer, did string) (*Profile, error) { diff --git a/appview/db/timeline.go b/appview/db/timeline.go index 0354b81..8acbd93 100644 --- a/appview/db/timeline.go +++ b/appview/db/timeline.go @@ -151,14 +151,10 @@ func getTimelineFollows(e Execer) ([]TimelineEvent, error) { return nil, nil } - profileMap := make(map[string]Profile) profiles, err := GetProfiles(e, FilterIn("did", subjects)) if err != nil { return nil, err } - for _, p := range profiles { - profileMap[p.Did] = p - } followStatMap := make(map[string]FollowStats) for _, s := range subjects { @@ -174,12 +170,12 @@ func getTimelineFollows(e Execer) ([]TimelineEvent, error) { var events []TimelineEvent for _, f := range follows { - profile, _ := profileMap[f.SubjectDid] + profile, _ := profiles[f.SubjectDid] followStatMap, _ := followStatMap[f.SubjectDid] events = append(events, TimelineEvent{ Follow: &f, - Profile: &profile, + Profile: profile, FollowStats: &followStatMap, EventAt: f.FollowedAt, }) diff --git a/appview/pages/funcmap.go b/appview/pages/funcmap.go index a092666..e637a86 100644 --- a/appview/pages/funcmap.go +++ b/appview/pages/funcmap.go @@ -271,6 +271,11 @@ func (p *Pages) funcMap() template.FuncMap { "layoutCenter": func() string { return "col-span-1 md:col-span-8 lg:col-span-6" }, + + "normalizeForHtmlId": func(s string) string { + // TODO: extend this to handle other cases? + return strings.ReplaceAll(s, ":", "_") + }, } } diff --git a/appview/pages/pages.go b/appview/pages/pages.go index 6035c8d..9744e3e 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -411,11 +411,11 @@ type ProfilePageParams struct { } type ProfileCard struct { - UserDid string - UserHandle string - FollowStatus db.FollowStatus - Followers int - Following int + UserDid string + UserHandle string + FollowStatus db.FollowStatus + FollowersCount int + FollowingCount int Profile *db.Profile } @@ -434,6 +434,34 @@ func (p *Pages) ReposPage(w io.Writer, params ReposPageParams) error { return p.execute("user/repos", w, params) } +type FollowCard struct { + UserDid string + FollowStatus db.FollowStatus + FollowersCount int + FollowingCount int + Profile *db.Profile +} + +type FollowersPageParams struct { + LoggedInUser *oauth.User + Followers []FollowCard + Card ProfileCard +} + +func (p *Pages) FollowersPage(w io.Writer, params FollowersPageParams) error { + return p.execute("user/followers", w, params) +} + +type FollowingPageParams struct { + LoggedInUser *oauth.User + Following []FollowCard + Card ProfileCard +} + +func (p *Pages) FollowingPage(w io.Writer, params FollowingPageParams) error { + return p.execute("user/following", w, params) +} + type FollowFragmentParams struct { UserDid string FollowStatus db.FollowStatus diff --git a/appview/pages/templates/timeline.html b/appview/pages/templates/timeline.html index ada0409..19006aa 100644 --- a/appview/pages/templates/timeline.html +++ b/appview/pages/templates/timeline.html @@ -150,11 +150,11 @@ {{ end }} {{ end }} {{ with $stat }} -
+
{{ i "users" "size-4" }} - {{ .Followers }} followers + {{ .Followers }} followers - {{ .Following }} following + {{ .Following }} following
{{ end }}
diff --git a/appview/pages/templates/user/followers.html b/appview/pages/templates/user/followers.html new file mode 100644 index 0000000..fb3c943 --- /dev/null +++ b/appview/pages/templates/user/followers.html @@ -0,0 +1,30 @@ +{{ define "title" }}{{ or .Card.UserHandle .Card.UserDid }} · followers {{ end }} + +{{ define "extrameta" }} + + + + +{{ end }} + +{{ define "content" }} +
+
+ {{ template "user/fragments/profileCard" .Card }} +
+
+ {{ block "followers" . }}{{ end }} +
+
+{{ end }} + +{{ define "followers" }} +

ALL FOLLOWERS

+
+ {{ range .Followers }} + {{ template "user/fragments/followCard" . }} + {{ else }} +

This user does not have any followers yet.

+ {{ end }} +
+{{ end }} diff --git a/appview/pages/templates/user/following.html b/appview/pages/templates/user/following.html new file mode 100644 index 0000000..195f7ff --- /dev/null +++ b/appview/pages/templates/user/following.html @@ -0,0 +1,30 @@ +{{ define "title" }}{{ or .Card.UserHandle .Card.UserDid }} · following {{ end }} + +{{ define "extrameta" }} + + + + +{{ end }} + +{{ define "content" }} +
+
+ {{ template "user/fragments/profileCard" .Card }} +
+
+ {{ block "following" . }}{{ end }} +
+
+{{ end }} + +{{ define "following" }} +

ALL FOLLOWING

+
+ {{ range .Following }} + {{ template "user/fragments/followCard" . }} + {{ else }} +

This user does not follow anyone yet.

+ {{ end }} +
+{{ end }} diff --git a/appview/pages/templates/user/fragments/follow.html b/appview/pages/templates/user/fragments/follow.html index b5c65b4..23fd3cd 100644 --- a/appview/pages/templates/user/fragments/follow.html +++ b/appview/pages/templates/user/fragments/follow.html @@ -1,5 +1,5 @@ {{ define "user/fragments/follow" }} -