design-system-dashboard-devmunity 0.4.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -31
- package/app/app.config.ts +2 -1
- package/app/app.vue +21 -3
- package/app/assets/css/themes/components/input.js +5 -0
- package/app/assets/css/themes/index.js +1 -0
- package/app/components/BaseButton.vue +3 -0
- package/app/components/Colors.mdx +42 -0
- package/app/components/Indroduction.mdx +100 -0
- package/app/components/a/button/a-button-avatar-dropdown.stories.ts +83 -0
- package/app/components/a/button/a-button-avatar-dropdown.vue +41 -17
- package/app/components/a/button/a-button-navigation.stories.ts +66 -0
- package/app/components/a/button/a-button-navigation.vue +57 -0
- package/app/components/a/card/a-card-inner.stories.ts +89 -0
- package/app/components/a/card/a-card-inner.vue +26 -13
- package/app/components/a/dropdown/a-dropdown-avatar.stories.ts +160 -0
- package/app/components/a/dropdown/a-dropdown-avatar.vue +75 -33
- package/app/components/a/pill/a-pill.stories.ts +91 -0
- package/app/components/a/pill/a-pill.vue +63 -42
- package/app/components/b/badge/b-badge.stories.ts +77 -0
- package/app/components/b/badge/b-badge.vue +43 -19
- package/app/components/b/card/b-card.stories.ts +120 -0
- package/app/components/b/card/b-card.vue +49 -32
- package/app/components/b/modal/b-modal.stories.ts +210 -0
- package/app/components/b/modal/b-modal.vue +125 -81
- package/app/components/c/badge/c-badge-status.stories.ts +72 -0
- package/app/components/c/badge/c-badge-status.vue +36 -15
- package/app/components/c/modal/c-modal-danger.stories.ts +112 -0
- package/app/components/c/modal/c-modal-danger.vue +60 -41
- package/app/components/d/action-buttons/d-action-buttons.stories.ts +90 -0
- package/app/components/d/action-buttons/d-action-buttons.vue +121 -0
- package/app/components/d/card/d-card-header.stories.ts +123 -0
- package/app/components/d/card/d-card-header.vue +59 -41
- package/app/components/d/upload/d-upload-avatar.stories.ts +66 -0
- package/app/components/d/upload/d-upload-avatar.vue +49 -30
- package/app/types/index.ts +1 -0
- package/app/types/semantic-colors.type.ts +3 -0
- package/app/utils/util-get-colors-from-css.ts +53 -0
- package/nuxt.config.ts +11 -16
- package/package.json +84 -68
- package/.editorconfig +0 -13
- package/.github/workflows/release.yml +0 -36
- package/.husky/commit-msg +0 -1
- package/.husky/pre-commit +0 -0
- package/.prettierrc +0 -24
- package/.storybook/main.js +0 -25
- package/.storybook/preview.js +0 -13
- package/.vscode/settings.json +0 -28
- package/CHANGELOG.md +0 -55
- package/app/Introduction.mdx +0 -44
- package/app/components/a/button/a-button-back.vue +0 -33
- package/app/components/d/d-action-buttons.vue +0 -99
- package/commitlint.config.js +0 -8
- package/tsconfig.json +0 -8
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
import ACardInner from './a-card-inner.vue'
|
|
3
|
+
import BCard from '@/components/b/card/b-card.vue'
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof ACardInner> = {
|
|
6
|
+
title: 'Atoms/Card/ACardInner',
|
|
7
|
+
component: ACardInner,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
'A simple component that allows you to apply standardized padding in all directions to separate content from its edges.',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
argTypes: {
|
|
18
|
+
class: {
|
|
19
|
+
control: 'text',
|
|
20
|
+
description: 'CSS classes to apply to the card',
|
|
21
|
+
},
|
|
22
|
+
as: {
|
|
23
|
+
control: 'select',
|
|
24
|
+
options: ['div', 'section', 'article', 'main', 'aside'],
|
|
25
|
+
description: 'HTML element to render as',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type Story = StoryObj<typeof meta>
|
|
31
|
+
export default meta
|
|
32
|
+
|
|
33
|
+
export const Default: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
as: 'div',
|
|
36
|
+
},
|
|
37
|
+
render: (args) => ({
|
|
38
|
+
components: { ACardInner },
|
|
39
|
+
setup() {
|
|
40
|
+
return { args }
|
|
41
|
+
},
|
|
42
|
+
template: '<a-card-inner v-bind="args">Default Content</a-card-inner>',
|
|
43
|
+
}),
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const CustomClass: Story = {
|
|
47
|
+
args: {
|
|
48
|
+
as: 'section',
|
|
49
|
+
class: 'bg-neutral-100 p-4 rounded-lg border border-neutral-200',
|
|
50
|
+
},
|
|
51
|
+
render: (args) => ({
|
|
52
|
+
components: { ACardInner },
|
|
53
|
+
setup() {
|
|
54
|
+
return { args }
|
|
55
|
+
},
|
|
56
|
+
template: '<a-card-inner v-bind="args">Content with custom styling</a-card-inner>',
|
|
57
|
+
}),
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const WithBCardComponent: Story = {
|
|
61
|
+
name: 'With BCard component',
|
|
62
|
+
args: {
|
|
63
|
+
as: 'section',
|
|
64
|
+
},
|
|
65
|
+
render: (args) => ({
|
|
66
|
+
components: { ACardInner, BCard },
|
|
67
|
+
setup() {
|
|
68
|
+
return { args }
|
|
69
|
+
},
|
|
70
|
+
template: `
|
|
71
|
+
<b-card>
|
|
72
|
+
<template #header>
|
|
73
|
+
<a-card-inner>
|
|
74
|
+
<h2>BCard Header</h2>
|
|
75
|
+
</a-card-inner>
|
|
76
|
+
</template>
|
|
77
|
+
|
|
78
|
+
<a-card-inner>
|
|
79
|
+
<p>BCard Inner content</p>
|
|
80
|
+
</a-card-inner>
|
|
81
|
+
|
|
82
|
+
<template #footer>
|
|
83
|
+
<a-card-inner>
|
|
84
|
+
<p>BCard Footer</p>
|
|
85
|
+
</a-card-inner>
|
|
86
|
+
</template>
|
|
87
|
+
</b-card>`,
|
|
88
|
+
}),
|
|
89
|
+
}
|
|
@@ -1,20 +1,33 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import {
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { Component } from 'vue'
|
|
3
|
+
import { twMerge, type ClassNameValue } from 'tailwind-merge'
|
|
3
4
|
import { card } from '~/assets/css/themes/index.js'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
interface Props {
|
|
7
|
+
/**
|
|
8
|
+
* The class to apply to the card
|
|
9
|
+
* @type ClassNameValue
|
|
10
|
+
*/
|
|
11
|
+
class?: ClassNameValue
|
|
12
|
+
/**
|
|
13
|
+
* The component to render the card as
|
|
14
|
+
* @type string | Component
|
|
15
|
+
*/
|
|
16
|
+
as?: string | Component
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
20
|
+
class: '',
|
|
21
|
+
as: 'div',
|
|
16
22
|
})
|
|
17
23
|
|
|
24
|
+
defineSlots<{
|
|
25
|
+
/**
|
|
26
|
+
* The default slot in which all the content
|
|
27
|
+
*/
|
|
28
|
+
default(): any
|
|
29
|
+
}>()
|
|
30
|
+
|
|
18
31
|
const cardClasses = computed(() => twMerge(card.slots.body, props.class))
|
|
19
32
|
</script>
|
|
20
33
|
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
import ADropdownAvatar, { type DropdownItem } from './a-dropdown-avatar.vue'
|
|
3
|
+
import UButton from '@nuxt/ui/components/Button.vue'
|
|
4
|
+
import UAvatar from '@nuxt/ui/components/Avatar.vue'
|
|
5
|
+
import AButtonAvatarDropdown from '@/components/a/button/a-button-avatar-dropdown.vue'
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: 'Atoms/Dropdown/ADropdownAvatar',
|
|
9
|
+
component: ADropdownAvatar,
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
'A specialized dropdown menu for displaying user information. Typically used in conjunction with the [AButtonAvatarDropdown](?path=/docs/atoms-button-abuttonavatardropdown--docs) component.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
render: (args) => ({
|
|
19
|
+
components: { ADropdownAvatar, UButton, UAvatar, AButtonAvatarDropdown },
|
|
20
|
+
setup() {
|
|
21
|
+
return { args }
|
|
22
|
+
},
|
|
23
|
+
template: `
|
|
24
|
+
<ADropdownAvatar v-bind="args">
|
|
25
|
+
<UButton icon="i-lucide-menu" color="neutral" variant="outline" />
|
|
26
|
+
</ADropdownAvatar>
|
|
27
|
+
`,
|
|
28
|
+
}),
|
|
29
|
+
argTypes: {
|
|
30
|
+
userName: {
|
|
31
|
+
control: 'text',
|
|
32
|
+
},
|
|
33
|
+
userEmail: {
|
|
34
|
+
control: 'text',
|
|
35
|
+
},
|
|
36
|
+
userTo: {
|
|
37
|
+
control: 'text',
|
|
38
|
+
},
|
|
39
|
+
items: {
|
|
40
|
+
control: 'object',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
} satisfies Meta<typeof ADropdownAvatar>
|
|
44
|
+
|
|
45
|
+
export default meta
|
|
46
|
+
|
|
47
|
+
type Story = StoryObj<typeof meta>
|
|
48
|
+
|
|
49
|
+
const items: DropdownItem[][] = [
|
|
50
|
+
[{ label: 'Profile', icon: 'heroicons:user' }],
|
|
51
|
+
[{ label: 'Settings', icon: 'heroicons:cog-6-tooth' }],
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
export const Default: Story = {
|
|
55
|
+
args: {
|
|
56
|
+
userName: 'John Doe',
|
|
57
|
+
userEmail: 'john@example.com',
|
|
58
|
+
items,
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const WithAButtonAvatarDropdownComponent: Story = {
|
|
63
|
+
name: 'With AButtonAvatarDropdown Component',
|
|
64
|
+
render: (args) => ({
|
|
65
|
+
components: { ADropdownAvatar, AButtonAvatarDropdown },
|
|
66
|
+
setup() {
|
|
67
|
+
return { args }
|
|
68
|
+
},
|
|
69
|
+
template: `
|
|
70
|
+
<ADropdownAvatar v-bind="args">
|
|
71
|
+
<span>
|
|
72
|
+
<AButtonAvatarDropdown
|
|
73
|
+
label="Custom Trigger"
|
|
74
|
+
color="success"
|
|
75
|
+
trailing-icon="i-heroicons-chevron-down"
|
|
76
|
+
src="https://avatars.githubusercontent.com/u/739984?v=4"
|
|
77
|
+
/>
|
|
78
|
+
</span>
|
|
79
|
+
</ADropdownAvatar>
|
|
80
|
+
`,
|
|
81
|
+
}),
|
|
82
|
+
args: {
|
|
83
|
+
userName: 'Admin',
|
|
84
|
+
userEmail: 'admin@sys.com',
|
|
85
|
+
userTo: '/profile',
|
|
86
|
+
items: [
|
|
87
|
+
...items,
|
|
88
|
+
[
|
|
89
|
+
{
|
|
90
|
+
label: 'Logout',
|
|
91
|
+
icon: 'heroicons:arrow-left-on-rectangle',
|
|
92
|
+
color: 'error',
|
|
93
|
+
trailingIcon: 'heroicons:arrow-left-on-rectangle',
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const Minimal: Story = {
|
|
101
|
+
args: {
|
|
102
|
+
userName: 'Jane',
|
|
103
|
+
items: [[{ label: 'Logout', icon: 'heroicons:arrow-left-on-rectangle' }]],
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const WithNavigation: Story = {
|
|
108
|
+
args: {
|
|
109
|
+
userName: 'Admin user',
|
|
110
|
+
userEmail: 'admin@system.com',
|
|
111
|
+
userTo: '/profile',
|
|
112
|
+
items,
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export const CustomTrigger: Story = {
|
|
117
|
+
render: (args) => ({
|
|
118
|
+
components: { ADropdownAvatar, UButton },
|
|
119
|
+
setup() {
|
|
120
|
+
return { args }
|
|
121
|
+
},
|
|
122
|
+
template: `
|
|
123
|
+
<ADropdownAvatar v-bind="args">
|
|
124
|
+
<UButton label="Custom Trigger" color="primary" trailing-icon="i-heroicons-chevron-down" />
|
|
125
|
+
</ADropdownAvatar>
|
|
126
|
+
`,
|
|
127
|
+
}),
|
|
128
|
+
args: {
|
|
129
|
+
userName: 'Custom User',
|
|
130
|
+
items,
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const CustomUserSlot: Story = {
|
|
135
|
+
render: (args) => ({
|
|
136
|
+
components: { ADropdownAvatar, UAvatar },
|
|
137
|
+
setup() {
|
|
138
|
+
return { args }
|
|
139
|
+
},
|
|
140
|
+
template: `
|
|
141
|
+
<ADropdownAvatar v-bind="args">
|
|
142
|
+
<UAvatar src="https://avatars.githubusercontent.com/u/739984?v=4" alt="Avatar" size="sm" />
|
|
143
|
+
<template #user="{ item }">
|
|
144
|
+
<div class="flex items-center gap-2 p-1">
|
|
145
|
+
<UAvatar :src="'https://ui.nuxt.com/avatars/' + item.userName + '.png'" size="xs" />
|
|
146
|
+
<div class="text-start">
|
|
147
|
+
<p class="text-sm font-bold text-primary-600">Admin: {{ item.userName }}</p>
|
|
148
|
+
<p class="text-xs text-gray-500">{{ item.userEmail }}</p>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
</template>
|
|
152
|
+
</ADropdownAvatar>
|
|
153
|
+
`,
|
|
154
|
+
}),
|
|
155
|
+
args: {
|
|
156
|
+
userName: 'benjamincanac',
|
|
157
|
+
userEmail: 'ben@nuxt.com',
|
|
158
|
+
items,
|
|
159
|
+
},
|
|
160
|
+
}
|
|
@@ -1,44 +1,86 @@
|
|
|
1
|
-
<script lang="
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { UDropdownMenu } from '#components'
|
|
3
|
+
|
|
4
|
+
export interface DropdownItem {
|
|
5
|
+
userName?: string
|
|
6
|
+
userEmail?: string
|
|
7
|
+
slot?: string
|
|
8
|
+
onSelect?: () => void
|
|
9
|
+
// label?: string
|
|
10
|
+
// icon?: string
|
|
11
|
+
// to?: string
|
|
12
|
+
[key: string]: any
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
/**
|
|
17
|
+
* Array of dropdown items to display, grouped in arrays
|
|
18
|
+
*/
|
|
19
|
+
items: DropdownItem[][]
|
|
20
|
+
/**
|
|
21
|
+
* Display name of the user
|
|
22
|
+
*/
|
|
23
|
+
userName: string
|
|
24
|
+
/**
|
|
25
|
+
* Email address of the user
|
|
26
|
+
*/
|
|
27
|
+
userEmail?: string
|
|
28
|
+
/**
|
|
29
|
+
* Navigation path for user profile
|
|
30
|
+
*/
|
|
31
|
+
userTo?: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
35
|
+
items: () => [],
|
|
36
|
+
userEmail: '',
|
|
37
|
+
userTo: '',
|
|
23
38
|
})
|
|
24
39
|
|
|
40
|
+
defineSlots<{
|
|
41
|
+
/**
|
|
42
|
+
* Default slot content for dropdown trigger (REQUIRED)
|
|
43
|
+
*/
|
|
44
|
+
default(): any
|
|
45
|
+
/**
|
|
46
|
+
* User information slot
|
|
47
|
+
*/
|
|
48
|
+
user(props: { item: DropdownItem }): any
|
|
49
|
+
/**
|
|
50
|
+
* Additional dynamic slots
|
|
51
|
+
*/
|
|
52
|
+
[name: string]: any
|
|
53
|
+
}>()
|
|
54
|
+
|
|
55
|
+
// Validate that the default slot is provided
|
|
56
|
+
const slots = useSlots()
|
|
57
|
+
if (!slots.default) {
|
|
58
|
+
console.warn('ADropdownAvatar: The default slot is required')
|
|
59
|
+
}
|
|
60
|
+
|
|
25
61
|
const uiStyles = computed(() => {
|
|
26
|
-
|
|
62
|
+
const ui = {
|
|
63
|
+
content: 'min-w-40',
|
|
64
|
+
}
|
|
65
|
+
if (props.userTo) return ui
|
|
27
66
|
return {
|
|
67
|
+
...ui,
|
|
28
68
|
item: 'data-highlighted:first:before:bg-transparent data-[state=open]:first:before:bg-transparent',
|
|
29
69
|
}
|
|
30
70
|
})
|
|
31
71
|
|
|
32
|
-
const itemsComputed = computed(() => [
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
72
|
+
const itemsComputed = computed((): DropdownItem[][] => [
|
|
73
|
+
[
|
|
74
|
+
{
|
|
75
|
+
userName: props.userName,
|
|
76
|
+
userEmail: props.userEmail,
|
|
77
|
+
slot: 'user',
|
|
78
|
+
onSelect: () => {
|
|
79
|
+
const path = props.userTo
|
|
80
|
+
if (path) navigateTo(path)
|
|
81
|
+
},
|
|
40
82
|
},
|
|
41
|
-
|
|
83
|
+
],
|
|
42
84
|
...props.items,
|
|
43
85
|
])
|
|
44
86
|
</script>
|
|
@@ -47,7 +89,7 @@ const itemsComputed = computed(() => [
|
|
|
47
89
|
<UDropdownMenu :items="itemsComputed" :ui="uiStyles">
|
|
48
90
|
<slot />
|
|
49
91
|
|
|
50
|
-
<template #user="{ item }">
|
|
92
|
+
<template #user="{ item }: { item: any }">
|
|
51
93
|
<div class="text-start">
|
|
52
94
|
<span class="text-highlighted block text-lg font-bold">
|
|
53
95
|
{{ item.userName }}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
import { fn } from '@storybook/test'
|
|
3
|
+
import APill, { type BadgeSize, type BadgeVariant } from './a-pill.vue'
|
|
4
|
+
import { semanticColors } from '@/utils/util-get-colors-from-css'
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: 'Atoms/Pill/APill',
|
|
8
|
+
component: APill,
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component:
|
|
13
|
+
"A small, rounded label used to display brief information. Typically used to show a user's name next to their avatar.",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
argTypes: {
|
|
18
|
+
variant: {
|
|
19
|
+
control: 'select',
|
|
20
|
+
options: ['solid', 'outline', 'soft', 'subtle'] satisfies BadgeVariant[],
|
|
21
|
+
},
|
|
22
|
+
size: {
|
|
23
|
+
control: 'select',
|
|
24
|
+
options: ['xs', 'sm', 'md', 'lg', 'xl'] satisfies BadgeSize[],
|
|
25
|
+
},
|
|
26
|
+
color: {
|
|
27
|
+
control: 'select',
|
|
28
|
+
options: Object.keys(semanticColors),
|
|
29
|
+
},
|
|
30
|
+
'onOn-close': {
|
|
31
|
+
table: { disable: true },
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
args: {
|
|
35
|
+
'onOn-close': fn(),
|
|
36
|
+
},
|
|
37
|
+
} satisfies Meta<typeof APill>
|
|
38
|
+
|
|
39
|
+
export default meta
|
|
40
|
+
|
|
41
|
+
type Story = StoryObj<typeof meta>
|
|
42
|
+
|
|
43
|
+
export const Default: Story = {
|
|
44
|
+
args: {
|
|
45
|
+
label: 'Design System',
|
|
46
|
+
src: 'https://avatars.githubusercontent.com/u/739984?v=4',
|
|
47
|
+
color: 'neutral',
|
|
48
|
+
variant: 'outline',
|
|
49
|
+
size: 'sm',
|
|
50
|
+
hasAvatar: true,
|
|
51
|
+
isClosable: true,
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const SolidPrimary: Story = {
|
|
56
|
+
args: {
|
|
57
|
+
...Default.args,
|
|
58
|
+
label: 'Primary Solid',
|
|
59
|
+
color: 'primary',
|
|
60
|
+
variant: 'solid',
|
|
61
|
+
size: 'md',
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const SoftSuccess: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
...Default.args,
|
|
68
|
+
label: 'Success Soft',
|
|
69
|
+
color: 'success',
|
|
70
|
+
variant: 'soft',
|
|
71
|
+
size: 'md',
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const NoAvatar: Story = {
|
|
76
|
+
args: {
|
|
77
|
+
...Default.args,
|
|
78
|
+
label: 'Just Text',
|
|
79
|
+
hasAvatar: false,
|
|
80
|
+
color: 'neutral',
|
|
81
|
+
variant: 'subtle',
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const NotClosable: Story = {
|
|
86
|
+
args: {
|
|
87
|
+
...Default.args,
|
|
88
|
+
label: 'Permanent',
|
|
89
|
+
isClosable: false,
|
|
90
|
+
},
|
|
91
|
+
}
|
|
@@ -1,45 +1,66 @@
|
|
|
1
|
-
<script lang="
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { UBadge, UButton } from '#components'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
|
|
5
|
+
// Derived types from Nuxt UI components
|
|
6
|
+
export type BadgeSize = InstanceType<typeof UBadge>['$props']['size']
|
|
7
|
+
export type BadgeColor = InstanceType<typeof UBadge>['$props']['color']
|
|
8
|
+
export type BadgeVariant = InstanceType<typeof UBadge>['$props']['variant']
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
/**
|
|
12
|
+
* Avatar image source URL
|
|
13
|
+
*/
|
|
14
|
+
src?: string
|
|
15
|
+
/**
|
|
16
|
+
* Text label to display
|
|
17
|
+
*/
|
|
18
|
+
label?: string
|
|
19
|
+
/**
|
|
20
|
+
* Color theme of the badge
|
|
21
|
+
*/
|
|
22
|
+
color?: BadgeColor
|
|
23
|
+
/**
|
|
24
|
+
* Visual style variant
|
|
25
|
+
*/
|
|
26
|
+
variant?: BadgeVariant
|
|
27
|
+
/**
|
|
28
|
+
* Size of the badge
|
|
29
|
+
*/
|
|
30
|
+
size?: BadgeSize
|
|
31
|
+
/**
|
|
32
|
+
* Whether to show avatar
|
|
33
|
+
*/
|
|
34
|
+
hasAvatar?: boolean
|
|
35
|
+
/**
|
|
36
|
+
* Whether to show close button
|
|
37
|
+
*/
|
|
38
|
+
isClosable?: boolean
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
42
|
+
src: '/media/img/user-unknown.png',
|
|
43
|
+
label: '',
|
|
44
|
+
color: 'neutral',
|
|
45
|
+
variant: 'outline',
|
|
46
|
+
size: 'sm',
|
|
47
|
+
hasAvatar: true,
|
|
48
|
+
isClosable: true,
|
|
40
49
|
})
|
|
41
50
|
|
|
42
|
-
const emit = defineEmits
|
|
51
|
+
const emit = defineEmits<{
|
|
52
|
+
/**
|
|
53
|
+
* Emitted when the close button is clicked
|
|
54
|
+
*/
|
|
55
|
+
(e: 'on-close'): void
|
|
56
|
+
}>()
|
|
57
|
+
|
|
58
|
+
defineSlots<{
|
|
59
|
+
/**
|
|
60
|
+
* The default slot in which all the content
|
|
61
|
+
*/
|
|
62
|
+
default(): any
|
|
63
|
+
}>()
|
|
43
64
|
|
|
44
65
|
const trailingIconSize = computed(() => {
|
|
45
66
|
const sizeMap = {
|
|
@@ -72,7 +93,7 @@ const textSize = computed(() => {
|
|
|
72
93
|
src,
|
|
73
94
|
size,
|
|
74
95
|
}
|
|
75
|
-
:
|
|
96
|
+
: undefined
|
|
76
97
|
"
|
|
77
98
|
:label="label"
|
|
78
99
|
:trailing-icon="isClosable ? 'heroicons:x-mark' : ''"
|
|
@@ -82,6 +103,7 @@ const textSize = computed(() => {
|
|
|
82
103
|
}"
|
|
83
104
|
:color="color"
|
|
84
105
|
:variant="variant"
|
|
106
|
+
:class="{ 'pl-2': !hasAvatar, 'pr-3': !isClosable }"
|
|
85
107
|
class="rounded-full font-normal"
|
|
86
108
|
>
|
|
87
109
|
<template #trailing>
|
|
@@ -90,7 +112,6 @@ const textSize = computed(() => {
|
|
|
90
112
|
:size="size"
|
|
91
113
|
:ui="{
|
|
92
114
|
leadingIcon: trailingIconSize,
|
|
93
|
-
icon: trailingIconSize,
|
|
94
115
|
}"
|
|
95
116
|
:color="color"
|
|
96
117
|
:variant="variant === 'solid' ? 'solid' : 'icon'"
|