Skip to content

Commit

Permalink
Add support for side position in two column layout
Browse files Browse the repository at this point in the history
Same as sticky, but with static position.

REDMINE-20900
  • Loading branch information
tf committed Jan 8, 2025
1 parent 4a61d87 commit d81fc02
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 11 deletions.
179 changes: 179 additions & 0 deletions entry_types/scrolled/package/spec/frontend/Layout-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,24 @@ describe('Layout', () => {
);
});

it('creates new group for side elements', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
{id: 2, type: 'probe', position: 'side'},
{id: 3, type: 'probe', position: 'side'},
{id: 4, type: 'probe', position: 'inline'}
];
const {container} = renderInEntry(
<Layout sectionProps={{layout: 'left'}} items={items}>
{(children, {position}) => <div>{position} {children}</div>}
</Layout>
);

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

it('places inline elements with custom margin in separate box in same group', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
Expand All @@ -139,6 +157,22 @@ describe('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'},
{id: 2, type: 'probeWithCustomMargin', position: 'side'}
];
const {container} = renderInEntry(
<Layout sectionProps={{layout: 'left'}} items={items}>
{(children, {position, customMargin}) =>
<div>{position} {customMargin ? 'custom' : 'normal'} {children}</div>
}
</Layout>
);

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

it('places sticky elements with and without custom margin in separate groups', () => {
const items = [
{id: 1, type: 'probe', position: 'sticky'},
Expand Down Expand Up @@ -199,6 +233,23 @@ describe('Layout', () => {
});
});

it('continues inline box after being interrupted by side box', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
{id: 2, type: 'probe', position: 'inline'},
{id: 3, type: 'probe', position: 'side'},
{id: 4, type: 'probe', position: 'side'},
{id: 5, type: 'probe', position: 'inline'},
];
const {container} = renderInEntry(
<Layout sectionProps={{layout: 'left'}} items={items}>
{(children, boxProps) => <Box {...boxProps}>{children}</Box>}
</Layout>
);

expect(container.textContent).toEqual('[( 1 2 |][( 3 4 )| 5 )]');
});

it('continues inline box after being interrupted by sticky box', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
Expand Down Expand Up @@ -233,6 +284,23 @@ describe('Layout', () => {
expect(container.textContent).toEqual('[( 1 2 |][( 3 4 )| 5 )]');
});

it('continues inline box in new group after side box', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
{id: 2, type: 'probe', position: 'side'},
{id: 3, type: 'probe', position: 'inline'},
{id: 4, type: 'probe', position: 'side'},
{id: 5, type: 'probe', position: 'inline'},
];
const {container} = renderInEntry(
<Layout sectionProps={{layout: 'left'}} items={items}>
{(children, boxProps) => <Box {...boxProps}>{children}</Box>}
</Layout>
);

expect(container.textContent).toEqual('[( 1 |][( 2 )| 3 |][( 4 )| 5 )]');
});

it('continues inline box in new group after sticky box', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
Expand Down Expand Up @@ -282,6 +350,22 @@ describe('Layout', () => {
expect(container.textContent).toEqual('[( 1 2 )][( 3 )][( 4 )]');
});

it('does not continue inline box after being interrupted by side and full box', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
{id: 2, type: 'probe', position: 'side'},
{id: 3, type: 'probe', position: 'inline', width: 3},
{id: 4, type: 'probe', position: 'inline'},
];
const {container} = renderInEntry(
<Layout sectionProps={{layout: 'left'}} items={items}>
{(children, boxProps) => <Box {...boxProps}>{children}</Box>}
</Layout>
);

expect(container.textContent).toEqual('[( 1 )][( 2 )][( 3 )][( 4 )]');
});

it('does not continue inline box after being interrupted by sticky and full box', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
Expand All @@ -298,6 +382,22 @@ describe('Layout', () => {
expect(container.textContent).toEqual('[( 1 )][( 2 )][( 3 )][( 4 )]');
});

it('does not continue inline box after being interrupted by full and side box', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
{id: 2, type: 'probe', position: 'inline', width: 3},
{id: 3, type: 'probe', position: 'side'},
{id: 4, type: 'probe', position: 'inline'},
];
const {container} = renderInEntry(
<Layout sectionProps={{layout: 'left'}} items={items}>
{(children, boxProps) => <Box {...boxProps}>{children}</Box>}
</Layout>
);

expect(container.textContent).toEqual('[( 1 )][( 2 )][( 3 )( 4 )]');
});

it('does not continue inline box after being interrupted by full and sticky box', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
Expand Down Expand Up @@ -329,6 +429,21 @@ describe('Layout', () => {
expect(container.textContent).toEqual('[( 1 )( 2 )( 3 )]');
});

it('continues inline box after being interrupted by side custom margin box', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
{id: 2, type: 'probeWithCustomMargin', position: 'side'},
{id: 3, type: 'probe', position: 'inline'},
];
const {container} = renderInEntry(
<Layout sectionProps={{layout: 'left'}} items={items}>
{(children, boxProps) => <Box {...boxProps}>{children}</Box>}
</Layout>
);

expect(container.textContent).toEqual('[( 1 |][( 2 )| 3 )]');
});

it('continues inline box after being interrupted by sticky custom margin box', () => {
const items = [
{id: 1, type: 'probe', position: 'inline'},
Expand All @@ -344,6 +459,37 @@ describe('Layout', () => {
expect(container.textContent).toEqual('[( 1 |][( 2 )| 3 )]');
});

it('inlines side elements of different width at different breakpoints ', () => {
const items = [
{id: 1, type: 'probe', position: 'side'},
{id: 2, type: 'probe', position: 'side', width: 1},
{id: 3, type: 'probe', position: 'side', width: 2}
];
viewportWidth = 1000;
const {container} = renderInEntry(
<Layout sectionProps={{layout: 'left'}} items={items}>
{(children, {position}) => <div>{position} {children}</div>}
</Layout>,
{
seed: {
themeOptions: {
properties: {
root: {
twoColumnStickyBreakpoint: '950px',
twoColumnStickyLgBreakpoint: '1024px',
twoColumnStickyXlBreakpoint: '1180px'
}
}
}
}
}
);

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

it('inlines sticky elements of different width at different breakpoints ', () => {
const items = [
{id: 1, type: 'probe', position: 'sticky'},
Expand Down Expand Up @@ -375,6 +521,39 @@ describe('Layout', () => {
);
});

it('decreases size when inlining wide side elements', () => {
const items = [
{id: 1, type: 'probe', position: 'side', width: -2},
{id: 2, type: 'probe', position: 'side', width: -1},
{id: 3, type: 'probe', position: 'side'},
{id: 4, type: 'probe', position: 'side', width: 1},
{id: 5, type: 'probe', position: 'side', width: 2}
];
viewportWidth = 500;
const {container} = renderInEntry(
<Layout sectionProps={{layout: 'left'}} items={items}>
{(children, {position, width}) => <div>{position} {widthName(width)} {children}</div>}
</Layout>,
{
seed: {
themeOptions: {
properties: {
root: {
twoColumnStickyBreakpoint: '950px',
twoColumnStickyLgBreakpoint: '1024px',
twoColumnStickyXlBreakpoint: '1180px'
}
}
}
}
}
);

expect(container.textContent).toEqual(
'[inline xs 1 ][inline sm 2 ][inline md 3 4 ][inline lg 5 ]'
);
});

it('decreases size when inlining wide sticky elements', () => {
const items = [
{id: 1, type: 'probe', position: 'sticky', width: -2},
Expand Down
14 changes: 9 additions & 5 deletions entry_types/scrolled/package/src/frontend/layouts/TwoColumn.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,19 @@ function groupItemsByPosition(items, shouldInline) {
const {customMargin: elementSupportsCustomMargin} =
api.contentElementTypes.getOptions(item.type) || {};
let width = item.width || 0;
const position = item.position === 'sticky' && !shouldInline(width) ? 'sticky' : 'inline';
const position = onTheSide(item.position) && !shouldInline(width) ? item.position : 'inline';
const customMargin = !!elementSupportsCustomMargin && width < widths.full;

if (item.position === 'sticky' && position === 'inline' && width > widths.md) {
if (onTheSide(item.position) && position === 'inline' && width > widths.md) {
width -= 1;
}

if (!currentGroup || previousPosition !== position ||
(position === 'sticky' && currentBox.customMargin !== customMargin) ||
(onTheSide(position) && currentBox.customMargin !== customMargin) ||
currentBox.width !== width) {
currentBox = null;

if (!(previousPosition === 'sticky' && position === 'inline' && width <= widths.md)) {
if (!(onTheSide(previousPosition) && position === 'inline' && width <= widths.md)) {
currentGroup = {
width,
boxes: []
Expand All @@ -149,7 +149,7 @@ function groupItemsByPosition(items, shouldInline) {
lastInlineBox = currentBox;
}
else if ((position === 'inline' && width > widths.md) ||
(customMargin && position !== 'sticky')) {
(customMargin && !onTheSide(position))) {
lastInlineBox = null;
}

Expand All @@ -163,6 +163,10 @@ function groupItemsByPosition(items, shouldInline) {
return groups;
}

function onTheSide(position) {
return position === 'side' || position === 'sticky';
}

function renderPlaceholder(placeholder) {
if (!placeholder) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,32 +80,36 @@
margin-left: auto;
}

.sticky {
.side {
--content-width: var(--theme-two-column-sticky-content-width, 25vw);
--content-max-width: min(var(--content-width), var(--two-column-sticky-content-max-width, 600px));
position: sticky;
float: right;
clear: both;
top: 33%;
width: var(--content-width);
}

.right .sticky {
.sticky {
composes: side;
position: sticky;
}

.right .side {
float: left;
}

.sticky.width-lg {
.side.width-lg {
--content-width: var(--theme-two-column-sticky-lg-content-width, 35vw);
--content-max-width: min(var(--content-width),
var(--two-column-sticky-lg-content-max-width, 700px));
}

.sticky.width-xl {
.side.width-xl {
--content-width: var(--theme-two-column-sticky-xl-content-width, 45vw);
--content-max-width: min(var(--content-width),
var(--two-column-sticky-xl-content-max-width, 1000px));
}

.sticky.customMargin {
.side.customMargin {
width: 100%;
}

0 comments on commit d81fc02

Please sign in to comment.