From 33e14a989bd14426b1e1cd9ba6abbe2f84ff97b5 Mon Sep 17 00:00:00 2001 From: Hardeep Asrani Date: Sun, 5 Jan 2025 11:20:48 +0530 Subject: [PATCH] various fixes --- .../gutenberg/feedzy-rss-feeds-loop-block.php | 19 ++- js/FeedzyLoop/components/FeedControl.js | 156 ++++++++++++++++++ js/FeedzyLoop/controls.js | 37 ++++- js/FeedzyLoop/edit.js | 17 +- js/FeedzyLoop/editor.scss | 112 ++++++++++++- js/FeedzyLoop/placeholder.js | 135 ++++----------- js/FeedzyLoop/variations.js | 121 +++++++++++--- 7 files changed, 458 insertions(+), 139 deletions(-) create mode 100644 js/FeedzyLoop/components/FeedControl.js diff --git a/includes/gutenberg/feedzy-rss-feeds-loop-block.php b/includes/gutenberg/feedzy-rss-feeds-loop-block.php index 5962eaf7..1e7d339b 100644 --- a/includes/gutenberg/feedzy-rss-feeds-loop-block.php +++ b/includes/gutenberg/feedzy-rss-feeds-loop-block.php @@ -182,7 +182,17 @@ public function render_callback( $attributes, $content ) { */ public function apply_magic_tags( $content, $item ) { $pattern = '/\{\{feedzy_([^}]+)\}\}/'; - $content = str_replace( FEEDZY_ABSURL . 'img/feedzy.svg', '{{feedzy_image}}', $content ); + $content = str_replace( + array( + FEEDZY_ABSURL . 'img/feedzy.svg', + 'http://{{feedzy_url}}' + ), + array( + '{{feedzy_image}}', + '{{feedzy_url}}' + ), + $content + ); return preg_replace_callback( $pattern, function( $matches ) use ( $item ) { return isset( $matches[1] ) ? $this->get_value( $matches[1], $item ) : ''; @@ -210,8 +220,11 @@ public function get_value( $key, $item ) { $item_date = isset( $item['item_date'] ) ? wp_date( get_option( 'time_format' ), $item['item_date'] ) : ''; return $item_date; case 'datetime': - $item_date = isset( $item['item_date'] ) ? wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $item['item_date'] ) : ''; - return $item_date; + $item_date = isset( $item['item_date'] ) ? wp_date( get_option( 'date_format' ), $item['item_date'] ) : ''; + $item_time = isset( $item['item_date'] ) ? wp_date( get_option( 'time_format' ), $item['item_date'] ) : ''; + /* translators: 1: date, 2: time */ + $datetime = sprintf( __( '%1$s at %2$s', 'feedzy-rss-feeds' ), $item_date, $item_time ); + return $datetime; case 'author': if ( isset( $item['item_author'] ) && is_string( $item['item_author'] ) ) { return $item['item_author']; diff --git a/js/FeedzyLoop/components/FeedControl.js b/js/FeedzyLoop/components/FeedControl.js new file mode 100644 index 00000000..05a5b412 --- /dev/null +++ b/js/FeedzyLoop/components/FeedControl.js @@ -0,0 +1,156 @@ +/** + * WordPress dependencies. + */ +import { useState, useEffect, useRef } from '@wordpress/element'; + +const FeedControl = ({ value, options, onChange }) => { + const [isOpen, setIsOpen] = useState(false); + const [inputValue, setInputValue] = useState(''); + const [selectedOption, setSelectedOption] = useState(null); + const dropdownRef = useRef(null); + + // Initialize component state based on value prop + useEffect(() => { + if (value?.type === 'group' && value.source) { + const selected = options.find((opt) => opt.value === value.source); + setSelectedOption(selected || null); + setInputValue(''); + } else if (value?.type === 'url' && Array.isArray(value.source)) { + setSelectedOption(null); + setInputValue(value.source.join(', ')); + } + }, [value, options]); + + useEffect(() => { + const handleClickOutside = (event) => { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target) + ) { + setIsOpen(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => + document.removeEventListener('mousedown', handleClickOutside); + }, []); + + const handleSelectOption = (option) => { + setSelectedOption(option); + setInputValue(''); + setIsOpen(false); + onChange({ + type: 'group', + source: option.value, + }); + }; + + const handleInputChange = (e) => { + const current = e.target.value; + setInputValue(current); + setSelectedOption(null); + }; + + const handleInputBlur = () => { + onChange({ + type: 'url', + source: inputValue + ? inputValue + .split(',') + .map((url) => url.trim()) + .filter(Boolean) + : [], + }); + }; + + const handleClear = () => { + setSelectedOption(null); + setInputValue(''); + onChange({ + type: 'url', + source: [], + }); + }; + + return ( +
+ +
+ {selectedOption && ( + + )} + +
+ + {isOpen && ( +
+ {options.map((option) => ( + + ))} +
+ )} +
+ ); +}; + +export default FeedControl; diff --git a/js/FeedzyLoop/controls.js b/js/FeedzyLoop/controls.js index 3559bdfb..a087c1a5 100644 --- a/js/FeedzyLoop/controls.js +++ b/js/FeedzyLoop/controls.js @@ -170,18 +170,37 @@ const Controls = ({ ]} initialOpen={false} key="filters" - className={ - window.feedzyData.isPro - ? 'feedzy-item-filter' - : 'feedzy-item-filter fz-locked' - } + className="feedzy-item-filter" > + {!window.feedzyData.isPro && ( +
+ {__( + 'Unlock this feature and more advanced options with', + 'feedzy-rss-feeds' + )}{' '} + + {__('Feedzy Pro', 'feedzy-rss-feeds')} + +
+ )} + { setAttributes({ conditions }); diff --git a/js/FeedzyLoop/edit.js b/js/FeedzyLoop/edit.js index 976e7b29..0c0603ca 100644 --- a/js/FeedzyLoop/edit.js +++ b/js/FeedzyLoop/edit.js @@ -15,6 +15,11 @@ import { InnerBlocks, } from '@wordpress/block-editor'; +import { + Placeholder as BlockEditorPlaceholder, + Spinner, +} from '@wordpress/components'; + import { useDispatch, useSelect } from '@wordpress/data'; import { useState } from '@wordpress/element'; @@ -30,13 +35,20 @@ import Controls from './controls'; const { name } = metadata; +const LoadingResponsePlaceholder = () => ( + + + +); + const Edit = ({ attributes, setAttributes, clientId }) => { const blockProps = useBlockProps(); const [isEditing, setIsEditing] = useState(!attributes?.feed?.source); const [isPreviewing, setIsPreviewing] = useState(false); - const { replaceInnerBlocks, selectBlock } = useDispatch(blockEditorStore); + const { clearSelectedBlock, replaceInnerBlocks, selectBlock } = + useDispatch(blockEditorStore); const isSelected = useSelect( (select) => { @@ -130,6 +142,7 @@ const Edit = ({ attributes, setAttributes, clientId }) => { ...attributes, innerBlocksContent, }} + LoadingResponsePlaceholder={LoadingResponsePlaceholder} /> @@ -165,8 +178,8 @@ const Edit = ({ attributes, setAttributes, clientId }) => { ), true ); + clearSelectedBlock(); } - selectBlock(clientId); }} /> )} diff --git a/js/FeedzyLoop/editor.scss b/js/FeedzyLoop/editor.scss index 7bb19b11..1650384f 100644 --- a/js/FeedzyLoop/editor.scss +++ b/js/FeedzyLoop/editor.scss @@ -5,7 +5,6 @@ } p { - margin: 0; width: 100%; } } @@ -100,4 +99,113 @@ } } } -} \ No newline at end of file +} + +.fz-url-category-input { + position: relative; + display: flex; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; +} + +input[type="text"].fz-input-field { + flex: 1; + height: 32px; + padding: 6px 8px; + font-size: 13px; + border: 1px solid #757575; + border-right: none; + border-radius: 2px 0 0 2px; + margin: 0; + background-color: #fff; + color: #1e1e1e; + box-sizing: border-box; +} + +input[type="text"].fz-input-field:focus { + outline: none; + border-color: #007cba; + box-shadow: 0 0 0 1px #007cba; +} + +input[type="text"].fz-input-field:disabled { + background-color: #fff; + cursor: default; + color: #1e1e1e; +} + +.fz-buttons-container { + display: flex; + border: 1px solid #757575; + border-radius: 0 2px 2px 0; + background: #fff; + height: 32px; + box-sizing: border-box; +} + +.fz-clear-button, +.fz-dropdown-button { + width: 32px; + height: 30px; + padding: 0; + display: flex; + align-items: center; + justify-content: center; + background: transparent; + border: none; + cursor: pointer; + color: #1e1e1e; +} + +.fz-clear-button { + border-right: 1px solid #757575; +} + +.fz-clear-button:hover, +.fz-dropdown-button:hover { + background-color: #f0f0f0; +} + +.fz-clear-button:focus, +.fz-dropdown-button:focus { + outline: none; + box-shadow: 0 0 0 1px #007cba; +} + +.fz-dropdown-menu { + position: absolute; + top: 100%; + left: 0; + right: 0; + margin-top: 4px; + background-color: #fff; + border: 1px solid #757575; + border-radius: 2px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + z-index: 1000; +} + +.fz-dropdown-item { + width: 100%; + padding: 8px 12px; + font-size: 13px; + text-align: left; + background: none; + border: none; + cursor: pointer; + color: #1e1e1e; +} + +.fz-dropdown-item:hover { + background-color: #f0f0f0; +} + +.fz-dropdown-item.fz-selected { + background-color: #f0f7ff; + color: #007cba; +} + +.fz-dropdown-item:focus { + outline: none; + background-color: #f0f7ff; + color: #007cba; +} diff --git a/js/FeedzyLoop/placeholder.js b/js/FeedzyLoop/placeholder.js index 9c89ed12..8d1f4018 100644 --- a/js/FeedzyLoop/placeholder.js +++ b/js/FeedzyLoop/placeholder.js @@ -5,19 +5,21 @@ import { __ } from '@wordpress/i18n'; import { - __experimentalToggleGroupControl as ToggleGroupControl, - __experimentalToggleGroupControlOption as ToggleGroupControlOption, + BaseControl, Button, Placeholder, - SelectControl, Spinner, - TextControl, } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; +/** + * Internal dependencies. + */ +import FeedControl from './components/FeedControl'; + const BlockPlaceholder = ({ attributes, setAttributes, onSaveFeed }) => { const { categories, isLoading } = useSelect((select) => { const { getEntityRecords, isResolving } = select(coreStore); @@ -31,15 +33,6 @@ const BlockPlaceholder = ({ attributes, setAttributes, onSaveFeed }) => { }; }, []); - const onChangeFeed = ({ type, value }) => { - setAttributes({ - feed: { - ...attributes.feed, - [type]: value, - }, - }); - }; - return ( { {!isLoading && ( <> - - onChangeFeed({ type: 'type', value }) - } + id="feed-source-control" > - - ({ + label: category?.title?.rendered, + value: category.id, + })), + ]} + onChange={(value) => setAttributes({ feed: value })} /> - - - {'url' === attributes?.feed?.type && ( - <> - - onChangeFeed({ - type: 'source', - value: value - .split(',') - .map((item) => item.trim()), - }) - } - /> -

- {__( - 'Enter the full URL of the feed source you wish to display here. Also you can add multiple URLs separated with a comma.', - 'feedzy-rss-feeds' - )} -

- - )} - {'group' === attributes?.feed?.type && ( - <> - ({ - label: category?.title?.rendered, - value: category.id, - })), - ]} - value={attributes?.feed?.source ?? ''} - onChange={(value) => - onChangeFeed({ - type: 'source', - value: parseInt(value, 10), - }) - } - /> -

- {__( - 'You can manage your groups feed from', - 'feedzy-rss-feeds' - )}{' '} - - {__('here', 'feedzy-rss-feeds')} - -

- - )} +

+ {__( + 'Enter the full URL of the feed source you wish to display here, or select a Feed Group. Also you can add multiple URLs separated with a comma. You can manage your feed groups from', + 'feedzy-rss-feeds' + )}{' '} + + {__('here', 'feedzy-rss-feeds')} + +

+