fix: guard data.sessions against undefined and enlarge tiles to 13px with 920px minimum width

This commit is contained in:
katR 2026-10-10 13:21:53 +05:30
parent d332848d73
commit 0a4ae66c92
3 changed files with 119 additions and 117 deletions

View file

@ -101,7 +101,7 @@ function HeatmapView() {
sessionTitle: "All Sessions (Global)" sessionTitle: "All Sessions (Global)"
}; };
} }
const session = data.sessions.find((s) => s.id === selectedSessionId); const session = (data.sessions || []).find((s) => s.id === selectedSessionId);
if (!session) { if (!session) {
return { return {
summary: data.summary, summary: data.summary,
@ -320,8 +320,8 @@ function HeatmapView() {
maxWidth: 240 maxWidth: 240
} }
}, },
/* @__PURE__ */ import_react.default.createElement("option", { value: "all" }, "All Sessions (", data.sessions.length, " total)"), /* @__PURE__ */ import_react.default.createElement("option", { value: "all" }, "All Sessions (", (data.sessions || []).length, " total)"),
data.sessions.map((s) => /* @__PURE__ */ import_react.default.createElement("option", { key: s.id, value: s.id }, new Date(s.createdAt).toLocaleDateString(), " \xB7 ", s.title.slice(0, 32))) (data.sessions || []).map((s) => /* @__PURE__ */ import_react.default.createElement("option", { key: s.id, value: s.id }, new Date(s.createdAt).toLocaleDateString(), " \xB7 ", s.title.slice(0, 32)))
)), /* @__PURE__ */ import_react.default.createElement( )), /* @__PURE__ */ import_react.default.createElement(
"button", "button",
{ {
@ -450,17 +450,17 @@ function HeatmapView() {
width: "100%", width: "100%",
overflowX: "auto", overflowX: "auto",
WebkitOverflowScrolling: "touch", WebkitOverflowScrolling: "touch",
paddingBottom: "8px" paddingBottom: "10px"
} }
}, },
/* @__PURE__ */ import_react.default.createElement( /* @__PURE__ */ import_react.default.createElement("div", { style: { minWidth: "920px", width: "100%", display: "inline-block" } }, /* @__PURE__ */ import_react.default.createElement(
"svg", "svg",
{ {
viewBox: "0 0 895 142", viewBox: "0 0 920 152",
style: { style: {
width: "100%", width: "100%",
minWidth: "860px", minWidth: "920px",
height: "142px", height: "152px",
display: "block", display: "block",
overflow: "visible" overflow: "visible"
} }
@ -469,7 +469,7 @@ function HeatmapView() {
"text", "text",
{ {
key: i, key: i,
x: 34 + m.col * 16, x: 36 + m.col * 16.5,
y: 12, y: 12,
fontSize: 11, fontSize: 11,
fill: "var(--dsw-alias-label-tertiary, #888888)", fill: "var(--dsw-alias-label-tertiary, #888888)",
@ -477,25 +477,25 @@ function HeatmapView() {
}, },
m.label m.label
)), )),
/* @__PURE__ */ import_react.default.createElement("text", { x: 4, y: 49, fontSize: 10, fill: "var(--dsw-alias-label-tertiary, #888888)", fontFamily: "inherit" }, "Mon"), /* @__PURE__ */ import_react.default.createElement("text", { x: 4, y: 51, fontSize: 10, fill: "var(--dsw-alias-label-tertiary, #888888)", fontFamily: "inherit" }, "Mon"),
/* @__PURE__ */ import_react.default.createElement("text", { x: 4, y: 81, fontSize: 10, fill: "var(--dsw-alias-label-tertiary, #888888)", fontFamily: "inherit" }, "Wed"), /* @__PURE__ */ import_react.default.createElement("text", { x: 4, y: 85, fontSize: 10, fill: "var(--dsw-alias-label-tertiary, #888888)", fontFamily: "inherit" }, "Wed"),
/* @__PURE__ */ import_react.default.createElement("text", { x: 4, y: 113, fontSize: 10, fill: "var(--dsw-alias-label-tertiary, #888888)", fontFamily: "inherit" }, "Fri"), /* @__PURE__ */ import_react.default.createElement("text", { x: 4, y: 119, fontSize: 10, fill: "var(--dsw-alias-label-tertiary, #888888)", fontFamily: "inherit" }, "Fri"),
calendarGrid.map((week, colIdx) => /* @__PURE__ */ import_react.default.createElement("g", { key: colIdx, transform: `translate(${34 + colIdx * 16}, 22)` }, week.map((day, rowIdx) => { calendarGrid.map((week, colIdx) => /* @__PURE__ */ import_react.default.createElement("g", { key: colIdx, transform: `translate(${36 + colIdx * 16.5}, 22)` }, week.map((day, rowIdx) => {
if (!day) return null; if (!day) return null;
const lvl = day.stats.level || 0; const lvl = day.stats.level || 0;
const bg = DEEPSEEK_LEVELS[lvl]; const bg = DEEPSEEK_LEVELS[lvl];
const isSelected = selectedDate === day.date; const isSelected = selectedDate === day.date;
const isHovered = hoveredDay?.date === day.date; const isHovered = hoveredDay?.date === day.date;
const strokeColor = isSelected ? "#ffffff" : isHovered ? "#5686fe" : lvl === 0 ? "rgba(255, 255, 255, 0.06)" : "transparent"; const strokeColor = isSelected ? "#ffffff" : isHovered ? "#5686fe" : lvl === 0 ? "rgba(255, 255, 255, 0.06)" : "transparent";
const strokeWidth = isSelected ? 1.8 : isHovered ? 1.4 : 1; const strokeWidth = isSelected ? 2 : isHovered ? 1.5 : 1;
return /* @__PURE__ */ import_react.default.createElement( return /* @__PURE__ */ import_react.default.createElement(
"rect", "rect",
{ {
key: rowIdx, key: rowIdx,
x: 0, x: 0,
y: rowIdx * 16, y: rowIdx * 17,
width: 12.5, width: 13,
height: 12.5, height: 13,
rx: 2.5, rx: 2.5,
ry: 2.5, ry: 2.5,
fill: bg, fill: bg,
@ -521,7 +521,7 @@ function HeatmapView() {
} }
); );
}))) })))
), )),
/* @__PURE__ */ import_react.default.createElement( /* @__PURE__ */ import_react.default.createElement(
"div", "div",
{ {

File diff suppressed because one or more lines are too long

View file

@ -127,7 +127,7 @@ export function HeatmapView() {
}; };
} }
const session = data.sessions.find((s) => s.id === selectedSessionId); const session = (data.sessions || []).find((s) => s.id === selectedSessionId);
if (!session) { if (!session) {
return { return {
summary: data.summary, summary: data.summary,
@ -383,8 +383,8 @@ export function HeatmapView() {
maxWidth: 240, maxWidth: 240,
}} }}
> >
<option value="all">All Sessions ({data.sessions.length} total)</option> <option value="all">All Sessions ({(data.sessions || []).length} total)</option>
{data.sessions.map((s) => ( {(data.sessions || []).map((s) => (
<option key={s.id} value={s.id}> <option key={s.id} value={s.id}>
{new Date(s.createdAt).toLocaleDateString()} · {s.title.slice(0, 32)} {new Date(s.createdAt).toLocaleDateString()} · {s.title.slice(0, 32)}
</option> </option>
@ -537,7 +537,7 @@ export function HeatmapView() {
)} )}
</div> </div>
{/* Comfortably sized GitHub-Style Calendar SVG with smooth horizontal scroll */} {/* Generously sized GitHub-Style Calendar with smooth horizontal scroll */}
{calendarGrid && ( {calendarGrid && (
<div <div
ref={scrollContainerRef} ref={scrollContainerRef}
@ -545,107 +545,109 @@ export function HeatmapView() {
width: "100%", width: "100%",
overflowX: "auto", overflowX: "auto",
WebkitOverflowScrolling: "touch", WebkitOverflowScrolling: "touch",
paddingBottom: "8px", paddingBottom: "10px",
}} }}
> >
<svg <div style={{ minWidth: "920px", width: "100%", display: "inline-block" }}>
viewBox="0 0 895 142" <svg
style={{ viewBox="0 0 920 152"
width: "100%", style={{
minWidth: "860px", width: "100%",
height: "142px", minWidth: "920px",
display: "block", height: "152px",
overflow: "visible", display: "block",
}} overflow: "visible",
> }}
{/* Month labels */} >
{monthHeaders.map((m, i) => ( {/* Month labels */}
<text {monthHeaders.map((m, i) => (
key={i} <text
x={34 + m.col * 16} key={i}
y={12} x={36 + m.col * 16.5}
fontSize={11} y={12}
fill="var(--dsw-alias-label-tertiary, #888888)" fontSize={11}
fontFamily="inherit" fill="var(--dsw-alias-label-tertiary, #888888)"
> fontFamily="inherit"
{m.label} >
{m.label}
</text>
))}
{/* Day of week labels */}
<text x={4} y={51} fontSize={10} fill="var(--dsw-alias-label-tertiary, #888888)" fontFamily="inherit">
Mon
</text>
<text x={4} y={85} fontSize={10} fill="var(--dsw-alias-label-tertiary, #888888)" fontFamily="inherit">
Wed
</text>
<text x={4} y={119} fontSize={10} fill="var(--dsw-alias-label-tertiary, #888888)" fontFamily="inherit">
Fri
</text> </text>
))}
{/* Day of week labels */} {/* Day Tiles: Generously sized 13px tiles with 16.5px step */}
<text x={4} y={49} fontSize={10} fill="var(--dsw-alias-label-tertiary, #888888)" fontFamily="inherit"> {calendarGrid.map((week, colIdx) => (
Mon <g key={colIdx} transform={`translate(${36 + colIdx * 16.5}, 22)`}>
</text> {week.map((day, rowIdx) => {
<text x={4} y={81} fontSize={10} fill="var(--dsw-alias-label-tertiary, #888888)" fontFamily="inherit"> if (!day) return null;
Wed
</text>
<text x={4} y={113} fontSize={10} fill="var(--dsw-alias-label-tertiary, #888888)" fontFamily="inherit">
Fri
</text>
{/* Day Tiles: comfortable 12.5px size with 16px step */} const lvl = day.stats.level || 0;
{calendarGrid.map((week, colIdx) => ( const bg = DEEPSEEK_LEVELS[lvl];
<g key={colIdx} transform={`translate(${34 + colIdx * 16}, 22)`}> const isSelected = selectedDate === day.date;
{week.map((day, rowIdx) => { const isHovered = hoveredDay?.date === day.date;
if (!day) return null;
const lvl = day.stats.level || 0; // GitHub-style glow & outline
const bg = DEEPSEEK_LEVELS[lvl]; const strokeColor = isSelected
const isSelected = selectedDate === day.date; ? "#ffffff"
const isHovered = hoveredDay?.date === day.date; : isHovered
? "#5686fe"
: lvl === 0
? "rgba(255, 255, 255, 0.06)"
: "transparent";
// GitHub-style glow & outline const strokeWidth = isSelected ? 2 : isHovered ? 1.5 : 1;
const strokeColor = isSelected
? "#ffffff"
: isHovered
? "#5686fe"
: lvl === 0
? "rgba(255, 255, 255, 0.06)"
: "transparent";
const strokeWidth = isSelected ? 1.8 : isHovered ? 1.4 : 1; return (
<rect
return ( key={rowIdx}
<rect x={0}
key={rowIdx} y={rowIdx * 17}
x={0} width={13}
y={rowIdx * 16} height={13}
width={12.5} rx={2.5}
height={12.5} ry={2.5}
rx={2.5} fill={bg}
ry={2.5} stroke={strokeColor}
fill={bg} strokeWidth={strokeWidth}
stroke={strokeColor} style={{
strokeWidth={strokeWidth} cursor: "pointer",
style={{ transition: "fill 0.12s ease, stroke 0.12s ease",
cursor: "pointer", filter: isSelected
transition: "fill 0.12s ease, stroke 0.12s ease", ? "drop-shadow(0 0 6px rgba(86, 134, 254, 0.9))"
filter: isSelected : isHovered
? "drop-shadow(0 0 6px rgba(86, 134, 254, 0.9))" ? "drop-shadow(0 0 4px rgba(86, 134, 254, 0.7))"
: isHovered : lvl === 4
? "drop-shadow(0 0 4px rgba(86, 134, 254, 0.7))" ? "drop-shadow(0 0 4px rgba(79, 133, 255, 0.6))"
: lvl === 4 : "none",
? "drop-shadow(0 0 4px rgba(79, 133, 255, 0.6))" }}
: "none", onClick={() => {
}} setSelectedDate(isSelected ? null : day.date);
onClick={() => { }}
setSelectedDate(isSelected ? null : day.date); onMouseEnter={(e) => {
}} setHoveredDay({ date: day.date, stats: day.stats });
onMouseEnter={(e) => { const rect = e.currentTarget.getBoundingClientRect();
setHoveredDay({ date: day.date, stats: day.stats }); setTooltipPos({ x: rect.left + rect.width / 2, y: rect.top - 8 });
const rect = e.currentTarget.getBoundingClientRect(); }}
setTooltipPos({ x: rect.left + rect.width / 2, y: rect.top - 8 }); onMouseLeave={() => {
}} setHoveredDay(null);
onMouseLeave={() => { setTooltipPos(null);
setHoveredDay(null); }}
setTooltipPos(null); />
}} );
/> })}
); </g>
})} ))}
</g> </svg>
))} </div>
</svg>
{/* Bottom Legend */} {/* Bottom Legend */}
<div <div