83 lines
2.5 KiB
Vue
83 lines
2.5 KiB
Vue
<script setup lang="ts" generic="Provider extends keyof ConfiguredImageProviders = ProviderDefaults['provider']">
|
|
import { Tooltip, TooltipTrigger } from '@/components/ui/tooltip';
|
|
import { cn } from "@/lib/utils";
|
|
import type { ConfiguredImageProviders, ProviderDefaults } from '@nuxt/image';
|
|
import type { HTMLAttributes } from 'vue';
|
|
import { imageVariants } from '.';
|
|
|
|
interface Props {
|
|
src: string;
|
|
alt?: string;
|
|
title?: string;
|
|
sizes?: string;
|
|
width?: number;
|
|
height?: number;
|
|
loading?: 'lazy' | 'eager';
|
|
provider?: Provider;
|
|
quality?: number;
|
|
class?: HTMLAttributes['class'];
|
|
overlayHeight?: string;
|
|
overlayOpacity?: number;
|
|
overlayClass?: string;
|
|
imageClass?: string;
|
|
variant?: 'default' | 'rounded' | 'elevated' | 'minimal';
|
|
size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
alt: '',
|
|
title: '',
|
|
sizes: '100vw sm:50vw md:33vw lg:25vw',
|
|
width: 400,
|
|
height: 300,
|
|
loading: 'lazy',
|
|
provider: undefined,
|
|
quality: 80,
|
|
overlayHeight: '4em',
|
|
overlayOpacity: 1,
|
|
overlayClass: '',
|
|
imageClass: '',
|
|
variant: 'default',
|
|
size: 'md',
|
|
});
|
|
|
|
const emit = defineEmits<{
|
|
hover: [state: boolean];
|
|
click: [event: MouseEvent];
|
|
}>();
|
|
|
|
const handleHover = (state: boolean) => {
|
|
emit('hover', state);
|
|
};
|
|
|
|
const handleClick = (event: MouseEvent) => {
|
|
emit('click', event);
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<Tooltip>
|
|
<TooltipTrigger as-child>
|
|
<div :class="cn(imageVariants({ variant, size }), props.class)" @mouseenter="handleHover(true)"
|
|
@mouseleave="handleHover(false)" @click="handleClick">
|
|
<NuxtImg :src="src" :alt="alt" :sizes="sizes" :width="width" :height="height" :loading="loading"
|
|
:provider="provider" :quality="quality" :class="cn('w-full h-auto object-cover', imageClass)" />
|
|
|
|
<div
|
|
:class="cn('absolute bottom-0 left-0 right-0 overlay-gradient bg-linear-to-t group-hover:opacity-0 opacity-100 from-muted from-20% to-transparent flex items-end transition-opacity p-4', overlayClass)">
|
|
<span v-if="title" class="text-white font-semibold text-sm md:text-base line-clamp-2">
|
|
{{ title }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</TooltipTrigger>
|
|
<slot />
|
|
</Tooltip>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.overlay-gradient {
|
|
height: v-bind(overlayHeight);
|
|
}
|
|
</style>
|