Skip to content

Commit

Permalink
Merge branch 'main' into product-titles
Browse files Browse the repository at this point in the history
  • Loading branch information
abocsan-plenty authored Nov 1, 2024
2 parents 16c0951 + 390294f commit 61090a4
Show file tree
Hide file tree
Showing 12 changed files with 288 additions and 27 deletions.
68 changes: 68 additions & 0 deletions apps/web/components/Editor/Editor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<template>
<div class="mx-auto p-5">
<div class="flex items-start border rounded-md shadow-lg max-h-[500px] overflow-hidden">
<div
class="bg-primary-500 text-white text-right pr-4 pt-2 font-mono text-sm w-10 h-[500px] overflow-y-auto"
ref="lineNumberContainer"
>
<div v-for="line in lineCount" :key="line">{{ line }}</div>
</div>
<textarea
v-model="jsonText"
@input="handleInput"
@scroll="syncScroll"
ref="textarea"
class="w-full p-2 font-mono text-sm border-none resize-none outline-none h-[500px]"
:placeholder="$t('editMode.editJsonPlaceholder')"
></textarea>
</div>
<UiButton @click="formatJson" class="mt-4 px-4 py-2 text-white rounded-md bg-blue-500 hover:bg-blue-600">
{{ $t('editMode.formatJson') }}
</UiButton>
<UiButton @click="purgeJson" class="mt-4 ml-2 px-4 py-2 text-white rounded-md bg-green-500 hover:bg-green-600">
{{ $t('editMode.minifyJson') }}
</UiButton>
<UiButton @click="clearText" class="mt-4 ml-2 px-4 py-2 text-white rounded-md bg-red-500 hover:bg-red-600">
{{ $t('editMode.clearJson') }}
</UiButton>
<div v-if="errorMessage" class="text-red-500 mt-2 text-sm">{{ errorMessage }}</div>
</div>
</template>

<script setup lang="ts">
import { heroData } from './heroData';
import { mediaData } from './mediaData';
const initialJson = JSON.stringify(
{
id: 22,
hero: heroData,
valueProposition: mediaData,
featured: [
{
headline: '',
categoryId: 1,
},
{
headline: '',
categoryId: 2,
},
],
},
null,
2,
);
const {
jsonText,
errorMessage,
lineCount,
textarea,
lineNumberContainer,
syncScroll,
handleInput,
formatJson,
purgeJson,
clearText,
} = useJsonEditor(initialJson);
</script>
28 changes: 28 additions & 0 deletions apps/web/components/Editor/heroData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const heroData = [
{
image: 'https://cdn02.plentymarkets.com/mevofvd5omld/frontend/homepage-hero-headphones.avif',
tagline: 'Feel the music harder',
heading: 'Your Sound, Elevated',
description:
"Immerse yourself in rich, crystal-clear audio with our cutting-edge headphones. Designed for the ultimate listening experience, whether you're a casual listener or an audiophile. Discover the perfect blend of style, comfort, and sound quality that elevates your music to new heights.",
callToAction: 'Order Now',
link: '',
},
{
image: 'https://cdn02.plentymarkets.com/mevofvd5omld/frontend/homepage-hero-headphones.avif',
tagline: 'Experience Sound Freedom',
heading: 'Wireless. Effortless. Seamless.',
description:
'Unleash your audio with our state-of-the-art wireless earbuds. Designed for all-day comfort and uncompromised sound quality, these earbuds deliver crisp highs and deep bass, letting you enjoy your music without any distractions. Discover freedom with a perfect fit, long battery life, and intuitive controls.',
callToAction: 'Shop Earbuds',
},
{
image: 'https://cdn02.plentymarkets.com/mevofvd5omld/frontend/homepage-hero-headphones.avif',
tagline: 'Amplify Your Space',
heading: 'Big Sound, Compact Design',
description:
"Transform your space with our portable speakers that pack a punch. Crafted for superior sound performance, these speakers are perfect for home or on the go. With easy connectivity and a sleek design, elevate your listening experience whether you're indoors or outdoors.",
callToAction: 'Browse Speakers',
link: '',
},
];
7 changes: 7 additions & 0 deletions apps/web/components/Editor/mediaData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const mediaData = [
{
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='text-base mb-6 padding-right-desktop typography-text-sm md:typography-text-lg '>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',
alignment: 'left',
},
];
28 changes: 28 additions & 0 deletions apps/web/components/ui/Toolbar/Toolbar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<template>
<div class="sticky top-0 bg-[#FDD835] py-2 z-50">
<div class="flex justify-center md:justify-end pr-5 space-x-2">
<UiButton variant="secondary" :size="buttonSize" class="self-start" @click="toggleEdit">
{{ isEditing ? $t('editMode.stopEdit') : $t('editMode.edit') }}
</UiButton>
<UiButton variant="secondary" :size="buttonSize" class="self-start">
{{ $t('editMode.save') }}
</UiButton>
<UiButton variant="secondary" :size="buttonSize" class="self-start">
{{ $t('editMode.publish') }}
</UiButton>
</div>
</div>
</template>

<script setup lang="ts">
const isEditing = useEditor();
const viewport = useViewport();
const buttonSize = computed(() => {
return viewport.isLessThan('md') ? 'sm' : 'lg';
});
const toggleEdit = () => {
isEditing.value = !isEditing.value;
};
</script>
1 change: 1 addition & 0 deletions apps/web/composables/useEditor/useEditor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const useEditor = () => useState('isEditing', () => false);
12 changes: 12 additions & 0 deletions apps/web/composables/useJsonEditor/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface UseJsonEditorReturn {
jsonText: Ref<string>;
errorMessage: Ref<string>;
lineCount: Ref<number[]>;
textarea: Ref<HTMLTextAreaElement | null>;
lineNumberContainer: Ref<HTMLElement | null>;
syncScroll: () => void;
handleInput: () => void;
formatJson: () => void;
purgeJson: () => void;
clearText: () => void;
}
82 changes: 82 additions & 0 deletions apps/web/composables/useJsonEditor/useJsonEditor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
export const useJsonEditor = (initialJson: string): UseJsonEditorReturn => {
const errorMessage = ref('');
const lineCount = ref<number[]>([]);
const textarea = ref<HTMLTextAreaElement | null>(null);
const lineNumberContainer = ref<HTMLElement | null>(null);

const jsonText = ref(initialJson);

const syncScroll = () => {
if (lineNumberContainer.value && textarea.value) {
lineNumberContainer.value.scrollTop = textarea.value.scrollTop;
}
};

const updateLineCount = () => {
if (textarea.value) {
const lineBreaks = (jsonText.value.match(/\n/g) || []).length;
lineCount.value = Array.from({ length: lineBreaks + 1 }, (_, i) => i + 1);
}
};

const validateJson = () => {
try {
JSON.parse(jsonText.value);
errorMessage.value = '';
} catch (error: any) {
errorMessage.value = 'Invalid JSON: ' + error.message;
}
};

const handleInput = () => {
validateJson();
updateLineCount();
};

const formatJson = () => {
try {
const json = JSON.parse(jsonText.value);
jsonText.value = JSON.stringify(json, null, 2);
errorMessage.value = '';
nextTick(updateLineCount);
} catch (error: any) {
errorMessage.value = 'Invalid JSON: ' + error.message;
}
};

const purgeJson = () => {
try {
const json = JSON.parse(jsonText.value);
jsonText.value = JSON.stringify(json);
errorMessage.value = '';
nextTick(updateLineCount);
} catch (error: any) {
errorMessage.value = 'Invalid JSON: ' + error.message;
}
};

const clearText = () => {
jsonText.value = '';
errorMessage.value = '';
updateLineCount();
};

onMounted(() => {
updateLineCount();
});

watch(jsonText, updateLineCount);

return {
jsonText,
errorMessage,
lineCount,
textarea,
lineNumberContainer,
syncScroll,
handleInput,
formatJson,
purgeJson,
clearText,
};
};
12 changes: 11 additions & 1 deletion apps/web/lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -950,5 +950,15 @@
"add": "Der Artikel wurde der Wunschliste hinzugefügt.",
"delete": "Der Artikel wurde von der Wunschliste entfernt."
},
"youAreOfflineText": "Es scheint, dass Sie derzeit offline sind, überprüfen Sie Ihre Internetverbindung"
"youAreOfflineText": "Es scheint, dass Sie derzeit offline sind, überprüfen Sie Ihre Internetverbindung",
"editMode": {
"save": "Speichern",
"edit": "Bearbeiten",
"publish": "Veröffentlichen",
"stopEdit": "Abbrechen",
"formatJson": "Template formatieren",
"minifyJson": "Template minimieren",
"clearJson": "Template löschen",
"editJsonPlaceholder": "JSON-Template eingeben..."
}
}
12 changes: 11 additions & 1 deletion apps/web/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -950,5 +950,15 @@
"add": "The item was added to your wish list.",
"delete": "The item was removed from your wish list."
},
"youAreOfflineText": "It seems you are currently offline, check your internet connection"
"youAreOfflineText": "It seems you are currently offline, check your internet connection",
"editMode": {
"save": "Save",
"edit": "Edit",
"publish": "Publish",
"stopEdit": "Cancel",
"formatJson": "Format template",
"minifyJson": "Minify template",
"clearJson": "Clear template",
"editJsonPlaceholder": "Edit JSON template..."
}
}
11 changes: 11 additions & 0 deletions apps/web/layouts/default.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<template>
<div>
<client-only>
<UiToolbar v-show="isPreview" />
</client-only>
<UiHeader />
<NarrowContainer v-if="breadcrumbs?.length" class="p-4 md:px-0">
<LazyUiBreadcrumbs :breadcrumbs="breadcrumbs" />
Expand All @@ -25,4 +28,12 @@ const { setLogoMeta } = useStructuredData();
const { isOpen, product } = useQuickCheckout();
const viewport = useViewport();
setLogoMeta();
const isPreview = ref(false);
onMounted(() => {
const config = useRuntimeConfig().public;
const showConfigurationDrawer = config.showConfigurationDrawer;
const cookieExists = document.cookie.split('; ').some((cookie) => cookie.trim().startsWith('pwa='));
isPreview.value = cookieExists || (showConfigurationDrawer as boolean);
});
</script>
53 changes: 28 additions & 25 deletions apps/web/pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,36 +1,39 @@
<template>
<UiHeroCarousel :hero-item-props="formattedHeroItems" />
<Editor v-if="isEditing" />
<div v-else class="content">
<UiHeroCarousel :hero-item-props="formattedHeroItems" />

<NuxtLazyHydrate when-visible>
<div class="max-w-screen-3xl mx-auto md:px-6 lg:px-10 mb-10">
<UiMediaCard
v-for="(item, index) in mediaData"
:key="index"
:image="item.image"
:alt="item.alt"
:text="item.text"
:alignment="item.alignment"
/>
</div>
</NuxtLazyHydrate>

<div class="max-w-screen-3xl mx-auto md:px-6 lg:px-10 mb-10">
<NuxtLazyHydrate when-visible>
<section class="mb-10 overflow-hidden">
<p data-testid="recommended-products" class="mb-4 typography-text-lg text-center md:text-left">
{{ t('moreItemsOfThisCategory') }}
</p>
<ProductRecommendedProducts cache-key="homepage" :category-id="recommendedProductsCategoryId" />
</section>
</NuxtLazyHydrate>
<NuxtLazyHydrate when-visible>
<NewsletterSubscribe v-if="showNewsletter" />
<div class="max-w-screen-3xl mx-auto md:px-6 lg:px-10 mb-10">
<UiMediaCard
v-for="(item, index) in mediaData"
:key="index"
:image="item.image"
:alt="item.alt"
:text="item.text"
:alignment="item.alignment"
/>
</div>
</NuxtLazyHydrate>

<div class="max-w-screen-3xl mx-auto md:px-6 lg:px-10 mb-10">
<NuxtLazyHydrate when-visible>
<section class="mb-10 overflow-hidden">
<p data-testid="recommended-products" class="mb-4 typography-text-lg text-center md:text-left">
{{ t('moreItemsOfThisCategory') }}
</p>
<ProductRecommendedProducts cache-key="homepage" :category-id="recommendedProductsCategoryId" />
</section>
</NuxtLazyHydrate>
<NuxtLazyHydrate when-visible>
<NewsletterSubscribe v-if="showNewsletter" />
</NuxtLazyHydrate>
</div>
</div>
</template>

<script lang="ts" setup async>
import useHomepageData from '~/composables/useHomepageData/useHomepageData';
const isEditing = useEditor();
const { formattedHeroItems, mediaData, recommendedProductsCategoryId } = await useHomepageData();
definePageMeta({ pageType: 'static' });
const { showNewsletter } = useNewsletter();
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 @@ -8,6 +8,7 @@
- Minified and purged swiper css files for speed optimization
- Fluid logo container + max-width and max-height addaptation
- Fix cls mobile
- Edit mode toolbar + Json editor Front End

### New

Expand Down

0 comments on commit 61090a4

Please sign in to comment.