81 lines
2.1 KiB
Vue
81 lines
2.1 KiB
Vue
<template>
|
|
<div
|
|
class="bg-white/95 rounded-2xl shadow-[0_8px_30px_rgb(0,0,0,0.12)] overflow-hidden flex flex-col relative transition-all duration-300 ease-out"
|
|
:class="[
|
|
heightClass,
|
|
hoverable ? 'cursor-pointer hover:-translate-y-3 hover:scale-[1.02] hover:shadow-2xl' : '',
|
|
clickable ? 'cursor-pointer' : '',
|
|
customClass,
|
|
]"
|
|
@click="$emit('click')"
|
|
>
|
|
<!-- ═══ HEADER SLOT ═══ -->
|
|
<div
|
|
v-if="$slots.header"
|
|
class="h-12 w-full shrink-0 flex items-center px-4"
|
|
:class="headerColorClass"
|
|
>
|
|
<slot name="header" />
|
|
</div>
|
|
|
|
<!-- ═══ BODY SLOT (default) ═══ -->
|
|
<div
|
|
class="flex-1 flex flex-col text-slate-800 overflow-hidden"
|
|
:class="bodyPaddingClass"
|
|
>
|
|
<slot />
|
|
</div>
|
|
|
|
<!-- ═══ FOOTER SLOT ═══ -->
|
|
<div v-if="$slots.footer" class="shrink-0 px-4 pb-4">
|
|
<slot name="footer" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
/** Enable hover lift effect (translate-y and stronger shadow) */
|
|
hoverable?: boolean
|
|
/** Enable cursor-pointer without hover animation */
|
|
clickable?: boolean
|
|
/** Card height Tailwind class (default: h-[350px]) */
|
|
height?: string
|
|
/** Header background color Tailwind class (default: bg-slate-700) */
|
|
headerColor?: string
|
|
/** Body padding: 'sm' | 'md' | 'lg' | 'none' (default: 'md') */
|
|
bodyPadding?: 'sm' | 'md' | 'lg' | 'none'
|
|
/** Additional CSS classes to merge */
|
|
customClass?: string
|
|
}>(),
|
|
{
|
|
hoverable: false,
|
|
clickable: false,
|
|
height: 'h-[350px]',
|
|
headerColor: 'bg-slate-700',
|
|
bodyPadding: 'md',
|
|
customClass: '',
|
|
}
|
|
)
|
|
|
|
defineEmits<{
|
|
click: []
|
|
}>()
|
|
|
|
const heightClass = computed(() => props.height)
|
|
|
|
const headerColorClass = computed(() => props.headerColor)
|
|
|
|
const bodyPaddingClass = computed(() => {
|
|
switch (props.bodyPadding) {
|
|
case 'sm': return 'p-3'
|
|
case 'lg': return 'p-6'
|
|
case 'none': return ''
|
|
default: return 'p-4'
|
|
}
|
|
})
|
|
</script>
|