From 39a178520df3346a1078ff5b9fa885763e4a274b Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Fri, 17 May 2024 15:59:23 +0300 Subject: [PATCH] Add home template details to inspector controls --- .../src/components/sidebar/post-summary.js | 8 +- .../site-settings-panel/blog-title-panel.js | 121 ++++++++++++++++ .../site-settings-panel/discussion-panel.js | 133 ++++++++++++++++++ .../components/site-settings-panel/index.js | 30 ++++ .../posts-per-page-panel.js | 100 +++++++++++++ .../components/site-settings-panel/style.scss | 28 ++++ packages/editor/src/style.scss | 1 + 7 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 packages/editor/src/components/site-settings-panel/blog-title-panel.js create mode 100644 packages/editor/src/components/site-settings-panel/discussion-panel.js create mode 100644 packages/editor/src/components/site-settings-panel/index.js create mode 100644 packages/editor/src/components/site-settings-panel/posts-per-page-panel.js create mode 100644 packages/editor/src/components/site-settings-panel/style.scss diff --git a/packages/editor/src/components/sidebar/post-summary.js b/packages/editor/src/components/sidebar/post-summary.js index 807ff25c2d9ff0..268f7e53e9e144 100644 --- a/packages/editor/src/components/sidebar/post-summary.js +++ b/packages/editor/src/components/sidebar/post-summary.js @@ -33,6 +33,7 @@ import { TEMPLATE_POST_TYPE, } from '../../store/constants'; import TemplateAreas from '../template-areas'; +import SiteSettingsPanel from '../site-settings-panel'; /** * Module Constants @@ -87,7 +88,12 @@ export default function PostSummary( { onActionPerformed } ) { - { isTemplate && } + { isTemplate && ( + <> + + + + ) } { fills } { ! isPattern && ! isTemplate && diff --git a/packages/editor/src/components/site-settings-panel/blog-title-panel.js b/packages/editor/src/components/site-settings-panel/blog-title-panel.js new file mode 100644 index 00000000000000..5043004087d7d2 --- /dev/null +++ b/packages/editor/src/components/site-settings-panel/blog-title-panel.js @@ -0,0 +1,121 @@ +/** + * WordPress dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; +import { debounce } from '@wordpress/compose'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { decodeEntities } from '@wordpress/html-entities'; +import { + Button, + Dropdown, + __experimentalInputControl as InputControl, +} from '@wordpress/components'; +import { useState, useEffect, useMemo } from '@wordpress/element'; +import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import PostPanelRow from '../post-panel-row'; + +const EMPTY_OBJECT = {}; + +export default function BlogTitlePanel() { + const { editEntityRecord } = useDispatch( coreStore ); + const { postsPageTitle, postsPageId } = useSelect( ( select ) => { + const { getEntityRecord } = select( coreStore ); + const siteSettings = getEntityRecord( 'root', 'site' ); + const _postsPageRecord = siteSettings?.page_for_posts + ? getEntityRecord( + 'postType', + 'page', + siteSettings?.page_for_posts + ) + : EMPTY_OBJECT; + return { + postsPageId: _postsPageRecord?.id, + postsPageTitle: _postsPageRecord?.title?.rendered, + }; + }, [] ); + const [ postsPageTitleValue, setPostsPageTitleValue ] = useState( '' ); + + /* + * This hook serves to set the server-retrieved postsPageTitle + * value to local state. + */ + useEffect( () => { + setPostsPageTitleValue( postsPageTitle ); + }, [ postsPageTitle ] ); + + // Use internal state instead of a ref to make sure that the component + // re-renders when the popover's anchor updates. + const [ popoverAnchor, setPopoverAnchor ] = useState( null ); + // Memoize popoverProps to avoid returning a new object every time. + const popoverProps = useMemo( + () => ( { + // Anchor the popover to the middle of the entire row so that it doesn't + // move around when the label changes. + anchor: popoverAnchor, + placement: 'left-start', + offset: 36, + shift: true, + } ), + [ popoverAnchor ] + ); + + if ( ! postsPageId ) { + return null; + } + + const setPostsPageTitle = ( newValue ) => { + setPostsPageTitleValue( newValue ); + editEntityRecord( 'postType', 'page', postsPageId, { + title: newValue, + } ); + }; + const decodedTitle = decodeEntities( postsPageTitle ); + return ( + + ( + + ) } + renderContent={ ( { onClose } ) => ( + <> + + + + ) } + /> + + ); +} diff --git a/packages/editor/src/components/site-settings-panel/discussion-panel.js b/packages/editor/src/components/site-settings-panel/discussion-panel.js new file mode 100644 index 00000000000000..66d24a0abcdc44 --- /dev/null +++ b/packages/editor/src/components/site-settings-panel/discussion-panel.js @@ -0,0 +1,133 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { + Button, + Dropdown, + RadioControl, + __experimentalVStack as VStack, + __experimentalText as Text, +} from '@wordpress/components'; +import { useState, useEffect, useMemo } from '@wordpress/element'; +import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import PostPanelRow from '../post-panel-row'; + +const COMMENT_OPTIONS = [ + { + label: ( + <> + { __( 'Open' ) } + + { __( 'Visitors can add new comments and replies.' ) } + + + ), + value: 'open', + }, + { + label: ( + <> + { __( 'Closed' ) } + + { __( 'Visitors cannot add new comments or replies.' ) } + + + { __( 'Existing comments remain visible.' ) } + + + ), + value: '', + }, +]; + +export default function DiscussionPanel() { + const { editEntityRecord } = useDispatch( coreStore ); + const allowCommentsOnNewPosts = useSelect( ( select ) => { + const { getEntityRecord } = select( coreStore ); + const siteSettings = getEntityRecord( 'root', 'site' ); + return siteSettings?.default_comment_status || ''; + }, [] ); + const [ commentsOnNewPostsValue, setCommentsOnNewPostsValue ] = + useState( '' ); + /* + * This hook serves to set the server-retrieved allowCommentsOnNewPosts + * value to local state. + */ + useEffect( () => { + setCommentsOnNewPostsValue( allowCommentsOnNewPosts ); + }, [ allowCommentsOnNewPosts ] ); + + // Use internal state instead of a ref to make sure that the component + // re-renders when the popover's anchor updates. + const [ popoverAnchor, setPopoverAnchor ] = useState( null ); + // Memoize popoverProps to avoid returning a new object every time. + const popoverProps = useMemo( + () => ( { + // Anchor the popover to the middle of the entire row so that it doesn't + // move around when the label changes. + anchor: popoverAnchor, + placement: 'left-start', + offset: 36, + shift: true, + } ), + [ popoverAnchor ] + ); + const setAllowCommentsOnNewPosts = ( newValue ) => { + setCommentsOnNewPostsValue( newValue ); + editEntityRecord( 'root', 'site', undefined, { + default_comment_status: newValue ? 'open' : null, + } ); + }; + return ( + + ( + + ) } + renderContent={ ( { onClose } ) => ( + <> + + + + { __( + 'Changes will apply to new posts only. Individual posts may override these settings.' + ) } + + + + + ) } + /> + + ); +} diff --git a/packages/editor/src/components/site-settings-panel/index.js b/packages/editor/src/components/site-settings-panel/index.js new file mode 100644 index 00000000000000..f1ebec6eaeb1b1 --- /dev/null +++ b/packages/editor/src/components/site-settings-panel/index.js @@ -0,0 +1,30 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { __experimentalVStack as VStack } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import BlogTitlePanel from './blog-title-panel'; +import PostsPerPagePanel from './posts-per-page-panel'; +import DiscussionPanel from './discussion-panel'; +import { store as editorStore } from '../../store'; + +export default function SiteSettingsPanel() { + const postSlug = useSelect( + ( select ) => select( editorStore ).getEditedPostAttribute( 'slug' ), + [] + ); + if ( ! [ 'home', 'index' ].includes( postSlug ) ) { + return null; + } + return ( + + + + + + ); +} diff --git a/packages/editor/src/components/site-settings-panel/posts-per-page-panel.js b/packages/editor/src/components/site-settings-panel/posts-per-page-panel.js new file mode 100644 index 00000000000000..106df0a3ef96f7 --- /dev/null +++ b/packages/editor/src/components/site-settings-panel/posts-per-page-panel.js @@ -0,0 +1,100 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { + Button, + Dropdown, + __experimentalNumberControl as NumberControl, +} from '@wordpress/components'; +import { useState, useEffect, useMemo } from '@wordpress/element'; +import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import PostPanelRow from '../post-panel-row'; + +export default function PostsPerPagePanel() { + const { editEntityRecord } = useDispatch( coreStore ); + const postsPerPage = useSelect( ( select ) => { + const { getEntityRecord } = select( coreStore ); + const siteSettings = getEntityRecord( 'root', 'site' ); + return siteSettings?.posts_per_page; + }, [] ); + const [ postsCountValue, setPostsCountValue ] = useState( 1 ); + + /* + * This hook serves to set the server-retrieved postsPerPage + * value to local state. + */ + useEffect( () => { + setPostsCountValue( postsPerPage ); + }, [ postsPerPage ] ); + + // Use internal state instead of a ref to make sure that the component + // re-renders when the popover's anchor updates. + const [ popoverAnchor, setPopoverAnchor ] = useState( null ); + // Memoize popoverProps to avoid returning a new object every time. + const popoverProps = useMemo( + () => ( { + // Anchor the popover to the middle of the entire row so that it doesn't + // move around when the label changes. + anchor: popoverAnchor, + placement: 'left-start', + offset: 36, + shift: true, + } ), + [ popoverAnchor ] + ); + const setPostsPerPage = ( newValue ) => { + setPostsCountValue( newValue ); + editEntityRecord( 'root', 'site', undefined, { + posts_per_page: newValue, + } ); + }; + return ( + + ( + + ) } + renderContent={ ( { onClose } ) => ( + <> + + + + ) } + /> + + ); +} diff --git a/packages/editor/src/components/site-settings-panel/style.scss b/packages/editor/src/components/site-settings-panel/style.scss new file mode 100644 index 00000000000000..5d41ade2dc1399 --- /dev/null +++ b/packages/editor/src/components/site-settings-panel/style.scss @@ -0,0 +1,28 @@ +.editor-site-settings-dropdown__content { + .components-popover__content { + min-width: 320px; + padding: $grid-unit-20; + } +} + +.editor-comment-status__options { + // TODO: it's not great to override component styles.. This might be resolved + // by the new radio control component. + .components-radio-control__option { + align-items: flex-start; + } + + label { + .components-text { + display: block; + margin-top: $grid-unit-05; + } + } +} + +.editor-site-settings-panel { + .editor-post-panel__row-label { + width: 38%; + } +} + diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss index a28a2db3ae4a28..a2e341b2c0a963 100644 --- a/packages/editor/src/style.scss +++ b/packages/editor/src/style.scss @@ -45,5 +45,6 @@ @import "./components/start-page-options/style.scss"; @import "./components/start-template-options/style.scss"; @import "./components/sidebar/style.scss"; +@import "./components/site-settings-panel/style.scss"; @import "./components/table-of-contents/style.scss"; @import "./components/template-areas/style.scss";