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.

Refresh the web surface with Everforest, readable type, and clearer navigation

796ac8c0ce77461174cf520d5fad4dea37744662 · Keenan Nemetz · 12d ago · parent ac00929f

docs/ui-plan.md +43−14

@@ -9,9 +9,20 @@ deliberately rather than by drift.
9 9 Avoid GitHub's whitespace-heavy chrome; avoid Sourcehut's bareness. A row of
10 10 data should be readable at a glance, and a page should fit on one screen when
11 11 it can.
12 - **Dark by default.** Every colour comes from a custom property on `:root`.
13 A light theme is a second block of variables, not a rewrite; it currently
14 follows the operating system's `prefers-color-scheme`.
12 - **Everforest is the theme.** Every colour comes from a custom property on
13 `:root`; `static/everforest.css` supplies six variants over the same layout:
14 dark and light, each in hard, medium, and soft contrast. The picker lives on
15 the Account page, and `static/theme.js` applies the saved variant before the
16 first paint. Its `System` default follows the operating system's dark or
17 light preference and uses the medium contrast; the base sheet's tokens remain
18 the fallback.
19 - **Readability first.** Lexend is the UI face and JetBrains Mono is the code
20 face; both are self-hosted WOFF2 under `static/fonts/` under the SIL Open Font
21 License 1.1, with the system stacks as fallback. The medium (100%) base is
22 15.4px with a 1.55 line height and subpixel-friendly smoothing. Every explicit
23 font size is multiplied by `--font-scale`; the Account page's Text size presets
24 are 90%, 100%, and 110%, stored in this browser and applied before first paint.
25 Medium is the default and matches the former Large size.
15 26 - **Server rendered.** Go `html/template` produces the page. HTMX is the default
16 27 dynamic layer, vendored into the binary; JavaScript is required — passkeys,
17 28 clipboard copy, and rich widgets such as the label/assignee token input all
@@ -21,16 +32,17 @@ deliberately rather than by drift.
21 32 answer a fragment when `HX-Request: true` and a redirect otherwise.
22 33 - **Identity later.** Keep the `vole` wordmark as a placeholder and keep colour,
23 34 type, radius, and spacing in tokens so a real identity is a token swap.
24 - **Single tenant.** No organisation/workspace switcher. The global bar has one
25 public destination, plus the account menu; the repository owns its own
26 horizontal tabs.
35 - **Single tenant.** No organisation/workspace switcher. The global bar is
36 limited to Home, Activity, search, and the account menu; the repository owns
37 its own horizontal tabs.
27 38
28 39 ## Navigation model
29 40
30 Global bar (slim): `vole` · `Activity` · search · account menu. The wordmark is
31 home, so there is no separate Repositories link. The account menu carries
32 Account, Status for instance admins, and Sign out; the current destination is
33 marked. Search is a field on wide screens and takes its own row on narrow ones.
41 Global bar (slim): `vole` · `Home` · `Activity` · search · account menu. The
42 wordmark links home too, but the text destination keeps the mark from being the
43 only label. The account menu carries Account, Status for instance admins, and
44 Sign out; the current destination is marked. Search is a field on wide screens
45 and takes its own row on narrow ones.
34 46
35 47 Repository header: the repository name and its short description sit above the
36 48 tabs at the home-page header scale, with a lock for a private repository or a
@@ -40,8 +52,8 @@ the tabs, not the page, are the navigation. The tabs are:
40 52 `Overview` · `Activity` · `Code` · `Issues` · `Change requests` · `Releases` · `Runs` · `Locks` · `Settings`
41 53
42 54 No sidebar. A sidebar only pays for its width when there are many persistent
43 destinations; here the repository has several and the global bar has one, and
44 they fit on one row at desktop widths. On narrow screens the tab row scrolls
55 destinations; here the repository has several and the global bar is separate,
56 and they fit on one row at desktop widths. On narrow screens the tab row scrolls
45 57 horizontally rather than collapsing into a menu.
46 58
47 59 Every tab opens with the same page header: a title and one-line summary on the
@@ -72,7 +84,7 @@ Status: `done` exists today · `wip` in progress · `todo` missing.
72 84
73 85 - done — repository list (`/`)
74 86 - done — sign-in, registration, enrollment link
75 - done — account (name, keys, passkeys, sessions)
87 - done — account (name, theme, text size, keys, passkeys, sessions)
76 88 - done — styled 404 page everywhere, including missing detail resources and
77 89 download paths
78 90 - done — styled 500 page everywhere; a handler panic before the first byte is
@@ -332,6 +344,21 @@ stored as path data in `server/web/icons.go` and rendered inline with
332 344 `currentColor` and size with the surrounding text. A test checks that every icon
333 345 named in a template exists.
334 346
347 The header emblem is `static/vole-head.png` used as a CSS mask and tinted with the
348 theme's ink, so it follows the selected Everforest variant. The favicon is a
349 separate transparent mark: `favicon.svg` and the light/dark PNG fallbacks switch
350 between black and white from `prefers-color-scheme` (the browser window's mode),
351 not from the in-app theme choice. That keeps the tab icon legible against the
352 browser's own tab colour.
353
354 ## Fonts
355
356 Lexend (UI) and JetBrains Mono (code) are self-hosted variable WOFF2 subsets under
357 `server/web/static/fonts/`, split into Latin and Latin-ext. Their OFL 1.1 license
358 texts sit beside them, and the system stacks in `--font`/`--mono` cover scripts
359 outside those ranges and the pre-load state. No CDN and no runtime font request
360 outside `/static/`.
361
335 362 ## Rules
336 363
337 364 - Every state-changing form carries the CSRF hidden input.
@@ -349,6 +376,8 @@ named in a template exists.
349 376 it; anything two surfaces share goes in `chrome.html`, `components.html`,
350 377 `diff.html` or its own component file.
351 378 - Stylesheet sections are listed in the table of contents at the top of
352 `vole.css`; add a line there when a section is added or moved.
379 `vole.css`; add a line there when a section is added or moved. The base sheet
380 stays the authority; every Everforest rule in `everforest.css` must stay
381 scoped to `[data-theme^="everforest-"]`.
353 382 - Tables are for tabular data; navigation and page chrome are not tables.
354 383 - Test the page at 1440, 1024, and 390 px wide before calling it done.