From 03a0ab0029a2d46f7f8ca1175cb06bbfda525b53 Mon Sep 17 00:00:00 2001 From: "pawel.gaca" Date: Mon, 8 Dec 2025 14:29:54 +0100 Subject: [PATCH] skeleton --- README.md | 17 +++++- klasa.js | 173 +++++++++++++++++++++++++++++++++++++++-------------- style.less | 90 +++++++++++++++++++++++----- 3 files changed, 216 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index ed15cc4..c2c8286 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ new IdmHotspot({ * @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 {number[]} [source.productsId] - Tablica ID 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.addToCompare] - Czy włączać dodawanie do porównywania + * @property {boolean|string} [options.addToBasket] - Obsługa koszyka: * - true = włącz * - false = wyłącz @@ -129,14 +130,24 @@ new IdmHotspot({ * - false = nieaktywny * - object = konfiguracja Swiper * @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.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[]} */ ``` - ###### Jedna ramka - HTML ###### ```
-
+

aaa diff --git a/klasa.js b/klasa.js index ccf5ca6..9285603 100644 --- a/klasa.js +++ b/klasa.js @@ -443,7 +443,8 @@ class IdmHotspot{ columnDesktop: 5, columnTablet: 3, columnMobile: 4, - } + }, + nameClamp: null// 2, }, options: { limit: 8, @@ -464,7 +465,7 @@ class IdmHotspot{ // WYBÓR // selectSize: false, - // selectVersion: false, + selectVersion: false, // SWIPER swiper: true, @@ -637,6 +638,7 @@ class IdmHotspot{ return singleMarkup; } + markupProductInnerHTML(prod){ // IDM DO POPRAWKI const prodExchangedData = app_shop?.fn?.getOmnibusDetails?.({productData: prod}) || app_shop.fn?.idmGetOmnibusDetails({productData: prod}); @@ -921,21 +923,26 @@ class IdmHotspot{ } markupHotspotContainer(){ - return `
-
+ return `
+ ${this.markupHotspotInnerDiv()} +
`; + } + + markupHotspotInnerDiv(){ + return `
${this?.title ? `

${this.title}

` : ""} ${this.markupHotspotSwiperContainer()} -
-
`; +

` } + markupHotspotSwiperContainer(productsHTML=""){ return `
- ${productsHTML} + ${productsHTML || this.markupSkeleton()}
@@ -943,6 +950,36 @@ class IdmHotspot{
`; } + + + + // SKELETONS MARKUPS + + markupSkeleton(){ + let skeletonMarkup = ""; + + // Tworzenie skeletonow + for(let i = 0; i <= this.options.limit; i++){ + skeletonMarkup += this.markupSingleSkeleton(); + } + + return ` +
+ ${skeletonMarkup} +
+ `; + } + markupSingleSkeleton(){ + return ` +
+
+
+
+ ${this.options.addToBasket ? `
` : ""} +
+ ` + } + // ======================================================== // HANDLERY ZDARZEŃ // ======================================================== @@ -1159,26 +1196,28 @@ class IdmHotspot{ // USTAWIANIE ZMIENNYCH CSS DLA RAMKI // ======================================================== // Ustawia się je w dwa sposoby - jako zmienne css przypisywane do ramki + jako dodaktowy tag style - cssSetAllVariables(){ this.cssVariableVersionColumnCount(); - - // css `) } + + cssSetAll(){ + this.cssSetAllVariables(); + this.cssSetAllTags(); + } // ======================================================== // FUNKCJE POMOCNICZE // ======================================================== @@ -1641,6 +1720,7 @@ class IdmHotspot{ } await this.initSwiper(); + // IDM setHeight this.setHeight({ selectors: [ @@ -1650,11 +1730,8 @@ class IdmHotspot{ container: `#${this.id} .products__wrapper`, }); this.initEvents(); + console.log(`Initialized hotspot #${this.id}`); - - // Ustawienie wszystkich zmiennych CSS - this.cssSetAllVariables(); - // funkcja wykonująca się po ramce rekomendacji if(typeof this.options?.callbackFn === "function") this.options?.callbackFn(); }catch(err){ @@ -1673,33 +1750,32 @@ class IdmHotspot{ // Zdefiniowanie funkcji do dodawania do ulubionych this.initExternalFunctions(); try{ - if(!this.products){ - if((!this?.query?.graphFn || !this?.query?.string) && !this.source?.link) this.setQueryData(); - - // pobranie danych o produktach - await this.getHotspotData(); - if(!this.products) throw new Error(idmHotspotTextObject["Nie znaleziono produktów"]); - } - - - // Wstawienie markupa na strone - if(this.hotspotEl.querySelector(".products.hotspot__products")) this.hotspotEl.querySelector(".products.hotspot__products").insertAdjacentHTML("beforeend", this.markup()); - else if(this.hotspotEl.querySelector(".hotspot")){ - this.hotspotEl.querySelector(".hotspot")?.insertAdjacentHTML("beforeend", this.markupHotspotSwiperContainer(this.markup())); - } - else{ - 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 - this.afterInit(); - }catch(err){ - console.error(idmHotspotTextObject["Wystąpił błąd"], err); - this.hotspotEl.remove(); + if(!this.products){ + if((!this?.query?.graphFn || !this?.query?.string) && !this.source?.link) this.setQueryData(); + + // pobranie danych o produktach + await this.getHotspotData(); + 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 + if(this.hotspotEl.querySelector(".products.hotspot__products")) this.hotspotEl.querySelector(".products.hotspot__products").insertAdjacentHTML("beforeend", this.markup()); + else if(this.hotspotEl.querySelector(".hotspot")){ + this.hotspotEl.querySelector(".hotspot")?.insertAdjacentHTML("beforeend", this.markupHotspotSwiperContainer(this.markup())); + } + else{ + throw new Error("Nie udało się wstawić produktów! Zła struktura HTML") + } + + // init swiper + add to basket + this.afterInit(); + }catch(err){ + console.error(idmHotspotTextObject["Wystąpił błąd"], err); + this.hotspotEl.remove(); + } } /** @@ -1709,9 +1785,6 @@ class IdmHotspot{ try{ // swiper || slick if(this.options?.swiper){ - // Opcje swipera - if(typeof this?.options?.swiper === "boolean") this.options.swiper = IdmHotspot.idmDefaultSwiperConfig; - // Wywołanie swipera const selectedSwiper = new HotspotSlider({ 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!`); + // Opcje swipera + if(typeof this?.options?.swiper === "boolean") this.options.swiper = IdmHotspot.idmDefaultSwiperConfig; + + // Wstawienie kontenera 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(); else this.fillHotspot(); diff --git a/style.less b/style.less index 03c6639..db32da0 100644 --- a/style.less +++ b/style.less @@ -1,7 +1,14 @@ +/* add to basket*/ .idm__hotspot .add_to_basket, .idm__hotspot .add_to_basket__link{ display: flex; 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{ flex-direction: column; } @@ -28,27 +35,68 @@ border-radius: 0.5rem; min-width: 3rem; } - @keyframes idm-skeleton-loading { - to { - background-position-x: -200%; - } + +/* SKELETON */ +@keyframes idm-skeleton-loading { + to { + background-position-x: -200%; } -.idm__hotspot.idm-loading{ +} + +.skeleton(@width, @height, @mobileWidth, @mobileHeight, @borderRadius) { position: relative; overflow: hidden; - transition: none; - border-radius: 8px; - background: #eee; - background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%); - background-size: 200% 100%; - animation: 1.5s idm-skeleton-loading linear infinite; - width: 100%; + &.idm-loading { + transition: none; + border-radius: @borderRadius; + background: #eee; + background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%); + background-size: 200% 100%; + animation: 1.5s idm-skeleton-loading linear infinite; + 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; + &_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) { .idm__hotspot.idm-loading{ width: 100%; @@ -335,4 +383,14 @@ clip-path: inset(0 0 0 0); } } -} \ No newline at end of file +} + +/* Ogolne */ +.idm__hotspot{ + .product__name{ + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: var(--hotspot-name-clamp, 999); + overflow: hidden; + } +}