+22
appview/pages/funcmap.go
+22
appview/pages/funcmap.go
···
360
360
"fullAvatar": func(handle string) string {
361
361
return p.AvatarUrl(handle, "")
362
362
},
363
+
"placeholderAvatar": func(size string) template.HTML {
364
+
sizeClass := "size-6"
365
+
iconSize := "size-4"
366
+
if size == "tiny" {
367
+
sizeClass = "size-6"
368
+
iconSize = "size-4"
369
+
} else if size == "small" {
370
+
sizeClass = "size-8"
371
+
iconSize = "size-5"
372
+
} else {
373
+
sizeClass = "size-12"
374
+
iconSize = "size-8"
375
+
}
376
+
icon, _ := p.icon("user-round", []string{iconSize, "text-gray-400", "dark:text-gray-500"})
377
+
return template.HTML(fmt.Sprintf(`<div class="%s rounded-full bg-gray-200 dark:bg-gray-700 flex items-center justify-center flex-shrink-0">%s</div>`, sizeClass, icon))
378
+
},
379
+
"profileAvatarUrl": func(profile *models.Profile, size string) string {
380
+
if profile != nil {
381
+
return p.AvatarUrl(profile.Did, size)
382
+
}
383
+
return ""
384
+
},
363
385
"langColor": enry.GetColor,
364
386
"layoutSide": func() string {
365
387
return "col-span-1 md:col-span-2 lg:col-span-3"
+1
-1
appview/pages/templates/layouts/profilebase.html
+1
-1
appview/pages/templates/layouts/profilebase.html
···
2
2
3
3
{{ define "extrameta" }}
4
4
{{ $handle := resolve .Card.UserDid }}
5
-
{{ $avatarUrl := fullAvatar $handle }}
5
+
{{ $avatarUrl := profileAvatarUrl .Card.Profile "" }}
6
6
<meta property="og:title" content="{{ $handle }}" />
7
7
<meta property="og:type" content="profile" />
8
8
<meta property="og:url" content="https://tangled.org/{{ $handle }}?tab={{ .Active }}" />
+44
appview/pages/templates/user/fragments/editAvatar.html
+44
appview/pages/templates/user/fragments/editAvatar.html
···
1
+
{{ define "user/fragments/editAvatar" }}
2
+
<form
3
+
hx-post="/profile/avatar"
4
+
hx-encoding="multipart/form-data"
5
+
hx-indicator="#spinner"
6
+
hx-swap="none"
7
+
class="flex flex-col gap-2">
8
+
<label for="avatar-file" class="uppercase p-0">
9
+
Upload avatar
10
+
</label>
11
+
<p class="text-sm text-gray-500 dark:text-gray-400">Select an image (PNG or JPEG, max 1MB)</p>
12
+
<input
13
+
type="file"
14
+
id="avatar-file"
15
+
name="avatar"
16
+
accept="image/png,image/jpeg"
17
+
required
18
+
class="block w-full text-sm text-gray-500 dark:text-gray-400
19
+
file:mr-4 file:py-2 file:px-4
20
+
file:rounded file:border-0
21
+
file:text-sm file:font-semibold
22
+
file:bg-gray-100 file:text-gray-700
23
+
dark:file:bg-gray-700 dark:file:text-gray-300
24
+
hover:file:bg-gray-200 dark:hover:file:bg-gray-600" />
25
+
<div class="flex gap-2 pt-2">
26
+
<button
27
+
id="cancel-avatar-btn"
28
+
type="button"
29
+
popovertarget="avatar-upload-modal"
30
+
popovertargetaction="hide"
31
+
class="btn w-1/2 flex items-center gap-2 text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300">
32
+
{{ i "x" "size-4" }}
33
+
cancel
34
+
</button>
35
+
<button type="submit" class="btn w-1/2 flex items-center">
36
+
<span class="inline-flex gap-2 items-center">{{ i "upload" "size-4" }} upload</span>
37
+
<span id="spinner" class="group">
38
+
{{ i "loader-circle" "ml-2 w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
39
+
</span>
40
+
</button>
41
+
</div>
42
+
<div id="avatar-error" class="text-red-500 dark:text-red-400"></div>
43
+
</form>
44
+
{{ end }}
+17
-3
appview/pages/templates/user/fragments/profileCard.html
+17
-3
appview/pages/templates/user/fragments/profileCard.html
···
3
3
<div class="grid grid-cols-3 md:grid-cols-1 gap-1 items-center">
4
4
<div id="avatar" class="col-span-1 flex justify-center items-center">
5
5
<div class="w-3/4 aspect-square relative">
6
-
<img class="absolute inset-0 w-full h-full object-cover rounded-full p-2" src="{{ fullAvatar .UserDid }}" />
6
+
<img class="absolute inset-0 w-full h-full object-cover rounded-full p-2" src="{{ profileAvatarUrl .Profile "" }}" />
7
+
{{ if eq .FollowStatus.String "IsSelf" }}
8
+
<button
9
+
class="absolute bottom-2 right-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-full p-2 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
10
+
popovertarget="avatar-upload-modal"
11
+
popovertargetaction="toggle"
12
+
title="Upload avatar">
13
+
{{ i "camera" "w-4 h-4" }}
14
+
</button>
15
+
{{ end }}
7
16
</div>
17
+
</div>
18
+
<div
19
+
id="avatar-upload-modal"
20
+
popover
21
+
class="bg-white w-full md:w-96 dark:bg-gray-800 p-4 rounded border border-gray-200 dark:border-gray-700 drop-shadow dark:text-white backdrop:bg-gray-400/50 dark:backdrop:bg-gray-800/50">
22
+
{{ template "user/fragments/editAvatar" . }}
8
23
</div>
9
24
<div class="col-span-2">
10
25
<div class="flex items-center flex-row flex-nowrap gap-2">
···
36
51
{{ block "followerFollowing" (list $ $userIdent) }} {{ end }}
37
52
</div>
38
53
39
-
<div class="flex flex-col gap-2 mb-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full">
54
+
<div class="flex flex-col gap-2 mb-2 overflow-hidden text-ellipsis whitespace-nowrap max-w-full">
40
55
{{ if .Location }}
41
56
<div class="flex items-center gap-2">
42
57
<span class="flex-shrink-0">{{ i "map-pin" "size-4" }}</span>
···
111
126
</div>
112
127
{{ end }}
113
128
{{ end }}
114
-
+4
-2
appview/pages/templates/user/settings/emails.html
+4
-2
appview/pages/templates/user/settings/emails.html
···
62
62
hx-swap="none"
63
63
class="flex flex-col gap-2"
64
64
>
65
-
<p class="uppercase p-0">ADD EMAIL</p>
65
+
<label for="email-address" class="uppercase p-0">
66
+
add email
67
+
</label>
66
68
<p class="text-sm text-gray-500 dark:text-gray-400">Commits using this email will be associated with your profile.</p>
67
69
<input
68
70
type="email"
···
91
93
<div id="settings-emails-error" class="text-red-500 dark:text-red-400"></div>
92
94
<div id="settings-emails-success" class="text-green-500 dark:text-green-400"></div>
93
95
</form>
94
-
{{ end }}
96
+
{{ end }}
+4
-2
appview/pages/templates/user/settings/keys.html
+4
-2
appview/pages/templates/user/settings/keys.html
···
21
21
<div class="col-span-1 md:col-span-2">
22
22
<h2 class="text-sm pb-2 uppercase font-bold">SSH Keys</h2>
23
23
<p class="text-gray-500 dark:text-gray-400">
24
-
SSH public keys added here will be broadcasted to knots that you are a member of,
24
+
SSH public keys added here will be broadcasted to knots that you are a member of,
25
25
allowing you to push to repositories there.
26
26
</p>
27
27
</div>
···
63
63
hx-swap="none"
64
64
class="flex flex-col gap-2"
65
65
>
66
-
<p class="uppercase p-0">ADD SSH KEY</p>
66
+
<label for="key-name" class="uppercase p-0">
67
+
add ssh key
68
+
</label>
67
69
<p class="text-sm text-gray-500 dark:text-gray-400">SSH keys allow you to push to repositories in knots you're a member of.</p>
68
70
<input
69
71
type="text"