forked from WordPress/gutenberg
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Style book: create static categories (WordPress#65430)
This commit creates a static category map based on list defined in Style Book: Iterate on presentation and design. WordPress#53431. It also: - Sorts examples based on static categories and their subcategories - Introduces simple layout for subcategories (under theme) - Adds unit tests for utils - Converts utils to TypeScript Co-authored-by: ramonjd <[email protected]> Co-authored-by: aaronrobertshaw <[email protected]> Co-authored-by: vcanales <[email protected]> Co-authored-by: jasmussen <[email protected]>
- Loading branch information
Showing
7 changed files
with
609 additions
and
158 deletions.
There are no files selected for viewing
91 changes: 91 additions & 0 deletions
91
packages/edit-site/src/components/style-book/categories.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { getCategories } from '@wordpress/blocks'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import type { | ||
BlockExample, | ||
StyleBookCategory, | ||
CategoryExamples, | ||
} from './types'; | ||
import { | ||
STYLE_BOOK_CATEGORIES, | ||
STYLE_BOOK_THEME_SUBCATEGORIES, | ||
} from './constants'; | ||
|
||
/** | ||
* Returns category examples for a given category definition and list of examples. | ||
* @param {StyleBookCategory} categoryDefinition The category definition. | ||
* @param {BlockExample[]} examples An array of block examples. | ||
* @return {CategoryExamples|undefined} An object containing the category examples. | ||
*/ | ||
export function getExamplesByCategory( | ||
categoryDefinition: StyleBookCategory, | ||
examples: BlockExample[] | ||
): CategoryExamples | undefined { | ||
if ( ! categoryDefinition?.slug || ! examples?.length ) { | ||
return; | ||
} | ||
|
||
if ( categoryDefinition?.subcategories?.length ) { | ||
return categoryDefinition.subcategories.reduce( | ||
( acc, subcategoryDefinition ) => { | ||
const subcategoryExamples = getExamplesByCategory( | ||
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, | ||
}; | ||
} | ||
|
||
/** | ||
* Returns category examples for a given category definition and list of examples. | ||
* | ||
* @return {StyleBookCategory[]} An array of top-level category definitions. | ||
*/ | ||
export function getTopLevelStyleBookCategories(): StyleBookCategory[] { | ||
const reservedCategories = [ | ||
...STYLE_BOOK_THEME_SUBCATEGORIES, | ||
...STYLE_BOOK_CATEGORIES, | ||
].map( ( { slug } ) => slug ); | ||
const extraCategories = getCategories().filter( | ||
( { slug } ) => ! reservedCategories.includes( slug ) | ||
); | ||
return [ ...STYLE_BOOK_CATEGORIES, ...extraCategories ]; | ||
} |
191 changes: 191 additions & 0 deletions
191
packages/edit-site/src/components/style-book/constants.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import type { StyleBookCategory } from './types'; | ||
|
||
export const STYLE_BOOK_THEME_SUBCATEGORIES: Omit< | ||
StyleBookCategory, | ||
'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: StyleBookCategory[] = [ | ||
{ | ||
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; | ||
} | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __, sprintf } from '@wordpress/i18n'; | ||
import { | ||
getBlockType, | ||
getBlockTypes, | ||
getBlockFromExample, | ||
createBlock, | ||
} from '@wordpress/blocks'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import type { BlockExample } from './types'; | ||
|
||
/** | ||
* Returns a list of examples for registered block types. | ||
* | ||
* @return {BlockExample[]} An array of block examples. | ||
*/ | ||
export function getExamples(): BlockExample[] { | ||
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 ]; | ||
} |
Oops, something went wrong.