mirror of
https://github.com/nocodb/nocodb.git
synced 2026-04-25 05:15:58 +00:00
219 lines
5.3 KiB
Vue
219 lines
5.3 KiB
Vue
<script lang="ts" setup>
|
|
import { IconType, type TeamV3V3Type } from 'nocodb-sdk'
|
|
import 'emoji-mart-vue-fast/css/emoji-mart.css'
|
|
import { Icon } from '@iconify/vue'
|
|
import { type IconMapKey, isColorDark, stringToColor } from '#imports'
|
|
|
|
export interface TeamIconProps {
|
|
size?: 'small' | 'medium' | 'base' | 'large' | 'xlarge' | 'auto'
|
|
team?: Partial<TeamV3V3Type> | null
|
|
disabled?: boolean
|
|
iconBgColor?: string
|
|
showPlaceholderIcon?: boolean
|
|
isDeleted?: boolean
|
|
initialsLength?: 1 | 2
|
|
placeholderIcon?: IconMapKey
|
|
wrapperClass?: string
|
|
}
|
|
|
|
const props = withDefaults(defineProps<TeamIconProps>(), {
|
|
user: () => ({}),
|
|
size: 'medium',
|
|
disabled: false,
|
|
iconBgColor: 'var(--nc-bg-gray-light)',
|
|
showPlaceholderIcon: false,
|
|
isDeleted: false,
|
|
initialsLength: 2,
|
|
placeholderIcon: 'ncUsers',
|
|
wrapperClass: '',
|
|
})
|
|
|
|
const { size } = toRefs(props)
|
|
|
|
const { getColor: _getColor } = useTheme()
|
|
|
|
const team = computed(() => {
|
|
return {
|
|
...(props.team || {}),
|
|
title: props.team?.title ?? '',
|
|
icon: props.team?.icon ?? '',
|
|
icon_type: props.team?.icon_type ?? '',
|
|
}
|
|
})
|
|
|
|
const isPlaceholderIconShown = ref(false)
|
|
|
|
const teamIcon = computed<{
|
|
icon: any
|
|
iconType: IconType | string
|
|
}>(() => {
|
|
isPlaceholderIconShown.value = false
|
|
|
|
if (props.isDeleted) {
|
|
return {
|
|
icon: 'ncSlash',
|
|
iconType: IconType.ICON,
|
|
}
|
|
}
|
|
|
|
const icon = team.value.icon || ''
|
|
const iconType = team.value.icon_type || ''
|
|
|
|
if ((!icon || !iconType) && props.placeholderIcon && props.showPlaceholderIcon) {
|
|
isPlaceholderIconShown.value = true
|
|
return {
|
|
icon: props.placeholderIcon,
|
|
iconType: IconType.ICON,
|
|
}
|
|
}
|
|
|
|
if (!icon || !iconType) {
|
|
return {
|
|
icon: '',
|
|
iconType: '',
|
|
}
|
|
}
|
|
|
|
return {
|
|
icon,
|
|
iconType,
|
|
}
|
|
})
|
|
|
|
const getColor = (color: string) => {
|
|
if (color === 'transparent') {
|
|
return _getColor('var(--nc-bg-default)')
|
|
}
|
|
|
|
return _getColor(color)
|
|
}
|
|
|
|
const backgroundColor = computed(() => {
|
|
if (props.iconBgColor === 'transparent') {
|
|
return 'transparent'
|
|
}
|
|
|
|
if (props.disabled || props.isDeleted) {
|
|
return '#bbbbbb'
|
|
}
|
|
|
|
// in comments we need to generate user icon from email
|
|
const color = team.value.title ? stringToColor(team.value.title) : '#FFFFFF'
|
|
|
|
if (teamIcon.value.icon) {
|
|
switch (teamIcon.value.iconType) {
|
|
case IconType.EMOJI: {
|
|
return props.iconBgColor
|
|
}
|
|
case IconType.ICON: {
|
|
return props.iconBgColor
|
|
}
|
|
|
|
default: {
|
|
return color || '#FFFFFF'
|
|
}
|
|
}
|
|
}
|
|
|
|
return color || '#FFFFFF'
|
|
})
|
|
|
|
const teamInitials = computed(() => {
|
|
if (props.disabled || props.isDeleted || !team.value.title) {
|
|
return ''
|
|
}
|
|
|
|
return getSafeInitials(team.value.title, props.initialsLength, true)
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
class="nc-team-avatar"
|
|
:class="[
|
|
{
|
|
'h-full min-h-5 aspect-square': size === 'auto',
|
|
'w-4 h-4': size === 'small',
|
|
'w-6 h-6': size === 'medium',
|
|
'w-8 h-8': size === 'base',
|
|
'w-20 h-20': size === 'large',
|
|
'w-26 h-26': size === 'xlarge',
|
|
},
|
|
wrapperClass,
|
|
]"
|
|
:style="{
|
|
backgroundColor,
|
|
}"
|
|
>
|
|
<div
|
|
v-if="teamIcon.icon && teamIcon.iconType === IconType.EMOJI"
|
|
class="flex items-center justify-center align-middle"
|
|
:class="{
|
|
'text-inherit': size === 'auto',
|
|
'text-white': isColorDark(getColor(backgroundColor)),
|
|
'text-black opacity-80': !isColorDark(getColor(backgroundColor)),
|
|
'text-tiny': size === 'small',
|
|
'text-base': size === 'medium',
|
|
'text-lg': size === 'base',
|
|
'text-4xl': size === 'large',
|
|
'text-5xl': size === 'xlarge',
|
|
}"
|
|
>
|
|
<div v-if="isUnicodeEmoji(teamIcon.icon)">
|
|
{{ teamIcon.icon }}
|
|
</div>
|
|
|
|
<Icon
|
|
v-else
|
|
:data-testid="`nc-icon-${teamIcon.icon}`"
|
|
class="!text-inherit flex-none"
|
|
:class="{
|
|
'w-[75%] h-[75%]': size === 'auto',
|
|
'w-3 h-3': size === 'small',
|
|
'w-4 h-4': size === 'medium',
|
|
'w-5 h-5': size === 'base',
|
|
'w-12 h-12': size === 'large',
|
|
'w-14 h-14': size === 'xlarge',
|
|
}"
|
|
:icon="teamIcon.icon"
|
|
></Icon>
|
|
</div>
|
|
<GeneralIcon
|
|
v-else-if="teamIcon.icon && teamIcon.iconType === IconType.ICON"
|
|
:icon="teamIcon.icon"
|
|
class="flex-none"
|
|
:class="{
|
|
'w-[75%] h-[75%]': size === 'auto',
|
|
'text-white': isColorDark(getColor(backgroundColor)),
|
|
'text-black opacity-80': !isColorDark(getColor(backgroundColor)),
|
|
'w-3 h-3': size === 'small',
|
|
'w-4 h-4': size === 'medium',
|
|
'w-5 h-5': size === 'base',
|
|
'w-12 h-12': size === 'large',
|
|
'w-14 h-14': size === 'xlarge',
|
|
'!opacity-50': isDeleted || isPlaceholderIconShown,
|
|
}"
|
|
/>
|
|
<div
|
|
v-else-if="teamInitials"
|
|
class="font-semibold"
|
|
:class="{
|
|
'!text-md': size === 'base',
|
|
'!text-3xl': size === 'large',
|
|
'!text-4xl': size === 'xlarge',
|
|
'text-white': isColorDark(getColor(backgroundColor)),
|
|
'text-black': !isColorDark(getColor(backgroundColor)),
|
|
}"
|
|
>
|
|
{{ teamInitials }}
|
|
</div>
|
|
<div v-else> </div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.nc-team-avatar {
|
|
@apply flex-none rounded-lg text-xs flex items-center justify-center uppercase overflow-hidden;
|
|
}
|
|
</style>
|