74 lines
1.6 KiB
Vue
74 lines
1.6 KiB
Vue
<template>
|
|
<div
|
|
:class="[
|
|
cn.b(),
|
|
cn.m(type),
|
|
cn.m(size),
|
|
cn.has('title', hasTitle),
|
|
cn.has('action', hasAction),
|
|
]"
|
|
>
|
|
<div :class="[cn.e('content')]">
|
|
<div
|
|
v-if="$slots.title || title"
|
|
:class="[cn.e('title')]"
|
|
>
|
|
<slot name="title">
|
|
{{ title }}
|
|
</slot>
|
|
</div>
|
|
|
|
<div :class="[cn.e('text')]">
|
|
<slot>{{ text }}</slot>
|
|
</div>
|
|
|
|
<slot name="action" />
|
|
</div>
|
|
|
|
<div :class="cn.e('icon')">
|
|
<slot name="icon">
|
|
<Component :is="resolveComponent(`ui-icon-${TYPE_ICON_MAPPING[type]}`)" />
|
|
</slot>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import useClassname from '../../composables/use-classname'
|
|
import type { AlertProps, AlertType } from './types'
|
|
import type { UiIcon } from '#build/types/ui/icons'
|
|
|
|
defineOptions({
|
|
name: 'UiAlert',
|
|
})
|
|
|
|
const props = withDefaults(defineProps<AlertProps>(), {
|
|
type: 'neutral',
|
|
size: 'normal',
|
|
})
|
|
|
|
const slots = defineSlots<{
|
|
default(props: NonNullable<unknown>): never
|
|
title(props: NonNullable<unknown>): never
|
|
action(props: NonNullable<unknown>): never
|
|
}>()
|
|
|
|
const TYPE_ICON_MAPPING: Record<AlertType, UiIcon> = {
|
|
neutral: 'exclamation-filled',
|
|
positive: 'confirmed-filled',
|
|
warning: 'danger-filled',
|
|
negative: 'cancel-filled',
|
|
marketing: 'ask-for-discount-filled',
|
|
}
|
|
|
|
const cn = useClassname('ui-alert')
|
|
|
|
const hasTitle = computed(() => !!props.title || slots.title)
|
|
const hasAction = computed(() => slots.action)
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
@use 'styles';
|
|
</style>
|