Files
2026-06-06 18:43:00 +08:00

105 lines
2.6 KiB
Vue

<template>
<div
class="card-custom"
:id="id"
:style="cardStyle"
:class="[
`shadow-${shadow}`,
{ 'is-premium': isPremium, 'no-padding': noPadding }
]"
>
<div v-if="title" class="card-header-custom">
<h4 class="card-title">{{ title }}</h4>
<div v-if="$slots.headerAction" class="header-action">
<slot name="headerAction" />
</div>
</div>
<div class="card-body-custom">
<slot />
</div>
<div v-if="$slots.footer" class="card-footer-custom">
<slot name="footer" />
</div>
</div>
</template>
<script setup>
defineProps({
title: { type: String, default: '' },
id: { type: String, default: '' },
cardStyle: { type: String, default: '' },
isPremium: { type: Boolean, default: true },
noPadding: { type: Boolean, default: false },
shadow: { type: String, default: 'md', validator: (v) => ['none', 'sm', 'md', 'lg'].includes(v) },
})
</script>
<style scoped>
.card-custom {
background: var(--bg-card, #ffffff);
border: 1px solid var(--border-color, rgba(0, 0, 0, 0.08));
border-radius: 16px;
overflow: hidden;
transition: all 0.3s ease;
height: 100%;
display: flex;
flex-direction: column;
}
.card-header-custom {
padding: 1.5rem;
border-bottom: 1px solid var(--border-color, rgba(0, 0, 0, 0.05));
display: flex;
align-items: center;
justify-content: space-between;
}
.card-title {
margin: 0;
font-size: 1.25rem;
font-weight: 700;
color: var(--text-primary, #1e1e1e);
}
.card-body-custom {
padding: 1.5rem;
flex-grow: 1;
}
.no-padding .card-body-custom {
padding: 0;
}
.card-footer-custom {
padding: 1.25rem 1.5rem;
border-top: 1px solid var(--border-color, rgba(0, 0, 0, 0.05));
background: var(--bg-secondary, rgba(0, 0, 0, 0.02));
}
/* Premium / Glassmorphism */
.is-premium {
background: rgba(255, 255, 255, 0.6);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(0, 0, 0, 0.05);
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.07);
}
:global(.dark-mode) .is-premium {
background: rgba(30, 41, 59, 0.7);
border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3);
}
.is-premium:hover {
border-color: var(--accent-color, rgba(83, 61, 234, 0.3));
transform: translateY(-2px);
}
/* Shadows */
.shadow-none { box-shadow: none; }
.shadow-sm { box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); }
.shadow-md { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); }
.shadow-lg { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); }
</style>