searxng: add Nord theme and deploy script
All checks were successful
CI / update (push) Successful in 3m25s
All checks were successful
CI / update (push) Successful in 3m25s
Override SearXNG's native CSS variables with Nord palette (cream white light mode, true black dark mode). Replace SearXNG logo with Bocken logo. Custom base.html template injects the CSS. Deploy script supports reset to restore original state.
This commit is contained in:
53
deploy-searxng.sh
Executable file
53
deploy-searxng.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/bin/sh
|
||||
# Deploy SearXNG custom theme to searx.bocken.org
|
||||
# CSS is hosted on bocken.org, template override on the SearXNG server
|
||||
#
|
||||
# Usage:
|
||||
# ./deploy-searxng.sh Deploy custom theme
|
||||
# ./deploy-searxng.sh reset Restore original SearXNG base.html and remove custom CSS
|
||||
|
||||
CSS_SRC=static/other/searxng.css
|
||||
CSS_DEST=/var/www/static/css/searxng.css
|
||||
|
||||
TMPL_SRC=static/other/searxng_base.html
|
||||
TMPL_DEST=/var/lib/searxng/venv/lib/python3.14/site-packages/searx/templates/simple/base.html
|
||||
TMPL_BACKUP="${TMPL_DEST}.orig"
|
||||
|
||||
if [ "$1" = "reset" ]; then
|
||||
echo "Resetting SearXNG to original theme..."
|
||||
ssh root@bocken.org "
|
||||
if [ -f '$TMPL_BACKUP' ]; then
|
||||
mv '$TMPL_BACKUP' '$TMPL_DEST'
|
||||
chown searxng:searxng '$TMPL_DEST'
|
||||
else
|
||||
echo 'No backup found at $TMPL_BACKUP — nothing to restore'
|
||||
exit 1
|
||||
fi
|
||||
rm -f '$CSS_DEST'
|
||||
systemctl restart uwsgi@emperor
|
||||
"
|
||||
echo "Done. Original theme restored."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Back up original base.html if no backup exists yet
|
||||
ssh root@bocken.org "
|
||||
if [ ! -f '$TMPL_BACKUP' ]; then
|
||||
cp '$TMPL_DEST' '$TMPL_BACKUP'
|
||||
echo 'Backed up original base.html'
|
||||
fi
|
||||
"
|
||||
|
||||
# Deploy CSS to bocken.org static hosting
|
||||
ssh root@bocken.org "mkdir -p /var/www/static/css"
|
||||
rsync -av "$CSS_SRC" "root@bocken.org:$CSS_DEST"
|
||||
|
||||
# Deploy custom base.html template to SearXNG server
|
||||
rsync -av "$TMPL_SRC" "root@bocken.org:$TMPL_DEST"
|
||||
ssh root@bocken.org "chown searxng:searxng '$TMPL_DEST'"
|
||||
|
||||
# Restart SearXNG to pick up template changes
|
||||
ssh root@bocken.org "systemctl restart uwsgi@emperor"
|
||||
|
||||
echo "Done. Check https://searx.bocken.org"
|
||||
echo "To restore original: ./deploy-searxng.sh reset"
|
||||
276
static/other/searxng.css
Normal file
276
static/other/searxng.css
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
SearXNG custom theme for searx.bocken.org
|
||||
Overrides SearXNG's native CSS variables with Nord palette
|
||||
Deployed via deploy-searxng.sh
|
||||
*/
|
||||
|
||||
/* ============================================
|
||||
LIGHT MODE — cream white base
|
||||
============================================ */
|
||||
:root {
|
||||
--color-base-font: #2a2a2a;
|
||||
--color-base-font-rgb: 42, 42, 42;
|
||||
--color-base-background: #f8f6f1;
|
||||
--color-base-background-mobile: #efecea;
|
||||
--color-url-font: #5E81AC;
|
||||
--color-url-visited-font: #B48EAD;
|
||||
--color-header-background: #f8f6f1;
|
||||
--color-header-border: #dfdcd8;
|
||||
--color-footer-background: #f8f6f1;
|
||||
--color-footer-border: #dfdcd8;
|
||||
--color-sidebar-border: #dfdcd8;
|
||||
--color-sidebar-font: #2a2a2a;
|
||||
--color-sidebar-background: #efecea;
|
||||
--color-backtotop-font: #555;
|
||||
--color-backtotop-border: #dfdcd8;
|
||||
--color-backtotop-background: #efecea;
|
||||
--color-btn-background: #5E81AC;
|
||||
--color-btn-font: #fff;
|
||||
--color-show-btn-background: #dfdcd8;
|
||||
--color-show-btn-font: #2a2a2a;
|
||||
--color-search-border: #dfdcd8;
|
||||
--color-search-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
--color-search-background: #efecea;
|
||||
--color-search-font: #2a2a2a;
|
||||
--color-search-background-hover: #5E81AC;
|
||||
--color-error: #BF616A;
|
||||
--color-error-background: #f5e1e3;
|
||||
--color-warning: #EBCB8B;
|
||||
--color-warning-background: #faf5e1;
|
||||
--color-success: #A3BE8C;
|
||||
--color-success-background: #e8f2e1;
|
||||
--color-categories-item-selected-font: #5E81AC;
|
||||
--color-categories-item-border-selected: #5E81AC;
|
||||
--color-autocomplete-font: #2a2a2a;
|
||||
--color-autocomplete-border: #dfdcd8;
|
||||
--color-autocomplete-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||||
--color-autocomplete-background: #efecea;
|
||||
--color-autocomplete-background-hover: #e8e5e1;
|
||||
--color-answer-font: #2a2a2a;
|
||||
--color-answer-background: #efecea;
|
||||
--color-result-keyvalue-col-table: #f8f6f1;
|
||||
--color-result-keyvalue-odd: #f8f6f1;
|
||||
--color-result-keyvalue-even: #efecea;
|
||||
--color-result-background: #efecea;
|
||||
--color-result-border: #dfdcd8;
|
||||
--color-result-url-font: #555;
|
||||
--color-result-vim-selected: #e8e5e1cc;
|
||||
--color-result-vim-arrow: #5E81AC;
|
||||
--color-result-description-highlight-font: #2a2a2a;
|
||||
--color-result-link-font: #5E81AC;
|
||||
--color-result-link-font-highlight: #5E81AC;
|
||||
--color-result-link-visited-font: #B48EAD;
|
||||
--color-result-publishdate-font: #777;
|
||||
--color-result-engines-font: #777;
|
||||
--color-result-search-url-border: #dfdcd8;
|
||||
--color-result-search-url-font: #555;
|
||||
--color-result-image-span-font: #555;
|
||||
--color-result-image-span-font-selected: #fff;
|
||||
--color-result-image-background: #efecea;
|
||||
--color-settings-tr-hover: #e8e5e1;
|
||||
--color-settings-engine-description-font: #777;
|
||||
--color-settings-table-group-background: rgba(0,0,0,0.03);
|
||||
--color-result-detail-font: #fff;
|
||||
--color-result-detail-label-font: #D8DEE9;
|
||||
--color-result-detail-background: #2E3440;
|
||||
--color-result-detail-hr: #4C566A;
|
||||
--color-result-detail-link: #88C0D0;
|
||||
--color-result-detail-loader-border: rgba(255,255,255,0.2);
|
||||
--color-result-detail-loader-borderleft: transparent;
|
||||
--color-toolkit-badge-font: #fff;
|
||||
--color-toolkit-badge-background: #4C566A;
|
||||
--color-toolkit-kbd-font: #fff;
|
||||
--color-toolkit-kbd-background: #2E3440;
|
||||
--color-toolkit-dialog-border: #dfdcd8;
|
||||
--color-toolkit-dialog-background: #f8f6f1;
|
||||
--color-toolkit-tabs-label-border: #f8f6f1;
|
||||
--color-toolkit-tabs-section-border: #dfdcd8;
|
||||
--color-toolkit-select-background: #e8e5e1;
|
||||
--color-toolkit-select-border: #dfdcd8;
|
||||
--color-toolkit-select-background-hover: #dfdcd8;
|
||||
--color-toolkit-input-text-font: #2a2a2a;
|
||||
--color-toolkit-checkbox-onoff-off-background: #dfdcd8;
|
||||
--color-toolkit-checkbox-onoff-on-background: #dfdcd8;
|
||||
--color-toolkit-checkbox-onoff-on-mark-background: #5E81AC;
|
||||
--color-toolkit-checkbox-onoff-on-mark-color: #fff;
|
||||
--color-toolkit-checkbox-onoff-off-mark-background: #aaa;
|
||||
--color-toolkit-checkbox-onoff-off-mark-color: #fff;
|
||||
--color-toolkit-checkbox-label-background: #dfdcd8;
|
||||
--color-toolkit-checkbox-label-border: #dfdcd8;
|
||||
--color-toolkit-checkbox-input-border: #5E81AC;
|
||||
--color-toolkit-engine-tooltip-border: #dfdcd8;
|
||||
--color-toolkit-engine-tooltip-background: #f8f6f1;
|
||||
--color-toolkit-loader-border: rgba(0,0,0,0.1);
|
||||
--color-toolkit-loader-borderleft: transparent;
|
||||
--color-doc-code: #2E3440;
|
||||
--color-doc-code-background: #e8e5e1;
|
||||
--color-bar-chart-primary: #5E81AC;
|
||||
--color-bar-chart-secondary: #D08770;
|
||||
--color-image-resolution-background: rgba(0,0,0,0.5);
|
||||
--color-image-resolution-font: #fff;
|
||||
--color-loading-indicator: rgba(255,255,255,0.2);
|
||||
--color-loading-indicator-gap: #f8f6f1;
|
||||
--color-line-number: #4C566A;
|
||||
--color-favicon-background-color: #e8e5e1;
|
||||
--color-favicon-border-color: #dfdcd8;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
DARK MODE — true black base
|
||||
============================================ */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root.theme-auto {
|
||||
--color-base-font: #e5e5e5;
|
||||
--color-base-font-rgb: 229, 229, 229;
|
||||
--color-base-background: #000;
|
||||
--color-base-background-mobile: #000;
|
||||
--color-url-font: #88C0D0;
|
||||
--color-url-visited-font: #c89fb6;
|
||||
--color-header-background: #000;
|
||||
--color-header-border: #222;
|
||||
--color-footer-background: #000;
|
||||
--color-footer-border: #222;
|
||||
--color-sidebar-border: #333;
|
||||
--color-sidebar-font: #e5e5e5;
|
||||
--color-sidebar-background: #1a1a1a;
|
||||
--color-backtotop-font: #aaa;
|
||||
--color-backtotop-border: #333;
|
||||
--color-backtotop-background: #1a1a1a;
|
||||
--color-btn-background: #88C0D0;
|
||||
--color-btn-font: #000;
|
||||
--color-show-btn-background: #333;
|
||||
--color-show-btn-font: #e5e5e5;
|
||||
--color-search-border: #333;
|
||||
--color-search-shadow: 0 2px 8px rgba(0,0,0,0.5);
|
||||
--color-search-background: #1a1a1a;
|
||||
--color-search-font: #e5e5e5;
|
||||
--color-search-background-hover: #88C0D0;
|
||||
--color-error: #BF616A;
|
||||
--color-error-background: #2a0f0f;
|
||||
--color-warning: #EBCB8B;
|
||||
--color-warning-background: #2a2008;
|
||||
--color-success: #A3BE8C;
|
||||
--color-success-background: #0e2a0a;
|
||||
--color-categories-item-selected-font: #88C0D0;
|
||||
--color-categories-item-border-selected: #88C0D0;
|
||||
--color-autocomplete-font: #e5e5e5;
|
||||
--color-autocomplete-border: #333;
|
||||
--color-autocomplete-shadow: 0 2px 8px rgba(0,0,0,0.5);
|
||||
--color-autocomplete-background: #1a1a1a;
|
||||
--color-autocomplete-background-hover: #111;
|
||||
--color-answer-font: #e5e5e5;
|
||||
--color-answer-background: #1a1a1a;
|
||||
--color-result-keyvalue-col-table: #111;
|
||||
--color-result-keyvalue-odd: #111;
|
||||
--color-result-keyvalue-even: #1a1a1a;
|
||||
--color-result-background: #1a1a1a;
|
||||
--color-result-border: #222;
|
||||
--color-result-url-font: #888;
|
||||
--color-result-vim-selected: #111c;
|
||||
--color-result-vim-arrow: #88C0D0;
|
||||
--color-result-description-highlight-font: #fff;
|
||||
--color-result-link-font: #88C0D0;
|
||||
--color-result-link-font-highlight: #88C0D0;
|
||||
--color-result-link-visited-font: #c89fb6;
|
||||
--color-result-publishdate-font: #888;
|
||||
--color-result-engines-font: #888;
|
||||
--color-result-search-url-border: #333;
|
||||
--color-result-search-url-font: #aaa;
|
||||
--color-result-image-span-font: #aaa;
|
||||
--color-result-image-span-font-selected: #fff;
|
||||
--color-result-image-background: #1a1a1a;
|
||||
--color-settings-tr-hover: #222;
|
||||
--color-settings-engine-description-font: #888;
|
||||
--color-settings-table-group-background: rgba(255,255,255,0.03);
|
||||
--color-result-detail-font: #e5e5e5;
|
||||
--color-result-detail-label-font: #aaa;
|
||||
--color-result-detail-background: #111;
|
||||
--color-result-detail-hr: #333;
|
||||
--color-result-detail-link: #88C0D0;
|
||||
--color-result-detail-loader-border: rgba(255,255,255,0.2);
|
||||
--color-result-detail-loader-borderleft: transparent;
|
||||
--color-toolkit-badge-font: #e5e5e5;
|
||||
--color-toolkit-badge-background: #4C566A;
|
||||
--color-toolkit-kbd-font: #e5e5e5;
|
||||
--color-toolkit-kbd-background: #000;
|
||||
--color-toolkit-dialog-border: #333;
|
||||
--color-toolkit-dialog-background: #111;
|
||||
--color-toolkit-tabs-label-border: #111;
|
||||
--color-toolkit-tabs-section-border: #333;
|
||||
--color-toolkit-select-background: #222;
|
||||
--color-toolkit-select-border: #333;
|
||||
--color-toolkit-select-background-hover: #333;
|
||||
--color-toolkit-input-text-font: #e5e5e5;
|
||||
--color-toolkit-checkbox-onoff-off-background: #333;
|
||||
--color-toolkit-checkbox-onoff-on-background: #333;
|
||||
--color-toolkit-checkbox-onoff-on-mark-background: #88C0D0;
|
||||
--color-toolkit-checkbox-onoff-on-mark-color: #000;
|
||||
--color-toolkit-checkbox-onoff-off-mark-background: #555;
|
||||
--color-toolkit-checkbox-onoff-off-mark-color: #e5e5e5;
|
||||
--color-toolkit-checkbox-label-background: #333;
|
||||
--color-toolkit-checkbox-label-border: #333;
|
||||
--color-toolkit-checkbox-input-border: #88C0D0;
|
||||
--color-toolkit-engine-tooltip-border: #333;
|
||||
--color-toolkit-engine-tooltip-background: #111;
|
||||
--color-toolkit-loader-border: rgba(255,255,255,0.1);
|
||||
--color-toolkit-loader-borderleft: transparent;
|
||||
--color-doc-code: #e5e5e5;
|
||||
--color-doc-code-background: #1a1a1a;
|
||||
--color-bar-chart-primary: #88C0D0;
|
||||
--color-bar-chart-secondary: #D08770;
|
||||
--color-image-resolution-background: rgba(0,0,0,0.7);
|
||||
--color-image-resolution-font: #e5e5e5;
|
||||
--color-loading-indicator: rgba(255,255,255,0.2);
|
||||
--color-loading-indicator-gap: #000;
|
||||
--color-line-number: #4C566A;
|
||||
--color-favicon-background-color: #222;
|
||||
--color-favicon-border-color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
FONT
|
||||
============================================ */
|
||||
* {
|
||||
font-family: Helvetica, Arial, "Noto Sans", sans-serif !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
INDEX PAGE — LOGO
|
||||
Replace SearXNG logo with Bocken logo
|
||||
============================================ */
|
||||
.index .title {
|
||||
background-image: url("https://bocken.org/static/css/logos/logo_text_smart.svg") !important;
|
||||
}
|
||||
|
||||
/* Results page logo */
|
||||
#search_logo svg,
|
||||
#search_logo img {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#search_logo span {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#search_logo::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100px;
|
||||
height: 30px;
|
||||
background: url("https://bocken.org/static/css/logos/logo_full_light.svg") no-repeat center / contain;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
#search_logo::after {
|
||||
background-image: url("https://bocken.org/static/css/logos/logo_full_dark.svg");
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
SCROLLBAR
|
||||
============================================ */
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--color-header-border) var(--color-base-background);
|
||||
}
|
||||
92
static/other/searxng_base.html
Normal file
92
static/other/searxng_base.html
Normal file
@@ -0,0 +1,92 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="no-js theme-{{ preferences.get_value('simple_style') or 'auto' }} center-alignment-{{ preferences.get_value('center_alignment') and 'yes' or 'no' }}" lang="{{ locale_rfc5646 }}" {% if rtl %} dir="rtl"{% endif %}>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="endpoint" content="{{ endpoint }}">
|
||||
<meta name="description" content="SearXNG — a privacy-respecting, open metasearch engine">
|
||||
<meta name="keywords" content="SearXNG, search, search engine, metasearch, meta search">
|
||||
<meta name="generator" content="searxng/{{ searx_version }}">
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<meta name="robots" content="noarchive">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}{% endblock %}{{ instance_name }}</title>
|
||||
<script type="module" src="{{ url_for('static', filename='sxng-core.min.js') }}" client_settings="{{ client_settings
|
||||
}}"></script>
|
||||
{% block meta %}{% endblock %}
|
||||
{% if rtl %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='sxng-rtl.min.css') }}" type="text/css" media="screen">
|
||||
{% else %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='sxng-ltr.min.css') }}" type="text/css" media="screen">
|
||||
{% endif %}
|
||||
{% if get_setting('server.limiter') or get_setting('server.public_instance') %}
|
||||
<link rel="stylesheet" href="{{ url_for('client_token', token=link_token) }}" type="text/css">
|
||||
{% endif %}
|
||||
<!-- bocken.org custom theme -->
|
||||
<link rel="stylesheet" href="https://bocken.org/static/css/searxng.css" type="text/css" media="screen">
|
||||
{% block head %}
|
||||
<link title="{{ instance_name }}" type="application/opensearchdescription+xml" rel="search" href="{{ opensearch_url }}">
|
||||
{% endblock %}
|
||||
<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') }}">
|
||||
</head>
|
||||
<body class="{{ endpoint }}_endpoint" >
|
||||
<main id="main_{{ self._TemplateReference__context.name|replace("simple/", "")|replace(".html", "") }}" class="{{body_class}}">
|
||||
{% if errors %}
|
||||
<div class="dialog-error" role="alert">
|
||||
<a href="#" class="close" aria-label="close" title="close">×</a>
|
||||
<ul>
|
||||
{% for message in errors %}
|
||||
<li>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<nav id="links_on_top">
|
||||
{%- from 'simple/icons.html' import icon_big -%}
|
||||
{%- block linkto_about -%}
|
||||
<a href="{{ url_for('info', pagename='about') }}" class="link_on_top_about">{{ icon_big('information-circle') }}<span>{{ _('About') }}</span></a>
|
||||
{%- endblock -%}
|
||||
{%- block linkto_donate -%}
|
||||
{%- if donation_url -%}
|
||||
<a href="{{ donation_url }}" class="link_on_top_donate">{{ icon_big('heart') }}<span>{{ _('Donate') }}</span></a>
|
||||
{%- endif -%}
|
||||
{%- endblock -%}
|
||||
{%- block linkto_preferences -%}
|
||||
{%- if request.args.get('preferences') -%}
|
||||
<a href="{{ url_for('preferences') }}?preferences={{ request.args.get('preferences') }}&preferences_preview_only=true" class="link_on_top_preferences">{{ icon_big('settings') }}<span>{{ _('Preferences') }}</span></a>
|
||||
{%- else -%}
|
||||
<a href="{{ url_for('preferences') }}" class="link_on_top_preferences">{{ icon_big('settings') }}<span>{{ _('Preferences') }}</span></a>
|
||||
{%- endif -%}
|
||||
{%- endblock -%}
|
||||
</nav>
|
||||
{% block header %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
<footer>
|
||||
<p>
|
||||
|
||||
{{ _('Powered by') }} <a href="{{ url_for('info', pagename='about') }}">SearXNG</a> - {{ searx_version }} — {{ _('a privacy-respecting, open metasearch engine') }}<br>
|
||||
<a href="{{ searx_git_url }}">{{ _('Source code') }}</a>
|
||||
| <a href="{{ get_setting('brand.issue_url') }}">{{ _('Issue tracker') }}</a>
|
||||
{% if enable_metrics %}| <a href="{{ url_for('stats') }}">{{ _('Engine stats') }}</a>{% endif %}
|
||||
{% if get_setting('brand.public_instances') %}
|
||||
| <a href="{{ get_setting('brand.public_instances') }}">{{ _('Public instances') }}</a>
|
||||
{% endif %}
|
||||
{% if get_setting('general.privacypolicy_url') %}
|
||||
| <a href="{{ get_setting('general.privacypolicy_url') }}">{{ _('Privacy policy') }}</a>
|
||||
{% endif %}
|
||||
{% if get_setting('general.contact_url') %}
|
||||
| <a href="{{ get_setting('general.contact_url') }}">{{ _('Contact instance maintainer') }}</a>
|
||||
{% endif %}
|
||||
{% for title, link in get_setting('brand.custom.links').items() %}
|
||||
| <a href="{{ link }}">{{ _(title) }}</a>
|
||||
{% endfor %}
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user