11<template >
22 <div
3- v-if =" isRatingEnabled && !are_details_open && displayedRating > 0 "
3+ v-if =" isRatingEnabled && !are_details_open"
44 :class =" {
5- 'absolute bottom-0 w-full sm:w-1/2 left-1/2 -translate-x-1/2 z-20 sm:h-1/8 h-14': true,
6- 'lg:hover:opacity-100 transition-opacity duration-500 ease-in-out': isHoverMode && !isTouchDevice(),
5+ 'group absolute bottom-0 w-full sm:w-1/2 left-1/2 -translate-x-1/2 z-20 sm:h-1/8 h-14': true,
76 'opacity-50 lg:opacity-20': isHoverMode && !isTouchDevice() && !isFullTransparency,
7+ 'hover:opacity-100 transition-opacity duration-500 ease-in-out': isHoverMode && !isTouchDevice(),
88 'opacity-75': isHoverMode && isTouchDevice() && !isFullTransparency,
99 'opacity-0': isHoverMode && isFullTransparency,
1010 hidden: is_slideshow_active,
1111 }"
1212 >
13- <div class =" absolute left-1/2 -translate-x-1/2 bottom-7 flex items-center gap-1 text-shadow " >
13+ <div v-if = " displayedRating > 0 " class =" absolute left-1/2 -translate-x-1/2 bottom-7 text-shadow group-hover:opacity-0 " >
1414 <StarRow :rating =" displayedRating" size =" large" />
1515 </div >
16+ <div
17+ v-if =" userStore.user !== undefined && photoStore?.photo && photoStore?.photo.rating"
18+ class =" absolute left-1/2 -translate-x-1/2 bottom-7 text-shadow"
19+ >
20+ <!-- Star rating buttons (1-5) -->
21+ <div class =" flex items-center h-6 gap-0.5" >
22+ <button
23+ v-for =" rating in [1, 2, 3, 4, 5]"
24+ :key =" `rate-${rating}`"
25+ :disabled =" loading"
26+ :class =" {
27+ 'w-6 h-6 transition-colors rounded block': true,
28+ 'cursor-pointer': !loading,
29+ 'cursor-not-allowed opacity-50': loading,
30+ }"
31+ @mouseenter =" handleMouseEnter(rating)"
32+ @mouseleave =" handleMouseLeave()"
33+ @click =" handleRatingClick(photoStore?.photo.id, rating as 1 | 2 | 3 | 4 | 5)"
34+ >
35+ <i
36+ :class =" {
37+ 'text-xl pi pi-star-fill text-amber-500': rating <= (hoverRating ?? photoStore?.photo.rating.rating_user),
38+ 'text-xl pi pi-star text-muted-color': rating > (hoverRating ?? photoStore?.photo.rating.rating_user),
39+ }"
40+ />
41+ </button >
42+ </div >
43+ </div >
1644 </div >
1745</template >
1846
@@ -24,13 +52,30 @@ import { isTouchDevice } from "@/utils/keybindings-utils";
2452import { useTogglablesStateStore } from " @/stores/ModalsState" ;
2553import { storeToRefs } from " pinia" ;
2654import StarRow from " @/components/icons/StarRow.vue" ;
55+ import { useUserStore } from " @/stores/UserState" ;
56+ import { useToast } from " primevue/usetoast" ;
57+ import { useRating } from " @/composables/photo/useRating" ;
2758
2859const photoStore = usePhotoStore ();
2960const lycheeStore = useLycheeStateStore ();
3061const togglableStore = useTogglablesStateStore ();
62+ const userStore = useUserStore ();
63+ const toast = useToast ();
3164
3265const { is_slideshow_active, are_details_open } = storeToRefs (togglableStore );
3366
67+ const { hoverRating, loading, handleRatingClick } = useRating (photoStore , toast , userStore );
68+
69+ function handleMouseEnter(rating : number ) {
70+ if (! loading .value ) {
71+ hoverRating .value = rating ;
72+ }
73+ }
74+
75+ function handleMouseLeave() {
76+ hoverRating .value = null ;
77+ }
78+
3479// Compute which rating should be shown on thumbnails
3580const displayedRating = computed (() => {
3681 if (lycheeStore .is_rating_show_avg_in_photo_view_enabled ) {
0 commit comments