forked from zaclys/searxng
Merge pull request #848 from not-my-profile/help-route
Introduce `/help` route
This commit is contained in:
commit
bf987bb608
|
@ -1,4 +1,4 @@
|
|||
# About [searxng][url_for:index]
|
||||
# About SearXNG
|
||||
|
||||
SearXNG is a fork from the well-known [searx] [metasearch engine], aggregating
|
||||
the results of other [search engines][url_for:preferences] while not storing
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -221,6 +221,16 @@ div.selectable_url {
|
|||
font-size: 90%;
|
||||
}
|
||||
|
||||
ul.tabs {
|
||||
border-bottom: 1px solid var(--color-toolkit-tabs-section-border);
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
@ -235,7 +245,8 @@ div.selectable_url {
|
|||
display: none;
|
||||
}
|
||||
|
||||
& > label {
|
||||
& > label,
|
||||
& > li > a {
|
||||
order: 1;
|
||||
padding: 0.7em;
|
||||
margin: 0 0.7em;
|
||||
|
@ -243,13 +254,21 @@ div.selectable_url {
|
|||
text-transform: uppercase;
|
||||
border: solid var(--color-toolkit-tabs-label-border);
|
||||
border-width: 0 0 2px 0;
|
||||
color: unset;
|
||||
|
||||
.disable-user-select();
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
border-bottom: 2px solid var(--color-categories-item-border-selected);
|
||||
background: var(--color-categories-item-selected);
|
||||
color: var(--color-categories-item-selected-font);
|
||||
}
|
||||
}
|
||||
|
||||
& > label:hover {
|
||||
& > label:hover,
|
||||
& > li > a:hover {
|
||||
border-bottom: 2px solid var(--color-categories-item-border-selected);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
{% extends "oscar/base.html" %}
|
||||
{% block title %}{{ _('about') }} - {% endblock %}
|
||||
{% block content %}
|
||||
{{ help.about | safe }}
|
||||
{% include "__common__/aboutextend.html" ignore missing %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,12 @@
|
|||
{% extends "oscar/base.html" %}
|
||||
{% block title %}{{ page.title }} - {% endblock %}
|
||||
{% block content %}
|
||||
<ul class="nav nav-tabs">
|
||||
{% for name, page in all_pages %}
|
||||
<li {% if name == page_filename %}class="active"{% endif %}>
|
||||
<a href="{{name}}">{{page.title}}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{{ page.content | safe }}
|
||||
{% endblock %}
|
|
@ -3,7 +3,7 @@
|
|||
<a href="{{ url_for('index') }}">{{ instance_name }}</a>{{- "" -}}
|
||||
</span>{{- "" -}}
|
||||
<span class="{% if rtl %}pull-left{% else %}pull-right{% endif %}">{{- "" -}}
|
||||
<a href="{{ url_for('about') }}">{{ _('about') }}</a>{{- "" -}}
|
||||
<a href="{{ url_for('help_page', pagename='about') }}">{{ _('about') }}</a>{{- "" -}}
|
||||
<a href="{{ url_for('preferences') }}">{{ _('preferences') }}</a>{{- "" -}}
|
||||
</span>{{- "" -}}
|
||||
</div>
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
{% extends 'simple/page_with_header.html' %}
|
||||
{% block content %}
|
||||
{{ help.about | safe }}
|
||||
{% include "__common__/aboutextend.html" ignore missing %}
|
||||
{% endblock %}
|
|
@ -58,7 +58,7 @@
|
|||
</main>
|
||||
<footer>
|
||||
<p>
|
||||
{{ _('Powered by') }} <a href="{{ url_for('about') }}">searxng</a> - {{ searx_version }} — {{ _('a privacy-respecting, hackable metasearch engine') }}<br/>
|
||||
{{ _('Powered by') }} <a href="{{ url_for('help_page', pagename='about') }}">searxng</a> - {{ searx_version }} — {{ _('a privacy-respecting, hackable metasearch engine') }}<br/>
|
||||
<a href="{{ searx_git_url }}">{{ _('Source code') }}</a> |
|
||||
<a href="{{ get_setting('brand.issue_url') }}">{{ _('Issue tracker') }}</a> |
|
||||
<a href="{{ url_for('stats') }}">{{ _('Engine stats') }}</a> |
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
{% extends 'simple/page_with_header.html' %}
|
||||
{% block title %}{{ page.title }} - {% endblock %}
|
||||
{% block content %}
|
||||
<ul class="tabs">
|
||||
{% for name, page in all_pages %}
|
||||
<li>
|
||||
<a href="{{name}}" {% if name == page_filename %}class="active"{% endif %}>{{page.title}}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{{ page.content | safe }}
|
||||
{% endblock %}
|
|
@ -1,5 +1,5 @@
|
|||
from typing import Dict
|
||||
import os.path
|
||||
# pyright: basic
|
||||
from typing import Dict, NamedTuple
|
||||
import pkg_resources
|
||||
|
||||
import flask
|
||||
|
@ -9,8 +9,17 @@ import mistletoe
|
|||
from . import get_setting
|
||||
from .version import GIT_URL
|
||||
|
||||
HELP: Dict[str, str] = {}
|
||||
""" Maps a filename under help/ without the file extension to the rendered HTML. """
|
||||
|
||||
class HelpPage(NamedTuple):
|
||||
title: str
|
||||
content: str
|
||||
|
||||
|
||||
# Whenever a new .md file is added to help/ it needs to be added here
|
||||
_TOC = ('about',)
|
||||
|
||||
PAGES: Dict[str, HelpPage] = {}
|
||||
""" Maps a filename under help/ without the file extension to the rendered page. """
|
||||
|
||||
|
||||
def render(app: flask.Flask):
|
||||
|
@ -37,12 +46,16 @@ def render(app: flask.Flask):
|
|||
|
||||
define_link_targets = ''.join(f'[{name}]: {url}\n' for name, url in link_targets.items())
|
||||
|
||||
for filename in pkg_resources.resource_listdir(__name__, 'help'):
|
||||
rootname, ext = os.path.splitext(filename)
|
||||
for pagename in _TOC:
|
||||
file_content = pkg_resources.resource_string(__name__, 'help/' + pagename + '.md').decode()
|
||||
markdown = define_link_targets + file_content
|
||||
assert file_content.startswith('# ')
|
||||
title = file_content.split('\n', maxsplit=1)[0].strip('# ')
|
||||
content: str = mistletoe.markdown(markdown)
|
||||
|
||||
if ext != '.md':
|
||||
continue
|
||||
|
||||
markdown = pkg_resources.resource_string(__name__, 'help/' + filename).decode()
|
||||
markdown = define_link_targets + markdown
|
||||
HELP[rootname] = mistletoe.markdown(markdown)
|
||||
if pagename == 'about':
|
||||
try:
|
||||
content += pkg_resources.resource_string(__name__, 'templates/__common__/aboutextend.html').decode()
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
PAGES[pagename] = HelpPage(title=title, content=content)
|
||||
|
|
|
@ -877,8 +877,21 @@ def __get_translated_errors(unresponsive_engines: Iterable[UnresponsiveEngine]):
|
|||
|
||||
@app.route('/about', methods=['GET'])
|
||||
def about():
|
||||
"""Render about page"""
|
||||
return render('about.html', help=user_help.HELP)
|
||||
"""Redirect to about page"""
|
||||
return redirect(url_for('help_page', pagename='about'))
|
||||
|
||||
|
||||
@app.route('/help/en/<pagename>', methods=['GET'])
|
||||
def help_page(pagename):
|
||||
"""Render help page"""
|
||||
page = user_help.PAGES.get(pagename)
|
||||
|
||||
if page is None:
|
||||
flask.abort(404)
|
||||
|
||||
return render(
|
||||
'help.html', page=user_help.PAGES[pagename], all_pages=user_help.PAGES.items(), page_filename=pagename
|
||||
)
|
||||
|
||||
|
||||
@app.route('/autocompleter', methods=['GET', 'POST'])
|
||||
|
|
|
@ -174,9 +174,9 @@ class ViewsTestCase(SearxTestCase):
|
|||
self.assertIn(b'<description>first test content</description>', result.data)
|
||||
|
||||
def test_about(self):
|
||||
result = self.app.get('/about')
|
||||
result = self.app.get('/help/en/about')
|
||||
self.assertEqual(result.status_code, 200)
|
||||
self.assertIn(b'<h1>About <a href="/">searxng</a></h1>', result.data)
|
||||
self.assertIn(b'<h1>About SearXNG</h1>', result.data)
|
||||
|
||||
def test_health(self):
|
||||
result = self.app.get('/healthz')
|
||||
|
|
Loading…
Reference in New Issue