Skip to content

Commit

Permalink
feat(Badge): handle icon prop (#2594)
Browse files Browse the repository at this point in the history
Co-authored-by: malik jouda <[email protected]>
  • Loading branch information
malik-jouda and MalikJouda authored Nov 12, 2024
1 parent b2ed466 commit 0d1a76e
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 2 deletions.
68 changes: 68 additions & 0 deletions docs/content/2.components/badge.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,74 @@ Badge
You can customize the whole [preset](#preset) by using the `ui` prop.
::

### Icon

Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.

Use the `leading` and `trailing` props to set the icon position or the `leading-icon` and `trailing-icon` props to set a different icon for each position.

::component-card
---
props:
icon: 'i-heroicons-rocket-launch'
size: 'sm'
color: 'primary'
variant: 'solid'
label: Badge
trailing: false
options:
- name: variant
restriction: only
values:
- solid
excludedProps:
- icon
- label
---
::

## Slots

### `leading`

Use the `#leading` slot to set the content of the leading icon.

::component-card
---
slots:
leading: <UAvatar src="https://avatars.githubusercontent.com/u/739984?v=4" size="3xs" />
baseProps:
color: 'gray'
props:
label: Badge
color: 'gray'
excludedProps:
- color
---

#leading
:u-avatar{src="https://avatars.githubusercontent.com/u/739984?v=4" size="3xs"}
::

### `trailing`

Use the `#trailing` slot to set the content of the trailing icon.

::component-card
---
slots:
trailing: <UIcon name="i-heroicons-rocket-launch" class="w-4 h-4" />
props:
label: Badge
color: 'gray'
excludedProps:
- color
---

#trailing
:u-icon{name="i-heroicons-rocket-launch" class="w-4 h-4"}
::

## Props

:component-props
Expand Down
77 changes: 75 additions & 2 deletions src/runtime/components/elements/Badge.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
<template>
<span :class="badgeClass" v-bind="attrs">
<slot>{{ label }}</slot>
<slot name="leading">
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="leadingIconClass" aria-hidden="true" />
</slot>

<slot>
<span v-if="label">
{{ label }}
</span>
</slot>

<slot name="trailing">
<UIcon v-if="isTrailing && trailingIconName" :name="trailingIconName" :class="trailingIconClass" aria-hidden="true" />
</slot>
</span>
</template>

<script lang="ts">
import { computed, toRef, defineComponent } from 'vue'
import type { PropType } from 'vue'
import { twMerge, twJoin } from 'tailwind-merge'
import UIcon from '../elements/Icon.vue'
import { useUI } from '../../composables/useUI'
import { mergeConfig } from '../../utils'
import { useInjectButtonGroup } from '../../composables/useButtonGroup'
Expand All @@ -19,6 +32,9 @@ import { badge } from '#ui/ui.config'
const config = mergeConfig<typeof badge>(appConfig.ui.strategy, appConfig.ui.badge, badge)
export default defineComponent({
components: {
UIcon
},
inheritAttrs: false,
props: {
size: {
Expand Down Expand Up @@ -49,6 +65,26 @@ export default defineComponent({
type: [String, Number],
default: null
},
icon: {
type: String,
default: null
},
leadingIcon: {
type: String,
default: null
},
trailingIcon: {
type: String,
default: null
},
trailing: {
type: Boolean,
default: false
},
leading: {
type: Boolean,
default: false
},
class: {
type: [String, Object, Array] as PropType<any>,
default: () => ''
Expand All @@ -63,6 +99,14 @@ export default defineComponent({
const { size, rounded } = useInjectButtonGroup({ ui, props })
const isLeading = computed(() => {
return (props.icon && props.leading) || (props.icon && !props.trailing) || !props.trailing || props.leadingIcon
})
const isTrailing = computed(() => {
return (props.icon && props.trailing) || props.trailing || props.trailingIcon
})
const badgeClass = computed(() => {
const variant = ui.value.color?.[props.color as string]?.[props.variant as string] || ui.value.variant[props.variant]
Expand All @@ -71,13 +115,42 @@ export default defineComponent({
ui.value.font,
rounded.value,
ui.value.size[size.value],
ui.value.gap[size.value],
variant?.replaceAll('{color}', props.color)
), props.class)
})
const leadingIconName = computed(() => {
return props.leadingIcon || props.icon
})
const trailingIconName = computed(() => {
return props.trailingIcon || props.icon
})
const leadingIconClass = computed(() => {
return twJoin(
ui.value.icon.base,
ui.value.icon.size[size.value]
)
})
const trailingIconClass = computed(() => {
return twJoin(
ui.value.icon.base,
ui.value.icon.size[size.value]
)
})
return {
attrs,
badgeClass
isLeading,
isTrailing,
badgeClass,
leadingIconName,
trailingIconName,
leadingIconClass,
trailingIconClass
}
}
})
Expand Down
15 changes: 15 additions & 0 deletions src/runtime/ui.config/elements/badge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ export default {
md: 'text-sm px-2 py-1',
lg: 'text-sm px-2.5 py-1.5'
},
gap: {
xs: 'gap-0.5',
sm: 'gap-1',
md: 'gap-1',
lg: 'gap-1.5'
},
color: {
white: {
solid: 'ring-1 ring-inset ring-gray-300 dark:ring-gray-700 text-gray-900 dark:text-white bg-white dark:bg-gray-900'
Expand All @@ -25,6 +31,15 @@ export default {
soft: 'bg-{color}-50 dark:bg-{color}-400 dark:bg-opacity-10 text-{color}-500 dark:text-{color}-400',
subtle: 'bg-{color}-50 dark:bg-{color}-400 dark:bg-opacity-10 text-{color}-500 dark:text-{color}-400 ring-1 ring-inset ring-{color}-500 dark:ring-{color}-400 ring-opacity-25 dark:ring-opacity-25'
},
icon: {
base: 'flex-shrink-0',
size: {
xs: 'h-4 w-4',
sm: 'h-4 w-4',
md: 'h-5 w-5',
lg: 'h-5 w-5'
}
},
default: {
size: 'sm',
variant: 'solid',
Expand Down

0 comments on commit 0d1a76e

Please sign in to comment.