refactor(notification): new theme

This commit is contained in:
07akioni 2021-01-06 10:51:36 +08:00
parent 7b2f77a573
commit dbb683cba6
12 changed files with 312 additions and 313 deletions

View File

@ -81,10 +81,12 @@ export default defineComponent({
type: Boolean,
default: false
},
// eslint-disable-next-line vue/prop-name-casing
'onUpdate:expandedKeys': {
type: Function,
default: () => {}
},
// eslint-disable-next-line vue/prop-name-casing
'onUpdate:value': {
type: Function,
default: () => {}

View File

@ -1,12 +1,11 @@
<template>
<div
:class="{
[`n-${mergedTheme}-theme`]: mergedTheme,
'n-notification--closable': closable,
'n-notification--show-avatar': showAvatar,
[`n-notification--${type}-type`]: type
'n-notification--show-avatar': showAvatar
}"
class="n-notification"
:style="cssVars"
>
<div v-if="showAvatar" class="n-notification__avatar">
<render v-if="avatar" :render="avatar" />
@ -50,9 +49,9 @@
</template>
<script>
import { configurable, themeable, withCssr } from '../../_mixins'
import { render } from '../../_utils'
import styles from './styles'
import { defineComponent, computed } from 'vue'
import { useTheme } from '../../_mixins'
import { createKey, render } from '../../_utils'
import { NIcon } from '../../icon'
import {
CloseIcon,
@ -61,8 +60,10 @@ import {
WarningIcon,
ErrorIcon
} from '../../_base/icons'
import { notificationLight } from '../styles'
import style from './styles/index.cssr.js'
export default {
export default defineComponent({
name: 'Notification',
components: {
NIcon,
@ -73,7 +74,6 @@ export default {
InfoIcon,
ErrorIcon
},
mixins: [configurable, themeable, withCssr(styles)],
props: {
closable: {
type: Boolean,
@ -116,15 +116,67 @@ export default {
required: true
}
},
computed: {
showAvatar () {
return this.avatar || this.type !== 'default'
}
},
methods: {
handleCloseClick () {
this.onClose()
setup (props) {
const themeRef = useTheme(
'Notification',
'Notification',
style,
notificationLight,
props
)
return {
showAvatar: computed(() => {
return props.avatar || props.type !== 'default'
}),
handleCloseClick () {
this.onClose()
},
cssVars: computed(() => {
const { type } = props
const {
self: {
color,
textColor,
closeColor,
closeColorHover,
closeColorPressed,
headerTextColor,
descriptionTextColor,
actionTextColor,
borderRadius,
headerFontWeight,
boxShadow,
lineHeight,
fontSize,
[createKey('iconColor', type)]: iconColor
},
common: {
cubicBezierEaseOut,
cubicBezierEaseIn,
cubicBezierEaseInOut
}
} = themeRef.value
return {
'--color': color,
'--font-size': fontSize,
'--text-color': textColor,
'--description-text-color': descriptionTextColor,
'--action-text-color': actionTextColor,
'--title-text-color': headerTextColor,
'--title-font-weight': headerFontWeight,
'--bezier': cubicBezierEaseInOut,
'--bezier-ease-out': cubicBezierEaseOut,
'--bezier-ease-in': cubicBezierEaseIn,
'--border-radius': borderRadius,
'--box-shadow': boxShadow,
'--close-color': closeColor,
'--close-color-hover': closeColorHover,
'--close-color-pressed': closeColorPressed,
'--line-height': lineHeight,
'--icon-color': iconColor
}
})
}
}
}
})
</script>

View File

@ -13,9 +13,10 @@
</template>
<script>
import { defineComponent } from 'vue'
import { NScrollbar } from '../../scrollbar'
export default {
export default defineComponent({
name: 'NotificationContainer',
components: {
NScrollbar
@ -26,5 +27,5 @@ export default {
required: true
}
}
}
})
</script>

View File

@ -1,7 +1,7 @@
import { nextTick, Transition, h } from 'vue'
import { nextTick, Transition, h, defineComponent } from 'vue'
import NNotification from './Notification.vue'
export default {
export default defineComponent({
name: 'NotificationEnvironment',
props: {
duration: {
@ -171,4 +171,4 @@ export default {
}
)
}
}
})

View File

@ -1,10 +1,10 @@
import { Fragment, h, reactive, ref, Teleport } from 'vue'
import { Fragment, h, reactive, ref, Teleport, defineComponent } from 'vue'
import { createId } from 'seemly'
import { omit } from '../../_utils'
import NotificationContainer from './NotificationContainer.vue'
import NotificationEnvironment from './NotificationEnvironment'
export default {
export default defineComponent({
name: 'NotificationProvider',
provide () {
return {
@ -94,4 +94,4 @@ export default {
this.$slots.default()
])
}
}
})

View File

@ -0,0 +1,208 @@
import { c, cB, cE, cM } from '../../../_utils/cssr'
// vars:
// --color
// --text-color
// --description-text-color
// --action-text-color
// --title-text-color
// --title-font-weight
// --bezier
// --bezier-ease-out
// --bezier-ease-in
// --border-radius
// --box-shadow
// --close-color
// --close-color-hover
// --close-color-pressed
// --line-height
// --icon-color
export default c([
cB('notification-container', `
z-index: 4000;
position: fixed;
top: 12px;
left: 0;
right: 0;
height: 0;
overflow: visible;
display: flex;
flex-direction: column;
align-items: flex-end;
`, [
c('>', [
cB('scrollbar', `
overflow: visible;
height: -moz-fit-content !important;
height: fit-content !important;
max-height: 100vh !important;
`, [
c('>', [
cB('scrollbar-container', `
height: -moz-fit-content !important;
height: fit-content !important;
max-height: 100vh !important;
`, [
cB('scrollbar-content', `
padding-top: 12px;
padding-bottom: 33px;
`)
])
])
])
]),
cM('scrollable', {
top: 0
}),
cB('notification', [
c('&-transition-enter-from, &-transition-leave-to', `
opacity: 0;
margin-bottom: 0 !important;
transform: translateX(calc(100% + 16px));
`),
c('&-transition-leave-from, &-transition-enter-to', `
opacity: 1;
transform: translateX(0);
`),
c('&-transition-leave-active', `
transition:
background-color .3s var(--bezier),
color .3s var(--bezier),
opacity .3s var(--bezier),
transform .3s var(--bezier-ease-in),
max-height .3s var(--bezier),
margin-bottom .3s linear,
box-shadow .3s var(--bezier);
`)
]),
cB('notification', `
background-color: var(--color);
color: var(--text-color);
transition:
background-color .3s var(--bezier),
color .3s var(--bezier),
opacity .3s var(--bezier),
transform .3s var(--bezier-ease-out),
max-height .3s var(--bezier),
margin-bottom .3s linear,
box-shadow .3s var(--bezier);
font-family: inherit;
font-size: var(--font-size);
font-weight: 400;
position: relative;
display: flex;
overflow: hidden;
flex-shrink: 0;
margin-bottom: 12px;
margin-left: 28px;
margin-right: 16px;
padding-left: 16px;
padding-right: 16px;
width: 365px;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
box-sizing: border-box;
opacity: 1;
`, [
// TODO: refactor type styles & transition
cE('avatar', [
cB('icon', {
color: 'var(--icon-color)'
})
]),
cM('show-avatar', [
cB('notification-main', `
margin-left: 40px;
width: calc(100% - 40px);
`)
]),
cM('closable', [
cB('notification-main', [
c('> *:first-child', {
paddingRight: '20px'
})
]),
cE('close', `
position: absolute;
top: 16px;
right: 12px;
font-size: 14px;
cursor: pointer;
transition: color .3s var(--bezier);
color: var(--close-color);
`, [
c('&:hover', {
color: 'var(--close-color-hover)'
}),
c('&:active', {
color: 'var(--close-color-pressed)'
})
])
]),
cE('avatar', `
position: absolute;
top: 16px;
left: 16px;
width: 28px;
height: 28px;
font-size: 28px;
`, [
cB('icon', {
transition: 'color .3s var(--bezier)'
})
]),
cB('notification-main', `
padding-top: 16px;
padding-bottom: 16px;
box-sizing: border-box;
display: flex;
flex-direction: column;
margin-left: 8px;
width: calc(100% - 8px);
`, [
cB('notification-main-footer', `
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 12px;
`, [
cE('meta', `
font-size: 12px;
transition: color .3s var(--bezier-ease-out);
color: var(--description-text-color);
`),
cE('action', `
cursor: pointer;
transition: color .3s var(--bezier-ease-out);
color: var(--action-text-color);
`)
]),
cE('header', `
font-weight: var(--title-font-weight);
font-size: 16px;
transition: color .3s var(--bezier-ease-out);
color: var(--title-text-color);
`),
cE('description', `
margin-top: 8px;
font-size: 12px;
transition: color .3s var(--bezier-ease-out);
color: var(--description-text-color);
`),
cE('content', `
line-height: var(--line-height);
margin: 12px 0 0 0;
font-family: inherit;
white-space: pre-wrap;
word-wrap: break-word;
transition: color .3s var(--bezier-ease-out);
color: var(--text-color);
`, [
c('&:first-child', {
margin: 0
})
])
])
])
])
])

View File

@ -1,9 +0,0 @@
import baseStyle from './themed-base.cssr.js'
export default [
{
key: 'mergedTheme',
watch: ['mergedTheme'],
CNode: baseStyle
}
]

View File

@ -1,261 +0,0 @@
import { cTB, c, cB, cE, cM, createKey } from '../../../_utils/cssr'
function typeStyle (type, color) {
return cM(`${type}-type`, [
cE('avatar', [
cB('icon', {
color
})
])
])
}
export default c([
cB('notification-container', {
raw: `
z-index: 4000;
position: fixed;
top: 12px;
left: 0;
right: 0;
height: 0;
overflow: visible;
display: flex;
flex-direction: column;
align-items: flex-end;
`
}, [
c('>', [
cB('scrollbar', {
raw: `
overflow: visible;
height: -moz-fit-content !important;
height: fit-content !important;
max-height: 100vh !important;
`
}, [
c('>', [
cB('scrollbar-container', {
raw: `
height: -moz-fit-content !important;
height: fit-content !important;
max-height: 100vh !important;
`
}, [
cB('scrollbar-content', {
raw: `
padding-top: 12px;
padding-bottom: 33px;
`
})
])
])
])
]),
cM('scrollable', {
top: 0
})
]),
({ props }) => {
const {
$local: {
color,
textColor,
closeColor,
closeColorHover,
closeColorPressed,
headerTextColor,
contentTextColor,
descriptionTextColor,
actionTextColor,
borderRadius,
headerFontWeight,
boxShadow,
lineHeight,
fontSize
},
$global: {
cubicBezierEaseOut,
cubicBezierEaseIn,
cubicBezierEaseInOut
}
} = props
return [
cB('notification', [
c('&-transition-enter-from, &-transition-leave-to', {
raw: `
opacity: 0;
margin-bottom: 0 !important;
transform: translateX(calc(100% + 16px));
`
}),
c('&-transition-leave-from, &-transition-enter-to', {
raw: `
opacity: 1;
transform: translateX(0);
`
}),
c('&-transition-leave-active', {
raw: `
transition:
background-color .3s ${cubicBezierEaseInOut},
color .3s ${cubicBezierEaseInOut},
opacity .3s ${cubicBezierEaseInOut},
transform .3s ${cubicBezierEaseIn},
max-height .3s ${cubicBezierEaseInOut},
margin-bottom .3s linear,
box-shadow .3s ${cubicBezierEaseInOut};
`
})
]),
cTB('notification', {
raw: `
background-color: ${color};
color: ${textColor};
transition:
background-color .3s ${cubicBezierEaseInOut},
color .3s ${cubicBezierEaseInOut},
opacity .3s ${cubicBezierEaseInOut},
transform .3s ${cubicBezierEaseOut},
max-height .3s ${cubicBezierEaseInOut},
margin-bottom .3s linear,
box-shadow .3s ${cubicBezierEaseInOut};
font-family: inherit;
font-size: ${fontSize};
font-weight: 400;
position: relative;
display: flex;
overflow: hidden;
flex-shrink: 0;
margin-bottom: 12px;
margin-left: 28px;
margin-right: 16px;
padding-left: 16px;
padding-right: 16px;
width: 365px;
border-radius: ${borderRadius};
box-shadow: ${boxShadow};
box-sizing: border-box;
opacity: 1;
`
}, [
// TODO: refactor type styles & transition
['success', 'info', 'warning', 'error', 'default']
.map(type => typeStyle(type, props.$local[createKey('iconColor', type)])),
cM('show-avatar', [
cB('notification-main', {
raw: `
margin-left: 40px;
width: calc(100% - 40px);
`
})
]),
cM('closable', [
cB('notification-main', [
c('> *:first-child', {
paddingRight: '20px'
})
]),
cE('close', {
raw: `
position: absolute;
top: 16px;
right: 12px;
font-size: 14px;
cursor: pointer;
transition: color .3s ${cubicBezierEaseInOut};
color: ${closeColor};
`
}, [
c('&:hover', {
color: closeColorHover
}),
c('&:active', {
color: closeColorPressed
})
])
]),
cE('avatar', {
raw: `
position: absolute;
top: 16px;
left: 16px;
width: 28px;
height: 28px;
font-size: 28px;
`
}, [
cB('icon', {
transition: `color .3s ${cubicBezierEaseInOut}`
})
]),
cB('notification-main', {
raw: `
padding-top: 16px;
padding-bottom: 16px;
box-sizing: border-box;
display: flex;
flex-direction: column;
margin-left: 8px;
width: calc(100% - 8px);
`
}, [
cB('notification-main-footer', {
raw: `
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 12px;
`
}, [
cE('meta', {
raw: `
font-size: 12px;
transition: color .3s ${cubicBezierEaseOut};
color: ${descriptionTextColor};
`
}),
cE('action', {
raw: `
cursor: pointer;
transition: color .3s ${cubicBezierEaseOut};
color: ${actionTextColor};
`
})
]),
cE('header', {
raw: `
font-weight: ${headerFontWeight};
font-size: 16px;
transition: color .3s ${cubicBezierEaseOut};
color: ${headerTextColor};
`
}),
cE('description', {
raw: `
margin-top: 8px;
font-size: 12px;
transition: color .3s ${cubicBezierEaseOut};
color: ${descriptionTextColor};
`
}),
cE('content', {
raw: `
line-height: ${lineHeight};
margin: 12px 0 0 0;
font-family: inherit;
white-space: pre-wrap;
word-wrap: break-word;
transition: color .3s ${cubicBezierEaseOut};
color: ${contentTextColor};
`
}, [
c('&:first-child', {
margin: 0
})
])
])
])
]
}
])

View File

@ -1,14 +1,17 @@
import create from '../../_styles/utils/create-component-base'
import { baseDark } from '../../_styles/base'
import { avatarDark } from '../../avatar/styles'
import { scrollbarDark } from '../../scrollbar/styles'
import { iconDark } from '../../icon/styles'
import { commonDark } from '../../_styles/new-common'
export default create({
export default {
name: 'Notification',
theme: 'dark',
peer: [baseDark, iconDark, avatarDark, scrollbarDark],
getLocalVars (vars) {
common: commonDark,
peers: {
Icon: iconDark,
Avatar: avatarDark,
Scrollbar: scrollbarDark
},
self (vars) {
const {
textColor2Overlay,
successColor,
@ -41,10 +44,9 @@ export default create({
closeColorHover: closeColorHoverOverlay,
closeColorPressed: closeColorOverlay,
headerTextColor: textColor1Overlay,
contentTextColor: textColor2Overlay,
descriptionTextColor: textColor3Overlay,
actionTextColor: textColor2Overlay,
boxShadow: boxShadow2
}
}
})
}

View File

@ -1,14 +1,17 @@
import create from '../../_styles/utils/create-component-base'
import { baseLight } from '../../_styles/base'
import { avatarLight } from '../../avatar/styles'
import { scrollbarLight } from '../../scrollbar/styles'
import { iconLight } from '../../icon/styles'
import { commonLight } from '../../_styles/new-common'
export default create({
export default {
name: 'Notification',
theme: 'light',
peer: [baseLight, iconLight, avatarLight, scrollbarLight],
getLocalVars (vars) {
common: commonLight,
peers: {
Icon: iconLight,
Avatar: avatarLight,
Scrollbar: scrollbarLight
},
self (vars) {
const {
textColor2,
successColor,
@ -41,10 +44,9 @@ export default create({
closeColorHover: closeColorHover,
closeColorPressed: closeColor,
headerTextColor: textColor1Overlay,
contentTextColor: textColor2,
descriptionTextColor: textColor3Overlay,
actionTextColor: textColor2,
boxShadow: boxShadow2
}
}
})
}

View File

@ -55,7 +55,7 @@ export { baseDark, baseLight } from './_styles/base'
// export { menuDark, menuLight } from './menu/styles'
// export { messageDark, messageLight } from './message/styles'
// export { modalDark, modalLight } from './modal/styles'
export { notificationDark, notificationLight } from './notification/styles'
// export { notificationDark, notificationLight } from './notification/styles'
export { paginationDark, paginationLight } from './pagination/styles'
export { popconfirmDark, popconfirmLight } from './popconfirm/styles'
export { popoverDark, popoverLight } from './popover/styles'

View File

@ -37,6 +37,7 @@ import { logDark } from './log/styles'
import { menuDark } from './menu/styles'
import { messageDark } from './message/styles'
import { modalDark } from './modal/styles'
import { notificationDark } from './notification/styles'
export const darkTheme = {
common: commonDark,
@ -77,5 +78,6 @@ export const darkTheme = {
Log: logDark,
Menu: menuDark,
Message: messageDark,
Modal: modalDark
Modal: modalDark,
Notification: notificationDark
}