Make dashboard, person, settings page htmx driven

This commit is contained in:
Peter Stockings
2022-11-23 22:36:45 +11:00
parent 1181937b6d
commit 41bfce9513
9 changed files with 170 additions and 154 deletions

14
app.py
View File

@@ -4,11 +4,13 @@ import jinja_partials
from decorators import validate_person, validate_topset, validate_workout
from db import DataBase
from utils import get_people_and_exercise_rep_maxes
from flask_htmx import HTMX
app = Flask(__name__)
app.config.from_pyfile('config.py')
jinja_partials.register_extensions(app)
db = DataBase(app)
htmx = HTMX(app)
@ app.route("/")
@@ -16,7 +18,10 @@ def dashboard():
all_topsets = db.get_all_topsets()
people_and_exercise_rep_maxes = get_people_and_exercise_rep_maxes(
all_topsets)
return render_template('index.html', model=people_and_exercise_rep_maxes)
if htmx:
return render_template('partials/page/dashboard.html',
model=people_and_exercise_rep_maxes), 200, {"HX-Trigger": "updatedPeople"}
return render_template('dashboard.html', model=people_and_exercise_rep_maxes)
@ app.route("/person/list", methods=['GET'])
@@ -29,6 +34,10 @@ def get_person_list():
@ validate_person
def get_person(person_id):
person = db.get_person(person_id)
if htmx:
return render_template('partials/page/person.html',
person=person, is_filtered=False), 200, {"HX-Trigger": "updatedPeople"}
return render_template('person.html', person=person)
@@ -204,6 +213,9 @@ def delete_exercise(exercise_id):
def settings():
people = db.get_people()
exercises = db.get_exercises()
if htmx:
return render_template('partials/page/settings.html',
people=people, exercises=exercises), 200, {"HX-Trigger": "updatedPeople"}
return render_template('settings.html', people=people, exercises=exercises)

View File

@@ -1,5 +1,6 @@
Flask==2.0.1
Flask==2.2.2
gunicorn==19.7.1
Jinja2==3.0.1
jinja-partials==0.1.1
psycopg2-binary==2.9.3
flask-htmx==0.2.0

View File

@@ -75,8 +75,8 @@
<div class="flex-1 flex flex-col pt-5 pb-4 overflow-y-auto">
<div class="flex-1 px-3 bg-white divide-y space-y-1">
<div class="space-y-2 pt-2">
<a href="{{ url_for('dashboard') }}"
class="text-base text-gray-900 font-normal rounded-lg flex items-center p-2 hover:bg-gray-100 group {{ is_selected_page(url_for('dashboard')) }}">
<a hx-get="{{ url_for('dashboard') }}" hx-push-url="true" hx-target="#container"
class="text-base text-gray-900 font-normal rounded-lg flex items-center p-2 hover:bg-gray-100 group cursor-pointer {{ is_selected_page(url_for('dashboard')) }}">
<svg class="w-6 h-6 text-gray-500 group-hover:text-gray-900 transition duration-75"
fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path d="M2 10a8 8 0 018-8v8h8a8 8 0 11-16 0z"></path>
@@ -92,8 +92,8 @@
</ul>
<div class="space-y-2 pt-2">
<a href="{{ url_for('settings') }}"
class="text-base text-gray-900 font-normal rounded-lg hover:bg-gray-100 group transition duration-75 flex items-center p-2 {{ is_selected_page(url_for('settings')) }}">
<a hx-get="{{ url_for('settings') }}" hx-push-url="true" hx-target="#container"
class="text-base text-gray-900 font-normal rounded-lg hover:bg-gray-100 group transition duration-75 flex items-center p-2 cursor-pointer {{ is_selected_page(url_for('settings')) }}">
<svg class="w-6 h-6 text-gray-500 group-hover:text-gray-900 transition duration-75"
fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"
data-darkreader-inline-fill="" style="--darkreader-inline-fill:currentColor;">
@@ -110,7 +110,7 @@
</aside>
<div class="h-full w-full bg-gray-50 relative overflow-y-auto lg:ml-64">
<main>
<div class="pt-6 px-4">
<div class="pt-6 px-4" id="container">
{% block content %}
{% endblock %}
</div>

8
templates/dashboard.html Normal file
View File

@@ -0,0 +1,8 @@
{% extends 'base.html' %}
{% block content %}
{{ render_partial('partials/page/dashboard.html',
people=people, exercises=exercises) }}
{% endblock %}

View File

@@ -1,7 +1,3 @@
{% extends 'base.html' %}
{% block content %}
<script>
let layout = {
margin: { t: 0 }, xaxis: { type: 'date', showgrid: false }, yaxis: {
@@ -93,5 +89,3 @@
</div>
{{ render_partial('partials/stats.html', stats=model['Stats']) }}
{% endblock %}

View File

@@ -1,4 +1,4 @@
<div id="person-view">
<div>
<div class="flex justify-center">
<div class="bg-white shadow rounded-lg p-4 sm:w-full xl:p-8 md:w-full lg:w-10/12 xl:w-8/12 2xl:w-6/12">
@@ -22,7 +22,7 @@
{% for e in person['Exercises'] %}
<div class="flex items-center mr-4"
hx-post="{{ url_for('filter_exercises_for_person', person_id=person['PersonId']) }}"
hx-include="[name='exercise_id']" hx-target="#person-view" hx-swap="outerHTML">
hx-include="[name='exercise_id']" hx-target="#container" hx-swap="outerHTML">
<input {{ is_checked(e['ExerciseId'], selected_exercise_ids) }} type="checkbox" name="exercise_id"
value="{{ e['ExerciseId'] }}"
class="w-4 h-4 text-blue-600 bg-gray-100 rounded border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">

View File

@@ -0,0 +1,133 @@
<div class="mt-4 w-full grid grid-cols-1 md:grid-cols-2 xl:grid-cols-2 gap-4">
<div class="bg-white shadow rounded-lg p-4 sm:p-6 xl:p-8 ">
<div class="mb-4 flex items-center justify-between">
<div>
<h3 class="text-xl font-bold text-gray-900 mb-2">Users</h3>
</div>
</div>
<div class="flex flex-col">
<div class="overflow-x-auto rounded-lg">
<div class="align-middle inline-block min-w-full">
<div class="shadow overflow-hidden sm:rounded-lg">
<table class="table-fixed min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col"
class="p-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-3/5">
Name
</th>
<th scope="col"
class="p-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
</th>
</tr>
</thead>
<tbody class="bg-white" id="new-person" hx-target="closest tr"
hx-swap="outerHTML swap:0.5s">
{% for p in people %}
{{ render_partial('partials/person.html', person_id=p['PersonId'],
name=p['Name'])}}
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<form class="w-full mt-3" hx-post="{{ url_for('create_person') }}" hx-swap="beforeend" hx-target="#new-person">
<div class="flex flex-wrap -mx-3 mb-2">
<div class="grow px-3">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-city">
New user
</label>
<input
class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
type="text" name="name">
</div>
<div class="flex flex-row pt-6 px-3 w-36">
<button
class="w-full flex text-white bg-cyan-600 hover:bg-cyan-700 focus:ring-4 focus:ring-cyan-200 font-medium rounded-lg text-sm px-5 py-2.5 text-center items-center h-12"
type="submit">
<svg class="w-6 h-6 text-gray-500 group-hover:text-gray-900 transition duration-75"
fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"
data-darkreader-inline-fill="" style="--darkreader-inline-fill:currentColor;">
<path fill-rule="evenodd"
d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z"
clip-rule="evenodd"></path>
</svg>
&nbsp; Add
</button>
</div>
</div>
</form>
</div>
<div class="bg-white shadow rounded-lg p-4 sm:p-6 xl:p-8 ">
<div class="mb-4 flex items-center justify-between">
<div>
<h3 class="text-xl font-bold text-gray-900 mb-2">Exercises</h3>
</div>
</div>
<div class="flex flex-col">
<div class="overflow-x-auto rounded-lg">
<div class="align-middle inline-block min-w-full">
<div class="shadow overflow-hidden sm:rounded-lg">
<table class="table-fixed min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col"
class="p-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-3/5">
Name
</th>
<th scope="col"
class="p-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
</th>
</tr>
</thead>
<tbody class="bg-white" id="new-exercise" hx-target="closest tr"
hx-swap="outerHTML swap:0.5s">
{% for e in exercises %}
{{ render_partial('partials/exercise.html', exercise_id=e['ExerciseId'],
name=e['Name'])}}
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<form class="w-full mt-3" hx-post="{{ url_for('create_exercise') }}" hx-swap="beforeend"
hx-target="#new-exercise">
<div class="flex flex-wrap -mx-3 mb-2">
<div class="grow px-3">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-city">
New exercise
</label>
<input
class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
type="text" name="name">
</div>
<div class="flex flex-row pt-6 px-3 w-36">
<button
class="w-full flex text-white bg-cyan-600 hover:bg-cyan-700 focus:ring-4 focus:ring-cyan-200 font-medium rounded-lg text-sm px-5 py-2.5 text-center items-center h-12 cursor-pointer"
type="submit">
<svg class="w-6 h-6 text-gray-500 group-hover:text-gray-900 transition duration-75"
fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"
data-darkreader-inline-fill="" style="--darkreader-inline-fill:currentColor;">
<path fill-rule="evenodd"
d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z"
clip-rule="evenodd"></path>
</svg>
&nbsp; Add
</button>
</div>
</div>
</form>
</div>
</div>

View File

@@ -1,7 +1,7 @@
{% for p in people %}
<li>
<a href="{{ url_for('get_person' ,person_id=p['PersonId']) }}"
class="text-base text-gray-900 font-normal rounded-lg hover:bg-gray-100 flex items-center p-2 group {% if p['IsActive']==1 %} bg-gray-200 {% endif %}">
<a hx-get="{{ url_for('get_person' ,person_id=p['PersonId']) }}" hx-push-url="true" hx-target="#container" class="text-base text-gray-900 font-normal rounded-lg hover:bg-gray-100 flex items-center p-2 group cursor-pointer {% if
p['IsActive']==1 %} bg-gray-200 {% endif %}">
<svg class="w-6 h-6 text-gray-500 flex-shrink-0 group-hover:text-gray-900 transition duration-75"
fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd">

View File

@@ -2,139 +2,7 @@
{% block content %}
<div class="mt-4 w-full grid grid-cols-1 md:grid-cols-2 xl:grid-cols-2 gap-4">
<div class="bg-white shadow rounded-lg p-4 sm:p-6 xl:p-8 ">
<div class="mb-4 flex items-center justify-between">
<div>
<h3 class="text-xl font-bold text-gray-900 mb-2">Users</h3>
</div>
</div>
<div class="flex flex-col">
<div class="overflow-x-auto rounded-lg">
<div class="align-middle inline-block min-w-full">
<div class="shadow overflow-hidden sm:rounded-lg">
<table class="table-fixed min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col"
class="p-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-3/5">
Name
</th>
<th scope="col"
class="p-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
</th>
</tr>
</thead>
<tbody class="bg-white" id="new-person" hx-target="closest tr"
hx-swap="outerHTML swap:0.5s">
{% for p in people %}
{{ render_partial('partials/person.html', person_id=p['PersonId'],
name=p['Name'])}}
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<form class="w-full mt-3" hx-post="{{ url_for('create_person') }}" hx-swap="beforeend" hx-target="#new-person">
<div class="flex flex-wrap -mx-3 mb-2">
<div class="grow px-3">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-city">
New user
</label>
<input
class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
type="text" name="name">
</div>
<div class="flex flex-row pt-6 px-3 w-36">
<button
class="w-full flex text-white bg-cyan-600 hover:bg-cyan-700 focus:ring-4 focus:ring-cyan-200 font-medium rounded-lg text-sm px-5 py-2.5 text-center items-center h-12"
type="submit">
<svg class="w-6 h-6 text-gray-500 group-hover:text-gray-900 transition duration-75"
fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"
data-darkreader-inline-fill="" style="--darkreader-inline-fill:currentColor;">
<path fill-rule="evenodd"
d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z"
clip-rule="evenodd"></path>
</svg>
&nbsp; Add
</button>
</div>
</div>
</form>
</div>
<div class="bg-white shadow rounded-lg p-4 sm:p-6 xl:p-8 ">
<div class="mb-4 flex items-center justify-between">
<div>
<h3 class="text-xl font-bold text-gray-900 mb-2">Exercises</h3>
</div>
</div>
<div class="flex flex-col">
<div class="overflow-x-auto rounded-lg">
<div class="align-middle inline-block min-w-full">
<div class="shadow overflow-hidden sm:rounded-lg">
<table class="table-fixed min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col"
class="p-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-3/5">
Name
</th>
<th scope="col"
class="p-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
</th>
</tr>
</thead>
<tbody class="bg-white" id="new-exercise" hx-target="closest tr"
hx-swap="outerHTML swap:0.5s">
{% for e in exercises %}
{{ render_partial('partials/exercise.html', exercise_id=e['ExerciseId'],
name=e['Name'])}}
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<form class="w-full mt-3" hx-post="{{ url_for('create_exercise') }}" hx-swap="beforeend"
hx-target="#new-exercise">
<div class="flex flex-wrap -mx-3 mb-2">
<div class="grow px-3">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-city">
New exercise
</label>
<input
class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
type="text" name="name">
</div>
<div class="flex flex-row pt-6 px-3 w-36">
<button
class="w-full flex text-white bg-cyan-600 hover:bg-cyan-700 focus:ring-4 focus:ring-cyan-200 font-medium rounded-lg text-sm px-5 py-2.5 text-center items-center h-12 cursor-pointer"
type="submit">
<svg class="w-6 h-6 text-gray-500 group-hover:text-gray-900 transition duration-75"
fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"
data-darkreader-inline-fill="" style="--darkreader-inline-fill:currentColor;">
<path fill-rule="evenodd"
d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z"
clip-rule="evenodd"></path>
</svg>
&nbsp; Add
</button>
</div>
</div>
</form>
</div>
</div>
{{ render_partial('partials/page/settings.html',
model=model) }}
{% endblock %}