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:
parent
b414e3b7e4
commit
cf4736d2df
8 changed files with 127 additions and 72 deletions
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
|
@ -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()}
|
||||
|
|
|
@ -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>
|
||||
|
|
1
ghost/portal/src/images/icons/checkmark-fill.svg
Normal file
1
ghost/portal/src/images/icons/checkmark-fill.svg
Normal 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 |
1
ghost/portal/src/images/icons/warning-fill.svg
Normal file
1
ghost/portal/src/images/icons/warning-fill.svg
Normal 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 |
Loading…
Add table
Reference in a new issue