Cleanup, layout fixes, better event colors.

This commit is contained in:
Leo Vasanko 2025-08-20 14:57:04 -06:00
parent c0d76109a1
commit 93c23c594c
5 changed files with 58 additions and 45 deletions

6
calendar-main.css Normal file
View File

@ -0,0 +1,6 @@
/* Calendar CSS - Main file with imports */
@import url('colors.css');
@import url('layout.css');
@import url('cells.css');
@import url('events.css');
@import url('utilities.css');

View File

@ -113,7 +113,7 @@ class InfiniteCalendar {
const handleWheel = e => {
e.preventDefault()
e.stopPropagation()
const currentYear = parseInt(this.weekLabel.textContent)
const currentYear = parseInt(this.yearLabel.textContent)
const topDisplayIndex = Math.floor(this.viewport.scrollTop / this.rowHeight)
const currentWeekIndex = topDisplayIndex + this.minVirtualWeek
const sensitivity = 1/3
@ -125,7 +125,7 @@ class InfiniteCalendar {
this.navigateToYear(newYear, currentWeekIndex)
setTimeout(() => throttled = false, 100)
}
this.weekLabel.addEventListener('wheel', handleWheel, { passive: false })
this.yearLabel.addEventListener('wheel', handleWheel, { passive: false })
}
navigateTo(date) {
@ -206,15 +206,15 @@ class InfiniteCalendar {
}
createHeader() {
this.weekLabel = document.createElement('div')
this.weekLabel.className = 'dow-label'
this.weekLabel.textContent = isoWeekInfo(new Date()).year
this.header.appendChild(this.weekLabel)
this.yearLabel = document.createElement('div')
this.yearLabel.className = 'year-label'
this.yearLabel.textContent = isoWeekInfo(new Date()).year
this.header.appendChild(this.yearLabel)
const names = this.getLocalizedWeekdayNames()
names.forEach((name, i) => {
const c = document.createElement('div')
c.className = 'cell dow'
c.classList.add('dow')
const dayIdx = (i + 1) % 7
if (this.weekend[dayIdx]) c.classList.add('weekend')
c.textContent = name
@ -294,7 +294,7 @@ class InfiniteCalendar {
const topVW = topDisplayIndex + this.minVirtualWeek
const monday = this.getMondayForVirtualWeek(topVW)
const { year } = isoWeekInfo(monday)
if (this.weekLabel.textContent !== String(year)) this.weekLabel.textContent = year
if (this.yearLabel.textContent !== String(year)) this.yearLabel.textContent = year
}
createWeekElement(virtualWeek) {
@ -626,7 +626,7 @@ class InfiniteCalendar {
title: eventData.title,
startDate: eventData.startDate,
endDate: eventData.endDate,
color: this.generateEventColor()
colorId: this.generateEventColorId()
}
const startDate = new Date(fromLocalString(event.startDate))
@ -641,12 +641,9 @@ class InfiniteCalendar {
this.refreshEvents()
}
generateEventColor() {
const colors = [
'#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4', '#feca57',
'#ff9ff3', '#54a0ff', '#5f27cd', '#00d2d3', '#ff9f43'
]
return colors[Math.floor(Math.random() * colors.length)]
generateEventColorId() {
// Return a color ID from 0-11 for 12 evenly spaced hues
return Math.floor(Math.random() * 12)
}
refreshEvents() {
@ -705,22 +702,9 @@ class InfiniteCalendar {
createOverlaySpan(overlay, w) {
const span = document.createElement('div')
span.className = 'event-span'
span.className = `event-span event-color-${w.colorId}`
span.style.gridColumn = `${w.startIdx + 1} / ${w.endIdx + 2}`
span.style.gridRow = `${w._row}`
span.style.height = '1.2em'
span.style.borderRadius = '.4em'
span.style.fontSize = '.75em'
span.style.lineHeight = '1.2'
span.style.padding = '0 .5em'
span.style.whiteSpace = 'nowrap'
span.style.overflow = 'hidden'
span.style.textOverflow = 'ellipsis'
span.style.background = w.color
span.style.color = 'white'
span.style.fontWeight = '600'
span.style.pointerEvents = 'auto'
span.style.zIndex = '1'
span.textContent = w.title
span.title = `${w.title} (${w.startDate === w.endDate ? w.startDate : w.startDate + ' - ' + w.endDate})`
overlay.appendChild(span)

View File

@ -1,10 +1,9 @@
/* Color tokens */
:root {
--bg: #f6f7fb;
--panel: #fff;
--today: #f83;
--ink: #111;
--ink-rgb: 17, 17, 17;
--ink: #222;
--inkstrong: #000;
--muted: #888;
--weekend: #888;
--firstday: #000;
@ -27,14 +26,26 @@
.oct { background: hsl(18 78% 95%) }
.nov { background: hsl(18 78% 88%) }
.event-color-0 { background: hsl(0, 40%, 80%); }
.event-color-1 { background: hsl(30, 40%, 80%); }
.event-color-2 { background: hsl(60, 40%, 80%); }
.event-color-3 { background: hsl(90, 40%, 80%); }
.event-color-4 { background: hsl(120, 40%, 80%); }
.event-color-5 { background: hsl(150, 40%, 80%); }
.event-color-6 { background: hsl(180, 40%, 80%); }
.event-color-7 { background: hsl(210, 40%, 80%); }
.event-color-8 { background: hsl(240, 40%, 80%); }
.event-color-9 { background: hsl(270, 40%, 80%); }
.event-color-10 { background: hsl(300, 40%, 80%); }
.event-color-11 { background: hsl(330, 40%, 80%); }
/* Color tokens (dark) */
@media (prefers-color-scheme: dark) {
:root {
--bg: radial-gradient(1200px 800px at 20% -10%, #1c2130 0%, #0c0f16 35%, #0a0b11 100%);
--panel: #111318;
--today: #f83;
--ink: #ddd;
--ink-rgb: 221, 221, 221;
--inkstrong: #fff;
--muted: #888;
--weekend: #999;
--firstday: #fff;
@ -56,15 +67,29 @@
.sep { background: hsl(18 70% 18%) }
.oct { background: hsl(18 70% 26%) }
.nov { background: hsl(18 70% 18%) }
.event-color-0 { background: hsl(0, 40%, 50%); }
.event-color-1 { background: hsl(30, 40%, 50%); }
.event-color-2 { background: hsl(60, 40%, 50%); }
.event-color-3 { background: hsl(90, 40%, 50%); }
.event-color-4 { background: hsl(120, 40%, 50%); }
.event-color-5 { background: hsl(150, 40%, 50%); }
.event-color-6 { background: hsl(180, 40%, 50%); }
.event-color-7 { background: hsl(210, 40%, 50%); }
.event-color-8 { background: hsl(240, 40%, 50%); }
.event-color-9 { background: hsl(270, 40%, 50%); }
.event-color-10 { background: hsl(300, 40%, 50%); }
.event-color-11 { background: hsl(330, 40%, 50%); }
}
/* Selection styles */
.weekend { color: var(--weekend) }
.firstday { color: var(--firstday); text-shadow: 0 0 .1em rgba(var(--ink-rgb), .5) }
.firstday { color: var(--firstday); text-shadow: 0 0 .1em; }
.selected {
background: var(--select);
border: 2px solid rgba(var(--ink-rgb), .3);
border: 2px solid var(--ink);
box-shadow: inset 0 0 0 1px rgba(255,255,255,.3);
}
.selected .event { opacity: .7 }

View File

@ -4,9 +4,8 @@
padding: .1em .3em;
margin: .1em 0;
border-radius: .2em;
color: white;
font-weight: 500;
white-space: nowrap;
white-space: normal;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
@ -15,14 +14,13 @@
cursor: pointer;
z-index: 5;
}
.event:hover { opacity: .8 }
/* Spanning events in the overlay (grid-positioned, not absolutely measured) */
.event-span {
font-size: .75em;
padding: 0 .5em;
border-radius: .4em;
color: white;
color: var(--inkstrong);
font-weight: 600;
white-space: nowrap;
overflow: hidden;

View File

@ -51,13 +51,11 @@ header {
.calendar-header, #calendar-header {
display: grid;
grid-template-columns: var(--label-w) repeat(7, var(--cell-w)) var(--overlay-w);
border-bottom: .1em solid var(--muted);
border-bottom: .2em solid var(--muted);
align-items: last baseline;
flex-shrink: 0;
width: 100%;
}
.calendar-header .dow-label { display:grid; place-items:center; height: var(--cell-h); color: var(--muted) }
.overlay-header-spacer { grid-column: -2 / -1 }
/* Main container */
.calendar-container, #calendar-container {
@ -108,16 +106,18 @@ header {
}
/* Label cells */
.dow-label, .week-label {
.year-label, .week-label {
display: grid;
place-items: center;
width: 100%;
height: var(--cell-h);
color: var(--muted);
cursor: ns-resize;
font-size: 1.2em;
}
.week-label {
height: var(--cell-h);
}
/* 7-day grid inside each week row */
.week-row > .days-grid {
grid-column: 2 / span 7;