Signed-off-by: oppiliappan me@oppi.li
+124
-31
Diff
round #0
+6
-5
appview/pages/pages.go
+6
-5
appview/pages/pages.go
···
402
402
}
403
403
404
404
type TimelineParams struct {
405
-
LoggedInUser *oauth.MultiAccountUser
406
-
Timeline []models.TimelineEvent
407
-
Repos []models.Repo
408
-
GfiLabel *models.LabelDefinition
409
-
BlueskyPosts []models.BskyPost
405
+
LoggedInUser *oauth.MultiAccountUser
406
+
Timeline []models.TimelineEvent
407
+
Repos []models.Repo
408
+
GfiLabel *models.LabelDefinition
409
+
BlueskyPosts []models.BskyPost
410
+
VouchSuggestions []models.VouchSuggestion
410
411
// ShowNewsletter controls whether the newsletter widget/CTA is rendered.
411
412
// For logged-in users it reflects their newsletter_preferences row; for
412
413
// anonymous visitors it is always true (dismissal falls back to
+39
appview/pages/templates/timeline/fragments/announcements.html
+39
appview/pages/templates/timeline/fragments/announcements.html
···
1
+
{{ define "timeline/fragments/announcements" }}
2
+
<div>
3
+
<h3 class="text-xl font-bold dark:text-white hidden md:flex items-center gap-4 px-4 pb-4">
4
+
{{ i "megaphone" "size-5 flex-shrink-0" }}
5
+
Announcements
6
+
</h3>
7
+
<div class="flex flex-col gap-3">
8
+
{{ template "vouchAnnouncement" . }}
9
+
</div>
10
+
</div>
11
+
{{ end }}
12
+
13
+
{{ define "vouchAnnouncement" }}
14
+
<div class="relative overflow-hidden border border-teal-300 dark:border-teal-600 bg-gradient-to-b from-teal-50 to-teal-100 dark:from-teal-900 dark:to-teal-800 rounded-sm p-6">
15
+
<div class="relative z-10">
16
+
<p class="font-semibold text-teal-800 dark:text-teal-300 mb-1">Build a web of trust</p>
17
+
<p class="text-teal-700 dark:text-teal-400">
18
+
Vouch for trustworthy users that make open-source a better place. Visit a user's
19
+
profile to vouch for them.
20
+
</p>
21
+
22
+
<div class="mt-3 flex items-center justify-between">
23
+
<a class="mt-3 no-underline inline-flex items-center gap-1 text-sm font-medium text-teal-700 dark:text-teal-300 hover:text-teal-900 dark:hover:text-teal-100 hover:underline" href="/vouching">
24
+
Read more
25
+
</a>
26
+
{{ if and .LoggedInUser .VouchSuggestions }}
27
+
<a class="md:hidden mt-3 no-underline inline-flex items-center gap-1 text-sm font-medium text-teal-700 dark:text-teal-300 hover:text-teal-900 dark:hover:text-teal-100 hover:underline" href="/{{ .LoggedInUser.Did }}?tab=vouches">
28
+
View suggestions {{ i "arrow-right" "size-3.5" }}
29
+
</a>
30
+
{{ end }}
31
+
</div>
32
+
33
+
</div>
34
+
35
+
<div class="pointer-events-none absolute -bottom-8 -right-16 text-teal-200 dark:text-teal-700 opacity-60">
36
+
{{ i "shield-plus" "size-48" }}
37
+
</div>
38
+
</div>
39
+
{{ end }}
+4
-3
appview/pages/templates/timeline/fragments/timeline.html
+4
-3
appview/pages/templates/timeline/fragments/timeline.html
···
1
1
{{ define "timeline/fragments/timeline" }}
2
2
<div class="py-4">
3
-
<div class="px-6 pb-4">
4
-
<p class="text-xl font-bold dark:text-white">Timeline</p>
5
-
</div>
3
+
<h3 class="text-xl font-bold dark:text-white flex items-center gap-4 px-4 pb-4">
4
+
{{ i "gallery-vertical" "size-5 flex-shrink-0" }}
5
+
Timeline
6
+
</h3>
6
7
7
8
<div class="flex flex-col gap-4">
8
9
{{ range $i, $e := .Timeline }}
+12
-12
appview/pages/templates/timeline/fragments/trending.html
+12
-12
appview/pages/templates/timeline/fragments/trending.html
···
1
1
{{ define "timeline/fragments/trending" }}
2
-
<div class="pt-4">
3
-
<h3 class="text-xl font-bold dark:text-white flex items-center gap-2 px-6 pb-4">
4
-
Trending
5
-
{{ i "trending-up" "size-4 flex-shrink-0" }}
2
+
<div>
3
+
<h3 class="text-xl font-bold dark:text-white flex items-center gap-4 px-4 pb-4">
4
+
{{ i "trending-up" "size-5 flex-shrink-0" }}
5
+
Trending
6
6
</h3>
7
7
{{ if .Repos }}
8
-
<div class="flex gap-4 overflow-x-auto scrollbar-hide items-stretch lg:flex-col lg:overflow-x-visible">
9
-
{{ range $index, $repo := .Repos }}
10
-
<div class="flex-none w-96 border border-gray-200 dark:border-gray-700 rounded-sm lg:flex-none lg:w-auto">
11
-
{{ template "user/fragments/repoCard" (list $ $repo true) }}
12
-
</div>
13
-
{{ end }}
8
+
<div class="flex gap-4 overflow-x-auto scrollbar-hide items-stretch md:flex-col md:overflow-x-visible">
9
+
{{ range $index, $repo := .Repos }}
10
+
<div class="flex-none w-96 border border-gray-200 dark:border-gray-700 rounded-sm md:flex-none md:w-auto">
11
+
{{ template "user/fragments/repoCard" (list $ $repo true) }}
12
+
</div>
13
+
{{ end }}
14
14
</div>
15
15
{{ else }}
16
16
<div class="p-6 border border-gray-200 dark:border-gray-700 rounded-sm text-sm text-gray-500 dark:text-gray-400 text-center">
17
-
No trending repositories this week
17
+
No trending repositories this week
18
18
</div>
19
19
{{ end }}
20
-
</div>
20
+
</div>
21
21
{{ end }}
+24
appview/pages/templates/timeline/fragments/vouchSuggestions.html
+24
appview/pages/templates/timeline/fragments/vouchSuggestions.html
···
1
+
{{ define "timeline/fragments/vouchSuggestions" }}
2
+
{{ if and .LoggedInUser .VouchSuggestions }}
3
+
<div>
4
+
<h3 class="text-xl font-bold dark:text-white flex items-center gap-4 px-4 pb-4">
5
+
{{ i "shield-plus" "size-5 flex-shrink-0" }}
6
+
Suggested
7
+
</h3>
8
+
<div class="flex flex-col gap-4 bg-white dark:bg-gray-800 p-4 border border-gray-200 dark:border-gray-700 shadow-sm">
9
+
{{ range .VouchSuggestions }}
10
+
<div class="flex items-center gap-3 ">
11
+
{{ template "user/fragments/picLink" (list .Did "size-10") }}
12
+
<div class="flex flex-col min-w-0 flex-1">
13
+
<a href="/{{ resolve .Did }}" class="text-sm font-medium dark:text-white hover:underline truncate">{{ resolve .Did }}</a>
14
+
<span class="text-xs text-gray-500 dark:text-gray-400 truncate" title="{{ .Reason }}">{{ .Reason }}</span>
15
+
</div>
16
+
<div class="shrink-0">
17
+
{{ template "user/fragments/vouch" . }}
18
+
</div>
19
+
</div>
20
+
{{ end }}
21
+
</div>
22
+
</div>
23
+
{{ end }}
24
+
{{ end }}
+8
-4
appview/pages/templates/timeline/timeline.html
+8
-4
appview/pages/templates/timeline/timeline.html
···
16
16
{{ end }}
17
17
18
18
{{ define "content" }}
19
-
<div id="timeline-grid" class="flex flex-col gap-4 lg:grid lg:grid-cols-3">
19
+
<div id="timeline-grid" class="flex flex-col gap-4 md:grid md:grid-cols-3">
20
20
21
-
<div class="order-2 lg:order-none lg:col-span-2 lg:row-start-1">
21
+
<div class="order-3 md:order-none md:col-span-2 md:row-start-1">
22
22
{{ template "timeline/fragments/timeline" . }}
23
23
</div>
24
24
25
-
<div class="order-1 lg:order-none flex flex-col gap-6 lg:col-start-3 lg:row-start-1">
25
+
<div class="order-1 md:order-none flex flex-col gap-6 md:col-start-3 md:row-start-1 md:pt-4">
26
26
{{ if .ShowNewsletter }}
27
-
<div id="newsletter-col" class="order-first lg:order-last">
27
+
<div id="newsletter-col" class="order-first md:order-last">
28
28
{{ template "timeline/fragments/newsletterWidget" . }}
29
29
</div>
30
30
{{ end }}
31
+
{{ template "timeline/fragments/announcements" . }}
32
+
<div class="hidden md:block">
33
+
{{ template "timeline/fragments/vouchSuggestions" . }}
34
+
</div>
31
35
{{ template "timeline/fragments/trending" . }}
32
36
</div>
33
37
</div>
+2
-2
appview/pages/templates/user/fragments/vouchPopover.html
+2
-2
appview/pages/templates/user/fragments/vouchPopover.html
···
32
32
class="flex flex-col gap-6 group">
33
33
34
34
<div>
35
-
<h3 class="text-lg font-semibold">Vouch for {{ $userIdent }}</h3>
36
-
<p class="text-gray-700 dark:text-gray-300">
35
+
<p class="font-semibold mb-1 text-base">Vouch for {{ $userIdent }}</p>
36
+
<p class="text-gray-600 dark:text-gray-400 text-sm">
37
37
{{ with .VouchRelationship }}
38
38
{{ with .GetDirectVouch }}
39
39
You {{if $isVouched}}vouched{{else}}denounced{{end}} {{ $userIdent }} {{ relTimeFmt .CreatedAt }}.
+29
-5
appview/state/timeline.go
+29
-5
appview/state/timeline.go
···
4
4
"net/http"
5
5
6
6
"tangled.org/core/appview/db"
7
+
"tangled.org/core/appview/models"
7
8
"tangled.org/core/appview/oauth"
8
9
"tangled.org/core/appview/pages"
9
10
"tangled.org/core/orm"
···
70
71
// non-fatal
71
72
}
72
73
74
+
var vouchSuggestions []models.VouchSuggestion
75
+
if user != nil {
76
+
vouchSuggestions, err = db.GetVouchSuggestions(s.db, user.Did, 3)
77
+
if err != nil {
78
+
s.logger.Error("failed to get vouch suggestions", "err", err)
79
+
}
80
+
if len(vouchSuggestions) > 0 {
81
+
suggestionDids := make([]string, len(vouchSuggestions))
82
+
for i, sv := range vouchSuggestions {
83
+
suggestionDids[i] = sv.Did
84
+
}
85
+
relationships, err := db.GetVouchRelationshipsBatch(s.db, user.Did, suggestionDids)
86
+
if err != nil {
87
+
s.logger.Error("failed to get vouch relationships for suggestions", "err", err)
88
+
} else {
89
+
for i := range vouchSuggestions {
90
+
vouchSuggestions[i].VouchRelationship = relationships[vouchSuggestions[i].Did]
91
+
}
92
+
}
93
+
}
94
+
}
95
+
73
96
s.pages.Timeline(w, pages.TimelineParams{
74
-
LoggedInUser: user,
75
-
Timeline: timeline,
76
-
Repos: repos,
77
-
GfiLabel: gfiLabel,
78
-
ShowNewsletter: s.showNewsletter(user),
97
+
LoggedInUser: user,
98
+
Timeline: timeline,
99
+
Repos: repos,
100
+
GfiLabel: gfiLabel,
101
+
VouchSuggestions: vouchSuggestions,
102
+
ShowNewsletter: s.showNewsletter(user),
79
103
})
80
104
}
81
105