Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Remove the avatars and read people by name again

28b19c7433fa6f6fe1ce826c443870385d856eb8 · Keenan Nemetz · 8d ago · parent 0fbeca85

Remove the avatars and read people by name again

The marks were harder to read than the names they replaced, so they are
gone: the account menu is back to the user icon, and the issue and
change tables, the profile, the directory and the contributor list all
say the account name.

This takes out everything that existed to draw a mark: the DiceBear
bundle and its licence file, the entry source that built it, the
Landscape style, avatar.go and its tests, the avatar template and its
three helper functions, the avatar palette in everforest.css and the
illustration rules in vole.css, and the app.js block that rendered and
re-rendered them on a theme change.

The tables keep the layout from the previous change — an author column
and an assignee column — because that part reads better with names too.
The assignee cells are the @name chips that already linked to the
filtered list.

`vole workflow run verify` passes, and the licence inventory is back to
one entry fewer.

server/web/avatar.go −83

@@ -1,83 +0,0 @@
1 package web
2
3 // A name's avatar.
4 //
5 // The mark itself is drawn in the browser by DiceBear from a seed, so this file
6 // decides only the ground and the fallback. Two things follow from that split,
7 // and both are deliberate:
8 //
9 // - The server renders the account's initial on one of seven Everforest grounds,
10 // exactly as every avatar looked before the marks existed. A browser without
11 // scripts, or one that has not run the bundle yet, shows a letter rather than
12 // an empty tile. The avatar is decoration; nothing about the page depends on
13 // it arriving.
14 // - The seed is the name, never an index or a session. The same account draws
15 // the same mark on every page and between visits, and the instance stores no
16 // image, accepts no upload, and calls no avatar service. The bundle is
17 // embedded in the binary like every other asset, so choosing an avatar makes
18 // no request anywhere.
19 //
20 // The tone is derived here rather than in the sheet so a letter keeps its ground
21 // even when the stylesheet has not loaded; vole.css names the same seven colours.
22 // The mark is decoration, not an identifier: a name is what identifies an account.
23
24 import (
25 "crypto/sha256"
26 "strings"
27 )
28
29 // avatarView is one avatar ready to render. Href is empty for a name that is not
30 // an account; the template then draws a span instead of a link.
31 type avatarView struct {
32 // Name is the seed, rendered as an attribute so the browser can draw the mark.
33 Name string
34 Tone int
35 // Initial is the fallback letter, shown until the mark is drawn.
36 Initial string
37 Href string
38 // Label is set when the avatar is the only content of its element, as in a
39 // table cell. It is decoration beside a printed name, but it is the name
40 // there, so it has to say so to a screen reader.
41 Label string
42 }
43
44 // avatar is the avatar for a name, on its own.
45 func (w *Web) avatar(name string) avatarView { return portrait(name) }
46
47 // avatarUser is the avatar for an account, linked to the profile it belongs to
48 // when the name resolves to one.
49 func (w *Web) avatarUser(ref userRef) avatarView {
50 v := portrait(ref.Name)
51 v.Href = ref.Href
52 return v
53 }
54
55 // avatarOnly is avatarUser for a place where the picture is the whole content,
56 // such as an author cell in a table. It carries the name for a screen reader
57 // instead of hiding itself the way a decorative avatar does.
58 func (w *Web) avatarOnly(ref userRef) avatarView {
59 v := w.avatarUser(ref)
60 v.Label = ref.Name
61 return v
62 }
63
64 // portrait derives the ground and the fallback letter from the name. SHA-256
65 // rather than a cheap hash so two similar names do not land on the same tone by
66 // construction; the mark's own variation comes from the bundle's seeded PRNG.
67 func portrait(name string) avatarView {
68 sum := sha256.Sum256([]byte(name))
69 return avatarView{
70 Name: name,
71 Tone: int(sum[8]%7) + 1,
72 Initial: initial(name),
73 }
74 }
75
76 // initial is the fallback letter. Account names are authoritative, so the first
77 // rune is enough; an empty name gets "?" rather than an empty tile.
78 func initial(name string) string {
79 for _, r := range strings.TrimSpace(name) {
80 return strings.ToUpper(string(r))
81 }
82 return "?"
83 }