Auto commit: 2026-04-16T13:25:51.679Z
This commit is contained in:
parent
3a44f34cf9
commit
9b2308aeac
Binary file not shown.
@ -18,7 +18,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<span class="eyebrow">History</span>
|
<span class="eyebrow">History</span>
|
||||||
<h1>{% if is_demo_mode %}Demo momentum entries{% else %}Your momentum entries{% endif %}</h1>
|
<h1>{% if is_demo_mode %}Demo momentum entries{% else %}Your momentum entries{% endif %}</h1>
|
||||||
<p>{% 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 %}</p>
|
<p>{% 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 %}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex flex-wrap gap-2 align-items-center">
|
<div class="d-flex flex-wrap gap-2 align-items-center">
|
||||||
<a class="btn btn-ghost" href="{% url 'home' %}">Back to dashboard</a>
|
<a class="btn btn-ghost" href="{% url 'home' %}">Back to dashboard</a>
|
||||||
@ -35,6 +35,37 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3 mb-4">
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
|
<article class="glass-panel summary-stat-card h-100">
|
||||||
|
<span>Total check-ins</span>
|
||||||
|
<strong>{{ history_overview.total_entries }}</strong>
|
||||||
|
<p>{% if history_overview.latest_entry %}Latest: {{ history_overview.latest_entry.entry_date|date:"M j, Y" }}{% else %}No entries yet{% endif %}</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
|
<article class="glass-panel summary-stat-card h-100">
|
||||||
|
<span>Avg. momentum</span>
|
||||||
|
<strong>{{ history_overview.avg_momentum }}/10</strong>
|
||||||
|
<p>Focus {{ history_overview.avg_focus }}/10 · Energy {{ history_overview.avg_energy }}/10</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
|
<article class="glass-panel summary-stat-card h-100">
|
||||||
|
<span>Current streak</span>
|
||||||
|
<strong>{{ history_overview.streak }} day{{ history_overview.streak|pluralize }}</strong>
|
||||||
|
<p>Top lane: {{ history_overview.top_category }}</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
|
<article class="glass-panel summary-stat-card h-100">
|
||||||
|
<span>Deep work total</span>
|
||||||
|
<strong>{{ history_overview.total_minutes }}m</strong>
|
||||||
|
<p>{% if is_demo_mode %}Sample time invested{% else %}Time protected for focused work{% endif %}</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="filter-row mb-4">
|
<div class="filter-row mb-4">
|
||||||
<a class="filter-chip {% if not selected_slug %}active{% endif %}" href="{% url 'entry_list' %}">All categories</a>
|
<a class="filter-chip {% if not selected_slug %}active{% endif %}" href="{% url 'entry_list' %}">All categories</a>
|
||||||
{% for category in categories %}
|
{% for category in categories %}
|
||||||
@ -43,10 +74,85 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if entries %}
|
{% if entries %}
|
||||||
|
<div class="row g-4 mb-4">
|
||||||
|
<div class="col-xl-7">
|
||||||
|
<section class="glass-panel chart-panel h-100">
|
||||||
|
<div class="chart-panel-top">
|
||||||
|
<div>
|
||||||
|
<span class="panel-label">Recent pattern</span>
|
||||||
|
<h2 class="h3 mb-2">Last {{ recent_activity|length }} check-ins at a glance</h2>
|
||||||
|
<p class="mb-0">Quick comparison bars make it easier to notice whether focus, energy, or deep work is drifting.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="activity-list">
|
||||||
|
{% for item in recent_activity %}
|
||||||
|
<article class="activity-row">
|
||||||
|
<div class="activity-row-head">
|
||||||
|
<div>
|
||||||
|
<span class="category-badge">{{ item.entry.category.name }}</span>
|
||||||
|
<h3><a href="{% url 'entry_detail' item.entry.pk %}">{{ item.entry.title }}</a></h3>
|
||||||
|
</div>
|
||||||
|
<span class="entry-date">{{ item.entry.entry_date|date:"M j" }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="score-track-group">
|
||||||
|
<div class="score-track-item">
|
||||||
|
<span>Focus</span>
|
||||||
|
<div class="score-track"><div class="score-fill focus" style="width: {{ item.focus_width }}%"></div></div>
|
||||||
|
<strong>{{ item.entry.focus_score }}/10</strong>
|
||||||
|
</div>
|
||||||
|
<div class="score-track-item">
|
||||||
|
<span>Energy</span>
|
||||||
|
<div class="score-track"><div class="score-fill energy" style="width: {{ item.energy_width }}%"></div></div>
|
||||||
|
<strong>{{ item.entry.energy_score }}/10</strong>
|
||||||
|
</div>
|
||||||
|
<div class="score-track-item minutes">
|
||||||
|
<span>Deep work</span>
|
||||||
|
<div class="score-track"><div class="score-fill minutes" style="width: {{ item.minutes_width }}%"></div></div>
|
||||||
|
<strong>{{ item.entry.deep_work_minutes }}m</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="col-xl-5">
|
||||||
|
<aside class="glass-panel chart-panel h-100">
|
||||||
|
<div class="chart-panel-top">
|
||||||
|
<div>
|
||||||
|
<span class="panel-label">Category lanes</span>
|
||||||
|
<h2 class="h3 mb-2">Where your momentum shows up most</h2>
|
||||||
|
<p class="mb-0">These lanes rank the strongest categories in the current filtered history.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lane-list">
|
||||||
|
{% for lane in category_breakdown %}
|
||||||
|
<article class="lane-card">
|
||||||
|
<div class="lane-card-top">
|
||||||
|
<div>
|
||||||
|
<strong>{{ lane.name }}</strong>
|
||||||
|
<span>{{ lane.entry_total }} entry{{ lane.entry_total|pluralize }}</span>
|
||||||
|
</div>
|
||||||
|
<span>{{ lane.avg_momentum }}/10 avg</span>
|
||||||
|
</div>
|
||||||
|
<div class="lane-track" aria-hidden="true">
|
||||||
|
<div class="lane-fill" style="width: {{ lane.share_percent }}%; background: linear-gradient(135deg, {{ lane.accent_color }}, var(--brand-highlight));"></div>
|
||||||
|
</div>
|
||||||
|
<div class="lane-meta">
|
||||||
|
<span>{{ lane.total_minutes }} minutes tracked</span>
|
||||||
|
<a href="{% url 'entry_list' %}?category={{ lane.slug }}">Open lane</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
{% for entry in entries %}
|
{% for entry in entries %}
|
||||||
<div class="col-lg-4 col-md-6">
|
<div class="col-lg-4 col-md-6">
|
||||||
<article class="glass-panel entry-card h-100">
|
<article class="glass-panel entry-card entry-card-enhanced h-100" style="--entry-accent: {{ entry.category.accent_color }};">
|
||||||
<div class="entry-card-top">
|
<div class="entry-card-top">
|
||||||
<span class="category-badge">{{ entry.category.name }}</span>
|
<span class="category-badge">{{ entry.category.name }}</span>
|
||||||
<span class="entry-date">{{ entry.entry_date|date:"M j, Y" }}</span>
|
<span class="entry-date">{{ entry.entry_date|date:"M j, Y" }}</span>
|
||||||
@ -58,6 +164,13 @@
|
|||||||
<span>Energy {{ entry.energy_score }}/10</span>
|
<span>Energy {{ entry.energy_score }}/10</span>
|
||||||
<span>{{ entry.deep_work_minutes }} min</span>
|
<span>{{ entry.deep_work_minutes }} min</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="entry-card-footer">
|
||||||
|
<div class="mini-meter">
|
||||||
|
<span>Momentum score</span>
|
||||||
|
<strong>{{ entry.momentum_score }}/10</strong>
|
||||||
|
</div>
|
||||||
|
<a class="text-link" href="{% url 'entry_detail' entry.pk %}">View details</a>
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@ -211,6 +211,16 @@
|
|||||||
<a class="text-link" href="{% url 'entry_list' %}">{% if is_demo_mode %}Open demo history{% else %}Open your history{% endif %}</a>
|
<a class="text-link" href="{% url 'entry_list' %}">{% if is_demo_mode %}Open demo history{% else %}Open your history{% endif %}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="glass-panel chart-panel">
|
<div class="glass-panel chart-panel">
|
||||||
|
<div class="chart-panel-top chart-panel-top-inline">
|
||||||
|
<div>
|
||||||
|
<span class="panel-label">Compare your week</span>
|
||||||
|
<p class="chart-intro mb-0">Two bars per day show whether focus and energy are moving together or drifting apart.</p>
|
||||||
|
</div>
|
||||||
|
<div class="chart-legend" aria-label="Chart legend">
|
||||||
|
<span class="legend-pill"><span class="legend-dot focus"></span>Focus</span>
|
||||||
|
<span class="legend-pill"><span class="legend-dot energy"></span>Energy</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="trend-chart">
|
<div class="trend-chart">
|
||||||
{% for day in weekly_trend %}
|
{% for day in weekly_trend %}
|
||||||
<article class="trend-day">
|
<article class="trend-day">
|
||||||
@ -224,6 +234,20 @@
|
|||||||
</article>
|
</article>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="trend-summary-grid">
|
||||||
|
<article class="trend-summary-card">
|
||||||
|
<span>Check-in days</span>
|
||||||
|
<strong>{{ weekly_summary.check_in_days }}/7</strong>
|
||||||
|
</article>
|
||||||
|
<article class="trend-summary-card">
|
||||||
|
<span>Deep work logged</span>
|
||||||
|
<strong>{{ weekly_summary.total_minutes }}m</strong>
|
||||||
|
</article>
|
||||||
|
<article class="trend-summary-card">
|
||||||
|
<span>Strongest day</span>
|
||||||
|
<strong>{{ weekly_summary.strongest_label }} · {{ weekly_summary.strongest_score }}/10</strong>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -241,7 +265,7 @@
|
|||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
{% for entry in recent_entries %}
|
{% for entry in recent_entries %}
|
||||||
<div class="col-lg-4 col-md-6">
|
<div class="col-lg-4 col-md-6">
|
||||||
<article class="glass-panel entry-card h-100">
|
<article class="glass-panel entry-card entry-card-enhanced h-100" style="--entry-accent: {{ entry.category.accent_color }};">
|
||||||
<div class="entry-card-top">
|
<div class="entry-card-top">
|
||||||
<span class="category-badge">{{ entry.category.name }}</span>
|
<span class="category-badge">{{ entry.category.name }}</span>
|
||||||
<span class="entry-date">{{ entry.entry_date|date:"M j" }}</span>
|
<span class="entry-date">{{ entry.entry_date|date:"M j" }}</span>
|
||||||
@ -253,6 +277,13 @@
|
|||||||
<span>Energy {{ entry.energy_score }}/10</span>
|
<span>Energy {{ entry.energy_score }}/10</span>
|
||||||
<span>{{ entry.deep_work_minutes }} min</span>
|
<span>{{ entry.deep_work_minutes }} min</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="entry-card-footer">
|
||||||
|
<div class="mini-meter">
|
||||||
|
<span>Momentum score</span>
|
||||||
|
<strong>{{ entry.momentum_score }}/10</strong>
|
||||||
|
</div>
|
||||||
|
<a class="text-link" href="{% url 'entry_detail' entry.pk %}">View details</a>
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
131
core/views.py
131
core/views.py
@ -71,6 +71,133 @@ def _build_weekly_trend(entries):
|
|||||||
return trend
|
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):
|
def _dashboard_context(request):
|
||||||
entries = _entries_for_request(request)
|
entries = _entries_for_request(request)
|
||||||
recent_entries = entries[:6]
|
recent_entries = entries[:6]
|
||||||
@ -106,6 +233,7 @@ def _dashboard_context(request):
|
|||||||
"recent_entries": recent_entries,
|
"recent_entries": recent_entries,
|
||||||
"categories": _categories_for_request(request),
|
"categories": _categories_for_request(request),
|
||||||
"weekly_trend": weekly_trend,
|
"weekly_trend": weekly_trend,
|
||||||
|
"weekly_summary": _build_weekly_summary(weekly_trend),
|
||||||
"is_demo_mode": not request.user.is_authenticated,
|
"is_demo_mode": not request.user.is_authenticated,
|
||||||
"stats": {
|
"stats": {
|
||||||
"total_entries": totals["total_entries"],
|
"total_entries": totals["total_entries"],
|
||||||
@ -170,6 +298,9 @@ def entry_list(request):
|
|||||||
"categories": _categories_for_request(request),
|
"categories": _categories_for_request(request),
|
||||||
"selected_slug": selected_slug,
|
"selected_slug": selected_slug,
|
||||||
"is_demo_mode": not request.user.is_authenticated,
|
"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)
|
return render(request, "core/entry_list.html", context)
|
||||||
|
|
||||||
|
|||||||
@ -589,3 +589,228 @@ p {
|
|||||||
width: fit-content;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -589,3 +589,228 @@ p {
|
|||||||
width: fit-content;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user