main
vue 241 lines 4.73 KB
Raw
1 <template>
2 <n-card
3 class="card-entity"
4 content-class="p-0!"
5 :class="[
6 `card-size-${size}`,
7 `card-status-${status}`,
8 { embedded, highlighted, clickable, hoverable, disabled },
9 cardEntityClass
10 ]"
11 >
12 <n-spin
13 :show="loading"
14 :description="loadingDescription"
15 content-class="h-full grow"
16 class="flex h-full flex-col"
17 >
18 <div class="card-entity-wrapper flex flex-col" :class="cardEntityWrapperClass">
19 <div class="main-box flex flex-col" :class="mainBoxClass">
20 <div v-if="$slots.header" class="header-box" :class="headerBoxClass">
21 <slot name="header" />
22 </div>
23
24 <div
25 v-if="!$slots.header && ($slots['header-main'] || $slots['header-extra'])"
26 class="header-box flex flex-wrap items-center justify-between"
27 :class="headerBoxClass"
28 >
29 <div :class="headerMainBoxClass">
30 <slot name="header-main" />
31 </div>
32 <div :class="headerExtraBoxClass">
33 <slot name="header-extra" />
34 </div>
35 </div>
36
37 <div v-if="$slots.default" class="content-box">
38 <slot name="default" />
39 </div>
40 </div>
41
42 <div v-if="$slots['main-extra']" class="extra-box">
43 <slot name="main-extra" />
44 </div>
45
46 <div v-if="$slots.footer" class="footer-box" :class="footerBoxClass">
47 <slot name="footer" />
48 </div>
49
50 <div
51 v-if="!$slots.footer && ($slots['footer-main'] || $slots['footer-extra'])"
52 class="footer-box flex flex-wrap items-start justify-between"
53 :class="footerBoxClass"
54 >
55 <div>
56 <slot name="footer-main" />
57 </div>
58 <div>
59 <slot name="footer-extra" />
60 </div>
61 </div>
62 </div>
63 </n-spin>
64 </n-card>
65 </template>
66
67 <script setup lang="ts">
68 import { NCard, NSpin } from "naive-ui"
69
70 const {
71 size,
72 status,
73 embedded,
74 highlighted,
75 clickable,
76 hoverable,
77 disabled,
78 loading,
79 loadingDescription,
80 mainBoxClass,
81 headerBoxClass,
82 headerMainBoxClass,
83 headerExtraBoxClass,
84 footerBoxClass,
85 cardEntityClass,
86 cardEntityWrapperClass
87 } = defineProps<{
88 size?: "medium" | "small" | "large"
89 status?: "success" | "warning" | "error"
90 embedded?: boolean
91 highlighted?: boolean
92 clickable?: boolean
93 hoverable?: boolean
94 disabled?: boolean
95 loading?: boolean
96 loadingDescription?: string
97 mainBoxClass?: string
98 headerBoxClass?: string
99 headerMainBoxClass?: string
100 headerExtraBoxClass?: string
101 footerBoxClass?: string
102 cardEntityClass?: string
103 cardEntityWrapperClass?: string
104 }>()
105 </script>
106
107 <style lang="scss" scoped>
108 .card-entity {
109 transition: all 0.2s var(--bezier-ease);
110 overflow: hidden;
111
112 .card-entity-wrapper {
113 .main-box {
114 .header-box {
115 font-family: var(--font-family-mono);
116 font-size: 13px;
117 color: var(--fg-secondary-color);
118
119 :deep(.n-button) {
120 font-family: var(--font-family);
121 }
122 }
123 .content-box {
124 word-break: break-word;
125 }
126 }
127
128 .extra-box {
129 border-top: 1px solid var(--border-color);
130 }
131
132 .footer-box {
133 border-top: 1px solid var(--border-color);
134 font-size: 13px;
135 background-color: var(--bg-secondary-color);
136 }
137
138 .main-box,
139 .extra-box,
140 .footer-box {
141 gap: calc(var(--spacing) * 3);
142 padding: calc(var(--spacing) * 4);
143 }
144
145 .main-box {
146 .header-box {
147 gap: calc(var(--spacing) * 3);
148 }
149 }
150 }
151
152 &.card-size-small {
153 .card-entity-wrapper {
154 .main-box,
155 .extra-box,
156 .footer-box {
157 gap: calc(var(--spacing) * 2);
158 padding: calc(var(--spacing) * 3);
159 }
160
161 .main-box {
162 .header-box {
163 gap: calc(var(--spacing) * 2);
164 }
165 }
166 }
167 }
168
169 &.card-size-large {
170 .card-entity-wrapper {
171 .main-box,
172 .extra-box,
173 .footer-box {
174 gap: calc(var(--spacing) * 6);
175 padding: calc(var(--spacing) * 6);
176 }
177
178 .main-box {
179 .header-box {
180 gap: calc(var(--spacing) * 6);
181 }
182 }
183 }
184 }
185
186 &.clickable {
187 cursor: pointer;
188 }
189
190 &.embedded {
191 background-color: var(--bg-secondary-color);
192 border: 1px solid var(--border-color);
193
194 .footer-box {
195 background-color: var(--bg-body-color);
196 }
197 }
198
199 &.card-status-success {
200 background-color: rgba(var(--success-color-rgb) / 0.05);
201 border-color: rgba(var(--success-color-rgb) / 0.3);
202 }
203
204 &.card-status-warning {
205 background-color: rgba(var(--warning-color-rgb) / 0.05);
206 border-color: rgba(var(--warning-color-rgb) / 0.3);
207 }
208
209 &.card-status-error {
210 background-color: rgba(var(--error-color-rgb) / 0.05);
211 border-color: rgba(var(--error-color-rgb) / 0.3);
212 }
213
214 &.hoverable {
215 &:not(.disabled) {
216 &:hover {
217 border-color: rgba(var(--primary-color-rgb) / 0.4);
218 }
219 }
220 }
221
222 &.highlighted {
223 background-color: rgba(var(--primary-color-rgb) / 0.05);
224 border-color: rgba(var(--primary-color-rgb) / 0.3);
225
226 &:not(.disabled) {
227 &:hover {
228 box-shadow: 0px 0px 0px 1px var(--primary-color);
229 }
230 }
231 }
232
233 &.disabled {
234 cursor: not-allowed;
235
236 .card-entity-wrapper {
237 opacity: 70%;
238 }
239 }
240 }
241 </style>