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>
|
||||
<span class="eyebrow">History</span>
|
||||
<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 class="d-flex flex-wrap gap-2 align-items-center">
|
||||
<a class="btn btn-ghost" href="{% url 'home' %}">Back to dashboard</a>
|
||||
@ -35,6 +35,37 @@
|
||||
</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">
|
||||
<a class="filter-chip {% if not selected_slug %}active{% endif %}" href="{% url 'entry_list' %}">All categories</a>
|
||||
{% for category in categories %}
|
||||
@ -43,10 +74,85 @@
|
||||
</div>
|
||||
|
||||
{% 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">
|
||||
{% for entry in entries %}
|
||||
<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">
|
||||
<span class="category-badge">{{ entry.category.name }}</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>{{ entry.deep_work_minutes }} min</span>
|
||||
</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>
|
||||
</div>
|
||||
{% 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>
|
||||
</div>
|
||||
<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">
|
||||
{% for day in weekly_trend %}
|
||||
<article class="trend-day">
|
||||
@ -224,6 +234,20 @@
|
||||
</article>
|
||||
{% endfor %}
|
||||
</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>
|
||||
</section>
|
||||
@ -241,7 +265,7 @@
|
||||
<div class="row g-4">
|
||||
{% for entry in recent_entries %}
|
||||
<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">
|
||||
<span class="category-badge">{{ entry.category.name }}</span>
|
||||
<span class="entry-date">{{ entry.entry_date|date:"M j" }}</span>
|
||||
@ -253,6 +277,13 @@
|
||||
<span>Energy {{ entry.energy_score }}/10</span>
|
||||
<span>{{ entry.deep_work_minutes }} min</span>
|
||||
</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>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
131
core/views.py
131
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)
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user