plone / volto

React-based frontend for the Plone Content Management System
https://demo.plone.org/
MIT License
448 stars 610 forks source link

Slots in Volto #1430

Closed sneridagh closed 6 months ago

sneridagh commented 4 years ago

We need to increase the "insertion points" in Volto by using something close to Plone Viewlets/Portlets/Macros. I would run from these names, and go for something more generic and not Plone-ish, to avoid confusion. I suggest to use "slots".

Macros-ish: https://github.com/plone/volto/pull/1424

Viewlet-ish: https://github.com/eea/volto-addons/tree/master/src/Viewlets

Portlet-ish?

We need to find time to discuss this.

sneridagh commented 4 years ago

https://github.com/plone/volto/issues/1397

tiberiuichim commented 4 years ago

I like "Slots".

I think portlets are a different story and, for their use case, they're unavoidable. They have database storage, can be configured TTW and they have inheritance. Whatever system would be created to replace them would just reimplement portlet storage and definitions.

Let's take a simple use case: the website editor wants to add a static text notification in a section of a website. Right now, in classic Plone, all he has to do is create a new Static Text portlet and it will be inherited in that section (subfolders, etc). There's no way to have this in Volto right now.

The implementation I had in mind for the so-called "viewlets" was that they would allow a centralized place to register <Portal> components. Nicola's proposal requires to customize (jbot style) the macro file, while my sketched proposal was to say "just declare what Portal nodes you want on a particular route, and I'll render them for you". If I were to extend my implementation, the configuration for the Slots would look something like this:

 config.slots = {
     aboveDocumentTitle: [
         { path: '/', component: ForestMetadata }
     ]
}

And then, in the appropriate places, a component would be inserted like:

<SlotRenderer name="aboveDocumentTitle" />

An addon would add a new slot insertion such as:

config.slots.aboveDocumentTitle.push({path:'/', component: ExtraComponent})
sneridagh commented 4 years ago

aboveDocumentTitle oh man, are we doing this again, isn't it? 😀 I like it.

@nzambello I implemented <AppExtras /> component to support whatever you want to put before the body is closed (GAnalytics, Matomo, etc...) Shadowing that would allow integrators to put whatever in that component. But if we want to go further (so we want to allow the addons system to use that "slot" and append things there, more than overriding them) we will be on the right track.

However, I would like to discuss this in depth because I still see some use cases, where a simple solution might be ok. Let's schedule a meeting to talk about this!

Regarding portlets I like to see them more like Viewlets that can be configured and the config stored. When one say Viewlets, one can say blocks :) I fiddled around with the concept, and works pretty well, I even created a BlocksRenderer wrapper to be able to instantiate blocks anywhere in the site. The only thing is to know where the info is going to be stored.

tiberiuichim commented 4 years ago

aboveDocumentTitle

I've mentioned it because it's the only viewlet that I can name by heart, and even then I don't think I got the name right.

Let's take a simple use case: I have a behavior called IExtendedMetadata whatever. It has several tagging and metadata fields that are used for to group and semantically decorate content. I can enable this behavior on several content types, including some that are block-powered. Next, I want a box with this metadata to appear on all pages that have these fields. Sure, I can shadow DefaultView.jsx and insert my component there, but that means that I will have to maintain that customized file. I can mostly achieve the same using Portals, but I still need a way to trigger the rendering of these Portal components and conditionally rendering portals is tricky.

sneridagh commented 4 years ago

@tiberiuichim I like the idea and the implementation! Implementations change over time, but good ideas/concepts don’t. So I’m +1 to bring the slots conceptualization in the same way of Plone Viewlets.

tiberiuichim commented 4 years ago

There's also old https://github.com/plone/volto/issues/16 which suggests looking at react-fill-slots. I've looked at it, it's an old library by now and I think outdated by today's standards. I also don't think there's a need for it if we use the system described above.

sneridagh commented 3 years ago

Had a rethought about it and a conversation with @tiberiuichim I'll try to summarize what we spoke about:

I see slots more than an evolution of the portlet paradigm, but a merge between Viewlets Managers and Portlets Managers, all at once. The slots could not only contain user parameterizable (persistent config and data) components (mainly blocks) but also static context aware components (aka viewlets) assigned to a place (slot) in the layout. Inheritance/block/per content type/group are still valid and valuable use cases. The ability to pre-define the slots per content type (like the new Volto blocks layout per content type feature) is also a nice to have. Some portlet use case are still capital i.e. navigation portlet.

The portlet engine can still be the foundation of the slots, even in the most simple form (create a portlet that can hold JSON to store the slot blocks.

Example: Doormat We would like to have an user customizable Doormat (footer slot) that contains columns with Blocks (text, images or any other block). These blocks would need to be saved somewhere and be inherited to all the content tree.

Example: Typical aside portlets slots We would like an user to be able to add and arrange blocks side by side to the content, in a vertical fashion. We should also be able to add a navigation "portlet". From where they are set, they are inherited to children objects.

(add more examples here)

To improve and avoid the shadowing hell we could also make the most of the basic Volto "Viwelets" to have a viewlet manager where you can add or remove components:

Example: App.jsx One end up by overriding App.jsx for adding components in the layout. We should avoid that by using more specific organization (Footer, TopHeader, etc) then add/remove things from there via slots definitions.

tiberiuichim commented 3 years ago

Further discussions:

perret123 commented 1 year ago

I would like to be able to add "Slots" only to specific Views which are bound to specific Content Types.

I think it would be quite nice if I could do something like the following in a View-File:

  <div id="page-document" className="ui container viewwrapper eduproduct-view">
       <div class="ui two grid">
          <div class="column left" style={{ flex: '1' }}>
             <RenderBlocks content={content} slotKey="mainContent"  />
           </div>
           <div class="column right" style={{ flex: '0 0 100px' }}>
              <RenderBlocks content={content} slotKey="sidebar"  />
           </div>
       </div>
   </div>

In this example, in the Editing-UI, the content editors could use two "lanes" of blocks instead of only one.

What do you think about this?

Probably it would also be nice to restrict the use of block-types for different "slot-keys".

If this is already somehow possible with Volto and I just missed it, please advice :-) Thank you :)

davisagli commented 6 months ago

Done in #5775