main
vue 138 lines 2.82 KB
Raw
1 <template>
2 <n-card content-class="p-0!" :class="{ hovered }">
3 <div class="flex h-full flex-col overflow-hidden">
4 <div class="card-header flex items-center justify-between gap-4">
5 <div class="title flex grow items-center gap-2">
6 <span class="truncate">{{ title }}</span>
7 <Icon v-if="hovered" :name="ArrowRightIcon" :size="12" />
8 </div>
9 <div class="icon">
10 <slot name="icon"></slot>
11 </div>
12 </div>
13 <div class="card-content divide-border grid grow grid-cols-[repeat(auto-fit,minmax(0,1fr))] divide-x">
14 <div
15 v-for="item of values"
16 :key="JSON.stringify(item)"
17 class="value-box flex flex-col"
18 :class="[item.status, values.length !== 1 ? `basis-1/${values.length}` : 'grow']"
19 >
20 <div class="value flex grow items-center justify-center">
21 {{ item.value }}
22 </div>
23 <div v-if="item.label" class="label">
24 {{ item.label }}
25 </div>
26 </div>
27 </div>
28 </div>
29 </n-card>
30 </template>
31
32 <script setup lang="ts">
33 import { NCard } from "naive-ui"
34 import { toRefs } from "vue"
35 import Icon from "@/components/common/Icon.vue"
36
37 export interface ItemProps {
38 value: number | string
39 label?: string
40 status?: "success" | "warning" | "error"
41 }
42
43 const props = defineProps<{
44 title: string
45 values: ItemProps[]
46 hovered?: boolean
47 }>()
48 const { title, values, hovered } = toRefs(props)
49
50 const ArrowRightIcon = "carbon:arrow-right"
51 </script>
52
53 <style scoped lang="scss">
54 .n-card {
55 overflow: hidden;
56
57 .card-header {
58 border-bottom: 1px solid var(--border-color);
59 overflow: hidden;
60 padding: 10px 16px;
61
62 .title {
63 font-size: 16px;
64 text-overflow: ellipsis;
65 white-space: nowrap;
66 overflow: hidden;
67 }
68 }
69
70 .card-content {
71 .value-box {
72 text-align: center;
73 overflow: hidden;
74
75 .value {
76 font-family: var(--font-family-display);
77 padding: 10px 6px;
78 font-size: 22px;
79 text-overflow: ellipsis;
80 white-space: nowrap;
81 overflow: hidden;
82 font-weight: bold;
83 text-overflow: ellipsis;
84 white-space: nowrap;
85 line-height: 1;
86 overflow: hidden;
87 }
88
89 .label {
90 font-family: var(--font-family-mono);
91 border-top: 1px solid var(--border-color);
92 color: var(--fg-secondary-color);
93 font-size: 13px;
94 padding: 6px;
95 line-height: 1;
96 background-color: var(--bg-secondary-color);
97 text-overflow: ellipsis;
98 white-space: nowrap;
99 overflow: hidden;
100 text-transform: uppercase;
101 }
102
103 &.success {
104 .value {
105 color: var(--success-color);
106 }
107 .label {
108 color: var(--success-color);
109 }
110 }
111
112 &.warning {
113 .value {
114 color: var(--warning-color);
115 }
116 .label {
117 color: var(--warning-color);
118 }
119 }
120
121 &.error {
122 .value {
123 color: var(--error-color);
124 }
125 .label {
126 color: var(--error-color);
127 }
128 }
129 }
130 }
131
132 &.hovered {
133 &:hover {
134 border-color: var(--primary-color);
135 }
136 }
137 }
138 </style>