detached 76aa55b

favicon(homepage): move SVG to frontend build (dist/favicon.svg) and serve via scheme; remove hardcoded SVG from main.go; map favicon.ico -> favicon.svg

commit
76aa55bff5b4f3639390a6c1d3a7ae74643b2963
author
bamen · · 2025-09-09 20:21 UTC
committer
bamen · · 2025-09-09 18:37 UTC
parent
e337302
signature
unsigned
3 files · +19 -3
M frontend/src/build-html.ts +4 -1
@@ -8,6 +8,9 @@ function buildHTML() {
88 const html = HTMLBuilder.createBaseHTML();
99 const outputPath = join(process.cwd(), 'dist', 'index.html');
1010 writeFileSync(outputPath, html);
11+ // Also emit favicon.svg as a file for dumb:// scheme lookups
12+ const favPath = join(process.cwd(), 'dist', 'favicon.svg');
13+ writeFileSync(favPath, HTMLBuilder.getFaviconSVG());
1114 console.log('✓ Generated index.html');
1215 } catch (error) {
1316 console.error('✗ Failed to generate HTML:', error);
@@ -18,4 +21,4 @@ function buildHTML() {
1821 // Only run when called directly (not imported)
1922 if (import.meta.url === `file://${process.argv[1]}`) {
2023 buildHTML();
21-}⏎̸
24+}
@@ -8,6 +8,9 @@ function buildHTML() {
8 const html = HTMLBuilder.createBaseHTML();8 const html = HTMLBuilder.createBaseHTML();
9 const outputPath = join(process.cwd(), 'dist', 'index.html');9 const outputPath = join(process.cwd(), 'dist', 'index.html');
10 writeFileSync(outputPath, html);10 writeFileSync(outputPath, html);
11+ // Also emit favicon.svg as a file for dumb:// scheme lookups
12+ const favPath = join(process.cwd(), 'dist', 'favicon.svg');
13+ writeFileSync(favPath, HTMLBuilder.getFaviconSVG());
11 console.log('✓ Generated index.html');14 console.log('✓ Generated index.html');
12 } catch (error) {15 } catch (error) {
13 console.error('✗ Failed to generate HTML:', error);16 console.error('✗ Failed to generate HTML:', error);
@@ -18,4 +21,4 @@ function buildHTML() {
18 // Only run when called directly (not imported)21 // Only run when called directly (not imported)
19 if (import.meta.url === `file://${process.argv[1]}`) {22 if (import.meta.url === `file://${process.argv[1]}`) {
20 buildHTML();23 buildHTML();
21-}⏎̸24+}
M frontend/src/utils/html-builder.ts +2 -2
@@ -35,7 +35,7 @@ export class HTMLBuilder {
3535 }
3636
3737 private static getFaviconDataURL(): string {
38- const svg = this.getFaviconSVG();
38+ const svg = HTMLBuilder.getFaviconSVG();
3939 // Minimal encoding for safe inline usage
4040 const encoded = encodeURIComponent(svg)
4141 .replace(/'/g, '%27')
@@ -44,7 +44,7 @@ export class HTMLBuilder {
4444 return `data:image/svg+xml;utf8,${encoded}`;
4545 }
4646
47- private static getFaviconSVG(): string {
47+ static getFaviconSVG(): string {
4848 // Stylized D with speed bolt on a subtle dark rounded card
4949 return `<?xml version="1.0" encoding="UTF-8"?>
5050 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
@@ -35,7 +35,7 @@ export class HTMLBuilder {
35 }35 }
36 36
37 private static getFaviconDataURL(): string {37 private static getFaviconDataURL(): string {
38- const svg = this.getFaviconSVG();38+ const svg = HTMLBuilder.getFaviconSVG();
39 // Minimal encoding for safe inline usage39 // Minimal encoding for safe inline usage
40 const encoded = encodeURIComponent(svg)40 const encoded = encodeURIComponent(svg)
41 .replace(/'/g, '%27')41 .replace(/'/g, '%27')
@@ -44,7 +44,7 @@ export class HTMLBuilder {
44 return `data:image/svg+xml;utf8,${encoded}`;44 return `data:image/svg+xml;utf8,${encoded}`;
45 }45 }
46 46
47- private static getFaviconSVG(): string {47+ static getFaviconSVG(): string {
48 // Stylized D with speed bolt on a subtle dark rounded card48 // Stylized D with speed bolt on a subtle dark rounded card
49 return `<?xml version="1.0" encoding="UTF-8"?>49 return `<?xml version="1.0" encoding="UTF-8"?>
50 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">50 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
M main.go +13 -0
@@ -287,6 +287,15 @@ func runBrowser() {
287287 rel = "index.html"
288288 }
289289 }
290+ // Special-case homepage favicon: map .ico request to embedded SVG file
291+ if (u.Host == "homepage" || u.Opaque == "homepage") && strings.EqualFold(rel, "favicon.ico") {
292+ log.Printf("[scheme] asset: rel=%s (host=%s path=%s) → mapping to favicon.svg", rel, u.Host, u.Path)
293+ data, rerr := assets.ReadFile(filepath.ToSlash(filepath.Join("frontend", "dist", "favicon.svg")))
294+ if rerr == nil {
295+ return "image/svg+xml", data, true
296+ }
297+ }
298+
290299 log.Printf("[scheme] asset: rel=%s (host=%s path=%s)", rel, u.Host, u.Path)
291300 data, rerr := assets.ReadFile(filepath.ToSlash(filepath.Join("frontend", "dist", rel)))
292301 if rerr != nil {
@@ -720,3 +729,7 @@ func detectAndSetKeyboardLocale() {
720729 // No layout-specific remaps; log for diagnostics only
721730 log.Printf("[locale] keyboard locale detected: %s", locale)
722731 }
732+
733+// getHomepageFaviconSVG returns the SVG used as a favicon for the homepage
734+// when WebKit requests dumb://homepage/favicon.ico.
735+// getHomepageFaviconSVG was inlined previously; now favicon.svg is emitted at build time.
@@ -287,6 +287,15 @@ func runBrowser() {
287 rel = "index.html"287 rel = "index.html"
288 }288 }
289 }289 }
290+ // Special-case homepage favicon: map .ico request to embedded SVG file
291+ if (u.Host == "homepage" || u.Opaque == "homepage") && strings.EqualFold(rel, "favicon.ico") {
292+ log.Printf("[scheme] asset: rel=%s (host=%s path=%s) → mapping to favicon.svg", rel, u.Host, u.Path)
293+ data, rerr := assets.ReadFile(filepath.ToSlash(filepath.Join("frontend", "dist", "favicon.svg")))
294+ if rerr == nil {
295+ return "image/svg+xml", data, true
296+ }
297+ }
298+
290 log.Printf("[scheme] asset: rel=%s (host=%s path=%s)", rel, u.Host, u.Path)299 log.Printf("[scheme] asset: rel=%s (host=%s path=%s)", rel, u.Host, u.Path)
291 data, rerr := assets.ReadFile(filepath.ToSlash(filepath.Join("frontend", "dist", rel)))300 data, rerr := assets.ReadFile(filepath.ToSlash(filepath.Join("frontend", "dist", rel)))
292 if rerr != nil {301 if rerr != nil {
@@ -720,3 +729,7 @@ func detectAndSetKeyboardLocale() {
720 // No layout-specific remaps; log for diagnostics only729 // No layout-specific remaps; log for diagnostics only
721 log.Printf("[locale] keyboard locale detected: %s", locale)730 log.Printf("[locale] keyboard locale detected: %s", locale)
722 }731 }
732+
733+// getHomepageFaviconSVG returns the SVG used as a favicon for the homepage
734+// when WebKit requests dumb://homepage/favicon.ico.
735+// getHomepageFaviconSVG was inlined previously; now favicon.svg is emitted at build time.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close