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

Style book: create static categories #65430

Open
wants to merge 15 commits into
base: trunk
Choose a base branch
from
87 changes: 87 additions & 0 deletions packages/edit-site/src/components/style-book/categories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* categoryDefinition object.
*
* @typedef {Object} StyleBookCategory
*
* @property {string} slug Category identifier.
* @property {string} title Category title/label.
* @property {Array?} blocks Array of block names to include in the category. Used when blocks are not included in the category by default.
* @property {Array?} excludes Array of blocks to exclude from the category. Used when blocks are included in the category by default.
Copy link
Member Author

@ramonjd ramonjd Sep 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if I should just convert this all to TS

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One step at a time?

It could easily be a follow-up but if you're going to pull the trigger on it, maybe before we get too deep into the weeds iterating on then Style Book?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good call. That was a 🧠 🌬️

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't see your reply before leaving my review which sort of flip-flopped. I think eventually we'll end up doing it. Now, or in a follow-up, I don't think it matters greatly.

*/

/**
* blockExamples object.
*
* @typedef {Object} blockExamples
*
* @property {string} name Block name, e.g., "core/paragraph".
* @property {string} title Block title/label.
* @property {string} category Block category.
* @property {Object} blocks Block object.
*/

/**
* getCategoryExamples return value.
*
* @typedef {Object} CategoryExamples
*
* @property {string} slug Category identifier.
* @property {string} title Category title/label.
* @property {Array<blockExamples>?} examples Array of block examples.
* @property {Array<CategoryExamples>?} subcategories Array of subcategory examples.
*/

/**
* Returns category examples for a given category definition and list of examples.
* @param {StyleBookCategory} categoryDefinition The category definition.
* @param {Array<blockExamples>} examples An array of block examples.
* @return {CategoryExamples|undefined} An object containing the category examples.
*/
export function getCategoryExamples( categoryDefinition, examples ) {
if ( ! categoryDefinition?.slug || ! examples?.length ) {
return;
}

if ( categoryDefinition?.subcategories?.length ) {
return categoryDefinition.subcategories.reduce(
( acc, subcategoryDefinition ) => {
const subcategoryExamples = getCategoryExamples(
subcategoryDefinition,
examples
);
if ( subcategoryExamples ) {
acc.subcategories = [
...acc.subcategories,
subcategoryExamples,
];
}
return acc;
},
{
title: categoryDefinition.title,
slug: categoryDefinition.slug,
subcategories: [],
}
);
}

const blocksToInclude = categoryDefinition?.blocks || [];
const blocksToExclude = categoryDefinition?.exclude || [];
const categoryExamples = examples.filter( ( example ) => {
return (
! blocksToExclude.includes( example.name ) &&
( example.category === categoryDefinition.slug ||
blocksToInclude.includes( example.name ) )
);
} );

if ( ! categoryExamples.length ) {
return;
}

return {
title: categoryDefinition.title,
slug: categoryDefinition.slug,
examples: categoryExamples,
};
}
183 changes: 183 additions & 0 deletions packages/edit-site/src/components/style-book/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';

export const STYLE_BOOK_THEME_SUBCATEGORIES = [
{
slug: 'site-identity',
title: __( 'Site Identity' ),
blocks: [ 'core/site-logo', 'core/site-title', 'core/site-tagline' ],
},
{
slug: 'design',
title: __( 'Design' ),
blocks: [ 'core/navigation', 'core/avatar', 'core/post-time-to-read' ],
exclude: [ 'core/home-link', 'core/navigation-link' ],
},
{
slug: 'posts',
title: __( 'Posts' ),
blocks: [
'core/post-title',
'core/post-excerpt',
'core/post-author',
'core/post-author-name',
'core/post-author-biography',
'core/post-date',
'core/post-terms',
'core/term-description',
'core/query-title',
'core/query-no-results',
'core/query-pagination',
'core/query-numbers',
],
},
{
slug: 'comments',
title: __( 'Comments' ),
blocks: [
'core/comments-title',
'core/comments-pagination',
'core/comments-pagination-numbers',
'core/comments',
'core/comments-author-name',
'core/comment-content',
'core/comment-date',
'core/comment-edit-link',
'core/comment-reply-link',
'core/comment-template',
'core/post-comments-count',
'core/post-comments-link',
],
},
];

export const STYLE_BOOK_CATEGORIES = [
{
slug: 'text',
title: __( 'Text' ),
blocks: [
'core/post-content',
'core/home-link',
'core/navigation-link',
],
},
{
slug: 'colors',
title: __( 'Colors' ),
blocks: [ 'custom/colors' ],
},
{
slug: 'theme',
title: __( 'Theme' ),
subcategories: STYLE_BOOK_THEME_SUBCATEGORIES,
},
{
slug: 'media',
title: __( 'Media' ),
blocks: [ 'core/post-featured-image' ],
},
{
slug: 'widgets',
title: __( 'Widgets' ),
blocks: [],
},
{
slug: 'embed',
title: __( 'Embeds' ),
include: [],
},
];

// The content area of the Style Book is rendered within an iframe so that global styles
// are applied to elements within the entire content area. To support elements that are
// not part of the block previews, such as headings and layout for the block previews,
// additional CSS rules need to be passed into the iframe. These are hard-coded below.
// Note that button styles are unset, and then focus rules from the `Button` component are
// applied to the `button` element, targeted via `.edit-site-style-book__example`.
// This is to ensure that browser default styles for buttons are not applied to the previews.
export const STYLE_BOOK_IFRAME_STYLES = `
// Forming a "block formatting context" to prevent margin collapsing.
// @see https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context
.is-root-container {
display: flow-root;
}

body {
position: relative;
padding: 32px !important;
}

.edit-site-style-book__examples {
max-width: 1200px;
margin: 0 auto;
}

.edit-site-style-book__example {
max-width: 900px;
border-radius: 2px;
cursor: pointer;
display: flex;
flex-direction: column;
gap: 40px;
padding: 16px;
width: 100%;
box-sizing: border-box;
scroll-margin-top: 32px;
scroll-margin-bottom: 32px;
margin: 0 auto 40px auto;
}

.edit-site-style-book__example.is-selected {
box-shadow: 0 0 0 1px var(--wp-components-color-accent, var(--wp-admin-theme-color, #007cba));
}

.edit-site-style-book__example:focus:not(:disabled) {
box-shadow: 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #007cba));
outline: 3px solid transparent;
}

.edit-site-style-book__examples.is-wide .edit-site-style-book__example {
flex-direction: row;
}

.edit-site-style-book__subcategory-title,
.edit-site-style-book__example-title {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
font-size: 11px;
font-weight: 500;
line-height: normal;
margin: 0;
text-align: left;
text-transform: uppercase;
}

.edit-site-style-book__subcategory-title {
font-size: 16px;
margin-bottom: 40px;
border-bottom: 1px solid #ddd;
padding-bottom: 8px;
}

.edit-site-style-book__examples.is-wide .edit-site-style-book__example-title {
text-align: right;
width: 120px;
}

.edit-site-style-book__example-preview {
width: 100%;
}

.edit-site-style-book__example-preview .block-editor-block-list__insertion-point,
.edit-site-style-book__example-preview .block-list-appender {
display: none;
}

.edit-site-style-book__example-preview .is-root-container > .wp-block:first-child {
margin-top: 0;
}
.edit-site-style-book__example-preview .is-root-container > .wp-block:last-child {
margin-bottom: 0;
}
`;
70 changes: 70 additions & 0 deletions packages/edit-site/src/components/style-book/examples.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import {
getBlockType,
getBlockTypes,
getBlockFromExample,
createBlock,
} from '@wordpress/blocks';

/**
* blockExamples object.
*
* @typedef {Object} blockExamples
*
* @property {string} name Block name, e.g., "core/paragraph".
* @property {string} title Block title/label.
* @property {string} category Block category.
* @property {Object} blocks Block object.
*/

/**
* Returns a list of examples for registered block types.
*
* @return {Array<blockExamples>} An array of block examples.
*/
export function getExamples() {
const nonHeadingBlockExamples = getBlockTypes()
.filter( ( blockType ) => {
const { name, example, supports } = blockType;
return (
name !== 'core/heading' &&
!! example &&
supports.inserter !== false
);
} )
.map( ( blockType ) => ( {
name: blockType.name,
title: blockType.title,
category: blockType.category,
blocks: getBlockFromExample( blockType.name, blockType.example ),
} ) );

const isHeadingBlockRegistered = !! getBlockType( 'core/heading' );

if ( ! isHeadingBlockRegistered ) {
return nonHeadingBlockExamples;
}

// Use our own example for the Heading block so that we can show multiple
// heading levels.
const headingsExample = {
name: 'core/heading',
title: __( 'Headings' ),
category: 'text',
blocks: [ 1, 2, 3, 4, 5, 6 ].map( ( level ) => {
return createBlock( 'core/heading', {
content: sprintf(
// translators: %d: heading level e.g: "1", "2", "3"
__( 'Heading %d' ),
level
),
level,
} );
} ),
};

return [ headingsExample, ...nonHeadingBlockExamples ];
}
Loading
Loading