Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Site Editor: Add "Added by" description to template part navigation sidebar #48732

Merged
merged 11 commits into from
Mar 15, 2023
253 changes: 113 additions & 140 deletions packages/edit-site/src/components/list/added-by.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { __experimentalHStack as HStack, Icon } from '@wordpress/components';
import { Icon, __experimentalHStack as HStack } from '@wordpress/components';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { useState } from '@wordpress/element';
Expand All @@ -20,23 +20,122 @@ import { _x } from '@wordpress/i18n';

const TEMPLATE_POST_TYPE_NAMES = [ 'wp_template', 'wp_template_part' ];

function BaseAddedBy( { text, icon, imageUrl, isCustomized, templateType } ) {
/**
*
* @typedef AddedByData
* @type {Object}
* @property {JSX.Element} icon The icon to display.
* @property {string} [imageUrl] The optional image URL to display.
* @property {string} [text] The text to display.
* @property {boolean} isCustomized Whether the template has been customized.
*
* @param {Object} template The template object.
* @return {AddedByData} The added by object or null.
*/
export function useAddedBy( template ) {
youknowriad marked this conversation as resolved.
Show resolved Hide resolved
return useSelect(
( select ) => {
const { getTheme, getPlugin, getEntityRecord, getMedia, getUser } =
select( coreStore );
if ( TEMPLATE_POST_TYPE_NAMES.includes( template.type ) ) {
// Added by theme.
// Template originally provided by a theme, but customized by a user.
// Templates originally didn't have the 'origin' field so identify
// older customized templates by checking for no origin and a 'theme'
// or 'custom' source.
if (
template.has_theme_file &&
( template.origin === 'theme' ||
( ! template.origin &&
[ 'theme', 'custom' ].includes(
template.source
) ) )
) {
return {
icon: themeIcon,
text:
getTheme( template.theme )?.name?.rendered ||
template.theme,
isCustomized: template.source === 'custom',
};
}

// Added by plugin.
if ( template.has_theme_file && template.origin === 'plugin' ) {
return {
icon: pluginIcon,
text:
getPlugin( template.theme )?.name || template.theme,
isCustomized: template.source === 'custom',
};
}

// Added by site.
// Template was created from scratch, but has no author. Author support
// was only added to templates in WordPress 5.9. Fallback to showing the
// site logo and title.
if (
! template.has_theme_file &&
template.source === 'custom' &&
! template.author
) {
const siteData = getEntityRecord(
'root',
'__unstableBase'
);
return {
icon: globeIcon,
imageUrl: siteData?.site_logo
? getMedia( siteData.site_logo )?.source_url
: undefined,
text: siteData?.name,
isCustomized: false,
};
}
}

// Added by user.
const user = getUser( template.author );
return {
icon: authorIcon,
imageUrl: user?.avatar_urls?.[ 48 ],
text: user?.nickname,
isCustomized: false,
};
},
[ template ]
);
}

/**
* @param {Object} props
* @param {string} props.imageUrl
*/
function AvatarImage( { imageUrl } ) {
const [ isImageLoaded, setIsImageLoaded ] = useState( false );

return (
<div
className={ classnames( 'edit-site-list-added-by__avatar', {
'is-loaded': isImageLoaded,
} ) }
>
<img
onLoad={ () => setIsImageLoaded( true ) }
alt=""
src={ imageUrl }
/>
</div>
);
}

export default function AddedBy( { template } ) {
const { text, icon, imageUrl, isCustomized } = useAddedBy( template );

return (
<HStack alignment="left">
{ imageUrl ? (
<div
className={ classnames( 'edit-site-list-added-by__avatar', {
'is-loaded': isImageLoaded,
} ) }
>
<img
onLoad={ () => setIsImageLoaded( true ) }
alt=""
src={ imageUrl }
/>
</div>
<AvatarImage imageUrl={ imageUrl } />
) : (
<div className="edit-site-list-added-by__icon">
<Icon icon={ icon } />
Expand All @@ -46,7 +145,7 @@ function BaseAddedBy( { text, icon, imageUrl, isCustomized, templateType } ) {
{ text }
{ isCustomized && (
<span className="edit-site-list-added-by__customized-info">
{ templateType === 'wp_template'
{ template.type === 'wp_template'
? _x( 'Customized', 'template' )
: _x( 'Customized', 'template part' ) }
</span>
Expand All @@ -55,129 +154,3 @@ function BaseAddedBy( { text, icon, imageUrl, isCustomized, templateType } ) {
</HStack>
);
}

function AddedByTheme( { slug, isCustomized, templateType } ) {
const theme = useSelect(
( select ) => select( coreStore ).getTheme( slug ),
[ slug ]
);

return (
<BaseAddedBy
icon={ themeIcon }
text={ theme?.name?.rendered || slug }
isCustomized={ isCustomized }
templateType={ templateType }
/>
);
}

function AddedByPlugin( { slug, isCustomized, templateType } ) {
const plugin = useSelect(
( select ) => select( coreStore ).getPlugin( slug ),
[ slug ]
);

return (
<BaseAddedBy
icon={ pluginIcon }
text={ plugin?.name || slug }
isCustomized={ isCustomized }
templateType={ templateType }
/>
);
}

function AddedByAuthor( { id, templateType } ) {
const user = useSelect(
( select ) => select( coreStore ).getUser( id ),
[ id ]
);

return (
<BaseAddedBy
icon={ authorIcon }
imageUrl={ user?.avatar_urls?.[ 48 ] }
text={ user?.nickname }
templateType={ templateType }
/>
);
}

function AddedBySite( { templateType } ) {
const { name, logoURL } = useSelect( ( select ) => {
const { getEntityRecord, getMedia } = select( coreStore );
const siteData = getEntityRecord( 'root', '__unstableBase' );

return {
name: siteData?.name,
logoURL: siteData?.site_logo
? getMedia( siteData.site_logo )?.source_url
: undefined,
};
}, [] );

return (
<BaseAddedBy
icon={ globeIcon }
imageUrl={ logoURL }
text={ name }
templateType={ templateType }
/>
);
}

export default function AddedBy( { templateType, template } ) {
if ( ! template ) {
return;
}

if ( TEMPLATE_POST_TYPE_NAMES.includes( templateType ) ) {
// Template originally provided by a theme, but customized by a user.
// Templates originally didn't have the 'origin' field so identify
// older customized templates by checking for no origin and a 'theme'
// or 'custom' source.
if (
template.has_theme_file &&
( template.origin === 'theme' ||
( ! template.origin &&
[ 'theme', 'custom' ].includes( template.source ) ) )
) {
return (
<AddedByTheme
slug={ template.theme }
isCustomized={ template.source === 'custom' }
templateType={ templateType }
/>
);
}

// Template originally provided by a plugin, but customized by a user.
if ( template.has_theme_file && template.origin === 'plugin' ) {
return (
<AddedByPlugin
slug={ template.theme }
isCustomized={ template.source === 'custom' }
templateType={ templateType }
/>
);
}

// Template was created from scratch, but has no author. Author support
// was only added to templates in WordPress 5.9. Fallback to showing the
// site logo and title.
if (
! template.has_theme_file &&
template.source === 'custom' &&
! template.author
) {
return <AddedBySite templateType={ templateType } />;
}
}

// Simply show the author for templates created from scratch that have an
// author or for any other post type.
return (
<AddedByAuthor id={ template.author } templateType={ templateType } />
);
}
7 changes: 3 additions & 4 deletions packages/edit-site/src/components/list/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,9 @@ export default function Table( { templateType } ) {
</td>

<td className="edit-site-list-table-column" role="cell">
<AddedBy
templateType={ templateType }
template={ template }
/>
{ template ? (
<AddedBy template={ template } />
) : null }
</td>
<td className="edit-site-list-table-column" role="cell">
<Actions template={ template } />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,29 @@ import useEditedEntityRecord from '../use-edited-entity-record';
import { unlock } from '../../private-apis';
import { store as editSiteStore } from '../../store';
import SidebarButton from '../sidebar-button';
import { useAddedBy } from '../list/added-by';

function AddedByDescription( { template } ) {
const addedBy = useAddedBy( template );

if ( ! addedBy.text ) return null;

return (
<p>
{ addedBy.isCustomized
? sprintf(
/* translators: %s: The author. Could be either the theme's name, plugin's name, or user's name. */
__( 'Added by %s (customized).' ),
addedBy.text
)
: sprintf(
/* translators: %s: The author. Could be either the theme's name, plugin's name, or user's name. */
__( 'Added by %s.' ),
addedBy.text
) }
</p>
);
}

export default function SidebarNavigationScreenTemplate() {
const { params } = useNavigator();
Expand Down Expand Up @@ -49,6 +72,7 @@ export default function SidebarNavigationScreenTemplate() {
/>
}
description={ description }
content={ <AddedByDescription template={ record } /> }
/>
);
}