init
This commit is contained in:
101
calendar/Day/DayHeaderRow.js
Normal file
101
calendar/Day/DayHeaderRow.js
Normal file
@@ -0,0 +1,101 @@
|
||||
import calendarUtil from "../calendarUtil.js";
|
||||
|
||||
class DayHeaderRow extends Shadow {
|
||||
constructor(groupedDay, calendars) {
|
||||
super()
|
||||
this.groupedDay = groupedDay;
|
||||
this.calendars = calendars;
|
||||
}
|
||||
|
||||
render() {
|
||||
const day = this.groupedDay.day;
|
||||
const today = calendarUtil.isToday(day);
|
||||
const allDayEvents = this.groupedDay.allDay;
|
||||
const maxEvents = allDayEvents.length;
|
||||
|
||||
VStack(() => {
|
||||
HStack(() => {
|
||||
VStack(() => {
|
||||
p(day.toLocaleDateString("en-US", { weekday: "long" }).toUpperCase())
|
||||
.margin(0)
|
||||
.fontSize(0.72, em)
|
||||
.fontWeight("600")
|
||||
.letterSpacing(0.04, em)
|
||||
.opacity(today ? 1 : 0.5)
|
||||
.textAlign("left")
|
||||
|
||||
h3(day.toLocaleDateString("en-US", { month: "long", day: "numeric" }))
|
||||
.margin(0)
|
||||
.fontSize(1.35, em)
|
||||
.fontWeight("700")
|
||||
.lineHeight("1")
|
||||
})
|
||||
.color(today ? "var(--quillred)" : "var(--headertext)")
|
||||
.flex(1)
|
||||
.alignItems("flex-start")
|
||||
.justifyContent("center")
|
||||
.gap(0.3, em)
|
||||
.paddingTop(0.85, em)
|
||||
.paddingBottom(maxEvents > 0 ? (maxEvents * 2.0) + 0.7 : 0.35, em)
|
||||
.paddingHorizontal(0.75, em)
|
||||
.boxSizing("border-box")
|
||||
})
|
||||
.width(100, pct)
|
||||
.alignItems("stretch")
|
||||
|
||||
if (allDayEvents.length > 0) {
|
||||
this.allDaySection(allDayEvents);
|
||||
}
|
||||
})
|
||||
.width(100, pct)
|
||||
.position("relative")
|
||||
.background("var(--sidebottombars)")
|
||||
.borderBottom("1px solid var(--divider)")
|
||||
}
|
||||
|
||||
allDaySection(events) {
|
||||
const rowHeight = 1.75;
|
||||
const gap = 0.25;
|
||||
const totalHeight = events.length * rowHeight + (events.length - 1) * gap;
|
||||
|
||||
ZStack(() => {
|
||||
events.forEach((event, slot) => {
|
||||
const color = calendarUtil.getCalendarColor(this.calendars, event.calendars.find(id => this.calendars.some(c => c.id === id)) ?? event.calendars[0]);
|
||||
const topEm = slot * (rowHeight + gap);
|
||||
|
||||
HStack(() => {
|
||||
p(event.title)
|
||||
.margin(0)
|
||||
.fontSize(0.72, em)
|
||||
.fontWeight("600")
|
||||
.color("white")
|
||||
.whiteSpace("nowrap")
|
||||
.overflow("hidden")
|
||||
})
|
||||
.position("absolute")
|
||||
.top(topEm, em)
|
||||
.left(0.25, em)
|
||||
.right(0.25, em)
|
||||
.height(rowHeight, em)
|
||||
.padding(0.35, em)
|
||||
.background(color)
|
||||
.borderRadius(0.25, em)
|
||||
.alignItems("center")
|
||||
.boxSizing("border-box")
|
||||
.overflow("hidden")
|
||||
.pointerEvents("auto")
|
||||
.cursor("pointer")
|
||||
.onTap(() => $("bottomsheet-").showEvent(event))
|
||||
})
|
||||
})
|
||||
.position("absolute")
|
||||
.bottom(0.25, em)
|
||||
.left(0)
|
||||
.right(0)
|
||||
.height(totalHeight, em)
|
||||
.boxSizing("border-box")
|
||||
.pointerEvents("none")
|
||||
}
|
||||
}
|
||||
|
||||
register(DayHeaderRow)
|
||||
124
calendar/Day/DayView.js
Normal file
124
calendar/Day/DayView.js
Normal file
@@ -0,0 +1,124 @@
|
||||
import calendarUtil from "../calendarUtil.js"
|
||||
import "../Week/SpacerCell.js"
|
||||
import "../Week/TimedLabelsColumn.js"
|
||||
import "../Week/TimedWeekGrid.js"
|
||||
import "./DayHeaderRow.js"
|
||||
|
||||
css(`
|
||||
dayview- {
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
dayview- .VStack::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
dayview- .VStack::-webkit-scrollbar-thumb {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
dayview- .VStack::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
`)
|
||||
|
||||
let _saved = null;
|
||||
|
||||
class DayView extends Shadow {
|
||||
constructor(calendars, events, currentDate, onSlotTap = null, isCenter = false) {
|
||||
super()
|
||||
this.calendars = calendars;
|
||||
this.events = events;
|
||||
this.currentDate = currentDate;
|
||||
this.onSlotTap = onSlotTap;
|
||||
this.isCenter = isCenter;
|
||||
this.slots = calendarUtil.generateTimeSlots({ stepMinutes: 30 });
|
||||
this.slotHeight = 2;
|
||||
this.sidebarWidth = 3;
|
||||
}
|
||||
|
||||
render() {
|
||||
ZStack(() => {
|
||||
const filteredEvents = this.filterEventsForDay(this.events);
|
||||
const groupedDay = this.groupEventsForDay(filteredEvents);
|
||||
const weekNumber = calendarUtil.getWeekNumber(this.currentDate);
|
||||
|
||||
VStack(() => {
|
||||
HStack(() => {
|
||||
SpacerCell(weekNumber, this.sidebarWidth)
|
||||
DayHeaderRow(groupedDay, this.calendars)
|
||||
})
|
||||
.boxSizing("border-box")
|
||||
.position("sticky")
|
||||
.top(0)
|
||||
.width(100, pct)
|
||||
.zIndex(2)
|
||||
|
||||
HStack(() => {
|
||||
TimedLabelsColumn(this.slots, this.slotHeight, this.sidebarWidth)
|
||||
TimedWeekGrid([groupedDay], this.slots, [groupedDay], this.calendars, this.slotHeight, "day", this.onSlotTap)
|
||||
})
|
||||
.boxSizing("border-box")
|
||||
.onAppear(() => {
|
||||
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")
|
||||
}
|
||||
|
||||
filterEventsForDay(events) {
|
||||
const dayStart = calendarUtil.startOfDay(this.currentDate);
|
||||
const dayEnd = calendarUtil.endOfDay(this.currentDate);
|
||||
const expanded = calendarUtil.expandRecurringEvents(events, dayStart, dayEnd);
|
||||
return expanded.filter(event => {
|
||||
const end = event.all_day ? calendarUtil.endOfDay(event.time_end) : calendarUtil.timedEnd(event);
|
||||
return calendarUtil.rangesOverlap(event.time_start, end, dayStart, dayEnd)
|
||||
&& this.calendars.some(c => event.calendars.some(c2 => c2 === c.id));
|
||||
});
|
||||
}
|
||||
|
||||
groupEventsForDay(events) {
|
||||
const dayStart = calendarUtil.startOfDay(this.currentDate);
|
||||
const dayEnd = calendarUtil.endOfDay(this.currentDate);
|
||||
return {
|
||||
day: this.currentDate,
|
||||
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);
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
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(this.currentDate);
|
||||
this.scrollTop = (_saved?.dateKey === dateKey) ? _saved.scrollTop : defaultTarget;
|
||||
this.addEventListener('scroll', () => { _saved = { dateKey, scrollTop: this.scrollTop }; }, { passive: true });
|
||||
} else {
|
||||
this.scrollTop = defaultTarget;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
register(DayView)
|
||||
Reference in New Issue
Block a user