Skip to content

Commit 01c4077

Browse files
authored
Merge pull request #23315 from Yoast/1248-fix-webinar-notification-spacing-in-general-page
fix: spacing between webinar notice and general page notices
2 parents eb4e1cb + b51f24c commit 01c4077

9 files changed

Lines changed: 77 additions & 60 deletions

File tree

css/src/general-page.css

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ body.toplevel_page_wpseo_dashboard {
33
display: none;
44
}
55

6-
.yoast-general-page-notices:last-child {
7-
margin-bottom: 2rem;
8-
}
9-
106
.yoast-general-page-notice, .yoast-webinar-dashboard {
117
background: white;
128
padding: 0.75rem;
@@ -30,16 +26,6 @@ body.toplevel_page_wpseo_dashboard {
3026
margin-right: 12px;
3127
}
3228

33-
.yoast-general-page-notice .notice-dismiss {
34-
position: relative;
35-
@apply yst-text-slate-400
36-
hover:yst-text-slate-500
37-
}
38-
39-
.yoast-general-page-notice .notice-dismiss:before {
40-
display: none;
41-
}
42-
4329
.yoast-general-page-notice .notice-yoast img {
4430
display: none;
4531
}
@@ -53,16 +39,14 @@ body.toplevel_page_wpseo_dashboard {
5339
margin-top: 0;
5440
}
5541

56-
.yoast-webinar-dashboard .notice-dismiss:before {
57-
/* yst-text-slate-400 */
58-
background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='2' stroke='%2394A3B8' class='yst-h-5 yst-w-5' role='img'><path stroke-linecap='round' stroke-linejoin='round' d='M6 18L18 6M6 6l12 12'></path></svg>");
59-
content: '';
42+
.yoast-webinar-dashboard .notice-dismiss:before{
43+
@apply yst-top-3 yst-right-3 yst-absolute;
6044
}
6145

62-
.yoast-webinar-dashboard .notice-dismiss:hover:before {
63-
/* yst-text-slate-500 */
64-
background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='2' stroke='%2364748b' class='yst-h-5 yst-w-5' role='img'><path stroke-linecap='round' stroke-linejoin='round' d='M6 18L18 6M6 6l12 12'></path></svg>");
65-
content: '';
46+
.yoast-webinar-dashboard .notice-dismiss:before, .yoast-general-page-notice .notice-dismiss:before {
47+
background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='2' stroke='%2394A3B8' class='yst-h-5 yst-w-5' role='img'><path stroke-linecap='round' stroke-linejoin='round' d='M6 18L18 6M6 6l12 12'></path></svg>") no-repeat center;
48+
color:transparent;
49+
background-size: 20px;
6650
}
6751

6852
.yoast-webinar-dashboard p {

packages/js/src/components/trustpilot-review-notification/trustpilot-review-notification.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const TrustpilotReviewNotification = ( props ) => {
2727
hasIcon={ false }
2828
isAlertDismissed={ ! shouldShow }
2929
onDismissed={ dismiss }
30+
className="yst-m-0"
3031
{ ...props }
3132
>
3233
{ __( "Happy with the plugin?", "wordpress-seo" ) }

packages/js/src/containers/PersistentDismissableNotification.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
/* eslint-disable complexity */
12
import { __ } from "@wordpress/i18n";
23
import PropTypes from "prop-types";
34
import withPersistentDismiss from "./withPersistentDismiss";
5+
import classNames from "classnames";
46

57
/**
68
* @param {string} id The id.
@@ -12,7 +14,6 @@ import withPersistentDismiss from "./withPersistentDismiss";
1214
*
1315
* @returns {Component} The composed Notification component.
1416
*/
15-
1617
export const PersistentDismissableNotification = ( {
1718
children,
1819
id,
@@ -21,9 +22,10 @@ export const PersistentDismissableNotification = ( {
2122
image: Image = null,
2223
isAlertDismissed,
2324
onDismissed,
25+
className = "",
2426
} ) => {
2527
return isAlertDismissed ? null : (
26-
<div id={ id } className="notice-yoast yoast is-dismissible yoast-webinar-dashboard yoast-general-page-notices yst-m-0">
28+
<div id={ id } className={ classNames( "notice-yoast yoast is-dismissible", className ) }>
2729
<div className="notice-yoast__container">
2830
<div>
2931
<div className="notice-yoast__header">
@@ -56,6 +58,7 @@ PersistentDismissableNotification.propTypes = {
5658
image: PropTypes.elementType,
5759
isAlertDismissed: PropTypes.bool.isRequired,
5860
onDismissed: PropTypes.func.isRequired,
61+
className: PropTypes.string,
5962
};
6063

6164
export default withPersistentDismiss( PersistentDismissableNotification );

packages/js/src/general/app.js

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ import { addQueryArgs } from "@wordpress/url";
1010
import { Notifications, SidebarNavigation, useSvgAria } from "@yoast/ui-library";
1111
import PropTypes from "prop-types";
1212
import { Link, Outlet, useLocation } from "react-router-dom";
13-
import { Notice, OptInContainer } from "./components";
13+
import { Notices, OptInContainer } from "./components";
1414
import { STORE_NAME } from "./constants";
15-
import WebinarPromoNotification from "../components/WebinarPromoNotification";
1615
import { deleteMigratingNotices } from "../helpers/migrateNotices";
1716
import { useNotificationCountSync, useSelectGeneralPage } from "./hooks";
1817
import { MenuItemLink, YoastLogo } from "../shared-admin/components";
@@ -135,23 +134,10 @@ const App = () => {
135134
enterFrom="yst-opacity-0"
136135
enterTo="yst-opacity-100"
137136
>
138-
{ pathname !== ROUTES.firstTimeConfiguration && <div>
139-
<WebinarPromoNotification store={ STORE_NAME } url={ webinarIntroSettingsUrl } image={ null } />
140-
{ notices.length > 0 && <div className={ notices.filter( notice => ! notice.isDismissed ).length > 0 ? "yst-space-y-3 yoast-general-page-notices" : "yst-hidden" }> {
141-
notices.map( ( notice, index ) =>
142-
<Notice
143-
key={ index }
144-
id={ notice.id || "yoast-general-page-notice-" + index }
145-
title={ notice.header }
146-
isDismissable={ notice.isDismissable }
147-
className={ notice.isDismissed ? "yst-hidden" : "" }
148-
>
149-
{ notice.content }
150-
</Notice>
151-
)
152-
}
153-
</div> }
154-
</div> }
137+
{ pathname !== ROUTES.firstTimeConfiguration && <Notices
138+
notices={ notices }
139+
webinarIntroSettingsUrl={ webinarIntroSettingsUrl }
140+
/> }
155141
<Outlet />
156142
</Transition>
157143
</main>

packages/js/src/general/components/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ export { OptInContainer } from "./opt-in-container";
1111
export { TaskListUpsellRow } from "./task-list-upsell-row";
1212
export { Task } from "./task";
1313
export { TaskListModal } from "./task-list-modal";
14+
export { Notices } from "./notices";

packages/js/src/general/components/notice.js

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
import XIcon from "@heroicons/react/outline/XIcon";
21
import { useDispatch } from "@wordpress/data";
32
import { useCallback } from "@wordpress/element";
43
import { __ } from "@wordpress/i18n";
5-
import { useSvgAria } from "@yoast/ui-library";
64
import classNames from "classnames";
75
import PropTypes from "prop-types";
86
import { STORE_NAME } from "../constants";
@@ -19,7 +17,6 @@ import { STORE_NAME } from "../constants";
1917
* @returns {JSX.Element} The Notice.
2018
*/
2119
export function Notice( { title, id, isDismissable, children, className = "" } ) {
22-
const ariaSvgProps = useSvgAria();
2320
const { dismissNotice } = useDispatch( STORE_NAME );
2421

2522
const handleDismiss = useCallback( () => {
@@ -30,22 +27,15 @@ export function Notice( { title, id, isDismissable, children, className = "" } )
3027
}, [ dismissNotice, id ] );
3128

3229
return (
33-
<div id={ id } className={ classNames( "yst-p-3 yst-rounded-md yoast-general-page-notice", className ) }>
30+
<div id={ id } className={ classNames( "yst-p-3 yst-rounded-md yoast-general-page-notice yst-relative", className ) }>
3431
<div className="yst-flex yst-flex-row yst-items-center yst-min-h-[24px]">
3532
<span className="yoast-icon" />
3633
{ title && <div className="yst-text-sm yst-font-medium" dangerouslySetInnerHTML={ { __html: title } } /> }
37-
{ isDismissable &&
38-
<div className="yst-relative yst-ms-auto">
39-
<button
40-
type="button"
41-
className="notice-dismiss"
42-
onClick={ handleDismiss }
43-
>
44-
<span className="yst-sr-only">{ __( "Close", "wordpress-seo" ) }</span>
45-
<XIcon className="yst-h-5 yst-w-5" { ...ariaSvgProps } />
46-
</button>
47-
</div>
48-
}
34+
{ isDismissable && (
35+
<button type="button" className="notice-dismiss" onClick={ handleDismiss }>
36+
<span className="yst-sr-only">{ __( "Close", "wordpress-seo" ) }</span>
37+
</button>
38+
) }
4939
</div>
5040
{ children && (
5141
<div className="yst-flex-1 yst-text-sm yst-max-w-[600px] yst-ps-[29px]" dangerouslySetInnerHTML={ { __html: children } } />
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import PropTypes from "prop-types";
2+
import classNames from "classnames";
3+
import { STORE_NAME } from "../constants";
4+
import WebinarPromoNotification from "../../components/WebinarPromoNotification";
5+
import { Notice } from ".";
6+
7+
/**
8+
* The notices component that renders the notices on the general page.
9+
* @param {object} props
10+
* @param {object[]} props.notices The notices to render.
11+
* @param {string} props.webinarIntroSettingsUrl The URL to the webinar intro settings page.
12+
* @returns {JSX.Element} The notices component.
13+
*/
14+
export const Notices = ( { notices, webinarIntroSettingsUrl } ) => ( <div>
15+
<WebinarPromoNotification
16+
store={ STORE_NAME }
17+
url={ webinarIntroSettingsUrl }
18+
image={ null }
19+
className={
20+
classNames(
21+
notices.filter( notice => ! notice.isDismissed ).length > 0 ? "yst-mb-3" : "yst-mb-8",
22+
"yoast-webinar-dashboard"
23+
) }
24+
/>
25+
{ notices.length > 0 && <div className={ notices.filter( notice => ! notice.isDismissed ).length > 0 ? "yst-mb-8" : "" }> {
26+
notices.map( ( notice, index ) =>
27+
<Notice
28+
key={ index }
29+
id={ notice.id || "yoast-general-page-notice-" + index }
30+
title={ notice.header }
31+
isDismissable={ notice.isDismissable }
32+
className={ notice.isDismissed ? "yst-hidden" : "yst-mb-3" }
33+
>
34+
{ notice.content }
35+
</Notice>
36+
)
37+
}
38+
</div> }
39+
</div> );
40+
41+
Notices.propTypes = {
42+
notices: PropTypes.arrayOf( PropTypes.shape( {
43+
id: PropTypes.string,
44+
header: PropTypes.string.isRequired,
45+
content: PropTypes.string.isRequired,
46+
isDismissable: PropTypes.bool.isRequired,
47+
isDismissed: PropTypes.bool.isRequired,
48+
} ) ).isRequired,
49+
webinarIntroSettingsUrl: PropTypes.string.isRequired,
50+
};

packages/js/src/hooks/use-first-eligible-notification.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export const useFirstEligibleNotification = ( { webinarIntroUrl } ) => {
3939
},
4040
{
4141
getIsEligible: shouldShowWebinarPromotionNotificationInSidebar,
42-
component: ( props ) => <WebinarPromoNotification hasIcon={ false } image={ null } url={ webinarIntroUrl } { ...props } />,
42+
component: ( props ) => <WebinarPromoNotification hasIcon={ false } image={ null } url={ webinarIntroUrl } className="yst-m-0" { ...props } />,
4343
},
4444
{
4545
getIsEligible: () => true,

packages/js/tests/general/components/route-error-fallback.test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ const LINK = "https://yoa.st/general-error-support";
99
jest.mock( "@wordpress/data", () => ( {
1010
useSelect: jest.fn( () => LINK ),
1111
registerStore: jest.fn(),
12+
withSelect: jest.fn( () => component => component ),
13+
withDispatch: jest.fn( () => component => component ),
1214
} ) );
1315

1416
/**

0 commit comments

Comments
 (0)