merge experimental #1
@ -1,35 +1,58 @@
|
|||||||
{% extends 'core/base.html' %}
|
{% extends 'core/base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% load widget_tweaks %}
|
||||||
|
{% block title %}
|
||||||
|
Medwings | Log In
|
||||||
|
{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="flex flex-col justify-center items-center gap-2 py-4">
|
<div class="flex flex-col justify-center items-center gap-2 py-4">
|
||||||
{% if form.errors %}
|
<h1>Log In</h1>
|
||||||
<div class="status-message error">
|
|
||||||
<p>Your username and password didn't match. Please try again.</p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if next %}
|
|
||||||
<div class="status-message error">
|
|
||||||
{% if user.is_authenticated %}
|
|
||||||
<p>Your account doesn't have access to this page. To proceed,
|
|
||||||
please login with an account that has access.</p>
|
|
||||||
{% else %}
|
|
||||||
<p>Please <a href="{% url 'login' %}">log in</a> to see this page.</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<form method="post" action="{% url 'login' %}">
|
<form method="post" action="{% url 'login' %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<fieldset class="border border-accent p-4">
|
<fieldset class="flex flex-col gap-4 items-center max-w-sm">
|
||||||
<legend>Please enter your login details</legend>
|
<legend>Please enter your login details</legend>
|
||||||
<div class="grid grid-cols-4 justify-center items-center gap-2">
|
|
||||||
<div class="col-span-1">{{ form.username.label_tag }}</div>
|
{% if form.non_field_errors %}
|
||||||
<div class="col-span-3">{{ form.username }}</div>
|
<div class="flex flex-col gap-2 status-message error">
|
||||||
<div class="col-span-1">{{ form.password.label_tag }}</div>
|
{% for error in form.non_field_errors %}
|
||||||
<div class="col-span-3">{{ form.password }}</div>
|
<p class="error">{{ error }}</p>
|
||||||
<input class="col-span-4" type="submit" value="Log In">
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-8">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
{% render_field form.username|add_error_class:"error" %}
|
||||||
|
<label class="text-sm text-accent-800 font-semibold" for="{{ form.username.id_for_label }}">
|
||||||
|
{% render_field form.username.label %}
|
||||||
|
</label>
|
||||||
|
{% if form.username.errors %}
|
||||||
|
<div class="flex flex-col gap-2 status-message error">
|
||||||
|
{% for error in form.username.errors %}
|
||||||
|
<p class="error">{{ error }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
{% render_field form.password|add_error_class:"error" %}
|
||||||
|
<label class="text-sm text-accent-800 font-semibold" for="{{ form.password.id_for_label }}">
|
||||||
|
{% render_field form.password.label %}
|
||||||
|
</label>
|
||||||
|
{% if form.password.errors %}
|
||||||
|
<div class="flex flex-col gap-2 status-message error">
|
||||||
|
{% for error in form.password.errors %}
|
||||||
|
<p class="error">{{ error }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" name="next" value="{{ next }}">
|
|
||||||
|
<input class="max-w-64" type="submit" value="Log In">
|
||||||
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ ALLOWED_HOSTS = []
|
|||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
|
'widget_tweaks',
|
||||||
'core',
|
'core',
|
||||||
'authentication',
|
'authentication',
|
||||||
'medwings',
|
'medwings',
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 4.2.3 on 2023-07-29 18:28
|
# Generated by Django 4.2.3 on 2023-07-30 21:15
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from medwings.models import Profile
|
from medwings.models import Profile, RespirationScoreRecord
|
||||||
|
|
||||||
|
|
||||||
class ProfileForm(forms.ModelForm):
|
class ProfileForm(forms.ModelForm):
|
||||||
@ -10,3 +10,9 @@ class ProfileForm(forms.ModelForm):
|
|||||||
widgets = {
|
widgets = {
|
||||||
'date_of_birth': forms.DateInput(attrs={'type': 'date'}),
|
'date_of_birth': forms.DateInput(attrs={'type': 'date'}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RespirationScoreForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = RespirationScoreRecord
|
||||||
|
fields = ['value_severity']
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 4.2.3 on 2023-07-29 18:28
|
# Generated by Django 4.2.3 on 2023-07-30 21:15
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
@ -79,7 +79,8 @@ class Migration(migrations.Migration):
|
|||||||
('blood_pressure_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.bloodpressurerecord')),
|
('blood_pressure_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.bloodpressurerecord')),
|
||||||
('body_temp_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.bodytemprecord')),
|
('body_temp_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.bodytemprecord')),
|
||||||
('heart_rate_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.heartraterecord')),
|
('heart_rate_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.heartraterecord')),
|
||||||
('respiration_score_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.spo2levelrecord')),
|
('respiration_score_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.respirationscorerecord')),
|
||||||
|
('spo2_level_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.spo2levelrecord')),
|
||||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -119,3 +119,5 @@ class MewsRecord(models.Model):
|
|||||||
mews_value += 0
|
mews_value += 0
|
||||||
else:
|
else:
|
||||||
mews_value += 2
|
mews_value += 2
|
||||||
|
|
||||||
|
return mews_value
|
||||||
|
191
app/medwings/templates/medwings/mews-continue.html
Normal file
191
app/medwings/templates/medwings/mews-continue.html
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
{% extends 'core/base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% load widget_tweaks %}
|
||||||
|
{% block title %}
|
||||||
|
Medwings | Take a measurement
|
||||||
|
{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="flex flex-col justify-center items-center gap-2 py-4 mx-4 max-w-4xl">
|
||||||
|
<h1>Record your health status</h1>
|
||||||
|
<div id="pageContainer" class="grid grid-cols-3 gap-6 text-xl justify-center items-center w-full p-4 border rounded-md">
|
||||||
|
<div class="font-semibold text-center sm:text-start col-span-2">
|
||||||
|
<p>Blood Pressure (systolic)</p>
|
||||||
|
</div>
|
||||||
|
<div id="bloodPressureLoader" class="loader h-1 bg-accent loader--loading"></div>
|
||||||
|
<div id="bloodPressureValue" class="font-bold text-end hidden">
|
||||||
|
<p><span id="bloodPressureValueNumber"></span> mmHG</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-3 h-px bg-secondary"></div>
|
||||||
|
<div class="font-semibold text-center sm:text-start col-span-2">
|
||||||
|
<p>Body Temperature</p>
|
||||||
|
</div>
|
||||||
|
<div id="bodyTempLoader" class="loader h-1 bg-accent loader--loading"></div>
|
||||||
|
<div id="bodyTempValue" class="font-bold text-end hidden">
|
||||||
|
<p><span id="bodyTempValueNumber"></span> °C</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-3 h-px bg-secondary"></div>
|
||||||
|
<div class="font-semibold text-center sm:text-start col-span-2">
|
||||||
|
<p>Heart Rate</p>
|
||||||
|
</div>
|
||||||
|
<div id="heartRateLoader" class="loader h-1 bg-accent loader--loading"></div>
|
||||||
|
<div id="heartRateValue" class="font-bold text-end hidden">
|
||||||
|
<p><span id="heartRateValueNumber"></span> bpm</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-3 h-px bg-secondary"></div>
|
||||||
|
<div class="font-semibold text-center sm:text-start col-span-2">
|
||||||
|
<p>Blood Oxygenation</p>
|
||||||
|
</div>
|
||||||
|
<div id="spo2Loader" class="loader h-1 bg-accent loader--loading"></div>
|
||||||
|
<div id="spo2Value" class="font-bold text-end hidden">
|
||||||
|
<p><span id="spo2ValueNumber"></span> %</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-3 h-px bg-secondary"></div>
|
||||||
|
<div class="font-semibold text-center sm:text-start col-span-2">
|
||||||
|
<p>Respiration Score</p>
|
||||||
|
</div>
|
||||||
|
<div id="respirationScoreLoader" class="loader h-1 bg-accent loader--loading"></div>
|
||||||
|
<div id="respirationScoreValue" class="font-bold text-end hidden">
|
||||||
|
<p><span id="respirationScoreValueNumber"></span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-span-3 h-0.5 bg-secondary"></div>
|
||||||
|
<div class="font-semibold text-center sm:text-start col-span-2">
|
||||||
|
<p>MEWS</p>
|
||||||
|
</div>
|
||||||
|
<div id="mewsLoader" class="loader h-1 bg-accent loader--loading"></div>
|
||||||
|
<div id="mewsValue" class="font-bold text-end hidden">
|
||||||
|
<p><span id="mewsValueNumber"></span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
const elements = {
|
||||||
|
"bloodPressure": {
|
||||||
|
"loader": document.getElementById("bloodPressureLoader"),
|
||||||
|
"value": document.getElementById("bloodPressureValue"),
|
||||||
|
"number": document.getElementById("bloodPressureValueNumber")
|
||||||
|
},
|
||||||
|
"bodyTemp": {
|
||||||
|
"loader": document.getElementById("bodyTempLoader"),
|
||||||
|
"value": document.getElementById("bodyTempValue"),
|
||||||
|
"number": document.getElementById("bodyTempValueNumber")
|
||||||
|
},
|
||||||
|
"heartRate": {
|
||||||
|
"loader": document.getElementById("heartRateLoader"),
|
||||||
|
"value": document.getElementById("heartRateValue"),
|
||||||
|
"number": document.getElementById("heartRateValueNumber")
|
||||||
|
},
|
||||||
|
"spo2": {
|
||||||
|
"loader": document.getElementById("spo2Loader"),
|
||||||
|
"value": document.getElementById("spo2Value"),
|
||||||
|
"number": document.getElementById("spo2ValueNumber")
|
||||||
|
},
|
||||||
|
"respirationScore": {
|
||||||
|
"loader": document.getElementById("respirationScoreLoader"),
|
||||||
|
"value": document.getElementById("respirationScoreValue"),
|
||||||
|
"number": document.getElementById("respirationScoreValueNumber")
|
||||||
|
},
|
||||||
|
"mews": {
|
||||||
|
"loader": document.getElementById("mewsLoader"),
|
||||||
|
"value": document.getElementById("mewsValue"),
|
||||||
|
"number": document.getElementById("mewsValueNumber")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function showError(message) {
|
||||||
|
let pageContainerDiv = document.getElementById("pageContainer");
|
||||||
|
pageContainerDiv.innerHTML = `<div class="col-span-3 flex justify-center items-center status-message error"><p>${message}</p></div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageTimeout = 10 * 60 * 1000;
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!fetchingComplete)
|
||||||
|
showError('Your measurement timed out. Please <a class="underline" href="/mews/init/">start again</a>.')
|
||||||
|
}, pageTimeout);
|
||||||
|
|
||||||
|
let fetchingData = false;
|
||||||
|
let fetchingComplete = false;
|
||||||
|
const pollingInterval = 5000;
|
||||||
|
let currentData = {
|
||||||
|
"blood_pressure_value": null,
|
||||||
|
"body_temp_value": null,
|
||||||
|
"heart_rate_value": null,
|
||||||
|
"spo2_level_value": null,
|
||||||
|
"respiration_score_value": null,
|
||||||
|
"mews_value": null
|
||||||
|
};
|
||||||
|
|
||||||
|
async function fetchData() {
|
||||||
|
if (fetchingData || fetchingComplete) return;
|
||||||
|
|
||||||
|
fetchingFata = true;
|
||||||
|
fetch("{% url 'mews-status' %}")
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('There was an error while retrieving your data.');
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
const names = {
|
||||||
|
"blood_pressure_value": "bloodPressure",
|
||||||
|
"body_temp_value": "bodyTemp",
|
||||||
|
"heart_rate_value": "heartRate",
|
||||||
|
"spo2_level_value": "spo2",
|
||||||
|
"respiration_score_value": "respirationScore",
|
||||||
|
"mews_value": "mews"
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let type of Object.keys(names)) {
|
||||||
|
if (currentData[type] === null && data[type] !== null) {
|
||||||
|
currentData[type] = data[type];
|
||||||
|
setTimeout(() => {
|
||||||
|
loadValue(names[type], data[type])
|
||||||
|
}, Math.floor(Math.random() * (1500 - 500 + 1)) + 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.values(currentData).every(value => value !== null)) {
|
||||||
|
fetchingComplete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchingData = false;
|
||||||
|
|
||||||
|
if (!fetchingComplete) {
|
||||||
|
setTimeout(() => {
|
||||||
|
fetchData();
|
||||||
|
}, pollingInterval)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
showError(error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData();
|
||||||
|
|
||||||
|
function loadValue(element, value) {
|
||||||
|
const loaderDiv = elements[element]["loader"];
|
||||||
|
const valueDiv = elements[element]["value"];
|
||||||
|
const numberSpan = elements[element]["number"];
|
||||||
|
|
||||||
|
loaderDiv.classList.remove("loader--loading");
|
||||||
|
loaderDiv.classList.add("loader--finished");
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
loaderDiv.classList.remove("loader--finished");
|
||||||
|
loaderDiv.classList.add("hidden");
|
||||||
|
|
||||||
|
valueDiv.classList.remove('hidden');
|
||||||
|
valueDiv.classList.add('loader--value');
|
||||||
|
numberSpan.textContent = value;
|
||||||
|
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock content %}
|
43
app/medwings/templates/medwings/mews-init.html
Normal file
43
app/medwings/templates/medwings/mews-init.html
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{% extends 'core/base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% load widget_tweaks %}
|
||||||
|
{% block title %}
|
||||||
|
Medwings | Take a measurement
|
||||||
|
{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="flex flex-col justify-center items-center gap-2 py-4 mx-4 max-w-4xl">
|
||||||
|
<h1>Record your health status</h1>
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<fieldset class="flex flex-col gap-4 items-center">
|
||||||
|
<legend>To get started, please answer the following question:</legend>
|
||||||
|
|
||||||
|
{% if respiration_score_form.non_field_errors %}
|
||||||
|
<div class="flex flex-col gap-2 status-message error">
|
||||||
|
{% for error in respiration_score_form.non_field_errors %}
|
||||||
|
<p class="error">{{ error }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex flex-col sm:flex-row gap-x-2">
|
||||||
|
<label class="font-semibold" for="{{ respiration_score_form.value_severity.id_for_label }}">
|
||||||
|
Are you experiencing any shortness of breath?
|
||||||
|
</label>
|
||||||
|
{% render_field respiration_score_form.value_severity|add_error_class:"error" %}
|
||||||
|
</div>
|
||||||
|
{% if respiration_score_form.value_severity.errors %}
|
||||||
|
<div class="flex flex-col gap-2 status-message error">
|
||||||
|
{% for error in respiration_score_form.value_severity.errors %}
|
||||||
|
<p class="error">{{ error }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<button class="btn" type="submit">Continue</button>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
@ -5,5 +5,7 @@ from . import views
|
|||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", views.index, name="home"),
|
path("", views.index, name="home"),
|
||||||
path("dashboard/", views.dashboard, name="dashboard"),
|
path("dashboard/", views.dashboard, name="dashboard"),
|
||||||
|
path("mews/init/", views.mews_init, name="mews-init"),
|
||||||
|
path("mews/continue/", views.mews_continue, name="mews-continue"),
|
||||||
path("mews/status/", views.mews_status, name="mews-status"),
|
path("mews/status/", views.mews_status, name="mews-status"),
|
||||||
]
|
]
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.shortcuts import render
|
from django.shortcuts import redirect, render
|
||||||
from django.http import HttpResponse, JsonResponse
|
from django.http import HttpResponse, JsonResponse
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.views.decorators.http import require_http_methods
|
from django.views.decorators.http import require_http_methods
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
from . import forms
|
||||||
|
|
||||||
|
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
@ -14,10 +15,41 @@ def index(request):
|
|||||||
return render(request, 'medwings/index.html')
|
return render(request, 'medwings/index.html')
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
def dashboard(request):
|
def dashboard(request):
|
||||||
return render(request, 'medwings/dashboard.html')
|
return render(request, 'medwings/dashboard.html')
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@require_http_methods(["GET", "POST"])
|
||||||
|
def mews_init(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
respiration_score_form = forms.RespirationScoreForm(request.POST)
|
||||||
|
|
||||||
|
if respiration_score_form.is_valid():
|
||||||
|
respiration_score = respiration_score_form.save(commit=False)
|
||||||
|
respiration_score.recorded = timezone.now()
|
||||||
|
respiration_score.user = request.user
|
||||||
|
respiration_score.save()
|
||||||
|
|
||||||
|
return redirect('mews-continue')
|
||||||
|
|
||||||
|
else:
|
||||||
|
respiration_score_form = forms.RespirationScoreForm()
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'respiration_score_form': respiration_score_form,
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, 'medwings/mews-init.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def mews_continue(request):
|
||||||
|
return render(request, 'medwings/mews-continue.html')
|
||||||
|
|
||||||
|
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
def mews_status(request):
|
def mews_status(request):
|
||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
@ -60,6 +92,7 @@ def mews_status(request):
|
|||||||
body_temp_record=body_temp_record,
|
body_temp_record=body_temp_record,
|
||||||
heart_rate_record=heart_rate_record,
|
heart_rate_record=heart_rate_record,
|
||||||
respiration_score_record=respiration_score_record,
|
respiration_score_record=respiration_score_record,
|
||||||
|
spo2_level_record=spo2_level_record
|
||||||
)
|
)
|
||||||
mews_record.save()
|
mews_record.save()
|
||||||
data['mews_value'] = mews_record.value_n
|
data['mews_value'] = mews_record.value_n
|
||||||
|
@ -2,6 +2,8 @@ asgiref==3.7.2
|
|||||||
certifi==2023.7.22
|
certifi==2023.7.22
|
||||||
charset-normalizer==3.2.0
|
charset-normalizer==3.2.0
|
||||||
Django==4.2.3
|
Django==4.2.3
|
||||||
|
django-widget-tweaks==1.4.12
|
||||||
|
djangorestframework==3.14.0
|
||||||
idna==3.4
|
idna==3.4
|
||||||
psycopg==3.1.9
|
psycopg==3.1.9
|
||||||
psycopg-binary==3.1.9
|
psycopg-binary==3.1.9
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 4.2.3 on 2023-07-29 18:35
|
# Generated by Django 4.2.3 on 2023-07-30 21:15
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
@ -47,7 +47,22 @@ input[type="submit"] {
|
|||||||
@apply hover:drop-shadow-xl;
|
@apply hover:drop-shadow-xl;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.btn {
|
input.error {
|
||||||
|
@apply border border-failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
@apply border border-accent p-4;
|
||||||
|
}
|
||||||
|
legend {
|
||||||
|
@apply text-sm text-accent-600 px-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
@apply underline text-primary-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@apply rounded rounded-lg drop-shadow-md px-4 py-2;
|
@apply rounded rounded-lg drop-shadow-md px-4 py-2;
|
||||||
@apply bg-accent-600;
|
@apply bg-accent-600;
|
||||||
@ -55,7 +70,7 @@ a.btn {
|
|||||||
@apply hover:drop-shadow-xl;
|
@apply hover:drop-shadow-xl;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.btn-outline {
|
.btn-outline {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@apply rounded rounded-lg drop-shadow-md px-4 py-2;
|
@apply rounded rounded-lg drop-shadow-md px-4 py-2;
|
||||||
@apply text-accent-600 bg-accent-600/10;
|
@apply text-accent-600 bg-accent-600/10;
|
||||||
@ -93,10 +108,68 @@ div.status-message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
div.status-message.error {
|
div.status-message.error {
|
||||||
@apply bg-failure/50;
|
@apply font-semibold bg-failure/50 border border-failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.call-to-action-box {
|
div.call-to-action-box {
|
||||||
@apply bg-gradient-to-r from-secondary-300/75 to-secondary-500/75;
|
@apply bg-gradient-to-r from-secondary-300/75 to-secondary-500/75;
|
||||||
@apply rounded-md py-4 px-6;
|
@apply rounded-md py-4 px-6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loader--loading {
|
||||||
|
animation: loading 2s infinite linear;
|
||||||
|
}
|
||||||
|
.loader--finished {
|
||||||
|
animation: finished 1.5s ease-in both;
|
||||||
|
}
|
||||||
|
.loader--value {
|
||||||
|
animation: loaded 1s ease-out both;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loading {
|
||||||
|
0% {
|
||||||
|
transform: scaleX(0%) translateX(-100%);
|
||||||
|
transform-origin: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scaleX(50%);
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: scaleX(0%) translateX(100%);
|
||||||
|
transform-origin: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes finished {
|
||||||
|
0% {
|
||||||
|
transform: scaleX(0%);
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scaleX(100%);
|
||||||
|
transform-origin: center;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: scaleX(100%) translateX(1000%);
|
||||||
|
transform-origin: right;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loaded {
|
||||||
|
0% {
|
||||||
|
transform: translateX(1000%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translateX(0%);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
const navbarToggleButton = document.querySelector('#navbarToggleButton');
|
const navbarToggleButton = document.querySelector('#navbarToggleButton');
|
||||||
|
|
||||||
button.addEventListener('click', () => {
|
//button.addEventListener('click', () => {
|
||||||
if (button.textContent === 'Click me') {
|
//if (button.textContent === 'Click me') {
|
||||||
button.textContent = 'Clicked';
|
//button.textContent = 'Clicked';
|
||||||
} else {
|
//} else {
|
||||||
button.textContent = 'Click me';
|
//button.textContent = 'Click me';
|
||||||
}
|
//}
|
||||||
});
|
//});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user