@polymarbot/nuxt-layer-shadcn-ui 0.5.2 → 0.5.4
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/app/components/ui/Alert/index.stories.ts +101 -13
- package/app/components/ui/Alert/index.vue +39 -17
- package/app/components/ui/Alert/types.ts +4 -0
- package/app/components/ui/Badge/index.vue +1 -1
- package/app/components/ui/Badge/types.ts +4 -2
- package/app/components/ui/Button/index.stories.ts +54 -2
- package/app/components/ui/Button/index.vue +27 -3
- package/app/components/ui/Button/types.ts +5 -3
- package/package.json +2 -2
|
@@ -10,15 +10,19 @@ const meta = {
|
|
|
10
10
|
argTypes: {
|
|
11
11
|
type: { control: 'select', options: types },
|
|
12
12
|
icon: { control: 'text' },
|
|
13
|
+
title: { control: 'text' },
|
|
14
|
+
description: { control: 'text' },
|
|
13
15
|
},
|
|
14
16
|
args: {
|
|
15
17
|
type: 'default',
|
|
16
18
|
icon: '',
|
|
19
|
+
title: 'Heads up!',
|
|
20
|
+
description: 'You can add components to your app using the cli.',
|
|
17
21
|
},
|
|
18
22
|
render: args => ({
|
|
19
23
|
components: { Alert },
|
|
20
24
|
setup: () => ({ args }),
|
|
21
|
-
template: '<Alert v-bind="args"
|
|
25
|
+
template: '<Alert v-bind="args" />',
|
|
22
26
|
}),
|
|
23
27
|
} satisfies Meta<typeof Alert>
|
|
24
28
|
|
|
@@ -37,9 +41,13 @@ export const Types: Story = {
|
|
|
37
41
|
code: `
|
|
38
42
|
<template>
|
|
39
43
|
<div class="space-y-3">
|
|
40
|
-
<Alert
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
<Alert
|
|
45
|
+
v-for="t in types"
|
|
46
|
+
:key="t"
|
|
47
|
+
:type="t"
|
|
48
|
+
:title="t"
|
|
49
|
+
description="This is an alert message."
|
|
50
|
+
/>
|
|
43
51
|
</div>
|
|
44
52
|
</template>
|
|
45
53
|
`.trim(),
|
|
@@ -51,14 +59,36 @@ export const Types: Story = {
|
|
|
51
59
|
setup: () => ({ types }),
|
|
52
60
|
template: `
|
|
53
61
|
<div class="space-y-3">
|
|
54
|
-
<Alert
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
<Alert
|
|
63
|
+
v-for="t in types"
|
|
64
|
+
:key="t"
|
|
65
|
+
:type="t"
|
|
66
|
+
:title="t"
|
|
67
|
+
description="This is an alert message."
|
|
68
|
+
/>
|
|
57
69
|
</div>
|
|
58
70
|
`,
|
|
59
71
|
}),
|
|
60
72
|
}
|
|
61
73
|
|
|
74
|
+
export const TitleOnly: Story = {
|
|
75
|
+
parameters: noControls,
|
|
76
|
+
args: {
|
|
77
|
+
type: 'info',
|
|
78
|
+
title: 'A short title without description.',
|
|
79
|
+
description: '',
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const DescriptionOnly: Story = {
|
|
84
|
+
parameters: noControls,
|
|
85
|
+
args: {
|
|
86
|
+
type: 'info',
|
|
87
|
+
title: '',
|
|
88
|
+
description: 'A standalone description without a title.',
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
|
|
62
92
|
export const WithIcons: Story = {
|
|
63
93
|
parameters: {
|
|
64
94
|
...noControls,
|
|
@@ -67,9 +97,9 @@ export const WithIcons: Story = {
|
|
|
67
97
|
code: `
|
|
68
98
|
<template>
|
|
69
99
|
<div class="space-y-3">
|
|
70
|
-
<Alert type="info" icon="bell"
|
|
71
|
-
<Alert type="success" icon="sparkles"
|
|
72
|
-
<Alert type="warn" icon="flag"
|
|
100
|
+
<Alert type="info" icon="bell" title="Custom bell icon" description="Override the default icon for this type." />
|
|
101
|
+
<Alert type="success" icon="sparkles" title="Custom sparkles icon" description="Pass any lucide icon name." />
|
|
102
|
+
<Alert type="warn" icon="flag" title="Custom flag icon" description="Works for every type." />
|
|
73
103
|
</div>
|
|
74
104
|
</template>
|
|
75
105
|
`.trim(),
|
|
@@ -80,10 +110,68 @@ export const WithIcons: Story = {
|
|
|
80
110
|
components: { Alert },
|
|
81
111
|
template: `
|
|
82
112
|
<div class="space-y-3">
|
|
83
|
-
<Alert type="info" icon="bell"
|
|
84
|
-
<Alert type="success" icon="sparkles"
|
|
85
|
-
<Alert type="warn" icon="flag"
|
|
113
|
+
<Alert type="info" icon="bell" title="Custom bell icon" description="Override the default icon for this type." />
|
|
114
|
+
<Alert type="success" icon="sparkles" title="Custom sparkles icon" description="Pass any lucide icon name." />
|
|
115
|
+
<Alert type="warn" icon="flag" title="Custom flag icon" description="Works for every type." />
|
|
86
116
|
</div>
|
|
87
117
|
`,
|
|
88
118
|
}),
|
|
89
119
|
}
|
|
120
|
+
|
|
121
|
+
export const HiddenIcon: Story = {
|
|
122
|
+
parameters: {
|
|
123
|
+
...noControls,
|
|
124
|
+
docs: {
|
|
125
|
+
source: {
|
|
126
|
+
code: `
|
|
127
|
+
<template>
|
|
128
|
+
<Alert type="success" :icon="null" title="Icon hidden" description="Pass icon=\\"null\\" to suppress the type's default icon." />
|
|
129
|
+
</template>
|
|
130
|
+
`.trim(),
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
render: () => ({
|
|
135
|
+
components: { Alert },
|
|
136
|
+
template: `
|
|
137
|
+
<Alert type="success" :icon="null" title="Icon hidden" description="Pass icon="null" to suppress the type's default icon." />
|
|
138
|
+
`,
|
|
139
|
+
}),
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const CustomSlots: Story = {
|
|
143
|
+
parameters: {
|
|
144
|
+
...noControls,
|
|
145
|
+
docs: {
|
|
146
|
+
source: {
|
|
147
|
+
code: `
|
|
148
|
+
<template>
|
|
149
|
+
<Alert type="info">
|
|
150
|
+
<template #icon>
|
|
151
|
+
<Icon name="rocket" />
|
|
152
|
+
</template>
|
|
153
|
+
<template #title>
|
|
154
|
+
<span class="underline">Custom title slot</span>
|
|
155
|
+
</template>
|
|
156
|
+
Description rendered via the default slot. You can put <strong>rich content</strong> here.
|
|
157
|
+
</Alert>
|
|
158
|
+
</template>
|
|
159
|
+
`.trim(),
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
render: () => ({
|
|
164
|
+
components: { Alert },
|
|
165
|
+
template: `
|
|
166
|
+
<Alert type="info">
|
|
167
|
+
<template #icon>
|
|
168
|
+
<Icon name="rocket" />
|
|
169
|
+
</template>
|
|
170
|
+
<template #title>
|
|
171
|
+
<span class="underline">Custom title slot</span>
|
|
172
|
+
</template>
|
|
173
|
+
Description rendered via the default slot. You can put <strong>rich content</strong> here.
|
|
174
|
+
</Alert>
|
|
175
|
+
`,
|
|
176
|
+
}),
|
|
177
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { Alert as ShadcnAlert } from '../../shadcn/alert'
|
|
2
|
+
import { Alert as ShadcnAlert, AlertDescription, AlertTitle } from '../../shadcn/alert'
|
|
3
3
|
import type { AlertProps, AlertType } from './types'
|
|
4
4
|
|
|
5
5
|
const typeIconNameMap: Partial<Record<AlertType, string>> = {
|
|
@@ -22,9 +22,17 @@ const typeClasses: Record<AlertType, string> = {
|
|
|
22
22
|
const props = withDefaults(defineProps<AlertProps>(), {
|
|
23
23
|
type: 'default',
|
|
24
24
|
icon: undefined,
|
|
25
|
+
title: undefined,
|
|
26
|
+
description: undefined,
|
|
25
27
|
class: undefined,
|
|
26
28
|
})
|
|
27
29
|
|
|
30
|
+
const slots = defineSlots<{
|
|
31
|
+
default?: () => any
|
|
32
|
+
title?: () => any
|
|
33
|
+
icon?: () => any
|
|
34
|
+
}>()
|
|
35
|
+
|
|
28
36
|
const defaultIconName = computed(() => {
|
|
29
37
|
// null explicitly hides the icon; any truthy value is an explicit icon.
|
|
30
38
|
if (props.icon || props.icon === null) return undefined
|
|
@@ -37,25 +45,39 @@ const mergedClass = computed(() =>
|
|
|
37
45
|
props.class,
|
|
38
46
|
),
|
|
39
47
|
)
|
|
48
|
+
|
|
49
|
+
const hasTitle = computed(() => Boolean(slots.title || props.title))
|
|
50
|
+
const hasDescription = computed(() => Boolean(slots.default || props.description))
|
|
40
51
|
</script>
|
|
41
52
|
|
|
42
53
|
<template>
|
|
43
54
|
<ShadcnAlert :class="mergedClass">
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
<slot name="icon">
|
|
56
|
+
<Icon
|
|
57
|
+
v-if="typeof icon === 'string' && icon"
|
|
58
|
+
:name="icon"
|
|
59
|
+
/>
|
|
60
|
+
<component
|
|
61
|
+
:is="icon"
|
|
62
|
+
v-else-if="icon"
|
|
63
|
+
/>
|
|
64
|
+
<Icon
|
|
65
|
+
v-else-if="defaultIconName"
|
|
66
|
+
:name="defaultIconName"
|
|
67
|
+
/>
|
|
68
|
+
</slot>
|
|
69
|
+
<AlertTitle v-if="hasTitle">
|
|
70
|
+
<slot name="title">
|
|
71
|
+
{{ title }}
|
|
72
|
+
</slot>
|
|
73
|
+
</AlertTitle>
|
|
74
|
+
<AlertDescription
|
|
75
|
+
v-if="hasDescription"
|
|
76
|
+
class="text-current/80"
|
|
77
|
+
>
|
|
78
|
+
<slot>
|
|
79
|
+
{{ description }}
|
|
80
|
+
</slot>
|
|
81
|
+
</AlertDescription>
|
|
60
82
|
</ShadcnAlert>
|
|
61
83
|
</template>
|
|
@@ -6,5 +6,9 @@ export interface AlertProps {
|
|
|
6
6
|
type?: AlertType
|
|
7
7
|
/** Pass `null` to explicitly hide the icon; leave undefined to use the type's default. */
|
|
8
8
|
icon?: string | Component | null
|
|
9
|
+
/** Bold heading line. Slot `#title` takes precedence. */
|
|
10
|
+
title?: string
|
|
11
|
+
/** Description text. Default slot takes precedence. */
|
|
12
|
+
description?: string
|
|
9
13
|
class?: ClassValue
|
|
10
14
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { BadgeVariants } from '../../shadcn/badge'
|
|
2
2
|
|
|
3
|
-
export type BadgeVariant =
|
|
3
|
+
export type BadgeVariant = BadgeVariants['variant']
|
|
4
4
|
|
|
5
|
-
export interface BadgeProps
|
|
5
|
+
export interface BadgeProps {
|
|
6
|
+
variant?: BadgeVariant
|
|
7
|
+
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
import type { SurfaceColor } from '../Surface/types'
|
|
2
3
|
import type { ButtonSize, ButtonVariant } from './types'
|
|
3
4
|
import Icon from '../Icon/index.vue'
|
|
5
|
+
import Surface from '../Surface/index.vue'
|
|
4
6
|
import Button from './index.vue'
|
|
5
7
|
|
|
6
8
|
const variants = [
|
|
7
9
|
'default',
|
|
10
|
+
'secondary',
|
|
8
11
|
'destructive',
|
|
9
12
|
'outline',
|
|
10
|
-
'secondary',
|
|
11
13
|
'ghost',
|
|
12
14
|
'link',
|
|
13
15
|
] as const satisfies readonly ButtonVariant[]
|
|
@@ -21,6 +23,16 @@ const sizes = [
|
|
|
21
23
|
'icon-lg',
|
|
22
24
|
] as const satisfies readonly ButtonSize[]
|
|
23
25
|
|
|
26
|
+
const surfaceColors = [
|
|
27
|
+
'default',
|
|
28
|
+
'primary',
|
|
29
|
+
'success',
|
|
30
|
+
'info',
|
|
31
|
+
'help',
|
|
32
|
+
'warn',
|
|
33
|
+
'danger',
|
|
34
|
+
] as const satisfies readonly SurfaceColor[]
|
|
35
|
+
|
|
24
36
|
const meta = {
|
|
25
37
|
title: 'UI/Button',
|
|
26
38
|
component: Button,
|
|
@@ -70,9 +82,9 @@ export const Variants: Story = {
|
|
|
70
82
|
code: `
|
|
71
83
|
<template>
|
|
72
84
|
<Button variant="default">default</Button>
|
|
85
|
+
<Button variant="secondary">secondary</Button>
|
|
73
86
|
<Button variant="destructive">destructive</Button>
|
|
74
87
|
<Button variant="outline">outline</Button>
|
|
75
|
-
<Button variant="secondary">secondary</Button>
|
|
76
88
|
<Button variant="ghost">ghost</Button>
|
|
77
89
|
<Button variant="link">link</Button>
|
|
78
90
|
</template>
|
|
@@ -265,3 +277,43 @@ export const LinkButtons: Story = {
|
|
|
265
277
|
`,
|
|
266
278
|
}),
|
|
267
279
|
}
|
|
280
|
+
|
|
281
|
+
export const InheritedHoverColor: Story = {
|
|
282
|
+
parameters: {
|
|
283
|
+
...noControls,
|
|
284
|
+
docs: {
|
|
285
|
+
source: {
|
|
286
|
+
code: `
|
|
287
|
+
<template>
|
|
288
|
+
<!-- outline / ghost / link inherit the parent's currentColor -->
|
|
289
|
+
<Surface variant="soft" color="success">
|
|
290
|
+
<Button variant="outline">Outline</Button>
|
|
291
|
+
<Button variant="ghost">Ghost</Button>
|
|
292
|
+
<Button variant="link">Link</Button>
|
|
293
|
+
</Surface>
|
|
294
|
+
</template>
|
|
295
|
+
`.trim(),
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
render: () => ({
|
|
300
|
+
components: { Button, Surface },
|
|
301
|
+
setup: () => ({ surfaceColors }),
|
|
302
|
+
template: `
|
|
303
|
+
<div class="grid grid-cols-1 gap-3 lg:grid-cols-2">
|
|
304
|
+
<Surface
|
|
305
|
+
v-for="c in surfaceColors"
|
|
306
|
+
:key="c"
|
|
307
|
+
variant="soft"
|
|
308
|
+
:color="c"
|
|
309
|
+
class="p-3 flex items-center gap-2"
|
|
310
|
+
>
|
|
311
|
+
<span class="mr-auto text-sm font-medium capitalize">{{ c }}</span>
|
|
312
|
+
<Button variant="outline" size="sm">Outline</Button>
|
|
313
|
+
<Button variant="ghost" size="sm">Ghost</Button>
|
|
314
|
+
<Button variant="link" size="sm">Link</Button>
|
|
315
|
+
</Surface>
|
|
316
|
+
</div>
|
|
317
|
+
`,
|
|
318
|
+
}),
|
|
319
|
+
}
|
|
@@ -4,9 +4,31 @@ import WebLink from '@polymarbot/nuxt-layer-shadcn-ui/app/components/ui/WebLink/
|
|
|
4
4
|
import type { ButtonProps } from './types'
|
|
5
5
|
|
|
6
6
|
const props = defineProps<ButtonProps>()
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
|
|
8
|
+
const variantClasses: Partial<Record<NonNullable<ButtonVariant>, string>> = {
|
|
9
|
+
outline: `
|
|
10
|
+
bg-transparent
|
|
11
|
+
dark:bg-transparent
|
|
12
|
+
border-current/20
|
|
13
|
+
dark:border-current/20
|
|
14
|
+
hover:bg-current/10
|
|
15
|
+
dark:hover:bg-current/10
|
|
16
|
+
hover:text-current
|
|
17
|
+
`,
|
|
18
|
+
ghost: `
|
|
19
|
+
hover:bg-current/10
|
|
20
|
+
dark:hover:bg-current/10
|
|
21
|
+
hover:text-current
|
|
22
|
+
`,
|
|
23
|
+
link: 'text-current',
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const mergedClass = computed(() => cn(
|
|
27
|
+
'cursor-pointer',
|
|
28
|
+
props.variant && variantClasses[props.variant],
|
|
29
|
+
props.rounded && 'rounded-full',
|
|
30
|
+
props.class,
|
|
31
|
+
))
|
|
10
32
|
|
|
11
33
|
const isLink = computed(() => !!props.href || !!props.to)
|
|
12
34
|
const hasIcon = computed(() => !!$slots.icon || !!props.icon)
|
|
@@ -19,6 +41,8 @@ const $slots = defineSlots<{
|
|
|
19
41
|
|
|
20
42
|
<template>
|
|
21
43
|
<ShadcnButton
|
|
44
|
+
:variant="variant"
|
|
45
|
+
:size="size"
|
|
22
46
|
:class="mergedClass"
|
|
23
47
|
:asChild="isLink"
|
|
24
48
|
:type="isLink ? undefined : 'button'"
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { ButtonVariants } from '../../shadcn/button'
|
|
2
2
|
import type { RouteLocationRaw } from 'vue-router'
|
|
3
3
|
|
|
4
|
-
export type ButtonVariant =
|
|
5
|
-
export type ButtonSize =
|
|
4
|
+
export type ButtonVariant = ButtonVariants['variant']
|
|
5
|
+
export type ButtonSize = ButtonVariants['size']
|
|
6
6
|
|
|
7
|
-
export interface ButtonProps
|
|
7
|
+
export interface ButtonProps {
|
|
8
|
+
variant?: ButtonVariant
|
|
9
|
+
size?: ButtonSize
|
|
8
10
|
loading?: boolean
|
|
9
11
|
disabled?: boolean
|
|
10
12
|
rounded?: boolean
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polymarbot/nuxt-layer-shadcn-ui",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "Nuxt layer providing shadcn-vue based UI components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"vue-i18n": "^11",
|
|
43
43
|
"vue-router": "^4 || ^5"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "fc48f5b21d76aa2ff0badd6ac6d9ccc5be906f26"
|
|
46
46
|
}
|