Skip to content

Commit

Permalink
feat: create a basic front end using Bootstrap 5
Browse files Browse the repository at this point in the history
  • Loading branch information
xenophonf committed Dec 13, 2023
1 parent 112f5d6 commit e3b4d12
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 8 deletions.
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ venv: .venv
.venv:
python3 -m venv $@

debug run: .venv/lib/python$(PYV)/site-packages/psycopg2.py
. .venv/bin/activate; python3 -m flask --debug --app stuart.app run
debug: .venv/lib/python$(PYV)/site-packages/psycopg2.py
. .venv/bin/activate; python3 -m flask --debug --app stuart.app run $(ARGS)

run: .venv/lib/python$(PYV)/site-packages/psycopg2.py
. .venv/bin/activate; python3 -m flask --app stuart.app run $(ARGS)

smoke: .venv/lib/python$(PYV)/site-packages/psycopg2.py
. .venv/bin/activate; pytest -m "smoke and not slow"
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ classifiers = [
"Topic :: Utilities",
]
dependencies = [
"bootstrap-flask",
"flask",
"flask-talisman",
"flask-wtf",
Expand Down
15 changes: 13 additions & 2 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,40 @@
import pkgutil

from flask import Blueprint, Flask
from flask_bootstrap import Bootstrap5
from flask_talisman import Talisman

from . import __app_name__, __path__
from . import __app_name__, __path__, __version__

# configure module-level logging
logger = logging.getLogger(__name__)

# create Flask extension objects
bootstrap = Bootstrap5()
talisman = Talisman()


def create_app(test_config=None) -> Flask:
# create and configure the web app
app = Flask(__app_name__, instance_relative_config=True)
app.config.from_mapping(SECRET_KEY="dev")
app.config.from_mapping(
BOOTSTRAP_BOOTSWATCH_THEME="cyborg",
BOOTSTRAP_SERVE_LOCAL=True,
SECRET_KEY="dev",
)
if test_config:
app.config.from_mapping(test_config)
else:
app.config.from_pyfile("config.py", silent=True)

# load extensions
bootstrap.init_app(app)
talisman.init_app(app)

# pass functions/variables to Jinja templates; see also
# flask.Flask.context_processor
app.jinja_env.globals["stuart_version"] = __version__

# load blueprints from submodules
[
(lambda bp: app.register_blueprint(bp) if isinstance(bp, Blueprint) else None)(
Expand Down
8 changes: 4 additions & 4 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@

import logging

from flask import Blueprint
from flask import Blueprint, render_template

# configure module-level logging
logger = logging.getLogger(__name__)

bp = Blueprint("main", __name__, url_prefix="")
bp = Blueprint(__name__.split(".")[-1], __name__, url_prefix="")


@bp.route("/")
def hello_world():
return "Hello, world!"
def home():
return render_template("home.html")
57 changes: 57 additions & 0 deletions src/templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{%- from 'bootstrap5/nav.html' import render_nav_item -%}
{%- from 'bootstrap5/utils.html' import render_messages -%}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
<title>Stuart, a self-hostable galaxy and market data aggregator for Elite: Dangerous</title>
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}"/>
{{ bootstrap.load_css() }}
<style>
pre {
background: #ddd;
padding: 10px;
}
h2 {
margin-top: 20px;
}
footer {
margin: 20px;
}
</style>
</head>
<body class="d-flex flex-column min-vh-100">
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-4">
<div class="container">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
{{- render_nav_item("main.home", "Home") -}}
</ul>
</div>
</div>
</nav>

<main class="container">
{{- render_messages(container=False, dismissible=True, dismiss_animate=True) }}
{%- block content %}{%- endblock %}
</main>

<footer class="mt-auto text-center">
{% block footer %}
<small>
<p>Stuart {{ stuart_version }}, a self-hostable game data aggregator for <a href="https://www.elitedangerous.com/">Elite: Dangerous</a>.
Copyright &copy; 2023 <a href="https://github.com/xenophonf">Matthew X. Economou</a>.
<br>License AGPLv3+: <a href="https://www.gnu.org/licenses/agpl.html">GNU AGPL version 3 or later</a>.
Source code for this version can be found at <a href="https://github.com/irtnog/stuart">https://github.com/irtnog/stuart</a>.</p>
</small>
{% endblock %}
</footer>

{{ bootstrap.load_js() }}
</body>
</html>
5 changes: 5 additions & 0 deletions src/templates/home.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{%- extends 'base.html' %}
{%- block content %}
<h1>Greetings, commanders!</h1>
<p>And to everyone else out there, the secret is to bang the rocks together, guys!<p>
{%- endblock %}
32 changes: 32 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# stuart, a self-hostable game data aggregator for Elite: Dangerous
# Copyright (C) 2023 Matthew X. Economou
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program. If not, see
# <https://www.gnu.org/licenses/>.

from pytest import mark

from stuart import __version__


@mark.order("first")
@mark.smoke
def test_main(client):
response = client.get(
"/",
environ_overrides={"wsgi.url_scheme": "https"},
)
assert response.status_code == 200
assert "<!DOCTYPE html>" in response.text
assert __version__ in response.text

0 comments on commit e3b4d12

Please sign in to comment.