Make calendar cells clickable and improve mood heatmap colors

This commit is contained in:
2026-04-11 19:32:51 +02:00
parent eba5f915c1
commit a3b24ccac1
2 changed files with 71 additions and 11 deletions
+28 -2
View File
@@ -417,11 +417,19 @@ button {
width: 0.8rem;
height: 0.8rem;
border-radius: 6px;
background: rgba(255, 255, 255, 0.08);
background: rgba(132, 193, 208, 0.55);
}
.calendar-dot--bad {
background: rgba(255, 117, 117, 0.85);
}
.calendar-dot--warn {
background: rgba(255, 171, 122, 0.82);
}
.calendar-dot--1 {
background: rgba(126, 239, 205, 0.32);
background: rgba(116, 226, 183, 0.7);
}
.calendar-dot--2 {
@@ -444,6 +452,24 @@ button {
font-size: 11px;
}
.calendar-link {
cursor: pointer;
}
.calendar-cell--active {
transition: transform 140ms ease, filter 140ms ease, stroke 140ms ease, stroke-width 140ms ease;
transform-box: fill-box;
transform-origin: center;
}
.calendar-link:hover .calendar-cell--active,
.calendar-link:focus .calendar-cell--active,
.calendar-link:focus-visible .calendar-cell--active {
filter: brightness(1.08);
stroke: rgba(255, 255, 255, 0.8);
stroke-width: 1.1;
}
.line-chart,
.bar-chart {
min-height: 17rem;
+42 -8
View File
@@ -366,6 +366,32 @@
return;
}
function calendarColor(entry) {
if (!entry) {
return "rgba(255, 255, 255, 0.06)";
}
const ratio = Math.max(0, Math.min(1, Number(entry.score) / Math.max(Number(entry.max || 1), 1)));
if (ratio <= 0.36) {
return `rgba(255, 117, 117, ${0.28 + (ratio * 0.8)})`;
}
if (ratio <= 0.52) {
return `rgba(255, 171, 122, ${0.28 + (ratio * 0.7)})`;
}
if (ratio <= 0.68) {
return `rgba(132, 193, 208, ${0.24 + (ratio * 0.55)})`;
}
if (ratio <= 0.84) {
return `rgba(116, 226, 183, ${0.28 + (ratio * 0.6)})`;
}
return `rgba(112, 240, 182, ${0.38 + (ratio * 0.52)})`;
}
const map = new Map(items.map(item => [item.date, item]));
const end = new Date();
const start = new Date(end);
@@ -386,12 +412,13 @@
cursor.setDate(cursor.getDate() + 1);
}
const width = Math.ceil(days.length / 7) * 17 + 56;
const totalWeeks = Math.floor((days.length - 1) / 7) + 1;
const height = 148;
const cellSize = 12;
const cellGap = 5;
const xOffset = 34;
const yOffset = 24;
const width = xOffset + ((totalWeeks - 1) * (cellSize + cellGap)) + cellSize + 28;
const monthLabels = [];
let lastMonth = -1;
@@ -400,10 +427,7 @@
const row = item.weekday === 0 ? 6 : item.weekday - 1;
const x = xOffset + (week * (cellSize + cellGap));
const y = yOffset + (row * (cellSize + cellGap));
const level = item.entry ? Math.max(0, Math.min(1, Number(item.entry.score) / Math.max(Number(item.entry.max || 1), 1))) : 0;
const fill = item.entry
? `rgba(126, 239, 205, ${0.18 + (level * 0.72)})`
: "rgba(255, 255, 255, 0.06)";
const fill = calendarColor(item.entry);
if (item.day <= 7 && item.month !== lastMonth) {
monthLabels.push({
@@ -417,7 +441,16 @@
? `${item.date}: ${formatNumber(Number(item.entry.score))} Punkte · ${item.entry.label}`
: `${item.date}: kein Eintrag`;
if (!item.entry) {
return `<rect x="${x}" y="${y}" width="${cellSize}" height="${cellSize}" rx="4" fill="${fill}"><title>${title}</title></rect>`;
}
return `
<a class="calendar-link" href="/track?date=${encodeURIComponent(item.date)}" aria-label="${title}">
<rect class="calendar-cell calendar-cell--active" x="${x}" y="${y}" width="${cellSize}" height="${cellSize}" rx="4" fill="${fill}"></rect>
<title>${title}</title>
</a>
`;
}).join("");
container.innerHTML = `
@@ -429,14 +462,15 @@
${cells}
</svg>
<div class="calendar-legend">
<span>weniger</span>
<span>schlecht</span>
<div class="calendar-scale">
<span class="calendar-dot calendar-dot--bad"></span>
<span class="calendar-dot calendar-dot--warn"></span>
<span class="calendar-dot"></span>
<span class="calendar-dot calendar-dot--1"></span>
<span class="calendar-dot calendar-dot--2"></span>
<span class="calendar-dot calendar-dot--3"></span>
</div>
<span>mehr</span>
<span>gut</span>
</div>
`;
}