refactor: Alert component refactoring (#195)

This commit is contained in:
Ilya Artamonov
2023-09-15 16:20:12 +03:00
committed by GitHub
parent 46c08239c3
commit 34cf4062e8
11 changed files with 329 additions and 364 deletions

View File

@@ -4,36 +4,17 @@ import AlertTitleExample from './alert/examples/AlertTitleExample.vue';
import AlertClosableExample from './alert/examples/AlertClosableExample.vue'; import AlertClosableExample from './alert/examples/AlertClosableExample.vue';
import AlertBorderExample from './alert/examples/AlertBorderExample.vue'; import AlertBorderExample from './alert/examples/AlertBorderExample.vue';
import AlertIconExample from './alert/examples/AlertIconExample.vue'; import AlertIconExample from './alert/examples/AlertIconExample.vue';
import AlertInlineExample from './alert/examples/AlertInlineExample.vue'; import AlertBorderAccentExample from './alert/examples/AlertBorderAccentExample.vue';
import AlertCustomContentExample from './alert/examples/AlertCustomContentExample.vue';
</script> </script>
# Vue Alert - Flowbite # Vue Alert - Flowbite
#### Show contextual information to your users using alert elements based on Tailwind CSS #### Show contextual information to your users using alert elements based on Tailwind CSS
---
:::tip
Original reference: [https://flowbite.com/docs/components/alert/](https://flowbite.com/docs/components/alert/)
:::
The alert component can be used to provide information to your users such as success or error messages, but also highlighted information complementing the normal flow of paragraphs and headers on a page. The alert component can be used to provide information to your users such as success or error messages, but also highlighted information complementing the normal flow of paragraphs and headers on a page.
Flowbite also includes dismissable alerts which can be hidden by the users by clicking on the close icon. ## Default alert
Use the following examples of alert components to show messages as feedback to your users.
## Prop - type
```typescript
export type AlertType = 'info' | 'danger' | 'success' | 'warning' | 'dark'
defineProps({
type: {
type: String as PropType<AlertType>,
default: 'info',
},
})
```
<AlertTypeExample /> <AlertTypeExample />
```vue ```vue
@@ -42,26 +23,76 @@ import { Alert } from 'flowbite-vue'
</script> </script>
<template> <template>
<div class="flex flex-col"> <div class="flex flex-col">
<Alert type="info" class="mb-2">Info</Alert> <Alert type="info" class="mb-2">Info alert! Change a few things up and try submitting again. </Alert>
<Alert type="warning" class="mb-2">Warning</Alert> <Alert type="warning" class="mb-2"> Warning alert! Change a few things up and try submitting again. </Alert>
<Alert type="danger" class="mb-2">Danger</Alert> <Alert type="danger" class="mb-2">Danger alert! Change a few things up and try submitting again. </Alert>
<Alert type="dark" class="mb-2">Dark</Alert> <Alert type="dark" class="mb-2"> Dark alert! Change a few things up and try submitting again. </Alert>
<Alert type="success">Success</Alert> <Alert type="success"> Success alert! Change a few things up and try submitting again. </Alert>
</div>
</template>
```
## Alerts with icon
You can also include a descriptive icon to complement the message inside the alert component with the following example.
<AlertIconExample />
```vue
<script setup>
import { Alert } from 'flowbite-vue'
</script>
<template>
<div class="flex flex-col">
<Alert type="info" class="mb-2" icon> Info alert! Change a few things up and try submitting again. </Alert>
<Alert type="warning" class="mb-2" icon> Warning alert! Change a few things up and try submitting again. </Alert>
<Alert type="danger" class="mb-2" icon> Danger alert! Change a few things up and try submitting again. </Alert>
<Alert type="dark" class="mb-2" icon> Dark alert! Change a few things up and try submitting again. </Alert>
<Alert type="success" icon> Success alert! Change a few things up and try submitting again. </Alert>
</div> </div>
</template> </template>
``` ```
## Prop - title ## Bordered alerts
Use this example to add a border accent to the alert component instead of just a plain background.
```typescript <AlertBorderExample />
defineProps({
title: { ```vue
type: String, <script setup>
default: '', import { Alert } from 'flowbite-vue'
}, </script>
}) <template>
<div class="flex flex-col">
<Alert type="info" border icon class="mb-2">Info alert! Change a few things up and try submitting again. </Alert>
<Alert type="warning" border icon class="mb-2">Warning alert! Change a few things up and try submitting again. </Alert>
<Alert type="danger" border icon class="mb-2"> Info Danger alert! Change a few things up and try submitting again. </Alert>
<Alert type="dark" border icon class="mb-2"> Info Dark alert! Change a few things up and try submitting again. </Alert>
<Alert type="success" border icon>Success alert! Change a few things up and try submitting again. </Alert>
</div>
</template>
``` ```
## Border accent
Use this example to add a border accent on top of the alert component for further visual distinction.
<AlertBorderAccentExample />
```vue
<script setup>
import { Alert } from 'flowbite-vue'
</script>
<template>
<div class="flex flex-col">
<Alert type="info" icon class="mb-2 border-t-4 rounded-none">Info alert! Change a few things up and try submitting again. </Alert>
<Alert type="warning" icon class="mb-2 border-t-4 rounded-none">Warning alert! Change a few things up and try submitting again. </Alert>
<Alert type="danger" icon class="mb-2 border-t-4 rounded-none"> Info Danger alert! Change a few things up and try submitting again. </Alert>
<Alert type="dark" icon class="mb-2 border-t-4 rounded-none"> Info Dark alert! Change a few things up and try submitting again. </Alert>
<Alert type="success" icon class="border-t-4 rounded-none">Success alert! Change a few things up and try submitting again. </Alert>
</div>
</template>
```
## Alerts with list
Use this example to show a list and a description inside an alert component.
<AlertTitleExample /> <AlertTitleExample />
@@ -71,26 +102,28 @@ import { Alert } from 'flowbite-vue'
</script> </script>
<template> <template>
<div class="flex flex-col"> <div class="flex flex-col">
<Alert type="info" title="Some info title" class="mb-2">Info</Alert> <Alert type="info" class="mb-2">
<Alert type="warning" title="Some warning title" class="mb-2">Warning</Alert> <span class="font-medium">Ensure that these requirements are met:</span>
<Alert type="danger" title="Some danger title" class="mb-2">Danger</Alert> <ul class="mt-1.5 ml-4 list-disc list-inside">
<Alert type="dark" title="Some dark title" class="mb-2">Dark</Alert> <li>At least 10 characters (and up to 100 characters)</li>
<Alert type="success" title="Some success title">Success</Alert> <li>At least one lowercase character</li>
<li>Inclusion of at least one special character, e.g., ! @ # ?</li>
</ul>
</Alert>
<Alert type="danger" class="mb-2">
<span class="font-medium">Ensure that these requirements are met:</span>
<ul class="mt-1.5 ml-4 list-disc list-inside">
<li>At least 10 characters (and up to 100 characters)</li>
<li>At least one lowercase character</li>
<li>Inclusion of at least one special character, e.g., ! @ # ?</li>
</ul>
</Alert>
</div> </div>
</template> </template>
``` ```
## Prop - closable ## Dismissing
Use the following alert elements that are also dismissable.
```typescript
defineProps({
closable: {
type: Boolean,
default: false,
},
})
```
<AlertClosableExample /> <AlertClosableExample />
@@ -109,110 +142,74 @@ import { Alert } from 'flowbite-vue'
</template> </template>
``` ```
## Prop - border ## Additional content
The following alert components can be used if you wish to disclose more information inside the element.
```typescript <AlertCustomContentExample />
defineProps({
border: {
type: Boolean,
default: false,
},
})
```
<AlertBorderExample />
```vue ```vue
<script setup> <script setup>
import { Alert } from 'flowbite-vue' import { Alert } from 'flowbite-vue'
</script> </script>
<template> <template>
<div class="flex flex-col"> <Alert type="info">
<Alert type="info" border class="mb-2">Info</Alert> <template #icon>
<Alert type="warning" border class="mb-2">Warning</Alert> <svg class="flex-shrink-0 w-4 h-4 mr-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
<Alert type="danger" border class="mb-2">Danger</Alert> <path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z" />
<Alert type="dark" border class="mb-2">Dark</Alert> </svg>
<Alert type="success" border>Success</Alert> <span class="sr-only">Info</span>
</div> </template>
<template #title>
<h3 class="text-lg font-medium">This is a info alert</h3>
</template>
<template v-slot:default="{ onCloseClick }">
<div class="mt-2 mb-4 text-sm">
More info about this info alert goes here. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.
</div>
<div class="flex">
<button
type="button"
class="text-white bg-blue-800 hover:bg-blue-900 focus:ring-4 focus:outline-none focus:ring-blue-200 font-medium rounded-lg text-xs px-3 py-1.5 mr-2 text-center inline-flex items-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
>
<svg class="-ml-0.5 mr-2 h-3 w-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 14">
<path d="M10 0C4.612 0 0 5.336 0 7c0 1.742 3.546 7 10 7 6.454 0 10-5.258 10-7 0-1.664-4.612-7-10-7Zm0 10a3 3 0 1 1 0-6 3 3 0 0 1 0 6Z" />
</svg>
View more
</button>
<button
type="button"
class="text-blue-800 bg-transparent border border-blue-800 hover:bg-blue-900 hover:text-white focus:ring-4 focus:outline-none focus:ring-blue-200 font-medium rounded-lg text-xs px-3 py-1.5 text-center dark:hover:bg-blue-600 dark:border-blue-600 dark:text-blue-400 dark:hover:text-white dark:focus:ring-blue-800"
data-dismiss-target="#alert-additional-content-1"
aria-label="Close"
@click="onCloseClick"
>
Dismiss
</button>
</div>
</template>
</Alert>
</template> </template>
``` ```
## Prop - icon ## API
```typescript ### Props
defineProps({ | Name | Values | Default |
icon: { |------------|-----------------------------------------------|---------|
type: Boolean, | type | `info`, `danger`, `success`,`warning`, `dark` | `info` |
default: true, | closable | `boolean` | `false` |
}, | icon | `boolean` | `false` |
}) | border | `boolean` | `false` |
```
### Events
| Name | Description |
|----------|----------------------|
| close | Close button pressed |
<AlertIconExample /> ### Slots
| Name | Description |
```vue |------------|-------------------|
<script setup> | default | alert content |
import { Alert } from 'flowbite-vue' | close-icon | custom close icon |
</script> | icon | custom icon |
<template> | title | title content |
<div class="flex flex-col">
<Alert type="info" :icon="false" class="mb-2">Info</Alert>
<Alert title="WARNING" type="warning" :icon="false" class="mb-2">Warning</Alert>
<Alert type="danger" :icon="false" class="mb-2">Danger</Alert>
<Alert type="dark" :icon="false" class="mb-2">Dark</Alert>
<Alert type="success" :icon="false">Success</Alert>
</div>
</template>
```
## Prop - inline
```typescript
defineProps({
inline: {
type: Boolean,
default: true,
},
})
```
<AlertInlineExample />
```vue
<script setup>
import { Alert } from 'flowbite-vue'
</script>
<template>
<div class="flex flex-col">
<Alert type="info" title="Info title" :inline="false" class="mb-2">
Lorem...
</Alert>
<Alert type="warning" title="Warning title" :inline="false" class="mb-2">
Lorem...
</Alert>
<Alert type="danger" title="Danger title" :inline="false" class="mb-2">
Lorem...
</Alert>
<Alert closable type="dark" title="Dark title" :inline="false" class="mb-2">
Lorem...
</Alert>
<Alert type="success" title="Success title" :inline="false">
Lorem...
<template #actions>
<Button size="sm" color="green" class="mr-2">
Buttons everywhere
</Button>
<Button size="sm" outline color="green">
<template #prefix>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 1a1 1 0 000 2h1.22l.305 1.222a.997.997 0 00.01.042l1.358 5.43-.893.892C3.74 11.846 4.632 14 6.414 14H15a1 1 0 000-2H6.414l1-1H14a1 1 0 00.894-.553l3-6A1 1 0 0017 3H6.28l-.31-1.243A1 1 0 005 1H3zM16 16.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM6.5 18a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"></path></svg>
</template>
And here
</Button>
</template>
</Alert>
</div>
</template>
```

View File

@@ -0,0 +1,12 @@
<template>
<div class="vp-raw flex flex-col">
<Alert type="info" icon class="mb-2 border-t-4 rounded-none">Info alert! Change a few things up and try submitting again. </Alert>
<Alert type="warning" icon class="mb-2 border-t-4 rounded-none">Warning alert! Change a few things up and try submitting again. </Alert>
<Alert type="danger" icon class="mb-2 border-t-4 rounded-none"> Info Danger alert! Change a few things up and try submitting again. </Alert>
<Alert type="dark" icon class="mb-2 border-t-4 rounded-none"> Info Dark alert! Change a few things up and try submitting again. </Alert>
<Alert type="success" icon class="border-t-4 rounded-none">Success alert! Change a few things up and try submitting again. </Alert>
</div>
</template>
<script setup>
import { Alert } from '../../../../src/index'
</script>

View File

@@ -1,10 +1,10 @@
<template> <template>
<div class="vp-raw flex flex-col"> <div class="vp-raw flex flex-col">
<Alert type="info" border class="mb-2">Info</Alert> <Alert type="info" border icon class="mb-2">Info alert! Change a few things up and try submitting again. </Alert>
<Alert type="warning" border class="mb-2">Warning</Alert> <Alert type="warning" border icon class="mb-2">Warning alert! Change a few things up and try submitting again. </Alert>
<Alert type="danger" border class="mb-2">Danger</Alert> <Alert type="danger" border icon class="mb-2"> Info Danger alert! Change a few things up and try submitting again. </Alert>
<Alert type="dark" border class="mb-2">Dark</Alert> <Alert type="dark" border icon class="mb-2"> Info Dark alert! Change a few things up and try submitting again. </Alert>
<Alert type="success" border>Success</Alert> <Alert type="success" border icon>Success alert! Change a few things up and try submitting again. </Alert>
</div> </div>
</template> </template>
<script setup> <script setup>

View File

@@ -1,10 +1,10 @@
<template> <template>
<div class="vp-raw flex flex-col"> <div class="vp-raw flex flex-col">
<Alert type="info" closable class="mb-2">Info</Alert> <Alert type="info" closable icon class="mb-2">Info</Alert>
<Alert type="warning" closable class="mb-2">Warning</Alert> <Alert type="warning" closable icon class="mb-2">Warning</Alert>
<Alert type="danger" closable class="mb-2">Danger</Alert> <Alert type="danger" closable icon class="mb-2">Danger</Alert>
<Alert type="dark" closable class="mb-2">Dark</Alert> <Alert type="dark" closable icon class="mb-2">Dark</Alert>
<Alert type="success" closable>Success</Alert> <Alert type="success" closable icon>Success</Alert>
</div> </div>
</template> </template>
<script setup> <script setup>

View File

@@ -0,0 +1,43 @@
<template>
<div class="vp-raw flex flex-col">
<Alert type="info">
<template #icon>
<svg class="flex-shrink-0 w-4 h-4 mr-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z" />
</svg>
<span class="sr-only">Info</span>
</template>
<template #title>
<h3 class="text-lg font-medium">This is a info alert</h3>
</template>
<template v-slot:default="{ onCloseClick }">
<div class="mt-2 mb-4 text-sm">
More info about this info alert goes here. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.
</div>
<div class="flex">
<button
type="button"
class="text-white bg-blue-800 hover:bg-blue-900 focus:ring-4 focus:outline-none focus:ring-blue-200 font-medium rounded-lg text-xs px-3 py-1.5 mr-2 text-center inline-flex items-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
>
<svg class="-ml-0.5 mr-2 h-3 w-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 14">
<path d="M10 0C4.612 0 0 5.336 0 7c0 1.742 3.546 7 10 7 6.454 0 10-5.258 10-7 0-1.664-4.612-7-10-7Zm0 10a3 3 0 1 1 0-6 3 3 0 0 1 0 6Z" />
</svg>
View more
</button>
<button
type="button"
class="text-blue-800 bg-transparent border border-blue-800 hover:bg-blue-900 hover:text-white focus:ring-4 focus:outline-none focus:ring-blue-200 font-medium rounded-lg text-xs px-3 py-1.5 text-center dark:hover:bg-blue-600 dark:border-blue-600 dark:text-blue-400 dark:hover:text-white dark:focus:ring-blue-800"
data-dismiss-target="#alert-additional-content-1"
aria-label="Close"
@click="onCloseClick"
>
Dismiss
</button>
</div>
</template>
</Alert>
</div>
</template>
<script setup>
import { Alert } from '../../../../src/index'
</script>

View File

@@ -1,10 +1,10 @@
<template> <template>
<div class="vp-raw flex flex-col"> <div class="vp-raw flex flex-col">
<Alert type="info" :icon="false" class="mb-2">Info</Alert> <Alert type="info" class="mb-2" icon> Info alert! Change a few things up and try submitting again. </Alert>
<Alert title="WARNING" type="warning" :icon="false" class="mb-2">Warning</Alert> <Alert type="warning" class="mb-2" icon> Warning alert! Change a few things up and try submitting again. </Alert>
<Alert type="danger" :icon="false" class="mb-2">Danger</Alert> <Alert type="danger" class="mb-2" icon> Danger alert! Change a few things up and try submitting again. </Alert>
<Alert type="dark" :icon="false" class="mb-2">Dark</Alert> <Alert type="dark" class="mb-2" icon> Dark alert! Change a few things up and try submitting again. </Alert>
<Alert type="success" :icon="false">Success</Alert> <Alert type="success" icon> Success alert! Change a few things up and try submitting again. </Alert>
</div> </div>
</template> </template>
<script setup> <script setup>

View File

@@ -1,33 +0,0 @@
<template>
<div class="vp-raw flex flex-col">
<Alert type="info" title="Info title" :inline="false" class="mb-2">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Assumenda beatae eaque error est eveniet, facere illo labore libero minima molestiae neque nisi non officia quod sed temporibus unde vitae voluptates.
</Alert>
<Alert type="warning" title="Warning title" :inline="false" class="mb-2">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequatur cupiditate dicta dolore dolores hic sequi tenetur, vero! Blanditiis consequatur culpa nisi ratione repellat! Delectus dolore magni nemo placeat qui sequi.
</Alert>
<Alert type="danger" title="Danger title" :inline="false" class="mb-2">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ab accusamus accusantium atque cupiditate, dignissimos dolorum, error inventore iste libero minus nihil possimus quasi quia quibusdam quisquam recusandae repellat reprehenderit temporibus.
</Alert>
<Alert closable type="dark" title="Dark title" :inline="false" class="mb-2">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. A aperiam dolore et, fuga impedit, iusto nam numquam officiis quas, repellat sapiente sit unde vel? Adipisci delectus dolore eius optio sunt.
</Alert>
<Alert type="success" title="Success title" :inline="false">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias at culpa cupiditate deleniti eos ipsam ipsum, nostrum perspiciatis provident tempore? Aspernatur expedita praesentium voluptatibus. Accusamus explicabo iusto nobis reiciendis temporibus!
<template #actions>
<Button size="sm" color="green" class="mr-2">
Buttons everywhere
</Button>
<Button size="sm" outline color="green">
<template #prefix>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 1a1 1 0 000 2h1.22l.305 1.222a.997.997 0 00.01.042l1.358 5.43-.893.892C3.74 11.846 4.632 14 6.414 14H15a1 1 0 000-2H6.414l1-1H14a1 1 0 00.894-.553l3-6A1 1 0 0017 3H6.28l-.31-1.243A1 1 0 005 1H3zM16 16.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM6.5 18a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"></path></svg>
</template>
And here
</Button>
</template>
</Alert>
</div>
</template>
<script setup>
import { Alert, Button } from '../../../../src/index'
</script>

View File

@@ -1,10 +1,21 @@
<template> <template>
<div class="vp-raw flex flex-col"> <div class="vp-raw flex flex-col">
<Alert type="info" title="Some info title" class="mb-2">Info</Alert> <Alert type="info" class="mb-2">
<Alert type="warning" title="Some warning title" class="mb-2">Warning</Alert> <span class="font-medium">Ensure that these requirements are met:</span>
<Alert type="danger" title="Some danger title" class="mb-2">Danger</Alert> <ul class="mt-1.5 ml-4 list-disc list-inside">
<Alert type="dark" title="Some dark title" class="mb-2">Dark</Alert> <li>At least 10 characters (and up to 100 characters)</li>
<Alert type="success" title="Some success title">Success</Alert> <li>At least one lowercase character</li>
<li>Inclusion of at least one special character, e.g., ! @ # ?</li>
</ul>
</Alert>
<Alert type="danger" class="mb-2">
<span class="font-medium">Ensure that these requirements are met:</span>
<ul class="mt-1.5 ml-4 list-disc list-inside">
<li>At least 10 characters (and up to 100 characters)</li>
<li>At least one lowercase character</li>
<li>Inclusion of at least one special character, e.g., ! @ # ?</li>
</ul>
</Alert>
</div> </div>
</template> </template>
<script setup> <script setup>

View File

@@ -1,10 +1,10 @@
<template> <template>
<div class="vp-raw flex flex-col"> <div class="vp-raw flex flex-col">
<Alert type="info" class="mb-2">Info</Alert> <Alert type="info" class="mb-2">Info alert! Change a few things up and try submitting again. </Alert>
<Alert type="warning" class="mb-2">Warning</Alert> <Alert type="warning" class="mb-2"> Warning alert! Change a few things up and try submitting again. </Alert>
<Alert type="danger" class="mb-2">Danger</Alert> <Alert type="danger" class="mb-2">Danger alert! Change a few things up and try submitting again. </Alert>
<Alert type="dark" class="mb-2">Dark</Alert> <Alert type="dark" class="mb-2"> Dark alert! Change a few things up and try submitting again. </Alert>
<Alert type="success">Success</Alert> <Alert type="success"> Success alert! Change a few things up and try submitting again. </Alert>
</div> </div>
</template> </template>
<script setup> <script setup>

View File

@@ -1,69 +1,110 @@
<template> <template>
<div :class="alertClasses" role="alert" v-if="visible"> <div v-if="visible" v-bind="$attrs" :class="wrapperClasses" role="alert">
<div :class="inline ? 'flex' : 'flex items-center'"> <div class="flex items-center">
<svg v-if="icon" :class="['flex-shrink-0', 'w-5', 'h-5', textClasses]" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path></svg> <slot v-if="icon || $slots.icon" name="icon">
<span <svg class="flex-shrink-0 w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
:class="titleClasses" <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path>
v-if="title" </svg>
> </slot>
{{ title }} <slot name="title"></slot>
</span> </div>
<button type="button" :class="closeClasses" aria-label="Close" @click="onCloseClick" v-if="!inline && closable"> <slot name="default" :on-close-click="onCloseClick" />
<slot name="close-icon" :on-close-click="onCloseClick">
<button v-if="closable" type="button" :class="closeBtnClasses" aria-label="Close" @click="onCloseClick">
<span class="sr-only">Dismiss</span> <span class="sr-only">Dismiss</span>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clip-rule="evenodd"
></path>
</svg>
</button> </button>
</div> </slot>
<div :class="contentClasses">
<slot />
</div>
<div class="inline-flex items-center" v-if="$slots.actions">
<slot name="actions" />
</div>
<button type="button" :class="closeClasses" aria-label="Close" @click="onCloseClick" v-if="inline && closable">
<span class="sr-only">Dismiss</span>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
</button>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import type { PropType } from 'vue' import { ref, useAttrs } from 'vue'
import { useAlertClasses } from './composables/useAlertClasses'
import { ref, toRefs } from 'vue'
import type { AlertType } from './types' import type { AlertType } from './types'
import { twMerge } from 'tailwind-merge'
interface IAlertProps {
const props = defineProps({ type?: AlertType
type: { closable?: boolean
type: String as PropType<AlertType>, icon?: boolean
default: 'info', border?: boolean
}, }
title: { defineOptions({
type: String, inheritAttrs: false,
default: '',
},
closable: {
type: Boolean,
default: false,
},
icon: {
type: Boolean,
default: true,
},
border: {
type: Boolean,
default: false,
},
inline: {
type: Boolean,
default: true,
},
}) })
const props = withDefaults(defineProps<IAlertProps>(), {
type: 'info',
closable: false,
icon: false,
border: false,
})
defineSlots<{
/* eslint-disable @typescript-eslint/no-explicit-any */
default: any
'close-icon': any
icon: any
title: any
/* eslint-enable @typescript-eslint/no-explicit-any */
}>()
const emits = defineEmits<{
(e: 'close'): void
}>()
const { alertClasses, textClasses, closeClasses, contentClasses, titleClasses } = useAlertClasses(toRefs(props)) const attrs = useAttrs()
const alertTextClasses: Record<AlertType, string> = {
danger: 'text-red-800 dark:text-red-400',
dark: 'text-gray-800 dark:text-gray-300',
info: 'text-blue-800 dark:text-blue-400',
success: 'text-green-800 dark:text-green-400',
warning: 'text-yellow-800 dark:text-yellow-300',
}
const alertTypeClasses: Record<AlertType, string> = {
danger: 'bg-red-50',
dark: 'bg-gray-50',
info: 'bg-blue-50',
success: 'bg-green-50',
warning: 'bg-yellow-50',
}
const defaultCloseButtonClasses = 'ml-auto -mr-1.5 -my-1.5 rounded-lg focus:ring-2 p-1.5 inline-flex h-8 w-8 dark:bg-gray-800 dark:hover:bg-gray-700'
const closeButtonClasses: Record<AlertType, string> = {
danger: 'text-red-500 dark:text-red-400 bg-red-50 hover:bg-red-200 focus:ring-red-400',
dark: 'text-gray-500 dark:text-gray-300 bg-gray-50 hover:bg-gray-200 focus:ring-gray-400 dark:hover:text-white',
info: 'text-blue-500 dark:text-blue-400 bg-blue-50 hover:bg-blue-200 focus:ring-blue-400',
success: 'text-green-500 dark:text-green-400 bg-green-50 hover:bg-green-200 focus:ring-green-400',
warning: 'text-yellow-500 dark:text-yellow-300 bg-yellow-50 hover:bg-yellow-200 focus:ring-yellow-400',
}
const closeBtnClasses = twMerge(defaultCloseButtonClasses, closeButtonClasses[props.type])
const borderColor: Record<AlertType, string> = {
danger: 'border-red-500 dark:text-red-400',
dark: 'border-gray-500 dark:text-gray-400',
info: 'border-blue-500 dark:text-blue-400',
success: 'border-green-500 dark:text-green-400',
warning: 'border-yellow-500 dark:text-yellow-400',
}
const colors = {
danger: [alertTextClasses.danger, alertTypeClasses.danger].join(' '),
dark: [alertTextClasses.dark, alertTypeClasses.dark].join(' '),
info: [alertTextClasses.info, alertTypeClasses.info].join(' '),
success: [alertTextClasses.success, alertTypeClasses.success].join(' '),
warning: [alertTextClasses.warning, alertTypeClasses.warning].join(' '),
}
const wrapperClasses = twMerge(
'p-4 gap-3 text-sm dark:bg-gray-800 rounded-lg',
colors[props.type],
(props.icon || props.closable) && 'flex items-center',
borderColor[props.type],
props.border && 'border',
attrs.class as string,
)
const visible = ref(true) const visible = ref(true)
const onCloseClick = () => { function onCloseClick() {
emits('close')
visible.value = false visible.value = false
} }
</script> </script>

View File

@@ -1,106 +0,0 @@
import type { AlertType } from '../types'
import { computed } from 'vue'
import type { Ref } from 'vue'
import classNames from 'classnames'
const defaultAlertClasses = 'p-4 text-sm'
const alertTextClasses: Record<AlertType, string> = {
danger: 'text-red-700 dark:text-red-800',
dark: 'text-gray-700 dark:text-gray-300',
info: 'text-blue-700 dark:text-blue-800',
success: 'text-green-700 dark:text-green-800',
warning: 'text-yellow-700 dark:text-yellow-800',
}
const alertTypeClasses: Record<AlertType, string> = {
danger: 'bg-red-100 dark:bg-red-200',
dark: 'bg-gray-100 dark:bg-gray-700',
info: 'bg-blue-100 dark:bg-blue-200',
success: 'bg-green-100 dark:bg-green-200',
warning: 'bg-yellow-100 dark:bg-yellow-200',
}
const alertBorderClasses: Record<AlertType, string> = {
danger: 'border-t-4 border-red-500',
dark: 'border-t-4 border-gray-500',
info: 'border-t-4 border-blue-500',
success: 'border-t-4 border-green-500',
warning: 'border-t-4 border-yellow-500',
}
const defaultCloseButtonClasses = 'ml-auto -mx-1.5 -my-1.5 rounded-lg focus:ring-2 p-1.5 inline-flex h-8 w-8'
const closeButtonClasses: Record<AlertType, string> = {
danger: 'hover:bg-red-200 dark:hover:bg-red-300 focus:ring-red-400 bg-red-100 dark:bg-red-200 text-red-500',
dark: 'dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-white hover:bg-gray-200 focus:ring-gray-400 bg-gray-100 text-gray-500',
info: 'hover:bg-blue-200 dark:hover:bg-blue-300 focus:ring-blue-400 bg-blue-100 dark:bg-blue-200 text-blue-500',
success: 'bg-green-100 dark:bg-green-200 text-green-500 focus:ring-green-400 hover:bg-green-200 dark:hover:bg-green-300',
warning: 'focus:ring-yellow-400 hover:bg-yellow-200 dark:hover:bg-yellow-300 bg-yellow-100 dark:bg-yellow-200 text-yellow-500',
}
export type UseAlertClassesProps = {
type: Ref<AlertType>
border: Ref<boolean>
icon: Ref<boolean>
inline: Ref<boolean>
title: Ref<string>
}
export function useAlertClasses(props: UseAlertClassesProps): {
alertClasses: Ref<string>,
textClasses: Ref<string>,
closeClasses: Ref<string>,
contentClasses: Ref<string>,
titleClasses: Ref<string>,
} {
const alertClasses = computed<string>(() => {
return classNames(
defaultAlertClasses,
alertTypeClasses[props.type.value],
textClasses.value,
props.border.value ? alertBorderClasses[props.type.value] : 'rounded-lg', // rounded only if no border
props.inline.value ? 'flex' : '',
)
})
const textClasses = computed<string>(() => {
return classNames(
alertTextClasses[props.type.value],
)
})
const closeClasses = computed<string>(() => {
return classNames(
defaultCloseButtonClasses,
closeButtonClasses[props.type.value],
)
})
const contentClasses = computed<string>(() => {
if(!props.inline.value) return classNames('mt-2 mb-4')
if(!props.icon.value && !props.title.value) return ''
return classNames(!props.title.value ? 'ml-3' : 'ml-1')
})
const titleClasses = computed<string>(() => {
if(!props.icon.value || !props.inline.value) return classNames(
'font-medium',
!props.inline.value ? 'text-lg ml-2' : '',
)
return classNames(
'font-medium ml-3',
!props.inline.value ? 'text-lg' : '',
)
})
return {
alertClasses,
textClasses,
closeClasses,
contentClasses,
titleClasses,
}
}