Compare commits
2 commits
d522f23b55
...
5c7586bb9a
Author | SHA1 | Date | |
---|---|---|---|
5c7586bb9a | |||
3c3cfc38ba |
8 changed files with 256 additions and 188 deletions
|
@ -1,7 +1,9 @@
|
|||
from frontend.classes import NavSection, NavItem
|
||||
from frontend.classes import NavSection, NavItem, DashboardSection
|
||||
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
# Sidebar navigation items
|
||||
|
||||
dreams_section = NavSection("Dreams")
|
||||
|
||||
dreams_items = {
|
||||
|
@ -13,4 +15,10 @@ dreams_items = {
|
|||
for _, item in dreams_items.items():
|
||||
dreams_section.add_item(item)
|
||||
|
||||
NAV_SECTIONS = [dreams_section]
|
||||
NAV_SECTIONS = [dreams_section]
|
||||
|
||||
# Dashboard sections
|
||||
|
||||
dreams_section = DashboardSection("Dreams", "dreams/dashboard_section.html")
|
||||
|
||||
DASHBOARD_SECTIONS = [dreams_section]
|
78
dreams/templates/dreams/dashboard_section.html
Normal file
78
dreams/templates/dreams/dashboard_section.html
Normal file
|
@ -0,0 +1,78 @@
|
|||
{% load dream_stats %}
|
||||
<!-- Dream Stats -->
|
||||
<div class="row">
|
||||
<!-- Total Dreams -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-primary shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Dream count (total)</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">{% total_dreams %}</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-book fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Weekly Dreams -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-success shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">Dreams (weekly)</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">{% weekly_dreams %}</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-calendar fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Special Dreams -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-info shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Special Dreams (lucid / wet)</div>
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-auto">
|
||||
{% special_dreams_weekly as weekly %}
|
||||
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">
|
||||
{{ weekly.0 }} / {{ weekly.1 }} <sub><i>(weekly)</i></sub>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="{{ moodobj.icon }} fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Most common theme -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-warning shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Most Common Theme (weekly)</div>
|
||||
{% most_common_theme_weekly as theme %}
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">
|
||||
{{ theme.0 }} <sub><i>({{ theme.1 }})</i></sub>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-bed fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,3 +1,6 @@
|
|||
from django.template.loader import render_to_string
|
||||
|
||||
|
||||
class NavSection:
|
||||
def __init__(self, name, order=100):
|
||||
self.name = name
|
||||
|
@ -16,22 +19,37 @@ class NavSection:
|
|||
self.items.sort(key=lambda x: x.order)
|
||||
|
||||
for item in self.items:
|
||||
html += """
|
||||
html += (
|
||||
"""
|
||||
<!-- Nav Item -->
|
||||
<li class="nav-item""" + (" active" if item.name == active else "") + f"""">
|
||||
<li class="nav-item"""
|
||||
+ (" active" if item.name == active else "")
|
||||
+ f"""">
|
||||
<a class="nav-link" href="{item.url}">
|
||||
<i class="{item.icon}"></i>
|
||||
<span>{item.name}</span>
|
||||
</a>
|
||||
</li>
|
||||
"""
|
||||
)
|
||||
|
||||
return html
|
||||
|
||||
|
||||
class NavItem:
|
||||
def __init__(self, name, url, icon="fas fa-fw fa-smile", title=None, order=100):
|
||||
self.name = name
|
||||
self.url = url
|
||||
self.icon = icon
|
||||
self.title = title or name
|
||||
self.order = order
|
||||
self.order = order
|
||||
|
||||
|
||||
class DashboardSection:
|
||||
def __init__(self, name, template, context=None):
|
||||
self.name = name
|
||||
self.template = template
|
||||
self.context = context or {}
|
||||
|
||||
def get_html(self, request):
|
||||
return render_to_string(self.template, self.context, request)
|
||||
|
|
|
@ -1,178 +1,6 @@
|
|||
{% extends "frontend/base.html" %}
|
||||
{% load mood_stats %}
|
||||
{% load dream_stats %}
|
||||
{% load dashboard %}
|
||||
{% block "content" %}
|
||||
<h2>Moods</h2>
|
||||
<!-- Mood calendar heatmap -->
|
||||
<div class="row">
|
||||
<div class="col-xl-12 mb-4">
|
||||
<div class="card shadow">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Mood Calendar</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="mood-count-heatmap"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Mood cards -->
|
||||
<div class="row">
|
||||
<!-- Status count -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-primary shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Status count (total)</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">{% total_moods %}</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-book fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Current Streak Length -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-success shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">Current Streak Length</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">
|
||||
{% current_streak %} <sub>days</sub>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-calendar fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Average mood -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-info shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Average mood (weekly)</div>
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-auto">
|
||||
{% average_mood_weekly as mood %} {% closest_mood mood as moodobj %}
|
||||
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">
|
||||
{{ moodobj }} <sub><i>({{ mood|floatformat:2 }})</i></sub>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="{{ moodobj.icon }} fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Most common activity -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-warning shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Most Common Activity (weekly)</div>
|
||||
{% most_common_activity_weekly as activity %}
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">
|
||||
{{ activity.0 }}<sub><i>({{ activity.1 }})</i></sub>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="{{ activity.0.icon }} fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Dreams</h2>
|
||||
<!-- Dream Stats -->
|
||||
<div class="row">
|
||||
<!-- Total Dreams -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-primary shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Dream count (total)</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">{% total_dreams %}</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-book fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Weekly Dreams -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-success shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">Dreams (weekly)</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">{% weekly_dreams %}</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-calendar fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Special Dreams -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-info shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Special Dreams (lucid / wet)</div>
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-auto">
|
||||
{% special_dreams_weekly as weekly %}
|
||||
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">
|
||||
{{ weekly.0 }} / {{ weekly.1 }} <sub><i>(weekly)</i></sub>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="{{ moodobj.icon }} fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Most common theme -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-warning shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Most Common Theme (weekly)</div>
|
||||
{% most_common_theme_weekly as theme %}
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">
|
||||
{{ theme.0 }} <sub><i>({{ theme.1 }})</i></sub>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-bed fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% dashboard as dashboard %}
|
||||
{{ dashboard | safe }}
|
||||
{% endblock "content" %}
|
||||
|
|
33
frontend/templatetags/dashboard.py
Normal file
33
frontend/templatetags/dashboard.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
from django import template
|
||||
from django.conf import settings
|
||||
|
||||
from importlib import import_module
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def dashboard(context):
|
||||
sections = []
|
||||
|
||||
for module in settings.CORE_MODULES + settings.ENABLED_MODULES:
|
||||
try:
|
||||
features = import_module(f"{module}.features")
|
||||
try:
|
||||
sections += features.DASHBOARD_SECTIONS
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
dashboard_html = ""
|
||||
|
||||
for section in sections:
|
||||
dashboard_html += f"<h2>{section.name}</h2>"
|
||||
|
||||
dashboard_html += section.get_html(context["request"])
|
||||
|
||||
if section != sections[-1]:
|
||||
dashboard_html += '<hr class="dashboard-divider">'
|
||||
|
||||
return dashboard_html
|
|
@ -1,18 +1,28 @@
|
|||
from frontend.classes import NavSection, NavItem
|
||||
from frontend.classes import NavSection, NavItem, DashboardSection
|
||||
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
# Sidebar navigation items
|
||||
|
||||
mood_section = NavSection("Mood")
|
||||
|
||||
mood_items = {
|
||||
"mood_status_list": NavItem("Status List", reverse_lazy("mood:status_list")),
|
||||
"mood_activity_list": NavItem("Activities", reverse_lazy("mood:activity_list")),
|
||||
"mood_mood_list": NavItem("Moods", reverse_lazy("mood:mood_list")),
|
||||
"mood_notification_list": NavItem("Notifications", reverse_lazy("mood:notification_list")),
|
||||
"mood_statistics": NavItem("Statistics", reverse_lazy("mood:statistics"))
|
||||
"mood_notification_list": NavItem(
|
||||
"Notifications", reverse_lazy("mood:notification_list")
|
||||
),
|
||||
"mood_statistics": NavItem("Statistics", reverse_lazy("mood:statistics")),
|
||||
}
|
||||
|
||||
for _, item in mood_items.items():
|
||||
mood_section.add_item(item)
|
||||
|
||||
NAV_SECTIONS = [mood_section]
|
||||
NAV_SECTIONS = [mood_section]
|
||||
|
||||
# Dashboard sections
|
||||
|
||||
mood_section = DashboardSection("Moods", "mood/dashboard_section.html")
|
||||
|
||||
DASHBOARD_SECTIONS = [mood_section]
|
||||
|
|
94
mood/templates/mood/dashboard_section.html
Normal file
94
mood/templates/mood/dashboard_section.html
Normal file
|
@ -0,0 +1,94 @@
|
|||
{% load mood_stats %}
|
||||
|
||||
<!-- Mood calendar heatmap -->
|
||||
<div class="row">
|
||||
<div class="col-xl-12 mb-4">
|
||||
<div class="card shadow">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Mood Calendar</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="mood-count-heatmap"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Mood cards -->
|
||||
<div class="row">
|
||||
<!-- Status count -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-primary shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Status count (total)</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">{% total_moods %}</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-book fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Current Streak Length -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-success shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">Current Streak Length</div>
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">
|
||||
{% current_streak %} <sub>days</sub>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="fas fa-calendar fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Average mood -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-info shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Average mood (weekly)</div>
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-auto">
|
||||
{% average_mood_weekly as mood %} {% closest_mood mood as moodobj %}
|
||||
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">
|
||||
{{ moodobj }} <sub><i>({{ mood|floatformat:2 }})</i></sub>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="{{ moodobj.icon }} fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Most common activity -->
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card border-left-warning shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Most Common Activity (weekly)</div>
|
||||
{% most_common_activity_weekly as activity %}
|
||||
<div class="h5 mb-0 font-weight-bold text-gray-800">
|
||||
{{ activity.0 }}<sub><i>({{ activity.1 }})</i></sub>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<i class="{{ activity.0.icon }} fa-2x text-gray-300"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -79,14 +79,13 @@
|
|||
<b>{{ activitycategory.name }}</b>
|
||||
</p>
|
||||
{% for activity in activitycategory.activity_set.all|dictsort:"name" %}
|
||||
{% if not activity.hidden %}
|
||||
<p {% if activity.hidden %}style="display: none;"{% endif %}>
|
||||
<input type="checkbox"
|
||||
{% if activity in object.activity_set %}checked{% endif %}
|
||||
value="{{ activity.id }}"
|
||||
name="activities">
|
||||
<i class="{{ activity.icon }}" style="color:{{ activity.color }};"></i> {{ activity }}
|
||||
<br>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% other_activities as activities %}
|
||||
|
|
Loading…
Reference in a new issue