Skip to content
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

feat: new hero carousel #930

Merged
merged 44 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
80c1ee4
Draft
Dec 31, 2024
6439245
update styling
ksted Jan 2, 2025
77c40c3
apply styling to hero content
ksted Jan 2, 2025
51cf209
update styling
ksted Jan 3, 2025
6490a55
create new hero props type
ksted Jan 3, 2025
29e2d85
use props in component
ksted Jan 3, 2025
0b9b846
responsive image
ksted Jan 6, 2025
9735d9a
rename component
ksted Jan 6, 2025
352ee20
remove redundant html check
ksted Jan 6, 2025
b3a537e
title styling
ksted Jan 6, 2025
6262162
update skeleton
ksted Jan 6, 2025
e0252c2
refactor: change props name
ksted Jan 6, 2025
43a0b12
test: banner all settings
ksted Jan 6, 2025
8edeca7
test: settings variations
ksted Jan 6, 2025
42f8e6f
refactor: split test cases into multiple files
ksted Jan 6, 2025
064a3bd
update text styles
ksted Jan 7, 2025
80d8ee2
chore: revert changes to existing content component
ksted Jan 7, 2025
a0935e3
update viewport config
ksted Jan 8, 2025
7c9f86c
use expressive property names for image sizes
ksted Jan 8, 2025
a162af0
use multiple slides
ksted Jan 8, 2025
1a6a8fe
test: update image test data
ksted Jan 8, 2025
05f0586
update demo data
ksted Jan 8, 2025
07cfd44
re-add swiper navigation
ksted Jan 8, 2025
b9615a7
Merge branch 'main' into customization/new_carousel
aoltean-plenty Jan 8, 2025
4cb0dfd
perf: fix cls
ksted Jan 8, 2025
0832c1f
Merge branch 'customization/new_carousel' of https://github.com/plent…
ksted Jan 8, 2025
ac62437
test: update expected image style
ksted Jan 9, 2025
e7fac0b
update breakpoints configuration
ksted Jan 9, 2025
d18ec5d
test: update edit mode e2e tests
ksted Jan 9, 2025
d3d3f21
fix: block covering account dropdown content
ksted Jan 9, 2025
3f46378
fix: apply styling conditionally
ksted Jan 9, 2025
688a55c
fix: content area alignment when no background is set
ksted Jan 9, 2025
224cb37
Small json addaptations + create custom swiper arrows
Jan 9, 2025
4dbc6d6
Arrows now use textColor
Jan 9, 2025
9f0f9be
Custom pagination
Jan 9, 2025
6ad1483
fix: action button z-index on tablets
ksted Jan 9, 2025
5d9053d
perf: lazy load images on later slides
ksted Jan 9, 2025
06a6408
Bug + mobile text box fix
Jan 9, 2025
1d8f864
Last of Alex's changes
Jan 9, 2025
5a3c59a
Merge branch 'refs/heads/main' into customization/new_carousel
Jan 9, 2025
039b483
fix: respect text alignment on mobile
ksted Jan 9, 2025
8a41396
Merge branch 'customization/new_carousel' of https://github.com/plent…
ksted Jan 9, 2025
56c8f11
Merge branch 'main' into customization/new_carousel
aoltean-plenty Jan 10, 2025
848e5de
Address PR changes
Jan 10, 2025
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
63 changes: 48 additions & 15 deletions apps/web/__tests__/fixtures/newContent.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,57 @@
{
"name": "UiHeroCarousel",
"options": {
"hero": [
"bannerItems": [
{
"image": {
"lg": "https://cdn02.plentymarkets.com/v5vzmmmcb10k/frontend/PWA/Homepage/headphones-lg.avif",
"md": "https://cdn02.plentymarkets.com/v5vzmmmcb10k/frontend/PWA/Homepage/headphones-md.avif",
"sm": "https://cdn02.plentymarkets.com/v5vzmmmcb10k/frontend/PWA/Homepage/headphones-sm.avif",
"xs": "https://cdn02.plentymarkets.com/v5vzmmmcb10k/frontend/PWA/Homepage/headphones-xs.avif"
"desktop": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/Test_Banner_Person/guy-1024.avif",
"tablet": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/Test_Banner_Person/guy-768.avif",
"mobile": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/Test_Banner_Person/guy-320.avif",
"alt": "",
"brightness": 0.5
},
"tagline": "New tagline from cypress",
"taglineColor": "#000000",
"heading": "New heading from cypress",
"headingColor": "#000000",
"description": "Description from cypress.",
"alt": "Capybara headphones",
"descriptionColor": "#000000",
"callToAction": "Discover Capybara",
"link": "/gear/headphones-capybara_157"
"text": {
"color": "#fff",
"bgcolor": "#000",
"bgopacity": 0.9,
"pretitle": "New pretitle from cypress",
"title": "New title from cypress",
"htmlDescription": "Description from cypress.",
"textAlignment": "left",
"justify": "center",
"align": "start"
},
"button": {
"label": "Discover Capybara",
"link": "/gear/headphones-capybara_157",
"variant": "primary"
}
},
{
"image": {
"desktop": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/Test_Banner_Drone/drone-A-1024.avif",
"tablet": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/Test_Banner_Drone/drone-A-768.avif",
"mobile": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/Test_Banner_Drone/drone-A-320.avif",
"alt": "",
"brightness": 0.75
},
"text": {
"color": "#fff",
"bgcolor": "#000",
"bgopacity": 1,
"pretitle": "The Future of Aerial Photography",
"title": "Drone Omega",
"htmlDescription": "A lightweight drone designed for stunning aerial footage. With a high-resolution camera on a 3-axis gimbal and up to 45 minutes of flight time, it's perfect for capturing smooth, stable video. Featuring GPS-assisted hover, obstacle avoidance, and easy portability, the Drone brings innovation and simplicity to your aerial shots.",
"textAlignment": "left",
"justify": "center",
"align": "start"
},
"button": {
"label": "Discover Omega",
"link": "/gear/drone-omega_154",
"variant": "primary"
}
}
]
}
}
}
21 changes: 13 additions & 8 deletions apps/web/__tests__/support/pageObjects/EditorObject.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { PageObject } from "./PageObject";

export class EditorObject extends PageObject {
get tagline() {
return cy.getByTestId('tagline');
get pretitle() {
return cy.getByTestId('banner-pretitle-0');
}

get headline() {
return cy.getByTestId('headline');
get title() {
return cy.getByTestId('banner-title-0');
}

get subtitle() {
return cy.getByTestId('banner-subtitle-0');
}

get description() {
return cy.getByTestId('description');
return cy.getByTestId('banner-description-0');
}

get editorToolbar() {
Expand Down Expand Up @@ -123,8 +127,9 @@ export class EditorObject extends PageObject {

checkEditorChanges() {
this.exitEditorButton.get('#close').click({ force: true });
this.tagline.should('have.text', 'New tagline from cypress');
this.headline.should('have.text', 'New heading from cypress');
this.pretitle.should('have.text', 'New pretitle from cypress');
this.title.should('have.text', 'New title from cypress');
this.subtitle.should('not.exist');
this.description.should('have.text', 'Description from cypress.');
}

Expand Down Expand Up @@ -173,7 +178,7 @@ export class EditorObject extends PageObject {
this.languageSwitcher.should('exist');
this.languageSwitcher.select('de');
cy.wait(['@getCart', '@getCategoryTree', '@getFacet']);
this.headline.first().should('have.text', 'Sound auf höchstem Niveau');
this.title.first().should('have.text', 'Dein Sound');
}

addBlockTop() {
Expand Down
9 changes: 6 additions & 3 deletions apps/web/components/PageBlock/PageBlock.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
<template>
<div
:class="[
'relative max-w-screen-3xl mx-auto md:px-6 lg:px-10 mt-3 mb-10 group',
block.name === 'UiHeroCarousel'
ksted marked this conversation as resolved.
Show resolved Hide resolved
? 'relative mb-10 group'
: 'relative max-w-screen-3xl mx-auto md:px-6 lg:px-10 mt-3 mb-10 group',
{
'outline outline-4 outline-[#538AEA]':
isPreview && disableActions && isClicked && isTablet && clickedBlockIndex === index,
},
{ 'hover:outline hover:outline-4 hover:outline-[#538AEA]': isPreview && disableActions && !isTablet },
{ '-z-10': !isPreview },
]"
@click="tabletEdit(index)"
data-testid="block-wrapper"
>
<button
v-if="disableActions && isPreview"
@click.stop="addNewBlock(index, -1)"
class="z-[0] md:z-[0] lg:z-[10] absolute top-0 left-1/2 transform -translate-x-1/2 -translate-y-1/2 rounded-[18px] p-[6px] bg-[#538aea] text-white opacity-0 hover:opacity-100 group-hover:opacity-100 group-focus:opacity-100"
class="z-[0] md:z-[1] lg:z-[10] absolute top-0 left-1/2 transform -translate-x-1/2 -translate-y-1/2 rounded-[18px] p-[6px] bg-[#538aea] text-white opacity-0 hover:opacity-100 group-hover:opacity-100 group-focus:opacity-100"
:class="[{ 'opacity-100': isClicked && clickedBlockIndex === index }]"
data-testid="top-add-block"
>
Expand All @@ -41,7 +44,7 @@
<button
v-if="disableActions && isPreview"
@click.stop="addNewBlock(index, 1)"
class="z-[0] md:z-[0] lg:z-[10] absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-1/2 rounded-[18px] p-[6px] bg-[#538aea] text-white opacity-0 group-hover:opacity-100 group-focus:opacity-100"
class="z-[0] md:z-[1] lg:z-[10] absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-1/2 rounded-[18px] p-[6px] bg-[#538aea] text-white opacity-0 group-hover:opacity-100 group-focus:opacity-100"
:class="[{ 'opacity-100': isClicked && clickedBlockIndex === index }]"
data-testid="bottom-add-block"
>
Expand Down
157 changes: 157 additions & 0 deletions apps/web/components/ui/Banner/Banner.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<template>
<NuxtImg
:src="getImageUrl()"
:alt="props.bannerProps.image?.alt ?? ''"
class="h-[320px] w-full object-cover"
:style="{
filter: props.bannerProps.image?.brightness
? 'brightness(' + (props.bannerProps.image?.brightness ?? 1) + ')'
: '',
height: getImageHeight(),
}"
:loading="props.index > 0 ? 'lazy' : 'eager'"
:data-testid="'banner-image-' + props.index"
/>

<div
v-if="props.bannerProps.text"
:class="['absolute inset-0 p-4 flex flex-col md:basis-2/4', { 'md:p-10': props.bannerProps.text.bgcolor }]"
:style="{
color: props.bannerProps.text.color,
textAlign: getTextAlignment(),
alignItems: getContentPosition(props.bannerProps.text.align ?? ''),
justifyContent: getContentPosition(props.bannerProps.text.justify ?? ''),
}"
:data-testid="'banner-overlay-' + props.index"
>
<div
:class="bannerContentClass"
:style="{ backgroundColor: props.bannerProps.text.bgcolor, opacity: props.bannerProps.text.bgopacity }"
:data-testid="'banner-content-' + props.index"
>
<div
v-if="props.bannerProps.text.pretitle"
class="typography-headline-6 font-bold tracking-widest"
:data-testid="'banner-pretitle-' + props.index"
>
{{ props.bannerProps.text.pretitle }}
</div>
<h1
v-if="props.bannerProps.text.title"
class="typography-display-3 md:typography-display-2 lg:typography-display-1 font-bold my-2 lg:leading-[4rem]"
:data-testid="'banner-title-' + props.index"
>
{{ props.bannerProps.text.title }}
</h1>

<div
v-if="props.bannerProps.text.subtitle"
class="typography-headline-6 font-bold tracking-widest mb-4"
:data-testid="'banner-subtitle-' + props.index"
>
{{ props.bannerProps.text.subtitle }}
</div>

<div
v-if="props.bannerProps.text.htmlDescription"
v-html="props.bannerProps.text.htmlDescription"
class="typography-text-sm md:typography-text-lg font-normal"
:data-testid="'banner-description-' + props.index"
></div>

<UiButton
v-if="props.bannerProps.button && props.bannerProps.button.label && props.bannerProps.button.link"
class="flex flex-col md:flex-row gap-4 mt-6"
:tag="NuxtLink"
:to="localePath(props.bannerProps.button.link ?? '')"
:variant="props.bannerProps.button.variant ?? 'primary'"
size="lg"
:data-testid="'banner-button-' + props.index"
>
{{ props.bannerProps.button.label }}
</UiButton>
</div>
</div>
</template>

<script setup lang="ts">
import { BannerProps } from './types';

const NuxtLink = resolveComponent('NuxtLink');

const localePath = useLocalePath();

const viewport = useViewport();
const isMobile = computed(() => viewport.isLessThan('lg'));

const props = defineProps<{
bannerProps: BannerProps;
index: number;
}>();

const getImageUrl = () => {
switch (viewport.breakpoint.value) {
case 'lg': {
return props.bannerProps.image?.desktop ?? '';
}
case 'md': {
return props.bannerProps.image?.tablet ?? '';
}
default: {
return props.bannerProps.image?.mobile ?? '';
}
}
};

const getImageHeight = () => {
ksted marked this conversation as resolved.
Show resolved Hide resolved
switch (viewport.breakpoint.value) {
case 'lg': {
return '576px';
}
case 'md': {
return '432px';
}
default: {
return '320px';
}
}
};

const getTextAlignment = () => {
const textAlignment = props.bannerProps.text?.textAlignment ?? '';

switch (textAlignment) {
case 'center': {
return 'center';
}
case 'right': {
return 'right';
}
default: {
return 'left';
}
}
};

const getContentPosition = (axis: string) => {
if (isMobile.value) {
return 'center';
}

switch (axis) {
case 'center': {
return 'center';
}
case 'end': {
return 'flex-end';
}
default: {
return 'flex-start';
}
}
};

const bannerContentClass = computed(() => {
return isMobile.value ? 'p-4 md:p-6 rounded-lg w-full' : 'p-4 md:p-6 rounded-lg md:max-w-[50%]';
});
</script>
ksted marked this conversation as resolved.
Show resolved Hide resolved
22 changes: 22 additions & 0 deletions apps/web/components/ui/Banner/BannerSkeleton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<template>
<div class="relative">
<div class="h-[320px] md:h-[432px] lg:h-[576px] w-full bg-gray-200 animate-pulse"></div>

<div class="absolute inset-0 p-4 md:p-10 flex flex-col justify-center self-center md:basis-2/4">
<div class="p-4 md:p-6 rounded-lg md:max-w-[50%] bg-white bg-opacity-80">
<div class="h-4 w-32 bg-gray-300 rounded animate-pulse mb-2"></div>

<div class="h-12 w-64 bg-gray-300 rounded animate-pulse my-2"></div>

<div class="h-4 w-48 bg-gray-300 rounded animate-pulse mb-4"></div>

<div class="space-y-2">
<div class="h-4 w-full bg-gray-300 rounded animate-pulse"></div>
<div class="h-4 w-3/4 bg-gray-300 rounded animate-pulse"></div>
</div>

<div class="mt-6 h-12 w-36 bg-gray-300 rounded animate-pulse"></div>
</div>
</div>
</div>
</template>
Loading
Loading