Skip to content

Scroller mode and full width for teaser lists #2242

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
de:
pageflow:
teaser_list_scroller:
feature_name: "Teaser List Scroller"
pageflow_scrolled:
editor:
aspect_ratios:
Expand All @@ -13,6 +16,11 @@ de:
content_elements:
externalLinkList:
attributes:
enableScroller:
label: "Layout-Verhalten"
values:
never: "In mehrere Zeilen umbrechen"
always: "Horizontal scrollen"
thumbnailAspectRatio:
label: "Thumbnail Seitenverhältnis"
inline_help: |-
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
en:
pageflow:
teaser_list_scroller:
feature_name: "Teaser List Scroller"
pageflow_scrolled:
editor:
aspect_ratios:
Expand All @@ -13,6 +16,11 @@ en:
content_elements:
externalLinkList:
attributes:
enableScroller:
label: "Layout behavior"
values:
never: "Wrap into multiple lines"
always: "Scroll horizontally"
thumbnailAspectRatio:
label: "Thumbnail aspect ratio"
inline_help: |-
Expand Down
1 change: 1 addition & 0 deletions entry_types/scrolled/lib/pageflow_scrolled/plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def configure(config)
c.features.register('custom_palette_colors')
c.features.register('decoration_effects')
c.features.register('backdrop_size')
c.features.register('teaser_list_scroller')

c.additional_frontend_seed_data.register(
'frontendVersion',
Expand Down
44 changes: 44 additions & 0 deletions entry_types/scrolled/package/spec/frontend/Layout-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ describe('Layout', () => {
}
});

frontend.contentElementTypes.register('probeWithCustomMarginFunction', {
customMargin({configuration}) { return configuration.useCustomMargin; },

component: function Probe({contentElementId}) {
return (
<div>{contentElementId} </div>
);
}
});

frontend.contentElementTypes.register('probeWithCustomMarginProp', {
customMargin: true,

Expand Down Expand Up @@ -144,6 +154,23 @@ describe('Layout', () => {
expect(container.textContent).toEqual('[inline normal 1 inline custom 2 inline normal 3 ]');
});

it('supports function for custom margin option', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
{id: 2, type: 'probeWithCustomMarginFunction', position: 'inline', props: {useCustomMargin: true}},
{id: 3, type: 'probeWithCustomMarginFunction', position: 'inline', props: {useCustomMargin: false}}
];
const {container} = renderInEntry(
<Layout sectionProps={{layout: 'left'}} items={items}>
{(children, {position, customMargin}) =>
<div>{position} {customMargin ? 'custom' : 'normal'} {children}</div>
}
</Layout>
);

expect(container.textContent).toEqual('[inline normal 1 inline custom 2 inline normal 3 ]');
});

it('places side elements with and without custom margin in separate groups', () => {
const items = [
{id: 1, type: 'probe', position: 'side'},
Expand Down Expand Up @@ -699,6 +726,23 @@ describe('Layout', () => {
expect(container.textContent).toEqual('normal 1 custom 2 normal 3 ');
});

it('supports function for custom margin option', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
{id: 2, type: 'probeWithCustomMarginFunction', position: 'inline', props: {useCustomMargin: true}},
{id: 3, type: 'probeWithCustomMarginFunction', position: 'inline', props: {useCustomMargin: false}}
];
const {container} = renderInEntry(
<Layout sectionProps={{layout: 'center'}} items={items}>
{(children, {customMargin}) =>
<div>{customMargin ? 'custom' : 'normal'} {children}</div>
}
</Layout>
);

expect(container.textContent).toEqual('normal 1 custom 2 normal 3 ');
});

describe('customMargin prop passed to content element', () => {
it('is true if rendered inline with custom margin', () => {
const items = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {editor} from 'pageflow-scrolled/editor';
import {features} from 'pageflow/frontend';
import {SelectInputView, SliderInputView, SeparatorView, CheckBoxInputView} from 'pageflow/ui';

import {SidebarRouter} from './SidebarRouter';
Expand All @@ -21,7 +22,7 @@ editor.contentElementTypes.register('externalLinkList', {
pictogram,
category: 'tilesAndLinks',
supportedPositions: ['inline', 'standAlone'],
supportedWidthRange: ['m', 'xl'],
supportedWidthRange: ['m', 'full'],

defaultConfig: {
thumbnailAspectRatio: 'square'
Expand Down Expand Up @@ -56,6 +57,13 @@ editor.contentElementTypes.register('externalLinkList', {
this.view(SeparatorView);
this.group('ContentElementPosition');
this.view(SeparatorView);

if (features.isEnabled('teaser_list_scroller')) {
this.input('enableScroller', SelectInputView, {
values: ['never', 'always']
});
}

this.input('linkWidth', SliderInputView, {
displayText: value => [
'XS', 'S', 'M', 'L', 'XL', 'XXL'
Expand All @@ -68,8 +76,16 @@ editor.contentElementTypes.register('externalLinkList', {
});
this.input('linkAlignment', SelectInputView, {
values: ['spaceEvenly', 'left', 'right', 'center'],
visibleBinding: 'textPosition',
visible: textPosition => textPosition !== 'right'
visibleBinding: ['textPosition', 'enableScroller'],
visible: ([textPosition, enableScroller]) =>
textPosition !== 'right' && enableScroller !== 'always',
});
this.input('linkAlignment', SelectInputView, {
values: ['left'],
disabled: true,
visibleBinding: ['textPosition', 'enableScroller'],
visible: ([textPosition, enableScroller]) =>
textPosition !== 'right' && enableScroller === 'always',
});
this.input('thumbnailSize', SelectInputView, {
values: ['small', 'medium', 'large'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export function ExternalLink({id, configuration, ...props}) {
<Link isEnabled={!configuration.displayButtons}
isEditable={isEditable}
actionButtonVisible={props.selected}
actionButtonPortal={true}
href={href}
openInNewTab={openInNewTab}
onChange={handleLinkChange}>
Expand Down Expand Up @@ -178,8 +179,7 @@ function Link({isEnabled, isEditable, ...props}) {
if ((isEnabled && props.href) || isEditable) {
return (
<EditableLink {...props}
actionButtonVisible={props.actionButtonVisible}
linkPreviewPosition="above" />
actionButtonVisible={props.actionButtonVisible} />
);
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
position: relative;
margin: 0;
padding: 0;
transition: transform 0.3s;
}

.item > a {
Expand All @@ -35,10 +34,11 @@
}

.textPosition-below .cardWrapper,
.textPosition-right .cardWrapper{
.textPosition-right .cardWrapper {
height: 100%;
display: flex;
flex-direction: column;
transition: transform 0.3s;
}

.card {
Expand Down Expand Up @@ -70,11 +70,11 @@
composes: textPosition-none;
}

.link.textPosition-below:not(.outlined):hover {
.link.textPosition-below:not(.outlined):hover .cardWrapper {
transform: scale(var(--theme-external-links-card-hover-scale, 1.05));
}

.link.textPosition-right:not(.outlined):hover {
.link.textPosition-right:not(.outlined):hover .cardWrapper {
transform: scale(var(--theme-external-links-card-hover-scale, 1.02));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import React, {useState} from 'react';
import classNames from 'classnames';
import {
LinkTooltipProvider,
useContentElementEditorCommandSubscription,
useContentElementEditorState,
useContentElementLifecycle,
useDarkBackground,
contentElementWidthName
useTheme,
contentElementWidthName,
contentElementWidths
} from 'pageflow-scrolled/frontend';
import {ExternalLink} from './ExternalLink';
import {Scroller} from './Scroller';
import styles from './ExternalLinkList.module.css';

import textPositionBelowStyles from './textPositons/below.module.css';
Expand All @@ -26,6 +30,7 @@ export function ExternalLinkList(props) {
const linkList = props.configuration.links || [];
const {shouldLoad} = useContentElementLifecycle();
const darkBackground = useDarkBackground();
const theme = useTheme();

const {setTransientState, isSelected} = useContentElementEditorState();
const [selectedItemId, setSelectedItemId] = useState();
Expand Down Expand Up @@ -72,42 +77,61 @@ export function ExternalLinkList(props) {
textPositionRightStyles :
textPositionBelowStyles;

const scrollerEnabled = props.configuration.enableScroller === 'always';
const fullWidth = props.contentElementWidth === contentElementWidths.full;
const linkAlignment = scrollerEnabled ? 'left' : props.configuration.linkAlignment;

return (
<div className={styles.container}>
<ul className={classNames(
styles.list,
styles[`textPosition-${textPosition}`],
<div className={classNames({[styles.contentMargin]: props.customMargin || fullWidth},
styles[`scrollButtons-${theme.options.teasersScrollButtons}`])}>
<Scroller enabled={scrollerEnabled}>
{({scrollerRef, handleScroll}) =>
<div className={classNames(styles.container, {[styles.fullContainer]: fullWidth})}>
<LinkTooltipProvider align="center">
<ul ref={scrollerRef}
className={classNames(
styles.list,
styles[`textPosition-${textPosition}`],
styles[`layout-${layout}`],
{[styles.full]: fullWidth},
{[styles.scroller]: scrollerEnabled},

props.configuration.variant &&
`scope-externalLinkList-${props.configuration.variant}`,
props.configuration.variant &&
`scope-externalLinkList-${props.configuration.variant}`,

textPositionStyles.list,
textPositionStyles[`layout-${layout}`],
textPositionStyles[`width-${contentElementWidthName(props.configuration.width)}`],
textPositionStyles[`linkWidth-${linkWidth}`],
textPositionStyles[`linkAlignment-${props.configuration.linkAlignment}`],
textPositionStyles[`textPosition-${textPosition}`]
)}
style={{'--overlay-opacity': (props.configuration.overlayOpacity || 70) / 100,
'--thumbnail-aspect-ratio': `var(--theme-aspect-ratio-${props.configuration.thumbnailAspectRatio || 'wide'})`}}
onClick={handleListClick}>
{linkList.map((link, index) =>
<ExternalLink {...link}
key={link.id}
configuration={props.configuration}
thumbnailAspectRatio={props.configuration.thumbnailAspectRatio}
thumbnailSize={props.configuration.thumbnailSize || 'small'}
thumbnailFit={props.configuration.thumbnailFit || 'cover'}
textPosition={props.configuration.textPosition || 'below'}
textSize={props.configuration.textSize || 'small'}
darkBackground={darkBackground}
loadImages={shouldLoad}
outlined={isSelected}
highlighted={highlightedIndex === index}
selected={link.id === selectedItemId && isSelected}
onClick={event => handleItemClick(event, link.id)} />
)}
</ul>
textPositionStyles.list,
textPositionStyles[`layout-${layout}`],
textPositionStyles[`width-${contentElementWidthName(props.contentElementWidth)}`],
textPositionStyles[`linkWidth-${fullWidth ? 'full-' : ''}${linkWidth}`],
textPositionStyles[`linkAlignment-${linkAlignment}`],
textPositionStyles[`textPosition-${textPosition}`],
{[textPositionStyles.scroller]: scrollerEnabled}
)}
style={{'--overlay-opacity': (props.configuration.overlayOpacity || 70) / 100,
'--thumbnail-aspect-ratio': `var(--theme-aspect-ratio-${props.configuration.thumbnailAspectRatio || 'wide'})`}}
onScroll={handleScroll}
onClick={handleListClick}>
{linkList.map((link, index) =>
<ExternalLink {...link}
key={link.id}
configuration={props.configuration}
thumbnailAspectRatio={props.configuration.thumbnailAspectRatio}
thumbnailSize={props.configuration.thumbnailSize || 'small'}
thumbnailFit={props.configuration.thumbnailFit || 'cover'}
textPosition={props.configuration.textPosition || 'below'}
textSize={props.configuration.textSize || 'small'}
darkBackground={darkBackground}
loadImages={shouldLoad}
outlined={isSelected}
highlighted={highlightedIndex === index}
selected={link.id === selectedItemId && isSelected}
onClick={event => handleItemClick(event, link.id)} />
)}
</ul>
</LinkTooltipProvider>
</div>
}
</Scroller>
</div>
);
}
Loading
Loading