web(review): switch cause tabs to PhotoGrid, add date-from-path suggestion
- CauseGroupCard now wraps PhotoGrid so selection, keyboard nav, and preview flow through the standard timeline plumbing. Per-tile hover Approve/Archive and the group-wide Approve all are gone — the bottom BulkActionBar's review-section Keep/Archive handle single + bulk. - Low Resolution tab opts into a new PhotoTile dimensionBadge prop so WxH stays visible on each tile. - New suggestDateFromPath util parses YYYY-MM-DD from filename or folder path. RightSidebar surfaces it as an amber Apply row above the Taken-at input whenever the photo lacks a trusted TakenAt. - BulkActionBar gains a "Accept date & Keep" button (review section only) that patches each selected photo's TakenAt from its path suggestion when available, then approves. - Drop the Same folder / Same camera / Same year strips and the RelatedStrip component from the metadata sidebar. Also bundles in-progress Notes route + tile components and small tweaks to LeftSidebar, DuplicatesView, CrossFolderGroupCard, and photoprism.ts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
57
web/src/lib/utils/suggestDateFromPath.ts
Normal file
57
web/src/lib/utils/suggestDateFromPath.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Best-effort calendar date guessed from a photo's filename / parent
|
||||
* folders. Returns `YYYY-MM-DD` only when year + month + day are all
|
||||
* present and form a real date; returns `null` for year-only or
|
||||
* unparseable inputs.
|
||||
*
|
||||
* Used by the EXIF Stripped review tab to pre-fill the metadata
|
||||
* sidebar's date suggestion row.
|
||||
*/
|
||||
|
||||
import { isValidISODate } from '$lib/services/photoprism';
|
||||
|
||||
interface Input {
|
||||
fileName?: string;
|
||||
path?: string;
|
||||
}
|
||||
|
||||
function pad2(n: number): string {
|
||||
return n < 10 ? `0${n}` : String(n);
|
||||
}
|
||||
|
||||
function tryDate(y: number, m: number, d: number): string | null {
|
||||
if (y < 1900 || y > 2100) return null;
|
||||
if (m < 1 || m > 12) return null;
|
||||
if (d < 1 || d > 31) return null;
|
||||
const iso = `${y}-${pad2(m)}-${pad2(d)}`;
|
||||
return isValidISODate(iso) ? iso : null;
|
||||
}
|
||||
|
||||
// `YYYY[sep]MM[sep]DD` where `sep` is an optional `-` or `_`. Anchored by
|
||||
// non-digit boundaries on both sides so `IMG_20070612_135421.jpg` matches
|
||||
// `20070612` cleanly without bleeding into the trailing timestamp.
|
||||
const BASENAME_YMD = /(?<!\d)(\d{4})[-_]?(\d{2})[-_]?(\d{2})(?!\d)/;
|
||||
|
||||
// Path variant accepts `/` as a separator too — `2007/06/12`, `2007-06-12/`.
|
||||
const PATH_YMD = /(?<!\d)(\d{4})[-_/](\d{2})[-_/](\d{2})(?!\d)/;
|
||||
|
||||
export function suggestDateFromPath(input: Input): string | null {
|
||||
const fileName = (input.fileName ?? '').trim();
|
||||
const path = (input.path ?? '').trim();
|
||||
|
||||
const fnMatch = fileName.match(BASENAME_YMD);
|
||||
if (fnMatch) {
|
||||
const iso = tryDate(Number(fnMatch[1]), Number(fnMatch[2]), Number(fnMatch[3]));
|
||||
if (iso) return iso;
|
||||
}
|
||||
|
||||
if (path) {
|
||||
const pMatch = path.match(PATH_YMD);
|
||||
if (pMatch) {
|
||||
const iso = tryDate(Number(pMatch[1]), Number(pMatch[2]), Number(pMatch[3]));
|
||||
if (iso) return iso;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user