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.

Derive theme metadata from the stylesheet file name

d222b0cf5d23444ea5df9429ec7d3690407dd00c · Keenan Nemetz · 1d ago · parent f7a34d87

Derive theme metadata from the stylesheet file name

profile/themes/index.json is gone. Each profile/themes/<id>.css is self-describing: the file name is the id and the label (acme-ocean.css becomes Acme Ocean), and the rules are scoped to that id. The loader discovers the files, validates the names, and sorts them by label.

Remove the manifest from the starter repository, its README, the Admin Configuration path table, and the configuration docs. An old index.json in an existing repository is ignored.

server/instance_repo_test.go +5−9

@@ -61,13 +61,9 @@ func TestInstanceThemesAppearInAppearance(t *testing.T) {
61 61 t.Parallel()
62 62 f := browserFixture(t)
63 63 f.instanceRepo(t, map[string][]byte{
64 "profile/themes/index.json": []byte(`{"themes":[
65 {"id":"acme-ocean","name":"Acme Ocean"},
66 {"id":"acme-paper","name":"Acme Paper"}
67 ]}`),
68 64 "profile/themes/acme-ocean.css": []byte(`:root[data-theme="acme-ocean"] { color-scheme: dark; --accent: #38bdf8; }`),
69 65 "profile/themes/acme-paper.css": []byte(`:root[data-theme="acme-paper"] { color-scheme: light; --accent: #9a5b13; }`),
70 "profile/themes/unlisted.css": []byte(`:root[data-theme="unlisted"] { --accent: red; }`),
66 "profile/themes/notes.txt": []byte("not a theme"),
71 67 })
72 68
73 69 _, cookie := f.browserSession(t, f.ownerID)
@@ -87,16 +83,16 @@ func TestInstanceThemesAppearInAppearance(t *testing.T) {
87 83 t.Errorf("Account is missing %q:\n%s", want, account)
88 84 }
89 85 }
90 if strings.Contains(account, `value="unlisted"`) {
91 t.Error("a stylesheet without a manifest entry became a picker option")
86 if strings.Contains(account, `value="notes"`) {
87 t.Error("a non-CSS file under themes/ became a picker option")
92 88 }
93 89
94 90 code, css := f.get("/static/custom/themes/acme-ocean.css")
95 91 if code != 200 || !strings.Contains(css, "#38bdf8") {
96 92 t.Fatalf("theme stylesheet = %d %q", code, css)
97 93 }
98 if code, _ := f.get("/static/custom/themes/unlisted.css"); code != 404 {
99 t.Fatalf("an unlisted theme file = %d, want 404", code)
94 if code, _ := f.get("/static/custom/themes/notes.css"); code != 404 {
95 t.Fatalf("a missing theme file = %d, want 404", code)
100 96 }
101 97 }
102 98