feat: photo/video capture-date pipeline + premium UI/UX overhaul
Backend — Photos timeline now groups by real capture date instead of upload time. New MediaMetadataService (FileLifecycleHook) extracts EXIF DateTimeOriginal from images and container creation_time from videos (mov/mp4/mkv) via nom-exif, timezone-correct (OffsetTimeOriginal), persisting captured_at so the existing media_sort_date trigger takes over. Adds POST /admin/photos/metadata/reextract to backfill existing media. Falls back to upload date when no embedded date exists. Frontend — premium grid cards: combined metadata line (relative date · size, owner avatar when shared), custom selection checkbox with a clear checked state, uniform full-width 4:3 thumbnail tiles independent of filename length, centered file-type icons, and a hit-test fix so checkbox/star/kebab clicks reach the controls (the decorative thumbnail no longer captures pointer events). Notification messages internationalised across all 16 locales. Broader polish: design tokens, a11y/focus-visible states, brand + PWA assets. Chore — bump semver-compatible dependencies (cargo upgrade); add nom-exif 3.6.1. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+98
-3
@@ -157,7 +157,11 @@
|
||||
"close": "닫기",
|
||||
"delete_permanently": "영구 삭제",
|
||||
"empty_trash": "휴지통 비우기",
|
||||
"open_parent_folder": "상위 폴더로 이동"
|
||||
"open_parent_folder": "상위 폴더로 이동",
|
||||
"add": "Add",
|
||||
"apply": "Apply",
|
||||
"clear": "Clear",
|
||||
"remove": "Remove"
|
||||
},
|
||||
"user_menu": {
|
||||
"appearance": "외관",
|
||||
@@ -197,7 +201,22 @@
|
||||
"shareCreated": "공유 링크가 성공적으로 생성되었습니다",
|
||||
"shareUpdated": "공유 설정이 성공적으로 업데이트되었습니다",
|
||||
"shareRemoved": "공유가 성공적으로 삭제되었습니다",
|
||||
"inviteByEmail": "이메일로 초대 — 초대장이 전송됩니다"
|
||||
"inviteByEmail": "이메일로 초대 — 초대장이 전송됩니다",
|
||||
"directoryUnavailable": "User directory unavailable",
|
||||
"linkNamePlaceholder": "Link name (optional)",
|
||||
"newLink": "New link",
|
||||
"noExpiry": "No expiry",
|
||||
"pending": "Pending",
|
||||
"people": "People",
|
||||
"publicLinks": "Public links",
|
||||
"role": {
|
||||
"canEdit": "Can edit",
|
||||
"canManage": "Can manage",
|
||||
"canView": "Can view"
|
||||
},
|
||||
"searchPlaceholder": "Search people…",
|
||||
"shareOf": "Share of:",
|
||||
"sharedLink": "Shared link"
|
||||
},
|
||||
"share_dialogTitle": "공유 링크",
|
||||
"share_linkLabel": "공유 링크:",
|
||||
@@ -460,7 +479,10 @@
|
||||
"magicLinkSubmit": "로그인 링크 보내기",
|
||||
"magicLinkSent": "해당 이메일에 대한 계정이 있는 경우 로그인 링크가 전송되었습니다. 받은편지함을 확인하세요.",
|
||||
"magicLinkUnavailable": "이 서버에서는 이메일 로그인을 사용할 수 없습니다.",
|
||||
"magicLinkNetworkError": "서버에 연결할 수 없습니다: {{message}}"
|
||||
"magicLinkNetworkError": "서버에 연결할 수 없습니다: {{message}}",
|
||||
"magicLinkToggle": "No password? Email me a sign-in link",
|
||||
"passwordsMatch": "Passwords match",
|
||||
"capsLock": "Caps Lock is on"
|
||||
},
|
||||
"storage": {
|
||||
"title": "저장소",
|
||||
@@ -881,5 +903,78 @@
|
||||
"notifyRateLimited": "이 수신자에게 알림이 너무 많습니다 — 나중에 다시 시도하세요.",
|
||||
"removeAccess": "액세스 제거",
|
||||
"resendInvitation": "초대 이메일 다시 보내기"
|
||||
},
|
||||
"sort": {
|
||||
"asc": "ascending",
|
||||
"desc": "descending"
|
||||
},
|
||||
"notif": {
|
||||
"errorTitle": "Error",
|
||||
"searchError": "Error performing search",
|
||||
"cleanupCompleted": "Cleanup completed",
|
||||
"cleanupCompletedBody": "Recent files history has been cleared",
|
||||
"batchCopy": "Batch copy",
|
||||
"batchCopyBody": "{{success}} copied, {{errors}} failed",
|
||||
"itemsCopied": "Items copied",
|
||||
"itemsCopiedBody": "{{count}} items copied successfully",
|
||||
"batchMove": "Batch move",
|
||||
"batchMoveBody": "{{success}} moved, {{errors}} failed",
|
||||
"itemsMoved": "Items moved",
|
||||
"itemsMovedBody": "{{count}} items moved successfully",
|
||||
"batchDelete": "Batch delete",
|
||||
"batchDeleteBody": "{{success}} moved to trash, {{errors}} failed",
|
||||
"movedToTrash": "Moved to trash",
|
||||
"movedToTrashBody": "{{count}} items moved to trash",
|
||||
"trashItemsError": "Could not move items to trash",
|
||||
"preparingDownload": "Preparing download",
|
||||
"preparingDownloadBody": "Preparing your download…",
|
||||
"downloadItemsError": "Could not download selected items",
|
||||
"favoritesAddError": "Could not add items to favorites",
|
||||
"invalidEmail": "Please enter a valid email address",
|
||||
"notificationSendError": "Could not send notification",
|
||||
"folderCreated": "Folder created",
|
||||
"folderCreatedBody": "\"{{name}}\" created successfully",
|
||||
"fileMoved": "File moved",
|
||||
"fileMovedBody": "File moved successfully",
|
||||
"fileMoveError": "Error moving the file: {{error}}",
|
||||
"fileMoveErrorGeneric": "Error moving the file",
|
||||
"folderMoved": "Folder moved",
|
||||
"folderMovedBody": "Folder moved successfully",
|
||||
"folderMoveError": "Error moving the folder: {{error}}",
|
||||
"folderMoveErrorGeneric": "Error moving the folder",
|
||||
"fileCopied": "File copied",
|
||||
"fileCopiedBody": "File copied successfully",
|
||||
"fileCopyError": "Error copying the file: {{error}}",
|
||||
"fileCopyErrorGeneric": "Error copying the file",
|
||||
"folderRenamed": "Folder renamed",
|
||||
"folderRenamedBody": "Folder renamed to \"{{name}}\"",
|
||||
"fileTrashed": "File moved to trash",
|
||||
"fileTrashedBody": "\"{{name}}\" moved to trash",
|
||||
"fileDeleted": "File deleted",
|
||||
"fileDeletedBody": "\"{{name}}\" deleted successfully",
|
||||
"fileDeleteError": "Error deleting the file",
|
||||
"folderTrashed": "Folder moved to trash",
|
||||
"folderTrashedBody": "\"{{name}}\" moved to trash",
|
||||
"folderDeleted": "Folder deleted",
|
||||
"folderDeletedBody": "\"{{name}}\" deleted successfully",
|
||||
"folderDeleteError": "Error deleting the folder",
|
||||
"itemRestored": "Item restored",
|
||||
"itemRestoredBody": "Item restored successfully",
|
||||
"itemRestoreError": "Error restoring the item",
|
||||
"itemDeleted": "Item deleted",
|
||||
"itemDeletedBody": "Item permanently deleted",
|
||||
"itemDeleteError": "Error deleting the item",
|
||||
"trashEmptied": "Trash emptied",
|
||||
"trashEmptiedBody": "The trash has been emptied successfully",
|
||||
"trashEmptyError": "Error emptying the trash",
|
||||
"cacheCleared": "Cache cleared",
|
||||
"cacheClearedBody": "Search cache cleared successfully",
|
||||
"cacheClearError": "Error clearing search cache",
|
||||
"wopiOpenError": "Could not open the document editor.",
|
||||
"linkCopied": "Link copied",
|
||||
"linkCopiedBody": "Link copied to clipboard",
|
||||
"linkCopyError": "Could not copy link",
|
||||
"notificationSent": "Notification sent",
|
||||
"notificationSentBody": "Notification sent to {{email}}"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user