sakura/src/components/messages/MessageNormal.vue

229 lines
6.5 KiB
Vue
Raw Normal View History

2021-07-18 19:52:09 +08:00
<template>
2021-07-29 00:01:45 +08:00
<div class="item__container mdc-card mdc-card--outlined" :type="$props.message.type">
2021-07-18 19:52:09 +08:00
<div class="item__content">
2021-07-29 00:01:45 +08:00
<div class="flex-box">
<div class="column__wrapper--icon">
<span><i :class="icon"></i></span>
</div>
<div class="column__wrapper--content">
<div class="row__wrapper--title">
<div class="title__content--message">
<div class="title">
<span>{{ $props.message.title }}</span>
</div>
2021-07-18 19:52:09 +08:00
</div>
<div
2021-07-29 00:01:45 +08:00
v-if="$props.message.detail"
:class="['title__content--collapse', { reverse: shouldShowDetail }]"
:title="msg.showDetails"
@click="handleShowDetailClick"
2021-07-18 19:52:09 +08:00
>
2021-07-29 00:01:45 +08:00
<i class="fas fa-angle-double-down"></i>
</div>
<div class="title__content--close" :title="msg.close" @click="handleCloseMessageEvent">
<i class="fas fa-times-circle"></i>
2021-07-18 19:52:09 +08:00
</div>
</div>
2021-07-29 17:41:40 +08:00
<div class="row__wrapper--detail">
<div
class="detailed"
:style="{ maxHeight: shouldShowDetail ? `${expandContentHeight}px` : '0px' }"
>
<div class="content" :ref="setExpandContentRef">
<span>{{ $props.message.detail }}</span>
</div>
</div>
</div>
2021-07-18 19:52:09 +08:00
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue'
import { useIntl, useInjector, useState, useElementRef, useResizeObserver } from '@/hooks'
import { messages } from '@/store'
import NormalButton from '@/components/buttons/NormalButton.vue'
export default defineComponent({
components: { NormalButton },
props: { message: Object },
setup(props) {
const intl = useIntl()
const msg = {
dismiss: intl.formatMessage({
id: 'messages.popup.dismiss',
defaultMessage: 'Dismiss',
}),
close: intl.formatMessage({
id: 'messages.popup.close',
defaultMessage: 'Close',
}),
showDetails: intl.formatMessage({
id: 'messages.popup.showDetails',
defaultMessage: 'Show details',
}),
}
2021-07-29 00:01:45 +08:00
const icon = computed(() => {
switch (props.message?.type) {
case 'success':
return 'fas fa-check-circle'
case 'warning':
return 'fas fa-exclamation-circle'
case 'info':
return 'fas fa-info-circle'
case 'error':
return 'fas fa-exclamation-triangle'
default:
return 'fas fa-info-circle'
}
})
2021-07-18 19:52:09 +08:00
const { messageList, removeMessage } = useInjector(messages)
const handleCloseMessageEvent = () => {
if (props.message) removeMessage(messageList, props.message.id)
}
const [shouldShowDetail, setShouldShowDetail] = useState(false)
const handleShowDetailClick = () => {
setShouldShowDetail(!shouldShowDetail.value)
}
const [expandContentRef, setExpandContentRef] = useElementRef()
const expandContentSize = useResizeObserver(expandContentRef)
const expandContentHeight = computed(() =>
isNaN(expandContentSize.value.height)
2021-07-18 19:52:09 +08:00
? 0
: expandContentSize.value.height + expandContentSize.value.paddingTop
)
return {
msg,
2021-07-29 00:01:45 +08:00
icon,
2021-07-18 19:52:09 +08:00
handleCloseMessageEvent,
shouldShowDetail,
handleShowDetailClick,
setExpandContentRef,
expandContentHeight,
}
},
})
</script>
<style lang="scss" scoped>
@use "sass:color";
2021-07-29 00:01:45 +08:00
@use '@/styles/mixins/polyfills';
2021-07-29 17:41:40 +08:00
@use '@/styles/mixins/text';
2021-07-18 19:52:09 +08:00
.item__container {
2021-07-29 00:01:45 +08:00
--text-color: #3c434a;
--text-color-lighter-30: color.adjust(#3c434a, $lightness: 30%);
--background-color: #ffffff;
&[type='success'] {
--highlight-color: #00b74a;
}
&[type='warning'] {
--highlight-color: #ffa900;
}
&[type='info'] {
--highlight-color: #39c0ed;
}
&[type='error'] {
--highlight-color: #f93154; // danger
}
2021-07-29 17:41:40 +08:00
width: var(--msg-width);
2021-07-29 00:01:45 +08:00
background: var(--background-color);
border-left: 3px solid var(--highlight-color, #757575);
2021-07-18 19:52:09 +08:00
> .item__content {
width: calc(100% - 24px);
padding: 12px;
2021-07-29 00:01:45 +08:00
> .flex-box {
2021-07-29 17:41:40 +08:00
width: 100%;
2021-07-29 00:01:45 +08:00
display: flex;
flex-flow: row nowrap;
align-items: space-between;
align-items: flex-start;
@include polyfills.flex-gap(12px, 'row nowrap');
> .column__wrapper {
&--icon {
flex: 0 0 auto;
span {
color: var(--highlight-color, #757575);
font-size: medium;
}
2021-07-18 19:52:09 +08:00
}
2021-07-29 00:01:45 +08:00
&--content {
flex: 1 1 auto;
width: 100%;
display: flex;
flex-flow: column nowrap;
align-items: flex-start;
2021-07-29 17:41:40 +08:00
// overflow-wrap: anywhere;
2021-07-29 00:01:45 +08:00
> .row__wrapper {
&--title {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: flex-start;
@include polyfills.flex-gap(12px, 'row nowrap');
2021-07-29 17:41:40 +08:00
width: calc(100% + 12px);
2021-07-29 00:01:45 +08:00
> * span {
line-height: 16px;
2021-07-29 17:41:40 +08:00
@include text.word-break;
2021-07-29 00:01:45 +08:00
}
> .title__content {
&--message {
flex: 1 1 auto;
width: 100%;
> .title {
2021-07-18 19:52:09 +08:00
span {
2021-07-29 00:01:45 +08:00
color: var(--text-color);
}
}
2021-07-18 19:52:09 +08:00
}
2021-07-29 00:01:45 +08:00
&--collapse {
flex: 0 0 auto;
transform: scaleY(1);
transition: transform 0.5s cubic-bezier(0, 0, 0.3, 1);
2021-07-29 17:41:40 +08:00
cursor: pointer;
2021-07-29 00:01:45 +08:00
&.reverse {
transform: scaleY(-1);
}
}
&--close {
flex: 0 0 auto;
2021-07-29 17:41:40 +08:00
cursor: pointer;
margin-right: 0;
}
}
}
&--detail {
> .detailed {
width: 100%;
max-height: 0;
transition: max-height 0.3s ease-in-out;
overflow: hidden;
> .content {
padding-top: 6px;
width: 100%;
span {
color: var(--text-color-lighter-30);
@include text.word-break;
}
2021-07-18 19:52:09 +08:00
}
}
}
2021-07-29 00:01:45 +08:00
&--buttons {
align-self: flex-end;
}
2021-07-18 19:52:09 +08:00
}
}
}
}
}
}
</style>