From 9b2308aeac6014969271ee0dd2b7ce9c6efaf2c6 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 16 Apr 2026 13:25:51 +0000 Subject: [PATCH] Auto commit: 2026-04-16T13:25:51.679Z --- core/__pycache__/views.cpython-311.pyc | Bin 12602 -> 19904 bytes core/templates/core/entry_list.html | 117 ++++++++++++- core/templates/core/index.html | 33 +++- core/views.py | 131 ++++++++++++++ static/css/custom.css | 225 +++++++++++++++++++++++++ staticfiles/css/custom.css | 225 +++++++++++++++++++++++++ 6 files changed, 728 insertions(+), 3 deletions(-) diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 1df2733d4df78c44deee548faa95f34ca92da2cc..65694602c6b7022422a93f41530718b00f6539f7 100644 GIT binary patch delta 7520 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
(SC6AGjFcY3C{J~PIQPrdHzyQAMX2LTs znIFZ}S~$PkZa$7qeBY;DT>8@`_-*&0cTDjKWjamJz2T@u4U+r3sJQ1)peUhjrl}YR zp4SyPep#v)4y%f9uZd!NUwuo^-Ni;i2jMI%4X$s|*IBiEokcS10~X-!;D+R7Tz`ck zKZkWgRrqf>6aF-Gjcs~T%|-M^je=vJu#QJFBfdtfD8acsJKL{NKwOoT&&65N6Usfx z-I`k$m*DR`ojDy~$zm||R02vXz9B5Y*5NMmDymCH_~!6|n5mmugR6UgPd%yQ44mHA z`|@YBV?Cip_=4~y!6d{9a|GRpdD5sPEacyPnG`+V@+dAq<4D&09@p26FhA165?jSN z@&Z&xb8HsoM*nA$F History

{% if is_demo_mode %}Demo momentum entries{% else %}Your momentum entries{% endif %}

-

{% if is_demo_mode %}Browse the seeded sample history, then create an account when you want private tracking.{% else %}Filter your private check-ins by category and open any one for its detail view.{% endif %}

+

{% if is_demo_mode %}Browse the seeded sample history, then create an account when you want private tracking.{% else %}Filter your private check-ins, spot patterns faster, and open any entry for the full detail view.{% endif %}

Back to dashboard @@ -35,6 +35,37 @@
+
+
+
+ Total check-ins + {{ history_overview.total_entries }} +

{% if history_overview.latest_entry %}Latest: {{ history_overview.latest_entry.entry_date|date:"M j, Y" }}{% else %}No entries yet{% endif %}

+
+
+
+
+ Avg. momentum + {{ history_overview.avg_momentum }}/10 +

Focus {{ history_overview.avg_focus }}/10 · Energy {{ history_overview.avg_energy }}/10

+
+
+
+
+ Current streak + {{ history_overview.streak }} day{{ history_overview.streak|pluralize }} +

Top lane: {{ history_overview.top_category }}

+
+
+
+
+ Deep work total + {{ history_overview.total_minutes }}m +

{% if is_demo_mode %}Sample time invested{% else %}Time protected for focused work{% endif %}

+
+
+
+
All categories {% for category in categories %} @@ -43,10 +74,85 @@
{% if entries %} +
+
+
+
+
+ Recent pattern +

Last {{ recent_activity|length }} check-ins at a glance

+

Quick comparison bars make it easier to notice whether focus, energy, or deep work is drifting.

+
+
+
+ {% for item in recent_activity %} +
+
+
+ {{ item.entry.category.name }} +

{{ item.entry.title }}

+
+ +
+
+
+ Focus +
+ {{ item.entry.focus_score }}/10 +
+
+ Energy +
+ {{ item.entry.energy_score }}/10 +
+
+ Deep work +
+ {{ item.entry.deep_work_minutes }}m +
+
+
+ {% endfor %} +
+
+
+
+ +
+
+
{% for entry in entries %}
-
+
{{ entry.category.name }} @@ -58,6 +164,13 @@ Energy {{ entry.energy_score }}/10 {{ entry.deep_work_minutes }} min
+
+
+ Momentum score + {{ entry.momentum_score }}/10 +
+ View details +
{% endfor %} diff --git a/core/templates/core/index.html b/core/templates/core/index.html index 81b349f..89ad168 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -211,6 +211,16 @@ {% if is_demo_mode %}Open demo history{% else %}Open your history{% endif %}
+
+
+ Compare your week +

Two bars per day show whether focus and energy are moving together or drifting apart.

+
+
+ Focus + Energy +
+
{% for day in weekly_trend %}
@@ -224,6 +234,20 @@
{% endfor %}
+
+
+ Check-in days + {{ weekly_summary.check_in_days }}/7 +
+
+ Deep work logged + {{ weekly_summary.total_minutes }}m +
+
+ Strongest day + {{ weekly_summary.strongest_label }} · {{ weekly_summary.strongest_score }}/10 +
+
@@ -241,7 +265,7 @@
{% for entry in recent_entries %}
-
+
{{ entry.category.name }} @@ -253,6 +277,13 @@ Energy {{ entry.energy_score }}/10 {{ entry.deep_work_minutes }} min
+
+
+ Momentum score + {{ entry.momentum_score }}/10 +
+ View details +
{% endfor %} diff --git a/core/views.py b/core/views.py index 992803c..d025d5b 100644 --- a/core/views.py +++ b/core/views.py @@ -71,6 +71,133 @@ def _build_weekly_trend(entries): return trend +def _build_weekly_summary(weekly_trend): + check_in_days = sum(1 for day in weekly_trend if day["focus"] or day["energy"] or day["minutes"]) + total_minutes = sum(day["minutes"] for day in weekly_trend) + strongest_day = max( + weekly_trend, + key=lambda day: (day["focus"] + day["energy"], day["minutes"]), + default=None, + ) + strongest_has_data = bool( + strongest_day and (strongest_day["focus"] or strongest_day["energy"] or strongest_day["minutes"]) + ) + strongest_score = round(((strongest_day["focus"] + strongest_day["energy"]) / 2), 1) if strongest_has_data else 0 + return { + "check_in_days": check_in_days, + "total_minutes": total_minutes, + "strongest_label": strongest_day["label"] if strongest_has_data else "No data yet", + "strongest_score": strongest_score, + } + + +def _build_history_overview(entries): + totals = entries.aggregate( + total_entries=Count("id"), + avg_focus=Coalesce(Avg("focus_score"), 0.0), + avg_energy=Coalesce(Avg("energy_score"), 0.0), + total_minutes=Coalesce(Sum("deep_work_minutes"), 0), + ) + avg_focus = float(totals["avg_focus"] or 0) + avg_energy = float(totals["avg_energy"] or 0) + avg_momentum = round((avg_focus + avg_energy) / 2, 1) if totals["total_entries"] else 0 + + ordered_dates = [] + seen_dates = set() + for entry_date in entries.values_list("entry_date", flat=True): + if entry_date not in seen_dates: + ordered_dates.append(entry_date) + seen_dates.add(entry_date) + + streak = 0 + previous_date = None + for entry_date in ordered_dates: + if previous_date is None: + streak = 1 + previous_date = entry_date + continue + if previous_date - timedelta(days=1) == entry_date: + streak += 1 + previous_date = entry_date + continue + break + + top_category = ( + entries.values("category__name") + .annotate(total=Count("id")) + .order_by("-total", "category__name") + .first() + ) + + latest_entry = entries.first() + return { + "total_entries": totals["total_entries"], + "avg_focus": round(avg_focus, 1), + "avg_energy": round(avg_energy, 1), + "avg_momentum": avg_momentum, + "total_minutes": int(totals["total_minutes"] or 0), + "streak": streak if totals["total_entries"] else 0, + "latest_entry": latest_entry, + "top_category": top_category["category__name"] if top_category else "No category yet", + } + + +def _build_recent_activity(entries, limit=7): + recent_entries = list(entries[:limit]) + if not recent_entries: + return [] + + recent_entries.reverse() + max_minutes = max((entry.deep_work_minutes for entry in recent_entries), default=0) + activity = [] + for entry in recent_entries: + momentum = float(entry.momentum_score) + minutes_width = 0 + if entry.deep_work_minutes and max_minutes: + minutes_width = max(14, int(round((entry.deep_work_minutes / max_minutes) * 100))) + activity.append( + { + "entry": entry, + "focus_width": entry.focus_score * 10, + "energy_width": entry.energy_score * 10, + "momentum_width": int(round(momentum * 10)), + "minutes_width": minutes_width, + } + ) + return activity + + +def _build_category_breakdown(entries): + grouped = list( + entries.values("category__name", "category__slug", "category__accent_color") + .annotate( + entry_total=Count("id"), + avg_focus=Coalesce(Avg("focus_score"), 0.0), + avg_energy=Coalesce(Avg("energy_score"), 0.0), + total_minutes=Coalesce(Sum("deep_work_minutes"), 0), + ) + .order_by("-entry_total", "category__name")[:4] + ) + total_entries = sum(item["entry_total"] for item in grouped) or 1 + + breakdown = [] + for item in grouped: + avg_momentum = round((float(item["avg_focus"] or 0) + float(item["avg_energy"] or 0)) / 2, 1) + breakdown.append( + { + "name": item["category__name"], + "slug": item["category__slug"], + "accent_color": item["category__accent_color"] or "#0F766E", + "entry_total": item["entry_total"], + "total_minutes": int(item["total_minutes"] or 0), + "avg_momentum": avg_momentum, + "share_percent": max(8, int(round((item["entry_total"] / total_entries) * 100))), + "momentum_width": max(8, int(round(avg_momentum * 10))) if avg_momentum else 0, + } + ) + return breakdown + + def _dashboard_context(request): entries = _entries_for_request(request) recent_entries = entries[:6] @@ -106,6 +233,7 @@ def _dashboard_context(request): "recent_entries": recent_entries, "categories": _categories_for_request(request), "weekly_trend": weekly_trend, + "weekly_summary": _build_weekly_summary(weekly_trend), "is_demo_mode": not request.user.is_authenticated, "stats": { "total_entries": totals["total_entries"], @@ -170,6 +298,9 @@ def entry_list(request): "categories": _categories_for_request(request), "selected_slug": selected_slug, "is_demo_mode": not request.user.is_authenticated, + "history_overview": _build_history_overview(entries), + "recent_activity": _build_recent_activity(entries), + "category_breakdown": _build_category_breakdown(entries), } return render(request, "core/entry_list.html", context) diff --git a/static/css/custom.css b/static/css/custom.css index 951a829..59b781d 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -589,3 +589,228 @@ p { width: fit-content; } } + + +/* Step 3 history + chart polish */ +.chart-panel-top { + display: flex; + justify-content: space-between; + gap: 1rem; + align-items: flex-start; + margin-bottom: 1.5rem; +} + +.chart-panel-top-inline { + align-items: center; +} + +.chart-intro { + max-width: 620px; + color: var(--brand-muted); +} + +.chart-legend { + display: flex; + flex-wrap: wrap; + gap: 0.65rem; +} + +.legend-pill { + display: inline-flex; + align-items: center; + gap: 0.45rem; + padding: 0.5rem 0.8rem; + border-radius: 999px; + background: rgba(248, 250, 252, 0.92); + border: 1px solid var(--brand-border); + font-size: 0.88rem; + color: var(--brand-ink); +} + +.legend-dot { + width: 12px; + height: 12px; + border-radius: 50%; + display: inline-block; +} + +.legend-dot.focus { + background: linear-gradient(180deg, var(--brand-primary), var(--brand-highlight)); +} + +.legend-dot.energy { + background: linear-gradient(180deg, var(--brand-secondary), var(--brand-accent)); +} + +.trend-summary-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 1rem; + margin-top: 1.5rem; +} + +.trend-summary-card, +.summary-stat-card { + background: rgba(255, 255, 255, 0.72); + border: 1px solid var(--brand-border); + border-radius: 24px; + padding: 1.2rem 1.25rem; +} + +.trend-summary-card span, +.summary-stat-card span, +.mini-meter span, +.lane-meta span, +.score-track-item span { + color: var(--brand-muted); + font-size: 0.88rem; +} + +.trend-summary-card strong, +.summary-stat-card strong { + display: block; + font-size: 1.4rem; + margin-top: 0.35rem; +} + +.summary-stat-card p { + margin: 0.65rem 0 0; + color: var(--brand-muted); +} + +.activity-list, +.lane-list { + display: grid; + gap: 1rem; +} + +.activity-row, +.lane-card { + padding: 1.15rem; + border-radius: 20px; + background: rgba(255, 255, 255, 0.7); + border: 1px solid var(--brand-border); +} + +.activity-row-head, +.lane-card-top, +.entry-card-footer, +.lane-meta { + display: flex; + justify-content: space-between; + gap: 1rem; + align-items: center; +} + +.activity-row-head h3 { + margin: 0.45rem 0 0; + font-size: 1.05rem; +} + +.score-track-group { + display: grid; + gap: 0.7rem; + margin-top: 1rem; +} + +.score-track-item { + display: grid; + grid-template-columns: 72px minmax(0, 1fr) auto; + gap: 0.75rem; + align-items: center; +} + +.score-track { + width: 100%; + height: 10px; + border-radius: 999px; + background: rgba(203, 213, 225, 0.5); + overflow: hidden; +} + +.score-fill { + height: 100%; + border-radius: inherit; +} + +.score-fill.focus { + background: linear-gradient(90deg, var(--brand-primary), var(--brand-highlight)); +} + +.score-fill.energy { + background: linear-gradient(90deg, var(--brand-secondary), var(--brand-accent)); +} + +.score-fill.minutes { + background: linear-gradient(90deg, var(--brand-ink), #334155); +} + +.lane-card-top strong { + display: block; +} + +.lane-card-top span, +.lane-meta a { + color: var(--brand-muted); + text-decoration: none; +} + +.lane-track { + height: 12px; + border-radius: 999px; + background: rgba(203, 213, 225, 0.45); + overflow: hidden; + margin: 0.95rem 0 0.8rem; +} + +.lane-fill { + height: 100%; + border-radius: inherit; + box-shadow: 0 8px 20px rgba(15, 23, 42, 0.12); +} + +.entry-card-enhanced { + position: relative; + overflow: hidden; +} + +.entry-card-enhanced::after { + content: ""; + position: absolute; + inset: auto 0 0 0; + height: 4px; + background: linear-gradient(90deg, var(--entry-accent, var(--brand-primary)), var(--brand-highlight)); +} + +.entry-card-footer { + margin-top: 1.2rem; + padding-top: 1rem; + border-top: 1px solid rgba(148, 163, 184, 0.2); +} + +.mini-meter strong { + display: block; + font-size: 1rem; + margin-top: 0.25rem; +} + +@media (max-width: 991.98px) { + .trend-summary-grid { + grid-template-columns: 1fr; + } +} + +@media (max-width: 767.98px) { + .chart-panel-top, + .activity-row-head, + .lane-card-top, + .entry-card-footer, + .lane-meta { + flex-direction: column; + align-items: flex-start; + } + + .score-track-item { + grid-template-columns: 1fr; + } +} diff --git a/staticfiles/css/custom.css b/staticfiles/css/custom.css index 951a829..59b781d 100644 --- a/staticfiles/css/custom.css +++ b/staticfiles/css/custom.css @@ -589,3 +589,228 @@ p { width: fit-content; } } + + +/* Step 3 history + chart polish */ +.chart-panel-top { + display: flex; + justify-content: space-between; + gap: 1rem; + align-items: flex-start; + margin-bottom: 1.5rem; +} + +.chart-panel-top-inline { + align-items: center; +} + +.chart-intro { + max-width: 620px; + color: var(--brand-muted); +} + +.chart-legend { + display: flex; + flex-wrap: wrap; + gap: 0.65rem; +} + +.legend-pill { + display: inline-flex; + align-items: center; + gap: 0.45rem; + padding: 0.5rem 0.8rem; + border-radius: 999px; + background: rgba(248, 250, 252, 0.92); + border: 1px solid var(--brand-border); + font-size: 0.88rem; + color: var(--brand-ink); +} + +.legend-dot { + width: 12px; + height: 12px; + border-radius: 50%; + display: inline-block; +} + +.legend-dot.focus { + background: linear-gradient(180deg, var(--brand-primary), var(--brand-highlight)); +} + +.legend-dot.energy { + background: linear-gradient(180deg, var(--brand-secondary), var(--brand-accent)); +} + +.trend-summary-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 1rem; + margin-top: 1.5rem; +} + +.trend-summary-card, +.summary-stat-card { + background: rgba(255, 255, 255, 0.72); + border: 1px solid var(--brand-border); + border-radius: 24px; + padding: 1.2rem 1.25rem; +} + +.trend-summary-card span, +.summary-stat-card span, +.mini-meter span, +.lane-meta span, +.score-track-item span { + color: var(--brand-muted); + font-size: 0.88rem; +} + +.trend-summary-card strong, +.summary-stat-card strong { + display: block; + font-size: 1.4rem; + margin-top: 0.35rem; +} + +.summary-stat-card p { + margin: 0.65rem 0 0; + color: var(--brand-muted); +} + +.activity-list, +.lane-list { + display: grid; + gap: 1rem; +} + +.activity-row, +.lane-card { + padding: 1.15rem; + border-radius: 20px; + background: rgba(255, 255, 255, 0.7); + border: 1px solid var(--brand-border); +} + +.activity-row-head, +.lane-card-top, +.entry-card-footer, +.lane-meta { + display: flex; + justify-content: space-between; + gap: 1rem; + align-items: center; +} + +.activity-row-head h3 { + margin: 0.45rem 0 0; + font-size: 1.05rem; +} + +.score-track-group { + display: grid; + gap: 0.7rem; + margin-top: 1rem; +} + +.score-track-item { + display: grid; + grid-template-columns: 72px minmax(0, 1fr) auto; + gap: 0.75rem; + align-items: center; +} + +.score-track { + width: 100%; + height: 10px; + border-radius: 999px; + background: rgba(203, 213, 225, 0.5); + overflow: hidden; +} + +.score-fill { + height: 100%; + border-radius: inherit; +} + +.score-fill.focus { + background: linear-gradient(90deg, var(--brand-primary), var(--brand-highlight)); +} + +.score-fill.energy { + background: linear-gradient(90deg, var(--brand-secondary), var(--brand-accent)); +} + +.score-fill.minutes { + background: linear-gradient(90deg, var(--brand-ink), #334155); +} + +.lane-card-top strong { + display: block; +} + +.lane-card-top span, +.lane-meta a { + color: var(--brand-muted); + text-decoration: none; +} + +.lane-track { + height: 12px; + border-radius: 999px; + background: rgba(203, 213, 225, 0.45); + overflow: hidden; + margin: 0.95rem 0 0.8rem; +} + +.lane-fill { + height: 100%; + border-radius: inherit; + box-shadow: 0 8px 20px rgba(15, 23, 42, 0.12); +} + +.entry-card-enhanced { + position: relative; + overflow: hidden; +} + +.entry-card-enhanced::after { + content: ""; + position: absolute; + inset: auto 0 0 0; + height: 4px; + background: linear-gradient(90deg, var(--entry-accent, var(--brand-primary)), var(--brand-highlight)); +} + +.entry-card-footer { + margin-top: 1.2rem; + padding-top: 1rem; + border-top: 1px solid rgba(148, 163, 184, 0.2); +} + +.mini-meter strong { + display: block; + font-size: 1rem; + margin-top: 0.25rem; +} + +@media (max-width: 991.98px) { + .trend-summary-grid { + grid-template-columns: 1fr; + } +} + +@media (max-width: 767.98px) { + .chart-panel-top, + .activity-row-head, + .lane-card-top, + .entry-card-footer, + .lane-meta { + flex-direction: column; + align-items: flex-start; + } + + .score-track-item { + grid-template-columns: 1fr; + } +}