mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-30 03:38:54 +01:00
feat(Avatar): add icon prop as fallback
This commit is contained in:
@@ -51,9 +51,25 @@ baseProps:
|
|||||||
|
|
||||||
### Placeholder
|
### Placeholder
|
||||||
|
|
||||||
If there is an error loading the `src` of the avatar or `src` is null a background placeholder will be displayed, customizable in `ui.avatar.background`.
|
If there is an error loading the `src` of the avatar or `src` is null / false a background placeholder will be displayed, customizable in `ui.avatar.background`.
|
||||||
|
|
||||||
If there's an `alt` prop initials will be displayed on top of the background, customizable in `ui.avatar.placeholder`.
|
#### Icon
|
||||||
|
|
||||||
|
You can use the `icon` prop to display an icon on top of the background, customizable in `ui.avatar.icon`.
|
||||||
|
|
||||||
|
::component-card
|
||||||
|
---
|
||||||
|
props:
|
||||||
|
icon: 'i-heroicons-photo'
|
||||||
|
size: 'sm'
|
||||||
|
excludedProps:
|
||||||
|
- icon
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
|
#### Alt
|
||||||
|
|
||||||
|
Otherwise, a placeholder will be displayed with the initials of the `alt` prop, customizable in `ui.avatar.placeholder`.
|
||||||
|
|
||||||
::component-card
|
::component-card
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -63,17 +63,18 @@ const avatar = {
|
|||||||
wrapper: 'relative inline-flex items-center justify-center',
|
wrapper: 'relative inline-flex items-center justify-center',
|
||||||
background: 'bg-gray-100 dark:bg-gray-800',
|
background: 'bg-gray-100 dark:bg-gray-800',
|
||||||
rounded: 'rounded-full',
|
rounded: 'rounded-full',
|
||||||
placeholder: 'font-medium leading-none text-gray-900 dark:text-white truncate',
|
text: 'font-medium leading-none text-gray-900 dark:text-white truncate',
|
||||||
|
placeholder: 'font-medium leading-none text-gray-500 dark:text-gray-400 truncate',
|
||||||
size: {
|
size: {
|
||||||
'3xs': 'h-4 w-4 text-[8px]',
|
'3xs': 'h-4 w-4 text-[8px]',
|
||||||
'2xs': 'h-5 w-5 text-[10px]',
|
'2xs': 'h-5 w-5 text-[10px]',
|
||||||
xs: 'h-6 w-6 text-[11px]',
|
xs: 'h-6 w-6 text-xs',
|
||||||
sm: 'h-8 w-8 text-xs',
|
sm: 'h-8 w-8 text-sm',
|
||||||
md: 'h-10 w-10 text-sm',
|
md: 'h-10 w-10 text-base',
|
||||||
lg: 'h-12 w-12 text-base',
|
lg: 'h-12 w-12 text-lg',
|
||||||
xl: 'h-14 w-14 text-lg',
|
xl: 'h-14 w-14 text-xl',
|
||||||
'2xl': 'h-16 w-16 text-xl',
|
'2xl': 'h-16 w-16 text-2xl',
|
||||||
'3xl': 'h-20 w-20 text-2xl'
|
'3xl': 'h-20 w-20 text-3xl'
|
||||||
},
|
},
|
||||||
chip: {
|
chip: {
|
||||||
base: 'absolute rounded-full ring-1 ring-white dark:ring-gray-900 flex items-center justify-center text-white dark:text-gray-900 font-medium',
|
base: 'absolute rounded-full ring-1 ring-white dark:ring-gray-900 flex items-center justify-center text-white dark:text-gray-900 font-medium',
|
||||||
@@ -96,6 +97,20 @@ const avatar = {
|
|||||||
'3xl': 'h-5 min-w-[1.25rem] text-[14px] p-1'
|
'3xl': 'h-5 min-w-[1.25rem] text-[14px] p-1'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
icon: {
|
||||||
|
base: 'text-gray-500 dark:text-gray-400 flex-shrink-0',
|
||||||
|
size: {
|
||||||
|
'3xs': 'h-2 w-2',
|
||||||
|
'2xs': 'h-2.5 w-2.5',
|
||||||
|
xs: 'h-3 w-3',
|
||||||
|
sm: 'h-4 w-4',
|
||||||
|
md: 'h-5 w-5',
|
||||||
|
lg: 'h-6 w-6',
|
||||||
|
xl: 'h-7 w-7',
|
||||||
|
'2xl': 'h-8 w-8',
|
||||||
|
'3xl': 'h-10 w-10'
|
||||||
|
}
|
||||||
|
},
|
||||||
default: {
|
default: {
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
chipColor: null,
|
chipColor: null,
|
||||||
|
|||||||
@@ -6,9 +6,11 @@
|
|||||||
:alt="alt"
|
:alt="alt"
|
||||||
:src="url"
|
:src="url"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
:onerror="() => onError()"
|
@error="onError"
|
||||||
>
|
>
|
||||||
<span v-else-if="text || placeholder" :class="ui.placeholder">{{ text || placeholder }}</span>
|
<span v-else-if="text" :class="ui.text">{{ text }}</span>
|
||||||
|
<UIcon v-else-if="icon" :name="icon" :class="iconClass" />
|
||||||
|
<span v-else-if="placeholder" :class="ui.placeholder">{{ placeholder }}</span>
|
||||||
|
|
||||||
<span v-if="chipColor" :class="chipClass">
|
<span v-if="chipColor" :class="chipClass">
|
||||||
{{ chipText }}
|
{{ chipText }}
|
||||||
@@ -21,6 +23,7 @@
|
|||||||
import { defineComponent, ref, computed, watch } from 'vue'
|
import { defineComponent, ref, computed, watch } from 'vue'
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import { defu } from 'defu'
|
import { defu } from 'defu'
|
||||||
|
import UIcon from '../elements/Icon.vue'
|
||||||
import { classNames } from '../../utils'
|
import { classNames } from '../../utils'
|
||||||
import { useAppConfig } from '#imports'
|
import { useAppConfig } from '#imports'
|
||||||
// TODO: Remove
|
// TODO: Remove
|
||||||
@@ -30,6 +33,9 @@ import appConfig from '#build/app.config'
|
|||||||
// const appConfig = useAppConfig()
|
// const appConfig = useAppConfig()
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
UIcon
|
||||||
|
},
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
src: {
|
src: {
|
||||||
@@ -44,6 +50,10 @@ export default defineComponent({
|
|||||||
type: String,
|
type: String,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
size: {
|
size: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => appConfig.ui.avatar.default.size,
|
default: () => appConfig.ui.avatar.default.size,
|
||||||
@@ -80,10 +90,21 @@ export default defineComponent({
|
|||||||
|
|
||||||
const ui = computed<Partial<typeof appConfig.ui.avatar>>(() => defu({}, props.ui, appConfig.ui.avatar))
|
const ui = computed<Partial<typeof appConfig.ui.avatar>>(() => defu({}, props.ui, appConfig.ui.avatar))
|
||||||
|
|
||||||
|
const url = computed(() => {
|
||||||
|
if (typeof props.src === 'boolean') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return props.src
|
||||||
|
})
|
||||||
|
|
||||||
|
const placeholder = computed(() => {
|
||||||
|
return (props.alt || '').split(' ').map(word => word.charAt(0)).join('').substring(0, 2)
|
||||||
|
})
|
||||||
|
|
||||||
const wrapperClass = computed(() => {
|
const wrapperClass = computed(() => {
|
||||||
return classNames(
|
return classNames(
|
||||||
ui.value.wrapper,
|
ui.value.wrapper,
|
||||||
ui.value.background,
|
(error.value || !url.value) && ui.value.background,
|
||||||
ui.value.rounded,
|
ui.value.rounded,
|
||||||
ui.value.size[props.size]
|
ui.value.size[props.size]
|
||||||
)
|
)
|
||||||
@@ -96,6 +117,13 @@ export default defineComponent({
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const iconClass = computed(() => {
|
||||||
|
return classNames(
|
||||||
|
ui.value.icon.base,
|
||||||
|
ui.value.icon.size[props.size]
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
const chipClass = computed(() => {
|
const chipClass = computed(() => {
|
||||||
return classNames(
|
return classNames(
|
||||||
ui.value.chip.base,
|
ui.value.chip.base,
|
||||||
@@ -105,17 +133,6 @@ export default defineComponent({
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const url = computed(() => {
|
|
||||||
if (typeof props.src === 'boolean') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return props.src
|
|
||||||
})
|
|
||||||
|
|
||||||
const placeholder = computed(() => {
|
|
||||||
return (props.alt || '').split(' ').map(word => word.charAt(0)).join('').substring(0, 2)
|
|
||||||
})
|
|
||||||
|
|
||||||
const error = ref(false)
|
const error = ref(false)
|
||||||
|
|
||||||
watch(() => props.src, () => {
|
watch(() => props.src, () => {
|
||||||
@@ -131,6 +148,7 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
wrapperClass,
|
wrapperClass,
|
||||||
avatarClass,
|
avatarClass,
|
||||||
|
iconClass,
|
||||||
chipClass,
|
chipClass,
|
||||||
url,
|
url,
|
||||||
placeholder,
|
placeholder,
|
||||||
|
|||||||
Reference in New Issue
Block a user