From 2d52834529e00a43b1a9b3015d073500b4208981 Mon Sep 17 00:00:00 2001 From: Malik-Jouda <48517781+Malik-Jouda@users.noreply.github.com> Date: Tue, 5 Nov 2024 20:34:40 +0200 Subject: [PATCH] feat(Badge): handle `icon` and `avatar` props (#2497) Co-authored-by: Benjamin Canac --- docs/content/3.components/badge.md | 48 +++++++ playground/app/pages/components/badge.vue | 27 +++- src/runtime/components/Badge.vue | 33 ++++- src/theme/badge.ts | 30 ++++- test/components/Badge.spec.ts | 12 +- .../__snapshots__/Badge-vue.spec.ts.snap | 101 ++++++++++++--- .../__snapshots__/Badge.spec.ts.snap | 117 +++++++++++++++--- .../__snapshots__/Table-vue.spec.ts.snap | 10 +- .../__snapshots__/Table.spec.ts.snap | 10 +- 9 files changed, 338 insertions(+), 50 deletions(-) diff --git a/docs/content/3.components/badge.md b/docs/content/3.components/badge.md index 7f648f34..47fb2f82 100644 --- a/docs/content/3.components/badge.md +++ b/docs/content/3.components/badge.md @@ -68,6 +68,54 @@ slots: --- :: +### Icon + +Use the `icon` prop to show an [Icon](/components/icon) inside the Badge. + +::component-code +--- +props: + icon: i-heroicons-rocket-launch + size: md + color: primary + variant: solid +slots: + default: Badge +--- +:: + +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-code +--- +props: + trailingIcon: i-heroicons-arrow-right + size: md +slots: + default: Badge +--- +:: + +### Avatar + +Use the `avatar` prop to show an [Avatar](/components/avatar) inside the Badge. + +::component-code +--- +prettier: true +props: + avatar: + src: 'https://github.com/nuxt.png' + size: md + color: neutral + variant: outline +slots: + default: | + + Badge +--- +:: + ## Examples ### `class` prop diff --git a/playground/app/pages/components/badge.vue b/playground/app/pages/components/badge.vue index 18245435..b86cee9a 100644 --- a/playground/app/pages/components/badge.vue +++ b/playground/app/pages/components/badge.vue @@ -14,13 +14,36 @@ const variants = Object.keys(theme.variants.variant) as Array
- +
- + +
+
+
+
+ +
+
+ +
diff --git a/src/runtime/components/Badge.vue b/src/runtime/components/Badge.vue index 293f5e8c..35715d84 100644 --- a/src/runtime/components/Badge.vue +++ b/src/runtime/components/Badge.vue @@ -3,6 +3,8 @@ import { tv, type VariantProps } from 'tailwind-variants' import type { AppConfig } from '@nuxt/schema' import _appConfig from '#build/app.config' import theme from '#build/ui/badge' +import type { UseComponentIconsProps } from '../composables/useComponentIcons' +import type { AvatarProps } from '../types' const appConfig = _appConfig as AppConfig & { ui: { badge: Partial } } @@ -10,7 +12,7 @@ const badge = tv({ extend: tv(theme), ...(appConfig.ui?.badge || {}) }) type BadgeVariants = VariantProps -export interface BadgeProps { +export interface BadgeProps extends Omit { /** * The element or component this component should render as. * @defaultValue 'span' @@ -21,26 +23,51 @@ export interface BadgeProps { variant?: BadgeVariants['variant'] size?: BadgeVariants['size'] class?: any + ui?: Partial } export interface BadgeSlots { + leading(props?: {}): any default(props?: {}): any + trailing(props?: {}): any } diff --git a/src/theme/badge.ts b/src/theme/badge.ts index 70b650e6..2741ded9 100644 --- a/src/theme/badge.ts +++ b/src/theme/badge.ts @@ -1,7 +1,14 @@ import type { ModuleOptions } from '../module' export default (options: Required) => ({ - base: 'rounded-[calc(var(--ui-radius)*1.5)] font-medium inline-flex items-center', + slots: { + base: 'rounded-[calc(var(--ui-radius)*1.5)] font-medium inline-flex items-center', + label: 'truncate', + leadingIcon: 'shrink-0', + leadingAvatar: 'shrink-0', + leadingAvatarSize: '', + trailingIcon: 'shrink-0' + }, variants: { color: { ...Object.fromEntries((options.theme.colors || []).map((color: string) => [color, ''])), @@ -14,9 +21,24 @@ export default (options: Required) => ({ subtle: '' }, size: { - sm: 'text-xs px-1.5 py-0.5', - md: 'text-xs px-2 py-1', - lg: 'text-sm px-2 py-1' + sm: { + base: 'text-xs px-1.5 py-0.5 gap-1', + leadingIcon: 'size-4', + leadingAvatarSize: '3xs', + trailingIcon: 'size-4' + }, + md: { + base: 'text-xs px-2 py-1 gap-1', + leadingIcon: 'size-4', + leadingAvatarSize: '3xs', + trailingIcon: 'size-4' + }, + lg: { + base: 'text-sm px-2 py-1 gap-1.5', + leadingIcon: 'size-5', + leadingAvatarSize: '2xs', + trailingIcon: 'size-5' + } } }, compoundVariants: [...(options.theme.colors || []).map((color: string) => ({ diff --git a/test/components/Badge.spec.ts b/test/components/Badge.spec.ts index 08072f07..f5c46b45 100644 --- a/test/components/Badge.spec.ts +++ b/test/components/Badge.spec.ts @@ -15,8 +15,18 @@ describe('Badge', () => { ...sizes.map((size: string) => [`with size ${size}`, { props: { label: 'Badge', size } }]), ...variants.map((variant: string) => [`with primary variant ${variant}`, { props: { label: 'Badge', variant } }]), ...variants.map((variant: string) => [`with neutral variant ${variant}`, { props: { label: 'Badge', variant, color: 'neutral' } }]), + ['with icon', { props: { icon: 'i-heroicons-rocket-launch' } }], + ['with leading and icon', { props: { leading: true, icon: 'i-heroicons-arrow-left' } }], + ['with leadingIcon', { props: { leadingIcon: 'i-heroicons-arrow-left' } }], + ['with trailing and icon', { props: { trailing: true, icon: 'i-heroicons-arrow-right' } }], + ['with trailingIcon', { props: { trailingIcon: 'i-heroicons-arrow-right' } }], + ['with avatar', { props: { avatar: { src: 'https://github.com/benjamincanac.png' } } }], + ['with avatar and leadingIcon', { props: { avatar: { src: 'https://github.com/benjamincanac.png' }, leadingIcon: 'i-heroicons-arrow-left' } }], + ['with avatar and trailingIcon', { props: { avatar: { src: 'https://github.com/benjamincanac.png' }, trailingIcon: 'i-heroicons-arrow-right' } }], // Slots - ['with default slot', { slots: { default: () => 'Default slot' } }] + ['with default slot', { slots: { default: () => 'Default slot' } }], + ['with leading slot', { slots: { leading: () => 'Leading slot' } }], + ['with trailing slot', { slots: { trailing: () => 'Trailing slot' } }] ])('renders %s correctly', async (nameOrHtml: string, options: { props?: BadgeProps, slots?: Partial }) => { const html = await ComponentRender(nameOrHtml, options, Badge) expect(html).toMatchSnapshot() diff --git a/test/components/__snapshots__/Badge-vue.spec.ts.snap b/test/components/__snapshots__/Badge-vue.spec.ts.snap index 5e7c6e38..6361f054 100644 --- a/test/components/__snapshots__/Badge-vue.spec.ts.snap +++ b/test/components/__snapshots__/Badge-vue.spec.ts.snap @@ -1,31 +1,102 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Badge > renders with as correctly 1`] = `"
Badge
"`; +exports[`Badge > renders with as correctly 1`] = ` +"
+ Badge + +
" +`; -exports[`Badge > renders with class correctly 1`] = `"Badge"`; +exports[`Badge > renders with avatar and leadingIcon correctly 1`] = `""`; -exports[`Badge > renders with default slot correctly 1`] = `"Default slot"`; +exports[`Badge > renders with avatar and trailingIcon correctly 1`] = ` +" +" +`; -exports[`Badge > renders with label correctly 1`] = `"Badge"`; +exports[`Badge > renders with avatar correctly 1`] = ` +" + +" +`; -exports[`Badge > renders with neutral variant outline correctly 1`] = `"Badge"`; +exports[`Badge > renders with class correctly 1`] = ` +"Badge +" +`; -exports[`Badge > renders with neutral variant soft correctly 1`] = `"Badge"`; +exports[`Badge > renders with default slot correctly 1`] = `"Default slot"`; -exports[`Badge > renders with neutral variant solid correctly 1`] = `"Badge"`; +exports[`Badge > renders with icon correctly 1`] = `""`; -exports[`Badge > renders with neutral variant subtle correctly 1`] = `"Badge"`; +exports[`Badge > renders with label correctly 1`] = ` +"Badge +" +`; -exports[`Badge > renders with primary variant outline correctly 1`] = `"Badge"`; +exports[`Badge > renders with leading and icon correctly 1`] = `""`; -exports[`Badge > renders with primary variant soft correctly 1`] = `"Badge"`; +exports[`Badge > renders with leading slot correctly 1`] = `"Leading slot"`; -exports[`Badge > renders with primary variant solid correctly 1`] = `"Badge"`; +exports[`Badge > renders with leadingIcon correctly 1`] = `""`; -exports[`Badge > renders with primary variant subtle correctly 1`] = `"Badge"`; +exports[`Badge > renders with neutral variant outline correctly 1`] = ` +"Badge +" +`; -exports[`Badge > renders with size lg correctly 1`] = `"Badge"`; +exports[`Badge > renders with neutral variant soft correctly 1`] = ` +"Badge +" +`; -exports[`Badge > renders with size md correctly 1`] = `"Badge"`; +exports[`Badge > renders with neutral variant solid correctly 1`] = ` +"Badge +" +`; -exports[`Badge > renders with size sm correctly 1`] = `"Badge"`; +exports[`Badge > renders with neutral variant subtle correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with primary variant outline correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with primary variant soft correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with primary variant solid correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with primary variant subtle correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with size lg correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with size md correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with size sm correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with trailing and icon correctly 1`] = `""`; + +exports[`Badge > renders with trailing slot correctly 1`] = `"Trailing slot"`; + +exports[`Badge > renders with trailingIcon correctly 1`] = `""`; diff --git a/test/components/__snapshots__/Badge.spec.ts.snap b/test/components/__snapshots__/Badge.spec.ts.snap index 5e7c6e38..7a707be7 100644 --- a/test/components/__snapshots__/Badge.spec.ts.snap +++ b/test/components/__snapshots__/Badge.spec.ts.snap @@ -1,31 +1,118 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Badge > renders with as correctly 1`] = `"
Badge
"`; +exports[`Badge > renders with as correctly 1`] = ` +"
+ Badge + +
" +`; -exports[`Badge > renders with class correctly 1`] = `"Badge"`; +exports[`Badge > renders with avatar and leadingIcon correctly 1`] = ` +" + +" +`; -exports[`Badge > renders with default slot correctly 1`] = `"Default slot"`; +exports[`Badge > renders with avatar and trailingIcon correctly 1`] = ` +" +" +`; -exports[`Badge > renders with label correctly 1`] = `"Badge"`; +exports[`Badge > renders with avatar correctly 1`] = ` +" + +" +`; -exports[`Badge > renders with neutral variant outline correctly 1`] = `"Badge"`; +exports[`Badge > renders with class correctly 1`] = ` +"Badge +" +`; -exports[`Badge > renders with neutral variant soft correctly 1`] = `"Badge"`; +exports[`Badge > renders with default slot correctly 1`] = `"Default slot"`; -exports[`Badge > renders with neutral variant solid correctly 1`] = `"Badge"`; +exports[`Badge > renders with icon correctly 1`] = ` +" + +" +`; -exports[`Badge > renders with neutral variant subtle correctly 1`] = `"Badge"`; +exports[`Badge > renders with label correctly 1`] = ` +"Badge +" +`; -exports[`Badge > renders with primary variant outline correctly 1`] = `"Badge"`; +exports[`Badge > renders with leading and icon correctly 1`] = ` +" + +" +`; -exports[`Badge > renders with primary variant soft correctly 1`] = `"Badge"`; +exports[`Badge > renders with leading slot correctly 1`] = `"Leading slot"`; -exports[`Badge > renders with primary variant solid correctly 1`] = `"Badge"`; +exports[`Badge > renders with leadingIcon correctly 1`] = ` +" + +" +`; -exports[`Badge > renders with primary variant subtle correctly 1`] = `"Badge"`; +exports[`Badge > renders with neutral variant outline correctly 1`] = ` +"Badge +" +`; -exports[`Badge > renders with size lg correctly 1`] = `"Badge"`; +exports[`Badge > renders with neutral variant soft correctly 1`] = ` +"Badge +" +`; -exports[`Badge > renders with size md correctly 1`] = `"Badge"`; +exports[`Badge > renders with neutral variant solid correctly 1`] = ` +"Badge +" +`; -exports[`Badge > renders with size sm correctly 1`] = `"Badge"`; +exports[`Badge > renders with neutral variant subtle correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with primary variant outline correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with primary variant soft correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with primary variant solid correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with primary variant subtle correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with size lg correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with size md correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with size sm correctly 1`] = ` +"Badge +" +`; + +exports[`Badge > renders with trailing and icon correctly 1`] = `""`; + +exports[`Badge > renders with trailing slot correctly 1`] = `"Trailing slot"`; + +exports[`Badge > renders with trailingIcon correctly 1`] = `""`; diff --git a/test/components/__snapshots__/Table-vue.spec.ts.snap b/test/components/__snapshots__/Table-vue.spec.ts.snap index 431d3274..4601c758 100644 --- a/test/components/__snapshots__/Table-vue.spec.ts.snap +++ b/test/components/__snapshots__/Table-vue.spec.ts.snap @@ -147,7 +147,7 @@ exports[`Table > renders with columns correctly 1`] = ` #m5gr84i9 Invalid Date - success + success
ken99@yahoo.com
@@ -179,7 +179,7 @@ exports[`Table > renders with columns correctly 1`] = ` #3u1reuv4 Invalid Date - success + success
Abe45@gmail.com
@@ -211,7 +211,7 @@ exports[`Table > renders with columns correctly 1`] = ` #derv1ws0 Invalid Date - processing + processing
Monserrat44@gmail.com
@@ -243,7 +243,7 @@ exports[`Table > renders with columns correctly 1`] = ` #5kma53ae Invalid Date - success + success
Silas22@gmail.com
@@ -275,7 +275,7 @@ exports[`Table > renders with columns correctly 1`] = ` #bhqecj4p Invalid Date - failed + failed
carmella@hotmail.com
diff --git a/test/components/__snapshots__/Table.spec.ts.snap b/test/components/__snapshots__/Table.spec.ts.snap index 7579437e..fb3bbe36 100644 --- a/test/components/__snapshots__/Table.spec.ts.snap +++ b/test/components/__snapshots__/Table.spec.ts.snap @@ -147,7 +147,7 @@ exports[`Table > renders with columns correctly 1`] = ` #m5gr84i9 Invalid Date - success + success
ken99@yahoo.com
@@ -179,7 +179,7 @@ exports[`Table > renders with columns correctly 1`] = ` #3u1reuv4 Invalid Date - success + success
Abe45@gmail.com
@@ -211,7 +211,7 @@ exports[`Table > renders with columns correctly 1`] = ` #derv1ws0 Invalid Date - processing + processing
Monserrat44@gmail.com
@@ -243,7 +243,7 @@ exports[`Table > renders with columns correctly 1`] = ` #5kma53ae Invalid Date - success + success
Silas22@gmail.com
@@ -275,7 +275,7 @@ exports[`Table > renders with columns correctly 1`] = ` #bhqecj4p Invalid Date - failed + failed
carmella@hotmail.com