Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
12 changes: 12 additions & 0 deletions code_samples/back_office/subitems/render_subitems.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const containerNode = document.querySelector('#sub-items-container');

ReactDOM.render(
React.createElement(ibexa.modules.SubItems, {
parentLocationId: { Number },
restInfo: {
token: { String },
siteaccess: { String },
},
}),
containerNode,
);
9 changes: 9 additions & 0 deletions code_samples/back_office/subitems/render_subitems.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const attrs = {
parentLocationId: {Number},
restInfo: {
token: {String},
siteaccess: {String}
}
};

<SubItemsModule {...attrs}/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import TimelineViewComponent from './timeline.view.component.js';
import { registerView } from '@ibexa-admin-ui-modules/sub-items/services/view.registry';

// Use the existing constants to replace a view
import { VIEW_MODE_GRID, VIEW_MODE_TABLE } from '@ibexa-admin-ui-modules/sub-items/constants';

registerView('timeline', {
component: TimelineViewComponent,
iconName: 'timeline',
label: 'Timeline view',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import PropTypes from 'prop-types';
import TimelineViewItemComponent from './timeline.view.item.component';

const TimelineViewComponent = ({ items, generateLink }) => {
const groupByDate = (items) => {
return items.reduce((groups, item) => {
const date = new Date(item.content._info.modificationDate.timestamp * 1000);
const dateKey = date.toISOString().split('T')[0];

if (!groups[dateKey]) {
groups[dateKey] = [];
}

groups[dateKey].push(item);
return groups;
}, {});
};

const groupedItems = groupByDate(items);

return (
<div className="app-timeline-view">
{Object.entries(groupedItems).map(([date, dateItems]) => (
<div key={date} className="app-timeline-view__group">
<div className="app-timeline-view__date">
<div className="app-timeline-view__date-marker" />
<h3>{new Date(date).toLocaleDateString()}</h3>
</div>
<div className="app-timeline-view__items">
{dateItems.map((item) => (
<TimelineViewItemComponent key={item.id} item={item} generateLink={generateLink} />
))}
</div>
</div>
))}
</div>
);
};

TimelineViewComponent.propTypes = {
items: PropTypes.array.isRequired,
generateLink: PropTypes.func.isRequired,
};

export default TimelineViewComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import PropTypes from 'prop-types';
import Icon from '@ibexa-admin-ui-modules/common/icon/icon';

const { ibexa } = window;

const TimelineViewItemComponent = ({ item, generateLink }) => {
const { content } = item;
const contentTypeIdentifier = content._info.contentType.identifier;
const contentTypeIconUrl = ibexa.helpers.contentType.getContentTypeIconUrl(contentTypeIdentifier);
const time = new Date(content._info.modificationDate.timestamp * 1000).toLocaleTimeString();

return (
<a className="app-timeline-view-item" href={generateLink(item.id, content._info.id)}>
<div className="app-timeline-view-item__time">{time}</div>
<div className="app-timeline-view-item__content">
<div className="app-timeline-view-item__info">
<div className="app-timeline-view-item__name">{content._name}</div>
<div className="app-timeline-view-item__type">
<Icon customPath={contentTypeIconUrl} extraClasses="ibexa-icon--small" />
<span className="app-timeline-view-item__type-name">{content._info.contentType.name}</span>
</div>
</div>
</div>
</a>
);
};

TimelineViewItemComponent.propTypes = {
item: PropTypes.object.isRequired,
generateLink: PropTypes.func.isRequired,
};

export default TimelineViewItemComponent;
84 changes: 84 additions & 0 deletions code_samples/back_office/subitems/timeline_view/timeline.view.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
@use '@ibexa-admin-ui/src/bundle/Resources/public/scss/custom.scss' as *;

.app-timeline-view {
padding: calculateRem(16px);

&__group {
position: relative;
margin-bottom: calculateRem(32px);
}

&__date {
display: flex;
align-items: center;
margin-bottom: calculateRem(16px);

h3 {
margin: 0;
font-size: $ibexa-text-font-size-large;
color: $ibexa-color-dark;
}
}

&__date-marker {
width: calculateRem(12px);
height: calculateRem(12px);
border-radius: 50%;
background: $ibexa-color-primary;
margin-right: calculateRem(16px);
}

&__items {
margin-left: calculateRem(6px);
padding-left: calculateRem(32px);
border-left: calculateRem(2px) solid $ibexa-color-light;
}
}

.app-timeline-view-item {
display: flex;
align-items: flex-start;
padding: calculateRem(16px);
margin-bottom: calculateRem(8px);
text-decoration: none;
color: inherit;
background: $ibexa-color-light-300;
border-radius: $ibexa-border-radius;
transition: background-color 0.2s $ibexa-admin-transition;

&:hover {
background: $ibexa-color-light-400;
}

&__time {
color: $ibexa-color-dark-400;
margin-right: calculateRem(16px);
min-width: calculateRem(80px);
}

&__content {
display: flex;
align-items: center;
}

&__icon {
margin-right: calculateRem(16px);
}

&__name {
font-weight: $ibexa-font-weight-bold;
margin-bottom: calculateRem(4px);
}

&__type {
font-size: $ibexa-text-font-size-small;
color: $ibexa-color-dark-400;
display: flex;
align-items: center;
gap: calculateRem(8px);
}

&__type-name {
line-height: calculateRem(16px);
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
93 changes: 69 additions & 24 deletions docs/administration/back_office/subitems_list.md
Original file line number Diff line number Diff line change
@@ -1,47 +1,92 @@
---
description: Inject a sub-items list into your back office customizations.
description: Inject a sub-items list into your back office customizations or customize the view.
---

# Sub-items list

The Sub-items List module is meant to be used as a part of the editorial interface of [[= product_name =]].
It provides an interface for listing the sub-items of any location.

!!! caution
## Create custom sub-items list view

You can extend the Sub-items List module to replace an existing view or add your own.

Check warning on line 12 in docs/administration/back_office/subitems_list.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/administration/back_office/subitems_list.md#L12

[Ibexa.EOLWhitespace] Remove whitespace characters from the end of the line.
Raw output
{"message": "[Ibexa.EOLWhitespace] Remove whitespace characters from the end of the line.", "location": {"path": "docs/administration/back_office/subitems_list.md", "range": {"start": {"line": 12, "column": 86}}}, "severity": "WARNING"}
The example below adds a new timeline view to highlight the modification date.

![Sub-items List module using the new Timeline view](img/subitems/timeline_view.png "Sub-items List module using the new Timeline view")

To recreate it, start by creating the components responsible for rendering the new view.
You can create two files:

- `assets/js/timeline.view.component.js` responsible for rendering the whole view

``` js
[[= include_file('code_samples/back_office/subitems/timeline_view/timeline.view.component.js') =]]
```

- `assets/js/timeline.view.item.component.js` responsible for rendering a single item

``` js
[[= include_file('code_samples/back_office/subitems/timeline_view/timeline.view.item.component.js') =]]
```

Provide the necessary styling in `assets/scss/timeline.view.scss`. The example below uses [[= product_name =]]'s SCSS variables for consistency with the rest of the back office interface.

``` scss
[[= include_file('code_samples/back_office/subitems/timeline_view/timeline.view.scss') =]]
```

The last step is adding the view module to the list of available views in the system, by using the provided `registerView` function.

You can create a new view by providing an unique identifier, or replace an existing one by reusing its identifier.
The existing view identifiers are defined as JavaScript constants in the `@ibexa-admin-ui-modules/sub-items/constants` module:

- Grid view: `VIEW_MODE_GRID` constant
- Table view: `VIEW_MODE_TABLE` constant

Create a file called `assets/js/registerTimelineView.js`:

``` js
[[= include_file('code_samples/back_office/subitems/timeline_view/registerTimelineView.js') =]]
```

And include it into the back office using Webpack Encore, together with your custom styles.
See [configuring assets from main project files](importing_assets_from_bundle.md#configuration-from-main-project-files) to learn more about this mechanism.

``` js
ibexaConfigManager.add({
ibexaConfig,
entryName: 'ibexa-admin-ui-layout-js',
newItems: [
path.resolve(__dirname, './assets/js/registerTimelineView.js')
],
});

ibexaConfigManager.add({
ibexaConfig,
entryName: 'ibexa-admin-ui-layout-css',
newItems: [
path.resolve(__dirname, './assets/scss/timeline.view.scss'),
],
});
```

If you want to load the Sub-items module, you need to load the JS code for it in your view, as it's not available by default.

## Use sub-items list

!!! caution

If you want to load the Sub-items module from your custom code, you need to load the JS code for it in your view, as it's not available by default.

With plain JS:

``` js
const containerNode = document.querySelector('#sub-items-container');

ReactDOM.render(
React.createElement(ibexa.modules.SubItems, {
parentLocationId: { Number },
restInfo: {
token: { String },
siteaccess: { String }
}
}),
containerNode
);
[[= include_file('code_samples/back_office/subitems/render_subitems.js') =]]
```

With JSX:

``` jsx
const attrs = {
parentLocationId: {Number},
restInfo: {
token: {String},
siteaccess: {String}
}
};

<SubItemsModule {...attrs}/>
[[= include_file('code_samples/back_office/subitems/render_subitems.jsx') =]]
```

## Properties list
Expand Down
Loading