0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-25 02:31:59 -05:00

Portal notifications style (#103)

- Updated notification style for a less opinionated design so that it works better with any accent color
- Changed full width notificaiton style to smaller to avoid covering navigation
This commit is contained in:
Peter Zimon 2020-10-01 13:59:32 +02:00 committed by GitHub
parent b414e3b7e4
commit cf4736d2df
8 changed files with 127 additions and 72 deletions

View file

@ -16,7 +16,7 @@ const DEV_MODE_DATA = {
showPopup: true,
site: Fixtures.site,
member: Fixtures.member.paid,
page: 'signup'
page: 'accountHome'
};
export default class App extends React.Component {
constructor(props) {

View file

@ -549,6 +549,16 @@ const MobileStyles = `
animation: popup-mobile 0.25s ease-in-out;
}
.gh-portal-popup-container.account-home {
background: var(--grey13);
}
.gh-portal-popup-container.account-home .gh-portal-account-footer {
border-top: none;
padding-top: 0;
height: unset;
}
.gh-portal-content {
overflow-y: auto !important;
max-height: unset !important;
@ -655,7 +665,7 @@ const MobileStyles = `
}
.gh-portal-account-main {
padding: 24px;
padding: 24px 24px 0;
}
}

View file

@ -2,6 +2,8 @@ import Frame from './Frame';
import AppContext from '../AppContext';
import NotificationStyle from './Notification.styles';
import {ReactComponent as CloseIcon} from '../images/icons/close.svg';
import {ReactComponent as CheckmarkIcon} from '../images/icons/checkmark-fill.svg';
import {ReactComponent as WarningIcon} from '../images/icons/warning-fill.svg';
import NotificationParser, {clearURLParams} from '../utils/notifications';
import {getPortalLink} from '../utils/helpers';
@ -12,11 +14,11 @@ const Styles = () => {
frame: {
zIndex: '4000000',
position: 'fixed',
top: '0px',
top: '0',
right: '0',
left: '0',
maxWidth: '415px',
width: '100%',
height: '80px',
height: '120px',
animation: '250ms ease 0s 1 normal none running animation-bhegco',
transition: 'opacity 0.3s ease 0s',
overflow: 'hidden'
@ -42,7 +44,7 @@ const NotificationText = ({type, status, context}) => {
} else if (type === 'signup' && status === 'success') {
return (
<p>
You've successfully subscribed to {context.site.title}
You've successfully subscribed to <strong>{context.site.title}</strong>
</p>
);
} else if (type === 'signup' && status === 'error') {
@ -128,7 +130,7 @@ class NotificationContent extends React.Component {
}
onAnimationEnd(e) {
if (e.animationName === 'notification-slideout') {
if (e.animationName === 'notification-slideout' || e.animationName === 'notification-slideout-mobile') {
this.props.onHideNotification(e);
}
}
@ -141,6 +143,7 @@ class NotificationContent extends React.Component {
return (
<div className='gh-portal-notification-wrapper'>
<div className={`gh-portal-notification${statusClass}${slideClass}`} onAnimationEnd={e => this.onAnimationEnd(e)}>
{(status === 'error' ? <WarningIcon className='gh-portal-notification-icon error' alt=''/> : <CheckmarkIcon className='gh-portal-notification-icon success' alt=''/>)}
<NotificationText type={type} status={status} context={this.context} />
<CloseIcon className='gh-portal-notification-closeicon' alt='Close' onClick={e => this.onNotificationClose(e)} />
</div>

View file

@ -2,24 +2,28 @@ import {GlobalStyles} from './Global.styles';
const NotificationStyles = `
.gh-portal-notification-wrapper {
display: flex;
flex-direction: column;
align-items: stretch;
padding: 12px;
position: relative;
overflow: hidden;
height: 100%;
width: 100%;
}
.gh-portal-notification {
position: relative;
position: absolute;
top: 12px;
right: 12px;
width: 100%;
padding: 12px 44px;
max-width: 100%;
font-size: 1.4rem;
padding: 10px 44px 12px 20px;
max-width: 380px;
min-height: 66px;
font-size: 1.3rem;
letter-spacing: 0.2px;
background: var(--grey1);
background: rgba(33,33,33,0.95);
backdrop-filter: blur(8px);
color: var(--white);
border-radius: 5px;
box-shadow: 0 3.2px 3.6px rgba(0, 0, 0, 0.024), 0 8.8px 10px -5px rgba(0, 0, 0, 0.08);
animation: notification-slidein 0.6s ease-in-out;
animation: notification-slidein 0.7s ease-in-out;
}
.gh-portal-notification.slideout {
@ -32,9 +36,15 @@ const NotificationStyles = `
.gh-portal-notification p {
flex-grow: 1;
text-align: center;
font-size: 1.4rem;
text-align: left;
margin: 0;
padding: 0;
padding: 0 0 0 40px;
color: var(--grey13);
}
.gh-portal-notification p strong {
color: var(--white);
}
.gh-portal-notification a {
@ -48,6 +58,22 @@ const NotificationStyles = `
opacity: 0.8;
}
.gh-portal-notification-icon {
position: absolute;
top: 17px;
left: 17px;
width: 28px;
height: 28px;
}
.gh-portal-notification-icon.success {
color: var(--green);
}
.gh-portal-notification-icon.error {
color: #FF2828;
}
.gh-portal-notification-closeicon {
position: absolute;
top: 5px;
@ -55,52 +81,51 @@ const NotificationStyles = `
right: 5px;
color: var(--white);
cursor: pointer;
width: 14px;
height: 14px;
padding: 12px;
width: 12px;
height: 12px;
padding: 10px;
transition: all 0.2s ease-in-out forwards;
opacity: 0.8;
}
.gh-portal-notification-closeicon:hover {
opacity: 1.0;
}
.gh-portal-notification.success {
background: var(--green);
}
.gh-portal-notification.warning {
background: var(--yellow);
color: var(--grey1);
}
.gh-portal-notification.warning a {
color: var(--grey1);
}
.gh-portal-notification.warning .gh-portal-notification-closeicon {
color: var(--grey1);
}
.gh-portal-notification.error {
background: var(--red);
}
.gh-portal-notification.branded {
background: var(--brandcolor);
}
}
@keyframes notification-slidein {
0% { transform: translateY(-100px); }
60% { transform: translateY(8px); }
100% { transform: translateY(0); }
0% { transform: translateX(380px); }
75% { transform: translateX(-8px); }
100% { transform: translateX(0); }
}
@keyframes notification-slideout {
0% { transform: translateX(0); }
25% { transform: translateX(-8px); }
100% { transform: translateX(380px); }
}
@keyframes notification-slidein-mobile {
0% { transform: translateY(-150px); }
75% { transform: translateY(8px); }
100% { transform: translateY(0); }
}
@keyframes notification-slideout-mobile {
0% { transform: translateY(0); }
40% { transform: translateY(8px); }
100% { transform: translateY(-100px); }
25% { transform: translateY(8px); }
100% { transform: translateY(-150px); }
}
@media (max-width: 414px) {
.gh-portal-notification {
left: 12px;
max-width: calc(100% - 24px);
animation-name: notification-slidein-mobile;
}
.gh-portal-notification.slideout {
animation-name: notification-slideout-mobile;
}
}
`;

View file

@ -109,6 +109,7 @@ class PopupContent extends React.Component {
popupWidthStyle = 'gh-portal-container-narrow';
}
let cookieBannerText = '';
let pageClass = page;
switch (page) {
case 'signup':
cookieBannerText = 'Cookies must be enabled in your browser to sign up.';
@ -116,13 +117,24 @@ class PopupContent extends React.Component {
case 'signin':
cookieBannerText = 'Cookies must be enabled in your browser to sign in.';
break;
case 'accountHome':
pageClass = 'account-home';
break;
case 'accountProfile':
pageClass = 'account-profile';
break;
case 'accountPlan':
pageClass = 'account-plan';
break;
default:
cookieBannerText = 'Cookies must be enabled in your browser.';
pageClass = page;
break;
}
return (
<div className='gh-portal-popup-wrapper'>
<div className={(hasMode(['preview', 'dev']) ? 'gh-portal-popup-container preview' : 'gh-portal-popup-container') + ' ' + popupWidthStyle} style={pageStyle} ref={node => (this.node = node)} tabIndex="-1">
<div className={(hasMode(['preview', 'dev']) ? 'gh-portal-popup-container preview' : 'gh-portal-popup-container') + ' ' + popupWidthStyle + ' ' + pageClass} style={pageStyle} ref={node => (this.node = node)} tabIndex="-1">
<CookieDisabledBanner message={cookieBannerText} />
{this.renderPopupNotification()}
{this.renderActivePage()}

View file

@ -1,6 +1,8 @@
import React from 'react';
import AppContext from '../../AppContext';
import {ReactComponent as CloseIcon} from '../../images/icons/close.svg';
import {ReactComponent as CheckmarkIcon} from '../../images/icons/checkmark-fill.svg';
import {ReactComponent as WarningIcon} from '../../images/icons/warning-fill.svg';
import {getSupportAddress} from '../../utils/helpers';
import {clearURLParams} from '../../utils/notifications';
@ -11,7 +13,7 @@ export const PopupNotificationStyles = `
left: 8px;
right: 8px;
padding: 8px;
background: var(--green);
background: var(--grey2);
z-index: 9999;
border-radius: 4px;
font-size: 1.3rem;
@ -36,9 +38,25 @@ export const PopupNotificationStyles = `
text-align: center;
}
.gh-portal-popupnotification-icon {
position: absolute;
top: 10px;
left: 10px;
width: 16px;
height: 16px;
}
.gh-portal-popupnotification-icon.success {
color: var(--green);
}
.gh-portal-popupnotification-icon.error {
color: #FF2828;
}
.gh-portal-popupnotification .closeicon {
position: absolute;
top: 1px;
top: 0px;
bottom: 0;
right: 0;
color: var(--white);
@ -54,22 +72,6 @@ export const PopupNotificationStyles = `
opacity: 1.0;
}
.gh-portal-popupnotification.success {
background: var(--green);
}
.gh-portal-popupnotification.error {
background: var(--red);
}
.gh-portal-popupnotification.warning {
background: var(--yellow);
}
.gh-portal-popupnotification.warning p, .gh-portal-popupnotification.warning .closeicon {
color: var(--grey1);
}
@keyframes popupnotification-slidein {
0% { transform: translateY(-100px); }
60% { transform: translateY(8px); }
@ -176,6 +178,7 @@ export default class PopupNotification extends React.Component {
return (
<div className={`gh-portal-popupnotification${statusClass}${slideClass}`} onAnimationEnd={e => this.onAnimationEnd(e)}>
{(status === 'error' ? <WarningIcon className='gh-portal-popupnotification-icon error' alt=''/> : <CheckmarkIcon className='gh-portal-popupnotification-icon success' alt=''/>)}
<NotificationText type={type} status={status} message={message} site={site} />
<CloseButton hide={!closeable} onClose={e => this.closeNotification(e)}/>
</div>

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.checkmark-icon-fill{fill:currentColor;}</style></defs><path class="checkmark-icon-fill" d="M12,0A12,12,0,1,0,24,12,12.014,12.014,0,0,0,12,0Zm6.927,8.2-6.845,9.289a1.011,1.011,0,0,1-1.43.188L5.764,13.769a1,1,0,1,1,1.25-1.562l4.076,3.261,6.227-8.451A1,1,0,1,1,18.927,8.2Z"/></svg>

After

Width:  |  Height:  |  Size: 352 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.warning-icon-fill{fill:currentColor;}</style></defs><path class="warning-icon-fill" d="M23.25,23.235a.75.75,0,0,0,.661-1.105l-11.25-21a.782.782,0,0,0-1.322,0l-11.25,21A.75.75,0,0,0,.75,23.235ZM12,20.485a1.5,1.5,0,1,1,1.5-1.5A1.5,1.5,0,0,1,12,20.485Zm0-12.25a1,1,0,0,1,1,1V14.7a1,1,0,0,1-2,0V9.235A1,1,0,0,1,12,8.235Z"/></svg>

After

Width:  |  Height:  |  Size: 399 B