explorer-app/components/Project/ProjectRating.vue

129 lines
3.3 KiB
Vue

<script lang="ts" setup>
import type { ProjectRating } from '~/types'
// Define props for score
const props = defineProps<{
rating: ProjectRating
percentage: number
compact?: boolean
disablePopover?: boolean
showOnlyPopover?: boolean
selected?: boolean
}>()
const emits = defineEmits(['selected'])
const colors = [
'#ff0000', // 0-10%
'#ff4500', // 11-20%
'#ff8c00', // 21-30%
'#ffd700', // 31-40%
'#adff2f', // 41-50%
'#7fff00', // 51-60%
'#00ff00', // 61-70%
'#32cd32', // 71-80%
'#00fa9a', // 81-90%
'#00ffff', // 91-100%
]
const backgroundColorByScore = computed(() => {
const normalizedPercentage = Math.min(Math.max(props.percentage, 0), 100)
const colorIndex = Math.floor(normalizedPercentage / 10)
return colors[colorIndex]
})
const isLargeScreen = useMediaQuery('(min-width: 1024px)')
function onClick() {
if (isLargeScreen.value)
return
if (props.disablePopover)
emits('selected')
else
isPopoverVisible.value = !isPopoverVisible.value
}
const isPopoverVisible = ref(false)
let hideTimeout: ReturnType<typeof setTimeout> | null = null
const showPopover = () => {
if (!isLargeScreen.value)
return
console.log('show')
if (hideTimeout) {
clearTimeout(hideTimeout)
hideTimeout = null
}
isPopoverVisible.value = true
}
const hidePopover = () => {
if (!isLargeScreen.value)
return
hideTimeout = setTimeout(() => {
isPopoverVisible.value = false
}, 100) // Delay of 200ms before hiding
}
</script>
<template>
<div
class="relative"
:class="{ 'w-full': showOnlyPopover }"
>
<!-- Main div that shows rating and triggers the popover on hover -->
<div
v-if="!showOnlyPopover"
flex
items-center
p-12px
gap-4px
hover:bg-app-bg-rating-hover
:class="{ 'bg-app-bg-rating-hover rounded-8px': selected }"
hover:rounded-8px
cursor-pointer
@mouseenter="showPopover"
@mouseleave="hidePopover"
@click.prevent="onClick()"
>
<div
v-for="point of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"
:key="point"
:style="`background-color: ${percentage >= point * 10 ? backgroundColorByScore : '#494949'}`"
:class="[compact ? 'h-8px lg:h-10px w-4px lg:w-5px' : 'w-5px lg:w-6px h-10px lg:h-12px', point % 2 === 0 ? 'rounded-l-2px' : 'rounded-r-2px ml--4px', 'bg-app-bg-rating-default']"
/>
</div>
<!-- Popover panel that appears on hover -->
<transition
v-if="!showOnlyPopover"
enter-active-class="transition duration-300 ease-out"
enter-from-class="transform scale-95 opacity-0"
enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-200 ease-in"
leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0"
>
<div
v-if="(isPopoverVisible && !disablePopover)"
class="absolute mt-2 p-2 bg-app-bg-rating-hover w-240px shadow-lg rounded"
z-100
left="-250% lg:50%"
flex
flex-col
gap-14px
px-16px
py-10px
@mouseenter="showPopover"
@mouseleave="hidePopover"
>
<ProjectRatingInfo :items="rating.items" />
</div>
</transition>
<ProjectRatingInfo
v-if="showOnlyPopover"
:items="rating.items"
:compact="false"
/>
</div>
</template>