76 lines
1.5 KiB
Vue
76 lines
1.5 KiB
Vue
<script setup lang="ts">
|
|
withDefaults(
|
|
defineProps<{
|
|
data?: Record<string, unknown>[];
|
|
dataLabel?: string;
|
|
dataUrl?: string;
|
|
}>(),
|
|
{
|
|
dataLabel: 'name',
|
|
dataUrl: 'imgUrl',
|
|
data: () => [],
|
|
},
|
|
);
|
|
</script>
|
|
<template>
|
|
<div class="avatar-group">
|
|
<div class="avatar" v-for="(person, i) in data.slice(0, 3)" :key="i">
|
|
<q-tooltip>
|
|
{{ person[dataLabel] }}
|
|
</q-tooltip>
|
|
<img
|
|
:src="
|
|
typeof person[dataUrl] === 'string' ? (person[dataUrl] as string) : ''
|
|
"
|
|
alt="Image"
|
|
/>
|
|
</div>
|
|
<div v-if="data.length > 3" class="avatar remaining-count">
|
|
<q-tooltip>
|
|
<div v-for="(person, i) in data.slice(3)" :key="i + 3">
|
|
{{ person.name }}
|
|
</div>
|
|
</q-tooltip>
|
|
<span>{{ `+${data.length - 3}` }}</span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.avatar-group {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
.avatar {
|
|
position: relative;
|
|
transition: 0.2s;
|
|
}
|
|
.avatar:not(:first-child) {
|
|
margin-left: -0.75rem;
|
|
}
|
|
.avatar:hover {
|
|
z-index: 1;
|
|
transform: translateY(-0.5rem);
|
|
}
|
|
.avatar img {
|
|
width: 30px;
|
|
height: 30px;
|
|
display: block;
|
|
object-fit: cover;
|
|
border-radius: 50%;
|
|
border: 2px solid var(--border-color);
|
|
}
|
|
.remaining-count {
|
|
color: hsl(var(--text-mute-2));
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 30px;
|
|
height: 30px;
|
|
background-color: var(--surface-2);
|
|
border: 2px solid var(--border-color);
|
|
border-radius: 50%;
|
|
font-size: 0.8rem;
|
|
margin-left: -0.75rem;
|
|
}
|
|
</style>
|