Big refactor of calendar

This commit is contained in:
2026-02-03 19:13:37 +13:00
parent fb8ed4ad55
commit 34cbaf3e6e

View File

@@ -1,11 +1,4 @@
<script lang="ts">
interface Entry {
date: string;
id: string;
image?: string;
content: string;
}
let {
year = $bindable("2026"),
month = $bindable("0"),
@@ -13,168 +6,7 @@
entries,
} = $props();
var headers = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
let days = $state([]);
let expanded = $state(false);
let currentYear = $state(parseInt(year));
let currentMonth = $state(parseInt(month));
// Helper function to find entry for a specific day
function getEntryForDay(
year: number,
month: number,
date: number,
): Entry | undefined {
if (!entries) return undefined;
const dateStr = new Date(year, month, date).toISOString().split("T")[0];
return entries.find((entry) => {
const entryDate = entry.date.split("T")[0];
return entryDate === dateStr;
});
}
// Get current week when in week view
function getCurrentWeek() {
const today = new Date();
const currentDay = today.getDay();
const diff = currentDay === 0 ? -6 : 1 - currentDay; // Adjust for Monday start
const monday = new Date(today);
monday.setDate(today.getDate() + diff);
const week = [];
for (let i = 0; i < 7; i++) {
const day = new Date(monday);
day.setDate(monday.getDate() + i);
const entry = getEntryForDay(
day.getFullYear(),
day.getMonth(),
day.getDate(),
);
week.push({
date: day.getDate(),
month: day.getMonth(),
year: day.getFullYear(),
dayName: headers[i],
isCurrentMonth: day.getMonth() === today.getMonth(),
isToday: day.toDateString() === today.toDateString(),
entry,
});
}
return week;
}
// Generate calendar for a full month
function generateMonth(year: number, month: number) {
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
const daysInMonth = lastDay.getDate();
// Get the day of week for first day (0 = Sunday, adjust to Monday = 0)
let startDay = firstDay.getDay() - 1;
if (startDay === -1) startDay = 6; // Sunday becomes 6
const days = [];
// Previous month days
const prevMonthLastDay = new Date(year, month, 0).getDate();
for (let i = startDay - 1; i >= 0; i--) {
const dayIndex = days.length % 7;
const dayDate = prevMonthLastDay - i;
const dayMonth = month - 1;
const dayYear = month === 0 ? year - 1 : year;
const entry = getEntryForDay(dayYear, dayMonth, dayDate);
days.push({
date: dayDate,
month: dayMonth,
year: dayYear,
dayName: headers[dayIndex],
isCurrentMonth: false,
isToday: false,
entry,
});
}
// Current month days
const today = new Date();
for (let i = 1; i <= daysInMonth; i++) {
const isToday =
today.getDate() === i &&
today.getMonth() === month &&
today.getFullYear() === year;
const dayIndex = days.length % 7;
const entry = getEntryForDay(year, month, i);
days.push({
date: i,
month: month,
year: year,
dayName: headers[dayIndex],
isCurrentMonth: true,
isToday,
entry,
});
}
// Next month days to fill the grid
const remaining = 42 - days.length; // 6 rows * 7 days
for (let i = 1; i <= remaining; i++) {
const dayIndex = days.length % 7;
const dayMonth = month + 1;
const dayYear = month === 11 ? year + 1 : year;
const entry = getEntryForDay(dayYear, dayMonth, i);
days.push({
date: i,
month: dayMonth,
year: dayYear,
dayName: headers[dayIndex],
isCurrentMonth: false,
isToday: false,
entry,
});
}
return days;
}
// Update days when expanded state or month changes
$effect(() => {
if (expanded) {
days = generateMonth(currentYear, currentMonth);
} else {
days = getCurrentWeek();
}
});
function toggleExpanded() {
expanded = !expanded;
if (expanded) {
// Reset to current date's month when expanding
const today = new Date();
currentYear = today.getFullYear();
currentMonth = today.getMonth();
}
}
function previousMonth() {
if (!expanded) return;
if (currentMonth === 0) {
currentMonth = 11;
currentYear--;
} else {
currentMonth--;
}
}
function nextMonth() {
if (!expanded) return;
if (currentMonth === 11) {
currentMonth = 0;
currentYear++;
} else {
currentMonth++;
}
}
const headers = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
const monthNames = [
"January",
"February",
@@ -189,6 +21,106 @@
"November",
"December",
];
let days = $state([]);
let expanded = $state(false);
let currentYear = $state(parseInt(year));
let currentMonth = $state(parseInt(month));
function getEntryForDay(year: number, month: number, date: number) {
if (!entries) return undefined;
const dateStr = new Date(year, month, date).toISOString().split("T")[0];
return entries.find((e) => e.date.split("T")[0] === dateStr);
}
function createDayObject(date: Date, isCurrentMonth: boolean) {
const today = new Date();
const entry = getEntryForDay(
date.getFullYear(),
date.getMonth(),
date.getDate(),
);
return {
date: date.getDate(),
month: date.getMonth(),
year: date.getFullYear(),
iso: date.toISOString().split('T')[0],
dayName: headers[date.getDay() === 0 ? 6 : date.getDay() - 1],
isCurrentMonth,
isToday: date.toDateString() === today.toDateString(),
entry,
};
}
function getCurrentWeek() {
const today = new Date();
const diff = today.getDay() === 0 ? -6 : 1 - today.getDay();
const monday = new Date(today);
monday.setDate(today.getDate() + diff);
return Array.from({ length: 7 }, (_, i) => {
const day = new Date(monday);
day.setDate(monday.getDate() + i);
return createDayObject(day, day.getMonth() === today.getMonth());
});
}
function generateMonth(year: number, month: number) {
const firstDay = new Date(year, month, 1);
const startDay = firstDay.getDay() === 0 ? 6 : firstDay.getDay() - 1;
const daysInMonth = new Date(year, month + 1, 0).getDate();
const prevMonthDays = new Date(year, month, 0).getDate();
const days = [];
// Previous month
for (let i = startDay - 1; i >= 0; i--) {
const date = new Date(year, month, 0);
date.setDate(prevMonthDays - i);
days.push(createDayObject(date, false));
}
// Current month
for (let i = 1; i <= daysInMonth; i++) {
days.push(createDayObject(new Date(year, month, i), true));
}
// Next month
const remaining = 42 - days.length;
for (let i = 1; i <= remaining; i++) {
days.push(createDayObject(new Date(year, month + 1, i), false));
}
return days;
}
$effect(() => {
days = expanded
? generateMonth(currentYear, currentMonth)
: getCurrentWeek();
});
function toggleExpanded() {
expanded = !expanded;
if (expanded) {
const today = new Date();
currentYear = today.getFullYear();
currentMonth = today.getMonth();
}
}
function previousMonth() {
if (!expanded) return;
currentMonth === 0
? ((currentMonth = 11), currentYear--)
: currentMonth--;
}
function nextMonth() {
if (!expanded) return;
currentMonth === 11
? ((currentMonth = 0), currentYear++)
: currentMonth++;
}
</script>
<div class="calendar-container">
@@ -218,7 +150,9 @@
class:other-month={!day.isCurrentMonth}
class:today={day.isToday}
class:has-image={day.entry?.image}
onclick={ day.entry ? () => dayClickCallback(day.entry.id) : null }
onclick={day.entry?.id
? () => dayClickCallback(true, day.entry.id)
: () => dayClickCallback(false, day.iso)}
style={day.entry?.image
? `background-image: url(${day.entry.image}); background-size: cover; background-position: center;`
: ""}
@@ -254,13 +188,11 @@
border-bottom: 1px solid rgba(166, 168, 179, 0.12);
}
.expand-btn {
width: 36px;
height: 36px;
.expand-btn,
.nav-btn {
border: 1px solid rgba(166, 168, 179, 0.2);
background: transparent;
color: #009fb7;
font-size: 24px;
cursor: pointer;
border-radius: 4px;
display: flex;
@@ -269,26 +201,19 @@
transition: all 0.2s;
}
.expand-btn:hover {
background: rgba(255, 255, 255, 0.1);
border-color: #009fb7;
.expand-btn {
width: 36px;
height: 36px;
font-size: 24px;
}
.nav-btn {
width: 32px;
height: 32px;
border: 1px solid rgba(166, 168, 179, 0.2);
background: transparent;
color: #009fb7;
font-size: 20px;
cursor: pointer;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
}
.expand-btn:hover,
.nav-btn:hover {
background: rgba(0, 159, 183, 0.1);
border-color: #009fb7;
@@ -317,7 +242,6 @@
box-sizing: border-box;
color: #98a0a6;
position: relative;
z-index: 1;
}
.day.has-image {
@@ -326,10 +250,7 @@
.image-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
inset: 0;
background: rgba(0, 0, 0, 0.3);
z-index: 1;
}
@@ -338,7 +259,6 @@
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
position: relative;
z-index: 2;
}
@@ -361,7 +281,6 @@
height: 8px;
border-radius: 50%;
background-color: #4a9eff;
display: inline-block;
margin-left: 8px;
}