Skip to content

Commit 01a54fd

Browse files
Merge pull request #84 from grueneschweiz/feat_greenV2
Green Layout 2025
2 parents 0e26874 + 065731f commit 01a54fd

30 files changed

Lines changed: 645 additions & 90 deletions

app/Http/Controllers/ImageController.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ public function update(Request $request, Image $image)
148148
'background' => [
149149
'sometimes',
150150
'required',
151-
'in:'.Image::BG_CUSTOM.','.Image::BG_TRANSPARENT.','.Image::BG_GRADIENT,
151+
'in:'.Image::BG_CUSTOM.','.Image::BG_TRANSPARENT.','.Image::BG_GRADIENT.','.Image::BG_ICONS,
152152
new ImageBackgroundRule($image),
153153
],
154154
// if mutable we would have to check the legal etc
@@ -215,7 +215,7 @@ public function store(Request $request, Image $image)
215215
],
216216
'background' => [
217217
'required',
218-
'in:'.Image::BG_CUSTOM.','.Image::BG_TRANSPARENT.','.Image::BG_GRADIENT,
218+
'in:'.Image::BG_CUSTOM.','.Image::BG_TRANSPARENT.','.Image::BG_GRADIENT.','.Image::BG_ICONS,
219219
new ImageBackgroundRule($image),
220220
],
221221
'type' => ['required', 'in:'.Image::TYPE_RAW.','.Image::TYPE_FINAL],

app/Image.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class Image extends Model
7070
public const BG_GRADIENT = 'gradient';
7171
public const BG_TRANSPARENT = 'transparent';
7272
public const BG_CUSTOM = 'custom';
73+
public const BG_ICONS = 'icons';
7374

7475
/**
7576
* The attributes that should be hidden for arrays.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
use App\Image;
4+
use Illuminate\Support\Facades\Schema;
5+
use Illuminate\Database\Schema\Blueprint;
6+
use Illuminate\Database\Migrations\Migration;
7+
use Illuminate\Support\Facades\DB;
8+
9+
class AddIconsBackgroundToImagesTable extends Migration
10+
{
11+
/**
12+
* Run the migrations.
13+
*
14+
* @return void
15+
*/
16+
public function up()
17+
{
18+
DB::statement("ALTER TABLE images MODIFY COLUMN background ENUM('gradient', 'transparent', 'custom', 'icons') NOT NULL");
19+
}
20+
21+
/**
22+
* Reverse the migrations.
23+
*
24+
* @return void
25+
*/
26+
public function down()
27+
{
28+
// ensure no rows use the 'icons' value
29+
DB::table('images')->where('background', 'icons')->update(['background' => 'gradient']);
30+
DB::statement("ALTER TABLE images MODIFY COLUMN background ENUM('gradient', 'transparent', 'custom') NOT NULL");
31+
}
32+
}

public/images/iconsBackground.png

4.4 MB
Loading

resources/js/components/atoms/ABar.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@
7272
},
7373
7474
barSchema() {
75+
if(!this.isSubline && ColorSchemes.green2025 === this.colorSchema) {
76+
return BarSchemes.green2025
77+
}
78+
7579
if (BarSchemes.magenta === this.bar.schema) {
7680
return BarSchemes.magenta
7781
}
@@ -126,6 +130,9 @@
126130
127131
case BarSchemes.transparent:
128132
return 'btn-outline-dark'
133+
134+
default:
135+
return 'btn-secondary'
129136
}
130137
},
131138
@@ -137,6 +144,9 @@
137144
case BarSchemes.transparent:
138145
return 'dark'
139146
147+
case BarSchemes.green2025:
148+
return 'green2025'
149+
140150
default:
141151
return 'green'
142152
}

resources/js/components/molecules/MAlignment.vue

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,45 @@
2828
return this.$store.getters['canvas/getBars'].filter(bar => bar.text.length).length > 0
2929
},
3030
31+
getStyleSet() {
32+
return this.$store.getters['canvas/getStyleSet']
33+
},
34+
3135
options() {
3236
if (this.hasBars) {
33-
return [
34-
{value: Alignments.left, text: this.$t('images.create.barsLeft')},
35-
{value: Alignments.right, text: this.$t('images.create.barsRight')},
36-
];
37+
if(this.getStyleSet === 'green2025' || this.getStyleSet === 'green2025Centered') {
38+
return [
39+
{value: Alignments.left, text: this.$t('images.create.barsLeft')},
40+
{value: Alignments.center, text: this.$t('images.create.barsCentered')},
41+
{value: Alignments.right, text: this.$t('images.create.barsRight')},
42+
];
43+
} else {
44+
return [
45+
{value: Alignments.left, text: this.$t('images.create.barsLeft')},
46+
{value: Alignments.right, text: this.$t('images.create.barsRight')},
47+
];
48+
}
3749
} else {
3850
return [
3951
{value: Alignments.right, text: this.$t('images.create.logoLeft')},
4052
{value: Alignments.left, text: this.$t('images.create.logoRight')},
4153
];
4254
}
4355
}
56+
},
57+
watch: {
58+
alignment(newVal, oldVal) {
59+
this.applyCorrectStyleSet(newVal);
60+
}
61+
},
62+
methods: {
63+
applyCorrectStyleSet(newAlignment) {
64+
if (this.getStyleSet === 'green2025' && newAlignment === Alignments.center) {
65+
this.$store.commit('canvas/setStyleSet', 'green2025Centered');
66+
} else if (this.getStyleSet === 'green2025Centered' && newAlignment !== Alignments.center) {
67+
this.$store.commit('canvas/setStyleSet', 'green2025');
68+
}
69+
}
4470
}
4571
}
4672
</script>

resources/js/components/molecules/MBackgroundBlock.vue

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@
1616
type="radio"
1717
>{{$t('images.create.backgroundGreen')}}
1818
</label>
19+
<label v-if="iconsBackgroundAvailable"
20+
:class="{
21+
'active': backgroundType === backgroundTypes.icons,
22+
'disabled': loading,
23+
}"
24+
class="btn btn-secondary btn-sm">
25+
<input
26+
v-model="backgroundType"
27+
:value="backgroundTypes.icons"
28+
name="background"
29+
type="radio"
30+
>{{$t('images.create.backgroundIcons')}}
31+
</label>
1932
<label v-if="!hugeCanvas"
2033
:class="{
2134
'active': backgroundType === backgroundTypes.transparent,
@@ -231,6 +244,11 @@ import {mapGetters} from "vuex";
231244
|| this.styleSet === StyleSetTypes.greenCentered;
232245
},
233246
247+
iconsBackgroundAvailable() {
248+
return this.styleSet === StyleSetTypes.green2025
249+
|| this.styleSet === StyleSetTypes.green2025Centered;
250+
},
251+
234252
acceptedMimeTypes() {
235253
return mimeTypesAllowed.join(',');
236254
},
@@ -336,6 +354,8 @@ import {mapGetters} from "vuex";
336354
if (this.hugeCanvas && this.backgroundType === BackgroundTypes.transparent) {
337355
if (this.styleSet === StyleSetTypes.young) {
338356
this.backgroundType = BackgroundTypes.placeholder
357+
} else if(this.styleSet === StyleSetTypes.green2025) {
358+
this.backgroundType = BackgroundTypes.icons
339359
} else {
340360
this.backgroundType = BackgroundTypes.gradient;
341361
}
@@ -371,12 +391,20 @@ import {mapGetters} from "vuex";
371391
this.maybeDisableTransparentBackground();
372392
},
373393
styleSet(valueNew) {
374-
if (StyleSetTypes.young === valueNew && BackgroundTypes.gradient === this.backgroundType) {
375-
this.backgroundType = BackgroundTypes.placeholder
376-
}
377-
if ((StyleSetTypes.green === valueNew || StyleSetTypes.greenCentered === valueNew )
378-
&& BackgroundTypes.placeholder === this.backgroundType) {
379-
this.backgroundType = BackgroundTypes.gradient
394+
const isYoungStyle = valueNew === StyleSetTypes.young;
395+
const isGreenStyle = valueNew === StyleSetTypes.green || valueNew === StyleSetTypes.greenCentered;
396+
const isGreen2025Style = valueNew === StyleSetTypes.green2025 || valueNew === StyleSetTypes.green2025Centered;
397+
398+
const isGradientOrIcons = this.backgroundType === BackgroundTypes.gradient || this.backgroundType === BackgroundTypes.icons;
399+
const isPlaceholderOrIcons = this.backgroundType === BackgroundTypes.placeholder || this.backgroundType === BackgroundTypes.icons;
400+
const isPlaceholderOrGradient = this.backgroundType === BackgroundTypes.placeholder || this.backgroundType === BackgroundTypes.gradient;
401+
402+
if (isYoungStyle && isGradientOrIcons) {
403+
this.backgroundType = BackgroundTypes.placeholder;
404+
} else if (isGreenStyle && isPlaceholderOrIcons) {
405+
this.backgroundType = BackgroundTypes.gradient;
406+
} else if (isGreen2025Style && isPlaceholderOrGradient) {
407+
this.backgroundType = BackgroundTypes.icons;
380408
}
381409
},
382410
user() {

resources/js/components/molecules/MBarBlock.vue

Lines changed: 120 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@
4848
import {
4949
BarSchemes,
5050
BarTypes,
51+
BackgroundTypes,
5152
ColorSchemes,
52-
StyleSetTypes
53+
StyleSetTypes,
54+
Alignments
5355
} from "../../service/canvas/Constants";
5456
import ABar from "../atoms/ABar";
5557
@@ -70,6 +72,7 @@
7072
colorSchema: 'canvas/getColorSchema',
7173
bars: 'canvas/getBars',
7274
textFitsImage: 'canvas/getTextFitsImage',
75+
backgroundType: 'canvas/getBackgroundType',
7376
}),
7477
7578
fontSizePercent: {
@@ -131,6 +134,72 @@
131134
)
132135
},
133136
137+
updateBarSchemas() {
138+
// Handle bars based on layout and color scheme
139+
if (this.bars.length > 0 && this.bars[0].type === BarTypes.headline) {
140+
const schema = this.getSchemaForBar(0);
141+
this.$store.dispatch('canvas/setBar', {
142+
index: 0,
143+
bar: { ...this.bars[0], schema }
144+
});
145+
}
146+
147+
// Force the second headline to use the scheme for current layout
148+
if (this.bars.length > 1 && this.bars[1].type === BarTypes.headline) {
149+
const schema = this.getSchemaForBar(1);
150+
this.$store.dispatch('canvas/setBar', {
151+
index: 1,
152+
bar: { ...this.bars[1], schema }
153+
});
154+
}
155+
156+
// Handle third headline bar if present (for green layout with 3 headline bars)
157+
if (this.bars.length > 2 && this.bars[2].type === BarTypes.headline &&
158+
!(this.styleSet === StyleSetTypes.green2025 || this.styleSet === StyleSetTypes.green2025Centered)) {
159+
this.$store.dispatch('canvas/setBar', {
160+
index: 2,
161+
bar: { ...this.bars[2], schema: BarSchemes.magenta }
162+
});
163+
}
164+
165+
// For subline, use the computed sublineSchema which is based on current style set
166+
if (this.bars.length > 2 && this.bars[2].type === BarTypes.subline) {
167+
this.$store.dispatch('canvas/setBar', {
168+
index: 2,
169+
bar: { ...this.bars[2], schema: this.sublineSchema }
170+
});
171+
}
172+
},
173+
174+
getSchemaForBar(index) {
175+
// Green2025 layout
176+
if (this.styleSet === StyleSetTypes.green2025 || this.styleSet === StyleSetTypes.green2025Centered) {
177+
return BarSchemes.green2025;
178+
}
179+
180+
// Young layout
181+
if (this.styleSet === StyleSetTypes.young) {
182+
if(index === 0) {
183+
return (this.colorSchema === ColorSchemes.white)
184+
? BarSchemes.white
185+
: BarSchemes.green;
186+
} else {
187+
return BarSchemes.magenta;
188+
}
189+
}
190+
191+
// Green layout
192+
const backgroundRequiresGreen =
193+
this.backgroundType === BackgroundTypes.transparent ||
194+
this.backgroundType === BackgroundTypes.image;
195+
196+
if (index === 0 || (index === 1 && this.bars.length >2 && this.bars[2].type === BarTypes.headline)) {
197+
return backgroundRequiresGreen ? BarSchemes.green : BarSchemes.white;
198+
}
199+
200+
return BarSchemes.magenta;
201+
},
202+
134203
maybeRemoveSubline() {
135204
// remove sublines for style set young
136205
if (this.styleSet === StyleSetTypes.young) {
@@ -148,7 +217,9 @@
148217
// remove first primary headline if there are two
149218
const primaryHeadlines = this.bars.filter(
150219
bar => bar.type === BarTypes.headline
151-
&& (bar.schema === BarSchemes.white || bar.schema === BarSchemes.green)
220+
&& (bar.schema === BarSchemes.white ||
221+
bar.schema === BarSchemes.green ||
222+
bar.schema === BarSchemes.green2025)
152223
);
153224
if (primaryHeadlines.length > 1) {
154225
this.$store.commit('canvas/removeBar', {index: 0})
@@ -157,19 +228,63 @@
157228
// remove first secondary headline if there are two
158229
const secondaryHeadlines = this.bars.filter(
159230
bar => bar.type === BarTypes.headline
160-
&& (bar.schema === BarSchemes.magenta)
231+
&& (bar.schema === BarSchemes.magenta ||
232+
bar.schema === BarSchemes.transparent2025)
161233
);
162234
if (secondaryHeadlines.length > 1) {
163235
this.$store.commit('canvas/removeBar', {index: 1})
164236
}
165237
}
238+
},
239+
240+
maybeAddHeadline() {
241+
// Green and young layouts need at least 2 headline bars
242+
if ((this.styleSet !== StyleSetTypes.green2025 &&
243+
this.styleSet !== StyleSetTypes.green2025Centered) &&
244+
this.bars.filter(bar => bar.type === BarTypes.headline).length === 1) {
245+
246+
const secondHeadline = {
247+
type: BarTypes.headline,
248+
schema: BarSchemes.magenta,
249+
text: 'Headline',
250+
canvas: null,
251+
padding: 0,
252+
};
253+
254+
this.$store.dispatch(
255+
'canvas/addBar',
256+
{index: 1, bar: secondHeadline}
257+
);
258+
}
166259
}
167260
},
168261
169262
watch: {
170263
styleSet() {
171-
this.maybeRemoveSubline()
172-
this.maybeRemoveHeadline()
264+
this.maybeRemoveSubline();
265+
this.maybeRemoveHeadline();
266+
this.maybeAddHeadline();
267+
268+
// Handle alignment based on style set
269+
const currentAlignment = this.$store.getters['canvas/getAlignment'];
270+
271+
if ((this.styleSet === StyleSetTypes.green || this.styleSet === StyleSetTypes.green2025) &&
272+
currentAlignment !== Alignments.left) {
273+
this.$store.dispatch('canvas/setAlignment', Alignments.left);
274+
} else if (this.styleSet === StyleSetTypes.greenCentered ||
275+
this.styleSet === StyleSetTypes.green2025Centered ||
276+
this.styleSet === StyleSetTypes.young) {
277+
this.$store.dispatch('canvas/setAlignment', Alignments.center);
278+
}
279+
280+
this.$nextTick(() => {
281+
this.updateBarSchemas();
282+
});
283+
},
284+
colorSchema() {
285+
this.$nextTick(() => {
286+
this.updateBarSchemas();
287+
});
173288
},
174289
textFitsImage(val) {
175290
if (!val) {

0 commit comments

Comments
 (0)