diff --git a/assets/css/src/design-pack-notice.scss b/assets/css/src/design-pack-notice.scss new file mode 100644 index 0000000..aa02b7a --- /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); + +#fork-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..764e811 --- /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( 'fork-design-pack-notice' ); + +if ( container ) { + createRoot( container ).render( ); +} diff --git a/inc/Admin.php b/inc/Admin.php index d78e1c3..211005d 100644 --- a/inc/Admin.php +++ b/inc/Admin.php @@ -34,6 +34,82 @@ public function setup_admin_hooks() { add_action( 'wp_ajax_fork_dismiss_welcome_notice', array( $this, 'remove_welcome_notice' ) ); add_action( 'wp_ajax_fork_set_otter_ref', array( $this, 'set_otter_ref' ) ); 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_fork_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( 'fork-dismiss-design-pack-notice' ), + 'ajaxUrl' => esc_url( admin_url( 'admin-ajax.php' ) ), + 'ajaxAction' => 'fork_dismiss_design_pack_notice', + 'buttonLink' => tsdk_utmify( 'https://themeisle.com/plugins/fse-design-pack', 'editor', 'fork' ), + 'strings' => array( + 'dismiss' => __( 'Dismiss', 'fork' ), + 'recommends' => __( 'Fork recommends', 'fork' ), + 'learnMore' => __( 'Learn More', 'fork' ), + 'noticeHtml' => sprintf( + /* translators: %s: FSE Design Pack: */ + __( '%s Access a collection of 40+ layout patterns ready to import to your website', 'fork' ), + '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'] ), 'fork-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 0e6d07f..2d80eec 100644 --- a/inc/Assets_Manager.php +++ b/inc/Assets_Manager.php @@ -16,9 +16,10 @@ */ class Assets_Manager { const ASSETS_SLUGS = array( - 'frontend-css' => 'fork-style', - 'editor-css' => 'fork-editor', - 'welcome-notice' => 'fork-welcome-notice', + 'frontend-css' => 'fork-style', + 'editor-css' => 'fork-editor', + 'welcome-notice' => 'fork-welcome-notice', + 'design-pack-notice' => 'fork-design-pack-notice', ); /** diff --git a/inc/Constants.php b/inc/Constants.php index 80eadce..56c3e9b 100644 --- a/inc/Constants.php +++ b/inc/Constants.php @@ -16,6 +16,7 @@ */ class Constants { const CACHE_KEYS = array( - 'dismissed-welcome-notice' => 'fork-welcome-notice-dismissed', + 'dismissed-welcome-notice' => 'fork-welcome-notice-dismissed', + 'dismissed-fse-design-pack-notice' => 'fork-design-pack-dismissed', ); } diff --git a/package.json b/package.json index 1455cd2..6adbbb4 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..aa0a4ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2201,6 +2201,21 @@ dependencies: "@types/react" "^17" +"@types/react-dom@^18.0.6": + version "18.3.0" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" + integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^18.0.21": + version "18.3.0" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.0.tgz#2e6ac50dea2f68f774b20f1bd536ef82365cd64a" + integrity sha512-DiUcKjzE6soLyln8NNZmyhcQjVv+WsUIFSqetMN0p8927OztKT4VTfFTqsbAi5oAGIcgOmOajlfBqyptDDjZRw== + 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.3.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.0.tgz#98a3a1cc4e471d517c2a084f38ab1d58d02cada7" + integrity sha512-zaKdLBftQJnvb7FtDIpZtsAIb2MZU087RM8bRDZU8LVCCFYjPTsDZJNFUWPcVz3HFSN1n/caxi0ca4B/aaVQGQ== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.1" + 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.3.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.3.0.tgz#84386d0a36fdf5ef50fa5755b7812bdfb76194a5" + integrity sha512-RPutkJftSAldDibyrjuku7q11d3oy6wKOyPe5K1HA/HwwrXcEqBdHsLypkC2FFYjP7bPUa6gbzSBhw4sY2JcDg== + 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.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.1.tgz#ef964a7936d7cbe8f7bc0d38fc479a823aed2923" + integrity sha512-5GKS5JGfiah1O38Vfa9srZE4s3wdHbwjlCrvIookrg2FO9aIwKLOJXuJQFlEfNcVSOXuaL2hzDeY20uVXcUtrw== + 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"