[mod] add manifest.json template and route (#5859)

URLs, name and colors are automatically rendered into manifest.json.
Furthermore user preference of theme (light, dark, black) and theme colors are
respected.  Theme colors can be set in settings.yml
This commit is contained in:
Ruben D.
2026-03-13 21:33:06 +01:00
committed by Markus Heiser
parent 924fc52f54
commit 3dc4d5daa8
5 changed files with 85 additions and 0 deletions

View File

@@ -18,6 +18,17 @@ class BrandCustom(msgspec.Struct, kw_only=True, forbid_unknown_fields=True):
"""Custom entries in the footer of the WEB page: ``[title]: [link]``"""
class ThemeColors(msgspec.Struct, kw_only=True, forbid_unknown_fields=True):
"""Custom settings for theme colors in the brand section."""
theme_color_light: str = "#3050ff"
background_color_light: str = "#fff"
theme_color_dark: str = "#58f"
background_color_dark: str = "#222428"
theme_color_black: str = "#3050ff"
background_color_black: str = "#000"
class SettingsBrand(msgspec.Struct, kw_only=True, forbid_unknown_fields=True):
"""Options for configuring brand properties.
@@ -53,3 +64,19 @@ class SettingsBrand(msgspec.Struct, kw_only=True, forbid_unknown_fields=True):
.. autoclass:: searx.brand.BrandCustom
:members:
"""
pwa_colors: ThemeColors = msgspec.field(default_factory=ThemeColors)
"""Custom settings for PWA colors."""
# new_issue_url is a hackish solution tailored for only one hoster (GH). As
# long as we don't have a more general solution, we should support it in the
# given function, but it should not be expanded further.
new_issue_url: str = "https://github.com/searxng/searxng/issues/new"
"""If you host your own issue tracker not on GitHub, then unset this URL.
Note: This URL will create a pre-filled GitHub bug report form for an
engine. Since this feature is implemented only for GH (and limited to
engines), it will probably be replaced by another solution in the near
future.
"""

View File

@@ -27,6 +27,15 @@ brand:
# links:
# Uptime: https://uptime.searxng.org/history/darmarit-org
# About: "https://searxng.org"
# pwa_colors:
# # Custom settings for PWA icon an colors used in manifest.json
# # Default colors are:
# theme_color_light: "#3050ff"
# background_color_light: "fff"
# theme_color_dark: "#58f"
# background_color_dark: "#222428"
# theme_color_black: "#3050ff"
# background_color_black: "#000"
search:
# Filter results. 0: None, 1: Moderate, 2: Strict

View File

@@ -26,6 +26,7 @@
<link rel="icon" href="{{ url_for('static', filename='img/favicon.png') }}" sizes="any">
<link rel="icon" href="{{ url_for('static', filename='img/favicon.svg') }}" type="image/svg+xml">
<link rel="apple-touch-icon" href="{{ url_for('static', filename='img/favicon.png') }}">
<link rel="manifest" href="{{ url_for('manifest') }}" />
</head>
<body class="{{ endpoint }}_endpoint" >
<main id="main_{{ self._TemplateReference__context.name|replace("simple/", "")|replace(".html", "") }}" class="{{body_class}}">

View File

@@ -0,0 +1,25 @@
{
"name": "{{ instance_name }}",
"short_name": "{{ instance_name }}",
"icons": [
{
"src": "{{ url_for('static', filename='img/favicon.svg', _external=True) }}",
"sizes": "any",
"type": "image/svg+xml"
},
{
"src": "{{ url_for('static', filename='img/192.png', _external=True) }}",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "{{ url_for('static', filename='img/512.png', _external=True) }}",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "{{ url_for('index') }}",
"theme_color": "{{ theme_color }}" ,
"background_color": "{{ background_color }}",
"display": "standalone"
}

View File

@@ -1215,6 +1215,29 @@ def opensearch():
return resp
@app.route('/manifest.json', methods=['GET'])
def manifest():
theme = sxng_request.preferences.get_value('simple_style')
if theme not in ("light", "dark", "black"):
theme = "light"
theme_color = get_setting(f'brand.pwa_colors.theme_color_{theme}')
background_color = get_setting(f'brand.pwa_colors.background_color_{theme}')
ret = render('manifest.json', theme_color=theme_color, background_color=background_color)
resp = Response(response=ret, status=200, mimetype="application/json")
return resp
@app.route('/logo/<resolution>')
def manifest_logo(resolution=0):
theme = sxng_request.preferences.get_value("theme")
return send_from_directory(
os.path.join(app.root_path, settings['ui']['static_path'], 'themes', theme, 'img', 'logos'), # type: ignore
resolution,
mimetype='image/vnd.microsoft.icon',
)
@app.route('/favicon.ico')
def favicon():
theme = sxng_request.preferences.get_value("theme")