105 lines
2.6 KiB
Vue
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>
|