diff --git a/i18n/en.json b/i18n/en.json
index 5af40ea51a..529ab6dfdb 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -1082,6 +1082,7 @@
"unable_to_scan_library": "Unable to scan library",
"unable_to_set_feature_photo": "Unable to set feature photo",
"unable_to_set_profile_picture": "Unable to set profile picture",
+ "unable_to_set_rating": "Unable to set rating",
"unable_to_submit_job": "Unable to submit job",
"unable_to_trash_asset": "Unable to trash asset",
"unable_to_unlink_account": "Unable to unlink account",
@@ -1702,10 +1703,12 @@
"purchase_settings_server_activated": "The server product key is managed by the admin",
"query_asset_id": "Query Asset ID",
"queue_status": "Queuing {count}/{total}",
+ "rate_asset": "Rate Asset",
"rating": "Star rating",
"rating_clear": "Clear rating",
"rating_count": "{count, plural, one {# star} other {# stars}}",
"rating_description": "Display the EXIF rating in the info panel",
+ "rating_set": "Rating set to {rating, plural, one {# star} other {# stars}}",
"reaction_options": "Reaction options",
"read_changelog": "Read Changelog",
"readonly_mode_disabled": "Read-only mode disabled",
@@ -2296,6 +2299,7 @@
"yes": "Yes",
"you_dont_have_any_shared_links": "You don't have any shared links",
"your_wifi_name": "Your Wi-Fi name",
+ "zero_to_clear_rating": "press 0 to clear asset rating",
"zoom_image": "Zoom Image",
"zoom_to_bounds": "Zoom to bounds"
}
diff --git a/web/src/lib/components/asset-viewer/actions/action.ts b/web/src/lib/components/asset-viewer/actions/action.ts
index 6a807d2766..df61b5d073 100644
--- a/web/src/lib/components/asset-viewer/actions/action.ts
+++ b/web/src/lib/components/asset-viewer/actions/action.ts
@@ -20,6 +20,7 @@ type ActionMap = {
[AssetAction.SET_VISIBILITY_LOCKED]: { asset: TimelineAsset };
[AssetAction.SET_VISIBILITY_TIMELINE]: { asset: TimelineAsset };
[AssetAction.SET_PERSON_FEATURED_PHOTO]: { asset: AssetResponseDto; person: PersonResponseDto };
+ [AssetAction.RATING]: { asset: TimelineAsset; rating: number | null };
};
export type Action = {
diff --git a/web/src/lib/components/asset-viewer/actions/rating-action.svelte b/web/src/lib/components/asset-viewer/actions/rating-action.svelte
new file mode 100644
index 0000000000..3791fccf23
--- /dev/null
+++ b/web/src/lib/components/asset-viewer/actions/rating-action.svelte
@@ -0,0 +1,55 @@
+
+
+ rateAsset(null) },
+ ...[1, 2, 3, 4, 5].map((rating) => ({
+ shortcut: { key: String(rating) },
+ onShortcut: () => rateAsset(rating),
+ })),
+ ]
+ : []}
+/>
diff --git a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte
index 689cd5c20c..08957a5340 100644
--- a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte
+++ b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte
@@ -12,6 +12,7 @@
import DownloadAction from '$lib/components/asset-viewer/actions/download-action.svelte';
import FavoriteAction from '$lib/components/asset-viewer/actions/favorite-action.svelte';
import KeepThisDeleteOthersAction from '$lib/components/asset-viewer/actions/keep-this-delete-others.svelte';
+ import RatingAction from '$lib/components/asset-viewer/actions/rating-action.svelte';
import RemoveAssetFromStack from '$lib/components/asset-viewer/actions/remove-asset-from-stack.svelte';
import RestoreAction from '$lib/components/asset-viewer/actions/restore-action.svelte';
import SetAlbumCoverAction from '$lib/components/asset-viewer/actions/set-album-cover-action.svelte';
@@ -179,6 +180,7 @@
{#if isOwner}
+
{/if}
{#if isOwner}
diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte
index 8b35c00fa1..7b07d57fd1 100644
--- a/web/src/lib/components/asset-viewer/asset-viewer.svelte
+++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte
@@ -331,6 +331,16 @@
asset = { ...asset, people: assetInfo.people };
break;
}
+ case AssetAction.RATING: {
+ asset = {
+ ...asset,
+ exifInfo: {
+ ...asset.exifInfo,
+ rating: action.rating,
+ },
+ };
+ break;
+ }
case AssetAction.KEEP_THIS_DELETE_OTHERS:
case AssetAction.UNSTACK: {
closeViewer();
diff --git a/web/src/lib/constants.ts b/web/src/lib/constants.ts
index 6f7c0d8e1e..72056008cd 100644
--- a/web/src/lib/constants.ts
+++ b/web/src/lib/constants.ts
@@ -18,6 +18,7 @@ export enum AssetAction {
SET_VISIBILITY_LOCKED = 'set-visibility-locked',
SET_VISIBILITY_TIMELINE = 'set-visibility-timeline',
SET_PERSON_FEATURED_PHOTO = 'set-person-featured-photo',
+ RATING = 'rating',
}
export enum AppRoute {
diff --git a/web/src/lib/modals/ShortcutsModal.svelte b/web/src/lib/modals/ShortcutsModal.svelte
index ebb5ea3c60..c5b09ffa1a 100644
--- a/web/src/lib/modals/ShortcutsModal.svelte
+++ b/web/src/lib/modals/ShortcutsModal.svelte
@@ -1,4 +1,5 @@