From 5e4b69963ed5f775b2f65271895f111c838841d2 Mon Sep 17 00:00:00 2001 From: Victor Fernandez de Alba Date: Sat, 9 Sep 2023 18:52:25 +0200 Subject: [PATCH 01/45] Update getting started --- docs/effective-volto/about_effective_volto.md | 2 +- .../effective-volto/getting-started/add-on.md | 145 ++++++++++++------ .../getting-started/project.md | 10 +- 3 files changed, 101 insertions(+), 56 deletions(-) diff --git a/docs/effective-volto/about_effective_volto.md b/docs/effective-volto/about_effective_volto.md index faf6bdffb..fed94bb61 100644 --- a/docs/effective-volto/about_effective_volto.md +++ b/docs/effective-volto/about_effective_volto.md @@ -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 diff --git a/docs/effective-volto/getting-started/add-on.md b/docs/effective-volto/getting-started/add-on.md index 5ce9b9505..d5d0938c2 100644 --- a/docs/effective-volto/getting-started/add-on.md +++ b/docs/effective-volto/getting-started/add-on.md @@ -18,7 +18,7 @@ they point the `main` key of their `package.json` to a module that exports, as a default function that acts as a Volto configuration loader. Although you could simply use `npm init` to generate an addon initial code, -we now have a nice +we have a [Yeoman-based generator](https://github.com/plone/generator-volto) that you can use: ```shell @@ -32,90 +32,141 @@ use the final ones from the very beginning. This means that you can use imports such as `import { Something } from '@plone/my-volto-addon'` without any extra configuration. -## Developing in isolation with a vanilla Volto project +## Developing in isolation using a full dockerized project approach -You can develop an add-on in isolation using the `@plone/scripts` `addon` command line. -This script creates and configures a vanilla project using the Volto generator. +You can develop an add-on in isolation using the boilerplate already provided by the add-on generator. The project is configured to have the current add-on installed and ready to work with. -This script is useful to bootstrap an isolated environment that can be used to quickly develop the add-on or for demo purposes. +This is useful to bootstrap an isolated environment that can be used to quickly develop the add-on or for demo purposes. It's also useful when testing an add-on in a CI environment. ```{note} It's quite similar when you develop a Plone backend add-on in the Python side, and embed a ready to use Plone build (using buildout or pip) in order to develop and test the package. ``` -Unfortunately, the NodeJS tooling does not work well with symlinks or outside the root of the project. -This script proceeds in the following way: +The dockerized approach performs all these actions in a custom built docker environment: 1. Generates a vanilla project using the official Volto Yo Generator (@plone/generator-volto) 2. Configures it to use the add-on with the name stated in the `package.json` -3. Copies over the root of the add-on (`src` and essential files) inside the created project +3. Links the root of the add-on inside the created project -After this, you can change directory to the created project, by default `addon-testing-project`. -The name of the created project is parameterizable. +After that you can use the inner dockerized project, and run any standard Volto command for linting, acceptance test or unit tests using Makefile commands provided for your convenience. -After that you can use the full fledged project, and run any standard Volto command for linting, acceptance test or unit tests. +### Setup the environment -### clone (git) +Run once -Given the add-on remote git repository, it pulls and configures it into the vanilla project generated by the script. +```shell +make dev +``` + +which will build and launch the backend and frontend containers. +There's no need to build them again after doing it the first time unless something has changed from the container setup. + +In order to make the local IDE play well with this setup, is it required to run once `yarn` to install locally the required packages (ESlint, Prettier, Stylelint). + +Run + +```shell +yarn +``` + +### Build the containers manually + +Run + +```shell +make build-backend +make build-addon +``` + +### Run the containers + +Run + +```shell +make start-dev +``` + +This will start both the frontend and backend containers. + +### Stop Backend (Docker) + +After developing, in order to stop the running backend, don't forget to run: + +Run -`npx -p @plone/scripts addon clone [options] [destination]` +```shell +make stop-backend +``` + +### Linting + +Run + +```shell +make lint +``` + +### Formatting + +Run + +```shell +make format +``` -```console - Usage: addon clone [options] [destination] +### i18n - clone a repository into a newly created directory +Run - Options: - -p, --private set if the repo is private, then GITHUB_TOKEN is used - -b, --branch set the repo branch, defaults to main - -c, --canary downloads latest Volto canary (alpha) version - -h, --help display help for command +```shell +make i18n ``` -This next command downloads the `volto-blocks-grid` add-on from its git repository's `main` branch, and will generate a project with the latest Volto canary (alpha) version. +### Unit tests + +Run ```shell -npx -p @plone/scripts addon clone https://github.com/kitconcept/volto-blocks-grid.git --branch main --canary +make test ``` -This will create a directory named `addon-testing-project`, and will bootstrap a new project using Volto's standard project generator. -It will adjust the configuration of this project to setup the add-on in the project using `mrs-developer`, and the git URL given to fetch the add-on contents. -You can specify the branch to be used, if the project should use the latest alpha available. -For private repositories, it uses the `GITHUB_TOKEN` present in your environment variables to fetch it. +### Acceptance tests -After this, as a developer you can use the usual project commands to run tests (unit, linting, acceptance) inside the generated `addon-testing-project`. -You can configure the CI of your choice for automated testing, you can take a look at how it's done in: https://github.com/kitconcept/volto-blocks-grid/tree/main/.github/workflows +Run once -The idea is to issue commands inside the generated `addon-testing-project` project and do your checks. -Take special care on how to pass down to the `npx` command the current pull request branch. -Depending on your CI system, this might be different. +```shell +make install-acceptance +``` -### clone local +For starting the servers -You can also clone the local add-on using: +Run ```shell -npx -p @plone/scripts addon clone . +make start-test-acceptance-server ``` -This only works if you execute the command from the root of your add-on directory. +The frontend is run in dev mode, so development while writing tests is possible. -### consolidate +Run -While developing, you might have done changes inside the generated project, and you most probably want to consolidate them, back into the root of the repository. -By running this script, it copies over from `addon-testing-project/src/addons/` to the root of your repository. +```shell +make test-acceptance +``` -It should be run at the root of the add-on, and it gets an optional `source` argument in case you have specified a directory other than `addon-testing-project`. +To run Cypress tests afterwards. -`npx -p @plone/scripts addon consolidate --help` +When finished, don't forget to shutdown the backend server. -```console - Usage: addon consolidate [options] [source] +```shell +make stop-test-acceptance-server +``` - Consolidate a cloned project +### Release - Options: - -h, --help display help for command +Run + +```shell +make release ``` diff --git a/docs/effective-volto/getting-started/project.md b/docs/effective-volto/getting-started/project.md index 648e68027..435dad01b 100644 --- a/docs/effective-volto/getting-started/project.md +++ b/docs/effective-volto/getting-started/project.md @@ -11,7 +11,7 @@ myst: # Bootstrapping a full Plone 6 project -We can use the new [cookiecutter-plone-starter](https://github.com/collective/cookiecutter-plone-starter) repository. +We will use the official [cookiecutter-plone-starter](https://github.com/collective/cookiecutter-plone-starter) repository. ```{note} The introduction of more tools are in store in order to ease the creation of the boilerplate for a full Plone 6 project, but they might revolve around this cookiecutter template. @@ -35,12 +35,10 @@ After that, install Yeoman according to the [Plone documentation](https://6.docs Finally, install `yarn` according to the [Plone documentation](https://6.docs.plone.org/volto/getting-started/install.html#yarn-nodejs-package-manager). - -### Docker (optional) +### Docker (optional, but recommended) Install `Docker` according to the [official documentation](https://docs.docker.com/get-docker/). - Generate a new Plone 6 Project: ```shell @@ -79,18 +77,14 @@ make build and restart backend and frontend by stopping and re-running - ```shell make start-backend ``` - ```shell make start-frontend ``` - - ## Project Generation Options These are all the template options that will be prompted by the [Cookiecutter CLI](https://github.com/cookiecutter/cookiecutter) prior to generating your project. From 1beaba5c8e2ee0ef9e76330516064ecd01075c03 Mon Sep 17 00:00:00 2001 From: Victor Fernandez de Alba Date: Sun, 10 Sep 2023 09:18:05 +0200 Subject: [PATCH 02/45] Add dataAdapter pattern --- docs/effective-volto/addons/blockdataform.md | 63 +++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/docs/effective-volto/addons/blockdataform.md b/docs/effective-volto/addons/blockdataform.md index ae386c7f8..9609f46c1 100644 --- a/docs/effective-volto/addons/blockdataform.md +++ b/docs/effective-volto/addons/blockdataform.md @@ -13,7 +13,7 @@ The BlockDataForm renders an form fully integrated with a block's extension mechanisms: variations and block styles. To use it, instantiate the schema and pass it down to the component. A full Volto block edit component could be like: -``` +```jsx export const MyBlockSchema = ({data, intl}) => { return { title: "My block", @@ -62,6 +62,9 @@ export const MyBlockEdit = (props) => { }); }} formData={data} + onChangeBlock={onChangeBlock} + block={block} + blocksConfig={blocksConfig} /> @@ -76,7 +79,7 @@ If there's any registered variations for this block, they will be displayed as a Select control for the active variation, in the sidebar. -``` +```js myblock: { id: 'myblock', title: 'My Block', @@ -112,3 +115,59 @@ a Select control for the active variation, in the sidebar. Note: you can assign the schema to `blockSchema` in the block configuration. It is used only to extract the block default values. This integration will be improved, in the future. + +## Using a dataAdapter pattern + +Sometimes is useful to adapt the incoming data to other data format, structure or type. +You can use the dataAdapter pattern in `BlockDataForm` as this: + +```jsx + const schema = blocksConfig[data['@type']].blockSchema({ intl }); + const dataAdapter = blocksConfig[data['@type']].dataAdapter; + + { + dataAdapter({ + block, + data, + id, + onChangeBlock, + value, + }); + }} + onChangeBlock={onChangeBlock} + formData={data} + block={block} + blocksConfig={blocksConfig} + /> +``` + +and define `dataAdapter` as this: + +```js +import { isEmpty } from 'lodash'; + +export const TeaserBlockDataAdapter = ({ + block, + data, + id, + onChangeBlock, + value, +}) => { + let dataSaved = { + ...data, + [id]: value, + }; + if (id === 'href' && !isEmpty(value) && !data.title && !data.description) { + dataSaved = { + ...dataSaved, + title: value[0].Title, + description: value[0].Description, + head_title: value[0].head_title, + }; + } + onChangeBlock(block, dataSaved); +}; +``` From b90901040788a0877fcdc3ac25dc1b3776fc85d9 Mon Sep 17 00:00:00 2001 From: Victor Fernandez de Alba Date: Sun, 10 Sep 2023 10:03:33 +0200 Subject: [PATCH 03/45] Blocks layout and blocks styling updates --- docs/effective-volto/addons/block-styling.md | 168 ++++++++++++++++--- docs/effective-volto/addons/blockslayout.md | 6 +- 2 files changed, 146 insertions(+), 28 deletions(-) diff --git a/docs/effective-volto/addons/block-styling.md b/docs/effective-volto/addons/block-styling.md index f62dff5d7..1a7f1ee17 100644 --- a/docs/effective-volto/addons/block-styling.md +++ b/docs/effective-volto/addons/block-styling.md @@ -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 @@ -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: @@ -91,7 +124,6 @@ const BlockView = (props)=> ( ) ``` -Same for the block edit component. The resultant HTML would be the following: ```html @@ -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 +
+ ... +
+``` + +## `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` + +## `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 @@ -143,7 +266,6 @@ const StyleSchema = () => ( We'll assign it to the listing block: ``` -config.blocks.blocksConfig.listing.enableStyling = true; config.blocks.blocksConfig.listing.stylesSchema = StyleSchema; ``` diff --git a/docs/effective-volto/addons/blockslayout.md b/docs/effective-volto/addons/blockslayout.md index 3577f5f4b..0a097e9dd 100644 --- a/docs/effective-volto/addons/blockslayout.md +++ b/docs/effective-volto/addons/blockslayout.md @@ -21,7 +21,7 @@ that content type. The available controls in the Block Settings tab are controlled by the `schema` property in the block configuration: -``` +```js hero: { id: 'hero', title: 'Hero', @@ -36,10 +36,6 @@ The available controls in the Block Settings tab are controlled by the `schema` mostUsed: false, blockHasOwnFocusManagement: true, sidebarTab: 1, - security: { - addPermission: [], - view: [], - }, }, ``` From b12dc17463d374678594979a3694191e6007ba66 Mon Sep 17 00:00:00 2001 From: Victor Fernandez de Alba Date: Sun, 10 Sep 2023 10:11:06 +0200 Subject: [PATCH 04/45] theme addons --- docs/effective-volto/addons/theme.md | 144 +++++++++++++++++++++++---- 1 file changed, 123 insertions(+), 21 deletions(-) diff --git a/docs/effective-volto/addons/theme.md b/docs/effective-volto/addons/theme.md index 77162f8c7..033a7372a 100644 --- a/docs/effective-volto/addons/theme.md +++ b/docs/effective-volto/addons/theme.md @@ -9,30 +9,38 @@ myst: # Create a theme add-on -We can create a Volto Add-on that acts as a theme Add-on, so we can detach it from the project. -The advantage is that you can deploy the same theme in different projects, or have themes depending on conditions that you could inject on build time. +We can create a Volto Add-on that acts as a Volto theme Add-on, so we can detach it from the project files. +The advantage is that you convert the project Volto theme in a pluggable one, so you can deploy the same theme in different projects. +You can even have themes depending on conditions that you could inject on build time. +This is the purpose of `volto.config.js`, the ability of declaring `add-ons` and the active `theme` programatically. See {ref}`volto-config-js` for more information. +For convenience, it can also be set via a `THEME` environment variable. -1. We have to create a file in the root of the add-on `razzle.extend.js` with these contents: +1. Add a `theme` key in your `volto.config.js` file in the root of your project: ```js -const plugins = (defaultPlugins) => { - return defaultPlugins; +module.exports = { + addons: ['volto-my-theme'], + theme: 'volto-my-theme' }; -const modify = (config, { target, dev }, webpack) => { - const themeConfigPath = `${__dirname}/src/theme/theme.config`; - config.resolve.alias['../../theme.config$'] = themeConfigPath; - config.resolve.alias['../../theme.config'] = themeConfigPath; +``` - return config; -}; +or add a key in your `package.json` project: -module.exports = { - plugins, - modify, -}; +```json +"theme": "volto-my-theme" ``` -2. Create a directory in `src/theme`, then add this file `theme.config`, replacing `` with your add-on name: +or via a `THEME` variable: + +```shell +THEME='volto-my-theme' yarn start +``` + +```{note} +Your add-on has to be defined in your add-ons key as well, in order to make Volto know about it. +``` + +2. Create a directory `src/theme` in your add-on, then add this file `theme.config`, replacing `` with your add-on name: ```less /******************************* @@ -109,7 +117,7 @@ module.exports = { @themesFolder : '~volto-themes'; /* Path to site override folder */ -@siteFolder : "~/theme"; +@siteFolder : "/theme"; /******************************* Import Theme @@ -125,8 +133,102 @@ module.exports = { /* End Config */ ``` -3. Load the add-on as any other in your project's `package.json` `addons` key. -4. The theme should be active and you can add now overrides to the default theme in `src/theme` as you would do it in a project. -5. If you want, you can delete now your project `theme` folder, since the one in the add-on will take precedence. +3. Declare the theme as an add-on by adding its name to the value for the `addons` key in either `volto.config.js` or `package.json` of your project. +4. After starting Volto, the theme should be active. + Now you can add overrides to the default theme in `src/theme`, same as you would in a project. +5. Now you can safely delete your project's `theme` folder, since the one in the add-on will take precedence and a project can only have one active theme at a time. + +## Using your own theming escape hatch + +Volto theming uses SemanticUI theming capabilities to define and extend a theme for your site. +However, while maintaining and playing well with the Semantic UI Volto base, using a traditional CSS approach can be done using the LESS preprocessor-based `extras` escape hatch. + +At the same time, one can either discard or complement the extras escape hatch and add your own, by customizing the `theme.js` module in Volto. + +```js +import 'semantic-ui-less/semantic.less'; +import '@plone/volto/../theme/themes/pastanaga/extras/extras.less'; + +// You can add more entry points for theming +import '@kitconcept/volto-light-theme/theme/main.scss'; +``` + +Customizing it is a special use case in Volto: add a `./@root/theme.js` file structure in your `customizations` folder in your add-on or project. + +You may want to do this to create a complete new theming experience adapted to your way of doing things that do not match the current Volto theming experience. +For example, if you want to use another preprocessor in the theme, like SCSS. +Maybe because your client forces you to have another entirely base of pre-made components based on another library other than Semantic UI: +See {ref}`volto-custom-theming-strategy` for an example of a custom theme escape hatch. + +While building your own escape hatch for theming, you can use the preprocessor of your choice (in the example, SCSS) while maintaining the "base" Volto theme, but customizing it using the resultant CSS. + +You can see an example of such a theme in: https://github.com/kitconcept/volto-light-theme + +## Modify a custom theme from another add-on + +Sometimes you have a custom theme that you want to reuse through all your projects, but with some differences, maintaining the base. +Usually, the only option would be to use an add-on that adds more CSS to the base theme, using imports that will load after the theme. +However, there is a problem with this approach. +You cannot use existing theme variables, including breakpoints, on these new styles. +Similarly, it gets somewhat detached from the normal flow of the loaded theme. +The same applies for add-ons, as they are detached from the current theme. +One could use a SemanticUI approach for making this work, but it's SemanticUI bound. + +```{warning} +This is only possible when using your own escape hatch, and works only with SCSS-based themes, and not with SemanticUI themes, since it enables a couple of entry points that only support SCSS files. +For an example of how it could be used, see: https://github.com/kitconcept/volto-light-theme +``` + +If your custom escape hatch defines a custom theme using SCSS, you can take advantage of this feature. +Although not limited to this, it would be possible to extend this feature to add more entry points, using another preprocessor or theming approach. + +This feature enables two entry points: variables and main. +From your add-on code, you can extend an existing theme by creating a file corresponding to each entry point: + +* `./src/theme/_variables.scss` +* `./src/theme/_main.scss` + +### Variables (`addonsThemeCustomizationsVariables`) + +Use this entry point file to modify the original variables of the current loaded theme by adding the entry point before the theme variable definitions. +In the theme, it should be imported as shown below: + +```scss hl_lines="2" +@import 'addonsThemeCustomizationsVariables'; +@import 'variables'; +@import 'typography'; +@import 'utils'; +@import 'layout'; +``` + +```{warning} +Following SCSS best practices, your theme variables should be "overridable" using the `!default` flag. +This assigns a value to a variable _only_ if that variable isn't defined or its value is [`null`](https://sass-lang.com/documentation/values/null). +Otherwise, the existing value will be used. +For more information, see https://sass-lang.com/documentation/variables#default-values +``` + +Volto will not only load your add-on entry point files, but it will also detect all the add-ons that have these entry point files and import them grouped under a single file. +It will also automatically add an `addonsThemeCustomizationsVariables` alias that can be referenced from the theme as shown above. + +### Main (`addonsThemeCustomizationsMain`) + +This entry point is intended to add your own style definitions, complementing those in the theme. +You should add it after all the CSS of your theme: + +```scss hl_lines="6" +@import 'blocks/search'; +@import 'blocks/listing'; + +@import 'temp'; -## Use less and css props +@import 'addonsThemeCustomizationsMain'; + +/* No CSS beyond this point */ +``` + +Volto will also detect all the add-ons that have these entry point files, and import them grouped under a single file, and will automatically add an `addonsThemeCustomizationsMain` alias that can be referenced from the theme as shown above. + +```{note} +It will only work in combination with the theme declaration in `volto.config.js` or in `package.json`. +``` From 1fde2ac5c82075e5d6120638056e361b9304bd87 Mon Sep 17 00:00:00 2001 From: Victor Fernandez de Alba Date: Sun, 10 Sep 2023 10:16:33 +0200 Subject: [PATCH 05/45] Update addons testing --- docs/effective-volto/testing/addons.md | 73 ++++++++++++++++---------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/docs/effective-volto/testing/addons.md b/docs/effective-volto/testing/addons.md index 422225031..2738840cd 100644 --- a/docs/effective-volto/testing/addons.md +++ b/docs/effective-volto/testing/addons.md @@ -47,42 +47,61 @@ This is specially useful in CI while developing add-ons, so you can pass an spec ## Testing add-ons in isolation Testing an add-on in isolation as you would do when you develop a Plone Python backend add-on can be a bit challenging, since an add-on needs a working project in order to bootstrap itself. -There are some utilities available in order to help bootstrap a testing environment for isolated add-ons. +The latest generator has the boilerplate needed in order to bootstrap a dockerized environment where you can run any test to your add-on. -(plone-scripts-label)= +### Setup the environment -### `@plone/scripts` +Run once -This library adds some useful command line utilities that come in handy when testing add-ons in isolation. +```shell +make dev +``` + +### Build the containers manually + +Run + +```shell +make build-backend +make build-addon +``` -First of all, your add-on should has `@plone/scripts` as dependency: +### Unit tests - ```json - "dependencies": { - "@plone/scripts": "*", - } - ``` +Run -Once done, your environment has an executable `addon` available which exposes a command line interface and you could run: +```shell +make test +``` -`npx -p @plone/scripts addon clone [options] [destination]` +### Acceptance tests - Options: - -p, --private set if the repo is private, then GITHUB_TOKEN is used - -b, --branch set the repo branch, defaults to main - -c, --canary downloads latest Volto canary (alpha) version - -h, --help display help for command +Run once -Example: +```shell +make install-acceptance +``` -`npx -p @plone/scripts addon clone https://github.com/kitconcept/volto-blocks-grid.git --branch my_new_branch --canary` +For starting the servers -This will create a directory named `addon-testing-project` (this is a sensible default, but you can specify a custom one) and will bootstrap a new project using Volto's standard project generator. -It will adjust the configuration of this project to setup the add-on in the project using `mrs-developer` and the git URL given to fetch the add-on contents. -You can specify the branch to be used, if the project should use the latest alpha available. -There is an option for private repos as well, in that case, it will use the `GITHUB_TOKEN` present in your environment variables to fetch it. +Run -After this, as a developer you can use the usual project commands to run tests (unit, linting, acceptance) inside the generated addon-testing-project`. -You can configure the CI of your choice for automated testing, you can take a look at how it's done in: https://github.com/kitconcept/volto-blocks-grid/tree/main/.github/workflows -The idea is to issue commands inside the generated `addon-testing-project` project and do your checks. -Take special care on how to pass down to the `npx` command the current PR branch. +```shell +make start-test-acceptance-server +``` + +The frontend is run in dev mode, so development while writing tests is possible. + +Run + +```shell +make test-acceptance +``` + +To run Cypress tests afterwards. + +When finished, don't forget to shutdown the backend server. + +```shell +make stop-test-acceptance-server +``` From 315e5fadf7a6ec205cbdc2b2d67f111c39613e53 Mon Sep 17 00:00:00 2001 From: Victor Fernandez de Alba Date: Sun, 10 Sep 2023 10:32:51 +0200 Subject: [PATCH 06/45] Update bypass cors local dev --- docs/effective-volto/development/setup.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/effective-volto/development/setup.md b/docs/effective-volto/development/setup.md index 5e8bb9825..2be8748cb 100644 --- a/docs/effective-volto/development/setup.md +++ b/docs/effective-volto/development/setup.md @@ -53,11 +53,9 @@ This is an advanced feature, and needs understanding of what you are doing and w Let's say you want to debug a deployed site in production, but the build does not allow you to look deeper into the tracebacks. You could bootstrap a frontend in your machine, and point it to the production server, combining environment variables like: ``` -RAZZLE_DEV_PROXY_API_PATH=https://2021.ploneconf.org RAZZLE_PROXY_REWRITE_TARGET=https://2021.ploneconf.org/++api++ yarn start +RAZZLE_INTERNAL_API_PATH=https://demo.plone.org RAZZLE_PROXY_REWRITE_TARGET=/++api++ RAZZLE_DEV_PROXY_INSECURE=1 yarn start ``` -This has the drawback that could be that the proxy does not work well with the proxied SSL connection. - If you have access (via tunnel) to the port of the deployed backend is even more easier: ``` From 503eeb3932c63abcaeebfc6462841ab50553f9ce Mon Sep 17 00:00:00 2001 From: Victor Fernandez de Alba Date: Sun, 10 Sep 2023 11:04:48 +0200 Subject: [PATCH 07/45] Fixed dataAdapter pattern --- docs/effective-volto/addons/blockdataform.md | 37 ++++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/docs/effective-volto/addons/blockdataform.md b/docs/effective-volto/addons/blockdataform.md index 9609f46c1..c925001d2 100644 --- a/docs/effective-volto/addons/blockdataform.md +++ b/docs/effective-volto/addons/blockdataform.md @@ -14,7 +14,7 @@ mechanisms: variations and block styles. To use it, instantiate the schema and pass it down to the component. A full Volto block edit component could be like: ```jsx -export const MyBlockSchema = ({data, intl}) => { +export const myBlockSchema = ({data, intl}) => { return { title: "My block", fieldsets: [ @@ -91,11 +91,7 @@ a Select control for the active variation, in the sidebar. mostUsed: false, blockHasOwnFocusManagement: true, sidebarTab: 1, - blockSchema: MyBlockSchema, - security: { - addPermission: [], - view: [], - }, + blockSchema: myBlockSchema, variations: [ { id: 'leftSideView', @@ -116,14 +112,29 @@ Note: you can assign the schema to `blockSchema` in the block configuration. It is used only to extract the block default values. This integration will be improved, in the future. -## Using a dataAdapter pattern +## Using a blockSchema and the dataAdapter pattern -Sometimes is useful to adapt the incoming data to other data format, structure or type. +You can declare the schema that the block is using internally in the `blockSchema` property in the block configuration. +This will enable some niceties in `BlockDataForm` internals and you will have access to it via configuration instead of using an arbitrary imported name. + +Sometimes is also useful to adapt the incoming data to other data format, structure or type. You can use the dataAdapter pattern in `BlockDataForm` as this: +Given a block with the config: + +```js + config.blocks.blocksConfig.myBlock = { + // ... + schemaEnhancer: myBlockSchemaEnhancer, + blockSchema: myBlockSchema, + dataAdapter: myBlockDataAdapter, + // ... + }; +``` + ```jsx - const schema = blocksConfig[data['@type']].blockSchema({ intl }); - const dataAdapter = blocksConfig[data['@type']].dataAdapter; + const schema = blocksConfig.myBlock.blockSchema({ intl }); + const dataAdapter = blocksConfig.myBlock.dataAdapter; Date: Mon, 11 Sep 2023 10:11:19 +0300 Subject: [PATCH 08/45] Asyncconnect chapter --- docs/effective-volto/addons/asyncconnect.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/effective-volto/addons/asyncconnect.md b/docs/effective-volto/addons/asyncconnect.md index aaee95cab..90dcd87da 100644 --- a/docs/effective-volto/addons/asyncconnect.md +++ b/docs/effective-volto/addons/asyncconnect.md @@ -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()` +- in Volto's `server.jsx` we conver the React component tree to an HTML string + with `react-dom.renderToString()` - the Router renders its declared components, which is the `App` and its direct child, the `View` component @@ -72,8 +73,9 @@ 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 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 = [ From fcb5999140cc5008b7049c359dfde9a4b545f11f Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Mon, 11 Sep 2023 10:38:07 +0300 Subject: [PATCH 09/45] Block styling chapter --- .../addons/block-extensions.md | 6 ++-- docs/effective-volto/addons/block-styling.md | 30 ++++++++++--------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/docs/effective-volto/addons/block-extensions.md b/docs/effective-volto/addons/block-extensions.md index e6bc65314..a62529084 100644 --- a/docs/effective-volto/addons/block-extensions.md +++ b/docs/effective-volto/addons/block-extensions.md @@ -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 diff --git a/docs/effective-volto/addons/block-styling.md b/docs/effective-volto/addons/block-styling.md index 1a7f1ee17..e183f6d31 100644 --- a/docs/effective-volto/addons/block-styling.md +++ b/docs/effective-volto/addons/block-styling.md @@ -156,7 +156,7 @@ data like: } ``` -will generate classnames `primary inverted` +will generate classnames `primary inverted`. This relies on the `noprefix` and `bool` converters that are registered in Volto. ## `styleClassNameExtenders` @@ -239,17 +239,13 @@ 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 '...'", @@ -257,16 +253,22 @@ const StyleSchema = () => ( default: 2, minimum: 0, maximum: 5, - }, - }, - required: [], - }); + }; + return schema; +} ``` We'll assign it to the listing block: ``` -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: From b66b8133be1a744a40859006bd7b124c483a44bb Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Mon, 11 Sep 2023 10:55:07 +0300 Subject: [PATCH 10/45] BlockDataForm chapter --- docs/effective-volto/addons/blockdataform.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/effective-volto/addons/blockdataform.md b/docs/effective-volto/addons/blockdataform.md index c925001d2..856aa19bb 100644 --- a/docs/effective-volto/addons/blockdataform.md +++ b/docs/effective-volto/addons/blockdataform.md @@ -9,12 +9,15 @@ myst: # Create a block using `BlockDataForm` -The BlockDataForm renders an form fully integrated with a block's extension +The `BlockDataForm` component renders a form fully integrated with Volto's blocks extensions mechanisms: variations and block styles. To use it, instantiate the schema and pass it down to the component. A full Volto block edit component could be like: ```jsx export const myBlockSchema = ({data, intl}) => { + // notice that we are pass the data, so the schema is "dynamic", we can + // compose it based on the data. + return { title: "My block", fieldsets: [ @@ -72,9 +75,6 @@ export const MyBlockEdit = (props) => { }; ``` -Note: in the future, this step may even be completely avoided, when Volto will -have a generic Edit component that uses this recipe for all the blocks. - If there's any registered variations for this block, they will be displayed as a Select control for the active variation, in the sidebar. @@ -109,13 +109,16 @@ a Select control for the active variation, in the sidebar. ``` Note: you can assign the schema to `blockSchema` in the block configuration. It -is used only to extract the block default values. This integration will be -improved, in the future. +is used to extract the block default values. + +Volto also has a "generic block edit component", the `EditDefaultBlock` which +you get by simply not setting the `edit` field of the block configuration +registration. This component uses the `blockSchema` field, so you are required +to set that. ## Using a blockSchema and the dataAdapter pattern You can declare the schema that the block is using internally in the `blockSchema` property in the block configuration. -This will enable some niceties in `BlockDataForm` internals and you will have access to it via configuration instead of using an arbitrary imported name. Sometimes is also useful to adapt the incoming data to other data format, structure or type. You can use the dataAdapter pattern in `BlockDataForm` as this: From 5eafc3899ffc297daacd752527eb1285a3f051a3 Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Mon, 11 Sep 2023 11:08:46 +0300 Subject: [PATCH 11/45] Addon dependencies chapter --- docs/effective-volto/addons/blockslayout.md | 16 ++++++++++++---- .../addons/customlistingtemplate.md | 2 +- docs/effective-volto/addons/dependencies.md | 13 ++++++++----- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/docs/effective-volto/addons/blockslayout.md b/docs/effective-volto/addons/blockslayout.md index 0a097e9dd..0fd1f07d3 100644 --- a/docs/effective-volto/addons/blockslayout.md +++ b/docs/effective-volto/addons/blockslayout.md @@ -9,11 +9,15 @@ myst: # Blocks Layout +The Blocks Layout is a feature that allows a website administrator to define, +through the Plone control panel, the default blocks that are initialized in the +add form when a new Plone document is created by the website editors. + Any Dexterity content type can be made compatible with Volto blocks engine by -enabling the `Blocks` behavior. From the Content Types Control Panel it's also -possible to define a default "layout" for a particular content type. In the -Block Layout page you get a regular Volto Pastanaga Blocks Editor page, but the -blocks have an additional tab in the sidebar, the "block settings". +enabling the `Blocks` behavior. From the Content Types Control Panel you can +define the default "layout" for a particular content type. In the Block Layout +page you get a regular Volto Pastanaga Blocks Editor page, but the blocks have +an additional tab in the sidebar, the "block settings". When using the content type to instantiate a new Plone content, the add form will already have the blocks from transfered from the Blocks Layout page of @@ -41,3 +45,7 @@ The available controls in the Block Settings tab are controlled by the `schema` The generic BlockSettingsSchema allow control over the behavior of the block in the future edit pages: is the block required? is it read only? etc. + +The default blocks for a content type are stored in that content type's schema, +so if you want to store that GenericSetup configuration in code, you need to +export the Content Types Registry. diff --git a/docs/effective-volto/addons/customlistingtemplate.md b/docs/effective-volto/addons/customlistingtemplate.md index 74fd45f96..9278bf02b 100644 --- a/docs/effective-volto/addons/customlistingtemplate.md +++ b/docs/effective-volto/addons/customlistingtemplate.md @@ -9,7 +9,7 @@ myst: # Create a custom Listing block variation -The Listing block is one of the most versatile blocks, and driver to many of +The Listing block is one of the most versatile blocks, and a driver to many of Volto's more "advanced" technologies, such as variations. It can be shaped into many forms, such as sliders, carousels, cards and more. diff --git a/docs/effective-volto/addons/dependencies.md b/docs/effective-volto/addons/dependencies.md index 46c0f1adb..d8b982747 100644 --- a/docs/effective-volto/addons/dependencies.md +++ b/docs/effective-volto/addons/dependencies.md @@ -14,15 +14,18 @@ in your addon's `addons` key, just like you do in your project. By doing so, that other addon's configuration loader is executed first, so you can depend on the configuration being already applied. Another benefit is that you'll have to declare only the "top level" addon in your project, the dependencies will be -discovered and automatically treated as Volto addons. For example, volto-slate -depends on volto-object-widget's configuration being already applied, so -volto-slate can declare in its package.json: +discovered and automatically treated as Volto addons. For example, the Volto +addon volto-eea-kitkat, which is the Volto umbrela addon that registers +a default set of addons for the EEA websites, depends on many other addons: ``` { - "name": "volto-slate", + "name": "volto-eea-kitkat", ... - "addons": ['@eeacms/volto-object-widget'] + "addons": [ + '@eeacms/volto-matomo', + // ... + ] } ``` From 1443ac625a6535a0b0aaec913d9fdb5e8281e21f Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Mon, 11 Sep 2023 12:34:39 +0300 Subject: [PATCH 12/45] How an addon works chapter --- .../addons/how-an-add-on-works.md | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/docs/effective-volto/addons/how-an-add-on-works.md b/docs/effective-volto/addons/how-an-add-on-works.md index 94565d87d..d2ee1d635 100644 --- a/docs/effective-volto/addons/how-an-add-on-works.md +++ b/docs/effective-volto/addons/how-an-add-on-works.md @@ -19,9 +19,7 @@ This gives you the ability to move all your project configuration, components, c An add-on can be published in an npm registry, just as any other package. However, Volto Add-ons should not be transpiled. They should be released as "source" packages. -See `@kitconcept/volto-blocks-grid` as an example. - -https://github.com/kitconcept/volto-blocks-grid +See [@kitconcept/volto-blocks-grid](https://github.com/kitconcept/volto-blocks-grid) as an example. ## Loading a Volto Add-on in a project @@ -47,12 +45,13 @@ features. In Plone terminology, it is like including a Python egg to the `zcml` section of zc.buildout. ``` -By including the addon name in the `addons` key, the addon's default export +By including the addon name in the `addons` key, the addon's main default export function is executed, being passed the Volto configuration registry. In that function, the addon can customize the registry. The function needs to return the `config` (Volto configuration registry) object, so that it's passed further along to the other addons. + ### Loading a Volto Add-on optional configuration Some addons might choose to allow the Volto project to selectively load some of @@ -111,6 +110,22 @@ And the `package.json` file of your addon: "main": "src/index.js", } ``` +In effect, Volto does the equivalent of: + + +``` +import installMyVoltoAddon from 'my-volto-addon' + +// ... in the configuration registry setup step: +const configRegistry = installMyVoltoAddon(defaultRegistry); +``` + +So the Volto addon needs to export a default function +that receives the Volto configuration registry, is free to change the registry +as it sees fit, then it needs to return that registry. + +Volto will chain-execute all the addon configuration functions to compute the +final configuration registry. ```{warning} An addon's default configuration method will always be loaded. From 4ebb3f1700e4aefda430a9ca61295e4f8c99f0a8 Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Mon, 11 Sep 2023 13:15:59 +0300 Subject: [PATCH 13/45] i18n chapter --- docs/effective-volto/addons/i18n.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/effective-volto/addons/i18n.md b/docs/effective-volto/addons/i18n.md index 0bec5ab18..0f0712dda 100644 --- a/docs/effective-volto/addons/i18n.md +++ b/docs/effective-volto/addons/i18n.md @@ -42,4 +42,6 @@ In the context of your project (eg. in the root), run `yarn i18n` to merge the a ## Override translations -The workflow allows you to override translations from your project scope, so the project translations "always win". +The addon loading chain is followed here as well, so the addons can override +translation messages and the last addon "wins". The project translations are +loaded last, so it can override any addon translations. From 3f438cf3e1517459ce2f59769c5e37c4afb5209d Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Mon, 11 Sep 2023 13:32:20 +0300 Subject: [PATCH 14/45] Pipeline chapter --- docs/effective-volto/addons/pipeline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/effective-volto/addons/pipeline.md b/docs/effective-volto/addons/pipeline.md index 1ba996254..d733b989b 100644 --- a/docs/effective-volto/addons/pipeline.md +++ b/docs/effective-volto/addons/pipeline.md @@ -35,7 +35,7 @@ module.exports = { } ``` -This is a scape hatch where you can define using code the add-ons that are used the current project. Take a look: +This is an "escape hatch" where you can use logic and environment conditions to define the add-ons to be loaded in the current project. Take a look: ```js From 7b614294d2aa720bea76c80b639e97bf38868e04 Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Mon, 11 Sep 2023 13:44:02 +0300 Subject: [PATCH 15/45] SemanticUI chapter --- docs/effective-volto/addons/semanticui.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/effective-volto/addons/semanticui.md b/docs/effective-volto/addons/semanticui.md index e853126b6..f73fa6e8a 100644 --- a/docs/effective-volto/addons/semanticui.md +++ b/docs/effective-volto/addons/semanticui.md @@ -18,7 +18,10 @@ exchangeable concepts. Classes use syntax from natural languages like noun/modifier relationships, word order, and plurality to link concepts intuitively. -Semantic-UI-LESS has a builtin theming engine based on the following concepts: +Volto uses Semantic-UI for both the public and the "private" administration +interface. See the [Theme](./theme) chapter for details on how to use a different CSS framework for the public part of your theme. + +Semantic-UI-LESS has a built-in theming engine based on the following concepts: - LESS [definitions](https://github.com/Semantic-Org/Semantic-UI-LESS/tree/master/definitions) files (split in globals, collections, elements, etc) to define the basic styles (ex: `definitions/modules/tab.less`) - A [semantic.less](https://github.com/Semantic-Org/Semantic-UI-LESS/blob/e4395217c1b8b3227c7387284d12f2d9774d33c6/semantic.less) file which imports all the available definition files @@ -41,9 +44,9 @@ theme.config](https://github.com/plone/volto/blob/7044eca789d836786e9e7890366690 (by shadowing, via webpack resolve aliases, the `../../theme.config` import path). -Volto's theme is called Pastanaga, which is a typical Semantic-UI theme. For +Volto's theme is called Pastanaga. It's a typical Semantic-UI theme. For the new elements and components that don't exist in Semantic-UI, the Pastanaga -theme uses the [extras](https://github.com/plone/volto/tree/master/theme/themes/pastanaga/extras) folder, which isn't fully using the Semantic-UI theming engine. +theme uses the [extras](https://github.com/plone/volto/tree/master/theme/themes/pastanaga/extras) folder. The downside is that they aren't fully using the Semantic-UI theming engine. The key to success in Volto theming is to understand how Semantic-UI's theming engine works and how to manipulate it. Reading the `theme.less` and @@ -59,7 +62,8 @@ import '@plone/volto/../theme/themes/pastanaga/extras/extras.less'; By simply providing your own copy of semantic.less (and changing the above import), you can tweak which basic semantic-ui definitions are loaded, or even -create new elements. +create new elements. See an example in the [EEA website +frontend](https://github.com/eea/eea-website-frontend/blob/160ecd7924d113966e1ebd6cbe957dca3f228c6b/src/theme.js) ``` & { From 01f986690c527f8f086bbc738f5e49afe40466ca Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Mon, 11 Sep 2023 13:51:08 +0300 Subject: [PATCH 16/45] Use Released addons chapter --- .../addons/use-released-addon.md | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/docs/effective-volto/addons/use-released-addon.md b/docs/effective-volto/addons/use-released-addon.md index 8df5799e6..804b2e9c9 100644 --- a/docs/effective-volto/addons/use-released-addon.md +++ b/docs/effective-volto/addons/use-released-addon.md @@ -7,19 +7,29 @@ myst: "keywords": "Volto, Plone, Volto add-on" --- -# Configure a released Volto Add-on in your project +# Add a third-party released Volto Add-on in your project -1. If you already have a Volto project, update `package.json`: +1. Add the JS package as a dependency to your project: + +``` +yarn add +``` + +2. Update the `package.json` to add the package name as a Volto addon: ```json "addons": [ "@kitconcept/volto-blocks-grid" ], -"dependencies": { - "@kitconcept/volto-blocks-grid": "*" -} ``` -2. Run `yarn` to download the released package. -3. Run the project, the add-on should be loaded and configured +If, instead, you want to add a Volto addon as a dependency to one of your +development addons, you should run: + +``` +yarn workspace add +``` + +And then you can edit the `package.json` of your development addon and add the +other Volto addon to the `addons` list (create it if it's not already there). From daf6a7133bc6a0d182e9eaca2fb158d6f6a6b26a Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Tue, 12 Sep 2023 11:01:06 +0300 Subject: [PATCH 17/45] View and use-repo-addon chapter --- docs/effective-volto/addons/use-repo-addon.md | 2 +- docs/effective-volto/addons/views.md | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/effective-volto/addons/use-repo-addon.md b/docs/effective-volto/addons/use-repo-addon.md index cf63db582..03d770b45 100644 --- a/docs/effective-volto/addons/use-repo-addon.md +++ b/docs/effective-volto/addons/use-repo-addon.md @@ -9,7 +9,7 @@ myst: # Configure an unreleased add-on from an existing repository -We use `mrs-developer` tool to manage the development cycle. +We use `mrs-developer` tool to manage the development cycle of Volto add-ons. This tool help us to pull the remote code and configure the current project to have the add-on(s) available for the build. ## Add mrs-developer dependency and related script diff --git a/docs/effective-volto/addons/views.md b/docs/effective-volto/addons/views.md index 50ee3773b..9d4fee2d4 100644 --- a/docs/effective-volto/addons/views.md +++ b/docs/effective-volto/addons/views.md @@ -11,9 +11,8 @@ myst: Writing a "custom view templates" is one of the most basic tasks in classic Plone development. The Volto blocks, powered by the Pastanaga Editor, make -this task a less frequent occurrence in Volto development, but it's still -possible to follow the same development model, to attach custom views to Plone -content. +this task a less frequent occurrence in Volto development, the Plone Classic +concept of writing a view template for a content type is supported by Volto. A Volto content view is a really simple React component. @@ -35,8 +34,8 @@ In the Volto configuration registry, you can assign views in the following keys: - `errorViews` - `defaultView` -In Volto the DefaultView is blocks-enabled, so you can easily enable the blocks -behavior for any content type. The resolution order is: +Volto's `DefaultView` is blocks-enabled, so it will automatically work for any +content type that has the Blocks behavior enabled. The view resolution order is: - get view by type - get view by layout @@ -44,8 +43,10 @@ behavior for any content type. The resolution order is: ## Router views -For generic, views, that aren't attached to the context content, you need to -write a new route. +If you need to implement an additional view for a content type, or something +that's not dirrectly attached to the context content, you have to use the +"router", which high-level component that connects the window location to the +proper React component to be used. The view component can be any React component, and you register that route like so: From ec046037ed9b7788fd4ad455e3f6ca873976e009 Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Tue, 12 Sep 2023 11:03:57 +0300 Subject: [PATCH 18/45] Webpack chapter --- docs/effective-volto/addons/webpack.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/effective-volto/addons/webpack.md b/docs/effective-volto/addons/webpack.md index 7f70840e3..ff064476a 100644 --- a/docs/effective-volto/addons/webpack.md +++ b/docs/effective-volto/addons/webpack.md @@ -11,8 +11,11 @@ myst: Just like you can extend Razzle's configuration from the project, you can do so with an addon, as well. You should provide a `razzle.extend.js` file in your -addon root folder. An example of such file where the theme.config alias is -changed, to enable a custom Semantic theme inside the addon: +addon root folder. Here's an example of such file, where we achieve two things: + +- we add a new webpack plugin, the + [bundle-analyzer](https://www.npmjs.com/package/webpack-bundle-analyzer) +- we reconfigure the `theme.config` alias, to enable a custom Semantic theme inside the addon: ```js const analyzerPlugin = { From e1af3f5181e0e8a395d5dc140b31d76cc1f8fe6e Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Tue, 12 Sep 2023 11:47:01 +0300 Subject: [PATCH 19/45] Babel and webpack --- docs/effective-volto/addons/webpack.md | 3 +++ docs/effective-volto/architecture/anatomy.md | 25 ++++++++++---------- docs/effective-volto/architecture/babel.md | 6 ++--- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/docs/effective-volto/addons/webpack.md b/docs/effective-volto/addons/webpack.md index ff064476a..b43c8f909 100644 --- a/docs/effective-volto/addons/webpack.md +++ b/docs/effective-volto/addons/webpack.md @@ -45,3 +45,6 @@ module.exports = { modify, }; ``` + +Check +[volto-searchlib razzle.extend.js](https://github.com/eea/volto-searchlib/blob/d84fec8eec1def0088d8025eaf5d7197074b95a7/razzle.extend.js) file for an example on how to include additional paths to the Babel configuration and how to add additional webpack name aliases. diff --git a/docs/effective-volto/architecture/anatomy.md b/docs/effective-volto/architecture/anatomy.md index 9593071bf..d1d843fe7 100644 --- a/docs/effective-volto/architecture/anatomy.md +++ b/docs/effective-volto/architecture/anatomy.md @@ -16,7 +16,7 @@ development world, Volto is no longer a strange beast. To list some of the things that Volto is: -- A **Single Page Application**, based on React that runs in client browsers +- A **Single Page Application**, based on React, it runs in the browsers - An **Express-powered HTTP server** that can completely generate full HTML pages server-side. See the [Server Side Rendering](./client-ssr) chapter for more. - A CMS UI to interact with Plone, the backend @@ -25,18 +25,18 @@ To list some of the things that Volto is: There are two ways of running Volto: -- **Standalone** (to develop Volto itself) - as a **Volto Project** (for your own custom use, to develop a new website). +- **Standalone** (to develop Volto itself) Running Volto standalone is simple: make a clone of Volto from Github, run -`yarn` to download its dependencies, then `yarn start` to simply start Volto. +`yarn install` to download its dependencies, then `yarn start` to simply start Volto. This is useful for developing Volto, but it is not the way to use it, if you want to develop your own custom Volto website. -The second method of running Volto is to use the **Volto App generator** and +The main method of running Volto is to use the **Volto App generator** and bootstrap (based on a fixed scaffolding) a new JavaScript package that can piggy-back on Volto and treat it as a library. We call this the "Volto -project". +Project". The next steps, after bootstrapping the new Volto project, is to make it your @@ -76,8 +76,8 @@ Looking inside Volto's source code, we find several points of interest: - `registry.js` and the `config` folder will constitute the Volto configuration registry, a deep JavaScript object that holds settings and configuration. The registry can be altered by Volto projects and Addons. It doesn't have the - fancy features of the component registry of ZCA, but it's easier to reason - and easily inspectable. + fancy features of the component registry of ZCA, but it's easier to + understand and easily inspectable. - the `theme.js` and the parent folder `theme` are Volto's Pastanaga theme, materialized as a Semantic-UI theme. @@ -86,7 +86,7 @@ Looking inside Volto's source code, we find several points of interest: To start Volto in development mode, we do `yarn start`. If you peek inside [Volto's package.json][1] at the script that's executed for that, you'll notice it simply says `razzle -start`. So, when we start Volto, we actually start Razzle. See the +start`. So, when we start Volto, we actually run Razzle. See the [Razzle chapter](./razzle) for more details. Running in development mode provides automatic reload of changed code @@ -96,9 +96,10 @@ Razzle provides two entrypoints for webpack: the server and the client bundles. ### Volto HTTP server -The server uses Expressjs uses `renderToString` from `react-dom/server` to -provide server-side rendering of the HTML pages. From these generated HTML -pages, the client bundle will be loaded by the browsers. +The server uses Expressjs and `renderToString` from `react-dom/server` to +provide server-side rendering of the HTML pages. The generated HTML +page includes `