Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions docs/how-to-guides/customize-related-items.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
myst:
html_meta:
"description": "How to hide or replace the related items list shown below content in Plone Aurora"
"property=og:description": "How to hide or replace the related items list shown below content in Plone Aurora"
"property=og:title": "Customize the related items"
"keywords": "Plone Aurora, related items, slot, belowContent"
---

# Customize the related items

Plone Aurora renders a content item's related items below the content as links.
The list comes from a slot component registered for the `belowContent` slot.
This guide shows you how to hide or replace it.

## Hide the related items

Set `showRelatedItems` to `false` in your add-on configuration to hide the list on every page.

```ts
import type { ConfigType } from '@plone/registry';

export default function install(config: ConfigType) {
config.settings.showRelatedItems = false;
return config;
}
```

The slot renders the list whenever an item has `relatedItems`, unless `showRelatedItems` is `false`.

## Replace the related items component

Register your own component for the `belowContent` slot under the same name to override the default.

```ts
import type { ConfigType } from '@plone/registry';
import MyRelatedItems from './MyRelatedItems';

export default function install(config: ConfigType) {
config.registerSlotComponent({
name: 'RelatedItems',
slot: 'belowContent',
component: MyRelatedItems,
});
return config;
}
```

Your component receives the slot props, including `content`, from which you can read `content.relatedItems`.
To learn how slots work in general, refer to {doc}`register-slots`.
1 change: 1 addition & 0 deletions docs/how-to-guides/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ icons
configure-plate-code-block-languages
bind-metadata-fields-to-plate-text-blocks
custom-content-types
customize-related-items
```
8 changes: 8 additions & 0 deletions packages/layout/config/slots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import HeaderTools from '../slots/Tools';
import ContentArea from '../slots/ContentArea';
import MainFooter from '../slots/MainFooter/MainFooter';
import Breadcrumbs from '../slots/Breadcrumbs';
import RelatedItems from '../slots/RelatedItems/RelatedItems';
import { NotContentTypeCondition } from '../helpers';

export default function install(config: ConfigType) {
Expand Down Expand Up @@ -83,5 +84,12 @@ export default function install(config: ConfigType) {
component: MainFooter,
});

// Related Items
config.registerSlotComponent({
name: 'RelatedItems',
slot: 'belowContent',
component: RelatedItems,
});

return config;
}
3 changes: 3 additions & 0 deletions packages/layout/locales/de/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
"toolbar": {
"label": "Werkzeugleiste"
},
"relatedItems": {
"label": "Verwandte Inhalte"
},
"views": {
"link": {
"linkLabel": "Die Linkadresse lautet:",
Expand Down
3 changes: 3 additions & 0 deletions packages/layout/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
"toolbar": {
"label": "Toolbar"
},
"relatedItems": {
"label": "Related items"
},
"views": {
"link": {
"linkLabel": "The link address is:",
Expand Down
3 changes: 3 additions & 0 deletions packages/layout/locales/it/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
"toolbar": {
"label": "Barra degli strumenti"
},
"relatedItems": {
"label": "Contenuti correlati"
},
"views": {
"link": {
"linkLabel": "L'indirizzo del link è:",
Expand Down
1 change: 1 addition & 0 deletions packages/layout/news/64.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a Related Items slot that renders a content item's related items as links below the content. @Cabonie
10 changes: 10 additions & 0 deletions packages/layout/slots/RelatedItems/RelatedItems.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@layer custom {
.relatedItems {
display: flex;
flex-direction: column;
padding: 0;
margin-top: 24px;
gap: 8px;
list-style: none;
}
}
40 changes: 40 additions & 0 deletions packages/layout/slots/RelatedItems/RelatedItems.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router';
import { RouterProvider } from 'react-aria-components';
import RelatedItems from './RelatedItems';

type Item = { '@id': string; title: string };

const renderRelatedItems = (relatedItems: Item[]) =>
render(
<MemoryRouter>
<RouterProvider navigate={() => undefined}>
<RelatedItems
content={{ relatedItems } as never}
location={{ pathname: '/' } as never}
/>
</RouterProvider>
</MemoryRouter>,
);

describe('RelatedItems slot', () => {
it('renders nothing when there are no related items', () => {
const { container } = renderRelatedItems([]);
expect(container).toBeEmptyDOMElement();
});

it('renders a link for each related item', () => {
renderRelatedItems([
{ '@id': '/news/one', title: 'News One' },
{ '@id': '/events/two', title: 'Event Two' },
]);
expect(screen.getByRole('link', { name: 'News One' })).toHaveAttribute(
'href',
'/news/one',
);
expect(screen.getByRole('link', { name: 'Event Two' })).toHaveAttribute(
'href',
'/events/two',
);
});
});
34 changes: 34 additions & 0 deletions packages/layout/slots/RelatedItems/RelatedItems.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useTranslation } from 'react-i18next';
import { Link } from '@plone/components';
import config from '@plone/registry';
import type { SlotComponentProps } from '../SlotRenderer';
import SectionWrapper from '../../components/SectionWrapper/SectionWrapper';
import styles from './RelatedItems.module.css';

const RelatedItems = (props: SlotComponentProps) => {
const { t } = useTranslation();
const items = props.content.relatedItems ?? [];

const showRelatedItems = config.settings.showRelatedItems !== false;
if (!showRelatedItems || items.length === 0) {
return null;
}

return (
<SectionWrapper
as="nav"
width="layout"
aria-label={t('layout.relatedItems.label')}
>
<ul className={styles.relatedItems}>
{items.map((item) => (
<li key={item['@id']}>
<Link href={item['@id']}>{item.title}</Link>
</li>
))}
</ul>
</SectionWrapper>
);
};

export default RelatedItems;
Loading