This commit is contained in:
2025-12-08 14:29:54 +01:00
parent 5f194e862f
commit 03a0ab0029
3 changed files with 216 additions and 64 deletions

View File

@@ -93,7 +93,7 @@ new IdmHotspot({
* @property {object} source - Dane źródłowe dla hotspotu. * @property {object} source - Dane źródłowe dla hotspotu.
* @property {string} [source.link] - link do listingu z którego mają być pobierane produkty (NIEZALECANE) * @property {string} [source.link] - link do listingu z którego mają być pobierane produkty (NIEZALECANE)(Reszta opcji source nie zadziała!!)
* @property {string} [source.hotspotType] - Typ hotspotu (np. "promotion"). * @property {string} [source.hotspotType] - Typ hotspotu (np. "promotion").
* @property {number[]} [source.productsId] - Tablica ID produktów. * @property {number[]} [source.productsId] - Tablica ID produktów.
* @property {number} [source.productsMenu] - Identyfikator menu produktów. * @property {number} [source.productsMenu] - Identyfikator menu produktów.
@@ -119,6 +119,7 @@ new IdmHotspot({
* @property {boolean} [options.addToFavorites] - Czy włączać dodawanie do ulubionych(DZIAŁA TYLKO PO ZMIANACH SZABLONOWYCH) * @property {boolean} [options.addToFavorites] - Czy włączać dodawanie do ulubionych(DZIAŁA TYLKO PO ZMIANACH SZABLONOWYCH)
* @property {boolean} [options.addToCompare] - Czy włączać dodawanie do porównywania * @property {boolean} [options.addToCompare] - Czy włączać dodawanie do porównywania
* @property {boolean|string} [options.addToBasket] - Obsługa koszyka: * @property {boolean|string} [options.addToBasket] - Obsługa koszyka:
* - true = włącz * - true = włącz
* - false = wyłącz * - false = wyłącz
@@ -129,14 +130,24 @@ new IdmHotspot({
* - false = nieaktywny * - false = nieaktywny
* - object = konfiguracja Swiper * - object = konfiguracja Swiper
* @property {boolean} [options.swiperScrollbar] - Czy włączać scrollbar w swiperze - DO DZIAŁANIA WYMAGA WŁĄCZONEGO SWIPERA * @property {boolean} [options.swiperScrollbar] - Czy włączać scrollbar w swiperze - DO DZIAŁANIA WYMAGA WŁĄCZONEGO SWIPERA
* @property {boolean} [options.showOpinions] - Czy wyświetlać opinie o produkcie w formie gwiazdek nad nazwą * @property {boolean} [options.showOpinions] - Czy wyświetlać opinie o produkcie w formie gwiazdek nad nazwą
* @property {boolean} [options.showSecondImage] - Czy wyświetlać drugie zdjęcie na hover * @property {boolean} [options.showSecondImage] - Czy wyświetlać drugie zdjęcie na hover
* @property {boolean} [options.selectVersion] - Pokazywanie multiwersji
* *
* @property {object} cssVariables - Obiekt z opcjami zmiennych CSS wgrywanymi do danej ramki rekomendacji
* @property {object} [cssVariables.version] - Obiekt ze zmiennymi css dla wersji
* @property {number} [cssVariables.version.columnDesktop] - liczba kolumn wersji na desktop
* @property {number} [cssVariables.version.columnTablet] - liczba kolumn wersji na tablecie
* @property {number} [cssVariables.version.columnMobile] - liczba kolumn wersji na mobile
* @property {number} [cssVariables.nameClamp] - liczba wyświetlanych linijek tekstu nazwy produktu
* @type {Hotspot[]} * @type {Hotspot[]}
*/ */
``` ```
###### Jedna ramka - HTML ###### ###### Jedna ramka - HTML ######
``` ```
<section id="idmBlogHotspot1" <section id="idmBlogHotspot1"
@@ -144,7 +155,7 @@ new IdmHotspot({
data-products-id="589,180,181590" data-products-id="589,180,181590"
data-lazy="true" data-lazy="true"
> >
<div class="hotspot --initialized"> <div class="hotspot">
<h3 class="hotspot__name headline__wrapper"> <h3 class="hotspot__name headline__wrapper">
<span class="headline"> <span class="headline">
<span class="headline__name" aria-label="aaa">aaa</span> <span class="headline__name" aria-label="aaa">aaa</span>

127
klasa.js
View File

@@ -443,7 +443,8 @@ class IdmHotspot{
columnDesktop: 5, columnDesktop: 5,
columnTablet: 3, columnTablet: 3,
columnMobile: 4, columnMobile: 4,
} },
nameClamp: null// 2,
}, },
options: { options: {
limit: 8, limit: 8,
@@ -464,7 +465,7 @@ class IdmHotspot{
// WYBÓR // WYBÓR
// selectSize: false, // selectSize: false,
// selectVersion: false, selectVersion: false,
// SWIPER // SWIPER
swiper: true, swiper: true,
@@ -637,6 +638,7 @@ class IdmHotspot{
return singleMarkup; return singleMarkup;
} }
markupProductInnerHTML(prod){ markupProductInnerHTML(prod){
// IDM DO POPRAWKI // IDM DO POPRAWKI
const prodExchangedData = app_shop?.fn?.getOmnibusDetails?.({productData: prod}) || app_shop.fn?.idmGetOmnibusDetails({productData: prod}); const prodExchangedData = app_shop?.fn?.getOmnibusDetails?.({productData: prod}) || app_shop.fn?.idmGetOmnibusDetails({productData: prod});
@@ -921,21 +923,26 @@ class IdmHotspot{
} }
markupHotspotContainer(){ markupHotspotContainer(){
return `<section id="${this.id}" class="hotspot__wrapper idm__hotspot --init idm-loading ${this?.classes}"> return `<section id="${this.id}" class="hotspot__wrapper idm__hotspot --init --hotspot-loading ${this?.classes}">
<div class="hotspot --initialized"> ${this.markupHotspotInnerDiv()}
</section>`;
}
markupHotspotInnerDiv(){
return `<div class="hotspot --initialized">
${this?.title ? ` ${this?.title ? `
<h3 class="hotspot__name headline__wrapper"> <h3 class="hotspot__name headline__wrapper">
<span class="headline"><span class="headline__name" aria-label="${this.title}">${this.title}</span></span> <span class="headline"><span class="headline__name" aria-label="${this.title}">${this.title}</span></span>
</h3> </h3>
` : ""} ` : ""}
${this.markupHotspotSwiperContainer()} ${this.markupHotspotSwiperContainer()}
</div> </div>`
</section>`;
} }
markupHotspotSwiperContainer(productsHTML=""){ markupHotspotSwiperContainer(productsHTML=""){
return `<div class="products__wrapper swiper"> return `<div class="products__wrapper swiper">
<div class="products hotspot__products swiper-wrapper"> <div class="products hotspot__products swiper-wrapper">
${productsHTML} ${productsHTML || this.markupSkeleton()}
</div> </div>
</div> </div>
<div class="swiper-button-prev --rounded --edge idm-button-prev"><i class="icon-angle-left"></i></div> <div class="swiper-button-prev --rounded --edge idm-button-prev"><i class="icon-angle-left"></i></div>
@@ -943,6 +950,36 @@ class IdmHotspot{
<div class="swiper-pagination"></div>`; <div class="swiper-pagination"></div>`;
} }
// SKELETONS MARKUPS
markupSkeleton(){
let skeletonMarkup = "";
// Tworzenie skeletonow
for(let i = 0; i <= this.options.limit; i++){
skeletonMarkup += this.markupSingleSkeleton();
}
return `
<div class="idm_hotspot__skeleton">
${skeletonMarkup}
</div>
`;
}
markupSingleSkeleton(){
return `
<div class="idm_hotspot__skeleton_product">
<div class="idm_hotspot__skeleton_img idm-loading"></div>
<div class="idm_hotspot__skeleton_name idm-loading"></div>
<div class="idm_hotspot__skeleton_price idm-loading"></div>
${this.options.addToBasket ? `<div class="idm_hotspot__skeleton_btn idm-loading"></div>` : ""}
</div>
`
}
// ======================================================== // ========================================================
// HANDLERY ZDARZEŃ // HANDLERY ZDARZEŃ
// ======================================================== // ========================================================
@@ -1159,26 +1196,28 @@ class IdmHotspot{
// USTAWIANIE ZMIENNYCH CSS DLA RAMKI // USTAWIANIE ZMIENNYCH CSS DLA RAMKI
// ======================================================== // ========================================================
// Ustawia się je w dwa sposoby - jako zmienne css przypisywane do ramki + jako dodaktowy tag style // Ustawia się je w dwa sposoby - jako zmienne css przypisywane do ramki + jako dodaktowy tag style
cssSetAllVariables(){ cssSetAllVariables(){
this.cssVariableVersionColumnCount(); this.cssVariableVersionColumnCount();
this.cssVariableNameClamp();
// css <style/> }
cssSetAllTags(){
this.cssInsertStyleTag(); this.cssInsertStyleTag();
} }
cssVariableNameClamp(){
if(this.cssVariables?.nameClamp) this.cssSetVariable("--hotspot-name-clamp", this.cssVariables.nameClamp);
}
cssVariableVersionColumnCount(){ cssVariableVersionColumnCount(){
this.cssSetVariable("--version-desktop-columns", this.cssVariables?.version?.columnDesktop || 5) this.cssSetVariable("--version-desktop-columns", this.cssVariables?.version?.columnDesktop || 5)
this.cssSetVariable("--version-tablet-columns", this.cssVariables?.version?.columnTablet || 3) this.cssSetVariable("--version-tablet-columns", this.cssVariables?.version?.columnTablet || 3)
this.cssSetVariable("--version-mobile-columns", this.cssVariables?.version?.columnMobile || 4) this.cssSetVariable("--version-mobile-columns", this.cssVariables?.version?.columnMobile || 4)
} }
cssSetVariable(name, value){ cssSetVariable(name, value){
this.hotspotEl.style.setProperty(name, value); this.hotspotEl.style.setProperty(name, value);
} }
cssVersionColumnStyle(){ cssVersionColumnStyle(){
return ` return `
@media (max-width: 756px){ @media (max-width: 756px){
@@ -1199,13 +1238,53 @@ class IdmHotspot{
` `
} }
cssSkeletonStyle(){
let skeletonStyles = "";
const skeletonStylesObj = {};
// Budowanie skeletona w zależności od ustawień hotspota
if(this.options.swiper){
skeletonStylesObj[0] = this.options.swiper?.slidesPerView;
for (const [key, value] of Object.entries(this.options.swiper.breakpoints)) {
if(value.slidesPerView) skeletonStylesObj[key] = value.slidesPerView
}
}else{
// mobile 2
skeletonStylesObj[0] = 2;
// desktop + tablet 4
skeletonStylesObj[757] = 4;
}
for (const [key, value] of Object.entries(skeletonStylesObj)) {
let style = `
#${this.hotspotEl.id}.hotspot__wrapper.idm__hotspot.--hotspot-loading .idm_hotspot__skeleton_product{
width: ${(1 / value) * 100}%
}
`
skeletonStyles += key === 0 ? style : `
@media (min-width: ${key}px){
${style}
}
`
}
return skeletonStyles;
}
cssInsertStyleTag(){ cssInsertStyleTag(){
this.hotspotEl.insertAdjacentHTML("beforeend", ` this.hotspotEl.insertAdjacentHTML("beforeend", `
<style> <style>
${this.cssVersionColumnStyle()} ${this.cssVersionColumnStyle()}
${this.cssSkeletonStyle()}
</style>`) </style>`)
} }
cssSetAll(){
this.cssSetAllVariables();
this.cssSetAllTags();
}
// ======================================================== // ========================================================
// FUNKCJE POMOCNICZE // FUNKCJE POMOCNICZE
// ======================================================== // ========================================================
@@ -1641,6 +1720,7 @@ class IdmHotspot{
} }
await this.initSwiper(); await this.initSwiper();
// IDM setHeight // IDM setHeight
this.setHeight({ this.setHeight({
selectors: [ selectors: [
@@ -1650,11 +1730,8 @@ class IdmHotspot{
container: `#${this.id} .products__wrapper`, container: `#${this.id} .products__wrapper`,
}); });
this.initEvents(); this.initEvents();
console.log(`Initialized hotspot #${this.id}`); console.log(`Initialized hotspot #${this.id}`);
// Ustawienie wszystkich zmiennych CSS
this.cssSetAllVariables();
// funkcja wykonująca się po ramce rekomendacji // funkcja wykonująca się po ramce rekomendacji
if(typeof this.options?.callbackFn === "function") this.options?.callbackFn(); if(typeof this.options?.callbackFn === "function") this.options?.callbackFn();
}catch(err){ }catch(err){
@@ -1681,6 +1758,8 @@ class IdmHotspot{
if(!this.products) throw new Error(idmHotspotTextObject["Nie znaleziono produktów"]); if(!this.products) throw new Error(idmHotspotTextObject["Nie znaleziono produktów"]);
} }
this.hotspotEl.querySelector(".idm_hotspot__skeleton")?.remove();
this.hotspotEl.classList.remove("--hotspot-loading");
// Wstawienie markupa na strone // Wstawienie markupa na strone
if(this.hotspotEl.querySelector(".products.hotspot__products")) this.hotspotEl.querySelector(".products.hotspot__products").insertAdjacentHTML("beforeend", this.markup()); if(this.hotspotEl.querySelector(".products.hotspot__products")) this.hotspotEl.querySelector(".products.hotspot__products").insertAdjacentHTML("beforeend", this.markup());
@@ -1691,9 +1770,6 @@ class IdmHotspot{
throw new Error("Nie udało się wstawić produktów! Zła struktura HTML") throw new Error("Nie udało się wstawić produktów! Zła struktura HTML")
} }
this.hotspotEl.classList.remove("idm-loading");
// init swiper + add to basket // init swiper + add to basket
this.afterInit(); this.afterInit();
}catch(err){ }catch(err){
@@ -1709,9 +1785,6 @@ class IdmHotspot{
try{ try{
// swiper || slick // swiper || slick
if(this.options?.swiper){ if(this.options?.swiper){
// Opcje swipera
if(typeof this?.options?.swiper === "boolean") this.options.swiper = IdmHotspot.idmDefaultSwiperConfig;
// Wywołanie swipera // Wywołanie swipera
const selectedSwiper = new HotspotSlider({ const selectedSwiper = new HotspotSlider({
selector: `#${this.id} .swiper`, selector: `#${this.id} .swiper`,
@@ -1788,7 +1861,17 @@ class IdmHotspot{
if(this.options?.devMode && dev !== "true") return console.error(`Brak włączonego devMode. Ramka ${this.id} nie mogła zostać utworzona!`); if(this.options?.devMode && dev !== "true") return console.error(`Brak włączonego devMode. Ramka ${this.id} nie mogła zostać utworzona!`);
// Opcje swipera
if(typeof this?.options?.swiper === "boolean") this.options.swiper = IdmHotspot.idmDefaultSwiperConfig;
// Wstawienie kontenera
if(!this.hotspotEl || !document.contains(this.hotspotEl)) this.initHotspotContainer(); if(!this.hotspotEl || !document.contains(this.hotspotEl)) this.initHotspotContainer();
else if(!this.hotspotEl.querySelector(".hotspot")) this.hotspotEl.innerHTML = this.markupHotspotInnerDiv();
else if(!this.hotspotEl.querySelector(".products__wrapper")) this.hotspotEl.querySelector(".hotspot").insertAdjacentHTML("beforeend", this.markupHotspotSwiperContainer())
// Ustawienie wszystkich zmiennych CSS
this.cssSetAll();
if(this.options?.lazy) this.handleObserveHotspotOnce(); if(this.options?.lazy) this.handleObserveHotspotOnce();
else this.fillHotspot(); else this.fillHotspot();

View File

@@ -1,7 +1,14 @@
/* add to basket*/
.idm__hotspot .add_to_basket, .idm__hotspot .add_to_basket__link{ .idm__hotspot .add_to_basket, .idm__hotspot .add_to_basket__link{
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
@media (max-width: 978px){
.idm__hotspot .add_to_basket__button.btn:not(.--error):not(.--success)::before{
position: static;
}
}
.idm__hotspot .add_to_basket.--range{ .idm__hotspot .add_to_basket.--range{
flex-direction: column; flex-direction: column;
} }
@@ -28,27 +35,68 @@
border-radius: 0.5rem; border-radius: 0.5rem;
min-width: 3rem; min-width: 3rem;
} }
@keyframes idm-skeleton-loading {
/* SKELETON */
@keyframes idm-skeleton-loading {
to { to {
background-position-x: -200%; background-position-x: -200%;
} }
} }
.idm__hotspot.idm-loading{
.skeleton(@width, @height, @mobileWidth, @mobileHeight, @borderRadius) {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
&.idm-loading {
transition: none; transition: none;
border-radius: 8px; border-radius: @borderRadius;
background: #eee; background: #eee;
background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%); background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%);
background-size: 200% 100%; background-size: 200% 100%;
animation: 1.5s idm-skeleton-loading linear infinite; animation: 1.5s idm-skeleton-loading linear infinite;
width: 100%; width: @width;
height: @height;
@media (max-width: 756px) {
width: @mobileWidth;
height: @mobileHeight;
}
}
}
.--hotspot-loading .products.hotspot__products.swiper-wrapper{
display: block!important;
}
.idm_hotspot__skeleton{
display: flex;
flex-wrap: nowrap;
overflow: hidden;
height: 50rem; height: 50rem;
&_product{
flex-shrink: 0;
padding-right: 16px;
display: flex;
flex-direction: column;
gap: 1rem;
}
&_img{
aspect-ratio: ~"1 / 1";
.skeleton(100%, auto, 100%, auto, 8px);
}
&_name{
.skeleton(100%, 4.2rem, 100%, 4.2rem, 0)
}
&_price{
.skeleton(50%, 2rem, 50%, 2rem, 0)
}
&_btn{
.skeleton(100%, 4.6rem, 100%, 4.6rem, 8px)
}
} }
.idm__hotspot.idm-loading .hotspot{
opacity: 0;
}
@media (max-width: 756px) { @media (max-width: 756px) {
.idm__hotspot.idm-loading{ .idm__hotspot.idm-loading{
width: 100%; width: 100%;
@@ -336,3 +384,13 @@
} }
} }
} }
/* Ogolne */
.idm__hotspot{
.product__name{
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: var(--hotspot-name-clamp, 999);
overflow: hidden;
}
}