This commit is contained in:
metacryst
2026-04-28 20:05:00 -05:00
commit 0d6c7683ff
123 changed files with 20922 additions and 0 deletions

142
calendar/Week/WeekView.js Normal file
View File

@@ -0,0 +1,142 @@
import calendarUtil from "../calendarUtil.js"
import "./SpacerCell.js"
import "./TimedLabelsColumn.js"
import "./TimedWeekGrid.js"
import "./WeekHeaderRow.js"
css(`
weekview- {
scrollbar-width: none;
-ms-overflow-style: none;
}
weekview- .VStack::-webkit-scrollbar {
display: none;
width: 0px;
height: 0px;
}
weekview- .VStack::-webkit-scrollbar-thumb {
background: transparent;
}
weekview- .VStack::-webkit-scrollbar-track {
background: transparent;
}
`)
let _saved = null;
class WeekView extends Shadow {
constructor(calendars, events, currentDate, weekStartsOn = 0, onSlotTap = null, onDayTap = null, isCenter = false) {
super()
this.calendars = calendars;
this.events = events;
this.currentDate = currentDate;
this.weekStartsOn = weekStartsOn;
this.onSlotTap = onSlotTap;
this.onDayTap = onDayTap;
this.isCenter = isCenter;
this.slots = calendarUtil.generateTimeSlots({ stepMinutes: 30 });
this.slotHeight = 2;
this.sidebarWidth = 3;
}
render() {
ZStack(() => {
const visibleWeekStart = calendarUtil.startOfWeek(this.currentDate, this.weekStartsOn);
const weekDays = this.getWeekDays(visibleWeekStart);
const groupedDays = this.groupEventsByWeekDay(
this.filterEventsForWeek(this.events, weekDays),
weekDays
);
const weekNumber = calendarUtil.getWeekNumber(visibleWeekStart);
VStack(() => {
HStack(() => {
SpacerCell(weekNumber, this.sidebarWidth)
WeekHeaderRow(groupedDays, this.calendars, this.onDayTap)
})
.boxSizing("border-box")
.position("sticky")
.top(0)
.width(100, pct)
.zIndex(2)
HStack(() => {
TimedLabelsColumn(this.slots, this.slotHeight, this.sidebarWidth)
TimedWeekGrid(weekDays, this.slots, groupedDays, this.calendars, this.slotHeight, "week", this.onSlotTap)
})
.boxSizing("border-box")
.onAppear(() => {
// console.log("groupedDays:", groupedDays)
this.scrollToEight();
})
})
})
.position("relative")
.gap(1, em)
.boxSizing("border-box")
.width(100, pct)
.height(100, pct)
.fontSize(0.9, em)
.overscrollBehavior("none")
.overflowY("scroll")
.display("block")
}
getWeekDays(weekStart) {
return Array.from({ length: 7 }, (_, i) => calendarUtil.addDays(weekStart, i));
}
filterEventsForWeek(events, weekDays) {
const rangeStart = calendarUtil.startOfDay(weekDays[0]);
const rangeEnd = calendarUtil.endOfDay(weekDays[6]);
const expanded = calendarUtil.expandRecurringEvents(events, rangeStart, rangeEnd);
return expanded.filter(event => {
const end = event.all_day ? calendarUtil.endOfDay(event.time_end) : calendarUtil.timedEnd(event);
return weekDays.some(day => calendarUtil.rangesOverlap(
event.time_start,
end,
calendarUtil.startOfDay(day),
calendarUtil.endOfDay(day)
) && this.calendars.some(c => event.calendars?.some(id => id === c.id)));
});
}
scrollToEight() {
requestAnimationFrame(() => {
const fs = parseFloat(getComputedStyle(this).fontSize);
const slotsBeforeEight = this.slots.findIndex(s => s.hour24 === 8 && s.minute === 0);
const defaultTarget = slotsBeforeEight * this.slotHeight * fs;
if (this.isCenter) {
const dateKey = calendarUtil.toDateInput(calendarUtil.startOfWeek(this.currentDate, this.weekStartsOn));
this.scrollTop = (_saved?.dateKey === dateKey) ? _saved.scrollTop : defaultTarget;
this.addEventListener('scroll', () => { _saved = { dateKey, scrollTop: this.scrollTop }; }, { passive: true });
} else {
this.scrollTop = defaultTarget;
}
})
}
groupEventsByWeekDay(events, weekDays) {
return weekDays.map(day => {
const dayStart = calendarUtil.startOfDay(day);
const dayEnd = calendarUtil.endOfDay(day)
return {
day,
allDay: events.filter(event => {
if (!event.all_day) return false;
const end = calendarUtil.endOfDay(event.time_end);
return calendarUtil.rangesOverlap(event.time_start, end, dayStart, dayEnd);
}),
timed: events.filter(event => {
return !event.all_day && calendarUtil.rangesOverlap(event.time_start, calendarUtil.timedEnd(event), dayStart, dayEnd);
})
};
});
}
}
register(WeekView)