feat: month strip display, fix dashboard counter, styled month form

- Add month_strip template tag rendering JFMAMJJASOND circles,
  active months dark green, inactive light grey
- Replace raw number list in pruning_strip with visual month strip
- Restyle pruning month checkboxes as clickable circles in plant form
- Fix dashboard 'Need pruning' counter (broken filter chain always showed 0)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Stephan Kerkman 2026-05-28 15:05:13 +02:00
parent 35bf5eee70
commit 36e4570141
8 changed files with 35 additions and 9 deletions

View file

@ -13,7 +13,16 @@
.care-chip { display: inline-block; padding: .2rem .55rem; border-radius: 1rem; font-size: .8rem; margin: .15rem; } .care-chip { display: inline-block; padding: .2rem .55rem; border-radius: 1rem; font-size: .8rem; margin: .15rem; }
.pruning-strip { border-left: 4px solid #ffc107; background: #fff9c4; padding: .5rem .75rem; border-radius: 0 .375rem .375rem 0; } .pruning-strip { border-left: 4px solid #ffc107; background: #fff9c4; padding: .5rem .75rem; border-radius: 0 .375rem .375rem 0; }
.pruning-strip.overdue { border-color: #dc3545; background: #fff5f5; } .pruning-strip.overdue { border-color: #dc3545; background: #fff5f5; }
.month-checkboxes .form-check { display: inline-flex; margin-right: .5rem; } /* Month strip — display */
.month-strip { display: flex; gap: 3px; }
.month-dot { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 50%; font-size: 10px; font-weight: 700; letter-spacing: 0; background: #e9ecef; color: #adb5bd; }
.month-dot--on { background: #2d6a4f; color: #fff; }
/* Month toggle — form */
.month-toggle-group { display: flex; flex-wrap: wrap; gap: 5px; }
.month-toggle { position: relative; }
.month-toggle input[type="checkbox"] { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }
.month-toggle label { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: 50%; font-size: 13px; font-weight: 700; cursor: pointer; background: #e9ecef; color: #6c757d; transition: background .15s, color .15s; user-select: none; }
.month-toggle input:checked + label { background: #2d6a4f; color: #fff; }
</style> </style>
</head> </head>
<body> <body>

View file

@ -19,7 +19,7 @@
<div class="card text-center h-100" style="background:#ffe8cc;"> <div class="card text-center h-100" style="background:#ffe8cc;">
<div class="card-body py-3"> <div class="card-body py-3">
<div class="display-5 fw-bold" style="color:#7d4a00;"> <div class="display-5 fw-bold" style="color:#7d4a00;">
{{ overdue|length|add:due_this_month|length }} {{ needs_pruning_count }}
</div> </div>
<div class="small" style="color:#7d4a00;">Need pruning</div> <div class="small" style="color:#7d4a00;">Need pruning</div>
</div> </div>

View file

@ -0,0 +1 @@
<div class="month-strip">{% for m in months %}<span class="month-dot{% if m.active %} month-dot--on{% endif %}">{{ m.letter }}</span>{% endfor %}</div>

View file

@ -1,15 +1,14 @@
{% load plant_extras %}
<div id="pruning-strip" class="pruning-strip {% if pruning_status == 'overdue' %}overdue{% endif %} mb-3 rounded-end"> <div id="pruning-strip" class="pruning-strip {% if pruning_status == 'overdue' %}overdue{% endif %} mb-3 rounded-end">
<div class="d-flex justify-content-between align-items-start"> <div class="d-flex justify-content-between align-items-start">
<div> <div>
<strong>✂️ Pruning</strong> <strong>✂️ Pruning</strong>
{% if plant.pruning_months %} {% if plant.pruning_months %}
<div class="small"> <div class="mt-1">{% month_strip plant.pruning_months %}</div>
Scheduled: {{ plant.pruning_months|join:", " }}
</div>
{% endif %} {% endif %}
{% with plant.pruning_logs.first as last_log %} {% with plant.pruning_logs.first as last_log %}
{% if last_log %} {% if last_log %}
<div class="small text-muted">Last pruned: {{ last_log.pruned_on|date:"j M Y" }}</div> <div class="small text-muted mt-1">Last pruned: {{ last_log.pruned_on|date:"j M Y" }}</div>
{% endif %} {% endif %}
{% endwith %} {% endwith %}
</div> </div>

View file

@ -42,11 +42,11 @@
<div class="mb-3"> <div class="mb-3">
<label class="form-label fw-semibold">Pruning months</label> <label class="form-label fw-semibold">Pruning months</label>
<div class="month-checkboxes d-flex flex-wrap gap-1"> <div class="month-toggle-group">
{% for widget in form.pruning_months %} {% for widget in form.pruning_months %}
<div class="form-check form-check-inline border rounded px-2 py-1"> <div class="month-toggle">
{{ widget.tag }} {{ widget.tag }}
<label class="form-check-label" for="{{ widget.id_for_label }}">{{ widget.choice_label }}</label> <label for="{{ widget.id_for_label }}">{{ widget.choice_label|slice:":1" }}</label>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>

View file

View file

@ -0,0 +1,16 @@
from django import template
register = template.Library()
_LETTERS = list('JFMAMJJASOND')
@register.inclusion_tag('plants/partials/month_strip.html')
def month_strip(pruning_months):
months_set = set(pruning_months or [])
return {
'months': [
{'letter': _LETTERS[i], 'active': (i + 1) in months_set}
for i in range(12)
]
}

View file

@ -21,5 +21,6 @@ def dashboard(request):
'total_plants': len(all_plants), 'total_plants': len(all_plants),
'overdue': overdue, 'overdue': overdue,
'due_this_month': due_this_month, 'due_this_month': due_this_month,
'needs_pruning_count': len(overdue) + len(due_this_month),
'today': today, 'today': today,
}) })