chore(Avatar): use preset system

This commit is contained in:
Benjamin Canac
2022-02-25 17:57:55 +01:00
parent 858b7da3c0
commit 55565d7079
4 changed files with 138 additions and 140 deletions

View File

@@ -68,7 +68,9 @@ const components = [
{ {
label: 'Avatar', label: 'Avatar',
to: '/components/Avatar', to: '/components/Avatar',
nuxt3: true nuxt3: true,
preset: true,
capi: true
}, },
{ {
label: 'AvatarGroup', label: 'AvatarGroup',

View File

@@ -93,6 +93,9 @@ export default defineNuxtModule<ModuleOptions>({
// Safelist dynamic colors used in preset // Safelist dynamic colors used in preset
safelist: [ safelist: [
'dark', 'dark',
{
pattern: new RegExp(`bg-(${safeColorsAsRegex})-400`)
},
{ {
pattern: new RegExp(`bg-(${safeColorsAsRegex})-(100|600|700)`), pattern: new RegExp(`bg-(${safeColorsAsRegex})-(100|600|700)`),
variants: ['hover', 'disabled', 'dark'] variants: ['hover', 'disabled', 'dark']

View File

@@ -1,151 +1,100 @@
<template> <template>
<span class="relative inline-flex items-center justify-center" :class="avatarClass" @click="goto"> <span :class="wrapperClass">
<img v-if="url" :src="url" :alt="alt" :class="[sizeClass, roundedClass]"> <img v-if="src" :class="avatarClass" :src="src" :alt="alt">
<span <span v-else-if="text || placeholder" :class="placeholderClass">{{ text || placeholder }}</span>
v-else-if="placeholder"
class="font-medium leading-none uppercase u-text-gray-900"
>{{ placeholder }}</span>
<span
v-else-if="text"
>{{ text }}</span>
<svg
v-else
class="w-full h-full u-text-gray-300"
:class="roundedClass"
fill="currentColor"
viewBox="0 0 24 24"
>
<path
d="M24 20.993V24H0v-2.996A14.977 14.977 0 0112.004 15c4.904 0 9.26 2.354 11.996 5.993zM16.002 8.999a4 4 0 11-8 0 4 4 0 018 0z"
/>
</svg>
<span v-if="chip" :class="chipClass" />
<slot /> <slot />
<span
v-if="status"
class="absolute top-0 right-0 block rounded-full ring-1 u-ring-white"
:class="statusClass"
/>
</span> </span>
</template> </template>
<script> <script setup>
export default { import { computed } from 'vue'
props: { import { classNames } from '../../utils'
src: { import $ui from '#build/ui'
type: [String, Boolean],
default: null const props = defineProps({
}, src: {
text: { type: [String, Boolean],
type: String, default: null
default: null },
}, alt: {
alt: { type: String,
type: String, default: null
default: null },
}, text: {
to: { type: String,
type: String, default: null
default: null },
}, size: {
size: { type: String,
type: String, default: 'md',
default: 'md', validator (value) {
validator (value) { return Object.keys($ui.avatar.size).includes(value)
return ['xxxs', 'xxs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'].includes(value)
}
},
rounded: {
type: Boolean,
default: false
},
status: {
type: String,
default: null,
validator (value) {
return ['online', 'idle', 'invisible', 'donotdisturb', 'focus'].includes(value)
}
} }
}, },
computed: { rounded: {
url () { type: Boolean,
if (typeof this.src === 'boolean') { default: true
return null },
} chip: {
return this.src type: Boolean,
}, default: false
placeholder () { },
if (!this.alt) { chipVariant: {
return type: String,
} default: 'primary',
return this.alt.split(' ').map(word => word.charAt(0)).join('').substr(0, 2) validator (value) {
}, return Object.keys($ui.avatar.chip.variant).includes(value)
sizeClass () {
return ({
xxxs: 'h-4 w-4 text-xs',
xxs: 'h-5 w-5 text-xs',
xs: 'h-6 w-6 text-xs',
sm: 'h-8 w-8 text-sm',
md: 'h-10 w-10 text-md',
lg: 'h-12 w-12 text-lg',
xl: 'h-14 w-14 text-xl',
'2xl': 'h-16 w-16 text-2xl',
'3xl': 'h-20 w-20 text-3xl'
})[this.size]
},
roundedClass () {
return ({
true: 'rounded-lg',
false: 'rounded-full'
})[this.rounded]
},
placeholderClass () {
return ({
true: 'u-bg-gray-100',
false: 'u-bg-gray-100'
})[!!this.alt]
},
avatarClass () {
return [
this.sizeClass,
this.roundedClass,
this.placeholderClass,
this.to ? 'cursor-pointer' : ''
].join(' ')
},
statusClass () {
return [
({
online: 'bg-green-400',
idle: 'bg-yellow-400',
invisible: 'u-bg-gray-300',
donotdisturb: 'bg-red-400',
focus: 'bg-primary-500'
})[this.status],
({
xxxs: 'h-1 w-1',
xxs: 'h-1 w-1',
xs: 'h-1.5 w-1.5',
sm: 'h-2 w-2',
md: 'h-2.5 w-2.5',
lg: 'h-3 w-3',
xl: 'h-3.5 w-3.5',
'2xl': 'h-3.5 w-3.5',
'3xl': 'h-4 w-4'
})[this.size],
({
true: 'transform -translate-y-1/2 translate-x-1/2'
})[this.rounded]
].join(' ')
} }
}, },
methods: { chipPosition: {
goto (e) { type: String,
if (!this.to || !this.$router) { return } default: 'top-right',
e.preventDefault() validator (value) {
this.$router.push(this.to) return Object.keys($ui.avatar.chip.position).includes(value)
} }
},
wrapperClass: {
type: String,
default: () => $ui.avatar.wrapper
},
backgroundClass: {
type: String,
default: () => $ui.avatar.background
},
placeholderClass: {
type: String,
default: () => $ui.avatar.placeholder
} }
} })
const wrapperClass = computed(() => {
return classNames(
props.wrapperClass,
props.backgroundClass,
$ui.avatar.size[props.size],
props.rounded ? 'rounded-full' : 'rounded-md'
)
})
const avatarClass = computed(() => {
return classNames(
$ui.avatar.size[props.size],
props.rounded ? 'rounded-full' : 'rounded-md'
)
})
const chipClass = computed(() => {
return classNames(
$ui.avatar.chip.base,
$ui.avatar.chip.position[props.chipPosition],
$ui.avatar.chip.variant[props.chipVariant],
$ui.avatar.chip.size[props.size]
)
})
const placeholder = computed(() => {
return (props.alt || '').split(' ').map(word => word.charAt(0)).join('').substr(0, 2)
})
</script> </script>

View File

@@ -307,6 +307,49 @@ const pills = {
inactive: 'u-text-gray-500 hover:u-text-gray-700' inactive: 'u-text-gray-500 hover:u-text-gray-700'
} }
const avatar = {
wrapper: 'relative inline-flex items-center justify-center',
background: 'u-bg-gray-100',
placeholder: 'text-xs font-medium leading-none u-text-black',
size: {
xxxs: 'h-4 w-4 text-xs',
xxs: 'h-5 w-5 text-xs',
xs: 'h-6 w-6 text-xs',
sm: 'h-8 w-8 text-sm',
md: 'h-10 w-10 text-md',
lg: 'h-12 w-12 text-lg',
xl: 'h-14 w-14 text-xl',
'2xl': 'h-16 w-16 text-2xl',
'3xl': 'h-20 w-20 text-3xl'
},
chip: {
base: 'absolute block rounded-full ring-2 u-ring-white',
position: {
'top-right': 'top-0 right-0',
'bottom-right': 'bottom-0 right-0',
'top-left': 'top-0 left-0',
'bottom-left': 'bottom-0 left-0'
},
variant: {
...safeColors.reduce((acc: any, color) => {
acc[color] = `bg-${color}-400`
return acc
}, {})
},
size: {
xxxs: 'h-1 w-1',
xxs: 'h-1 w-1',
xs: 'h-1.5 w-1.5',
sm: 'h-2 w-2',
md: 'h-2.5 w-2.5',
lg: 'h-3 w-3',
xl: 'h-3.5 w-3.5',
'2xl': 'h-3.5 w-3.5',
'3xl': 'h-4 w-4'
}
}
}
export default { export default {
card, card,
button, button,
@@ -324,5 +367,6 @@ export default {
alertDialog, alertDialog,
dropdown, dropdown,
tabs, tabs,
pills pills,
avatar
} }