Skip to content

Commit 7b7a14e

Browse files
authored
Merge pull request #2234 from tf/decoration-effect
Backdrop decoration effects
2 parents b0f8242 + c95001f commit 7b7a14e

File tree

16 files changed

+254
-13
lines changed

16 files changed

+254
-13
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
de:
2+
pageflow:
3+
decoration_effects:
4+
feature_name: Dekoration-Effekte
5+
pageflow_scrolled:
6+
editor:
7+
backdrop_effects:
8+
frame:
9+
label: 'Rahmen'
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
en:
2+
pageflow:
3+
decoration_effects:
4+
feature_name: Decoration Effects
5+
pageflow_scrolled:
6+
editor:
7+
backdrop_effects:
8+
frame:
9+
label: 'Frame'

entry_types/scrolled/lib/pageflow_scrolled/plugin.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ def configure(config)
4949
c.features.register('scrolled_entry_fragment_caching')
5050
c.features.register('backdrop_content_elements')
5151
c.features.register('custom_palette_colors')
52+
c.features.register('decoration_effects')
5253

5354
c.additional_frontend_seed_data.register(
5455
'frontendVersion',

entry_types/scrolled/package/spec/editor/collections/EffectsCollection-spec.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import {EffectsCollection} from 'editor/collections/EffectsCollection';
22

33
import {useFakeTranslations} from 'pageflow/testHelpers';
4+
import {features} from 'pageflow/frontend';
45

56
describe('EffectsCollection', () => {
7+
beforeEach(() => features.enabledFeatureNames = []);
8+
69
describe('#getUnusedEffects', () => {
710
useFakeTranslations({
811
'pageflow_scrolled.editor.backdrop_effects.blur.label': 'Blur'
@@ -25,6 +28,23 @@ describe('EffectsCollection', () => {
2528
expect(unusedEffects.pluck('name')).not.toContain('brightness');
2629
});
2730

31+
it('does not include decoration effects by default', () => {
32+
const effects = new EffectsCollection();
33+
34+
const unusedEffects = effects.getUnusedEffects();
35+
36+
expect(unusedEffects.pluck('name')).not.toContain('frame');
37+
});
38+
39+
it('includes decoration effects if feature is enabled', () => {
40+
const effects = new EffectsCollection();
41+
features.enable('frontend', ['decoration_effects']);
42+
43+
const unusedEffects = effects.getUnusedEffects();
44+
45+
expect(unusedEffects.pluck('name')).toContain('frame');
46+
});
47+
2848
it('selecting an unused effects adds it to the collection', () => {
2949
const effects = new EffectsCollection();
3050

entry_types/scrolled/package/spec/editor/models/Effect-spec.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,16 @@ describe('Effect', () => {
2525

2626
expect(effect.get('value')).toEqual(50);
2727
});
28+
29+
it('defaults to slider inputType', () => {
30+
const effect = new Effect({name: 'blur'});
31+
32+
expect(effect.inputType()).toEqual('slider');
33+
});
34+
35+
it('supports colors inputType', () => {
36+
const effect = new Effect({name: 'frame'});
37+
38+
expect(effect.inputType()).toEqual('color');
39+
});
2840
});
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import {renderEntry, usePageObjects} from 'support/pageObjects';
2+
import '@testing-library/jest-dom/extend-expect'
3+
4+
import effectsStyles from 'frontend/BackdropFrameEffect.module.css';
5+
6+
import {usePortraitOrientation} from 'frontend/usePortraitOrientation';
7+
jest.mock('frontend/usePortraitOrientation');
8+
9+
describe('backdrop decoration effects', () => {
10+
usePageObjects();
11+
12+
it('does not render Backdrop frame', () => {
13+
const {container} = renderEntry({
14+
seed: {
15+
imageFiles: [{permaId: 100}],
16+
sections: [
17+
{
18+
permaId: 1,
19+
configuration: {
20+
backdrop: {image: 100}
21+
}
22+
}
23+
]
24+
}
25+
});
26+
27+
expect(container.querySelector(`.${effectsStyles.outer}`)).not.toBeInTheDocument();
28+
});
29+
30+
it('renders elements if effect is present', () => {
31+
const {container} = renderEntry({
32+
seed: {
33+
imageFiles: [{permaId: 100}],
34+
sections: [
35+
{
36+
permaId: 1,
37+
configuration: {
38+
backdrop: {image: 100},
39+
backdropEffects: [
40+
{
41+
name: 'frame',
42+
value: '#ff0'
43+
}
44+
]
45+
}
46+
}
47+
]
48+
}
49+
});
50+
51+
expect(container.querySelector(`.${effectsStyles.outer}`)).toBeInTheDocument();
52+
});
53+
54+
it('supports scroll parallax for mobile image', () => {
55+
usePortraitOrientation.mockReturnValue(true);
56+
57+
const {container} = renderEntry({
58+
seed: {
59+
imageFiles: [
60+
{permaId: 100},
61+
{permaId: 101},
62+
],
63+
sections: [
64+
{
65+
permaId: 1,
66+
configuration: {
67+
backdrop: {
68+
image: 100,
69+
imageMobile: 101
70+
},
71+
backdropEffectsMobile: [
72+
{
73+
name: 'frame',
74+
value: '#ff0'
75+
}
76+
]
77+
}
78+
}
79+
]
80+
}
81+
});
82+
83+
expect(container.querySelector(`.${effectsStyles.outer}`)).toBeInTheDocument();
84+
expect(container.querySelector(`.${effectsStyles.outer}`)).toHaveStyle('--frame-color: #ff0');
85+
});
86+
});

entry_types/scrolled/package/src/editor/collections/EffectsCollection.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Backbone from 'backbone';
2+
import {features} from 'pageflow/frontend';
23
import {Effect} from '../models/Effect';
34

45
export const EffectsCollection = Backbone.Collection.extend({
@@ -8,6 +9,8 @@ export const EffectsCollection = Backbone.Collection.extend({
89
const effects = this;
910
const unusedEffects = new Backbone.Collection(
1011
Effect.names
12+
.filter(name => features.isEnabled('decoration_effects') ||
13+
Effect.getKind(name) !== 'decoration')
1114
.filter(name => !this.findWhere({name}))
1215
.map(name => ({name})),
1316
{

entry_types/scrolled/package/src/editor/models/Effect.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,26 +49,39 @@ const TYPES = {
4949
maxValue: 100,
5050
defaultValue: 50,
5151
kind: 'animation'
52+
},
53+
frame: {
54+
kind: 'decoration',
55+
inputType: 'color',
56+
defaultValue: '#ffffff'
5257
}
5358
}
5459

5560
export const Effect = Backbone.Model.extend({
5661
initialize({name}) {
5762
if (!this.has('value')) {
58-
this.set('value', TYPES[name].defaultValue);
63+
this.set('value', this.defaultValue());
5964
}
6065
},
6166

6267
label() {
6368
return Effect.getLabel(this.get('name'));
6469
},
6570

71+
defaultValue() {
72+
return TYPES[this.get('name')].defaultValue;
73+
},
74+
6675
minValue() {
6776
return TYPES[this.get('name')].minValue;
6877
},
6978

7079
maxValue() {
7180
return TYPES[this.get('name')].maxValue;
81+
},
82+
83+
inputType() {
84+
return TYPES[this.get('name')].inputType || 'slider';
7285
}
7386
});
7487

entry_types/scrolled/package/src/editor/views/inputs/EffectListInputView.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,20 +54,20 @@ const EffectListItemView = Marionette.ItemView.extend({
5454

5555
template: (data) => `
5656
<div class="${styles.label}">${data.label}</div>
57-
<div class="${styles.value}"></div>
58-
<div class="${styles.widget}"></div>
57+
${renderInput(data.inputType)}
5958
<button class="${styles.remove}"
6059
title="${I18n.t('pageflow_scrolled.editor.effect_list_input.remove')}">
6160
</button>
6261
`,
6362

6463
serializeData() {
6564
return {
66-
label: this.model.label()
65+
label: this.model.label(),
66+
inputType: this.model.inputType()
6767
};
6868
},
6969

70-
ui: cssModulesUtils.ui(styles, 'widget', 'value'),
70+
ui: cssModulesUtils.ui(styles, 'widget', 'value', 'colorInput'),
7171

7272
events: cssModulesUtils.events(styles, {
7373
'click remove': function() {
@@ -92,5 +92,25 @@ const EffectListItemView = Marionette.ItemView.extend({
9292
});
9393

9494
this.ui.widget.slider('option', 'value', this.model.get('value') || 50);
95+
96+
this.ui.colorInput.minicolors({
97+
defaultValue: this.model.defaultValue(),
98+
position: 'bottom right',
99+
changeDelay: 200,
100+
change: color => {
101+
this.model.set('value', color);
102+
}
103+
});
104+
105+
this.ui.colorInput.minicolors('value', this.model.get('value'));
95106
}
96107
});
108+
109+
function renderInput(inputType) {
110+
if (inputType === 'color') {
111+
return `<input class="${styles.colorInput}" />`;
112+
} else {
113+
return `<div class="${styles.value}"></div>
114+
<div class="${styles.widget}"></div>`;
115+
}
116+
}

entry_types/scrolled/package/src/editor/views/inputs/EffectListInputView.module.css

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,32 @@
8686
outline-width: 2px;
8787
}
8888

89+
.item :global(.minicolors) {
90+
flex: 1;
91+
margin: -4px 0 -4px 2.6rem;
92+
}
93+
94+
.colorInput {
95+
border: 0;
96+
width: 100% !important;
97+
height: 22px !important;
98+
box-sizing: border-box;
99+
font-size: 12px;
100+
padding-right: 0 !important;
101+
padding-left: 20px !important;
102+
}
103+
104+
.colorInput:focus {
105+
outline: solid 1px transparent;
106+
}
107+
108+
.item :global(.minicolors-input-swatch) {
109+
top: 3px !important;
110+
left: 0px !important;
111+
width: 14px;
112+
height: 14px;
113+
}
114+
89115
.remove {
90116
composes: cancel from '../icons.module.css';
91117
padding: 0 space(2);

0 commit comments

Comments
 (0)