Skip to content

Commit

Permalink
Merge pull request #793 from plone/effectiveVolto2023
Browse files Browse the repository at this point in the history
Effective Volto 2023
  • Loading branch information
sneridagh authored Oct 1, 2023
2 parents 32f9910 + 99e4a21 commit 6087185
Show file tree
Hide file tree
Showing 62 changed files with 1,099 additions and 421 deletions.
2 changes: 1 addition & 1 deletion docs/effective-volto/about_effective_volto.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Tiberiu Ichim

Víctor Fernández de Alba

: Víctor is CTO at kitconcept GmbH, a Plone solution provider from Bonn, Germany. Member of the Plone Community since 2006, author of a Plone book, co-author of Plone 5’s multilingual feature and its default theme Barceloneta. He is the Plone 6 Volto Release Manager, member of the Volto Team and Plone REST API contributor. He was also organizer of the Barcelona Plone Conference in 2017, sprints and other Plone events in Barcelona and Bonn and he is deeply involved in several Plone Community Teams including the Plone Foundation Board of directors.
: Víctor is CTO at kitconcept GmbH, a Plone solution provider from Bonn, Germany. Member of the Plone Community since 2006, currently he's the Release Manager of Plone Volto and Volto Team leader. Author of a Plone book, co-author of Plone 5’s multilingual feature and its default theme Barceloneta. He is the Plone 6 Volto Release Manager, member of the Volto Team and Plone REST API contributor. He was also organizer of the Barcelona Plone Conference in 2017, sprints and other Plone events in Barcelona and Bonn and he is deeply involved in several Plone Community Teams.

## License

Expand Down
12 changes: 7 additions & 5 deletions docs/effective-volto/addons/asyncconnect.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ components, making it an isomorphic application.

How does that work? In simplified pseudocode, it works like this:

- in server.jsx we have code like `react-dom.renderToString(<Router/>)`
- in Volto's `server.jsx` we convert the React component tree to an HTML string
with `react-dom.renderToString(<Router routes={routes} />)`
- the Router renders its declared components, which is the `App` and its
direct child, the `View` component

Expand Down Expand Up @@ -68,12 +69,13 @@ prefetch a `footer-links` page from the backend and include it with every SSR:
];
```
Note: this example is a low-tech "frontend-er only" solution. In real life you
will probably want to devise a mechanism where that footer-links information is
Note: this example is a low-tech "frontend only" solution. In real life you
will probably want to create a mechanism where that footer-links information is
automatically included with every content request.
Notice the extender mechanism, we register a "modifier" for the current list of
"async connect dispatch actions".
As you can see from the above example, the configuration registration is done
by using a "modifier" of all the other registered asyncPropsExtender, so we
can even change that list of extenders, with something like:
```
config.settings.asyncPropsExtenders = [
Expand Down
6 changes: 3 additions & 3 deletions docs/effective-volto/addons/block-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ myst:

# Block Extensions

A common pattern in blocks is the "variations" pattern - a slightly different
A common pattern in blocks is the "variations" UI pattern - a slightly different
versions of a block that can be toggled on demand by the editors. Choosing the
listing template (gallery, summary listing, etc.) for the `Listing` block is
one example of the typical use cases for this feature.
one example of the typical use case for this feature.

A block can define variations in the block configuration. These variations can
A block defines variations in its block configuration. These variations can
be used to enhance or complement the default behavior of a block without having
to shadow its stock components. These enhancements can be at the settings level
(add or remove block settings) via schema enhancers or, if the code of your
Expand Down
196 changes: 160 additions & 36 deletions docs/effective-volto/addons/block-styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,39 +25,72 @@ See below for an example.
## Enabling Style Wrapper in a block

The wrapper is always present in the rendering of both the view and edit components.
If you want to add the default set of styles, you need to enable them with the following flag:
The wrapper expects an object field `styles` in the block's schema, so there's a helper available to enable it via a block `schemaEnhancer` that does this for you called `addStyling`.

```{note}
The style wrapper only will work if your block uses the `BlocksForm` component to define schema-driven block configuration settings.
```

```js
// (in your block config object)
my_custom_block: {
// (more block settings)
enableStyling: true,
}
import { addStyling } from '@plone/volto/helpers/Extensions/withBlockSchemaEnhancer';

export const defaultStylingSchema = ({ schema, formData, intl }) => {

addStyling({ schema, intl });

return schema;
};
```

```{note}
This will work if your block uses the `BlocksForm` component to define schema-driven block configuration settings.
The signature for a `schemaEnhancer` is `({schema, formData, intl})`. You can find the reference of the default schema in `@plone/volto/components/manage/Blocks/Block/StylesSchema`.
```

Then in the block's config:

```js
config.blocks.blocksConfig.myBlock = {
...config.blocks.blocksConfig.myBlock,
schemaEnhancer: defaultStylingSchema,
};
```

This will add a new fieldset `Styling` at the end of your block schema settings with a single `styles` object field in it.
By default, this object field has only one field: `align`. It is configured by `defaultSchema` in `src/components/manage/Blocks/Block/StylesSchema.jsx`.

## Extending the default `styles` field in `Styling` fieldset

You can modify the default set of styles by using a `schemaEnhancer` function in the same way that you would for any block schema enhancer.
Use the `stylesSchema` key in your block configuration object as follows:
You can modify the default set of styles by using the `schemaEnhancer` function previously mentioned like this:

```js
// (in your block config object)
my_custom_block: {
// (more block settings)
enableStyling: true,
stylesSchema: myCustomStyleSchema
}
```

```{note}
The signature for a `schemaEnhancer` is `({schema, formData, intl})`. You can find the reference of the default schema in `@plone/volto/components/manage/Blocks/Block/StylesSchema`.
import { addStyling } from '@plone/volto/helpers/Extensions/withBlockSchemaEnhancer';

export const defaultStylingSchema = ({ schema, formData, intl }) => {
const BG_COLORS = [
{ name: 'transparent', label: 'Transparent' },
{ name: 'grey', label: 'Grey' },
];

const colors =
config.blocks?.blocksConfig?.[formData['@type']]?.colors || BG_COLORS;

const defaultBGColor =
config.blocks?.blocksConfig?.[formData['@type']]?.defaultBGColor;

addStyling({ schema, intl });

schema.properties.styles.schema.fieldsets[0].fields = [
...schema.properties.styles.schema.fieldsets[0].fields,
'backgroundColor',
];
schema.properties.styles.schema.properties.backgroundColor = {
widget: 'color_picker',
title: intl.formatMessage(messages.backgroundColor),
colors,
default: defaultBGColor,
};

return schema;
};
```
## The `styles` field
Expand All @@ -78,7 +111,7 @@ The `stylesSchema` adds the fields into this field, creating an object that is t
}
```
## Using `className` in your block
## Using `className` in your block view component
The resultant class names are injected as a `className` prop into the wrapped block.
Thus you can use it in the root component of your block view and edit components as follows:
Expand All @@ -91,7 +124,6 @@ const BlockView = (props)=> (
)
```
Same for the block edit component.
The resultant HTML would be the following:
```html
Expand All @@ -100,6 +132,97 @@ The resultant HTML would be the following:
Then it's at your discretion how you define the CSS class names in your theme.
The block editor wrapper does the same for the block edit component, but it's automatically injected into the wrapper containers.
```html
<div data-rbd-draggable-context-id="0" data-rbd-draggable-id="9949a5fa-5d57-4e0c-a150-71149a31096c" class="block-editor-listing has--backgroundColor--ee22ee has--myCustomStyleField--red has--myCustom2StyleField--color--black has--myCustom2StyleField--color--MyGradient">
...
</div>
```
## `styleClassNameConverters`
If you need other style of classnames generated, you can use the classname
converters defined in `config.settings.styleClassNameConverters`, by
registering fieldnames suffixed with the converter name. For example, a style
data like:
```
{
"styles": {
"theme:noprefix": "primary",
"inverted:bool": true,
}
}
```
will generate classnames `primary inverted`. This relies on the `noprefix` and `bool` converters that are registered in Volto.
## `styleClassNameExtenders`
An array containing functions that extends how the StyleWrapper builds a list of styles. These functions have the signature `({ block, content, data, classNames }) => classNames`. Here are some examples of useful ones, for simplicity, they are compacted in one extender:
```js
import { getPreviousNextBlock } from '@plone/volto/helpers';

config.settings.styleClassNameExtenders = [
({ block, content, data, classNames }) => {
let styles = [];
const [previousBlock, nextBlock] = getPreviousNextBlock({
content,
block,
});

// Inject a class depending of which type is the next block
if (nextBlock?.['@type']) {
styles.push(`next--is--${nextBlock['@type']}`);
}

// Inject a class depending if previous is the same type of block
if (data?.['@type'] === previousBlock?.['@type']) {
styles.push('previous--is--same--block-type');
}

// Inject a class depending if next is the same type of block
if (data?.['@type'] === nextBlock?.['@type']) {
styles.push('next--is--same--block-type');
}

// Inject a class depending if it's the first of block type
if (data?.['@type'] !== previousBlock?.['@type']) {
styles.push('is--first--of--block-type');
}

// Inject a class depending if it's the last of block type
if (data?.['@type'] !== nextBlock?.['@type']) {
styles.push('is--last--of--block-type');
}

// Given a StyleWrapper defined `backgroundColor` style
const previousColor =
previousBlock?.styles?.backgroundColor ?? 'transparent';
const currentColor = data?.styles?.backgroundColor ?? 'transparent';
const nextColor = nextBlock?.styles?.backgroundColor ?? 'transparent';

// Inject a class depending if the previous block has the same `backgroundColor`
if (currentColor === previousColor) {
styles.push('previous--has--same--backgroundColor');
} else if (currentColor !== previousColor) {
styles.push('previous--has--different--backgroundColor');
}

// Inject a class depending if the next block has the same `backgroundColor`
if (currentColor === nextColor) {
styles.push('next--has--same--backgroundColor');
} else if (currentColor !== nextColor) {
styles.push('next--has--different--backgroundColor');
}

return [...classNames, ...styles];
},
];
```
### Using CSS variables
Once you start using the style wrapper you'll realise that simply using the
Expand All @@ -116,35 +239,36 @@ a fixed number of lines.
We'll have the following styles schema:
```js
const StyleSchema = () => (
{
fieldsets: [
{
const maxLinesSchemaEnhancer = (schema) => {
schema.properties.styles.schema.fieldsets.push({
title: 'Styling',
id: 'default',
fields: ['maxLines'],
}
],
properties: {
maxLines: {
});
schema.properties.styles.schema.properties.maxLines = {
title: 'Max lines',
description:
"Limit description to a maximum number of lines by adding trailing '...'",
type: 'number',
default: 2,
minimum: 0,
maximum: 5,
},
},
required: [],
});
};
return schema;
}
```
We'll assign it to the listing block:
```
config.blocks.blocksConfig.listing.enableStyling = true;
config.blocks.blocksConfig.listing.stylesSchema = StyleSchema;
import { composeSchema } from '@plone/volto/helpers';

// ... somewhere in the configuration function
config.blocks.blocksConfig.listing.schemaEnhancer = composeSchema(
config.blocks.blocksConfig.listing.schemaEnhancer,
maxLinesSchemaEnhancer
);
// ...
```
For the CSS part, we add the following code:
Expand Down
Loading

0 comments on commit 6087185

Please sign in to comment.