diff --git a/assets/css/src/design-pack-notice.scss b/assets/css/src/design-pack-notice.scss new file mode 100644 index 0000000..f8613ef --- /dev/null +++ b/assets/css/src/design-pack-notice.scss @@ -0,0 +1,118 @@ +@custom-media --max-tablet (max-width: 769px); +@custom-media --max-desktop (max-width: 1200px); + +#neve-fse-design-pack-notice { + + .notice-wrap { + display: flex; + align-items: center; + gap: 15px; + border: 0; + border-radius: 8px; + padding: 20px 25px; + opacity: 0; + animation: fade-down-in 0.3s ease forwards 0.3s; + z-index: 10000; + position: fixed; + background: #fff; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + right: 10px; + bottom: 35px; + + @media (--max-desktop) { + bottom: 10px; + right: 10px; + padding: 10px 15px; + margin-left: 10px; + } + + &.dismissed { + animation: fade-up-out 0.3s ease forwards 0s; + } + } + + svg { + flex-shrink: 0; + } + + button { + border: 0; + background: 0; + cursor: pointer; + padding: 0; + border-radius: 5px; + + &:hover { + background: #e7e7e7; + } + } + + .content-wrap { + display: grid; + } + + span { + font-weight: 600; + color: #6a6a6a; + font-size: 12px; + + @media (--max-desktop) { + font-size: 10px; + } + } + + p { + + @media (--max-desktop) { + font-size: 12px; + } + font-size: 16px; + margin: 0; + padding: 0; + } + + a { + margin-left: 35px; + font-weight: 700; + font-size: 16px; + text-decoration: 0; + color: #fff; + background: #383fef; + border-radius: 5px; + padding: 12px 16px; + text-align: center; + + @media (--max-desktop) { + font-size: 14px; + padding: 7px 10px; + margin-left: 0; + flex-shrink: 0; + } + } +} + +@keyframes fade-down-in { + + 0% { + opacity: 0; + transform: translateY(-20px); + } + + 100% { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fade-up-out { + + 0% { + opacity: 1; + transform: translateY(0); + } + + 100% { + opacity: 0; + transform: translateY(-20px); + } +} diff --git a/assets/js/src/components/DesignPackNotice.js b/assets/js/src/components/DesignPackNotice.js new file mode 100644 index 0000000..d9afc33 --- /dev/null +++ b/assets/js/src/components/DesignPackNotice.js @@ -0,0 +1,98 @@ +/* global designPackNoticeData */ +import { useSelect } from '@wordpress/data'; +import { Icon, closeSmall } from '@wordpress/icons'; +import { useEffect, useState } from '@wordpress/element'; + +const logo = ( + + + +); + +const BLOCK_PATTERN_INSERTED_NOTICE = 'block-pattern-inserted-notice'; +export default () => { + const [ dismissed, setDismissed ] = useState( false ); + const [ noticeTriggered, setNoticeTriggered ] = useState( false ); + + const patternInserted = useSelect( + ( select ) => + select( 'core/notices' ) + .getNotices() + .filter( ( n ) => n.id === BLOCK_PATTERN_INSERTED_NOTICE ) + .length > 0 + ); + + useEffect( () => { + if ( noticeTriggered ) { + return; + } + if ( patternInserted ) { + setNoticeTriggered( true ); + } + }, [ patternInserted ] ); + + const { ajaxUrl, ajaxAction, nonce, strings, buttonLink } = + designPackNoticeData; + const { dismiss, recommends, learnMore, noticeHtml } = strings; + + const dismissNotice = () => { + const data = new window.FormData(); + + data.append( 'action', ajaxAction ); + data.append( 'nonce', nonce ); + + fetch( ajaxUrl, { + method: 'POST', + body: data, + } ).then( () => { + setDismissed( true ); + } ); + }; + + const classes = [ 'notice-wrap' ]; + + if ( dismissed ) { + classes.push( 'dismissed' ); + } + + if ( ! noticeTriggered ) { + return null; + } + + return ( +
+ { logo } + +
+ { recommends } + +

+
+ + + { learnMore } + + + +
+ ); +}; diff --git a/assets/js/src/design-pack-notice.js b/assets/js/src/design-pack-notice.js new file mode 100644 index 0000000..b7c382c --- /dev/null +++ b/assets/js/src/design-pack-notice.js @@ -0,0 +1,9 @@ +import { createRoot } from '@wordpress/element'; + +import DesignPackNotice from './components/DesignPackNotice'; + +const container = document.getElementById( 'neve-fse-design-pack-notice' ); + +if ( container ) { + createRoot( container ).render( ); +} diff --git a/inc/Admin.php b/inc/Admin.php index eba013b..22f06b5 100644 --- a/inc/Admin.php +++ b/inc/Admin.php @@ -56,6 +56,82 @@ public function setup_admin_hooks() { add_action( 'wp_ajax_neve_fse_dismiss_welcome_notice', array( $this, 'remove_welcome_notice' ) ); add_action( 'wp_ajax_neve_fse_dismiss_survey_notice', array( $this, 'remove_survey_notice' ) ); add_action( 'admin_print_scripts', array( $this, 'add_nps_form' ) ); + + add_action( 'enqueue_block_editor_assets', array( $this, 'add_fse_design_pack_notice' ) ); + add_action( 'wp_ajax_neve_fse_dismiss_design_pack_notice', array( $this, 'remove_design_pack_notice' ) ); + } + + /** + * Render design pack notice. + * + * @return void + */ + public function add_fse_design_pack_notice() { + if ( ! $this->should_render_design_pack_notice() ) { + return; + } + + Assets_Manager::enqueue_style( Assets_Manager::ASSETS_SLUGS['design-pack-notice'], 'design-pack-notice' ); + Assets_Manager::enqueue_script( + Assets_Manager::ASSETS_SLUGS['design-pack-notice'], + 'design-pack-notice', + true, + array(), + array( + 'nonce' => wp_create_nonce( 'neve-fse-dismiss-design-pack-notice' ), + 'ajaxUrl' => esc_url( admin_url( 'admin-ajax.php' ) ), + 'ajaxAction' => 'neve_fse_dismiss_design_pack_notice', + 'buttonLink' => tsdk_utmify( 'https://themeisle.com/plugins/fse-design-pack', 'editor', 'neve-fse' ), + 'strings' => array( + 'dismiss' => __( 'Dismiss', 'neve-fse' ), + 'recommends' => __( 'Neve FSE recommends', 'neve-fse' ), + 'learnMore' => __( 'Learn More', 'neve-fse' ), + 'noticeHtml' => sprintf( + /* translators: %s: FSE Design Pack: */ + __( '%s Access a collection of 40+ layout patterns ready to import to your website', 'neve-fse' ), + 'FSE Design Pack:' + ), + ), + ), + 'designPackNoticeData' + ); + + echo '
'; + } + + /** + * Should we show the design pack notice? + * + * @return bool + */ + private function should_render_design_pack_notice() { + // Already using. + if ( is_plugin_active( 'fse-design-pack/fse-design-pack.php' ) ) { + return false; + } + + // Notice was dismissed. + if ( get_option( Constants::CACHE_KEYS['dismissed-fse-design-pack-notice'], 'no' ) === 'yes' ) { + return false; + } + + return true; + } + + /** + * Dismiss the design pack notice. + * + * @return void + */ + public function remove_design_pack_notice() { + if ( ! isset( $_POST['nonce'] ) ) { + return; + } + if ( ! wp_verify_nonce( sanitize_text_field( $_POST['nonce'] ), 'neve-fse-dismiss-design-pack-notice' ) ) { + return; + } + update_option( Constants::CACHE_KEYS['dismissed-fse-design-pack-notice'], 'yes' ); + wp_die(); } /** diff --git a/inc/Assets_Manager.php b/inc/Assets_Manager.php index 6f4ff88..314f8af 100644 --- a/inc/Assets_Manager.php +++ b/inc/Assets_Manager.php @@ -16,10 +16,11 @@ */ class Assets_Manager { const ASSETS_SLUGS = array( - 'frontend-css' => 'neve-fse-style', - 'editor-css' => 'neve-fse-editor', - 'welcome-notice' => 'neve-fse-welcome-notice', - 'general-notice' => 'neve-fse-general-notice', + 'frontend-css' => 'neve-fse-style', + 'editor-css' => 'neve-fse-editor', + 'welcome-notice' => 'neve-fse-welcome-notice', + 'general-notice' => 'neve-fse-general-notice', + 'design-pack-notice' => 'neve-fse-design-pack-notice', ); const AVAILABLE_THEME_FONTS = array( diff --git a/inc/Constants.php b/inc/Constants.php index e3453f7..47ebde3 100644 --- a/inc/Constants.php +++ b/inc/Constants.php @@ -16,8 +16,9 @@ */ class Constants { const CACHE_KEYS = array( - 'dismissed-welcome-notice' => 'neve-fse-welcome-notice-dismissed', - 'dismissed-survey-notice' => 'neve-fse-survey-notice-dismissed', + 'dismissed-welcome-notice' => 'neve-fse-welcome-notice-dismissed', + 'dismissed-survey-notice' => 'neve-fse-survey-notice-dismissed', + 'dismissed-fse-design-pack-notice' => 'neve-fse-design-pack-dismissed', ); const PRODUCT_KEY = 'neve_fse'; diff --git a/package.json b/package.json index 345aa01..639d3ce 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@semantic-release/exec": "^6.0.3", "@semantic-release/git": "^10.0.1", "@wordpress/eslint-plugin": "^12.8.0", + "@wordpress/icons": "^9.47.0", "@wordpress/scripts": "^23.6.0", "@wordpress/stylelint-config": "^20.0.2", "conventional-changelog-simple-preset": "^1.0.20", diff --git a/yarn.lock b/yarn.lock index b13a187..5d92d53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2201,6 +2201,21 @@ dependencies: "@types/react" "^17" +"@types/react-dom@^18.0.6": + version "18.2.25" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.25.tgz#2946a30081f53e7c8d585eb138277245caedc521" + integrity sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^18.0.21": + version "18.2.79" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.79.tgz#c40efb4f255711f554d47b449f796d1c7756d865" + integrity sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + "@types/react@^17", "@types/react@^17.0.37": version "17.0.52" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.52.tgz#10d8b907b5c563ac014a541f289ae8eaa9bf2e9b" @@ -2626,6 +2641,20 @@ react "^17.0.2" react-dom "^17.0.2" +"@wordpress/element@^5.33.0": + version "5.33.0" + resolved "https://registry.yarnpkg.com/@wordpress/element/-/element-5.33.0.tgz#33ffd6c75ed8f711b55f8e6051dc09e963d23c78" + integrity sha512-RNisHbRgAO5/RLyfckgHYWgKq+IKd8Yn1mJHYWp+1Fx+1K6vjlhr/1D4a81fWL15IoCTV3tYh6zYei4/fRpZog== + dependencies: + "@babel/runtime" "^7.16.0" + "@types/react" "^18.0.21" + "@types/react-dom" "^18.0.6" + "@wordpress/escape-html" "^2.56.0" + change-case "^4.1.2" + is-plain-object "^5.0.0" + react "^18.2.0" + react-dom "^18.2.0" + "@wordpress/escape-html@^2.22.0": version "2.22.0" resolved "https://registry.yarnpkg.com/@wordpress/escape-html/-/escape-html-2.22.0.tgz#2fa4e901b0ab96634541ca7d153baf910b741977" @@ -2633,6 +2662,13 @@ dependencies: "@babel/runtime" "^7.16.0" +"@wordpress/escape-html@^2.56.0": + version "2.56.0" + resolved "https://registry.yarnpkg.com/@wordpress/escape-html/-/escape-html-2.56.0.tgz#042626b9fc33dbd210b24ed554e71a9a9665b246" + integrity sha512-f+NDe9ZyUtaoiU8VYSKRjxsKqqzinrVcpcqj+umiLhKD5ShGW8V7LcSr3JOdE4TgjHvw2eezFvRmEo/kXowmMA== + dependencies: + "@babel/runtime" "^7.16.0" + "@wordpress/eslint-plugin@^12.8.0", "@wordpress/eslint-plugin@^12.9.0": version "12.9.0" resolved "https://registry.yarnpkg.com/@wordpress/eslint-plugin/-/eslint-plugin-12.9.0.tgz#c49f0a523c8c72ade28c2b86a975668832b22938" @@ -2655,6 +2691,15 @@ globals "^13.12.0" requireindex "^1.2.0" +"@wordpress/icons@^9.47.0": + version "9.47.0" + resolved "https://registry.yarnpkg.com/@wordpress/icons/-/icons-9.47.0.tgz#ea817c822b2e307bdfb5c9ec555933037a2c0c6a" + integrity sha512-IQIoEr0LxPWUOgcHnMIqU/ytg3x/swxbl8AGG1ONFks3/2tYdDk3I2/CAYgQGpaiSFIOJjNVk1keqa8DBOnciw== + dependencies: + "@babel/runtime" "^7.16.0" + "@wordpress/element" "^5.33.0" + "@wordpress/primitives" "^3.54.0" + "@wordpress/jest-console@^5.4.0": version "5.4.0" resolved "https://registry.yarnpkg.com/@wordpress/jest-console/-/jest-console-5.4.0.tgz#b01301ced098b0f0f6adeeb2e5235699d7a80b66" @@ -2692,6 +2737,15 @@ resolved "https://registry.yarnpkg.com/@wordpress/prettier-config/-/prettier-config-1.4.0.tgz#8eaeb8daf7253e8b0806da2279017d4f4fef0f62" integrity sha512-uvrgUAhRnOvIysXjcXH9VDsrKLqH9r3BfdGoy+WFLSHFnTfdMhW7bdDQXl4F4UIUuefUwGi+ZvT/rChg9zoBkQ== +"@wordpress/primitives@^3.54.0": + version "3.54.0" + resolved "https://registry.yarnpkg.com/@wordpress/primitives/-/primitives-3.54.0.tgz#7e46aed14c1e261314171b4fc496ce5214604d54" + integrity sha512-2TrXDvYW3V0nlq6ZCYYvJ5obPZNtrsuIdB0iLdUavCOSBoXTROhRZY9Pxz45bB2CLlmEUs9OfL7izx9IuAg4Mw== + dependencies: + "@babel/runtime" "^7.16.0" + "@wordpress/element" "^5.33.0" + classnames "^2.3.1" + "@wordpress/scripts@^23.6.0": version "23.7.2" resolved "https://registry.yarnpkg.com/@wordpress/scripts/-/scripts-23.7.2.tgz#93f38354d799ed91cc9adc27144927c6935ce413" @@ -3836,6 +3890,11 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== +classnames@^2.3.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" + integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -10670,6 +10729,14 @@ react-dom@^17.0.2: object-assign "^4.1.1" scheduler "^0.20.2" +react-dom@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + react-is@^16.12.0, react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -10716,6 +10783,13 @@ react@^17.0.2: loose-envify "^1.1.0" object-assign "^4.1.1" +react@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" + read-cmd-shim@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-3.0.1.tgz#868c235ec59d1de2db69e11aec885bc095aea087" @@ -11230,6 +11304,13 @@ scheduler@^0.20.2: loose-envify "^1.1.0" object-assign "^4.1.1" +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== + dependencies: + loose-envify "^1.1.0" + schema-utils@^2.6.5: version "2.7.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7"