Custom pages

Contents

Hardcoded content is nice, but letting the editor create content is even better!

This is where the real power of React4XP comes into play, we can easily make a page component which allows the editor to drag and drop components into the page!

Task: Set up page rendering

Content types need to exist in Enonic before an editor can create content. Similarly, page components must be defined before Content Studio can enable editors to create pages.

  1. Add a page component to the app:

    /src/main/resources/react4xp/components/page/Page.tsx
    import {Regions,} from '@enonic/react-components';
    import React from 'react'
    import {componentRegistry} from '../../componentRegistry';
    import styles from './Page.module.css';
    
    export const Page = (props: any) => {
        const page = props.page;
        if (!page.regions || !Object.keys(page.regions).length) {
            page.regions = {
                main: {
                    name: 'main',
                    components: [],
                }
            }
        }
        const regionsProps = {componentRegistry, regions: page.regions}
        return (
            <div className={styles.page}>
                {props.parent && (
                    <div className={"back"}>
                        <a href={props.parent}>
                            <p>Back</p>
                        </a>
                    </div>
                )}
                <Regions {...regionsProps} />
            </div>
        );
    };
  2. Add a page processor to the app:

    /src/main/resources/react4xp/components/page/PageProcessor.ts
    import {getSite, pageUrl} from '/lib/xp/portal';
    import {parentPath} from '/react4xp/utils/path';
    import {PageComponent} from "@enonic-types/core";
    import type {ComponentProcessorFunction} from '@enonic-types/lib-react4xp/DataFetcher';
    
    export const pageProcessor: ComponentProcessorFunction<'com.enonic.app.hmdb:main'> = (props) => {
        const component = props.component as PageComponent;
        const regions = component?.regions || {};
        const site = getSite();
    
        const baseUrl = pageUrl({path: site._path});
        const parentSegment = parentPath(props.request.path);
        const parentBaseSegment = parentPath(baseUrl);
    
        // always define parent, but only keep it if it truly differs
        const parent = parentSegment !== parentBaseSegment
                       ? parentSegment
                       : undefined;
    
        return {
            page: {
                type: 'page',
                path: '/',
                config: component.config || {},
                descriptor: 'com.enonic.app.hmdb:main',
                regions
            },
            parent
    
        };
    };
  3. Style the page component:

    /src/main/resources/react4xp/components/page/Page.module.css
    .page {
      padding-bottom: 0;
      margin-bottom: 0;
      display: flow-root;
    }
  4. Fetch the data:

    /src/main/resources/react4xp/dataFetcher.ts
    import {DataFetcher} from '/lib/enonic/react4xp';
    //import {helloProcessor} from './components/hello/HelloProcessor';
    import {personProcessor} from './components/content/PersonProcessor';
    import {pageProcessor} from './components/page/PageProcessor';
    
    export const dataFetcher = new DataFetcher();
    
    //dataFetcher.addContentType('portal:site', {processor: helloProcessor});
    dataFetcher.addContentType('com.enonic.app.hmdb:person', {processor: personProcessor});
    dataFetcher.addPage('com.enonic.app.hmdb:main', {processor: pageProcessor});
  5. Register the page component in the component registry(and remove the old hello component):

    /src/main/resources/componentRegistry.tsx
    //import {Hello} from './components/hello/Hello';
    import {Factbox} from '/react4xp/components/macro/FactBox';
    import {Page} from '/react4xp/components/page/Page';
    import {ComponentRegistry} from '@enonic/react-components';
    import {Person} from './components/content/Person';
    
    export const componentRegistry = new ComponentRegistry();
    
    //componentRegistry.addContentType('portal:site', {View: Hello});
    componentRegistry.addContentType('com.enonic.app.hmdb:person', {View: Person});
    componentRegistry.addMacro('factbox', {View: Factbox});
    componentRegistry.addPage('com.enonic.app.hmdb:main', {View: Page});

Now you can create pages!

Task: Create your first page!

It is time to build a custom page.

  1. Turn the landing-site into a page

    Before we can continue we need to remove the hello component from the componentRegistry and dataFetcher.

    From Content Studio, select and edit the /hmdb content item. From the edit view, activate the page editor by clicking the monitor icon in the top right corner.

    You should now see the following: empty site

    Now that we have a page component with a single "dropzone" inside (the region we specified earlier). We can give it some content.

Use the text component

Content Studio ships with a built-in Text component which can be handy when composing pages.

  1. From the Insert tab (on the right hand side), drag a Text component into the region.

  2. Text mode will now be activated, and you can use the rich-text editor to write and format text, but also insert images.

    entry site complete

  3. You may also click the Preview button in Content Studio for a full screen version.

That concludes the introduction to page rendering, coming up we’ll add some configurable page components to play with using parts.


Contents

Contents

AI-powered search

Juke AI