From 17ae59cf63420d3a93478028c0f70f00d3aa5c95 Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Fri, 4 Aug 2023 15:51:54 +0200 Subject: [PATCH 01/32] add volto4dummies --- docs/volto4dummies/index.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 docs/volto4dummies/index.md diff --git a/docs/volto4dummies/index.md b/docs/volto4dummies/index.md new file mode 100644 index 000000000..5236f5612 --- /dev/null +++ b/docs/volto4dummies/index.md @@ -0,0 +1,25 @@ +--- +myst: + html_meta: + "description": "Volto for Dummies" + "property=og:description": "Volto for Dummies" + "property=og:title": "Volto for Dummies" + "keywords": "Plone, Volto, Training" +--- + +(effective-volto-label)= + +# Volto for Dummies + +TODO + +*Volto for Dummies* teaches you the basics of customizing Volto without knowing a lot of React or JavaScript. + +```{toctree} +--- +caption: Volto for Dummies +name: toc-volto4dummies +maxdepth: 3 +--- + +``` From 9925535b57625f98eac01c05acbf8b607c6deddc Mon Sep 17 00:00:00 2001 From: nileshgulia1 Date: Mon, 21 Aug 2023 00:04:36 +0530 Subject: [PATCH 02/32] add structure and chapters --- docs/index.md | 1 + docs/volto4dummies/addons.md | 221 +++++++++++++++++++++++ docs/volto4dummies/blocks.md | 1 + docs/volto4dummies/component_registry.md | 1 + docs/volto4dummies/content_type.md | 1 + docs/volto4dummies/data_adapters.md | 1 + docs/volto4dummies/extending_teasers.md | 1 + docs/volto4dummies/index.md | 17 +- docs/volto4dummies/installation.md | 3 + docs/volto4dummies/intro.md | 44 +++++ docs/volto4dummies/listing_block.md | 1 + docs/volto4dummies/schema.md | 0 docs/volto4dummies/styling.md | 1 + docs/volto4dummies/teaser_variations.md | 1 + docs/volto4dummies/theming.md | 1 + docs/volto4dummies/voltosettings.md | 1 + 16 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 docs/volto4dummies/addons.md create mode 100644 docs/volto4dummies/blocks.md create mode 100644 docs/volto4dummies/component_registry.md create mode 100644 docs/volto4dummies/content_type.md create mode 100644 docs/volto4dummies/data_adapters.md create mode 100644 docs/volto4dummies/extending_teasers.md create mode 100644 docs/volto4dummies/installation.md create mode 100644 docs/volto4dummies/intro.md create mode 100644 docs/volto4dummies/listing_block.md create mode 100644 docs/volto4dummies/schema.md create mode 100644 docs/volto4dummies/styling.md create mode 100644 docs/volto4dummies/teaser_variations.md create mode 100644 docs/volto4dummies/theming.md create mode 100644 docs/volto4dummies/voltosettings.md diff --git a/docs/index.md b/docs/index.md index 2b3c71c39..8076a9732 100644 --- a/docs/index.md +++ b/docs/index.md @@ -20,6 +20,7 @@ mastering-plone/index mastering-plone-5/index voltohandson/index voltoaddons/index +volto4dummies/index effective-volto/index testing/index theming/index diff --git a/docs/volto4dummies/addons.md b/docs/volto4dummies/addons.md new file mode 100644 index 000000000..dd47f2a88 --- /dev/null +++ b/docs/volto4dummies/addons.md @@ -0,0 +1,221 @@ +--- +myst: + html_meta: + "description": "Volto add-ons for dummies" + "property=og:description": "Volto add-ons" + "property=og:title": "Volto add-ons" + "keywords": "Volto" +--- + +# Volto add-ons + +## Bootstrap a new Volto project + +To bootstrap a new Volto project, you can use Yeoman [@plone/generator-volto](https://github.com/plone/generator-volto). +First, install it as a global tool (use [NVM] if you're being asked for sudo +access): + +```shell +npm install -g yo +npm install -g @plone/generator-volto +``` + +Then you can bootstrap the project with: + +```shell +yo @plone/volto volto-tutorial-project +``` + +The yo-based generator partially integrates add-ons (it can generate a +`package.json` with add-ons and workspaces already specified). When prompted +to add add-ons, choose `false`. + +Now you can start your newly created Volto project: + +```shell +cd volto-tutorial-project +yarn start +``` + +You can then login with admin/admin at http://localhost:3000/login. + +## Bootstrap an add-on + +Let's start creating an add-on. We'll create a new package: +`volto-teaser-tutorial`. Inside your Volto project, bootstrap +the add-on by running (in the Volto project root): + +```shell +yo @plone/volto:addon +``` + +Note: You can also use the namespace like `@plone-collective/volto-teaser-tutorial` (or any other) is not required and is +optional. We're using namespaces for scoped package under some organisation. + +Use `volto-teaser-tutorial` as the package name. After the +scaffolding of the add-on completes, you can check the created files in +`src/addons/volto-teaser-tutorial`. + +Back to the project, you can edit `jsconfig.json` and add your add-on: + +```json +{ + "compilerOptions": { + "baseUrl": "src", + "paths": { + "volto-teaser-tutorial": ["addons/volto-teaser-tutorial/src"] + } + } +} +``` + +```{note} +The `jsconfig.json` file is needed by Volto to identify development +packages. You are not strictly limited to Volto add-ons in its use, you +could, for example, use this to make it easier to debug third-party +JavaScript packages that are shipped transpiled. +``` + +### Volto addon script + +Alternatively, if you already have an addon pushed to a remote repository and you want to create a volto development stack with it, you can use our addon script to easily scaffold a dev environment without creating a project externally. + +```shell +npx -p @plone/scripts addon clone [options] [destination] +``` + +This command downloads the volto-teaser-tutorial add-on from its git repository's main branch, and will generate a project with the latest Volto version. + +```shell +npx -p @plone/scripts addon clone https://github.com/kitconcept/volto-teaser-tutorial.git --branch main +``` + +### (Optional) Use mrs-developer to sync add-on to GitHub + +You can also immediately push the package to GitHub, then use `[mrs-developer]` +to manage the package and `jsconfig.json` changes. + +Install mrs-developer as a development dependency by running: + +```shell +yarn add -W -D mrs-developer +``` + +Create a `mrs.developer.json` in your project with the following content (adjust it according +to your names and repository location): + +```json +{ + "volto-teaser-tutorial": { + "url": "https://github.com//volto-teaser-tutorial.git", + "path": "src", + "package": "volto-teaser-tutorial", + "branch": "main" + } +} +``` + +Then run `yarn develop`, which will bring the package in `src/addons` and +adjust `jsconfig.json`. + +### Add the add-on as workspace + +The Volto project becomes a monorepo, with the Volto project being the "workspace root" and each add-on needs to be a "workspace", so that yarn knows that it should include that add-on location as a package and install its dependencies. + +You could treat workspaces as major "working environment" for your project. So a yarn install would also install dependencies from `src/addons/*` + +Change the Volto project's `package.json` to include something like: + +```json +{ + "private": "true", + "workspaces": [ + "src/addons/volto-teaser-tutorial" // or simply src/addons/* + ] +} +``` + +```{note} +Don't be scared by that `"private": "true"` in the Volto project `package.json`. +It's only needed to make sure you can't accidentally publish the package to NPM. +``` + +### Managing add-on dependencies + +To be able to add dependencies to the add-on, you need to add them via the +workspaces machinery by running something like (at the Volto project root): + +```shell +yarn workspaces info +yarn workspace volto-teaser-tutorial add papaparse +``` + +````{note} +There are several other add-on templates, such as +[voltocli](https://github.com/nzambello/voltocli) or +[eea/volto-addon-template](https://github.com/eea/volto-addon-template). +You could very well decide not to use any of them, and instead bootstrap a new +add-on by running: + +```shell +mkdir -p src/addons/volto-teaser-tutorial +cd src/addons/volto-teaser-tutorial +npm init +``` + +Remember, an add-on is just a JavaScript package that exports +a configuration loader. Just make sure to point the `main` in +`package.json` to `src/index.js`. +```` + +### Load the add-on in Volto + +To tell Volto about our new add-on, add it to the `addons` key of the Volto +project `package.json`: + +```js +// ... +"addons": ["volto-teaser-tutorial"] +// ... +``` + +## Add-ons - first look + +Volto add-ons are just plain JavaScript packages with an +additional feature: they provide helper functions that mutate Volto's +configuration registry. + +Their `main` entry in `package.json` should point to `src/index.js`, +which should be an ES6 module with a default export. +Here is the default add-on configuration loader: + +```jsx +export default (config) => { + return config; +}; +``` + +The `config` object that is passed is the Volto `configuration registry`, +the singleton module referenced throughout Volto and Volto projects, +by importing `@plone/volto/registry`. The add-on can mutate the properties of +the config, such as `settings`, `blocks`, `views`, `widgets`, or its dedicated +`addonRoutes` and `addonReducers`. + +So: {guilabel}`Volto → add-ons → project`. + +To load an add-on, the project needs to specify the add-on in the `addons` key +of `project.json`. Optional configuration loaders are specified as +a comma-separated list after the `:` colon symbol. + +```js +// ... +"addons": [ + "volto-slate:asDefaultBlock,simpleLink", + "@eeacms/volto-tabs-block", +] +// ... +``` + +Notice the use of `:` symbol that specifies optional configuration loaders that are exported by the add-on's `src/index.js`. + +## Develop a basic Teaser (TODO) diff --git a/docs/volto4dummies/blocks.md b/docs/volto4dummies/blocks.md new file mode 100644 index 000000000..5edc7cf30 --- /dev/null +++ b/docs/volto4dummies/blocks.md @@ -0,0 +1 @@ +### Extend volto blocks diff --git a/docs/volto4dummies/component_registry.md b/docs/volto4dummies/component_registry.md new file mode 100644 index 000000000..179e8f581 --- /dev/null +++ b/docs/volto4dummies/component_registry.md @@ -0,0 +1 @@ +### component Registry( Can be moved to configuration) diff --git a/docs/volto4dummies/content_type.md b/docs/volto4dummies/content_type.md new file mode 100644 index 000000000..13486519f --- /dev/null +++ b/docs/volto4dummies/content_type.md @@ -0,0 +1 @@ +### Create and modify Content-type Views diff --git a/docs/volto4dummies/data_adapters.md b/docs/volto4dummies/data_adapters.md new file mode 100644 index 000000000..367e108a1 --- /dev/null +++ b/docs/volto4dummies/data_adapters.md @@ -0,0 +1 @@ +### Enhance Teaser block with additional data diff --git a/docs/volto4dummies/extending_teasers.md b/docs/volto4dummies/extending_teasers.md new file mode 100644 index 000000000..43af10e29 --- /dev/null +++ b/docs/volto4dummies/extending_teasers.md @@ -0,0 +1 @@ +### Extending Teasers per type diff --git a/docs/volto4dummies/index.md b/docs/volto4dummies/index.md index 5236f5612..fd38c7d1f 100644 --- a/docs/volto4dummies/index.md +++ b/docs/volto4dummies/index.md @@ -13,7 +13,7 @@ myst: TODO -*Volto for Dummies* teaches you the basics of customizing Volto without knowing a lot of React or JavaScript. +_Volto for Dummies_ teaches you the basics of customizing Volto without knowing a lot of React or JavaScript. ```{toctree} --- @@ -22,4 +22,19 @@ name: toc-volto4dummies maxdepth: 3 --- +intro +installation +addons +voltosettings +content_type +blocks +schema +styling +listing_block +teaser_variations +extending_teasers +data_adapters +component_registry +theming + ``` diff --git a/docs/volto4dummies/installation.md b/docs/volto4dummies/installation.md new file mode 100644 index 000000000..4646ba67a --- /dev/null +++ b/docs/volto4dummies/installation.md @@ -0,0 +1,3 @@ +### Installation + +Todo- Installation steps diff --git a/docs/volto4dummies/intro.md b/docs/volto4dummies/intro.md new file mode 100644 index 000000000..94726f575 --- /dev/null +++ b/docs/volto4dummies/intro.md @@ -0,0 +1,44 @@ +--- +myst: + html_meta: + "description": "Introduction to the Volto for Dummies Training Documentation" + "property=og:description": "Introduction to the Volto for Dummies Training Documentation" + "property=og:title": "Volto for Dummies Training" + "keywords": "Volto, Training, Dummies" +--- + +(volto4dummies-intro-label)= + +# Introduction + +## Who are you? + +You are a beginner into Volto development era and wants to know about cheat codes that will help in modern day development with volto. + +(volto4dummies-intro-what-will-we-do-label)= + +## Prerequisites + +Some technologies and tools we use during the training: + +- React +- Yarn +- JSX +- Volto +- Volto Generator +- Plone 6! + +This training assumes that you have already taken (either in person at a Plone Conference or online) the existing Volto and React training. You already know about Content-types, Blocks and visual components in Plone 6. + +If you haven't already, we suggest you to go through it first. + +(volto4dummies-intro-documentation-label)= + +## Software requirements + +To follow the training as smoothly as possible it is recommended that you have the following software installed on your computer: + +- [node.js](https://nodejs.org/en/) >= 16 +- [yarn](https://yarnpkg.com/getting-started/install) +- [node version manager](https://github.com/nvm-sh/nvm) +- [docker](https://www.docker.com/get-started/) diff --git a/docs/volto4dummies/listing_block.md b/docs/volto4dummies/listing_block.md new file mode 100644 index 000000000..e2add32da --- /dev/null +++ b/docs/volto4dummies/listing_block.md @@ -0,0 +1 @@ +### create a simple listing block variation diff --git a/docs/volto4dummies/schema.md b/docs/volto4dummies/schema.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/volto4dummies/styling.md b/docs/volto4dummies/styling.md new file mode 100644 index 000000000..c9840af82 --- /dev/null +++ b/docs/volto4dummies/styling.md @@ -0,0 +1 @@ +### Usage of StyleWrapper( Styling Schemas) and StyleMenu diff --git a/docs/volto4dummies/teaser_variations.md b/docs/volto4dummies/teaser_variations.md new file mode 100644 index 000000000..21a6d6010 --- /dev/null +++ b/docs/volto4dummies/teaser_variations.md @@ -0,0 +1 @@ +### Teaser block extensions and variations diff --git a/docs/volto4dummies/theming.md b/docs/volto4dummies/theming.md new file mode 100644 index 000000000..b17d0fd44 --- /dev/null +++ b/docs/volto4dummies/theming.md @@ -0,0 +1 @@ +### Theming diff --git a/docs/volto4dummies/voltosettings.md b/docs/volto4dummies/voltosettings.md new file mode 100644 index 000000000..40ea27a66 --- /dev/null +++ b/docs/volto4dummies/voltosettings.md @@ -0,0 +1 @@ +### Most useful volto settings From ceb4b46111a3b4b5de00d9ad66aec81967831dc3 Mon Sep 17 00:00:00 2001 From: nileshgulia1 Date: Mon, 21 Aug 2023 00:06:56 +0530 Subject: [PATCH 03/32] add schema chapter --- docs/volto4dummies/schema.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/volto4dummies/schema.md b/docs/volto4dummies/schema.md index e69de29bb..ced56f67f 100644 --- a/docs/volto4dummies/schema.md +++ b/docs/volto4dummies/schema.md @@ -0,0 +1 @@ +### Blocks schema and extensions From 600cc9e7589452cb368d913211f25cfd455c82b3 Mon Sep 17 00:00:00 2001 From: nileshgulia1 Date: Fri, 8 Sep 2023 15:54:04 +0530 Subject: [PATCH 04/32] add documentation for teasers variation and extensions --- docs/index.md | 2 +- docs/volto4dummies/blocks.md | 1 - docs/volto4dummies/data_adapters.md | 1 - docs/volto4dummies/extending_teasers.md | 1 - docs/volto4dummies/index.md | 40 -- docs/volto4dummies/schema.md | 1 - docs/volto4dummies/styling.md | 1 - docs/volto4dummies/teaser_variations.md | 1 - .../addons.md | 37 +- docs/volto_customization/blocks.md | 75 +++ .../component_registry.md | 0 .../content_type.md | 0 docs/volto_customization/data_adapters.md | 90 +++ docs/volto_customization/extending_teasers.md | 585 ++++++++++++++++++ docs/volto_customization/index.md | 40 ++ .../installation.md | 0 .../intro.md | 0 .../listing_block.md | 0 docs/volto_customization/schema.md | 203 ++++++ docs/volto_customization/styling.md | 194 ++++++ docs/volto_customization/teaser_variations.md | 166 +++++ .../theming.md | 0 .../voltosettings.md | 0 23 files changed, 1373 insertions(+), 65 deletions(-) delete mode 100644 docs/volto4dummies/blocks.md delete mode 100644 docs/volto4dummies/data_adapters.md delete mode 100644 docs/volto4dummies/extending_teasers.md delete mode 100644 docs/volto4dummies/index.md delete mode 100644 docs/volto4dummies/schema.md delete mode 100644 docs/volto4dummies/styling.md delete mode 100644 docs/volto4dummies/teaser_variations.md rename docs/{volto4dummies => volto_customization}/addons.md (87%) create mode 100644 docs/volto_customization/blocks.md rename docs/{volto4dummies => volto_customization}/component_registry.md (100%) rename docs/{volto4dummies => volto_customization}/content_type.md (100%) create mode 100644 docs/volto_customization/data_adapters.md create mode 100644 docs/volto_customization/extending_teasers.md create mode 100644 docs/volto_customization/index.md rename docs/{volto4dummies => volto_customization}/installation.md (100%) rename docs/{volto4dummies => volto_customization}/intro.md (100%) rename docs/{volto4dummies => volto_customization}/listing_block.md (100%) create mode 100644 docs/volto_customization/schema.md create mode 100644 docs/volto_customization/styling.md create mode 100644 docs/volto_customization/teaser_variations.md rename docs/{volto4dummies => volto_customization}/theming.md (100%) rename docs/{volto4dummies => volto_customization}/voltosettings.md (100%) diff --git a/docs/index.md b/docs/index.md index 8076a9732..3ca373f65 100644 --- a/docs/index.md +++ b/docs/index.md @@ -20,7 +20,7 @@ mastering-plone/index mastering-plone-5/index voltohandson/index voltoaddons/index -volto4dummies/index +volto_customization/index effective-volto/index testing/index theming/index diff --git a/docs/volto4dummies/blocks.md b/docs/volto4dummies/blocks.md deleted file mode 100644 index 5edc7cf30..000000000 --- a/docs/volto4dummies/blocks.md +++ /dev/null @@ -1 +0,0 @@ -### Extend volto blocks diff --git a/docs/volto4dummies/data_adapters.md b/docs/volto4dummies/data_adapters.md deleted file mode 100644 index 367e108a1..000000000 --- a/docs/volto4dummies/data_adapters.md +++ /dev/null @@ -1 +0,0 @@ -### Enhance Teaser block with additional data diff --git a/docs/volto4dummies/extending_teasers.md b/docs/volto4dummies/extending_teasers.md deleted file mode 100644 index 43af10e29..000000000 --- a/docs/volto4dummies/extending_teasers.md +++ /dev/null @@ -1 +0,0 @@ -### Extending Teasers per type diff --git a/docs/volto4dummies/index.md b/docs/volto4dummies/index.md deleted file mode 100644 index fd38c7d1f..000000000 --- a/docs/volto4dummies/index.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -myst: - html_meta: - "description": "Volto for Dummies" - "property=og:description": "Volto for Dummies" - "property=og:title": "Volto for Dummies" - "keywords": "Plone, Volto, Training" ---- - -(effective-volto-label)= - -# Volto for Dummies - -TODO - -_Volto for Dummies_ teaches you the basics of customizing Volto without knowing a lot of React or JavaScript. - -```{toctree} ---- -caption: Volto for Dummies -name: toc-volto4dummies -maxdepth: 3 ---- - -intro -installation -addons -voltosettings -content_type -blocks -schema -styling -listing_block -teaser_variations -extending_teasers -data_adapters -component_registry -theming - -``` diff --git a/docs/volto4dummies/schema.md b/docs/volto4dummies/schema.md deleted file mode 100644 index ced56f67f..000000000 --- a/docs/volto4dummies/schema.md +++ /dev/null @@ -1 +0,0 @@ -### Blocks schema and extensions diff --git a/docs/volto4dummies/styling.md b/docs/volto4dummies/styling.md deleted file mode 100644 index c9840af82..000000000 --- a/docs/volto4dummies/styling.md +++ /dev/null @@ -1 +0,0 @@ -### Usage of StyleWrapper( Styling Schemas) and StyleMenu diff --git a/docs/volto4dummies/teaser_variations.md b/docs/volto4dummies/teaser_variations.md deleted file mode 100644 index 21a6d6010..000000000 --- a/docs/volto4dummies/teaser_variations.md +++ /dev/null @@ -1 +0,0 @@ -### Teaser block extensions and variations diff --git a/docs/volto4dummies/addons.md b/docs/volto_customization/addons.md similarity index 87% rename from docs/volto4dummies/addons.md rename to docs/volto_customization/addons.md index dd47f2a88..033870f9a 100644 --- a/docs/volto4dummies/addons.md +++ b/docs/volto_customization/addons.md @@ -195,27 +195,28 @@ export default (config) => { }; ``` -The `config` object that is passed is the Volto `configuration registry`, -the singleton module referenced throughout Volto and Volto projects, -by importing `@plone/volto/registry`. The add-on can mutate the properties of -the config, such as `settings`, `blocks`, `views`, `widgets`, or its dedicated -`addonRoutes` and `addonReducers`. +**Pro-Tip 💡** -So: {guilabel}`Volto → add-ons → project`. - -To load an add-on, the project needs to specify the add-on in the `addons` key -of `project.json`. Optional configuration loaders are specified as -a comma-separated list after the `:` colon symbol. +```{note} +If you want to register a specific profile of an addon, wrap the configuration in a function and provide it after a colon(:) next to addon name. You can also provde a comma seperated multiple loaders profiles. Note the main configuration will be loaded always. +``` ```js -// ... -"addons": [ - "volto-slate:asDefaultBlock,simpleLink", - "@eeacms/volto-tabs-block", -] -// ... +export function simpleLink(config) { + return installSimpleLink(config); +} + +export function tableButton(config) { + return installTableButton(config); +} ``` -Notice the use of `:` symbol that specifies optional configuration loaders that are exported by the add-on's `src/index.js`. +``` + ... +"addons": [ +"volto-slate:tableButton,simpleLink", +"@eeacms/volto-tabs-block", +] +... -## Develop a basic Teaser (TODO) +``` diff --git a/docs/volto_customization/blocks.md b/docs/volto_customization/blocks.md new file mode 100644 index 000000000..9871ca32e --- /dev/null +++ b/docs/volto_customization/blocks.md @@ -0,0 +1,75 @@ +### Extend volto blocks + +There are various ways of extending Volto blocks from core behaviour. The component shadowing is the plain old way of customizing components in volto. But it comes with its own problems like keeping the shadowed component up to date with latest fixes and features. +In the modern day volto development we can directly extend blocks in form of variations and extensions and populate each of them with their own schemas. + +Let us take an example for a teaser block which we already have in volto core. In our addon `volto-teaser-tutorial` we will step by step extend each component that we have in volto core. + +The most simple customization is the View of the Teaser. The volto core teaser block confiugration looks like: + +```jsx + teaser: { + id: 'teaser', + title: 'Teaser', + icon: imagesSVG, + group: 'common', + view: TeaserViewBlock, + edit: TeaserEditBlock, + restricted: false, + mostUsed: true, + sidebarTab: 1, + blockSchema: TeaserSchema, + dataAdapter: TeaserBlockDataAdapter, + variations: [ + { + id: 'default', + isDefault: true, + title: 'Default', + template: TeaserBlockDefaultBody, + }, + ], + }, +``` + +Plain and simple. Every block in Volto have Edit and View stock components. You can customize each of them individually by either shadowing or directly like: + +``` +config.blocks.blocksConfig.teaser.view = MyTeaserView + +``` + +Let's replace our Main teaser view with our `MyTeaserView` component: + +```jsx +const MyDataProvider = (props) => { + const enhancedChildren = React.Children.map(props.children, (child) => { + if (React.isValidElement(child)) { + return React.cloneElement(child, { + ...props, + enhancedProp: "some-enhanced-prop", + }); + } + return child; + }); + + return enhancedChildren; +}; + +const TeaserView = (props) => { + return ( + + + + ); +}; + +export default withBlockExtensions(TeaserView); +``` + +Here, the View component renders a TeaserBody which will be a result of an active variation, we will come to that in later chapters. + +Notice we are wrapping our TeaserBody variation in a DataProvider which may inject some extra props along with its original ones. + +```{note} 💡 +The React.cloneElement() API creates a clone of an element and returns a new React element. The cool thing is that the resulting element will have all of the original element’s props, with the new props merged in. +``` diff --git a/docs/volto4dummies/component_registry.md b/docs/volto_customization/component_registry.md similarity index 100% rename from docs/volto4dummies/component_registry.md rename to docs/volto_customization/component_registry.md diff --git a/docs/volto4dummies/content_type.md b/docs/volto_customization/content_type.md similarity index 100% rename from docs/volto4dummies/content_type.md rename to docs/volto_customization/content_type.md diff --git a/docs/volto_customization/data_adapters.md b/docs/volto_customization/data_adapters.md new file mode 100644 index 000000000..7e15802f7 --- /dev/null +++ b/docs/volto_customization/data_adapters.md @@ -0,0 +1,90 @@ +### Enhance Teaser block with additional data + +Teaser block has an ability to let user mutate or intercept block settings data from their customization. The `dataAdapter` field gets registered in Teaser configuration in order to acheive this. + +```js +teaser: { + id: 'teaser', + title: 'Teaser', + icon: imagesSVG, + group: 'common', + view: TeaserViewBlock, + edit: TeaserEditBlock, + restricted: false, + mostUsed: true, + sidebarTab: 1, + blockSchema: TeaserSchema, + dataAdapter: TeaserBlockDataAdapter, + variations: [ + { + id: 'default', + isDefault: true, + title: 'Default', + template: TeaserBlockDefaultBody, + }, + ], + }, + +``` + +The signature of `dataAdapter` is like this: + +```js +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); +}; +``` + +The above dataAdapter intercepts the blocksData and modifies its properties namely `title,description,head_title`. Note that you can also add new fields here. + +We can register our own dataAdapter in place of this by maintaining same definition. + +```{note} +In order for dataAdapters to work make sure the code of your block allows and consumes it in its implmentation. +``` + +The above Adapter gets consumed in [Data](https://github.com/plone/volto/blob/9667cf735e5c3e848de852d615941d98193e0a5e/src/components/manage/Blocks/Teaser/Data.jsx#L47) component of teaser block. + +Let's register a new `dataAdapter` our config: + +```js +config.blocks.blocksConfig.teaser.dataAdapter = myDataOwnAdapter; +``` + +In your data-adapter.js: + +```js +export const myDataOwnAdapter = ({ block, data, id, onChangeBlock, value }) => { + let dataSaved = { + ...data, + [id]: value, + }; + if (id === "title" && !isEmpty(value) && !data.title) { + dataSaved = { + ...dataSaved, + title: value[0].toUpperCase() + string.slice(1), + }; + } + onChangeBlock(block, dataSaved); +}; +``` + +We are upperCasing the first letter of title in our blocksData. Make sure to call `onChangeBlock` at the end. diff --git a/docs/volto_customization/extending_teasers.md b/docs/volto_customization/extending_teasers.md new file mode 100644 index 000000000..1c6c181c4 --- /dev/null +++ b/docs/volto_customization/extending_teasers.md @@ -0,0 +1,585 @@ +### Extending Teasers per type + +The basic scenario is to add variations to a block so that it can give control over its look and feel. Sometimes its also possible for a need to have control over individual elements. For instance, Consider we have a teaaser grid in which we can have a base variation of its layout. Then we would left with styling and adjusting individual teasers. This is where extensions come into play. + +In this chapter we will tweak our newly created variation to also support extensions per teaser block and then later we will add grid support to teasers. + +### Block Extensions + +Block extensions are the way to display a new form of your block for a particular block type. For instance if you have a teaserGrid, with block extensions you can control the styling and behaviour of individual teasers. The split of responsibilites is as follows: "the variation will control how the teasers layout and extension will control the individual rendering." + +We already learn about the block variation in the former chapters. We will now add the teaser block extenttions the same way we do for variations. + +```js +config.blocks.blocksConfig.teaser.extensions = { + ...(config.blocks.blocksConfig.teaser.extensions || {}), + cardTemplates: { + items: [ + { + id: "card", + isDefault: true, + title: "Card (default)", + template: TeaserBlockImageDefault, + }, + { + id: "imageOnRight", + isDefault: false, + title: "Image Right", + template: TeaserBlockImageRight, + }, + { + id: "imageOverlay", + isDefault: false, + title: "Image Overlay", + template: TeaserBlockImageOverlay, + }, + ], + }, +}; +``` + +As for the training we created only three extensions namely `TeaserBlockImageDefault`, `TeaserBlockImageRight` and `TeaserBlockImageOverlay`. + +In order to support these extension first we need to add a special fieldset to our variation schema so that we can seperate the concerns about individual teasers and put these extensions under it. + +Luckily, In order to do that we have a helper in volto which automatic adds a select field where we want in the schema to display variations/extensions from a particualar block. As its a standalone method we can also add a variation from a completely different block like we do in SearchBlock in volto. + +Go ahead and register that in index.js in our variation schemaEnhancer: + +```jsx +import { addExtensionFieldToSchema } from '@plone/volto/helpers/Extensions/withBlockSchemaEnhancer'; + +config.blocks.blocksConfig.teaser.variations = [ + ...config.blocks.blocksConfig.teaser.variations, + { + id: 'image-top-variation', + title: 'Image(Top) variation', + template: TeaserBlockImageVariation, + isDefault: false, + schemaEnhancer: ({ schema, FormData, intl }) => { + const extension = 'cardTemplates'; + schema.fieldsets.push({ + id: 'Cards', + title: 'Cards', + fields: [], + }); + addExtensionFieldToSchema({ + schema, + name: extension, + items: config.blocks.blocksConfig.teaser.extensions[extension]?.items, + intl, + title: { id: 'Card Type' }, + insertFieldToOrder: (schema, extension) => { + const cardFieldSet = schema.fieldsets.find( + (item) => item.id === 'Cards', + ).fields; + if (cardFieldSet.indexOf(extension) === -1) + cardFieldSet.unshift(extension); + }, + }); + ... +``` + +Notice first we added a new fieldSet where our extensions will recide and the method `addExtensionFieldToSchema` imported volto core. This method as mentioned above adds a new field in the given fieldSet with the given extenionName `cardTemplates`. + +```{note} +By default ``addExtensionFieldToSchema` adds the extewnsion field to default fieldSet, in order to ovverride that you can pass `insertFieldToOrder` method to specifiy where it should be added. + +``` + +Woot. We will now have our extensions loaded into the schema. We will have to refactor our intial Variation code to adapt the extension now. + +```{note} +The concept of extensions are only possible if the code of your block allows it. That is the reason why we created a variation out of a teaser block at the first place. +``` + +So our `TeaserBlockImageVariation` can be simplified now as: + +```jsx +import React from "react"; +import PropTypes from "prop-types"; +import { useIntl } from "react-intl"; +import cloneDeep from "lodash/cloneDeep"; +import config from "@plone/volto/registry"; + +const TeaserBlockImageVariation = (props) => { + const { data, extension = "cardTemplates" } = props; + const intl = useIntl(); + + const teaserExtenstions = + config.blocks.blocksConfig?.teaser?.extensions[extension].items; + let activeItem = teaserExtenstions.find( + (item) => item.id === data[extension] + ); + const extenionSchemaEnhancer = activeItem?.schemaEnhancer; + if (extenionSchemaEnhancer) + extenionSchemaEnhancer({ + schema: cloneDeep(config.blocks.blocksConfig?.teaser?.blockSchema), + data, + intl, + }); + const ExtensionToRender = activeItem?.template; + + return ExtensionToRender ? ( +
+ +
+ ) : null; +}; + +TeaserBlockImageVariation.propTypes = { + data: PropTypes.objectOf(PropTypes.any).isRequired, + isEditMode: PropTypes.bool, +}; + +export default TeaserBlockImageVariation; +``` + +We have added the "active extension" logic to this code and removed the templating code to their individual components under `extensions/` folder. +Notice that we can also add more schema Enhancers to our base variation schema if each extensions can provide it. + +The `ExtensionToRender` will be selected extensions from `extensions/` folder. + +Create a folder named `extensions/` within `components` and add three components provided below: + +TeaserBlockImageDefault: + +```jsx +import React from "react"; +import PropTypes from "prop-types"; +import { Message } from "semantic-ui-react"; +import { defineMessages, useIntl } from "react-intl"; + +import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; + +import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; +import { getTeaserImageURL } from "@plone/volto/components/manage/Blocks/Teaser/utils"; +import { MaybeWrap } from "@plone/volto/components"; +import { formatDate } from "@plone/volto/helpers/Utils/Date"; +import { UniversalLink } from "@plone/volto/components"; +import cx from "classnames"; +import config from "@plone/volto/registry"; + +const messages = defineMessages({ + PleaseChooseContent: { + id: "Please choose an existing content as source for this element", + defaultMessage: + "Please choose an existing content as source for this element", + }, +}); + +const DefaultImage = (props) => {props.alt; + +const TeaserBlockImageDefault = (props) => { + const { className, data, isEditMode } = props; + const locale = config.settings.dateLocale || "en"; + const intl = useIntl(); + const href = data.href?.[0]; + const image = data.preview_image?.[0]; + const align = data?.styles?.align; + const creationDate = data.href?.[0]?.CreationDate; + const formattedDate = formatDate({ + date: creationDate, + format: { + year: "numeric", + month: "short", + day: "2-digit", + }, + locale: locale, + }); + + const hasImageComponent = config.getComponent("Image").component; + const Image = config.getComponent("Image").component || DefaultImage; + const { openExternalLinkInNewTab } = config.settings; + const defaultImageSrc = + href && flattenToAppURL(getTeaserImageURL({ href, image, align })); + + return ( +
+ <> + {!href && isEditMode && ( + +
+ +

{intl.formatMessage(messages.PleaseChooseContent)}

+
+
+ )} + {href && ( + +
+ {(href.hasPreviewImage || href.image_field || image) && ( +
+ +
+ )} +
+ {data?.head_title && ( +
{data.head_title}
+ )} +

{data?.title}

+ {data.creationDate &&

{formattedDate}

} + {!data.hide_description &&

{data?.description}

} +
+
+
+ )} + +
+ ); +}; + +TeaserBlockImageDefault.propTypes = { + data: PropTypes.objectOf(PropTypes.any).isRequired, + isEditMode: PropTypes.bool, +}; + +export default TeaserBlockImageDefault; +``` + +TeaserBlockImageRight: + +```jsx +import React from "react"; +import PropTypes from "prop-types"; +import { Message } from "semantic-ui-react"; +import { defineMessages, useIntl } from "react-intl"; + +import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; + +import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; +import { getTeaserImageURL } from "@plone/volto/components/manage/Blocks/Teaser/utils"; +import { MaybeWrap } from "@plone/volto/components"; +import { formatDate } from "@plone/volto/helpers/Utils/Date"; +import { UniversalLink } from "@plone/volto/components"; +import cx from "classnames"; +import config from "@plone/volto/registry"; + +const messages = defineMessages({ + PleaseChooseContent: { + id: "Please choose an existing content as source for this element", + defaultMessage: + "Please choose an existing content as source for this element", + }, +}); + +const DefaultImage = (props) => {props.alt; + +const TeaserBlockImageRight = (props) => { + const { className, data, isEditMode } = props; + const locale = config.settings.dateLocale || "en"; + const intl = useIntl(); + const href = data.href?.[0]; + const image = data.preview_image?.[0]; + const align = data?.styles?.align; + const creationDate = data.href?.[0]?.CreationDate; + const formattedDate = formatDate({ + date: creationDate, + format: { + year: "numeric", + month: "short", + day: "2-digit", + }, + locale: locale, + }); + + const hasImageComponent = config.getComponent("Image").component; + const Image = config.getComponent("Image").component || DefaultImage; + const { openExternalLinkInNewTab } = config.settings; + const defaultImageSrc = + href && flattenToAppURL(getTeaserImageURL({ href, image, align })); + + return ( +
+ <> + {!href && isEditMode && ( + +
+ +

{intl.formatMessage(messages.PleaseChooseContent)}

+
+
+ )} + {href && ( + +
+
+ {data?.head_title && ( +
{data.head_title}
+ )} +

{data?.title}

+ {data.creationDate &&

{formattedDate}

} + {!data.hide_description &&

{data?.description}

} +
+ {(href.hasPreviewImage || href.image_field || image) && ( +
+ +
+ )} +
+
+ )} + +
+ ); +}; + +TeaserBlockImageRight.propTypes = { + data: PropTypes.objectOf(PropTypes.any).isRequired, + isEditMode: PropTypes.bool, +}; + +export default TeaserBlockImageRight; +``` + +TeaserBlockImageOverlay: + +```jsx +import React from "react"; +import PropTypes from "prop-types"; +import { Message } from "semantic-ui-react"; +import { defineMessages, useIntl } from "react-intl"; +import cloneDeep from "lodash/cloneDeep"; +import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; +import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; +import { getTeaserImageURL } from "@plone/volto/components/manage/Blocks/Teaser/utils"; +import { MaybeWrap } from "@plone/volto/components"; +import { formatDate } from "@plone/volto/helpers/Utils/Date"; +import { UniversalLink } from "@plone/volto/components"; +import cx from "classnames"; +import config from "@plone/volto/registry"; +import "./styles.less"; + +const messages = defineMessages({ + PleaseChooseContent: { + id: "Please choose an existing content as source for this element", + defaultMessage: + "Please choose an existing content as source for this element", + }, +}); + +const DefaultImage = (props) => {props.alt; + +const TeaserBlockImageOverlay = (props) => { + const { className, data, isEditMode, extension = "cardTemplates" } = props; + const locale = config.settings.dateLocale || "en"; + const intl = useIntl(); + const href = data.href?.[0]; + const image = data.preview_image?.[0]; + const align = data?.styles?.align; + const creationDate = data.href?.[0]?.CreationDate; + const formattedDate = formatDate({ + date: creationDate, + format: { + year: "numeric", + month: "short", + day: "2-digit", + }, + locale: locale, + }); + + const teaserExtenstions = + config.blocks.blocksConfig?.teaser?.extensions[extension].items; + let activeItem = teaserExtenstions.find( + (item) => item.id === data[extension] + ); + const extenionSchemaEnhancer = activeItem?.schemaEnhancer; + if (extenionSchemaEnhancer) + extenionSchemaEnhancer({ + schema: cloneDeep(config.blocks.blocksConfig?.teaser?.blockSchema), + data, + intl, + }); + + const hasImageComponent = config.getComponent("Image").component; + const Image = config.getComponent("Image").component || DefaultImage; + const { openExternalLinkInNewTab } = config.settings; + const defaultImageSrc = + href && flattenToAppURL(getTeaserImageURL({ href, image, align })); + + return ( +
+ <> + {!href && isEditMode && ( + +
+ +

{intl.formatMessage(messages.PleaseChooseContent)}

+
+
+ )} + {href && ( + +
+ {(href.hasPreviewImage || href.image_field || image) && ( +
+ +
+ )} + +
+ {data?.head_title && ( +
{data.head_title}
+ )} +
+

{data?.title}

+ {!data.hide_description &&

{data?.description}

} + {data?.creationDate && ( +

{formattedDate}

+ )} +
+
+
+
+ )} + +
+ ); +}; + +TeaserBlockImageOverlay.propTypes = { + data: PropTypes.objectOf(PropTypes.any).isRequired, + isEditMode: PropTypes.bool, +}; + +export default TeaserBlockImageOverlay; +``` + +The styles.less is to be created as well: + +```css +.gradiant { + h2 { + color: white; + } + position: absolute; + bottom: 30px; + display: flex; + width: 100%; + height: 200px; + align-items: flex-end; + padding: 1.5rem; + background-image: linear-gradient( + 13.39deg, + rgba(46, 62, 76, 0.65) 38.6%, + rgba(46, 62, 76, 0.169) 59.52%, + rgba(69, 95, 106, 0) 79.64% + ); +} + +.teaser-item.overlay { + display: flex; + + .image-wrapper { + width: 100%; + } +} + +.has--objectFit--contain { + img { + object-fit: contain !important; + } +} + +.has--objectFit--cover { + img { + object-fit: cover !important; + } +} + +.has--objectFit--fill { + img { + object-fit: fill !important; + } +} + +.has--objectFit--scale-down { + img { + object-fit: scale-down !important; + } +} +``` + +Great. We now have extension per teaser in our block which controls each item individually. + +### Grid support to Teasers + +As mentioned before we will add grid support in our project to be able to have a whole `teaserGrid` working properly along with our extended code. In order to demonstrate it, we need to list teasers in grid system. We'll use `@kitconcept/volto-blocks-grid` for that and extend it in our own ways. + +First add `@kitconcept/volto-blocks-grid` in addons key and dependencies in package.json of your project's config. + +In your project's config: + +```js +addons: [ + "@kitconcept/volto-blocks-grid", + "volto-teaser-tutorial", +] + +dependencies: [ + "@kitconcept/volto-blocks-grid": "*" +] +``` + +```{note} +Its essential that we load `volto-teaser-tutorial` after volto-blocks-grid so that we overrride teaser block the right way. +``` + +Now since, grid block from `@kitconcept/volto-blocks-grid` uses teaser from its blocksConfig we need to override it with our teaser block so that it is used instead of the one in `@kitconcept/volto-blocks-grid`. + +In your volto-teaser-tutorial addon's `index.js`: + +```js +if ( + config.blocks.blocksConfig?.__grid?.blocksConfig?.teaser && + config.blocks.blocksConfig?.teaser +) { + //This ensures that grid block uses our overrideen teaser + config.blocks.blocksConfig.__grid.blocksConfig.teaser = + config.blocks.blocksConfig.teaser; +} +``` + +Woot. We will now have a grid block with our teaser variations so that each teaser can now have its own set of extensions. diff --git a/docs/volto_customization/index.md b/docs/volto_customization/index.md new file mode 100644 index 000000000..e4ca89f8a --- /dev/null +++ b/docs/volto_customization/index.md @@ -0,0 +1,40 @@ +--- +myst: + html_meta: + "description": "Volto Customization for JavaScript Beginners" + "property=og:description": "Volto Customization for JavaScript Beginners" + "property=og:title": "Volto Customization for JavaScript Beginners" + "keywords": "Plone, Volto, Training" +--- + +(effective-volto-label)= + +# Volto Customization for JavaScript Beginners + +TODO + +_Volto Customization for JavaScript Beginners_ teaches you the basics of customizing Volto without knowing a lot of React or JavaScript. + +```{toctree} +--- +caption: Volto Customization for JavaScript Beginners +name: toc-voltocustomization +maxdepth: 3 +--- + +intro +installation +addons +voltosettings +content_type +blocks +schema +styling +data_adapters +teaser_variations +extending_teasers +listing_block +component_registry +theming + +``` diff --git a/docs/volto4dummies/installation.md b/docs/volto_customization/installation.md similarity index 100% rename from docs/volto4dummies/installation.md rename to docs/volto_customization/installation.md diff --git a/docs/volto4dummies/intro.md b/docs/volto_customization/intro.md similarity index 100% rename from docs/volto4dummies/intro.md rename to docs/volto_customization/intro.md diff --git a/docs/volto4dummies/listing_block.md b/docs/volto_customization/listing_block.md similarity index 100% rename from docs/volto4dummies/listing_block.md rename to docs/volto_customization/listing_block.md diff --git a/docs/volto_customization/schema.md b/docs/volto_customization/schema.md new file mode 100644 index 000000000..bce1ce678 --- /dev/null +++ b/docs/volto_customization/schema.md @@ -0,0 +1,203 @@ +### Blocks schema and variations + +In the previous chapter we just replaced or enhanced our View component by directly mutating the View in the Blocks engine. Now since all the blocks in principle should be schema based and should use `BlockDataForm` we do have another concept of extending Blocks with respect to schema. + +The `BlockDataForm` renders a schemaEnhanced form ready to be used along with the variations support. + +The variations are various "View" mode options that your block might have whether its layout, the designs or a completely enhanced form of a block. We don't need to shadow or customize any block in order to obtain a desired structure. + +So in the current schema for teaser block we have: + +```js + teaser: { + id: 'teaser', + title: 'Teaser', + icon: imagesSVG, + group: 'common', + view: TeaserViewBlock, + edit: TeaserEditBlock, + restricted: false, + mostUsed: true, + sidebarTab: 1, + blockSchema: TeaserSchema, + dataAdapter: TeaserBlockDataAdapter, + variations: [ + { + id: 'default', + isDefault: true, + title: 'Default', + template: TeaserBlockDefaultBody, + }, + ], + }, +``` + +Notice the variations key, in which we can have multiple view templates for a given block. Right now its going to use the default one which is the [TeaserBlockDefaultBody](https://github.com/plone/volto/blob/985e419396b4d00567d12e7e309ea420012e9cc7/src/components/manage/Blocks/Teaser/DefaultBody.jsx#L1). + +We are going to create a new variation of this teaser block. This variation is essential because using it we are gonna create block extension per teaser. Later we can also enhance this variation with the new schema. + +Go ahead and register it in the variations key like: + +```js + variations: [ + { + id: 'default', + isDefault: true, + title: 'Default', + template: TeaserBlockDefaultBody, + }, + { + id: 'image-top-variation', + title: 'Image(Top) variation', + template: TeaserBlockImageVariation, + }, + ], +``` + +We should create this view template in our `components/TeaserBlockImageVariation.jsx` + +TeaserBlockImageVariation.jsx: + +```jsx +import React from "react"; +import PropTypes from "prop-types"; +import { Message } from "semantic-ui-react"; +import { defineMessages, useIntl } from "react-intl"; + +import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; + +import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; +import { getTeaserImageURL } from "@plone/volto/components/manage/Blocks/Teaser/utils"; +import { MaybeWrap } from "@plone/volto/components"; +import { formatDate } from "@plone/volto/helpers/Utils/Date"; +import { UniversalLink } from "@plone/volto/components"; +import cx from "classnames"; +import config from "@plone/volto/registry"; + +const messages = defineMessages({ + PleaseChooseContent: { + id: "Please choose an existing content as source for this element", + defaultMessage: + "Please choose an existing content as source for this element", + }, +}); + +const DefaultImage = (props) => {props.alt; + +const TeaserBlockImageDefault = (props) => { + const { className, data, isEditMode } = props; + const locale = config.settings.dateLocale || "en"; + const intl = useIntl(); + const href = data.href?.[0]; + const image = data.preview_image?.[0]; + const align = data?.styles?.align; + const creationDate = data.href?.[0]?.CreationDate; + const formattedDate = formatDate({ + date: creationDate, + format: { + year: "numeric", + month: "short", + day: "2-digit", + }, + locale: locale, + }); + + const hasImageComponent = config.getComponent("Image").component; + const Image = config.getComponent("Image").component || DefaultImage; + const { openExternalLinkInNewTab } = config.settings; + const defaultImageSrc = + href && flattenToAppURL(getTeaserImageURL({ href, image, align })); + + return ( +
+ <> + {!href && isEditMode && ( + +
+ +

{intl.formatMessage(messages.PleaseChooseContent)}

+
+
+ )} + {href && ( + +
+ {(href.hasPreviewImage || href.image_field || image) && ( +
+ +
+ )} +
+ {data?.head_title && ( +
{data.head_title}
+ )} +

{data?.title}

+ {data.creationDate &&

{formattedDate}

} + {!data.hide_description &&

{data?.description}

} +
+
+
+ )} + +
+ ); +}; + +TeaserBlockImageDefault.propTypes = { + data: PropTypes.objectOf(PropTypes.any).isRequired, + isEditMode: PropTypes.bool, +}; + +export default TeaserBlockImageDefault; +``` + +styles.less: + +```css +.gradiant { + h2 { + color: white; + } + position: absolute; + bottom: 30px; + display: flex; + width: 100%; + height: 200px; + align-items: flex-end; + padding: 1.5rem; + background-image: linear-gradient( + 13.39deg, + rgba(46, 62, 76, 0.65) 38.6%, + rgba(46, 62, 76, 0.169) 59.52%, + rgba(69, 95, 106, 0) 79.64% + ); +} + +.teaser-item.overlay { + display: flex; + + .image-wrapper { + width: 100%; + } +} +``` + +Right now it this variation only shows default variation of Teaser block. In the coming chapter we are gonna enhance it with extension per teaser. + +```{note} +The [Body](https://github.com/plone/volto/blob/9667cf735e5c3e848de852d615941d98193e0a5e/src/components/manage/Blocks/Teaser/Body.jsx#L13) component in Teaser block also supports variations from component registry. You can read more about component registry in following chapters. +``` diff --git a/docs/volto_customization/styling.md b/docs/volto_customization/styling.md new file mode 100644 index 000000000..ac3c1ac4f --- /dev/null +++ b/docs/volto_customization/styling.md @@ -0,0 +1,194 @@ +### Usage of StyleWrapper( Styling Schemas) and StyleMenu + +Its essential to also control the styling of Blocks and most importantly if the styling is done based on schema. In Volto we have a central wrapper named [`StyleWrapper`](https://github.com/plone/volto/blob/9667cf735e5c3e848de852d615941d98193e0a5e/src/components/manage/Blocks/Block/StyleWrapper.jsx#L1) which wraps around all the View template of Blocks. The job of stylewrapper is to build and inject style classNames into its children. + +In the schema at any point in time, we can call a volto helper which adds `styles` fields. Which then gets converted into classNames with the prefix `--has`. Its upto the theme owner in which way they want to add css for it. +Simply, the job of StyleWrapper is to inject classNames(build from schema) into their children. + +We see that in our Teaser config volto already calls the [addStyling](https://github.com/plone/volto/blob/9667cf735e5c3e848de852d615941d98193e0a5e/src/helpers/Extensions/withBlockSchemaEnhancer.js#L297) in the schema. The job of this function is to add styles field in the styling fieldset in schema provided. + +```jsx +export const TeaserSchema = ({ intl }) => { + const schema = { + title: intl.formatMessage(messages.teaser), + fieldsets: [ + { + id: "default", + title: "Default", + fields: ["href", "title", "head_title", "description", "preview_image"], + }, + ], + + properties: { + href: { + title: intl.formatMessage(messages.Target), + widget: "object_browser", + mode: "link", + selectedItemAttrs: [ + "Title", + "head_title", + "Description", + "hasPreviewImage", + "image_field", + "image_scales", + "@type", + ], + allowExternals: true, + }, + title: { + title: intl.formatMessage(messages.title), + }, + head_title: { + title: intl.formatMessage(messages.head_title), + }, + description: { + title: intl.formatMessage(messages.description), + widget: "textarea", + }, + preview_image: { + title: intl.formatMessage(messages.imageOverride), + widget: "object_browser", + mode: "image", + allowExternals: true, + selectedItemAttrs: ["image_field", "image_scales"], + }, + openLinkInNewTab: { + title: intl.formatMessage(messages.openLinkInNewTab), + type: "boolean", + }, + }, + required: [], + }; + + addStyling({ schema, intl }); + + schema.properties.styles.schema.properties.align = { + widget: "align", + title: intl.formatMessage(messages.align), + actions: ["left", "right", "center"], + default: "left", + }; + + schema.properties.styles.schema.fieldsets[0].fields = ["align"]; + + return schema; +}; +``` + +and then we can manipulate those fields by adding whatever styles we want. Let's extend it and add one more style named as image object-fit css property. + +In your variation schemaEnhancer: + +```js +config.blocks.blocksConfig.teaser.variations = [ + ...config.blocks.blocksConfig.teaser.variations, + { + id: "image-top-variation", + title: "Image(Top) variation", + template: TeaserBlockImageVariation, + isDefault: false, + schemaEnhancer: ({ schema, FormData, intl }) => { + schema.fieldsets[0].fields.push("creationDate"); + schema.properties.creationDate = { + title: "Show creation Date", + type: "boolean", + }; + schema.properties.href.selectedItemAttrs.push("CreationDate"); + + schema.properties.styles.schema.properties.objectFit = { + title: "Object fit", + description: "Css object fit property", + choices: [ + ["cover", "cover"], + ["contain", "contain"], + ["fill", "fill"], + ["scale-down", "scale-down"], + ["none", "none"], + ], + }; + + schema.properties.styles.schema.fieldsets[0].fields.push("objectFit"); + return schema; + }, + }, +]; +``` + +As StyleWrapper wraps around our view component in `RenderBlocks`. The styleNames should be available in our component's rendered html. + +``` + +``` + +Go ahead and add classNames in your `css/less` files + +```css +.has--objectFit--contain { + img { + object-fit: contain !important; + } +} + +.has--objectFit--cover { + img { + object-fit: cover !important; + } +} + +.has--objectFit--fill { + img { + object-fit: fill !important; + } +} + +.has--objectFit--scale-down { + img { + object-fit: scale-down !important; + } +} +``` + +### StyleMenu + +StyleMenu is not the part of Blocks engine instead its a volto-slate plugin and its used to style rich text content only. + +In your policy package, you can add styleMenu configuration like: + +```js +config.settings.slate.styleMenu = { + ...(config.settings.slate.styleMenu || {}), + blockStyles: [ + { + cssClass: "primary", + label: "Primary", + icon: () => , + }, + { + cssClass: "secondary", + label: "Secondary", + icon: () => , + }, + { + cssClass: "tertiary", + label: "Tertiary", + icon: () => , + }, + ], +}; +``` + +Make sure to add relevant classNames in your css. diff --git a/docs/volto_customization/teaser_variations.md b/docs/volto_customization/teaser_variations.md new file mode 100644 index 000000000..ef7f57c83 --- /dev/null +++ b/docs/volto_customization/teaser_variations.md @@ -0,0 +1,166 @@ +### Teaser block variations Schemas + +Now that we have learnt on how to add a new variation to a teaser block. Sometimes its important to also have schemas of those variations merged into the main schema. So each variation can come up with its own set of schema. We can use `schemaEnhancers` for this purpose. + +schemaEnhancers works on the concept of composition. They are just functions which take original schema, formdata and intl and return modified schema based on its arguments. + +In our variation, lets add a schemaEnhancer to modify existing schema and add a `CreationDate` from catalog metadata brain. + +```js +config.blocks.blocksConfig.teaser.variations = [ + ...config.blocks.blocksConfig.teaser.variations, + { + id: "image-top-variation", + title: "Image(Top) variation", + template: TeaserBlockImageVariation, + isDefault: false, + schemaEnhancer: ({ schema, FormData, intl }) => { + schema.fieldsets[0].fields.push("creationDate"); + schema.properties.creationDate = { + title: "Show creation Date", + type: "boolean", + }; + schema.properties.href.selectedItemAttrs.push("CreationDate"); + return schema; + }, + }, +]; +``` + +And then in your code of that variation, you should consume that field accordingly. + +```js +const creationDate = data.href?.[0]?.CreationDate; +const formattedDate = formatDate({ + date: creationDate, + format: { + year: "numeric", + month: "short", + day: "2-digit", + }, + locale: locale, +}); +``` + +`data.href` contains the catalog brain properties which are requested via `selectedItemAttrs`. CreationDate is one of them. Notice we are using formatDate from Volto helpers which is used to parse date into respective formats on the basis of locales. + +Finaly render it conditionally on the basis of data.creationDate + +```jsx +{ + data?.creationDate &&

{formattedDate}

; +} +``` + +The whole component looks like: + +```jsx +import React from "react"; +import PropTypes from "prop-types"; +import { Message } from "semantic-ui-react"; +import { defineMessages, useIntl } from "react-intl"; +import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; +import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; +import { getTeaserImageURL } from "@plone/volto/components/manage/Blocks/Teaser/utils"; +import { MaybeWrap } from "@plone/volto/components"; +import { formatDate } from "@plone/volto/helpers/Utils/Date"; +import { UniversalLink } from "@plone/volto/components"; +import cx from "classnames"; +import config from "@plone/volto/registry"; +import "./styles.less"; + +const messages = defineMessages({ + PleaseChooseContent: { + id: "Please choose an existing content as source for this element", + defaultMessage: + "Please choose an existing content as source for this element", + }, +}); + +const DefaultImage = (props) => {props.alt; + +const TeaserBlockImageOverlay = (props) => { + const { className, data, isEditMode } = props; + const locale = config.settings.dateLocale || "en"; + const intl = useIntl(); + const href = data.href?.[0]; + const image = data.preview_image?.[0]; + const align = data?.styles?.align; + const creationDate = data.href?.[0]?.CreationDate; + const formattedDate = formatDate({ + date: creationDate, + format: { + year: "numeric", + month: "short", + day: "2-digit", + }, + locale: locale, + }); + + const hasImageComponent = config.getComponent("Image").component; + const Image = config.getComponent("Image").component || DefaultImage; + const { openExternalLinkInNewTab } = config.settings; + const defaultImageSrc = + href && flattenToAppURL(getTeaserImageURL({ href, image, align })); + + return ( +
+ <> + {!href && isEditMode && ( + +
+ +

{intl.formatMessage(messages.PleaseChooseContent)}

+
+
+ )} + {href && ( + +
+ {(href.hasPreviewImage || href.image_field || image) && ( +
+ +
+ )} + +
+ {data?.head_title && ( +
{data.head_title}
+ )} +
+

{data?.title}

+ {!data.hide_description &&

{data?.description}

} + {data?.creationDate && ( +

{formattedDate}

+ )} +
+
+
+
+ )} + +
+ ); +}; + +TeaserBlockImageOverlay.propTypes = { + data: PropTypes.objectOf(PropTypes.any).isRequired, + isEditMode: PropTypes.bool, +}; + +export default TeaserBlockImageOverlay; +``` diff --git a/docs/volto4dummies/theming.md b/docs/volto_customization/theming.md similarity index 100% rename from docs/volto4dummies/theming.md rename to docs/volto_customization/theming.md diff --git a/docs/volto4dummies/voltosettings.md b/docs/volto_customization/voltosettings.md similarity index 100% rename from docs/volto4dummies/voltosettings.md rename to docs/volto_customization/voltosettings.md From 4fbd65d94233d52672cf7d4288f3b02aba2b8b0c Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Sun, 17 Sep 2023 18:24:18 +0200 Subject: [PATCH 05/32] add chapter on configuration --- docs/volto_customization/voltosettings.md | 75 +++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/docs/volto_customization/voltosettings.md b/docs/volto_customization/voltosettings.md index 40ea27a66..1a648afe4 100644 --- a/docs/volto_customization/voltosettings.md +++ b/docs/volto_customization/voltosettings.md @@ -1 +1,76 @@ ### Most useful volto settings + +You can configure Volto by modifying settings in a js-file. + +This is the original ``config.js`` of a project where the registry is imported and returned unchanged. + +```js +import '@plone/volto/config'; + +export default function applyConfig(config) { + // Add here your project's configuration here by modifying `config` accordingly + return config; +} +``` + +Here three settings are changed: + +```js +import '@plone/volto/config'; + +export default function applyConfig(config) { + config.settings = { + ...config.settings, + navDepth: 3, + openExternalLinkInNewTab: true, + hasWorkingCopySupport: true, + }; + return config; +}; +``` + +```{note} +The `...` is a use of the [spread-syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) that "expands" the configuration into its elements and allows to change existing values and add new ones. +``` + +Some of the settings are duplicates of setting existing in the Plone backend. +For example the setting `supportedLanguages` must match the one set in the Plone registry as `plone.available_languages` and in `plone.default_language`. + +To use Volto in a multilingual project you do this: + +```js +import '@plone/volto/config'; + +export default function applyConfig(config) { + config.settings = { + ...config.settings, + defaultLanguage: 'de', + isMultilingual: true, + supportedLanguages: ['en', 'de', 'fr'], + }; + return config; +}; +``` + +```{seealso} +{doc}`plone6docs:volto/configuration/multilingual` +``` + +Here are some more setting you might use in your projects: + +* `contentIcons` - configure Content Types icons. See https://6.docs.plone.org/volto/configuration/settings-reference.html#term-contentIcons +* `navDepth` - Navigation levels depth used in the navigation endpoint calls. Increasing this is useful for implementing fat navigation menus. +* `workflowMapping` - colors for workflow states/transitions. +* `openExternalLinkInNewTab` +* `hasWorkingCopySupport` +* `maxFileUploadSize` + +You can find all existing options in the file [config/index.js](https://github.com/plone/volto/blob/master/src/config/index.js#L73) of Volto itself which is available in your projects in `frontend/omelette/src/config/index.js`. + +```{seealso} +Many options are explained in the {doc}`plone6docs:volto/configuration/settings-reference` +``` + +You can not only change but also extend Volto here by extending existing configuration options or adding new ones. + +For example here you add new blocks, cusomize existing blocks or configure what view/template is used for viewing a certain content-type. From 600c5496d6bddd5dd5fee652b2a012ffbc18df3e Mon Sep 17 00:00:00 2001 From: nileshgulia1 Date: Sat, 23 Sep 2023 00:08:09 +0530 Subject: [PATCH 06/32] listing block variation,extensions,wip:volto-settings --- .../volto_customization/component_registry.md | 1 - docs/volto_customization/index.md | 2 - docs/volto_customization/listing_block.md | 215 ++++++++++++++++++ docs/volto_customization/theming.md | 1 - docs/volto_customization/voltosettings.md | 30 +-- 5 files changed, 231 insertions(+), 18 deletions(-) delete mode 100644 docs/volto_customization/component_registry.md delete mode 100644 docs/volto_customization/theming.md diff --git a/docs/volto_customization/component_registry.md b/docs/volto_customization/component_registry.md deleted file mode 100644 index 179e8f581..000000000 --- a/docs/volto_customization/component_registry.md +++ /dev/null @@ -1 +0,0 @@ -### component Registry( Can be moved to configuration) diff --git a/docs/volto_customization/index.md b/docs/volto_customization/index.md index e4ca89f8a..47b3a457c 100644 --- a/docs/volto_customization/index.md +++ b/docs/volto_customization/index.md @@ -34,7 +34,5 @@ data_adapters teaser_variations extending_teasers listing_block -component_registry -theming ``` diff --git a/docs/volto_customization/listing_block.md b/docs/volto_customization/listing_block.md index e2add32da..8ea39bcf3 100644 --- a/docs/volto_customization/listing_block.md +++ b/docs/volto_customization/listing_block.md @@ -1 +1,216 @@ ### create a simple listing block variation + +We will create a variation for listing block, the approach is the same we did for teasers. A new variation which will control the layout and extensions which will take care of individual items styling. + +First of all let's add a styling fieldset in the current schema of volto's default listing block . + +In your addon config: + +```js +if (config.blocks.blocksConfig.listing) { + config.blocks.blocksConfig.listing.title = "Listing (Tutorial)"; + config.blocks.blocksConfig.listing.schemaEnhancer = addStylingFieldset; +} +``` + +Create a file named `helpers.js` and add the relevant schema enhancer for it: + +```js +import { cloneDeep } from "lodash"; +import imageNarrowSVG from "@plone/volto/icons/image-narrow.svg"; +import imageFitSVG from "@plone/volto/icons/image-fit.svg"; +import imageWideSVG from "@plone/volto/icons/image-wide.svg"; +import imageFullSVG from "@plone/volto/icons/image-full.svg"; + +export const ALIGN_INFO_MAP = { + narrow_width: [imageNarrowSVG, "Narrow width"], + container_width: [imageFitSVG, "Container width"], + wide_width: [imageWideSVG, "Wide width"], + full: [imageFullSVG, "Full width"], +}; + +export const addStylingFieldset = ({ schema }) => { + const applied = schema?.properties?.styles; + + if (!applied) { + const resSchema = cloneDeep(schema); + + resSchema.fieldsets.push({ + id: "styling", + fields: ["styles"], + title: "Styling", + }); + resSchema.properties.styles = { + widget: "object", + title: "Styling", + schema: { + fieldsets: [ + { + id: "default", + title: "Default", + fields: ["size"], + }, + ], + properties: { + size: { + widget: "align", + title: "Section size", + actions: Object.keys(ALIGN_INFO_MAP), + actionsInfoMap: ALIGN_INFO_MAP, + }, + }, + required: [], + }, + }; + return resSchema; + } + + return schema; +}; +``` + +This function will inject styles field into the schema if isn't present already. We can add relevant styling here. Volto will build classNames based on the styles as mentioned in the earlier chapters. We will have to provide our own css for the generated classNames. + +```less +#main .has--size--narrow_width, +#main .narrow_width, +[class~="narrow_view"] [id="page-document"] > * { + max-width: var(--narrow-text-width, 500px) !important; +} + +#main .container_width, +#main .has--size--container_width, +.view-wrapper > *, +[class~="view-defaultview"] [id="page-document"] > *, +[class~="view-viewview"] [id="page-document"] > * { + max-width: var(--container-text-width, 1120px) !important; +} +``` + +In order to have a control over individual items in the listing let's create a sample variation of listing block. + +```js +import ListingVariation from 'volto-teaser-tutorial/components/ListingBlockVariation'; + + + config.blocks.blocksConfig.listing.variations = [ + ...(config.blocks.blocksConfig.listing.variations || []) + { + id: 'tutorial', + isDefault: false, + title: 'Sample Variation', + template: ListingVariation, + schemaEnhancer: ({ schema, FormData, intl }) => { + const extension = 'cardTemplates'; + schema.fieldsets.push({ + id: 'Cards', + title: 'Cards', + fields: [], + }); + addExtensionFieldToSchema({ + schema, + name: extension, + items: config.blocks.blocksConfig.teaser.extensions[extension]?.items, + intl, + title: { id: 'Card Type' }, + insertFieldToOrder: (schema, extension) => { + const cardFieldSet = schema.fieldsets.find( + (item) => item.id === 'Cards', + ).fields; + if (cardFieldSet.indexOf(extension) === -1) + cardFieldSet.unshift(extension); + }, + }); + return schema; + }, + }, + ] + +``` + +Notice that here we will keep the schemaEnhancer configuration of teaser extensions. For better readability we can also move these lines of code into a `baseSchemaEnhancer` which will serve for both listing and teaser block extensions. But we can leave it up to the user for now. + +Finally we write our own variation for ListingBlock: + +ListingVariation.jsx + +```jsx +import React from "react"; +import PropTypes from "prop-types"; +import cloneDeep from "lodash/cloneDeep"; +import { useIntl } from "react-intl"; +import { ConditionalLink, UniversalLink } from "@plone/volto/components"; +import { flattenToAppURL } from "@plone/volto/helpers"; +import config from "@plone/volto/registry"; + +import { isInternalURL } from "@plone/volto/helpers/Url/Url"; + +const ListingVariation = (props) => { + const { + items, + linkTitle, + linkHref, + isEditMode, + data, + extension = "cardTemplates", + } = props; + let link = null; + let href = linkHref?.[0]?.["@id"] || ""; + + if (isInternalURL(href)) { + link = ( + + {linkTitle || href} + + ); + } else if (href) { + link = {linkTitle || href}; + } + + const intl = useIntl(); + + const teaserExtenstions = + config.blocks.blocksConfig?.teaser?.extensions[extension].items; + let activeItem = teaserExtenstions.find( + (item) => item.id === props?.[extension] + ); + const extenionSchemaEnhancer = activeItem?.schemaEnhancer; + if (extenionSchemaEnhancer) + extenionSchemaEnhancer({ + schema: cloneDeep(config.blocks.blocksConfig?.teaser?.blockSchema), + data: data || props, + intl, + }); + const ExtensionToRender = activeItem?.template; + + return ( + <> +
+ {items.map((item) => ( +
+ +
+ ))} +
+ + {link &&
{link}
} + + ); +}; + +ListingVariation.propTypes = { + items: PropTypes.arrayOf(PropTypes.any).isRequired, + linkMore: PropTypes.any, + isEditMode: PropTypes.bool, +}; +export default ListingVariation; +``` + +We will now have the per listing item styling support like we have for teaser blocks. We can also add more styling schema with the help of its individual schema extenders. diff --git a/docs/volto_customization/theming.md b/docs/volto_customization/theming.md deleted file mode 100644 index b17d0fd44..000000000 --- a/docs/volto_customization/theming.md +++ /dev/null @@ -1 +0,0 @@ -### Theming diff --git a/docs/volto_customization/voltosettings.md b/docs/volto_customization/voltosettings.md index 1a648afe4..972d32af1 100644 --- a/docs/volto_customization/voltosettings.md +++ b/docs/volto_customization/voltosettings.md @@ -2,10 +2,10 @@ You can configure Volto by modifying settings in a js-file. -This is the original ``config.js`` of a project where the registry is imported and returned unchanged. +This is the original `config.js` of a project where the registry is imported and returned unchanged. ```js -import '@plone/volto/config'; +import "@plone/volto/config"; export default function applyConfig(config) { // Add here your project's configuration here by modifying `config` accordingly @@ -16,7 +16,7 @@ export default function applyConfig(config) { Here three settings are changed: ```js -import '@plone/volto/config'; +import "@plone/volto/config"; export default function applyConfig(config) { config.settings = { @@ -26,7 +26,7 @@ export default function applyConfig(config) { hasWorkingCopySupport: true, }; return config; -}; +} ``` ```{note} @@ -39,17 +39,17 @@ For example the setting `supportedLanguages` must match the one set in the Plone To use Volto in a multilingual project you do this: ```js -import '@plone/volto/config'; +import "@plone/volto/config"; export default function applyConfig(config) { config.settings = { ...config.settings, - defaultLanguage: 'de', + defaultLanguage: "de", isMultilingual: true, - supportedLanguages: ['en', 'de', 'fr'], + supportedLanguages: ["en", "de", "fr"], }; return config; -}; +} ``` ```{seealso} @@ -58,12 +58,13 @@ export default function applyConfig(config) { Here are some more setting you might use in your projects: -* `contentIcons` - configure Content Types icons. See https://6.docs.plone.org/volto/configuration/settings-reference.html#term-contentIcons -* `navDepth` - Navigation levels depth used in the navigation endpoint calls. Increasing this is useful for implementing fat navigation menus. -* `workflowMapping` - colors for workflow states/transitions. -* `openExternalLinkInNewTab` -* `hasWorkingCopySupport` -* `maxFileUploadSize` +- `contentIcons` - configure Content Types icons. See https://6.docs.plone.org/volto/configuration/settings-reference.html#term-contentIcons +- `navDepth` - Navigation levels depth used in the navigation endpoint calls. Increasing this is useful for implementing fat navigation menus. +- `workflowMapping` - colors for workflow states/transitions. +- `openExternalLinkInNewTab` +- `hasWorkingCopySupport` +- `maxFileUploadSize` +- `nonContentRoutes` - A list of path strings which are considered to be outside of plone-restapi's content serialization. For example: `/controlpanel, /login,/sitemap,/personal-information` are all nonContentRoutes. You can find all existing options in the file [config/index.js](https://github.com/plone/volto/blob/master/src/config/index.js#L73) of Volto itself which is available in your projects in `frontend/omelette/src/config/index.js`. @@ -74,3 +75,4 @@ Many options are explained in the {doc}`plone6docs:volto/configuration/settings- You can not only change but also extend Volto here by extending existing configuration options or adding new ones. For example here you add new blocks, cusomize existing blocks or configure what view/template is used for viewing a certain content-type. +Here are the most useful volto settings which we have for a typical volto project. From e680d8d0430a91cb6e24eff07c8e4bc348d73f3f Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Sat, 23 Sep 2023 12:14:28 +0200 Subject: [PATCH 07/32] add shadowing chapter (pointing to mastering plone) --- docs/volto_customization/content_type.md | 1 - docs/volto_customization/index.md | 2 +- docs/volto_customization/shadowing.md | 20 ++++++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) delete mode 100644 docs/volto_customization/content_type.md create mode 100644 docs/volto_customization/shadowing.md diff --git a/docs/volto_customization/content_type.md b/docs/volto_customization/content_type.md deleted file mode 100644 index 13486519f..000000000 --- a/docs/volto_customization/content_type.md +++ /dev/null @@ -1 +0,0 @@ -### Create and modify Content-type Views diff --git a/docs/volto_customization/index.md b/docs/volto_customization/index.md index 47b3a457c..f5f0ae9b3 100644 --- a/docs/volto_customization/index.md +++ b/docs/volto_customization/index.md @@ -26,7 +26,7 @@ intro installation addons voltosettings -content_type +shadowing blocks schema styling diff --git a/docs/volto_customization/shadowing.md b/docs/volto_customization/shadowing.md new file mode 100644 index 000000000..759a52fca --- /dev/null +++ b/docs/volto_customization/shadowing.md @@ -0,0 +1,20 @@ +### Customize Content-type Views and other Components + +You can customize all components of Volto using a technique called component shadowing. + +Basically you copy the component (i.e. the file) to a folder `customizations` keeping the same folder-structure and the overridden file will replace the original. + +```{tip} +Those familiar with Plone's JBOT (just a bunch of templates) customizing add-on will recognize this pattern since it works the same way, except that here you have to create exactly the same folder structure hierarchy of the original component instead of using the dotted notation used in JBOT overrides. +``` + +To avoid duplication we simply follow the chapter {ref}`volto-overrides-label` of the Mastering Plone Training. + +In that chapter you learn how to override the logo, the footer, the news-item view and the default listing-block. + + +```{seealso} +- {ref}`voltohandson-header-component-label` (Volto Hands-On Training) +- {doc}`plone6docs:volto/recipes/customizing-components` (Plone Frontend Documentation) +- {doc}`plone6docs:volto/recipes/customizing-views` (Plone Frontend Documentation) +``` From 200618d75517b5ff214e9451724c654e5806daf2 Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Mon, 25 Sep 2023 15:23:15 +0300 Subject: [PATCH 08/32] update intro doc --- docs/volto_customization/index.md | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/volto_customization/index.md b/docs/volto_customization/index.md index f5f0ae9b3..406aeb5a3 100644 --- a/docs/volto_customization/index.md +++ b/docs/volto_customization/index.md @@ -11,9 +11,30 @@ myst: # Volto Customization for JavaScript Beginners -TODO +Are you new to JavaScript development and eager to explore the world of Volto customization? Unlock the power of Volto, the modern React-based CMS framework for Plone, by joining our comprehensive half day training designed specifically for JavaScript beginners. -_Volto Customization for JavaScript Beginners_ teaches you the basics of customizing Volto without knowing a lot of React or JavaScript. +Level +: Beginner + +What You'll Learn: + +: In this hands-on training, you will embark on a journey to master Volto customization from the ground up. Whether you're a developer looking to expand your skill set or someone entirely new to JavaScript, this course will provide you with the knowledge and tools to excel in Volto development. Here's what you can expect to learn: + * Introduction to Volto: Get acquainted with Volto's architecture, key concepts, and its role in modern web development. + * JavaScript Fundamentals: Build a strong foundation in JavaScript, covering essential topics like variables, functions, and data structures. + * React Essentials: Dive into React, the heart of Volto, and learn how to create dynamic user interfaces using React components. + * Customizing Volto: Explore the art of customizing Volto projects, from theming and styling to creating custom blocks. + * Building Blocks: Discover the building blocks of a Volto project, including new variations. + * Best Practices: Gain insights into industry best practices for efficient Volto development. + +Who Should Attend: + +: This training program is tailored for: + * JavaScript beginners looking to enter the world of Volto and React. + * Developers interested in extending their expertise to include Volto customization. + +Prerequisites: + +: No prior experience with Volto is required. However, a basic understanding of web development concepts and basic JavaScript knowledge will be beneficial. ```{toctree} --- From f0f1dfc8889fc5a71b0aca099681aaf9a02e6bab Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Mon, 25 Sep 2023 15:32:27 +0300 Subject: [PATCH 09/32] fix upper case for section title --- docs/volto_customization/listing_block.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/volto_customization/listing_block.md b/docs/volto_customization/listing_block.md index 8ea39bcf3..75e2cd2e4 100644 --- a/docs/volto_customization/listing_block.md +++ b/docs/volto_customization/listing_block.md @@ -1,4 +1,4 @@ -### create a simple listing block variation +### Create a simple listing block variation We will create a variation for listing block, the approach is the same we did for teasers. A new variation which will control the layout and extensions which will take care of individual items styling. From 26f61537fdd188a897c8a2daf9d11e325273694f Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Mon, 25 Sep 2023 16:07:55 +0300 Subject: [PATCH 10/32] add meta --- docs/volto_customization/addons.md | 4 ++-- docs/volto_customization/blocks.md | 9 +++++++++ docs/volto_customization/data_adapters.md | 9 +++++++++ docs/volto_customization/extending_teasers.md | 9 +++++++++ docs/volto_customization/installation.md | 9 +++++++++ docs/volto_customization/intro.md | 8 ++++---- docs/volto_customization/listing_block.md | 9 +++++++++ docs/volto_customization/schema.md | 9 +++++++++ docs/volto_customization/shadowing.md | 9 +++++++++ docs/volto_customization/styling.md | 11 ++++++++++- docs/volto_customization/teaser_variations.md | 11 ++++++++++- docs/volto_customization/voltosettings.md | 9 +++++++++ 12 files changed, 98 insertions(+), 8 deletions(-) diff --git a/docs/volto_customization/addons.md b/docs/volto_customization/addons.md index 033870f9a..60e10ed12 100644 --- a/docs/volto_customization/addons.md +++ b/docs/volto_customization/addons.md @@ -1,10 +1,10 @@ --- myst: html_meta: - "description": "Volto add-ons for dummies" + "description": "Volto add-ons for beginners" "property=og:description": "Volto add-ons" "property=og:title": "Volto add-ons" - "keywords": "Volto" + "keywords": "Volto, Training" --- # Volto add-ons diff --git a/docs/volto_customization/blocks.md b/docs/volto_customization/blocks.md index 9871ca32e..f164ef721 100644 --- a/docs/volto_customization/blocks.md +++ b/docs/volto_customization/blocks.md @@ -1,3 +1,12 @@ +--- +myst: + html_meta: + "description": "How to extend volto blocks" + "property=og:description": "How to extend volto blocks" + "property=og:title": "Extend volto blocks" + "keywords": "Volto, Training, Extend block" +--- + ### Extend volto blocks There are various ways of extending Volto blocks from core behaviour. The component shadowing is the plain old way of customizing components in volto. But it comes with its own problems like keeping the shadowed component up to date with latest fixes and features. diff --git a/docs/volto_customization/data_adapters.md b/docs/volto_customization/data_adapters.md index 7e15802f7..ce26ed1d1 100644 --- a/docs/volto_customization/data_adapters.md +++ b/docs/volto_customization/data_adapters.md @@ -1,3 +1,12 @@ +--- +myst: + html_meta: + "description": "How to enhance Teaser block with additional data" + "property=og:description": "How to enhance Teaser block with additional data" + "property=og:title": "Enhance Teaser block with additional data" + "keywords": "Volto, Enhance block, dataAdapter" +--- + ### Enhance Teaser block with additional data Teaser block has an ability to let user mutate or intercept block settings data from their customization. The `dataAdapter` field gets registered in Teaser configuration in order to acheive this. diff --git a/docs/volto_customization/extending_teasers.md b/docs/volto_customization/extending_teasers.md index 1c6c181c4..20bd0b8c0 100644 --- a/docs/volto_customization/extending_teasers.md +++ b/docs/volto_customization/extending_teasers.md @@ -1,3 +1,12 @@ +--- +myst: + html_meta: + "description": "How to support extensions per teaser block" + "property=og:description": "How to support extensions per teaser block" + "property=og:title": "Block Extensions" + "keywords": "Volto, Block, Variations" +--- + ### Extending Teasers per type The basic scenario is to add variations to a block so that it can give control over its look and feel. Sometimes its also possible for a need to have control over individual elements. For instance, Consider we have a teaaser grid in which we can have a base variation of its layout. Then we would left with styling and adjusting individual teasers. This is where extensions come into play. diff --git a/docs/volto_customization/installation.md b/docs/volto_customization/installation.md index 4646ba67a..a6bb97e07 100644 --- a/docs/volto_customization/installation.md +++ b/docs/volto_customization/installation.md @@ -1,3 +1,12 @@ +--- +myst: + html_meta: + "description": "Volto and Plone development - installation steps for JavaScript Beginners" + "property=og:description": "Volto and Plone development - installation steps for JavaScript Beginners" + "property=og:title": "Installation steps for JavaScript Beginners" + "keywords": "Plone, Volto, Training, Installation" +--- + ### Installation Todo- Installation steps diff --git a/docs/volto_customization/intro.md b/docs/volto_customization/intro.md index 94726f575..29ba1a481 100644 --- a/docs/volto_customization/intro.md +++ b/docs/volto_customization/intro.md @@ -1,10 +1,10 @@ --- myst: html_meta: - "description": "Introduction to the Volto for Dummies Training Documentation" - "property=og:description": "Introduction to the Volto for Dummies Training Documentation" - "property=og:title": "Volto for Dummies Training" - "keywords": "Volto, Training, Dummies" + "description": "Introduction to the Volto Customization for JavaScript Beginners Training Documentation" + "property=og:description": "Introduction to the Volto Customization for JavaScript Beginners Training Documentation" + "property=og:title": "Volto Customization for JavaScript Beginners" + "keywords": "Volto, Training, Beginners" --- (volto4dummies-intro-label)= diff --git a/docs/volto_customization/listing_block.md b/docs/volto_customization/listing_block.md index 75e2cd2e4..00d8de10f 100644 --- a/docs/volto_customization/listing_block.md +++ b/docs/volto_customization/listing_block.md @@ -1,3 +1,12 @@ +--- +myst: + html_meta: + "description": "How to create a block variation" + "property=og:description": "How to create a block variation" + "property=og:title": "Create a simple listing block variation" + "keywords": "Volto, Training, Block variation" +--- + ### Create a simple listing block variation We will create a variation for listing block, the approach is the same we did for teasers. A new variation which will control the layout and extensions which will take care of individual items styling. diff --git a/docs/volto_customization/schema.md b/docs/volto_customization/schema.md index bce1ce678..a48acdede 100644 --- a/docs/volto_customization/schema.md +++ b/docs/volto_customization/schema.md @@ -1,3 +1,12 @@ +--- +myst: + html_meta: + "description": "How to approach the blocks schema and variations" + "property=og:description": "How to approach the blocks schema and variations" + "property=og:title": "Blocks schema and variations" + "keywords": "Volto, Blocks, Schema" +--- + ### Blocks schema and variations In the previous chapter we just replaced or enhanced our View component by directly mutating the View in the Blocks engine. Now since all the blocks in principle should be schema based and should use `BlockDataForm` we do have another concept of extending Blocks with respect to schema. diff --git a/docs/volto_customization/shadowing.md b/docs/volto_customization/shadowing.md index 759a52fca..7343df11d 100644 --- a/docs/volto_customization/shadowing.md +++ b/docs/volto_customization/shadowing.md @@ -1,3 +1,12 @@ +--- +myst: + html_meta: + "description": "How to customize content-type Views and other Components" + "property=og:description": "How to customize content-type Views and other Components" + "property=og:title": "Customize Content-type Views and other Components" + "keywords": "Volto, Customize, Shadowing" +--- + ### Customize Content-type Views and other Components You can customize all components of Volto using a technique called component shadowing. diff --git a/docs/volto_customization/styling.md b/docs/volto_customization/styling.md index ac3c1ac4f..3c30921ac 100644 --- a/docs/volto_customization/styling.md +++ b/docs/volto_customization/styling.md @@ -1,4 +1,13 @@ -### Usage of StyleWrapper( Styling Schemas) and StyleMenu +--- +myst: + html_meta: + "description": "How to use StyleWrapper(Styling Schemas) and StyleMenu" + "property=og:description": "How to use StyleWrapper(Styling Schemas) and StyleMenu" + "property=og:title": "Usage of StyleWrapper(Styling Schemas) and StyleMenu" + "keywords": "Volto, StyleWrapper, StyleMenu" +--- + +### Usage of StyleWrapper(Styling Schemas) and StyleMenu Its essential to also control the styling of Blocks and most importantly if the styling is done based on schema. In Volto we have a central wrapper named [`StyleWrapper`](https://github.com/plone/volto/blob/9667cf735e5c3e848de852d615941d98193e0a5e/src/components/manage/Blocks/Block/StyleWrapper.jsx#L1) which wraps around all the View template of Blocks. The job of stylewrapper is to build and inject style classNames into its children. diff --git a/docs/volto_customization/teaser_variations.md b/docs/volto_customization/teaser_variations.md index ef7f57c83..6000da2dc 100644 --- a/docs/volto_customization/teaser_variations.md +++ b/docs/volto_customization/teaser_variations.md @@ -1,4 +1,13 @@ -### Teaser block variations Schemas +--- +myst: + html_meta: + "description": "How to work with block variations schema" + "property=og:description": "How to work with block variations schema" + "property=og:title": "Teaser block variations Schema" + "keywords": "Volto, Blocks, Variations, schemaEnhancers" +--- + +### Teaser block variations Schema Now that we have learnt on how to add a new variation to a teaser block. Sometimes its important to also have schemas of those variations merged into the main schema. So each variation can come up with its own set of schema. We can use `schemaEnhancers` for this purpose. diff --git a/docs/volto_customization/voltosettings.md b/docs/volto_customization/voltosettings.md index 972d32af1..adfe12e36 100644 --- a/docs/volto_customization/voltosettings.md +++ b/docs/volto_customization/voltosettings.md @@ -1,3 +1,12 @@ +--- +myst: + html_meta: + "description": "How can you configure Volto" + "property=og:description": "How can you configure Volto" + "property=og:title": "Most useful volto settings" + "keywords": "Volto, configuration" +--- + ### Most useful volto settings You can configure Volto by modifying settings in a js-file. From 2d760d746abd98d2cd3db8874be6d70d5261f6ca Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Mon, 25 Sep 2023 17:06:25 +0300 Subject: [PATCH 11/32] Update intro page --- docs/volto_customization/intro.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/volto_customization/intro.md b/docs/volto_customization/intro.md index 29ba1a481..846b6e252 100644 --- a/docs/volto_customization/intro.md +++ b/docs/volto_customization/intro.md @@ -11,9 +11,13 @@ myst: # Introduction +Before we dive into the content, let's take a moment to get to know each other and ensure that this training meets your needs. This session is designed to equip you with the knowledge and skills necessary for Volto customization. Whether you're new to JavaScript or have some experience, we're here to support your growth. + ## Who are you? -You are a beginner into Volto development era and wants to know about cheat codes that will help in modern day development with volto. +Please take a moment to briefly introduce yourself, sharing your name, your background in web development (if any), and what you hope to achieve or learn from this training. This will help us tailor the session to your needs and create a collaborative learning environment. + +Additionally, if you have any specific questions, challenges, or expectations for this training, please feel free to share them with us. We want to ensure that your time here is both informative and valuable. (volto4dummies-intro-what-will-we-do-label)= @@ -28,9 +32,11 @@ Some technologies and tools we use during the training: - Volto Generator - Plone 6! -This training assumes that you have already taken (either in person at a Plone Conference or online) the existing Volto and React training. You already know about Content-types, Blocks and visual components in Plone 6. +Before we dive into the content of this training, I'd like to make a helpful suggestion. If you're new to Volto and React or feel like you could benefit from a refresher, it might be a great idea to [explore some existing Volto and React training resources](https://www.youtube.com/playlist?list=PLGN9BI-OAQkTVkkJfSMHu-l-_AVW_uoRf) that can provide you with a solid foundation. These resources can serve as valuable supplements to what we'll cover here. + +We have designed this training to be beginner-friendly, but having some prior exposure to these technologies can be advantageous. It will help you grasp the concepts more quickly and make the learning experience even more enjoyable. -If you haven't already, we suggest you to go through it first. +Of course, if you're already familiar with Volto and React, that's fantastic, and you're well-prepared for this training. Regardless of your experience level, we're here to support your learning journey every step of the way. (volto4dummies-intro-documentation-label)= @@ -38,7 +44,7 @@ If you haven't already, we suggest you to go through it first. To follow the training as smoothly as possible it is recommended that you have the following software installed on your computer: -- [node.js](https://nodejs.org/en/) >= 16 +- [node.js](https://nodejs.org/en/) >= 18 - [yarn](https://yarnpkg.com/getting-started/install) - [node version manager](https://github.com/nvm-sh/nvm) - [docker](https://www.docker.com/get-started/) From 6d11dd7f388c24b91ceb1054b3d1bcc22b7548f2 Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Mon, 25 Sep 2023 17:16:09 +0300 Subject: [PATCH 12/32] fix: resources - open link in new window --- docs/volto_customization/intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/volto_customization/intro.md b/docs/volto_customization/intro.md index 846b6e252..2aea34d3d 100644 --- a/docs/volto_customization/intro.md +++ b/docs/volto_customization/intro.md @@ -32,7 +32,7 @@ Some technologies and tools we use during the training: - Volto Generator - Plone 6! -Before we dive into the content of this training, I'd like to make a helpful suggestion. If you're new to Volto and React or feel like you could benefit from a refresher, it might be a great idea to [explore some existing Volto and React training resources](https://www.youtube.com/playlist?list=PLGN9BI-OAQkTVkkJfSMHu-l-_AVW_uoRf) that can provide you with a solid foundation. These resources can serve as valuable supplements to what we'll cover here. +Before we dive into the content of this training, I'd like to make a helpful suggestion. If you're new to Volto and React or feel like you could benefit from a refresher, it might be a great idea to explore some existing Volto and React training resources that can provide you with a solid foundation. These resources can serve as valuable supplements to what we'll cover here. We have designed this training to be beginner-friendly, but having some prior exposure to these technologies can be advantageous. It will help you grasp the concepts more quickly and make the learning experience even more enjoyable. From 0deb1d9e96f678942514f2be407255c766fb9d3a Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Mon, 25 Sep 2023 17:23:12 +0300 Subject: [PATCH 13/32] toc - numbered list --- docs/volto_customization/index.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/volto_customization/index.md b/docs/volto_customization/index.md index 406aeb5a3..82498e277 100644 --- a/docs/volto_customization/index.md +++ b/docs/volto_customization/index.md @@ -37,11 +37,10 @@ Prerequisites: : No prior experience with Volto is required. However, a basic understanding of web development concepts and basic JavaScript knowledge will be beneficial. ```{toctree} ---- -caption: Volto Customization for JavaScript Beginners -name: toc-voltocustomization -maxdepth: 3 ---- +:caption: Volto Customization for JavaScript Beginners +:name: toc-voltocustomization +:maxdepth: 3 +:numbered: true intro installation From 8b955b4a9cc7fd68130a9f2d8caf1af0df793cf8 Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Mon, 25 Sep 2023 17:39:19 +0300 Subject: [PATCH 14/32] fix: fix headers/chapters/sections --- docs/volto_customization/blocks.md | 2 +- docs/volto_customization/data_adapters.md | 2 +- docs/volto_customization/extending_teasers.md | 6 +++--- docs/volto_customization/installation.md | 4 +++- docs/volto_customization/listing_block.md | 2 +- docs/volto_customization/schema.md | 2 +- docs/volto_customization/shadowing.md | 2 +- docs/volto_customization/styling.md | 10 +++++++--- docs/volto_customization/teaser_variations.md | 2 +- docs/volto_customization/voltosettings.md | 2 +- 10 files changed, 20 insertions(+), 14 deletions(-) diff --git a/docs/volto_customization/blocks.md b/docs/volto_customization/blocks.md index f164ef721..5cfe2680a 100644 --- a/docs/volto_customization/blocks.md +++ b/docs/volto_customization/blocks.md @@ -7,7 +7,7 @@ myst: "keywords": "Volto, Training, Extend block" --- -### Extend volto blocks +# Extend volto blocks There are various ways of extending Volto blocks from core behaviour. The component shadowing is the plain old way of customizing components in volto. But it comes with its own problems like keeping the shadowed component up to date with latest fixes and features. In the modern day volto development we can directly extend blocks in form of variations and extensions and populate each of them with their own schemas. diff --git a/docs/volto_customization/data_adapters.md b/docs/volto_customization/data_adapters.md index ce26ed1d1..30923c800 100644 --- a/docs/volto_customization/data_adapters.md +++ b/docs/volto_customization/data_adapters.md @@ -7,7 +7,7 @@ myst: "keywords": "Volto, Enhance block, dataAdapter" --- -### Enhance Teaser block with additional data +# Enhance Teaser block with additional data Teaser block has an ability to let user mutate or intercept block settings data from their customization. The `dataAdapter` field gets registered in Teaser configuration in order to acheive this. diff --git a/docs/volto_customization/extending_teasers.md b/docs/volto_customization/extending_teasers.md index 20bd0b8c0..002c9066f 100644 --- a/docs/volto_customization/extending_teasers.md +++ b/docs/volto_customization/extending_teasers.md @@ -7,13 +7,13 @@ myst: "keywords": "Volto, Block, Variations" --- -### Extending Teasers per type +# Extending Teasers per type The basic scenario is to add variations to a block so that it can give control over its look and feel. Sometimes its also possible for a need to have control over individual elements. For instance, Consider we have a teaaser grid in which we can have a base variation of its layout. Then we would left with styling and adjusting individual teasers. This is where extensions come into play. In this chapter we will tweak our newly created variation to also support extensions per teaser block and then later we will add grid support to teasers. -### Block Extensions +## Block Extensions Block extensions are the way to display a new form of your block for a particular block type. For instance if you have a teaserGrid, with block extensions you can control the styling and behaviour of individual teasers. The split of responsibilites is as follows: "the variation will control how the teasers layout and extension will control the individual rendering." @@ -553,7 +553,7 @@ The styles.less is to be created as well: Great. We now have extension per teaser in our block which controls each item individually. -### Grid support to Teasers +## Grid support to Teasers As mentioned before we will add grid support in our project to be able to have a whole `teaserGrid` working properly along with our extended code. In order to demonstrate it, we need to list teasers in grid system. We'll use `@kitconcept/volto-blocks-grid` for that and extend it in our own ways. diff --git a/docs/volto_customization/installation.md b/docs/volto_customization/installation.md index a6bb97e07..2efe7fc8f 100644 --- a/docs/volto_customization/installation.md +++ b/docs/volto_customization/installation.md @@ -9,4 +9,6 @@ myst: ### Installation -Todo- Installation steps +Todo- Installation steps - Work in progress (Claudia) + + \ No newline at end of file diff --git a/docs/volto_customization/listing_block.md b/docs/volto_customization/listing_block.md index 00d8de10f..03538178f 100644 --- a/docs/volto_customization/listing_block.md +++ b/docs/volto_customization/listing_block.md @@ -7,7 +7,7 @@ myst: "keywords": "Volto, Training, Block variation" --- -### Create a simple listing block variation +# Create a simple listing block variation We will create a variation for listing block, the approach is the same we did for teasers. A new variation which will control the layout and extensions which will take care of individual items styling. diff --git a/docs/volto_customization/schema.md b/docs/volto_customization/schema.md index a48acdede..4938bf1d4 100644 --- a/docs/volto_customization/schema.md +++ b/docs/volto_customization/schema.md @@ -7,7 +7,7 @@ myst: "keywords": "Volto, Blocks, Schema" --- -### Blocks schema and variations +# Blocks schema and variations In the previous chapter we just replaced or enhanced our View component by directly mutating the View in the Blocks engine. Now since all the blocks in principle should be schema based and should use `BlockDataForm` we do have another concept of extending Blocks with respect to schema. diff --git a/docs/volto_customization/shadowing.md b/docs/volto_customization/shadowing.md index 7343df11d..3f9f28049 100644 --- a/docs/volto_customization/shadowing.md +++ b/docs/volto_customization/shadowing.md @@ -7,7 +7,7 @@ myst: "keywords": "Volto, Customize, Shadowing" --- -### Customize Content-type Views and other Components +# Customize Content-type Views and other Components You can customize all components of Volto using a technique called component shadowing. diff --git a/docs/volto_customization/styling.md b/docs/volto_customization/styling.md index 3c30921ac..5da0e0a63 100644 --- a/docs/volto_customization/styling.md +++ b/docs/volto_customization/styling.md @@ -7,9 +7,13 @@ myst: "keywords": "Volto, StyleWrapper, StyleMenu" --- -### Usage of StyleWrapper(Styling Schemas) and StyleMenu +# Usage of StyleWrapper(Styling Schemas) and StyleMenu -Its essential to also control the styling of Blocks and most importantly if the styling is done based on schema. In Volto we have a central wrapper named [`StyleWrapper`](https://github.com/plone/volto/blob/9667cf735e5c3e848de852d615941d98193e0a5e/src/components/manage/Blocks/Block/StyleWrapper.jsx#L1) which wraps around all the View template of Blocks. The job of stylewrapper is to build and inject style classNames into its children. +Its essential to also control the styling of Blocks and most importantly if the styling is done based on schema or not. + +## StyleWrapper(Styling Schemas) + +In Volto we have a central wrapper named [`StyleWrapper`](https://github.com/plone/volto/blob/9667cf735e5c3e848de852d615941d98193e0a5e/src/components/manage/Blocks/Block/StyleWrapper.jsx#L1) which wraps around all the View template of Blocks. The job of stylewrapper is to build and inject style classNames into its children. In the schema at any point in time, we can call a volto helper which adds `styles` fields. Which then gets converted into classNames with the prefix `--has`. Its upto the theme owner in which way they want to add css for it. Simply, the job of StyleWrapper is to inject classNames(build from schema) into their children. @@ -171,7 +175,7 @@ Go ahead and add classNames in your `css/less` files } ``` -### StyleMenu +## StyleMenu StyleMenu is not the part of Blocks engine instead its a volto-slate plugin and its used to style rich text content only. diff --git a/docs/volto_customization/teaser_variations.md b/docs/volto_customization/teaser_variations.md index 6000da2dc..8b2da4df5 100644 --- a/docs/volto_customization/teaser_variations.md +++ b/docs/volto_customization/teaser_variations.md @@ -7,7 +7,7 @@ myst: "keywords": "Volto, Blocks, Variations, schemaEnhancers" --- -### Teaser block variations Schema +# Teaser block variations Schema Now that we have learnt on how to add a new variation to a teaser block. Sometimes its important to also have schemas of those variations merged into the main schema. So each variation can come up with its own set of schema. We can use `schemaEnhancers` for this purpose. diff --git a/docs/volto_customization/voltosettings.md b/docs/volto_customization/voltosettings.md index adfe12e36..ea7f01fde 100644 --- a/docs/volto_customization/voltosettings.md +++ b/docs/volto_customization/voltosettings.md @@ -7,7 +7,7 @@ myst: "keywords": "Volto, configuration" --- -### Most useful volto settings +# Most useful volto settings You can configure Volto by modifying settings in a js-file. From c870a7509cc8da8b624ce2271be51a434589df29 Mon Sep 17 00:00:00 2001 From: nileshgulia1 Date: Mon, 25 Sep 2023 23:58:34 +0530 Subject: [PATCH 15/32] re-order chapters --- docs/volto_customization/index.md | 20 +++++++++++--------- docs/volto_customization/schema.md | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/docs/volto_customization/index.md b/docs/volto_customization/index.md index 82498e277..ca2efbfbd 100644 --- a/docs/volto_customization/index.md +++ b/docs/volto_customization/index.md @@ -19,18 +19,20 @@ Level What You'll Learn: : In this hands-on training, you will embark on a journey to master Volto customization from the ground up. Whether you're a developer looking to expand your skill set or someone entirely new to JavaScript, this course will provide you with the knowledge and tools to excel in Volto development. Here's what you can expect to learn: - * Introduction to Volto: Get acquainted with Volto's architecture, key concepts, and its role in modern web development. - * JavaScript Fundamentals: Build a strong foundation in JavaScript, covering essential topics like variables, functions, and data structures. - * React Essentials: Dive into React, the heart of Volto, and learn how to create dynamic user interfaces using React components. - * Customizing Volto: Explore the art of customizing Volto projects, from theming and styling to creating custom blocks. - * Building Blocks: Discover the building blocks of a Volto project, including new variations. - * Best Practices: Gain insights into industry best practices for efficient Volto development. + +- Introduction to Volto: Get acquainted with Volto's architecture, key concepts, and its role in modern web development. +- JavaScript Fundamentals: Build a strong foundation in JavaScript, covering essential topics like variables, functions, and data structures. +- React Essentials: Dive into React, the heart of Volto, and learn how to create dynamic user interfaces using React components. +- Customizing Volto: Explore the art of customizing Volto projects, from theming and styling to creating custom blocks. +- Building Blocks: Discover the building blocks of a Volto project, including new variations. +- Best Practices: Gain insights into industry best practices for efficient Volto development. Who Should Attend: : This training program is tailored for: - * JavaScript beginners looking to enter the world of Volto and React. - * Developers interested in extending their expertise to include Volto customization. + +- JavaScript beginners looking to enter the world of Volto and React. +- Developers interested in extending their expertise to include Volto customization. Prerequisites: @@ -49,9 +51,9 @@ voltosettings shadowing blocks schema +teaser_variations styling data_adapters -teaser_variations extending_teasers listing_block diff --git a/docs/volto_customization/schema.md b/docs/volto_customization/schema.md index 4938bf1d4..ad05c8f91 100644 --- a/docs/volto_customization/schema.md +++ b/docs/volto_customization/schema.md @@ -205,7 +205,7 @@ styles.less: } ``` -Right now it this variation only shows default variation of Teaser block. In the coming chapter we are gonna enhance it with extension per teaser. +Right now this variation only shows default variation of Teaser block. In the coming chapter we are gonna enhance it with extension per teaser. ```{note} The [Body](https://github.com/plone/volto/blob/9667cf735e5c3e848de852d615941d98193e0a5e/src/components/manage/Blocks/Teaser/Body.jsx#L13) component in Teaser block also supports variations from component registry. You can read more about component registry in following chapters. From 61770839948237e0d94cade94af788d70e05ea7b Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Tue, 26 Sep 2023 00:17:48 +0300 Subject: [PATCH 16/32] reorder sections --- docs/volto_customization/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/volto_customization/index.md b/docs/volto_customization/index.md index ca2efbfbd..b86d22ac1 100644 --- a/docs/volto_customization/index.md +++ b/docs/volto_customization/index.md @@ -52,9 +52,11 @@ shadowing blocks schema teaser_variations -styling data_adapters +styling extending_teasers listing_block ``` + + \ No newline at end of file From c4b2fa7551dc53fe013d8a28c414c25aa5a476e0 Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Tue, 26 Sep 2023 02:02:10 +0300 Subject: [PATCH 17/32] add install instructions --- docs/volto_customization/addons.md | 222 -------------------- docs/volto_customization/index.md | 1 - docs/volto_customization/installation.md | 247 ++++++++++++++++++++++- 3 files changed, 245 insertions(+), 225 deletions(-) delete mode 100644 docs/volto_customization/addons.md diff --git a/docs/volto_customization/addons.md b/docs/volto_customization/addons.md deleted file mode 100644 index 60e10ed12..000000000 --- a/docs/volto_customization/addons.md +++ /dev/null @@ -1,222 +0,0 @@ ---- -myst: - html_meta: - "description": "Volto add-ons for beginners" - "property=og:description": "Volto add-ons" - "property=og:title": "Volto add-ons" - "keywords": "Volto, Training" ---- - -# Volto add-ons - -## Bootstrap a new Volto project - -To bootstrap a new Volto project, you can use Yeoman [@plone/generator-volto](https://github.com/plone/generator-volto). -First, install it as a global tool (use [NVM] if you're being asked for sudo -access): - -```shell -npm install -g yo -npm install -g @plone/generator-volto -``` - -Then you can bootstrap the project with: - -```shell -yo @plone/volto volto-tutorial-project -``` - -The yo-based generator partially integrates add-ons (it can generate a -`package.json` with add-ons and workspaces already specified). When prompted -to add add-ons, choose `false`. - -Now you can start your newly created Volto project: - -```shell -cd volto-tutorial-project -yarn start -``` - -You can then login with admin/admin at http://localhost:3000/login. - -## Bootstrap an add-on - -Let's start creating an add-on. We'll create a new package: -`volto-teaser-tutorial`. Inside your Volto project, bootstrap -the add-on by running (in the Volto project root): - -```shell -yo @plone/volto:addon -``` - -Note: You can also use the namespace like `@plone-collective/volto-teaser-tutorial` (or any other) is not required and is -optional. We're using namespaces for scoped package under some organisation. - -Use `volto-teaser-tutorial` as the package name. After the -scaffolding of the add-on completes, you can check the created files in -`src/addons/volto-teaser-tutorial`. - -Back to the project, you can edit `jsconfig.json` and add your add-on: - -```json -{ - "compilerOptions": { - "baseUrl": "src", - "paths": { - "volto-teaser-tutorial": ["addons/volto-teaser-tutorial/src"] - } - } -} -``` - -```{note} -The `jsconfig.json` file is needed by Volto to identify development -packages. You are not strictly limited to Volto add-ons in its use, you -could, for example, use this to make it easier to debug third-party -JavaScript packages that are shipped transpiled. -``` - -### Volto addon script - -Alternatively, if you already have an addon pushed to a remote repository and you want to create a volto development stack with it, you can use our addon script to easily scaffold a dev environment without creating a project externally. - -```shell -npx -p @plone/scripts addon clone [options] [destination] -``` - -This command downloads the volto-teaser-tutorial add-on from its git repository's main branch, and will generate a project with the latest Volto version. - -```shell -npx -p @plone/scripts addon clone https://github.com/kitconcept/volto-teaser-tutorial.git --branch main -``` - -### (Optional) Use mrs-developer to sync add-on to GitHub - -You can also immediately push the package to GitHub, then use `[mrs-developer]` -to manage the package and `jsconfig.json` changes. - -Install mrs-developer as a development dependency by running: - -```shell -yarn add -W -D mrs-developer -``` - -Create a `mrs.developer.json` in your project with the following content (adjust it according -to your names and repository location): - -```json -{ - "volto-teaser-tutorial": { - "url": "https://github.com//volto-teaser-tutorial.git", - "path": "src", - "package": "volto-teaser-tutorial", - "branch": "main" - } -} -``` - -Then run `yarn develop`, which will bring the package in `src/addons` and -adjust `jsconfig.json`. - -### Add the add-on as workspace - -The Volto project becomes a monorepo, with the Volto project being the "workspace root" and each add-on needs to be a "workspace", so that yarn knows that it should include that add-on location as a package and install its dependencies. - -You could treat workspaces as major "working environment" for your project. So a yarn install would also install dependencies from `src/addons/*` - -Change the Volto project's `package.json` to include something like: - -```json -{ - "private": "true", - "workspaces": [ - "src/addons/volto-teaser-tutorial" // or simply src/addons/* - ] -} -``` - -```{note} -Don't be scared by that `"private": "true"` in the Volto project `package.json`. -It's only needed to make sure you can't accidentally publish the package to NPM. -``` - -### Managing add-on dependencies - -To be able to add dependencies to the add-on, you need to add them via the -workspaces machinery by running something like (at the Volto project root): - -```shell -yarn workspaces info -yarn workspace volto-teaser-tutorial add papaparse -``` - -````{note} -There are several other add-on templates, such as -[voltocli](https://github.com/nzambello/voltocli) or -[eea/volto-addon-template](https://github.com/eea/volto-addon-template). -You could very well decide not to use any of them, and instead bootstrap a new -add-on by running: - -```shell -mkdir -p src/addons/volto-teaser-tutorial -cd src/addons/volto-teaser-tutorial -npm init -``` - -Remember, an add-on is just a JavaScript package that exports -a configuration loader. Just make sure to point the `main` in -`package.json` to `src/index.js`. -```` - -### Load the add-on in Volto - -To tell Volto about our new add-on, add it to the `addons` key of the Volto -project `package.json`: - -```js -// ... -"addons": ["volto-teaser-tutorial"] -// ... -``` - -## Add-ons - first look - -Volto add-ons are just plain JavaScript packages with an -additional feature: they provide helper functions that mutate Volto's -configuration registry. - -Their `main` entry in `package.json` should point to `src/index.js`, -which should be an ES6 module with a default export. -Here is the default add-on configuration loader: - -```jsx -export default (config) => { - return config; -}; -``` - -**Pro-Tip 💡** - -```{note} -If you want to register a specific profile of an addon, wrap the configuration in a function and provide it after a colon(:) next to addon name. You can also provde a comma seperated multiple loaders profiles. Note the main configuration will be loaded always. -``` - -```js -export function simpleLink(config) { - return installSimpleLink(config); -} - -export function tableButton(config) { - return installTableButton(config); -} -``` - -``` - ... -"addons": [ -"volto-slate:tableButton,simpleLink", -"@eeacms/volto-tabs-block", -] -... - -``` diff --git a/docs/volto_customization/index.md b/docs/volto_customization/index.md index b86d22ac1..d7aab054f 100644 --- a/docs/volto_customization/index.md +++ b/docs/volto_customization/index.md @@ -46,7 +46,6 @@ Prerequisites: intro installation -addons voltosettings shadowing blocks diff --git a/docs/volto_customization/installation.md b/docs/volto_customization/installation.md index 2efe7fc8f..ed6a6786e 100644 --- a/docs/volto_customization/installation.md +++ b/docs/volto_customization/installation.md @@ -7,8 +7,251 @@ myst: "keywords": "Plone, Volto, Training, Installation" --- -### Installation +# Installation -Todo- Installation steps - Work in progress (Claudia) +```{warning} +For the most up-to-date information on how to get started with Volto you can check the [official documentation](https://6.docs.plone.org/volto/getting-started/install.html). +``` + +Getting started with Volto involves setting up a development environment, understanding its core concepts, and exploring its features. Here's a step-by-step guide to help you begin your journey with Volto: + +## Prerequisites + +Before you start working with Volto, ensure you have the following prerequisites: + +- Node.js LTS (18.x) - (see instructions for installation) +- Python - See below for specific versions. +- Docker (if using the Plone docker images - see instructions for installation and how to run a Plone docker container) + +The versions of Python that are supported in Volto depend on the version of Plone that you use. + +| Plone | Python | Volto | +|---|---|---| +| 5.2 | 2.7, 3.6-3.8 | 15.0 | +| 6.0 | 3.8-3.10 | 16.0 | + +Depending on the operating system that you are using, some of the following pre-requisites might change. +They assume you have a macOS/Linux machine. + +## Bootstrap a new Volto project + +To bootstrap a new Volto project, you can use Yeoman [@plone/generator-volto](https://github.com/plone/generator-volto). +First, install it as a global tool (see instructions for installation): + +```shell +npm install -g yo +npm install -g @plone/generator-volto +``` + +Then you can bootstrap the project with: + +```shell +yo @plone/volto volto-tutorial-project +``` + +The yo-based generator partially integrates add-ons (it can generate a +`package.json` with add-ons and workspaces already specified). When prompted +to add add-ons, choose `false`. + +Now you can start your newly created Volto project: + +```shell +cd volto-tutorial-project +yarn start +``` + +You can then login with admin/admin at http://localhost:3000/login. + +## Bootstrap an add-on + +Let's start creating an add-on. We'll create a new package: +`volto-teaser-tutorial`. Inside your Volto project, bootstrap +the add-on by running (in the Volto project root): + +```shell +yo @plone/volto:addon +``` + +Note: You can also use the namespace like `@plone-collective/volto-teaser-tutorial` (or any other) is not required and is +optional. We're using namespaces for scoped package under some organisation. + +Use `volto-teaser-tutorial` as the package name. After the +scaffolding of the add-on completes, you can check the created files in +`src/addons/volto-teaser-tutorial`. + +Back to the project, you can edit `jsconfig.json` and add your add-on: + +```json +{ + "compilerOptions": { + "baseUrl": "src", + "paths": { + "volto-teaser-tutorial": ["addons/volto-teaser-tutorial/src"] + } + } +} +``` + +```{note} +The `jsconfig.json` file is needed by Volto to identify development +packages. You are not strictly limited to Volto add-ons in its use, you +could, for example, use this to make it easier to debug third-party +JavaScript packages that are shipped transpiled. +``` + +### Volto addon script + +Alternatively, if you already have an addon pushed to a remote repository and you want to create a volto development stack with it, you can use our addon script to easily scaffold a dev environment without creating a project externally. + +```shell +npx -p @plone/scripts addon clone [options] [destination] +``` + +This command downloads the volto-teaser-tutorial add-on from its git repository's main branch, and will generate a project with the latest Volto version. + +```shell +npx -p @plone/scripts addon clone https://github.com/kitconcept/volto-teaser-tutorial.git --branch main +``` + +### (Optional) Use mrs-developer to sync add-on to GitHub + +You can also immediately push the package to GitHub, then use `[mrs-developer]` +to manage the package and `jsconfig.json` changes. + +Install mrs-developer as a development dependency by running: + +```shell +yarn add -W -D mrs-developer +``` + +Create a `mrs.developer.json` in your project with the following content (adjust it according +to your names and repository location): + +```json +{ + "volto-teaser-tutorial": { + "url": "https://github.com//volto-teaser-tutorial.git", + "path": "src", + "package": "volto-teaser-tutorial", + "branch": "main" + } +} +``` + +Then run `yarn develop`, which will bring the package in `src/addons` and +adjust `jsconfig.json`. + +### Add the add-on as workspace + +The Volto project becomes a monorepo, with the Volto project being the "workspace root" and each add-on needs to be a "workspace", so that yarn knows that it should include that add-on location as a package and install its dependencies. + +You could treat workspaces as major "working environment" for your project. So a yarn install would also install dependencies from `src/addons/*` + +Change the Volto project's `package.json` to include something like: + +```json +{ + "private": "true", + "workspaces": [ + "src/addons/volto-teaser-tutorial" // or simply src/addons/* + ] +} +``` + +```{note} +Don't be scared by that `"private": "true"` in the Volto project `package.json`. +It's only needed to make sure you can't accidentally publish the package to NPM. +``` + +### Managing add-on dependencies + +To be able to add dependencies to the add-on, you need to add them via the +workspaces machinery by running something like (at the Volto project root): + +```shell +yarn workspaces info +yarn workspace volto-teaser-tutorial add papaparse +``` + +````{note} +There are several other add-on templates, such as +[voltocli](https://github.com/nzambello/voltocli) or +[eea/volto-addon-template](https://github.com/eea/volto-addon-template). +You could very well decide not to use any of them, and instead bootstrap a new +add-on by running: + +```shell +mkdir -p src/addons/volto-teaser-tutorial +cd src/addons/volto-teaser-tutorial +npm init +``` + +Remember, an add-on is just a JavaScript package that exports +a configuration loader. Just make sure to point the `main` in +`package.json` to `src/index.js`. +```` + +### Load the add-on in Volto + +To tell Volto about our new add-on, add it to the `addons` key of the Volto +project `package.json`: + +```js +// ... +"addons": ["volto-teaser-tutorial"] +// ... +``` + +## Add-ons - first look + +Volto add-ons are just plain JavaScript packages with an +additional feature: they provide helper functions that mutate Volto's +configuration registry. + +Their `main` entry in `package.json` should point to `src/index.js`, +which should be an ES6 module with a default export. +Here is the default add-on configuration loader: + +```jsx +export default (config) => { + return config; +}; +``` + +**Pro-Tip 💡** + +```{note} +If you want to register a specific profile of an addon, wrap the configuration in a function and provide it after a colon(:) next to addon name. You can also provde a comma seperated multiple loaders profiles. Note the main configuration will be loaded always. +``` + +```js +export function simpleLink(config) { + return installSimpleLink(config); +} + +export function tableButton(config) { + return installTableButton(config); +} +``` + +``` + ... +"addons": [ +"volto-slate:tableButton,simpleLink", +"@eeacms/volto-tabs-block", +] +... + +``` + +## Documentation and Resources + +Refer to the official Volto documentation for in-depth guides, tutorials, and examples. + +Join the Volto community, participate in discussions, and ask questions on the Volto GitHub repository or the Plone community chat on Discord. + +```{warning} +Getting started with Volto may seem complex at first, but with practice and exploration, you'll become more comfortable with its features and capabilities. It offers a powerful and flexible platform for building modern web applications with React and Plone. +``` \ No newline at end of file From 4f4558fbe3c54e26eb815d089518cc9603c32ae5 Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Tue, 26 Sep 2023 12:25:27 +0300 Subject: [PATCH 18/32] fix warnings --- docs/volto_customization/blocks.md | 9 +++-- docs/volto_customization/data_adapters.md | 10 +++-- docs/volto_customization/extending_teasers.md | 14 ++++--- docs/volto_customization/installation.md | 40 +++++++++---------- docs/volto_customization/listing_block.md | 13 +++--- docs/volto_customization/schema.md | 7 +++- docs/volto_customization/styling.md | 38 ++++++++++-------- docs/volto_customization/teaser_variations.md | 10 +++-- docs/volto_customization/voltosettings.md | 6 +-- 9 files changed, 85 insertions(+), 62 deletions(-) diff --git a/docs/volto_customization/blocks.md b/docs/volto_customization/blocks.md index 5cfe2680a..eccdbc185 100644 --- a/docs/volto_customization/blocks.md +++ b/docs/volto_customization/blocks.md @@ -16,7 +16,8 @@ Let us take an example for a teaser block which we already have in volto core. I The most simple customization is the View of the Teaser. The volto core teaser block confiugration looks like: -```jsx +```{code-block} jsx + teaser: { id: 'teaser', title: 'Teaser', @@ -42,14 +43,16 @@ The most simple customization is the View of the Teaser. The volto core teaser b Plain and simple. Every block in Volto have Edit and View stock components. You can customize each of them individually by either shadowing or directly like: -``` +```{code-block} js + config.blocks.blocksConfig.teaser.view = MyTeaserView ``` Let's replace our Main teaser view with our `MyTeaserView` component: -```jsx +```{code-block} jsx + const MyDataProvider = (props) => { const enhancedChildren = React.Children.map(props.children, (child) => { if (React.isValidElement(child)) { diff --git a/docs/volto_customization/data_adapters.md b/docs/volto_customization/data_adapters.md index 30923c800..90b2a7cf6 100644 --- a/docs/volto_customization/data_adapters.md +++ b/docs/volto_customization/data_adapters.md @@ -11,7 +11,8 @@ myst: Teaser block has an ability to let user mutate or intercept block settings data from their customization. The `dataAdapter` field gets registered in Teaser configuration in order to acheive this. -```js +```{code-block} js + teaser: { id: 'teaser', title: 'Teaser', @@ -38,7 +39,8 @@ teaser: { The signature of `dataAdapter` is like this: -```js +```{code-block} js + export const TeaserBlockDataAdapter = ({ block, data, @@ -74,13 +76,13 @@ The above Adapter gets consumed in [Data](https://github.com/plone/volto/blob/96 Let's register a new `dataAdapter` our config: -```js +```{code-block} js config.blocks.blocksConfig.teaser.dataAdapter = myDataOwnAdapter; ``` In your data-adapter.js: -```js +```{code-block} js export const myDataOwnAdapter = ({ block, data, id, onChangeBlock, value }) => { let dataSaved = { ...data, diff --git a/docs/volto_customization/extending_teasers.md b/docs/volto_customization/extending_teasers.md index 002c9066f..eb7670eb7 100644 --- a/docs/volto_customization/extending_teasers.md +++ b/docs/volto_customization/extending_teasers.md @@ -262,7 +262,8 @@ export default TeaserBlockImageDefault; TeaserBlockImageRight: -```jsx +```{code-block} jsx + import React from "react"; import PropTypes from "prop-types"; import { Message } from "semantic-ui-react"; @@ -371,7 +372,8 @@ export default TeaserBlockImageRight; TeaserBlockImageOverlay: -```jsx +```{code-block} jsx + import React from "react"; import PropTypes from "prop-types"; import { Message } from "semantic-ui-react"; @@ -498,7 +500,9 @@ export default TeaserBlockImageOverlay; The styles.less is to be created as well: -```css +```{code-block} less +:force: true + .gradiant { h2 { color: white; @@ -561,7 +565,7 @@ First add `@kitconcept/volto-blocks-grid` in addons key and dependencies in pack In your project's config: -```js +```{code-block} js addons: [ "@kitconcept/volto-blocks-grid", "volto-teaser-tutorial", @@ -580,7 +584,7 @@ Now since, grid block from `@kitconcept/volto-blocks-grid` uses teaser from its In your volto-teaser-tutorial addon's `index.js`: -```js +```{code-block} js if ( config.blocks.blocksConfig?.__grid?.blocksConfig?.teaser && config.blocks.blocksConfig?.teaser diff --git a/docs/volto_customization/installation.md b/docs/volto_customization/installation.md index ed6a6786e..d689268f7 100644 --- a/docs/volto_customization/installation.md +++ b/docs/volto_customization/installation.md @@ -25,10 +25,10 @@ Before you start working with Volto, ensure you have the following prerequisites The versions of Python that are supported in Volto depend on the version of Plone that you use. -| Plone | Python | Volto | -|---|---|---| -| 5.2 | 2.7, 3.6-3.8 | 15.0 | -| 6.0 | 3.8-3.10 | 16.0 | +| Plone | Python | Volto | +| ----- | ------------ | ----- | +| 5.2 | 2.7, 3.6-3.8 | 15.0 | +| 6.0 | 3.8-3.10 | 16.0 | Depending on the operating system that you are using, some of the following pre-requisites might change. They assume you have a macOS/Linux machine. @@ -38,14 +38,14 @@ They assume you have a macOS/Linux machine. To bootstrap a new Volto project, you can use Yeoman [@plone/generator-volto](https://github.com/plone/generator-volto). First, install it as a global tool (see instructions for installation): -```shell +```{code-block} shell npm install -g yo npm install -g @plone/generator-volto ``` Then you can bootstrap the project with: -```shell +```{code-block} shell yo @plone/volto volto-tutorial-project ``` @@ -55,7 +55,7 @@ to add add-ons, choose `false`. Now you can start your newly created Volto project: -```shell +```{code-block} shell cd volto-tutorial-project yarn start ``` @@ -68,7 +68,7 @@ Let's start creating an add-on. We'll create a new package: `volto-teaser-tutorial`. Inside your Volto project, bootstrap the add-on by running (in the Volto project root): -```shell +```{code-block} shell yo @plone/volto:addon ``` @@ -81,7 +81,7 @@ scaffolding of the add-on completes, you can check the created files in Back to the project, you can edit `jsconfig.json` and add your add-on: -```json +```{code-block} json { "compilerOptions": { "baseUrl": "src", @@ -103,13 +103,13 @@ JavaScript packages that are shipped transpiled. Alternatively, if you already have an addon pushed to a remote repository and you want to create a volto development stack with it, you can use our addon script to easily scaffold a dev environment without creating a project externally. -```shell +```{code-block} shell npx -p @plone/scripts addon clone [options] [destination] ``` This command downloads the volto-teaser-tutorial add-on from its git repository's main branch, and will generate a project with the latest Volto version. -```shell +```{code-block} shell npx -p @plone/scripts addon clone https://github.com/kitconcept/volto-teaser-tutorial.git --branch main ``` @@ -120,14 +120,14 @@ to manage the package and `jsconfig.json` changes. Install mrs-developer as a development dependency by running: -```shell +```{code-block} shell yarn add -W -D mrs-developer ``` Create a `mrs.developer.json` in your project with the following content (adjust it according to your names and repository location): -```json +```{code-block} json { "volto-teaser-tutorial": { "url": "https://github.com//volto-teaser-tutorial.git", @@ -149,7 +149,7 @@ You could treat workspaces as major "working environment" for your project. So a Change the Volto project's `package.json` to include something like: -```json +```{code-block} json { "private": "true", "workspaces": [ @@ -168,7 +168,7 @@ It's only needed to make sure you can't accidentally publish the package to NPM. To be able to add dependencies to the add-on, you need to add them via the workspaces machinery by running something like (at the Volto project root): -```shell +```{code-block} shell yarn workspaces info yarn workspace volto-teaser-tutorial add papaparse ``` @@ -180,7 +180,7 @@ There are several other add-on templates, such as You could very well decide not to use any of them, and instead bootstrap a new add-on by running: -```shell +```{code-block} shell mkdir -p src/addons/volto-teaser-tutorial cd src/addons/volto-teaser-tutorial npm init @@ -196,7 +196,7 @@ a configuration loader. Just make sure to point the `main` in To tell Volto about our new add-on, add it to the `addons` key of the Volto project `package.json`: -```js +```{code-block} js // ... "addons": ["volto-teaser-tutorial"] // ... @@ -212,7 +212,7 @@ Their `main` entry in `package.json` should point to `src/index.js`, which should be an ES6 module with a default export. Here is the default add-on configuration loader: -```jsx +```{code-block} js export default (config) => { return config; }; @@ -224,7 +224,7 @@ export default (config) => { If you want to register a specific profile of an addon, wrap the configuration in a function and provide it after a colon(:) next to addon name. You can also provde a comma seperated multiple loaders profiles. Note the main configuration will be loaded always. ``` -```js +```{code-block} js export function simpleLink(config) { return installSimpleLink(config); } @@ -254,4 +254,4 @@ Join the Volto community, participate in discussions, and ask questions on the V Getting started with Volto may seem complex at first, but with practice and exploration, you'll become more comfortable with its features and capabilities. It offers a powerful and flexible platform for building modern web applications with React and Plone. ``` - \ No newline at end of file + diff --git a/docs/volto_customization/listing_block.md b/docs/volto_customization/listing_block.md index 03538178f..7e69a3c20 100644 --- a/docs/volto_customization/listing_block.md +++ b/docs/volto_customization/listing_block.md @@ -15,7 +15,7 @@ First of all let's add a styling fieldset in the current schema of volto's defau In your addon config: -```js +```{code-block} js if (config.blocks.blocksConfig.listing) { config.blocks.blocksConfig.listing.title = "Listing (Tutorial)"; config.blocks.blocksConfig.listing.schemaEnhancer = addStylingFieldset; @@ -24,7 +24,7 @@ if (config.blocks.blocksConfig.listing) { Create a file named `helpers.js` and add the relevant schema enhancer for it: -```js +```{code-block} js import { cloneDeep } from "lodash"; import imageNarrowSVG from "@plone/volto/icons/image-narrow.svg"; import imageFitSVG from "@plone/volto/icons/image-fit.svg"; @@ -80,7 +80,9 @@ export const addStylingFieldset = ({ schema }) => { This function will inject styles field into the schema if isn't present already. We can add relevant styling here. Volto will build classNames based on the styles as mentioned in the earlier chapters. We will have to provide our own css for the generated classNames. -```less +```{code-block} less +:force: true + #main .has--size--narrow_width, #main .narrow_width, [class~="narrow_view"] [id="page-document"] > * { @@ -98,7 +100,8 @@ This function will inject styles field into the schema if isn't present already. In order to have a control over individual items in the listing let's create a sample variation of listing block. -```js +```{code-block} js + import ListingVariation from 'volto-teaser-tutorial/components/ListingBlockVariation'; @@ -143,7 +146,7 @@ Finally we write our own variation for ListingBlock: ListingVariation.jsx -```jsx +```{code-block} jsx import React from "react"; import PropTypes from "prop-types"; import cloneDeep from "lodash/cloneDeep"; diff --git a/docs/volto_customization/schema.md b/docs/volto_customization/schema.md index ad05c8f91..4dbae2ed5 100644 --- a/docs/volto_customization/schema.md +++ b/docs/volto_customization/schema.md @@ -67,7 +67,8 @@ We should create this view template in our `components/TeaserBlockImageVariation TeaserBlockImageVariation.jsx: -```jsx +```{code-block} jsx + import React from "react"; import PropTypes from "prop-types"; import { Message } from "semantic-ui-react"; @@ -176,7 +177,9 @@ export default TeaserBlockImageDefault; styles.less: -```css +```{code-block} less +:force: true + .gradiant { h2 { color: white; diff --git a/docs/volto_customization/styling.md b/docs/volto_customization/styling.md index 5da0e0a63..f1006e539 100644 --- a/docs/volto_customization/styling.md +++ b/docs/volto_customization/styling.md @@ -9,7 +9,7 @@ myst: # Usage of StyleWrapper(Styling Schemas) and StyleMenu -Its essential to also control the styling of Blocks and most importantly if the styling is done based on schema or not. +Its essential to also control the styling of Blocks and most importantly if the styling is done based on schema or not. ## StyleWrapper(Styling Schemas) @@ -20,7 +20,8 @@ Simply, the job of StyleWrapper is to inject classNames(build from schema) into We see that in our Teaser config volto already calls the [addStyling](https://github.com/plone/volto/blob/9667cf735e5c3e848de852d615941d98193e0a5e/src/helpers/Extensions/withBlockSchemaEnhancer.js#L297) in the schema. The job of this function is to add styles field in the styling fieldset in schema provided. -```jsx +```{code-block} jsx + export const TeaserSchema = ({ intl }) => { const schema = { title: intl.formatMessage(messages.teaser), @@ -92,7 +93,8 @@ and then we can manipulate those fields by adding whatever styles we want. Let's In your variation schemaEnhancer: -```js +```{code-block} js + config.blocks.blocksConfig.teaser.variations = [ ...config.blocks.blocksConfig.teaser.variations, { @@ -129,27 +131,30 @@ config.blocks.blocksConfig.teaser.variations = [ As StyleWrapper wraps around our view component in `RenderBlocks`. The styleNames should be available in our component's rendered html. -``` +```{code-block} html +
- ``` Go ahead and add classNames in your `css/less` files -```css +```{code-block} less +:force: true + .has--objectFit--contain { img { object-fit: contain !important; @@ -181,7 +186,8 @@ StyleMenu is not the part of Blocks engine instead its a volto-slate plugin and In your policy package, you can add styleMenu configuration like: -```js +```{code-block} jsx + config.settings.slate.styleMenu = { ...(config.settings.slate.styleMenu || {}), blockStyles: [ diff --git a/docs/volto_customization/teaser_variations.md b/docs/volto_customization/teaser_variations.md index 8b2da4df5..8c63e97d8 100644 --- a/docs/volto_customization/teaser_variations.md +++ b/docs/volto_customization/teaser_variations.md @@ -15,7 +15,8 @@ schemaEnhancers works on the concept of composition. They are just functions whi In our variation, lets add a schemaEnhancer to modify existing schema and add a `CreationDate` from catalog metadata brain. -```js +```{code-block} js + config.blocks.blocksConfig.teaser.variations = [ ...config.blocks.blocksConfig.teaser.variations, { @@ -38,7 +39,8 @@ config.blocks.blocksConfig.teaser.variations = [ And then in your code of that variation, you should consume that field accordingly. -```js +```{code-block} js + const creationDate = data.href?.[0]?.CreationDate; const formattedDate = formatDate({ date: creationDate, @@ -55,7 +57,7 @@ const formattedDate = formatDate({ Finaly render it conditionally on the basis of data.creationDate -```jsx +```{code-block} jsx { data?.creationDate &&

{formattedDate}

; } @@ -63,7 +65,7 @@ Finaly render it conditionally on the basis of data.creationDate The whole component looks like: -```jsx +```{code-block} jsx import React from "react"; import PropTypes from "prop-types"; import { Message } from "semantic-ui-react"; diff --git a/docs/volto_customization/voltosettings.md b/docs/volto_customization/voltosettings.md index ea7f01fde..2b2f5a896 100644 --- a/docs/volto_customization/voltosettings.md +++ b/docs/volto_customization/voltosettings.md @@ -13,7 +13,7 @@ You can configure Volto by modifying settings in a js-file. This is the original `config.js` of a project where the registry is imported and returned unchanged. -```js +```{code-block} js import "@plone/volto/config"; export default function applyConfig(config) { @@ -24,7 +24,7 @@ export default function applyConfig(config) { Here three settings are changed: -```js +```{code-block} js import "@plone/volto/config"; export default function applyConfig(config) { @@ -47,7 +47,7 @@ For example the setting `supportedLanguages` must match the one set in the Plone To use Volto in a multilingual project you do this: -```js +```{code-block} js import "@plone/volto/config"; export default function applyConfig(config) { From 338a223f25517e1e2681e9b50f205f6974891fe9 Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Tue, 26 Sep 2023 15:10:59 +0300 Subject: [PATCH 19/32] pick node 16 version --- docs/volto_customization/installation.md | 2 +- docs/volto_customization/intro.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/volto_customization/installation.md b/docs/volto_customization/installation.md index d689268f7..22571da4f 100644 --- a/docs/volto_customization/installation.md +++ b/docs/volto_customization/installation.md @@ -19,7 +19,7 @@ Getting started with Volto involves setting up a development environment, unders Before you start working with Volto, ensure you have the following prerequisites: -- Node.js LTS (18.x) - (see instructions for installation) +- Node.js LTS (16.x) - (see instructions for installation) - Python - See below for specific versions. - Docker (if using the Plone docker images - see instructions for installation and how to run a Plone docker container) diff --git a/docs/volto_customization/intro.md b/docs/volto_customization/intro.md index 2aea34d3d..65db343bf 100644 --- a/docs/volto_customization/intro.md +++ b/docs/volto_customization/intro.md @@ -44,7 +44,7 @@ Of course, if you're already familiar with Volto and React, that's fantastic, an To follow the training as smoothly as possible it is recommended that you have the following software installed on your computer: -- [node.js](https://nodejs.org/en/) >= 18 +- [node.js](https://nodejs.org/en/) >= 16 - [yarn](https://yarnpkg.com/getting-started/install) - [node version manager](https://github.com/nvm-sh/nvm) - [docker](https://www.docker.com/get-started/) From 78220cc6273994b3340d8beb3da3a016ca612b13 Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Wed, 27 Sep 2023 13:44:04 +0200 Subject: [PATCH 20/32] adapt to use in addon --- docs/volto_customization/voltosettings.md | 34 ++++++++++++----------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/volto_customization/voltosettings.md b/docs/volto_customization/voltosettings.md index 2b2f5a896..1a11a5636 100644 --- a/docs/volto_customization/voltosettings.md +++ b/docs/volto_customization/voltosettings.md @@ -11,23 +11,20 @@ myst: You can configure Volto by modifying settings in a js-file. -This is the original `config.js` of a project where the registry is imported and returned unchanged. +In our addon we can modify the `index.js` ```{code-block} js -import "@plone/volto/config"; - -export default function applyConfig(config) { - // Add here your project's configuration here by modifying `config` accordingly +const applyConfig = (config) => { return config; -} +}; + +export default applyConfig; ``` Here three settings are changed: ```{code-block} js -import "@plone/volto/config"; - -export default function applyConfig(config) { +const applyConfig = (config) => { config.settings = { ...config.settings, navDepth: 3, @@ -36,21 +33,25 @@ export default function applyConfig(config) { }; return config; } + +export default applyConfig; ``` ```{note} The `...` is a use of the [spread-syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) that "expands" the configuration into its elements and allows to change existing values and add new ones. ``` -Some of the settings are duplicates of setting existing in the Plone backend. +```{note} +If you instead make your changes in the project (i.e. not using a addon) you make the same changes in the file `config.js` of the project. +``` + +Some of the settings are duplicates of settings that exist in the Plone backend. For example the setting `supportedLanguages` must match the one set in the Plone registry as `plone.available_languages` and in `plone.default_language`. -To use Volto in a multilingual project you do this: +To configure Volto as a multilingual project you do this: ```{code-block} js -import "@plone/volto/config"; - -export default function applyConfig(config) { +const applyConfig = (config) => { config.settings = { ...config.settings, defaultLanguage: "de", @@ -59,6 +60,8 @@ export default function applyConfig(config) { }; return config; } + +export default applyConfig; ``` ```{seealso} @@ -83,5 +86,4 @@ Many options are explained in the {doc}`plone6docs:volto/configuration/settings- You can not only change but also extend Volto here by extending existing configuration options or adding new ones. -For example here you add new blocks, cusomize existing blocks or configure what view/template is used for viewing a certain content-type. -Here are the most useful volto settings which we have for a typical volto project. +For example here you add new blocks, customize existing blocks or configure what view/template is used when displaying a certain content-type. From aaafe43b78dea2951d9766e7f60eafd221bdffdb Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Wed, 27 Sep 2023 16:47:45 +0200 Subject: [PATCH 21/32] wording of blocks chapter --- docs/volto_customization/blocks.md | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/docs/volto_customization/blocks.md b/docs/volto_customization/blocks.md index eccdbc185..cfdaf847e 100644 --- a/docs/volto_customization/blocks.md +++ b/docs/volto_customization/blocks.md @@ -9,14 +9,21 @@ myst: # Extend volto blocks -There are various ways of extending Volto blocks from core behaviour. The component shadowing is the plain old way of customizing components in volto. But it comes with its own problems like keeping the shadowed component up to date with latest fixes and features. -In the modern day volto development we can directly extend blocks in form of variations and extensions and populate each of them with their own schemas. +There are various ways of extending Volto blocks. +Component shadowing (see last chapter) is a very basic to customize components in volto. +But it comes with its own problems like keeping the shadowed component up to date with latest fixes and features of newer Volto versions. +Instead of shadowing components we can: -Let us take an example for a teaser block which we already have in volto core. In our addon `volto-teaser-tutorial` we will step by step extend each component that we have in volto core. +* Change the block-config +* Extend blocks by adding new block-variations +* Write add schemaEnhancer to modify blocks schema -The most simple customization is the View of the Teaser. The volto core teaser block confiugration looks like: +Let us first change the View of the teaser block which we already have in volto core by changing the block-configuration. +In our addon `volto-teaser-tutorial` we will step by step extend each component that we have in volto core. -```{code-block} jsx +The most simple customization is the View of the Teaser. The volto core teaser block configration (in `omelette/src/config/Blocks.jsx`) looks like: + +```{code-block} js teaser: { id: 'teaser', @@ -41,15 +48,22 @@ The most simple customization is the View of the Teaser. The volto core teaser b }, ``` -Plain and simple. Every block in Volto have Edit and View stock components. You can customize each of them individually by either shadowing or directly like: +Every block in Volto has Edit and View components. +You can customize these individually by either shadowing or directly in the confuguration (`index.js` of your addon) like this: ```{code-block} js +import MyTeaserView from 'volto-teaser-tutorial/components/Blocks/Teaser/View' -config.blocks.blocksConfig.teaser.view = MyTeaserView +const applyConfig = (config) => { + config.blocks.blocksConfig.teaser.view = MyTeaserView + return config; +} +export default applyConfig; ``` -Let's replace our Main teaser view with our `MyTeaserView` component: +Of course we need to add our custom `MyTeaserView` component in our addon. +From the root of the project that is `src/addon/volto-teaser-tutorial/src/components/Blocks/Teaser/View.jsx`: ```{code-block} jsx From 3458752d1fe18da3c6aae0c1cd35fae30f4c28ed Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Fri, 29 Sep 2023 12:41:50 +0300 Subject: [PATCH 22/32] WIP: weather block --- docs/volto_customization/custom_block.md | 73 ++++++++++++++++++++++++ docs/volto_customization/index.md | 4 +- 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 docs/volto_customization/custom_block.md diff --git a/docs/volto_customization/custom_block.md b/docs/volto_customization/custom_block.md new file mode 100644 index 000000000..11714ddb5 --- /dev/null +++ b/docs/volto_customization/custom_block.md @@ -0,0 +1,73 @@ +--- +myst: + html_meta: + "description": "How to add a custom block" + "property=og:description": "How to add a custom block" + "property=og:title": "Volto Weather Block (custom block)" + "keywords": "Volto, Training, Custom block" +--- + +# Volto Weather Block (custom block) + +Let's create a volto block that will display weather information for Eibar. For this we can use Open-Meteo API. Open-Meteo is an open-source weather API and offers free access for non-commercial use. No API key required. + +Creating a basic block in Volto, involves several steps. Below, I'll outline the steps to create a Volto block that displays the weather forecast in Eibar. + +1. **Setup Your Volto Project:** If you haven't already, set up a Volto project. You can use the instructions presented in [Installation -> Bootstrap a new Volto project](installation.md#bootstrap-a-new-volto-project) section. + +2. **Create a New Block:** In your Volto project directory, navigate to the "src/components" folder and locate/create the "Blocks" directory. Create a new folder for your custom block; let's name it "Weather". + +3. **Define the Block Schema:** Inside the "Weather" folder, create a "schema.js" file to define your block's schema. Here's a basic schema for our block needs: + +```{code-block} js +export const weatherBlockSchema = (props) => { + return { + title: 'Weather Block', + description: 'Display weather information for location.', + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: ['latitude', 'longitude'], + }, + ], + properties: { + latitude: { + title: 'Latitude', + description: + 'Enter the latitude of the location for which you want to display the weather (e.g., 43.1849).', + widget: 'text', + }, + longitude: { + title: 'Longitude', + description: + 'Enter the longitude of the location for which you want to display the weather (e.g., -2.4716).', + widget: 'text', + }, + }, + required: ['latitude', 'longitude'], + }; +}; + +export default weatherBlockSchema; +``` + +4. **Create the Block Component:** Inside the "Weather" folder, create a "Block.js" file to define your block's React component. This component will make an API request to fetch the weather data and display it: + +```{code-block} jsx + +``` + +```{code-block} jsx + +``` + +5. **Register the Block:** In your Volto project, locate the "blocks.blocks.js" file and add an entry for your "Weather Block" + +```{code-block} js + +``` + +6. **Use the Weather Block:** In Volto's Dexterity-based content types, create or edit a content type that includes the "Weather Block" in the allowedBlocks field. Then, create a content item and add the "Weather Block" to display the weather information for the location you specify. + +Additionally, you may customize the UI and add more weather details based on the API's response data as needed. diff --git a/docs/volto_customization/index.md b/docs/volto_customization/index.md index d7aab054f..43994b39b 100644 --- a/docs/volto_customization/index.md +++ b/docs/volto_customization/index.md @@ -24,6 +24,7 @@ What You'll Learn: - JavaScript Fundamentals: Build a strong foundation in JavaScript, covering essential topics like variables, functions, and data structures. - React Essentials: Dive into React, the heart of Volto, and learn how to create dynamic user interfaces using React components. - Customizing Volto: Explore the art of customizing Volto projects, from theming and styling to creating custom blocks. +- API Integration: Learn how to integrate external APIs into your Volto applications to add new functionalities. - Building Blocks: Discover the building blocks of a Volto project, including new variations. - Best Practices: Gain insights into industry best practices for efficient Volto development. @@ -47,6 +48,7 @@ Prerequisites: intro installation voltosettings +custom_block shadowing blocks schema @@ -58,4 +60,4 @@ listing_block ``` - \ No newline at end of file + From 536858bd46d443e0c92458467f373dd94fa27b63 Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Fri, 29 Sep 2023 12:57:27 +0300 Subject: [PATCH 23/32] fix --- docs/volto_customization/custom_block.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/volto_customization/custom_block.md b/docs/volto_customization/custom_block.md index 11714ddb5..27df55bfb 100644 --- a/docs/volto_customization/custom_block.md +++ b/docs/volto_customization/custom_block.md @@ -62,7 +62,7 @@ export default weatherBlockSchema; ``` -5. **Register the Block:** In your Volto project, locate the "blocks.blocks.js" file and add an entry for your "Weather Block" +5. **Register the Block:** In your Volto project, locate the "components/index.js" file and add an entry for your "Weather Block" ```{code-block} js From ddf2a0d245426b25d02f24b96a996a8e73239786 Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Fri, 29 Sep 2023 12:17:17 +0200 Subject: [PATCH 24/32] update migrations training --- docs/migrations/exportimport.md | 171 ++++++++++++++++++++++++++++++-- docs/migrations/migrations.md | 8 +- docs/migrations/volto.md | 9 +- 3 files changed, 166 insertions(+), 22 deletions(-) diff --git a/docs/migrations/exportimport.md b/docs/migrations/exportimport.md index e0070e94d..4b6cdd07f 100644 --- a/docs/migrations/exportimport.md +++ b/docs/migrations/exportimport.md @@ -74,11 +74,12 @@ It also does the following: It can be used in: -* Plone 4 - 6 +* Plone 4 - 6 (and beyond) Most of the additional exports and imports are separate from the content because they may require two or more content items. During import, you cannot be certain that both items already exist when one is imported. -It also makes it easier to adapt and/or skip these exports and imports to your need. +Example: Imagine a relation from A to B. When you try to create the relation while importing A the item B may not have been imported yet. +It also makes it easier to adapt and/or skip these exports and imports to your needs. ## Step 1: Cleanup @@ -121,12 +122,12 @@ eggs += [versions] # always use the newest version! -collective.exportimport = 1.6 +collective.exportimport = 1.9 # Use the latest 7.x version for py2 and at support -plone.restapi = 7.8.0 +plone.restapi = 7.8.3 pyrsistent = 0.15.7 hurry.filesize = 0.9 -ijson = 3.1.4 +ijson = 3.2.3 ``` @@ -146,12 +147,12 @@ eggs += [versions] # always use the newest version! -collective.exportimport = 1.6 +collective.exportimport = 1.9 # Use the version that is shipped with your Plone version -# plone.restapi = 8.22.0 -pyrsistent = 0.18.1 +# plone.restapi = 9.0.0 +pyrsistent = 0.19.3 hurry.filesize = 0.9 -ijson = 3.1.4 +ijson = 3.2.3 ``` @@ -339,7 +340,7 @@ contentexport = fs contentexport [versions] # always use the newest version! -collective.exportimport = 1.6 +collective.exportimport = 1.9 # Use the latest 7.x version for py2 and at support plone.restapi = 7.8.0 pyrsistent = 0.15.7 @@ -452,15 +453,163 @@ Here are some of the discussed examples: * Alternative ways to handle items without parent * Export/Import registry settings * Export/Import Zope Users +* Export/Import properties, registry-settings and installed addons * Migrate `PloneFormGen` to `Easyform` * Export and import `collective.cover` content * Fixing invalid collection queries +* Migrate very old Plone Versions with data created by collective.jsonify ## Fix html +The html generated by Plone 6 Classic differs from Plone 4 and 5 version in various ways. Here are some examples: + +* Image-scales in Archetypes were created using urls like `.../myimage/image_large`. In Dexterity we use `.../myimage/@@images/[fieldname]/large` instead. +* The image-tag generated by TinyMCE now requires a data-attributes `data-scale` +* Link- and Image-tags require the uuid of the target as `data-val` to be able to find it during editing. +* Image-Tags now support picture-variants and srcsets. + +Exportimport deals with these changes by modifying the html of all richtext-fields and static portlets. +It uses [Beautiful Soup](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) to parse and update the html and does a pretty good job. + +But sometimes you may need additional changes in the html. +For this exportimport allows you to pass additional fixers (methods that modify the html). + +Here are examples for some additional fixers and how to use them: + +```python +from collective.exportimport.fix_html import fix_html_in_content_fields + +class ImportAll(BrowserView): + def __call__(self): + # ... + fixers = [anchor_fixer, table_class_fixer, scale_unscaled_images, remove_spans] + results = fix_html_in_content_fields(fixers=fixers) + # ... + + +def anchor_fixer(text, obj=None): + """Remove anchors and links without text. + Volto does not support anchors (yet). + """ + soup = BeautifulSoup(text, "html.parser") + for link in soup.find_all("a"): + if not link.get("href") and not link.text: + # drop empty links (e.g. anchors) + link.decompose() + elif not link.get("href") and link.text: + # drop links without a href but keep the text + link.unwrap() + return soup.decode() + + +def table_class_fixer(text, obj=None): + """Cleanup some table-classes""" + if "table" not in text: + return text + dropped_classes = [ + "MsoNormalTable", + "MsoTableGrid", + ] + replaced_classes = { + "invisible": "invisible-grid", + } + soup = BeautifulSoup(text, "html.parser") + for table in soup.find_all("table"): + table_classes = table.get("class", []) + for dropped in dropped_classes: + if dropped in table_classes: + table_classes.remove(dropped) + for old, new in replaced_classes.items(): + if old in table_classes: + table_classes.remove(old) + table_classes.append(new) + # all tables get the default bootstrap table class + if "table" not in table_classes: + table_classes.insert(0, "table") + + return soup.decode() + + +def scale_unscaled_images(text, obj=None): + """Scale unscaled image""" + if not text: + return text + fallback_scale = "huge" + soup = BeautifulSoup(text, "html.parser") + for tag in soup.find_all("img"): + if "data-val" not in tag.attrs: + # maybe external image + continue + scale = tag["data-scale"] + # Prevent unscaled images! + if not scale: + scale = fallback_scale + tag["data-scale"] = fallback_scale + if not tag["src"].endswith(scale): + tag["src"] = tag["src"] + "/" + scale + return soup.decode() + + +def remove_spans(text, obj=None): + """Remove obsolete spans and smoothify html""" + if not text: + return text + soup = BeautifulSoup(text, "html.parser") + for tag in soup.find_all("span"): + style = tag.get("style", "") + if "font-style:italic" in style or "font-weight:bold" in style: + continue + logger.info("Removing %s: %s", tag.name, tag.attrs) + tag.unwrap() + soup.smooth() + return soup.decode() +``` + +## Migrate to Volto using exportimport + +You can reuse the migration-code provided by the form `@@migrate_to_volto` (it is in `plone.volto`) in a migration. + +You need to have the Blocks Conversion Tool (https://github.com/plone/blocks-conversion-tool) running that takes care of migrating richtext-values to Volto-blocks. + + +```python +class ImportAll(BrowserView): + def __call__(self): + # ... + logger.info("Start migrating richtext to blocks...") + migrate_richtext_to_blocks() + transaction.commit() + logger.info("Finished migrating richtext to blocks!") + + view = api.content.get_view("migrate_to_volto", portal, request) + view.migrate_default_pages = True + view.slate = True + view.service_url = "http://localhost:5000/html" + logger.info("Start migrating Folders to Documents...") + view.do_migrate_folders() + transaction.commit() + logger.info("Finished migrating Folders to Documents!") + logger.info("Start migrating Collections to Documents...") + view.migrate_collections() + transaction.commit() + logger.info("Finished migrating Collections to Documents!") + +``` + ## Final steps -* reset_dates +After everyting else was done you can reset the modification- and creation-dates of all migrated content. + +```python +class ImportAll(BrowserView): + def __call__(self): + # ... + reset_dates = api.content.get_view("reset_dates", portal, request) + reset_dates() +``` + +Keep in mind though that in a very strict sense you are lying to the users since the migrated content was actually created and modified by the migration... + ## Further reading diff --git a/docs/migrations/migrations.md b/docs/migrations/migrations.md index 0c2fe0fcc..da440aed8 100644 --- a/docs/migrations/migrations.md +++ b/docs/migrations/migrations.md @@ -27,7 +27,7 @@ These changes are reflected in different releases of Plone. The [release-schedule](https://plone.org/download/release-schedule) specifies, which versions are supported and for how long. -```{figure} https://plone.org/download/plonereleaseschedule-2022-09-12.png/@@images/image +```{figure} https://plone.org/download/release-schedule/plone-release-schedule-2022-12-13.png/@@images/image :alt: The Plone release schedule ``` @@ -39,10 +39,10 @@ Security support : Plone security hotfixes will be made available for this series. For more information, see the [security update policy](https://plone.org/security/update-policy). -From the moment Plone 6 is released, Plone 6.0.x will be under maintenance support, and Plone 5.2.x will be under security support. -That means new features are being developed for Plone 6.1.x, and bugfixes are being developed for Plone 6.0.x. +From the moment Plone 6 was released, Plone 6.0.x was under maintenance support, and Plone 5.2.x will be under security support when Plone 6.1 is released. +That means new features are being developed for Plone 6.1.x while bugfixes are being developed for Plone 6.0.x. -Plone intends to provide stable releases (for example, 5.2.8 is a stable release of the 5.2.x series). +Plone intends to provide stable releases (for example, 5.2.14 is a stable release of the 5.2.x series). Only bugfixes and changes that extend or improve an existing feature—as long as they don't break anything—make it into a bugfix release. diff --git a/docs/migrations/volto.md b/docs/migrations/volto.md index 1ab68826c..738178711 100644 --- a/docs/migrations/volto.md +++ b/docs/migrations/volto.md @@ -13,12 +13,7 @@ myst: See the chapter {ref}`plone6docs:backend-migrate-to-volto-label` of the Plone Upgrade Guide. -Issues: +This explains mostly why you need to do what and how to use the form `@@migrate_to_volto` by hand. -* Complex HTML, such as in tables, is transformed to HTML blocks. -* There is no migration from DraftJS to Slate. +You can (and should) use the power of that feature in your exportimport-based migration as described in https://github.com/collective/collective.exportimport#migrate-to-volto -Alternatives: - -* Start fresh -* Use `collective.exportimport` (TODO: https://github.com/collective/collective.exportimport/issues/133). From 2db9d9dae7369ee00de95444a21645650cd35557 Mon Sep 17 00:00:00 2001 From: nileshgulia1 Date: Fri, 29 Sep 2023 16:56:30 +0530 Subject: [PATCH 25/32] add missing imports, rewording a bit --- docs/volto_customization/blocks.md | 38 +++------ docs/volto_customization/data_adapters.md | 14 ++-- docs/volto_customization/extending_teasers.md | 16 ++-- docs/volto_customization/listing_block.md | 24 +++++- docs/volto_customization/schema.md | 60 ++------------ docs/volto_customization/styling.md | 5 +- docs/volto_customization/teaser_variations.md | 80 +++++++++---------- 7 files changed, 100 insertions(+), 137 deletions(-) diff --git a/docs/volto_customization/blocks.md b/docs/volto_customization/blocks.md index cfdaf847e..9144866b0 100644 --- a/docs/volto_customization/blocks.md +++ b/docs/volto_customization/blocks.md @@ -14,9 +14,9 @@ Component shadowing (see last chapter) is a very basic to customize components i But it comes with its own problems like keeping the shadowed component up to date with latest fixes and features of newer Volto versions. Instead of shadowing components we can: -* Change the block-config -* Extend blocks by adding new block-variations -* Write add schemaEnhancer to modify blocks schema +- Change the block-config +- Extend blocks by adding new block-variations +- Write add schemaEnhancer to modify blocks schema Let us first change the View of the teaser block which we already have in volto core by changing the block-configuration. In our addon `volto-teaser-tutorial` we will step by step extend each component that we have in volto core. @@ -63,39 +63,19 @@ export default applyConfig; ``` Of course we need to add our custom `MyTeaserView` component in our addon. -From the root of the project that is `src/addon/volto-teaser-tutorial/src/components/Blocks/Teaser/View.jsx`: +From the root of the project that is `src/addon/volto-teaser-tutorial/src/components/Blocks/Teaser/View.jsx`: ```{code-block} jsx - -const MyDataProvider = (props) => { - const enhancedChildren = React.Children.map(props.children, (child) => { - if (React.isValidElement(child)) { - return React.cloneElement(child, { - ...props, - enhancedProp: "some-enhanced-prop", - }); - } - return child; - }); - - return enhancedChildren; -}; +import React from 'react'; +import TeaserBody from '@plone/volto/components/manage/Blocks/Teaser/Body'; +import { withBlockExtensions } from '@plone/volto/helpers'; const TeaserView = (props) => { - return ( - - - - ); + return ; }; export default withBlockExtensions(TeaserView); + ``` Here, the View component renders a TeaserBody which will be a result of an active variation, we will come to that in later chapters. - -Notice we are wrapping our TeaserBody variation in a DataProvider which may inject some extra props along with its original ones. - -```{note} 💡 -The React.cloneElement() API creates a clone of an element and returns a new React element. The cool thing is that the resulting element will have all of the original element’s props, with the new props merged in. -``` diff --git a/docs/volto_customization/data_adapters.md b/docs/volto_customization/data_adapters.md index 90b2a7cf6..581100fbc 100644 --- a/docs/volto_customization/data_adapters.md +++ b/docs/volto_customization/data_adapters.md @@ -77,21 +77,25 @@ The above Adapter gets consumed in [Data](https://github.com/plone/volto/blob/96 Let's register a new `dataAdapter` our config: ```{code-block} js -config.blocks.blocksConfig.teaser.dataAdapter = myDataOwnAdapter; +import {myOwnDataAdapter} from 'volto-teaser-tuturial/components/data-adapter'; + +config.blocks.blocksConfig.teaser.dataAdapter = myOwnDataAdapter; ``` -In your data-adapter.js: +Create a file named data-adapter.js in `volto-teaser-tutorial/components`: ```{code-block} js -export const myDataOwnAdapter = ({ block, data, id, onChangeBlock, value }) => { +import isEmpty from 'lodash/isEmpty'; + +export const myOwnDataAdapter = ({ block, data, id, onChangeBlock, value }) => { let dataSaved = { ...data, [id]: value, }; - if (id === "title" && !isEmpty(value) && !data.title) { + if (id === 'title' && !isEmpty(value)) { dataSaved = { ...dataSaved, - title: value[0].toUpperCase() + string.slice(1), + title: value[0].toUpperCase() + value.slice(1), }; } onChangeBlock(block, dataSaved); diff --git a/docs/volto_customization/extending_teasers.md b/docs/volto_customization/extending_teasers.md index eb7670eb7..89a2cfc92 100644 --- a/docs/volto_customization/extending_teasers.md +++ b/docs/volto_customization/extending_teasers.md @@ -17,9 +17,13 @@ In this chapter we will tweak our newly created variation to also support extens Block extensions are the way to display a new form of your block for a particular block type. For instance if you have a teaserGrid, with block extensions you can control the styling and behaviour of individual teasers. The split of responsibilites is as follows: "the variation will control how the teasers layout and extension will control the individual rendering." -We already learn about the block variation in the former chapters. We will now add the teaser block extenttions the same way we do for variations. +We already learn about the block variation in the former chapters. We will now add the teaser block extensions the same way we do for variations. ```js +import TeaserBlockImageDefault from "volto-teaser-tutorial/components/extensions/TeaserBlockImageDefault"; +import TeaserBlockImageRight from "volto-teaser-tutorial/components/extensions/TeaserBlockImageRight"; +import TeaserBlockImageOverlay from "volto-teaser-tutorial/components/extensions/TeaserBlockImageOverlay"; + config.blocks.blocksConfig.teaser.extensions = { ...(config.blocks.blocksConfig.teaser.extensions || {}), cardTemplates: { @@ -47,7 +51,7 @@ config.blocks.blocksConfig.teaser.extensions = { }; ``` -As for the training we created only three extensions namely `TeaserBlockImageDefault`, `TeaserBlockImageRight` and `TeaserBlockImageOverlay`. +As for the training we created only three extensions namely `TeaserBlockImageDefault`, `TeaserBlockImageRight` and `TeaserBlockImageOverlay` into our addons `components/extensions` folder. In order to support these extension first we need to add a special fieldset to our variation schema so that we can seperate the concerns about individual teasers and put these extensions under it. @@ -92,7 +96,7 @@ config.blocks.blocksConfig.teaser.variations = [ Notice first we added a new fieldSet where our extensions will recide and the method `addExtensionFieldToSchema` imported volto core. This method as mentioned above adds a new field in the given fieldSet with the given extenionName `cardTemplates`. ```{note} -By default ``addExtensionFieldToSchema` adds the extewnsion field to default fieldSet, in order to ovverride that you can pass `insertFieldToOrder` method to specifiy where it should be added. +By default `addExtensionFieldToSchema` adds the extewnsion field to default fieldSet, in order to ovverride that you can pass `insertFieldToOrder` method to specifiy where it should be added. ``` @@ -387,7 +391,7 @@ import { formatDate } from "@plone/volto/helpers/Utils/Date"; import { UniversalLink } from "@plone/volto/components"; import cx from "classnames"; import config from "@plone/volto/registry"; -import "./styles.less"; + const messages = defineMessages({ PleaseChooseContent: { @@ -498,7 +502,7 @@ TeaserBlockImageOverlay.propTypes = { export default TeaserBlockImageOverlay; ``` -The styles.less is to be created as well: +The styles have to be added as well: ```{code-block} less :force: true @@ -576,6 +580,8 @@ dependencies: [ ] ``` +You have to stop the frontend server and run `yarn install` again from the root of your project. + ```{note} Its essential that we load `volto-teaser-tutorial` after volto-blocks-grid so that we overrride teaser block the right way. ``` diff --git a/docs/volto_customization/listing_block.md b/docs/volto_customization/listing_block.md index 7e69a3c20..01dee6ab4 100644 --- a/docs/volto_customization/listing_block.md +++ b/docs/volto_customization/listing_block.md @@ -16,13 +16,15 @@ First of all let's add a styling fieldset in the current schema of volto's defau In your addon config: ```{code-block} js +import { addStylingFieldset } from 'volto-teaser-tutorial/components/helpers'; + if (config.blocks.blocksConfig.listing) { config.blocks.blocksConfig.listing.title = "Listing (Tutorial)"; config.blocks.blocksConfig.listing.schemaEnhancer = addStylingFieldset; } ``` -Create a file named `helpers.js` and add the relevant schema enhancer for it: +Create a file named `helpers.js` inside `components/` folder and add the relevant schema enhancer for it: ```{code-block} js import { cloneDeep } from "lodash"; @@ -106,7 +108,7 @@ import ListingVariation from 'volto-teaser-tutorial/components/ListingBlockVaria config.blocks.blocksConfig.listing.variations = [ - ...(config.blocks.blocksConfig.listing.variations || []) + ...(config.blocks.blocksConfig.listing.variations || []), { id: 'tutorial', isDefault: false, @@ -144,7 +146,7 @@ Notice that here we will keep the schemaEnhancer configuration of teaser extensi Finally we write our own variation for ListingBlock: -ListingVariation.jsx +ListingBlockVariation.jsx ```{code-block} jsx import React from "react"; @@ -225,4 +227,20 @@ ListingVariation.propTypes = { export default ListingVariation; ``` +You might want to modify rendering of the images a bit in all the teaser block extensions in the `extensions/` folder. + +Thus, locate the Image component in `TeaserBlockImageDefault` and replace it with: + +```jsx + +``` + We will now have the per listing item styling support like we have for teaser blocks. We can also add more styling schema with the help of its individual schema extenders. diff --git a/docs/volto_customization/schema.md b/docs/volto_customization/schema.md index 4dbae2ed5..65553c1d0 100644 --- a/docs/volto_customization/schema.md +++ b/docs/volto_customization/schema.md @@ -48,13 +48,10 @@ We are going to create a new variation of this teaser block. This variation is e Go ahead and register it in the variations key like: ```js - variations: [ - { - id: 'default', - isDefault: true, - title: 'Default', - template: TeaserBlockDefaultBody, - }, +import TeaserBlockImageVariation from 'volto-teaser-tutorial/components/TeaserBlockImageVariation'; + +config.blocks.blocksConfig.teaser.variations = [ + ...config.blocks.blocksConfig.teaser.variations, { id: 'image-top-variation', title: 'Image(Top) variation', @@ -101,16 +98,6 @@ const TeaserBlockImageDefault = (props) => { const href = data.href?.[0]; const image = data.preview_image?.[0]; const align = data?.styles?.align; - const creationDate = data.href?.[0]?.CreationDate; - const formattedDate = formatDate({ - date: creationDate, - format: { - year: "numeric", - month: "short", - day: "2-digit", - }, - locale: locale, - }); const hasImageComponent = config.getComponent("Image").component; const Image = config.getComponent("Image").component || DefaultImage; @@ -156,8 +143,6 @@ const TeaserBlockImageDefault = (props) => {
{data.head_title}
)}

{data?.title}

- {data.creationDate &&

{formattedDate}

} - {!data.hide_description &&

{data?.description}

}
@@ -175,41 +160,8 @@ TeaserBlockImageDefault.propTypes = { export default TeaserBlockImageDefault; ``` -styles.less: - -```{code-block} less -:force: true - -.gradiant { - h2 { - color: white; - } - position: absolute; - bottom: 30px; - display: flex; - width: 100%; - height: 200px; - align-items: flex-end; - padding: 1.5rem; - background-image: linear-gradient( - 13.39deg, - rgba(46, 62, 76, 0.65) 38.6%, - rgba(46, 62, 76, 0.169) 59.52%, - rgba(69, 95, 106, 0) 79.64% - ); -} - -.teaser-item.overlay { - display: flex; - - .image-wrapper { - width: 100%; - } -} -``` - -Right now this variation only shows default variation of Teaser block. In the coming chapter we are gonna enhance it with extension per teaser. +After this you will be able to choose variations for this block from the Blocks Settings sidebar. Right now this variation only shows default variation of Teaser block. In the coming chapter we are gonna enhance it with extension per teaser. ```{note} -The [Body](https://github.com/plone/volto/blob/9667cf735e5c3e848de852d615941d98193e0a5e/src/components/manage/Blocks/Teaser/Body.jsx#L13) component in Teaser block also supports variations from component registry. You can read more about component registry in following chapters. +The [Body](https://github.com/plone/volto/blob/9667cf735e5c3e848de852d615941d98193e0a5e/src/components/manage/Blocks/Teaser/Body.jsx#L13) component in Teaser block also supports adding variations from component registry. You can read more about component registry in following chapters. ``` diff --git a/docs/volto_customization/styling.md b/docs/volto_customization/styling.md index f1006e539..e7cdc0ded 100644 --- a/docs/volto_customization/styling.md +++ b/docs/volto_customization/styling.md @@ -150,7 +150,7 @@ As StyleWrapper wraps around our view component in `RenderBlocks`. The styleName ``` -Go ahead and add classNames in your `css/less` files +Go ahead and add classNames in your `css/less` files. Create a file name `styles.less` inside `components/` folder and copy the styles below. Make sure to import this file into `index.js`. ```{code-block} less :force: true @@ -188,6 +188,9 @@ In your policy package, you can add styleMenu configuration like: ```{code-block} jsx +import paintSVG from '@plone/volto/icons/paint.svg'; +import { Icon } from '@plone/volto/components'; + config.settings.slate.styleMenu = { ...(config.settings.slate.styleMenu || {}), blockStyles: [ diff --git a/docs/volto_customization/teaser_variations.md b/docs/volto_customization/teaser_variations.md index 8c63e97d8..0d259c2fc 100644 --- a/docs/volto_customization/teaser_variations.md +++ b/docs/volto_customization/teaser_variations.md @@ -66,33 +66,32 @@ Finaly render it conditionally on the basis of data.creationDate The whole component looks like: ```{code-block} jsx -import React from "react"; -import PropTypes from "prop-types"; -import { Message } from "semantic-ui-react"; -import { defineMessages, useIntl } from "react-intl"; -import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; -import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; -import { getTeaserImageURL } from "@plone/volto/components/manage/Blocks/Teaser/utils"; -import { MaybeWrap } from "@plone/volto/components"; -import { formatDate } from "@plone/volto/helpers/Utils/Date"; -import { UniversalLink } from "@plone/volto/components"; -import cx from "classnames"; -import config from "@plone/volto/registry"; -import "./styles.less"; +import React from 'react'; +import PropTypes from 'prop-types'; +import { Message } from 'semantic-ui-react'; +import { defineMessages, useIntl } from 'react-intl'; +import imageBlockSVG from '@plone/volto/components/manage/Blocks/Image/block-image.svg'; +import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers'; +import { getTeaserImageURL } from '@plone/volto/components/manage/Blocks/Teaser/utils'; +import { MaybeWrap } from '@plone/volto/components'; +import { formatDate } from '@plone/volto/helpers/Utils/Date'; +import { UniversalLink } from '@plone/volto/components'; +import cx from 'classnames'; +import config from '@plone/volto/registry'; const messages = defineMessages({ PleaseChooseContent: { - id: "Please choose an existing content as source for this element", + id: 'Please choose an existing content as source for this element', defaultMessage: - "Please choose an existing content as source for this element", + 'Please choose an existing content as source for this element', }, }); -const DefaultImage = (props) => {props.alt; +const DefaultImage = (props) => {props.alt; -const TeaserBlockImageOverlay = (props) => { +const TeaserBlockImageDefault = (props) => { const { className, data, isEditMode } = props; - const locale = config.settings.dateLocale || "en"; + const locale = config.settings.dateLocale || 'en'; const intl = useIntl(); const href = data.href?.[0]; const image = data.preview_image?.[0]; @@ -101,21 +100,21 @@ const TeaserBlockImageOverlay = (props) => { const formattedDate = formatDate({ date: creationDate, format: { - year: "numeric", - month: "short", - day: "2-digit", + year: 'numeric', + month: 'short', + day: '2-digit', }, locale: locale, }); - const hasImageComponent = config.getComponent("Image").component; - const Image = config.getComponent("Image").component || DefaultImage; + const hasImageComponent = config.getComponent('Image').component; + const Image = config.getComponent('Image').component || DefaultImage; const { openExternalLinkInNewTab } = config.settings; const defaultImageSrc = href && flattenToAppURL(getTeaserImageURL({ href, image, align })); return ( -
+
<> {!href && isEditMode && ( @@ -129,36 +128,36 @@ const TeaserBlockImageOverlay = (props) => { -
+
{(href.hasPreviewImage || href.image_field || image) && (
)} - -
+
{data?.head_title && (
{data.head_title}
)} -
-

{data?.title}

- {!data.hide_description &&

{data?.description}

} - {data?.creationDate && ( -

{formattedDate}

- )} -
+

{data?.title}

+ {data.creationDate &&

{formattedDate}

} + {!data.hide_description &&

{data?.description}

}
@@ -168,10 +167,11 @@ const TeaserBlockImageOverlay = (props) => { ); }; -TeaserBlockImageOverlay.propTypes = { +TeaserBlockImageDefault.propTypes = { data: PropTypes.objectOf(PropTypes.any).isRequired, isEditMode: PropTypes.bool, }; -export default TeaserBlockImageOverlay; +export default TeaserBlockImageDefault; + ``` From 960623b4c0085a7b93d470749fb77ab96d4e0d69 Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Fri, 29 Sep 2023 14:41:19 +0200 Subject: [PATCH 26/32] add volto4dummies to frontpage --- docs/index.md | 6 +++++- docs/volto_customization/voltosettings.md | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/index.md b/docs/index.md index 076130875..481ee9eea 100644 --- a/docs/index.md +++ b/docs/index.md @@ -65,6 +65,10 @@ teaching/index : Build custom Volto add-ons, explore more advanced Volto topics. +{doc}`volto_customization/index` + +: Are you new to JavaScript development and eager to explore the world of Volto customization? Unlock the power of Volto, the modern React-based CMS framework for Plone, by joining our comprehensive half day training designed specifically for JavaScript beginners. + {doc}`effective-volto/index` : Learn proven practices of Plone frontend development. @@ -125,7 +129,7 @@ Because we began this practice in 2022, all previous trainings that have documen #### Volto, React, and Javascript -- [Volto](https://2022.training.plone.org/volto/index.html) +- [Volto](https://2022.training.plone.org/volto/index.html) - [Angular SDK for Plone](https://2022.training.plone.org/angular/index.html) - [GatsbyJS](https://2022.training.plone.org/gatsby/index.html) - [JavaScript For Plone Developers (up to Plone 5)](https://2022.training.plone.org/javascript/index.html) diff --git a/docs/volto_customization/voltosettings.md b/docs/volto_customization/voltosettings.md index 1a11a5636..ba4a006e5 100644 --- a/docs/volto_customization/voltosettings.md +++ b/docs/volto_customization/voltosettings.md @@ -72,10 +72,10 @@ Here are some more setting you might use in your projects: - `contentIcons` - configure Content Types icons. See https://6.docs.plone.org/volto/configuration/settings-reference.html#term-contentIcons - `navDepth` - Navigation levels depth used in the navigation endpoint calls. Increasing this is useful for implementing fat navigation menus. -- `workflowMapping` - colors for workflow states/transitions. -- `openExternalLinkInNewTab` -- `hasWorkingCopySupport` -- `maxFileUploadSize` +- `workflowMapping` - Configure colors for workflow states/transitions - if you have a custom workflow or want to change the default colors. +- `openExternalLinkInNewTab` - Kind of self-explaining, isn't it? +- `hasWorkingCopySupport` - Enable if `plone.app.iterate` (Working Copy Support) is installed. +- `maxFileUploadSize` - Limit the size of uploads - `nonContentRoutes` - A list of path strings which are considered to be outside of plone-restapi's content serialization. For example: `/controlpanel, /login,/sitemap,/personal-information` are all nonContentRoutes. You can find all existing options in the file [config/index.js](https://github.com/plone/volto/blob/master/src/config/index.js#L73) of Volto itself which is available in your projects in `frontend/omelette/src/config/index.js`. From 278e54527521799620a5445f4ccb0925b1bde921 Mon Sep 17 00:00:00 2001 From: Claudia Ifrim Date: Fri, 29 Sep 2023 16:11:33 +0300 Subject: [PATCH 27/32] add weather block --- docs/volto_customization/custom_block.md | 139 ++++++++++++++++++++++- 1 file changed, 135 insertions(+), 4 deletions(-) diff --git a/docs/volto_customization/custom_block.md b/docs/volto_customization/custom_block.md index 27df55bfb..e3e3ad877 100644 --- a/docs/volto_customization/custom_block.md +++ b/docs/volto_customization/custom_block.md @@ -28,7 +28,7 @@ export const weatherBlockSchema = (props) => { { id: 'default', title: 'Default', - fields: ['latitude', 'longitude'], + fields: ['latitude', 'longitude', 'location'], }, ], properties: { @@ -44,30 +44,161 @@ export const weatherBlockSchema = (props) => { 'Enter the longitude of the location for which you want to display the weather (e.g., -2.4716).', widget: 'text', }, + location: { + title: 'Location', + description: + 'Enter the name of the location for which you want to display the weather (e.g., Eibar, Basque Country).', + widget: 'text', + }, }, - required: ['latitude', 'longitude'], + required: ['latitude', 'longitude', 'location'], }; }; export default weatherBlockSchema; + ``` -4. **Create the Block Component:** Inside the "Weather" folder, create a "Block.js" file to define your block's React component. This component will make an API request to fetch the weather data and display it: +4. **Create the Block Component:** Inside the "Weather" folder, create a "View.jsx" file to define your block's React component. This component will make an API request to fetch the weather data and display it: ```{code-block} jsx +import React, { useEffect, useState } from 'react'; + +const View = (props) => { + const { data = {} } = props; + const location = data.location || 'Eibar, Basque Country'; + + const [weatherData, setWeatherData] = useState(null); + + useEffect(() => { + const latitude = data.latitude || '43.1849'; // Default Eibar latitude if no latitude is provided + const longitude = data.longitude || '-2.4716'; // Default to longitude if no longitude is provided + + const abortController = new AbortController(); // creating an AbortController + + fetch( + `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t_weather=true&timezone=auto`, + { signal: abortController.signal }, // passing the signal to the query + ) + .then((response) => response.json()) + .then((data) => { + setWeatherData(data); + }) + .catch((error) => { + if (error.name === 'AbortError') return; + console.error('Error fetching weather data:', error); + throw error; + }); + + return () => { + abortController.abort(); // stop the query by aborting on the AbortController on unmount + }; + }, [data.latitude, data.longitude]); + + return ( + <> + {weatherData ? ( +
+

Weather in {location}

+

Temperature: {weatherData.current_weather.temperature} °C

+
+ ) : ( +

Loading weather data...

+ )} + + ); +}; + +export default View; ``` +You should also create a "Edit.jsx" file. The BlockDataForm component will transform the schema.js data into a usable sidebar. + ```{code-block} jsx +import React, { useMemo } from 'react'; +import { SidebarPortal } from '@plone/volto/components'; +import BlockDataForm from '@plone/volto/components/manage/Form/BlockDataForm'; +import weatherBlockSchema from './schema'; +import View from './View'; + +const Edit = (props) => { + const schema = useMemo(() => weatherBlockSchema(props), [props]); + + return ( + <> + + + + { + props.onChangeBlock(props.block, { + ...props.data, + [id]: value, + }); + }} + onChangeBlock={props.onChangeBlock} + formData={props.data} + block={props.block} + /> + + + ); +}; + +export default Edit; + ``` -5. **Register the Block:** In your Volto project, locate the "components/index.js" file and add an entry for your "Weather Block" +5. **Register the Block:** In your Volto project, locate the "components/index.js" file and add an the entries for your "Weather Block" ```{code-block} js +... +import WeatherEdit from './components/Blocks/Weather/Edit'; +import WeatherView from './components/Blocks/Weather/View'; +... +export { WeatherView, WeatherEdit }; ``` +We need to configure the project to make it aware of a new block by adding it to the object configuration that is located in "src/config.js". For that we need the 2 blocks components we created and a svg icon that will be displayed in the blocks chooser. + +```{code-block} js +import WeatherEdit from './Edit'; +import WeatherView from './View'; +import worldSVG from '@plone/volto/icons/world.svg'; +... +export default function applyConfig(config) { + + ... + + config.blocks.blocksConfig.weather = { + id: 'weather', + title: 'Weather', + icon: worldSVG, + group: 'common', + edit: WeatherEdit, + view: WeatherView, + restricted: false, + mostUsed: false, + sidebarTab: 1, + blocks: {}, + security: { + addPermission: [], + view: [], + }, + }; + + ... + + return config; +}; +... +``` + 6. **Use the Weather Block:** In Volto's Dexterity-based content types, create or edit a content type that includes the "Weather Block" in the allowedBlocks field. Then, create a content item and add the "Weather Block" to display the weather information for the location you specify. Additionally, you may customize the UI and add more weather details based on the API's response data as needed. From bcd98ebd015e91b3c5e84653164b105fa478e2f3 Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Fri, 29 Sep 2023 15:37:02 +0200 Subject: [PATCH 28/32] mention changes due to addon approach --- docs/volto_customization/shadowing.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/volto_customization/shadowing.md b/docs/volto_customization/shadowing.md index 3f9f28049..90cce6229 100644 --- a/docs/volto_customization/shadowing.md +++ b/docs/volto_customization/shadowing.md @@ -21,6 +21,17 @@ To avoid duplication we simply follow the chapter {ref}`volto-overrides-label` o In that chapter you learn how to override the logo, the footer, the news-item view and the default listing-block. +The only difference is whenever we add new files instead of adding them to the project we add the to our addon. + +For example when we customize the News Item View instead of adding the override as: + +`src/customizations/components/theme/View/NewsItemView.jsx` + +we add it as + +`src/addon/volto-teaser-tutorial/src/customizations/volto/components/theme/View/NewsItemView.jsx`. + +Both paths work fine though, we just want to go all-in with the addon-approach. ```{seealso} - {ref}`voltohandson-header-component-label` (Volto Hands-On Training) From 9502f00ef79a9ef91e41a3caf956b3a708fd4db4 Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Fri, 29 Sep 2023 15:38:19 +0200 Subject: [PATCH 29/32] workon wording of block variation --- .../_static/variations.png | Bin 0 -> 11798 bytes docs/volto_customization/schema.md | 43 ++++++++++++------ 2 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 docs/volto_customization/_static/variations.png diff --git a/docs/volto_customization/_static/variations.png b/docs/volto_customization/_static/variations.png new file mode 100644 index 0000000000000000000000000000000000000000..b4bca9e74ba9a776d9affd2dd259fd56b3086663 GIT binary patch literal 11798 zcmeHtWmsHGw#yUja{s<&$CoLB~Q! zNM1rnh*;jy&eX!%1Onpy7nisR+FplugL+2sdgwin$5qoTnoE((zs0N^)rEv4_4I0s zZFqe?(SL$7ql$>idxUEh*Un53l+9==)lt`*aO(}_zP|FkKJmz!xb(;=)KH?afK%Kr zLq~|=!p2Uf%x`CZu@JVQvuBg<=vXN)-i_=+?*WJjY z)(aW#oFR_RmCjTpEg2G9tUY_O3ic_y8*WX)Sx5glOSWd4=I>g?AKJ!(e>9t9Z$D+p3N%#}czDhs++G4zxu8J_k3qsi> z9~uevXOARj-axZ(4s}5CIv2k$(|YMJ=vUHV@_aAHqtce>HFPU^|fHXV=6eI=&G?0P>J`iCR5HR301Oz4U3jqNg9|{2n{9*uK`5dVK%!PExf&Nz- z6I4(@Nk~Eh_*F7;G%>MtGPiRkGL)WyfPmt$P*!(VmyzZ)va?|@Ft#%^VQ{yx2UUUK zcIO0=HYUyn#O^lMwoaVxJfz?foIo1%n30qiT*TRmhg4lgo><7v(S(?dfr){Mloyeh zn3&tq*pyRISoH7efW$*;?(A&O$;jyD=EmU0%3$Yc#>mXU!NJJH!pOox50s#H^00L_ zaHqF*BKxb6|7=It#L39f!rs}!&XyR|u7RPQi!%=?DX61={r#nrz=Kov~+@<=zyJY?J;h$apBj+DAK||n_bF=_@ zGXU9;mzkUKzdZZ9JU1iA!2dA#U$Y5*3QQ+2A~)l|mIg0k{adRl2ngzS31IK-Yv5?@IrPcffr5-3R}^e<|{3Ko&XI~)@-dDyS^2)9J^zwmt$jgY`0?`rr3{)$e6eY zK*2bFYWQsy5!!ip3}Q&&U&R00I4Tq~UW`+}GcMIhtm@VX$H&Jne~aAR*d0A(Yu*V%{R+|!3jwBS${hZ-zE9ZV zc2Wof7vI|J!|zRzJN-Kr7o9SDlKn?})}{7nSyEK|xKacJ#XLb+gyFAZCQpXHL^W<- z8cQw*K3Yn4bDazg!Jd8r4FzEy-CkmP*RNhMKK^UIYJsF;g|S3>x?t#8XlU?IeXww` zYC{J7lPgta8=sgh`AVExmWQgPT1i>WmWSU91j1{?1gN`lrX{Z@dwica&p~d zw`?z6No@L(9-5cTr;101&EVxG2c46lbTv!mGPu*VA7Tlav1RSVvvP==o$qSAZ?|M|IGjRTvX{_IY*PB+VE*745|Ph+PT_gfZuXQ} zQ#ByS_i49Dzc|ev)kC;}?Dbolqny9!*KHw(rj$t#qKYYfKzklls~C#EK18XGRq(CU zeVD5}7Wk`w33y;x6zw=r-e*YSuI44vWpnDh;#rl^$>w$vC3q|AtpgQ3&tdJo)rtJ}npnROlm;JPG56`#g^E--C)3F4`)f5_o zyQX)4K=>mHdV- zD==@|)rWBL=W=U%{d_Ccbn)!@pg0SKQJ!B%FEUn5%sMuBrc7Re;JWf#2x2k8$NMxf z@GheT)bb2bEHK{R{$zX*{zb7;)5VCHRi5GbsWIAzYAcie#9#D?@a8gCsCc;#XNR;w zjtsORYcbElzZ(rKoBm<4V730N5j+9`~nBq4;kXbO03sN$qbUp(slP77ZaPtivvcc zgbHoJk}=I_R!gkBCVNa;v%JS#;?-xQ@fq=SXC5a#u)`+SHe+Q5=q`(A=!)z|zq|bH zQOg|47cI3+OrI_|K$aY$hIx!W6OJsR^&+K_jC>cB=JA}m;?=_aN3P9RXMA9wgi%n3 z`KEAdRKfh2OrV(h-S5^{-3Vzo*cMvG_!yXvcG z{}~*pDIKQ^12-Sf-w>=?h3im-))ntLYEmsBu2jR&nm6$E2TsXP^f z>J`vbt{(!YZ^x=o84;+xCVu~KCs1^z6rcs8N5!vjdrfHg1U|4~fwTLqJ~J(-*dI>d zq_4b1I}`(*=?rK&-&-M~G$cUh`W%A%v`>4OIv>cw_5pyOfK?xp1QqL$1=>F3>AMH- z1|*3T}|twP0l{F>}5@c%oMOf^~%gx<#r=Ndy)1 z&IH=_0MzW9Y8s65I#9gy2X>uL4a#Ne3Z!IYE8mH0glqv0SY~#fa$3Z2>gxdc0WdNw3$zt@G6Jcp;TI+v0NQe5)=s^GlO4ZcjfS&`7^O2Ol1!K}7UQP1zG zzU|Lul*Yl=@i8glsv90f=ixKwo(fok+c>J)SIl-iUPbrk`Bi3`(?lNI=m|N+(Yg1&7r%dMtxO>0q{;mdou#+2j7^ znD#U7$9PyIZ1JF1D8`4gdsB7+0UFS=7ohrU(+|sDzXGkxV zozE@$H_vCisH1y7^K5*HA18QjGiXW$LlCD*)fg9=9P*BzV+gpWFB#jf;+;>HH4^9Y zB``fs+i$Hs%DffpEmeN<-LCm{8p6!3A4G1@BL=z2%f~q%Ob;iD*`?nWW&2_vzgrAN z#vvsWjh;;Aj_2ouvIyZRg>5%iuUd!OJfSu~6`!M_!hC#sf~~!d<-HeguwF1smpM%3 z3P!^wAfVT2byX46Yxi`a)@^IL7ZOs34dt_(U#KG!S2w5P1Sih&ZUxde|p^A z&B%2=-y4_;Kr{nKD80sflM{OnjZa-}Q`IiT>C;$pMIP?Cq5mv&ztkr0n>4QC* zwdOLXW63Y`&vS384-ejL^7}`j}4Ts0!n9qIQ zhk1bC$@_4`YO&N%?pdf(s%n|DH&>ZWFPyhF$z)OWDcGKgOwLNYSKn{F3-bC^(oAkv z-OhO$3_pLEc3sX}Tp_Kh5%ylry_BRxgcfo#45ShF_ znpCA{u~{nu2~7G=H%oR658QXj{O;~e7%O>Vv69~2Z7t09>-^nax&@M00`E(OBQOqZ z%$^_b9D()!{)^ZEA&=*fk{nM#R`=4+1ZpK^@mIN=(rA=2Y5A|z=r`SewL0!dmP`^6 z^17X5^unGq=(LFE3WmVA;D5AKZW;EcN$C{tBGxBzba-Rrh8<5PFgM|;IKP77qKsDS z@)+QA`Qwx2tLP7pkQTpK9q2DO2}qDrva_>g6~zcdB@)fG_nO+V)qV6He$I{KyRcJ{ zkdUa{`1_~-e6NFTi%qA_q(T_Zc{~eaIa5+#Ybdid^o6X(W{GWop|(gmn^%X^_2_-A z=?_I#li;byH`L!=DRNJ?c{q9O<%Uhy!Uq`C_%prE>R*Ig9b-D2DC7CF9wa&a(=Ww& zJxvtK0%0DBvxn&>_uaBnKdIbPx#?C)qEO$jwDu~$s!Qd?rPK~rt!Wo`qw~%F8rNgZ z?jr(L2OG}lz=uVq^r@(L&8zEnErN}=4FU?Dv2(FT$2*s{P~mZGTKwp4Y1-$MJ)S%oI}s1m~br`M!H}ix4{3JmxHNtk8#1q zMR1Sg*A$rBF;<<=E>{!u#ao)p&9Pe3oZodVDf_z2YwDS+oE$y3Fz^{~^!JZ+mG~z* z0)!N-4HY~+@}4miq=N8}))pyJx07X>SG;E9_*ho`<8Ol{(6SppZI>z+$3Onrils@? zDv~8wvXA z(Z14F7Hd=XL_tCAB!#g$8Xqw16Zs$Cw%RtoF9{*=u+K{TZH|2!^EG4^ms`cM*J*o0N?{(K^~3J*#NcPVqF{neBtG|ku`(>vQ@EvBrrMXa zm*=7$!5d!tm;jT78WT${GSl6&5FAcHnDAp$P?;RuJO0qR^kE%i~U!fuTRW6a! zg%@k~ejd$f``qP{wTDRKGPaccr{dV`8C-fQySwJ?p98-DDA*~=R`1U|NAs%1x6`dh zUEfgkf4;Mmg73^_tSa5!isegc^SDG5w3+`H96Jk$3}L85*mV9z-A=y>Wh~(PdENgXYO8I)z%9&2cO5ktqhu`r}!^zyj7bwF0eNZ$;mr;XN=!|&^pCX z`dj233ZJ`I_tM)Q&3T$|9ZIIL=yMZhYqh>5+;Im~(u|+HFB`pKNP=wc>4NHva#`G# z-EY>&CSR?cMc5R(lLhUIXl7C!qeoSsxd+c*t;eyUR!R^TVGhlvddi0N-{asu#{7;=pSK+>5V z`Z6H6*kuC%#76WfNHCIq4YYlF1#1QF$`(Mot)JswgNwNVDA1>fQ5_QmOzqQwZf$~{ z0eA=?X(6C(E}!l+08_^KF9F@!lI25#ik%SvZLjSk%?5*XU8V%^Asz_U#}eUEl0mA7 zcex=LdlsIw${79ti!FfGv&UWy89-JrkfuCRW{UvQ{|`N{W!rDQ4$Gfxvde!w)T*tE zsI+CLaami;D&XCZhT&fyx}&{N*xt7eL60jhsAd{PhsW)ho&BxtOA0F#l&@Xw&C=t7^hVWm9L$TC3Sa5i3qO~r)ma}J*1uUU=Nw?cvZ(ewuS~iq*is7-Q3~Q11rMQU6SQk!VqV)S3 zkH=mtMX)z#xC`|NLKXOY-ef5f5=m{ntV7nSQH$`*VGd$&79-?%R>Zv4?qs|fR^xl3 za8RopB?#@Ta5+h;yv_k8K8~Ym=zj zIRtXN-NT*Bd>Z?7Boe-lMjS-YC`G5Xl9cs-R+~0UPx>Nw7ij!^JD7j_O|L*eIAyx6 zsA^=c$x#7kxvq}W&vDr9;=F;6q6=+JS5&-Ea+oQ#@%noPi>?LV7l-}DZ=*-Vfe8fbf0O0M;o84R_GdJJgB)GYRl$*G_jpaNneUpgv4=Q*6kS~6tx^IXyAfKBV%A=z%c#*fEq zA*oQ#m)$`DOFfrOV2oD~vV!mP=o2SiEP0#>4DsR<--=Q2jcrTaTUR}F=jrH; zWV%B~PREe0mLO)D2h4$JxO3-ulr47(=HVNqN%(Hz;N6eHTu*~nl`rS!vy5@U!v zfN!f}q=)D^!CL^*(e0Ud-|;1LL_@}C=`HrBYq@q7*aG8ReF0?N@{cqGl;KTfPuJEZ zTC_J}cv?g8HWuN7y{33O7QJIHjy)(osVCtA0ZVXG1_prw5K&nKRtZ%IT-ck{Hs`+? zl8^M>xJ*+ccd~!$siUJfGqY~PVv~tZ+PkPiJl`lqF4Zhc`$qie$mISdx%`o}67MGc zx1)1j6XLD0@deTw@^{nWt!BmrQQL_tgX5zq^?vW7>R`9|5^V?0SUp2;%Y-0$R#(hV zYF3K2XH?*ndr7Vq+DCU(`#6+3v2Y5_a01%>28z|Utx8eFw|^p8Qb}#khdTOIx0N9G zy}#voi4%S^Or?dI@iidoW+cm~`a-^+^g`oS%MMQK(itUj*I2qOGEZnSeOXPJKI>ql z_jUxhMCDZHnXIhVvRG}Q55JAq>Irl@q}z|FtfQm73xeJ$w?iGRjq;Un%SIs2F*_pO zkP3{sx6kH$Kj|InUwuP8XjD1EBRb!Y^+5J}#HMq|d3>HXqC7G;AY-(tC&|N3Mt>{! z^1^;WuyK4ngzJq9Bfr@fu&bkn%BXRVq8Nqn6H1d_Qpl-OMxEP+k*J0w>h=qVBrlQ6b(%=g50`0i1l&6O0$tLp*;&MlNPwggDXA_asu8uwr#juCL( zUXYwoV5Ue89T5KiaQ@5e%u<|n!x0Vjgdk!0%cQdn_eEfqBL&gl!UNMHRy9>jDPN*Y zoyzCe(NXt!4qW+@PCFiC9sb_Vml`WU6d8!>`AR7x zNuk-qXV?c{tdJLakHco20)SwVos~|%&T^D&zvpIve3770{!V$qkT!eywqMHb-rm75tJOEN;XS!I4#dew9r4nEP4&e1xT3j%v zVGY9rOn!b7Iq=?}DgcP68Rxo;Yb3wMQX|e?R|NAz-~yqdljZRn=cBm+ajWZb+ST4q zq0OzWov~C_OaBtx_7+@X<~R^FS7W!vTddt&b8!RQR7Or#T220(ZMd#_SmHnp95Q@{ z;TFv?9*(EJ{QX1exkxrME%5N8)$II;R;z2dWT{?f2R#Z^xn{kj#cEr#bqs&sqo?*bTa(} zKz%BwF~3`!68(%@u=q72!&+)9!Uf*G&^C2r$qje0$-zj=#;Tt4Y8x10!SO~p`o3IRGoIjW;or#qd+Y?&* zWx?LEdF$#@cbk5ro$RwWNpjur?bPUZ>;i}B_F{CmY_?>F_g%hJGDBcv^vm;Yry;U= zjpYo@N2%M(%i0}~Qu5Q~zvg&q{p<;!29X?_G^fZ9#mQFWOkv=p3JBF1LHI(y8q06UH+Ad3(~lOV}+} zq5Z<(hXpXPYpR35#g|$^51_RWMM%hDbBi>-c6It;&06zmWkSQh+d###66GdDN?)wv zk;gOKdIujDDk5m({;KvEAdXAP$8OXrw2QIDXjMw`r9Tz9Etcr}E+;a%s6r62Y6=Q?x;Y^h1M4A?1#OlZT-f;wd}8K)lb@ZQ*^S>+ zt56c__syxm!$yU`vl4Fyiu7L}&J|e_U@LqH&7>a+YI7f0t*V7Fh|d)Y8`JKj; zjUy4-K5kr-{ir|Bw*}gy=BIPd_|TGhqMwy{Ry}qJ>ha8geQdeWsNWrUqd|~m)L>gi z1dlC|?Y@Z+=8jn2JNP*du-EG7Lx>hqvYWTOsWKkMZO>c zGBkjCdC@&4267_x!=&3iudNr*es|vphXF4mVussX&WmQ7KeNgbENKxM5$5|UbP8essX;mEQ1FETCAU6Ba zy0|?q@~sFre>Np^x!E?`Zv-L=5Z47xiUWt5HB#lhKwtH_w7L0rSx0y089PxIXLbHG z;YSI>!-A(4!8E#k2Ie6H+TCCT%nV$ZDGvQW3(z`GtEdwdVk&hb-!p&e3V@!W`$$7G zf~~aL=26?%-!B0ig1;aG|E$SQvTl9K<18!<4uV0Ju7Ky%ey8;@u?V2HInRd3Y0=lE zS0vkQE*hRMMj0*V!~hOEQqBmEcyml0zrRua*lndLut&*Pr&vhT<9r|>4rvyNQZ6e) zL3Onj0`LT|oC}gNeX{6}hhZtXWYGaQoE-vb8Uk}i+&gLyZoBT=L+IBi%f3(d5&(6x z;?Qp<1Ndv(Kv`o<(5;mpQ(s!=>pD32BK<#R0tUG4MOC<{UAIOy6Uawwt+QHNFOu~SW_5y$K;KBLKm=e^IZ;S6+65=iq)&XT^%hb z`Tp5}i%pW)CD%8B@}&;dz=2pg;eh&MK2xTlbkel-8t0R31~~=AaJpRwbuxoaJivNO z>Fet!Va3!uK0dNs?Y@uAt3%E-wr8dFF_A~M`@$az!>%-ehHBR$w0^eH3kqsYa9>7q z-|yv3m8j6BezZ!eGyf@Qj~bf#0C-jVr>oR<9clkn@bV>qF=QwmS(IMcJt9TW^+U`{#5`3n#)NCNm-H3YXr8kKDT)O|Uet0aqJnI<^4 zSZ+G!qvnqD--U;9AOFasmB}wI9v+RuD!S^vg;ESajI?Xgj+lkY&d$zJcWio1a!~AP zV&g8B?^zvzUXZg2h#DaXV+FyR{$6B48q|UUf`^VENHqMFDz;3kQMTY304@Db=lHAe zz)?jB1R3Rfc%Ap;6N`)nV-)kn(Nj5`3R@apu1{J|O9Eb5xL^9O0TC#1Am}%9M8xWW z3=c2#Q@raJuySrc7(_h~vD@cZue7KT$B4xeCO$tsi~^9yHociE3N9!R+nM`UnFi~% zIe>I*7>Ltc4yF}q9kjkV81f0t?!rSZ;5{0sqDDnWD~rK5w*$Gu&r_~3lTmEQlqoZe z+D-BlB;3IZJgYS3^5fe-j8(UomEv#nf=&WV(f#f`1D6TdVpu3$HTTl zUle#iW9y+K$So{UDP6oc3x?qaMZhImuy1{UgBA-z0{~{9gI`DK-yqT|6-Hz5(@9${ z0g+7J>k)K2*ea0orO^wsQl#K);{OgC8ZvD%n&gml;*b87Ta5TxxzA~5vKAIWUkq{c zS7pb2$>Kox!nqicPrmpblQ=+Mt03bV;2s$Y>}~y$`WMsX z?r~6Dq%02AD#RodW}q77&UI71#oIvs8i%DXm+zrZ>sVqU@$iPof*`Otk?#*EYT!BQ zALn+ws6wAX`a=VV_NI?S-f+-NXz-1RK~-R^C&y}23_PZi`kzS(3JR9|an%%i%cxt| zKk{q!a`xka&)tPd@?nTNX9K697)pnX6j{I#a66n}n4%k0gaM#DnSg+RrC)mi?)ZRb zX4mnWO1rLzD)62Ic7V^rO|f0JBc9Rt!Kd2kq;IxKS;k!6pDx`f{LAi2>!JbqS+Xb-_|BQ^K0#Aai8LLDFeOtD { + // ... + config.blocks.blocksConfig.teaser.variations = [ ...config.blocks.blocksConfig.teaser.variations, - { - id: 'image-top-variation', - title: 'Image(Top) variation', - template: TeaserBlockImageVariation, - }, - ], + { + id: 'image-top-variation', + title: 'Image(Top) variation', + template: TeaserBlockImageVariation, + }, + ] + return config; +} + +export default applyConfig; ``` We should create this view template in our `components/TeaserBlockImageVariation.jsx` @@ -160,7 +174,10 @@ TeaserBlockImageDefault.propTypes = { export default TeaserBlockImageDefault; ``` -After this you will be able to choose variations for this block from the Blocks Settings sidebar. Right now this variation only shows default variation of Teaser block. In the coming chapter we are gonna enhance it with extension per teaser. +After this you will be able to choose variations for this block from the Blocks Settings sidebar. +Right now this variation only shows default variation of Teaser block. +You could decide to modify the template here already though. +In the coming chapter we are gonna enhance this variation with extension per teaser. ```{note} The [Body](https://github.com/plone/volto/blob/9667cf735e5c3e848de852d615941d98193e0a5e/src/components/manage/Blocks/Teaser/Body.jsx#L13) component in Teaser block also supports adding variations from component registry. You can read more about component registry in following chapters. From 01d8ce6bfb8e90941ab5caeedbec87f167eed028 Mon Sep 17 00:00:00 2001 From: nileshgulia1 Date: Fri, 29 Sep 2023 21:40:57 +0530 Subject: [PATCH 30/32] adapt to use volto 17 --- docs/volto_customization/extending_teasers.md | 43 +++++++++++-------- docs/volto_customization/listing_block.md | 16 ------- docs/volto_customization/schema.md | 13 +++--- docs/volto_customization/teaser_variations.md | 17 ++++---- 4 files changed, 42 insertions(+), 47 deletions(-) diff --git a/docs/volto_customization/extending_teasers.md b/docs/volto_customization/extending_teasers.md index 89a2cfc92..86478c4d2 100644 --- a/docs/volto_customization/extending_teasers.md +++ b/docs/volto_customization/extending_teasers.md @@ -166,7 +166,6 @@ import { defineMessages, useIntl } from "react-intl"; import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; -import { getTeaserImageURL } from "@plone/volto/components/manage/Blocks/Teaser/utils"; import { MaybeWrap } from "@plone/volto/components"; import { formatDate } from "@plone/volto/helpers/Utils/Date"; import { UniversalLink } from "@plone/volto/components"; @@ -201,11 +200,8 @@ const TeaserBlockImageDefault = (props) => { locale: locale, }); - const hasImageComponent = config.getComponent("Image").component; const Image = config.getComponent("Image").component || DefaultImage; const { openExternalLinkInNewTab } = config.settings; - const defaultImageSrc = - href && flattenToAppURL(getTeaserImageURL({ href, image, align })); return (
@@ -234,9 +230,16 @@ const TeaserBlockImageDefault = (props) => { {(href.hasPreviewImage || href.image_field || image) && (
)} @@ -276,7 +279,6 @@ import { defineMessages, useIntl } from "react-intl"; import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; -import { getTeaserImageURL } from "@plone/volto/components/manage/Blocks/Teaser/utils"; import { MaybeWrap } from "@plone/volto/components"; import { formatDate } from "@plone/volto/helpers/Utils/Date"; import { UniversalLink } from "@plone/volto/components"; @@ -311,11 +313,8 @@ const TeaserBlockImageRight = (props) => { locale: locale, }); - const hasImageComponent = config.getComponent("Image").component; const Image = config.getComponent("Image").component || DefaultImage; const { openExternalLinkInNewTab } = config.settings; - const defaultImageSrc = - href && flattenToAppURL(getTeaserImageURL({ href, image, align })); return (
@@ -351,10 +350,17 @@ const TeaserBlockImageRight = (props) => {
{(href.hasPreviewImage || href.image_field || image) && (
-
)} @@ -385,7 +391,6 @@ import { defineMessages, useIntl } from "react-intl"; import cloneDeep from "lodash/cloneDeep"; import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; -import { getTeaserImageURL } from "@plone/volto/components/manage/Blocks/Teaser/utils"; import { MaybeWrap } from "@plone/volto/components"; import { formatDate } from "@plone/volto/helpers/Utils/Date"; import { UniversalLink } from "@plone/volto/components"; @@ -434,11 +439,8 @@ const TeaserBlockImageOverlay = (props) => { intl, }); - const hasImageComponent = config.getComponent("Image").component; const Image = config.getComponent("Image").component || DefaultImage; const { openExternalLinkInNewTab } = config.settings; - const defaultImageSrc = - href && flattenToAppURL(getTeaserImageURL({ href, image, align })); return (
@@ -466,10 +468,17 @@ const TeaserBlockImageOverlay = (props) => {
{(href.hasPreviewImage || href.image_field || image) && (
-
)} diff --git a/docs/volto_customization/listing_block.md b/docs/volto_customization/listing_block.md index 01dee6ab4..f95c4c9f5 100644 --- a/docs/volto_customization/listing_block.md +++ b/docs/volto_customization/listing_block.md @@ -227,20 +227,4 @@ ListingVariation.propTypes = { export default ListingVariation; ``` -You might want to modify rendering of the images a bit in all the teaser block extensions in the `extensions/` folder. - -Thus, locate the Image component in `TeaserBlockImageDefault` and replace it with: - -```jsx - -``` - We will now have the per listing item styling support like we have for teaser blocks. We can also add more styling schema with the help of its individual schema extenders. diff --git a/docs/volto_customization/schema.md b/docs/volto_customization/schema.md index cb04fdbd2..09f681d8b 100644 --- a/docs/volto_customization/schema.md +++ b/docs/volto_customization/schema.md @@ -88,7 +88,6 @@ import { defineMessages, useIntl } from "react-intl"; import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; -import { getTeaserImageURL } from "@plone/volto/components/manage/Blocks/Teaser/utils"; import { MaybeWrap } from "@plone/volto/components"; import { formatDate } from "@plone/volto/helpers/Utils/Date"; import { UniversalLink } from "@plone/volto/components"; @@ -113,11 +112,8 @@ const TeaserBlockImageDefault = (props) => { const image = data.preview_image?.[0]; const align = data?.styles?.align; - const hasImageComponent = config.getComponent("Image").component; const Image = config.getComponent("Image").component || DefaultImage; const { openExternalLinkInNewTab } = config.settings; - const defaultImageSrc = - href && flattenToAppURL(getTeaserImageURL({ href, image, align })); return (
@@ -146,9 +142,16 @@ const TeaserBlockImageDefault = (props) => { {(href.hasPreviewImage || href.image_field || image) && (
)} diff --git a/docs/volto_customization/teaser_variations.md b/docs/volto_customization/teaser_variations.md index 0d259c2fc..9c7d6ff78 100644 --- a/docs/volto_customization/teaser_variations.md +++ b/docs/volto_customization/teaser_variations.md @@ -72,7 +72,6 @@ import { Message } from 'semantic-ui-react'; import { defineMessages, useIntl } from 'react-intl'; import imageBlockSVG from '@plone/volto/components/manage/Blocks/Image/block-image.svg'; import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers'; -import { getTeaserImageURL } from '@plone/volto/components/manage/Blocks/Teaser/utils'; import { MaybeWrap } from '@plone/volto/components'; import { formatDate } from '@plone/volto/helpers/Utils/Date'; import { UniversalLink } from '@plone/volto/components'; @@ -107,11 +106,9 @@ const TeaserBlockImageDefault = (props) => { locale: locale, }); - const hasImageComponent = config.getComponent('Image').component; const Image = config.getComponent('Image').component || DefaultImage; const { openExternalLinkInNewTab } = config.settings; - const defaultImageSrc = - href && flattenToAppURL(getTeaserImageURL({ href, image, align })); + return (
@@ -139,15 +136,17 @@ const TeaserBlockImageDefault = (props) => {
{(href.hasPreviewImage || href.image_field || image) && (
-
)} From c41ec1f591f58650e479307c2dbc075fbe0e7090 Mon Sep 17 00:00:00 2001 From: nileshgulia1 Date: Fri, 29 Sep 2023 22:10:44 +0530 Subject: [PATCH 31/32] fix typo --- docs/volto_customization/data_adapters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/volto_customization/data_adapters.md b/docs/volto_customization/data_adapters.md index 581100fbc..ae06cbff7 100644 --- a/docs/volto_customization/data_adapters.md +++ b/docs/volto_customization/data_adapters.md @@ -77,7 +77,7 @@ The above Adapter gets consumed in [Data](https://github.com/plone/volto/blob/96 Let's register a new `dataAdapter` our config: ```{code-block} js -import {myOwnDataAdapter} from 'volto-teaser-tuturial/components/data-adapter'; +import {myOwnDataAdapter} from 'volto-teaser-tutorial/components/data-adapter'; config.blocks.blocksConfig.teaser.dataAdapter = myOwnDataAdapter; ``` From 8b779c2670f8b9d8c736dcfb396fc64ba3b1bc8f Mon Sep 17 00:00:00 2001 From: nileshgulia1 Date: Fri, 29 Sep 2023 22:26:30 +0530 Subject: [PATCH 32/32] fix missing import --- docs/volto_customization/extending_teasers.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/volto_customization/extending_teasers.md b/docs/volto_customization/extending_teasers.md index 86478c4d2..e1d29efc5 100644 --- a/docs/volto_customization/extending_teasers.md +++ b/docs/volto_customization/extending_teasers.md @@ -165,7 +165,11 @@ import { defineMessages, useIntl } from "react-intl"; import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; -import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; +import { + flattenToAppURL, + isInternalURL, + addAppURL, +} from "@plone/volto/helpers"; import { MaybeWrap } from "@plone/volto/components"; import { formatDate } from "@plone/volto/helpers/Utils/Date"; import { UniversalLink } from "@plone/volto/components"; @@ -278,7 +282,7 @@ import { defineMessages, useIntl } from "react-intl"; import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; -import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; +import { flattenToAppURL, isInternalURL, addAppURL } from "@plone/volto/helpers"; import { MaybeWrap } from "@plone/volto/components"; import { formatDate } from "@plone/volto/helpers/Utils/Date"; import { UniversalLink } from "@plone/volto/components"; @@ -390,7 +394,7 @@ import { Message } from "semantic-ui-react"; import { defineMessages, useIntl } from "react-intl"; import cloneDeep from "lodash/cloneDeep"; import imageBlockSVG from "@plone/volto/components/manage/Blocks/Image/block-image.svg"; -import { flattenToAppURL, isInternalURL } from "@plone/volto/helpers"; +import { flattenToAppURL, isInternalURL, addAppURL } from "@plone/volto/helpers"; import { MaybeWrap } from "@plone/volto/components"; import { formatDate } from "@plone/volto/helpers/Utils/Date"; import { UniversalLink } from "@plone/volto/components";