[templates] Add pill buttons to calendar
All checks were successful
build & deploy / test (push) Successful in 1m49s
build & deploy / build-and-deploy (push) Successful in 28s

This commit is contained in:
2026-05-27 13:22:52 -04:00
parent 99789e5477
commit 75479d91a3
3 changed files with 53 additions and 11 deletions

View File

@ -93,7 +93,7 @@ fetching and simple saving.
:LOGBOOK: :LOGBOOK:
CLOCK: [2025-07-09 Wed 09:55]--[2025-07-09 Wed 10:15] => 0:20 CLOCK: [2025-07-09 Wed 09:55]--[2025-07-09 Wed 10:15] => 0:20
:END: :END:
* Backlog [26/42] * Backlog [26/42] :vrobbler:project:personal:
** TODO [#C] Add sentiment parsing for Scrobbles with notes :vrobbler:project:scrobbles:sentiment: ** TODO [#C] Add sentiment parsing for Scrobbles with notes :vrobbler:project:scrobbles:sentiment:
:PROPERTIES: :PROPERTIES:
:ID: 37781d6a-f3b0-48b2-bf98-33c2c791cf85 :ID: 37781d6a-f3b0-48b2-bf98-33c2c791cf85
@ -496,6 +496,7 @@ or at least make it optional, and then require a M2M between Track and Artist.
Then this one would be a Track by both `Matt Sweeney` and `Bonnie "Prince" Then this one would be a Track by both `Matt Sweeney` and `Bonnie "Prince"
Billy` Billy`
** TODO [#A] Allow special parameter to re-import already processed GPX files :imports:gpx:
** DONE [#A] Add CSS Grid calendar view for scrobbles :vrobbler:personal:project:templates:feature: ** DONE [#A] Add CSS Grid calendar view for scrobbles :vrobbler:personal:project:templates:feature:
:PROPERTIES: :PROPERTIES:
:ID: be915acf-d803-466a-8770-823819ebf2a9 :ID: be915acf-d803-466a-8770-823819ebf2a9

View File

@ -1305,6 +1305,8 @@ class ScrobbleCalendarView(LoginRequiredMixin, TemplateView):
"Mood": "🥰", "Mood": "🥰",
} }
DEFAULT_EXCLUDE = ["Task"]
MONTH_COLORS = [ MONTH_COLORS = [
"#db7a7a", # Jan "#db7a7a", # Jan
"#db847a", # Feb "#db847a", # Feb
@ -1345,12 +1347,18 @@ class ScrobbleCalendarView(LoginRequiredMixin, TemplateView):
prev_month = month_start - timedelta(days=1) prev_month = month_start - timedelta(days=1)
next_month = month_end + timedelta(days=1) next_month = month_end + timedelta(days=1)
media_type_filter = self.request.GET.get("media_type")
if media_type_filter and media_type_filter in self.CALENDAR_MEDIA_TYPES:
active_types = [media_type_filter]
else:
active_types = [t for t in self.CALENDAR_MEDIA_TYPES if t not in self.DEFAULT_EXCLUDE]
scrobbles = ( scrobbles = (
Scrobble.objects.filter( Scrobble.objects.filter(
user=self.request.user, user=self.request.user,
timestamp__date__gte=month_start, timestamp__date__gte=month_start,
timestamp__date__lte=month_end, timestamp__date__lte=month_end,
media_type__in=self.CALENDAR_MEDIA_TYPES, media_type__in=active_types,
) )
.select_related("task", "birding_location", "food", "trail", "video_game", "book", "mood") .select_related("task", "birding_location", "food", "trail", "video_game", "book", "mood")
.order_by("timestamp") .order_by("timestamp")
@ -1400,6 +1408,8 @@ class ScrobbleCalendarView(LoginRequiredMixin, TemplateView):
"current_month": today.isoformat()[:7], "current_month": today.isoformat()[:7],
"day_names": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], "day_names": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
"month_color": month_color, "month_color": month_color,
"active_filter": media_type_filter or "",
"media_types": [{"name": mt, "emoji": self.MEDIA_EMOJI.get(mt, "📌")} for mt in self.CALENDAR_MEDIA_TYPES],
} }
) )
return ctx return ctx

View File

@ -13,25 +13,48 @@ header.navbar { display: none !important; }
margin: 0; margin: 0;
max-width: 100%; max-width: 100%;
} }
.top-bar { display: none; }
.home-btn { .home-btn {
position: fixed; margin-left: auto;
top: 12px; padding: 4px 16px;
left: 12px;
z-index: 100;
background: rgba(255,255,255,0.85);
border: 1px solid #ddd;
border-radius: 20px; border-radius: 20px;
padding: 6px 16px;
font-size: 0.85rem; font-size: 0.85rem;
text-decoration: none; text-decoration: none;
color: #555; color: #555;
background: rgba(255,255,255,0.85);
border: 1px solid #ddd;
box-shadow: 0 1px 4px rgba(0,0,0,0.1); box-shadow: 0 1px 4px rgba(0,0,0,0.1);
width: auto;
} }
.home-btn:hover { .home-btn:hover {
background: #fff; background: #fff;
color: #333; color: #333;
} }
.filter-bar {
display: flex;
gap: 6px;
flex-wrap: wrap;
margin-bottom: 8px;
align-items: center;
}
.filter-bar a {
padding: 4px 12px;
border-radius: 16px;
font-size: 0.8rem;
text-decoration: none;
color: #666;
background: rgba(255,255,255,0.5);
border: 1px solid #ddd;
transition: all 0.15s;
}
.filter-bar a:hover {
background: rgba(255,255,255,0.8);
border-color: #aaa;
}
.filter-bar a.active {
background: {{ month_color }};
color: #fff;
border-color: {{ month_color }};
}
.calendar-wrapper { .calendar-wrapper {
height: 100vh; height: 100vh;
display: flex; display: flex;
@ -141,8 +164,16 @@ header.navbar { display: none !important; }
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<a href="/" class="home-btn">Home</a>
<div class="calendar-wrapper"> <div class="calendar-wrapper">
<div class="filter-bar">
<a href="?date={{ current_month }}"
{% if not active_filter %}class="active"{% endif %}>All</a>
{% for mt in media_types %}
<a href="?date={{ current_month }}&media_type={{ mt.name }}"
{% if active_filter == mt.name %}class="active"{% endif %}>{{ mt.emoji }} {{ mt.name }}</a>
{% endfor %}
<a href="/" class="home-btn">Home</a>
</div>
<div class="calendar-grid"> <div class="calendar-grid">
<div class="month-banner"> <div class="month-banner">
<a href="?date={{ prev_month }}">&larr;</a> <a href="?date={{ prev_month }}">&larr;</a>