diff --git a/src/templates/mapping.go b/src/templates/mapping.go index 0794d544..7dc9c7f3 100644 --- a/src/templates/mapping.go +++ b/src/templates/mapping.go @@ -184,11 +184,12 @@ func ThreadToTemplate(t *models.Thread) Thread { } func UserAvatarDefaultUrl(theme string) string { + // TODO(redesign): Get rid of theme here return hmnurl.BuildTheme("empty-avatar.svg", theme, true) } func UserAvatarUrl(u *models.User) string { - avatar := "" + avatar := UserAvatarDefaultUrl("light") if u != nil && u.AvatarAsset != nil { avatar = hmnurl.BuildS3Asset(u.AvatarAsset.S3Key) } diff --git a/src/templates/src/project_edit.html b/src/templates/src/project_edit.html index 75d93d46..efa66302 100644 --- a/src/templates/src/project_edit.html +++ b/src/templates/src/project_edit.html @@ -145,18 +145,24 @@
{{ range .ProjectSettings.Owners }} -
+
- {{ .Username }} +
+ + {{ .Name }} +
{{ if (or $.User.IsStaff (ne .ID $.User.ID)) }} - {{ svg "close" }} + {{ svg "close" }} {{ end }}
{{ end }} @@ -267,11 +273,6 @@

- -
-
- Example User -
@@ -340,6 +341,7 @@ let ownerList = document.querySelector("#owner_list"); let ownerTemplate = makeTemplateCloner("owner_row"); let ownerPreviewTemplate = makeTemplateCloner("owner_preview"); + let ownersPreviewContainer = document.querySelector("#owners_preview"); addOwnerInput.addEventListener("keypress", function(ev) { if (ev.which == 13) { @@ -385,7 +387,7 @@ let result = xhr.response; if (result) { if (result.found) { - addOwner(result.canonical); + addOwner(result.username, result.name, result.avatarUrl); addOwnerInput.value = ""; } else { ownersError.textContent = "Username not found"; @@ -417,21 +419,41 @@ updateAddOwnerStyles(); } - function addOwner(username) { + function addOwner(username, bestName, avatarUrl) { let ownerEl = ownerTemplate(); ownerEl.input.value = username; - ownerEl.name.textContent = username; + ownerEl.name.textContent = bestName; + ownerEl.title = username; + ownerEl.avatar.src = avatarUrl; ownerList.appendChild(ownerEl.root); updateAddOwnerStyles(); + updateOwnersPreview(); } ownerList.addEventListener("click", function(ev) { - if (ev.target.classList.contains("remove_owner")) { - ev.target.parentElement.remove(); + if (ev.target.closest(".remove_owner")) { + ev.target.closest(".owner_row").remove(); } updateAddOwnerStyles(); + updateOwnersPreview(); }); + function updateOwnersPreview() { + let ownerEls = ownerList.querySelectorAll(".owner_row"); + ownersPreviewContainer.innerHTML = ""; + for (let i = 0; i < ownerEls.length; ++i) { + let avatarUrl = ownerEls[i].querySelector("img").src; + let name = ownerEls[i].querySelector("span").textContent; + let previewEl = ownerPreviewTemplate(); + previewEl.avatar.src = avatarUrl; + previewEl.name.textContent = name; + ownersPreviewContainer.appendChild(previewEl.root); + } + + } + + updateOwnersPreview(); + ////////////////////////////// // Logo / header management // ////////////////////////////// diff --git a/src/website/api.go b/src/website/api.go index 80645159..09bd3af9 100644 --- a/src/website/api.go +++ b/src/website/api.go @@ -8,50 +8,34 @@ import ( "strings" "git.handmade.network/hmn/hmn/src/db" + "git.handmade.network/hmn/hmn/src/hmndata" "git.handmade.network/hmn/hmn/src/models" "git.handmade.network/hmn/hmn/src/oops" + "git.handmade.network/hmn/hmn/src/templates" "git.handmade.network/hmn/hmn/src/utils" ) func APICheckUsername(c *RequestContext) ResponseData { c.Req.ParseForm() usernameArgs, hasUsername := c.Req.Form["username"] - found := false - canonicalUsername := "" + var user *models.User + var err error if hasUsername { requestedUsername := usernameArgs[0] - found = true - c.Perf.StartBlock("SQL", "Fetch user") - user, err := db.QueryOne[models.User](c, c.Conn, - ` - SELECT $columns - FROM - hmn_user - WHERE - LOWER(hmn_user.username) = LOWER($1) - AND status = ANY ($2) - `, - requestedUsername, - []models.UserStatus{models.UserStatusConfirmed, models.UserStatusApproved}, - ) - c.Perf.EndBlock() - if err != nil { - if errors.Is(err, db.NotFound) { - found = false - } else { - return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user: %s", requestedUsername)) - } - } else { - canonicalUsername = user.Username + user, err = hmndata.FetchUserByUsername(c, c.Conn, c.CurrentUser, requestedUsername, hmndata.UsersQuery{}) + if err != nil && !errors.Is(err, db.NotFound) { + return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user: %s", requestedUsername)) } } var res ResponseData addCORSHeaders(c, &res) - if found { + if user != nil { res.WriteJson(map[string]any{ "found": true, - "canonical": canonicalUsername, + "username": user.Username, + "name": user.BestName(), + "avatarUrl": templates.UserAvatarUrl(user), }, nil) } else { res.WriteJson(map[string]any{