fix(timeline): CodeRabbit review corrections

- Fix cols overflow: use (containerWidth - GAP) formula so the grid
  never exceeds the container width
- Explicitly pin "unknown" date keys to the end of the sort rather than
  relying on alphabetical accident ("u" > digits)
- Guard buildLabel against non-YYYY-MM keys with finite/range checks
  and an isNaN fallback to "Unknown Date"
- Clear similarSourceFolderId, similarFolderId, and similarCrop when
  switching to the timeline view so all similar-state is consistently
  reset
This commit is contained in:
2026-06-08 22:26:28 +01:00
parent 0ab156d2d9
commit a2804d8c1b
2 changed files with 12 additions and 4 deletions
+11 -3
View File
@@ -15,7 +15,11 @@ interface TimelineGroup {
function buildLabel(key: string): string {
if (key === "unknown") return "Unknown Date";
const [yearStr, monthStr] = key.split("-");
const date = new Date(Number(yearStr), Number(monthStr) - 1);
const year = Number(yearStr);
const month = Number(monthStr);
if (!isFinite(year) || !isFinite(month) || month < 1 || month > 12) return "Unknown Date";
const date = new Date(year, month - 1);
if (isNaN(date.getTime())) return "Unknown Date";
return date.toLocaleDateString(undefined, { month: "long", year: "numeric" });
}
@@ -32,7 +36,11 @@ function groupImages(images: ImageRecord[]): TimelineGroup[] {
bucket.push(img);
}
return Array.from(map.entries())
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
.sort(([a], [b]) => {
if (a === "unknown") return 1;
if (b === "unknown") return -1;
return a < b ? -1 : a > b ? 1 : 0;
})
.map(([key, imgs]) => ({ key, label: buildLabel(key), images: imgs }));
}
@@ -67,7 +75,7 @@ export function Timeline() {
const tileSize = tileSizeForZoom(zoomPreset);
const cols = useMemo(
() => Math.max(1, Math.floor((containerWidth + GAP) / (tileSize + GAP))),
() => Math.max(1, Math.floor((containerWidth - GAP) / (tileSize + GAP))),
[containerWidth, tileSize],
);
+1 -1
View File
@@ -906,7 +906,7 @@ export const useGalleryStore = create<GalleryState>((set, get) => ({
setView: (activeView) => {
if (activeView === "timeline") {
set({ activeView, sort: "taken_asc", images: [], loadedCount: 0, collectionTitle: null, similarSourceImageId: null, similarHasMore: false, imageLoadError: null });
set({ activeView, sort: "taken_asc", images: [], loadedCount: 0, collectionTitle: null, similarSourceImageId: null, similarSourceFolderId: null, similarFolderId: null, similarHasMore: false, similarCrop: null, imageLoadError: null });
void get().loadImages(true);
return;
}