Skip to content
This repository was archived by the owner on Sep 3, 2026. It is now read-only.

Commit 77aca53

Browse files
author
outlndrr
committed
fix(ui): serve favicon assets from root
Browsers expect the favicon and manifest files at root paths. Serve the moved priv assets with explicit routes instead of exposing the whole priv directory, which also contains migrations. Update the UI head links and route tests to match the new locations.
1 parent dc61c49 commit 77aca53

9 files changed

Lines changed: 88 additions & 4 deletions

priv/apple-touch-icon.png

55.8 KB
Loading

priv/favicon-96x96.png

17 KB
Loading

priv/favicon.ico

14.7 KB
Binary file not shown.

priv/favicon.svg

Lines changed: 1 addition & 0 deletions
Loading

priv/site.webmanifest

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "Lummy",
3+
"short_name": "Lummy",
4+
"icons": [
5+
{
6+
"src": "/web-app-manifest-192x192.png",
7+
"sizes": "192x192",
8+
"type": "image/png",
9+
"purpose": "maskable"
10+
},
11+
{
12+
"src": "/web-app-manifest-512x512.png",
13+
"sizes": "512x512",
14+
"type": "image/png",
15+
"purpose": "maskable"
16+
}
17+
],
18+
"theme_color": "#ffffff",
19+
"background_color": "#ffffff",
20+
"display": "standalone"
21+
}

priv/web-app-manifest-192x192.png

64 KB
Loading

priv/web-app-manifest-512x512.png

347 KB
Loading

src/lummy_agent/transport/http_server.gleam

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,30 @@ pub fn handle(
245245

246246
http.Get, ["ui"] -> wisp.html_response(ui_index_html(), 200)
247247

248+
http.Get, ["favicon-96x96.png"] ->
249+
static_file_response("./priv/favicon-96x96.png", "image/png")
250+
251+
http.Get, ["favicon.svg"] ->
252+
static_file_response("./priv/favicon.svg", "image/svg+xml")
253+
254+
http.Get, ["favicon.ico"] ->
255+
static_file_response("./priv/favicon.ico", "image/x-icon")
256+
257+
http.Get, ["apple-touch-icon.png"] ->
258+
static_file_response("./priv/apple-touch-icon.png", "image/png")
259+
260+
http.Get, ["site.webmanifest"] ->
261+
static_file_response(
262+
"./priv/site.webmanifest",
263+
"application/manifest+json",
264+
)
265+
266+
http.Get, ["web-app-manifest-192x192.png"] ->
267+
static_file_response("./priv/web-app-manifest-192x192.png", "image/png")
268+
269+
http.Get, ["web-app-manifest-512x512.png"] ->
270+
static_file_response("./priv/web-app-manifest-512x512.png", "image/png")
271+
248272
http.Get, ["api", "v1", "providers", "openrouter", "models"] ->
249273
handle_list_openrouter_models(config)
250274

@@ -1658,6 +1682,12 @@ fn json_response(body: json.Json, status: Int) -> wisp.Response {
16581682
|> fn(content) { wisp.json_response(content, status) }
16591683
}
16601684

1685+
fn static_file_response(path: String, content_type: String) -> wisp.Response {
1686+
response.new(200)
1687+
|> response.set_header("content-type", content_type)
1688+
|> response.set_body(wisp.File(path:, offset: 0, limit: option.None))
1689+
}
1690+
16611691
fn ui_index_html() -> String {
16621692
[
16631693
"<!doctype html>",
@@ -1666,6 +1696,12 @@ fn ui_index_html() -> String {
16661696
" <meta charset=\"utf-8\" />",
16671697
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />",
16681698
" <title>Luumy</title>",
1699+
" <link rel=\"icon\" type=\"image/png\" href=\"/favicon-96x96.png\" sizes=\"96x96\" />",
1700+
" <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\" />",
1701+
" <link rel=\"shortcut icon\" href=\"/favicon.ico\" />",
1702+
" <link rel=\"apple-touch-icon\" sizes=\"180x180\" href=\"/apple-touch-icon.png\" />",
1703+
" <meta name=\"apple-mobile-web-app-title\" content=\"Lummy\" />",
1704+
" <link rel=\"manifest\" href=\"/site.webmanifest\" />",
16691705
" <style>",
16701706
" :root {",
16711707
" color-scheme: dark;",

test/lummy_agent_http_api_test.gleam

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,11 +263,37 @@ pub fn ui_shell_route_test() {
263263
simulate.request(http.Get, "/ui")
264264
|> http_server.handle(runtime.config, runtime.dependencies, _)
265265

266+
let body = simulate.read_body(response)
267+
266268
assert response.status == 200
267-
assert string.contains(
268-
simulate.read_body(response),
269-
"/ui/dist/lummy_agent_ui.js",
270-
)
269+
assert string.contains(body, "/ui/dist/lummy_agent_ui.js")
270+
assert string.contains(body, "/favicon-96x96.png")
271+
assert string.contains(body, "/site.webmanifest")
272+
}
273+
274+
pub fn favicon_manifest_static_route_test() {
275+
let runtime = runtime("http-favicon-manifest")
276+
277+
let response =
278+
simulate.request(http.Get, "/site.webmanifest")
279+
|> http_server.handle(runtime.config, runtime.dependencies, _)
280+
281+
let body = simulate.read_body(response)
282+
283+
assert response.status == 200
284+
assert string.contains(body, "\"name\": \"Lummy\"")
285+
assert string.contains(body, "/web-app-manifest-192x192.png")
286+
}
287+
288+
pub fn favicon_svg_static_route_test() {
289+
let runtime = runtime("http-favicon-svg")
290+
291+
let response =
292+
simulate.request(http.Get, "/favicon.svg")
293+
|> http_server.handle(runtime.config, runtime.dependencies, _)
294+
295+
assert response.status == 200
296+
assert string.contains(simulate.read_body(response), "<svg")
271297
}
272298

273299
pub fn append_message_and_get_session_snapshot_route_test() {

0 commit comments

Comments
 (0)