diff --git a/client/src/App.jsx b/client/src/App.jsx index 505f7d9..133fb81 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -120,7 +120,7 @@ export default function App() { setView('library')}> Library {total !== null && ( - + {total.toLocaleString()} )} @@ -192,7 +192,7 @@ export default function App() {

)} {photos.length === 0 && !loading && !error && ( -
+
{hasFilter ? (

No photos match these filters.

) : ( @@ -207,7 +207,7 @@ export default function App() {
{loading &&

Loading…

} {nextCursor === null && photos.length > 0 && !loading && ( -

+

— {total?.toLocaleString()} photo{total === 1 ? '' : 's'} —

)} @@ -216,7 +216,7 @@ export default function App() { {/* Map */} {view === 'map' && ( - Loading map…

}> + Loading map…

}> openLightbox([photo], 0)} />
)} diff --git a/client/src/components/DetailPanel.jsx b/client/src/components/DetailPanel.jsx index 980dbc1..840815e 100644 --- a/client/src/components/DetailPanel.jsx +++ b/client/src/components/DetailPanel.jsx @@ -77,7 +77,7 @@ export default function DetailPanel({ photoId }) { function Section({ label, children }) { return (
-
+
{label}
{children} @@ -88,7 +88,7 @@ function Section({ label, children }) { function Row({ k, v, mono }) { return (
- {k} + {k} {/* Meta */} -
+
{fmtDate(photo.date_taken)} {[fmtSize(photo.filesize), photo.width && `${photo.width}×${photo.height}`].filter(Boolean).join(' · ')} {photo.camera_model && ( - + {photo.camera_model} )} @@ -77,7 +77,7 @@ export default function DuplicateGroup({ photos, onDismiss, onOpen }) { borderTop: '1px solid #1a1a1a', display: 'flex', alignItems: 'center', gap: 12, }}> - + {photos.length} similar photos @@ -333,7 +333,7 @@ export default function SettingsPanel({ onClose }) { handleSetting('preview_quality', v)} /> -

+

Changes apply to newly ingested photos. Existing thumbnails are not regenerated.

@@ -343,7 +343,7 @@ export default function SettingsPanel({ onClose }) { handleSetting('dedupe_threshold', v)} /> -

+

Hamming distance — lower = stricter (fewer, more exact matches).

@@ -390,7 +390,7 @@ export default function SettingsPanel({ onClose }) { error={syncError.icloud} onSync={() => handleSync('icloud')} /> -

+

First run: docker exec <container> icloudpd --username <id> --auth-only --cookie-directory /data/icloud-cookies

@@ -398,7 +398,7 @@ export default function SettingsPanel({ onClose }) { {/* Amazon Photos */} -

+

Request your library at amazon.com → Account → Request Your Data → Amazon Photos. Extract the ZIP, copy to your server, then add the folder path here.

@@ -430,7 +430,7 @@ export default function SettingsPanel({ onClose }) {
-

+

Also add the iCloud download folder to Watch Folders once sync runs.

@@ -441,7 +441,7 @@ export default function SettingsPanel({ onClose }) { {cleared ? '✓ Done' : 'Clear dismissed duplicates'} -

+

Resets all "Not duplicates" decisions so groups reappear in the review list.

@@ -459,7 +459,7 @@ function Section({ title, children }) {
{title} @@ -610,7 +610,7 @@ function SyncControls({ job, error, onSync }) { )} {lastRunLabel && !job.running && ( - + Last: {lastRunLabel} {job.exitCode !== null && ( @@ -624,7 +624,7 @@ function SyncControls({ job, error, onSync }) {