Skip to content

Commit

Permalink
Show theme, plugin or author in Added By column with appropriate icon…
Browse files Browse the repository at this point in the history
… or avatar (#36763)

* Show theme, plugin or author in Added By column with appropriate icon or avatar

* Add success and error snackbars to the templates list page (#36808)

* Add success and error snackbars to the list page

* Fix Unit Test error

* Apply 'is-navigation-open' to interface skeleton

* Fix NavigationToggle unit test

* Apply suggestions from code review

Co-authored-by: Robert Anderson <robert@noisysocks.com>

* Use deleting

* Remove snackbars for creation

* Add notices for reverting

* Fix test

* Add getLastEntityDeleteError

* Add comment

Co-authored-by: George Mamadashvili <georgemamadashvili@gmail.com>
Co-authored-by: Robert Anderson <robert@noisysocks.com>

* Show theme, plugin or author in Added By column with appropriate icon or avatar

* Fix plugin name rendering

* Add blue dot for customize templates

* Add tooltip and tidy up logic

* Fallback to showin slug

* Handle missing author by showing template as a customized theme template

* Fallback to site name and logo

* Make the avatars load in a fancy way

* Avoid icon stretch on narrow viewports

* Fix dodgy rebase

* Use core version of template and template part post types and REST endpoints

* Revert "Use core version of template and template part post types and REST endpoints"

This reverts commit 6b40260.

* Rename to AddedBy

* Use onLoad

Co-authored-by: Kai Hao <kevin830726@gmail.com>
Co-authored-by: George Mamadashvili <georgemamadashvili@gmail.com>
Co-authored-by: Robert Anderson <robert@noisysocks.com>
  • Loading branch information
4 people committed Nov 29, 2021
1 parent df38b3d commit 812fa1b
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 1 deletion.
8 changes: 8 additions & 0 deletions packages/core-data/src/entities.js
Expand Up @@ -154,6 +154,14 @@ export const defaultEntities = [
baseURLParams: { context: 'edit' },
key: 'stylesheet',
},
{
label: __( 'Plugins' ),
name: 'plugin',
kind: 'root',
baseURL: '/wp/v2/plugins',
baseURLParams: { context: 'edit' },
key: 'plugin',
},
];

export const kinds = [
Expand Down
179 changes: 179 additions & 0 deletions packages/edit-site/src/components/list/added-by.js
@@ -0,0 +1,179 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import {
__experimentalHStack as HStack,
Icon,
Tooltip,
} from '@wordpress/components';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { useState } from '@wordpress/element';
import { layout as themeIcon, plugins as pluginIcon } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';

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

function CustomizedTooltip( { isCustomized, children } ) {
if ( ! isCustomized ) {
return children;
}

return (
<Tooltip text={ __( 'This template has been customized' ) }>
{ children }
</Tooltip>
);
}

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

return (
<HStack alignment="left">
<CustomizedTooltip isCustomized={ isCustomized }>
<div
className={ classnames( 'edit-site-list-added-by__icon', {
'is-customized': isCustomized,
} ) }
>
<Icon icon={ themeIcon } />
</div>
</CustomizedTooltip>
<span>{ theme?.name?.rendered || slug }</span>
</HStack>
);
}

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

return (
<HStack alignment="left">
<CustomizedTooltip isCustomized={ isCustomized }>
<div className="edit-site-list-added-by__icon">
<Icon icon={ pluginIcon } />
</div>
</CustomizedTooltip>
<span>{ plugin?.name || slug }</span>
</HStack>
);
}

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

return (
<HStack alignment="left">
<div
className={ classnames( 'edit-site-list-added-by__avatar', {
'is-loaded': isImageLoaded,
} ) }
>
<img
onLoad={ () => setIsImageLoaded( true ) }
alt=""
src={ user?.avatar_urls[ 48 ] }
/>
</div>
<span>{ user?.nickname }</span>
</HStack>
);
}

function AddedBySite() {
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,
};
}, [] );
const [ isImageLoaded, setIsImageLoaded ] = useState( false );

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

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' }
/>
);
}

// 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' }
/>
);
}

// 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 />;
}
}

// Simply show the author for templates created from scratch that have an
// author or for any other post type.
return <AddedByAuthor id={ template.author } />;
}
52 changes: 52 additions & 0 deletions packages/edit-site/src/components/list/style.scss
Expand Up @@ -154,3 +154,55 @@
margin-right: $grid-unit-10;
}
}

.edit-site-list-added-by__icon {
display: flex;
flex-shrink: 0;
position: relative;
align-items: center;
justify-content: center;
width: $grid-unit-40;
height: $grid-unit-40;
background: $gray-800;
border-radius: 100%;

svg {
fill: $white;
}

&.is-customized::after {
position: absolute;
content: "";
background: var(--wp-admin-theme-color);
height: $grid-unit-10;
width: $grid-unit-10;
outline: 2px solid $white;
border-radius: 100%;
top: -1px;
right: -1px;
}
}

.edit-site-list-added-by__avatar {
flex-shrink: 0;
overflow: hidden;
border-radius: 100%;
background: $gray-800;
width: $grid-unit-40;
height: $grid-unit-40;

img {
width: $grid-unit-40;
height: $grid-unit-40;
object-fit: cover;
opacity: 0;
transition: opacity 0.1s linear;
@include reduce-motion("transition");
}

&.is-loaded {
img {
opacity: 1;
}
}
}
6 changes: 5 additions & 1 deletion packages/edit-site/src/components/list/table.js
Expand Up @@ -14,6 +14,7 @@ import { addQueryArgs } from '@wordpress/url';
* Internal dependencies
*/
import Actions from './actions';
import AddedBy from './added-by';

export default function Table( { templateType } ) {
const { templates, isLoading, postType } = useSelect(
Expand Down Expand Up @@ -104,7 +105,10 @@ export default function Table( { templateType } ) {
</td>

<td className="edit-site-list-table-column" role="cell">
{ template.theme }
<AddedBy
templateType={ templateType }
template={ template }
/>
</td>
<td className="edit-site-list-table-column" role="cell">
<Actions template={ template } />
Expand Down

0 comments on commit 812fa1b

Please sign in to comment.