mirror of
https://github.com/mudler/LocalAI.git
synced 2026-10-28 00:59:28 -04:00
feat(ui): serve an apple-touch-icon so iOS shows the logo on the home screen (#12917)
iOS ignores the SVG favicon and draws the first letter of the page title when a page is saved to the home screen. Serve a 180x180 PNG made from logo.png at /apple-touch-icon.png, link it from the React UI head, and rewrite the link under a reverse-proxy prefix like the favicon link. The logo is flattened on white because iOS fills transparency with black. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Mauro Morales <contact@mauromorales.com> Co-authored-by: Mauro Morales <contact@mauromorales.com>
This commit is contained in:
1 parent
4b4c96852f
commit
53ddea6384
4 files changed
+13
No files matched your search
@@ -389,6 +389,16 @@ func API(application *application.Application) (*echo.Echo, error) {
|
||||
return c.Blob(http.StatusOK, "image/svg+xml", data)
|
||||
})
|
||||
|
||||
// iOS draws the home-screen icon from an apple-touch-icon PNG and ignores
|
||||
// the SVG favicon, so it falls back to the first letter of the page title.
|
||||
e.GET("/apple-touch-icon.png", func(c echo.Context) error {
|
||||
data, err := embedDirStatic.ReadFile("static/apple-touch-icon.png")
|
||||
if err != nil {
|
||||
return c.NoContent(http.StatusNotFound)
|
||||
}
|
||||
return c.Blob(http.StatusOK, "image/png", data)
|
||||
})
|
||||
|
||||
// Static files - use fs.Sub to create a filesystem rooted at "static"
|
||||
staticFS, err := fs.Sub(embedDirStatic, "static")
|
||||
if err != nil {
|
||||
@@ -671,6 +681,7 @@ func API(application *application.Application) (*echo.Echo, error) {
|
||||
html := string(indexHTML)
|
||||
html = strings.ReplaceAll(html, `="/assets/`, `="`+safePrefix+`assets/`)
|
||||
html = strings.ReplaceAll(html, `="/favicon.svg"`, `="`+safePrefix+`favicon.svg"`)
|
||||
html = strings.ReplaceAll(html, `="/apple-touch-icon.png"`, `="`+safePrefix+`apple-touch-icon.png"`)
|
||||
indexHTML = []byte(html)
|
||||
}
|
||||
return c.HTMLBlob(http.StatusOK, indexHTML)
|
||||
|
||||
@@ -469,6 +469,7 @@ var _ = Describe("API test", func() {
|
||||
Expect(string(body)).To(ContainSubstring(`<base href="https://example.org/myprefix/" />`), "body")
|
||||
Expect(string(body)).ToNot(ContainSubstring(`="/assets/`), "asset URLs must include the prefix")
|
||||
Expect(string(body)).ToNot(ContainSubstring(`="/favicon.svg"`), "favicon URL must include the prefix")
|
||||
Expect(string(body)).ToNot(ContainSubstring(`="/apple-touch-icon.png"`), "touch icon URL must include the prefix")
|
||||
})
|
||||
|
||||
// X-Forwarded-Prefix is attacker controllable on misconfigured
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>LocalAI</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
<script>
|
||||
// Set the theme before first paint, with the same rule as ThemeContext:
|
||||
// a stored choice wins, a fresh install opens dark.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Reference in new issue
Block a user