Skip to content

Commit

Permalink
feat: text image component (#955)
Browse files Browse the repository at this point in the history
Co-authored-by: oivan-plenty <oana.ivan@plentysystems.com>
Co-authored-by: aoltean-plenty <alexandru.oltean@plentysystems.com>
Co-authored-by: Kevin Stederoth <43753494+ksted@users.noreply.github.com>
  • Loading branch information
4 people authored Jan 14, 2025
1 parent 49c381a commit 600cced
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 79 deletions.
38 changes: 38 additions & 0 deletions apps/web/components/TextContent/TextContent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<template>
<div :class="['w-full', 'space-y-4', textAlignmentClass]">
<div v-if="text?.pretitle" class="text-xl font-bold mb-2">{{ text.pretitle }}</div>
<h2 v-if="text?.title" class="text-2xl font-semibold mb-4">{{ text.title }}</h2>
<div v-if="text?.subtitle" class="text-lg font-semibold">{{ text.subtitle }}</div>
<div v-if="text?.htmlDescription" class="text-base" v-html="text.htmlDescription" />
<UiButton
v-if="button?.label && button?.link"
:tag="NuxtLink"
:to="localePath(button?.link ?? '')"
:variant="button?.variant ?? 'primary'"
class="mt-3 px-4 py-2"
>
{{ button?.label }}
</UiButton>
</div>
</template>

<script setup lang="ts">
import { defineProps, computed } from 'vue';
import type { TextContentProps } from '~/components/TextContent/types';
const props = defineProps<TextContentProps>();
const localePath = useLocalePath();
const NuxtLink = resolveComponent('NuxtLink');
const textAlignmentClass = computed(() => {
switch (props.text?.textAlignment) {
case 'center':
return 'text-center items-center';
case 'right':
return 'text-right items-end';
default:
return 'text-left items-start';
}
});
</script>
14 changes: 14 additions & 0 deletions apps/web/components/TextContent/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export type TextContentProps = {
text?: {
pretitle?: string;
title?: string;
subtitle?: string;
htmlDescription?: string;
textAlignment?: 'left' | 'center' | 'right';
};
button?: {
label?: string;
link?: string;
variant?: 'primary' | 'secondary';
};
};
52 changes: 52 additions & 0 deletions apps/web/components/ui/ImageText/ImageText.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<template>
<div :class="['flex flex-col md:flex-row items-center', positionClass]">
<div :class="['md:w-1/2']">
<NuxtImg
:src="getImageUrl()"
:alt="props.image?.alt"
class="mx-auto h-auto object-cover"
:width="getImageDimensions().width"
:height="getImageDimensions().height"
/>
</div>
<TextContent :text="props.text" :button="props.button" />
</div>
</template>

<script setup lang="ts">
import type { ImageTextProps, ImageDimensions } from '~/components/ui/ImageText/types';
const viewport = useViewport();
const props = defineProps<ImageTextProps>();
const positionClass = computed(() => (props.image?.imageAlignment === 'right' ? 'md:flex-row-reverse' : 'md:flex-row'));
const getImageUrl = () => {
switch (viewport.breakpoint.value) {
case 'lg': {
return props.image?.desktop;
}
case 'md': {
return props.image?.tablet;
}
default: {
return props.image?.mobile;
}
}
};
const getImageDimensions = (): ImageDimensions => {
switch (viewport.breakpoint.value) {
case 'lg': {
return { width: 1200, height: 800 };
}
case 'md': {
return { width: 800, height: 533 };
}
default: {
return { width: 400, height: 267 };
}
}
};
</script>
27 changes: 27 additions & 0 deletions apps/web/components/ui/ImageText/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export type ImageTextProps = {
image?: {
desktop?: string;
tablet?: string;
mobile?: string;
alt: string;
imageAlignment: 'left' | 'right';
};

text?: {
pretitle?: string;
title?: string;
subtitle?: string;
htmlDescription?: string;
textAlignment?: 'left' | 'center' | 'right';
};
button?: {
label?: string;
link?: string;
variant?: 'primary' | 'secondary';
};
};

export interface ImageDimensions {
width: number;
height: number;
}
41 changes: 0 additions & 41 deletions apps/web/components/ui/MediaCard/MediaCard.vue

This file was deleted.

6 changes: 0 additions & 6 deletions apps/web/components/ui/MediaCard/types.ts

This file was deleted.

25 changes: 4 additions & 21 deletions apps/web/components/ui/TextCard/TextCard.vue
Original file line number Diff line number Diff line change
@@ -1,39 +1,22 @@
<template>
<div :class="['w-full', 'flex', 'flex-col', 'items-start', 'p-5', 'space-y-4', textAlignmentClass]">
<div v-if="props.text?.pretitle" class="text-xl font-bold mb-2">{{ props.text.pretitle }}</div>
<h2 v-if="props.text?.title" class="text-2xl font-semibold mb-4">{{ props.text.title }}</h2>
<div v-if="props.text?.subtitle" class="text-lg font-semibold">{{ props.text.subtitle }}</div>
<div v-if="props.text?.htmlDescription" class="text-base" v-html="props.text.htmlDescription" />
<UiButton
v-if="props.button?.label && props.button?.link"
:tag="NuxtLink"
:to="localePath(props.button?.link ?? '')"
:variant="props.button?.variant ?? 'primary'"
class="mt-3 px-4 py-2"
>
{{ props.button?.label }}
</UiButton>
<TextContent :text="props.text" :button="props.button" />
</div>
</template>

<script setup lang="ts">
import type { TextCardProps } from '~/components/ui/TextCard/types';
const props = defineProps<TextCardProps>();
const localePath = useLocalePath();
const NuxtLink = resolveComponent('NuxtLink');
const textAlignmentClass = computed(() => {
switch (props.text?.textAlignment) {
case 'center': {
case 'center':
return 'text-center items-center';
}
case 'right': {
case 'right':
return 'text-right items-end';
}
default: {
default:
return 'text-left items-start';
}
}
});
</script>
25 changes: 20 additions & 5 deletions apps/web/composables/useHomepage/homepageTemplateDataDe.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,27 @@
}
},
{
"name": "UiMediaCard",
"name": "UiImageText",
"options": {
"text": "<div class='flex flex-col mt-5 sm:mt-20 mt-0 sm:p-0 p-5 text-center sm:text-left'><span class='text-xl font-bold mb-2'>Die Zukunft des Klangs</span><h2 class='text-2xl font-semibold mb-4'>Das neue Hörerlebnis</h2><p class='typography-text-sm md:typography-text-lg mb-6 padding-right-desktop'>Unsere Kopfhörer-Kollektion setzt neue Maßstäbe in Sachen Audio-Präzision. Mit tiefem Bass, klaren Höhen und einem eindrucksvollen Klangbild bieten diese Kopfhörer ein einzigartiges Hörerlebnis für jedes Musikgenre. Mit Ihrer Kombination aus modernem Design, höchstem Komfort und neuester Technologie sind sie die perfekte Wahl für alle, die keine Kompromisse bei der Klangqualität eingehen möchten.</p><ul class='list-disc list-inside typography-text-sm md:typography-text-lg '><li>Premium-Sound in Studioqualität</li><li>Elegant und formschön</li><li>Lange Akkulaufzeit</li><li>Kabellose Verbindung via Bluetooth</li></ul></div>",
"image": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/headphones-mediacard.avif",
"alt": "Headphones",
"alignment": "left"
"text": {
"htmlDescription": "Willkommen in unserem Shop, in dem Technikbegeisterte und Modeliebhaber gleichermaßen fündig werden! Von Premium-Kopfhörern und Hochleistungsdrohnen bis hin zu stylischer Kleidung bieten wir alles, was Ihr Leben smarter und Ihren Style einzigartig macht. Unsere Mission ist es, Ihnen eine sorgfältig zusammengestellte Auswahl an Produkten zu bieten, die Qualität, Innovation und Design vereinen. Egal, ob Sie einen neuen Lautsprecher für perfekten Sound oder einen lässigen Hoodie suchen, um Ihren Look zu vervollständigen – bei uns sind Sie an der richtigen Adresse.",
"title": "Entdecken Sie Technik und Stil",
"subtitle": "Innovative Technologie trifft moderne Mode",
"pretitle": "Willkommen in Ihrem neuen Lieblingsshop",
"textAlignment": "left"
},
"button": {
"label": "Get Started",
"link": "",
"variant": "primary"
},
"image": {
"desktop": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/headphones-mediacard.avif",
"tablet": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/headphones-mediacard.avif",
"mobile": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/headphones-mediacard.avif",
"alt": "Headphones",
"imageAlignment": "right"
}
}
},
{
Expand Down
25 changes: 20 additions & 5 deletions apps/web/composables/useHomepage/homepageTemplateDataEn.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,27 @@
}
},
{
"name": "UiMediaCard",
"name": "UiImageText",
"options": {
"text": "<div class='flex flex-col mt-5 sm:mt-20 mt-0 sm:p-0 p-5 text-center sm:text-left'><span class='text-xl font-bold mb-2'>Experience the Future of Sound</span><h2 class='text-2xl font-semibold mb-4'>Redefine Your Listening Experience</h2><p class='typography-text-sm md:typography-text-lg mb-6 padding-right-desktop'>Our latest collection of headphones is designed to deliver unparalleled audio precision, with deep bass, clear highs, and an immersive experience for every genre of music. Combining sleek design, comfort, and cutting-edge technology, these headphones are made for those who refuse to compromise on sound quality.</p><ul class='list-disc list-inside typography-text-sm md:typography-text-lg '><li>Premium, studio-quality sound</li><li>Comfortable fit for extended listening</li><li>Long-lasting battery life</li><li>Seamless wireless connectivity</li></ul></div>",
"image": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/headphones-mediacard.avif",
"alt": "Headphones",
"alignment": "right"
"text": {
"htmlDescription": "Welcome to our shop, where tech enthusiasts and fashion lovers alike will find exactly what they’re looking for! From premium headphones and high-performance drones to stylish clothing, we offer everything to make your life smarter and your style unique.Our mission is to provide you with a carefully curated selection of products that combine quality, innovation, and design. Whether you’re in search of a new speaker for perfect sound or a casual hoodie to complete your look – we’ve got you covered.",
"title": "Discover Tech & Style",
"subtitle": "Innovative technology meets modern fashion",
"pretitle": "Welcome to your new favorite shop",
"textAlignment": "left"
},
"button": {
"label": "Get Started",
"link": "",
"variant": "primary"
},
"image": {
"desktop": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/headphones-mediacard.avif",
"tablet": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/headphones-mediacard.avif",
"mobile": "https://cdn02.plentymarkets.com/mevofvd5omld/frontend/headphones-mediacard.avif",
"alt": "Headphones",
"imageAlignment": "right"
}
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion apps/web/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ const addNewBlock = (index: number, position: number) => {
const getComponent = (name: string) => {
if (name === 'NewsletterSubscribe') return resolveComponent('NewsletterSubscribe');
if (name === 'UiHeroCarousel') return resolveComponent('UiHeroCarousel');
if (name === 'UiMediaCard') return resolveComponent('UiMediaCard');
if (name === 'UiTextCard') return resolveComponent('UiTextCard');
if (name === 'UiImageText') return resolveComponent('UiImageText');
if (name === 'ProductRecommendedProducts') return resolveComponent('ProductRecommendedProducts');
};
Expand Down
1 change: 1 addition & 0 deletions docs/changelog/changelog_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Added delivery days to checkout shipping providers.
- Added robots for category page.
- Subtitle, pretitle and title options where added to the Recommened Products component
- Media Card is now Image Text

### 🩹 Fixed

Expand Down

0 comments on commit 600cced

Please sign in to comment.