Improve month calendar

This commit is contained in:
Peter Stockings
2024-12-29 01:02:11 +11:00
parent ff66583b7b
commit 07ae62c633
3 changed files with 216 additions and 33 deletions

View File

@@ -156,6 +156,35 @@ def dashboard():
badges.append("Night Owl: Logged Readings Every Night for a Week")
return badges
def generate_monthly_calendar(readings, selected_date, local_timezone):
# Convert selected date to user's timezone and extract the start/end dates
today = datetime.now(local_timezone).date()
date = selected_date.astimezone(local_timezone).date()
first_day_of_month = date.replace(day=1)
days_to_subtract = (first_day_of_month.weekday() + 1) % 7
start_date = first_day_of_month - timedelta(days=days_to_subtract)
end_date = start_date + timedelta(days=6 * 7 - 1)
# Group readings by day
readings_by_day = {}
for reading in readings:
local_date = reading.timestamp.astimezone(local_timezone).date()
readings_by_day.setdefault(local_date, []).append(reading)
# Build calendar days
calendar = []
current_date = start_date
while current_date <= end_date:
calendar.append({
'day': current_date.day,
'is_today': current_date == today,
'is_in_current_month': current_date.month == date.month,
'readings': readings_by_day.get(current_date, []),
})
current_date += timedelta(days=1)
return calendar
# Get the first and last reading timestamps
first_reading_timestamp, last_reading_timestamp = get_reading_date_range(current_user.id)
@@ -188,6 +217,8 @@ def dashboard():
reading.relative_timestamp = humanize.naturaltime(now - reading.timestamp)
reading.local_timestamp = utc.localize(reading.timestamp).astimezone(local_tz)
month_view = generate_monthly_calendar(readings, now, local_tz)
# Calculate weekly summary and progress badges
systolic_avg, diastolic_avg, heart_rate_avg = calculate_weekly_summary(readings)
badges = calculate_progress_badges(readings)
@@ -223,6 +254,7 @@ def dashboard():
start_date=start_date,
end_date=end_date,
readings_by_date=readings_by_date,
month = month_view,
date=date,
timedelta=timedelta
)

View File

@@ -717,6 +717,14 @@ video {
margin-top: 1.5rem;
}
.-mb-px {
margin-bottom: -1px;
}
.ml-0 {
margin-left: 0px;
}
.block {
display: block;
}
@@ -766,6 +774,14 @@ video {
height: 2rem;
}
.h-10 {
height: 2.5rem;
}
.h-36 {
height: 9rem;
}
.w-16 {
width: 4rem;
}
@@ -826,6 +842,10 @@ video {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.cursor-pointer {
cursor: pointer;
}
.grid-cols-1 {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
@@ -842,6 +862,10 @@ video {
flex-wrap: wrap;
}
.items-start {
align-items: flex-start;
}
.items-center {
align-items: center;
}
@@ -904,6 +928,16 @@ video {
margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
}
.overflow-hidden {
overflow: hidden;
}
.truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.rounded {
border-radius: 0.25rem;
}
@@ -916,6 +950,10 @@ video {
border-radius: 0.5rem;
}
.rounded-md {
border-radius: 0.375rem;
}
.border {
border-width: 1px;
}
@@ -924,6 +962,10 @@ video {
border-width: 2px;
}
.border-4 {
border-width: 4px;
}
.border-b {
border-bottom-width: 1px;
}
@@ -947,6 +989,11 @@ video {
border-color: rgb(255 255 255 / var(--tw-border-opacity, 1));
}
.border-green-50 {
--tw-border-opacity: 1;
border-color: rgb(240 253 244 / var(--tw-border-opacity, 1));
}
.bg-blue-600 {
--tw-bg-opacity: 1;
background-color: rgb(37 99 235 / var(--tw-bg-opacity, 1));
@@ -1098,6 +1145,16 @@ video {
padding-bottom: 1rem;
}
.px-0 {
padding-left: 0px;
padding-right: 0px;
}
.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
.pl-2 {
padding-left: 0.5rem;
}
@@ -1106,6 +1163,18 @@ video {
padding-top: 1.5rem;
}
.pl-1 {
padding-left: 0.25rem;
}
.pr-2 {
padding-right: 0.5rem;
}
.pt-2 {
padding-top: 0.5rem;
}
.text-left {
text-align: left;
}
@@ -1166,6 +1235,14 @@ video {
font-weight: 600;
}
.font-light {
font-weight: 300;
}
.leading-none {
line-height: 1;
}
.text-blue-600 {
--tw-text-opacity: 1;
color: rgb(37 99 235 / var(--tw-text-opacity, 1));
@@ -1383,7 +1460,42 @@ video {
text-decoration-line: underline;
}
@media (min-width: 640px) {
.sm\:ml-0\.5 {
margin-left: 0.125rem;
}
.sm\:block {
display: block;
}
.sm\:hidden {
display: none;
}
.sm\:h-40 {
height: 10rem;
}
.sm\:px-0\.5 {
padding-left: 0.125rem;
padding-right: 0.125rem;
}
}
@media (min-width: 768px) {
.md\:ml-2 {
margin-left: 0.5rem;
}
.md\:block {
display: block;
}
.md\:hidden {
display: none;
}
.md\:w-auto {
width: auto;
}
@@ -1403,9 +1515,22 @@ video {
.md\:p-4 {
padding: 1rem;
}
.md\:px-0\.5 {
padding-left: 0.125rem;
padding-right: 0.125rem;
}
}
@media (min-width: 1024px) {
.lg\:ml-2 {
margin-left: 0.5rem;
}
.lg\:block {
display: block;
}
.lg\:flex {
display: flex;
}
@@ -1426,7 +1551,26 @@ video {
align-items: center;
}
.lg\:px-0\.5 {
padding-left: 0.125rem;
padding-right: 0.125rem;
}
.lg\:pt-0 {
padding-top: 0px;
}
}
@media (min-width: 1280px) {
.xl\:block {
display: block;
}
.xl\:hidden {
display: none;
}
.xl\:flex-row {
flex-direction: row;
}
}

View File

@@ -175,45 +175,54 @@
</div>
<!-- Monthly View -->
<div x-show="activeView === 'monthly'" class="space-y-4">
<div class="flex flex-col px-2 py-2 -mb-px" x-show="activeView === 'monthly'">
{% set current_date = date.today().replace(day=1) %}
<!-- Month Name -->
<div class="text-center">
<h2 class="text-xl font-bold text-gray-800">{{ current_date.strftime('%B %Y') }}</h2>
</div>
<!-- Day Headers -->
<div class="grid grid-cols-7 text-center">
<div class="font-semibold text-gray-700">Sun</div>
<div class="font-semibold text-gray-700">Mon</div>
<div class="font-semibold text-gray-700">Tue</div>
<div class="font-semibold text-gray-700">Wed</div>
<div class="font-semibold text-gray-700">Thu</div>
<div class="font-semibold text-gray-700">Fri</div>
<div class="font-semibold text-gray-700">Sat</div>
<div class="grid grid-cols-7 pl-2 pr-2">
<div class="p-2 h-10 text-center font-bold">
<span class="xl:block lg:block md:block sm:block hidden">Sunday</span>
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Sun</span>
</div>
<div class="p-2 h-10 text-center font-bold">
<span class="xl:block lg:block md:block sm:block hidden">Monday</span>
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Mon</span>
</div>
<div class="p-2 h-10 text-center font-bold">
<span class="xl:block lg:block md:block sm:block hidden">Tuesday</span>
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Tue</span>
</div>
<div class="p-2 h-10 text-center font-bold">
<span class="xl:block lg:block md:block sm:block hidden">Wednesday</span>
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Wed</span>
</div>
<div class="p-2 h-10 text-center font-bold">
<span class="xl:block lg:block md:block sm:block hidden">Thursday</span>
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Thu</span>
</div>
<div class="p-2 h-10 text-center font-bold">
<span class="xl:block lg:block md:block sm:block hidden">Friday</span>
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Fri</span>
</div>
<div class="p-2 h-10 text-center font-bold">
<span class="xl:block lg:block md:block sm:block hidden">Saturday</span>
<span class="xl:hidden lg:hidden md:hidden sm:hidden block">Sat</span>
</div>
</div>
<!-- Calendar Grid -->
<div class="grid grid-cols-7 text-center">
{% set days_in_month = (current_date.replace(month=current_date.month % 12 + 1, day=1) -
timedelta(days=1)).day %}
{% set first_weekday = current_date.weekday() %}
<div class="grid grid-cols-7 overflow-hidden flex-1 pl-2 pr-2 w-full">
<!-- Empty slots for days before the 1st -->
{% for _ in range((first_weekday + 1) % 7) %}
<div></div>
{% endfor %}
<!-- Days of the Month -->
{% for day in range(1, days_in_month + 1) %}
{% set current_day = current_date.replace(day=day) %}
<div class="border p-1 md:p-4 bg-gray-50 relative">
<!-- Day Label -->
<div class="text-sm font-bold text-gray-500 text-left">{{ current_day.day }}</div>
<!-- Readings -->
{% if current_day in readings_by_date %}
{% for reading in readings_by_date[current_day]|sort(attribute="timestamp", reverse = True) %}
{% for day in month %}
<div
class="{% if day.is_today %}rounded-md border-4 border-green-50{% endif %} border flex flex-col h-36 sm:h-40 md:h-30 lg:h-30 mx-auto mx-auto overflow-hidden w-full pt-2 pl-1 cursor-pointer {% if day.is_in_current_month %}bg-gray-100{% endif %}">
<div class="top h-5 w-full">
<span class="text-gray-500 font-semibold">{{ day.day }}</span>
</div>
{% for reading in day.readings %}
<a href="{{ url_for('main.edit_reading', reading_id=reading.id) }}"
class="block mt-2 p-0 md:p-2 bg-green-100 rounded-lg shadow hover:bg-green-200 transition">
<p class="text-xs font-medium text-green-800">
@@ -226,11 +235,9 @@
</div>
</a>
{% endfor %}
{% else %}
<div class="h-8"></div> <!-- Placeholder for spacing -->
{% endif %}
</div>
{% endfor %}
</div>
</div>