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/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

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

Use the rodent emblem as the logo and the favicon

6416cab19d8c205d4ed643399f9a78596f5a31ca · Keenan Nemetz · 13d ago · parent 13cff33f

Use the rodent emblem as the logo and the favicon

The header carried a letter in an accent chip and the favicon was a separate "v"
glyph, so the forge had two marks that could drift apart. They are now one piece of
artwork, served from the binary like every other static asset: a dark rounded tile
with a white rodent face, named by the shell as both the icons and the header mark.

The source drawing is a tile on a white page. Only the page is removed — a fuzz
flood fill from the corner, which leaves the face opaque because the tile encloses
it — so the mark has transparent corners and reads on either theme without a second
set of assets. Sizes are 128 for the header (22 CSS px, so it survives a high-DPI
screen), 32 and 16 for the tab, each square and centred because a favicon that is
31 pixels tall is a favicon some browser will letterbox.

favicon.svg is removed; nothing else referenced it. A test now asserts that the
three files are served as PNG and that the shell names them, so the next rename
cannot leave every page pointing at a missing icon.

server/ui_test.go +50

@@ -4,6 +4,8 @@ package server_test
4 4 // normal page must all come back as Vole HTML, not as a bare Go error string.
5 5
6 6 import (
7 "io"
8 "net/http"
7 9 "strings"
8 10 "testing"
9 11 "time"
@@ -84,6 +86,54 @@ func TestStaticAssetsAreServedFromTheBinary(t *testing.T) {
84 86 }
85 87 }
86 88
89 // TestTheEmblemShipsAndTheShellNamesIt: the mark and the favicon are one file,
90 // so a page that points at a name nobody ships is a broken tab icon on every
91 // page. This is the test that would have caught the rename.
92 func TestTheEmblemShipsAndTheShellNamesIt(t *testing.T) {
93 t.Parallel()
94 f := newFixture(t)
95
96 for _, name := range []string{"logo.png", "favicon-32.png", "favicon-16.png"} {
97 resp, err := http.Get(f.http.URL + "/static/" + name)
98 if err != nil {
99 t.Fatal(err)
100 }
101 if resp.StatusCode != http.StatusOK {
102 resp.Body.Close()
103 t.Fatalf("/static/%s = %d", name, resp.StatusCode)
104 }
105 if ct := resp.Header.Get("Content-Type"); !strings.Contains(ct, "png") {
106 resp.Body.Close()
107 t.Fatalf("%s Content-Type = %q", name, ct)
108 }
109 head := make([]byte, 8)
110 if _, err := io.ReadFull(resp.Body, head); err != nil {
111 resp.Body.Close()
112 t.Fatal(err)
113 }
114 resp.Body.Close()
115 if string(head) != "\x89PNG\r\n\x1a\n" {
116 t.Errorf("%s is not a PNG: %x", name, head)
117 }
118 }
119
120 code, shell := f.get("/")
121 if code != http.StatusOK {
122 t.Fatalf("landing page = %d", code)
123 }
124 if !strings.Contains(shell, `href="/static/favicon-32.png"`) {
125 t.Error("the shell does not name the emblem as its icon")
126 }
127 if !strings.Contains(shell, `src="/static/logo.png"`) {
128 t.Error("the header does not use the emblem")
129 }
130 for _, gone := range []string{"logo.svg", "favicon.svg"} {
131 if strings.Contains(shell, gone) {
132 t.Errorf("the shell still points at the removed %s", gone)
133 }
134 }
135 }
136
87 137 // The celebration library is a static asset like any other, but it is not in the
88 138 // shell: the shell would make every page load fetch it. app.js names it, and names
89 139 // it once, so the only request is the one a landing asks for.