57 lines
1.6 KiB
Vue
57 lines
1.6 KiB
Vue
<script setup>
|
|
import { computed } from 'vue'
|
|
|
|
defineProps({
|
|
image: { type: String, required: true },
|
|
title: { type: String, required: true },
|
|
description: { type: String, required: true },
|
|
action: {
|
|
type: Object,
|
|
default: () => ({ route: '#', color: 'success', label: 'Read more' }),
|
|
},
|
|
})
|
|
|
|
const linkColors = {
|
|
primary: 'text-primary',
|
|
secondary: 'text-secondary',
|
|
success: 'text-success',
|
|
warning: 'text-warning',
|
|
danger: 'text-danger',
|
|
info: 'text-info',
|
|
dark: 'text-dark',
|
|
white: 'text-white',
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex flex-col">
|
|
<!-- Image — no card wrapper, just soft shadow and rounded corners -->
|
|
<div class="overflow-hidden rounded-xl shadow-soft-md">
|
|
<a :href="action.route" class="block">
|
|
<img
|
|
:src="image"
|
|
:alt="title"
|
|
loading="lazy"
|
|
class="h-48 w-full object-cover transition-transform duration-500 hover:scale-105"
|
|
/>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Body — no background, plain text -->
|
|
<div class="mt-4">
|
|
<h5 class="font-bold text-dark">
|
|
<a :href="action.route" class="hover:text-primary transition-colors">{{ title }}</a>
|
|
</h5>
|
|
<p class="mt-2 text-sm text-secondary leading-relaxed">{{ description }}</p>
|
|
<a
|
|
:href="action.route"
|
|
class="mt-3 inline-flex items-center gap-1 text-sm font-medium transition-opacity hover:opacity-80"
|
|
:class="linkColors[action.color] ?? linkColors.success"
|
|
>
|
|
{{ action.label }}
|
|
<span class="material-icons text-base leading-none">arrow_forward</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</template>
|