commit 8d4ff16d9beb8707ee1c538d83b7dd158fbf9d9b Author: jzitnik-dev Date: Fri May 22 10:54:32 2026 +0200 initial commit, cuz im getting lost in this diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..88f092a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +compiled.js diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..a8890b2 --- /dev/null +++ b/TODO.md @@ -0,0 +1,4 @@ +- Account and login in header + + +- Slider changable time in UI diff --git a/global/route.regexpr b/global/route.regexpr new file mode 100644 index 0000000..0b19940 --- /dev/null +++ b/global/route.regexpr @@ -0,0 +1 @@ +^[\s\S]*$ diff --git a/global/templates/header/config.yaml b/global/templates/header/config.yaml new file mode 100644 index 0000000..a5194a2 --- /dev/null +++ b/global/templates/header/config.yaml @@ -0,0 +1,3 @@ +original_template: + default_styles: + disable: true diff --git a/global/templates/header/replace_selector b/global/templates/header/replace_selector new file mode 100644 index 0000000..9f5d3b2 --- /dev/null +++ b/global/templates/header/replace_selector @@ -0,0 +1 @@ +#header diff --git a/global/templates/header/scrape.js b/global/templates/header/scrape.js new file mode 100644 index 0000000..408f16b --- /dev/null +++ b/global/templates/header/scrape.js @@ -0,0 +1,62 @@ +(() => { + const header = document.querySelector("#header"); + + // Extract Logo + const logoEl = header.querySelector(".vc-headerlogo img"); + const logo = { + src: logoEl ? logoEl.src : '', + alt: logoEl ? logoEl.alt : '', + }; + + const customContentBlock = header.querySelector(".custom-content-block.custom-content-header-1 > .content"); + const customContentHeader = customContentBlock ? customContentBlock.innerHTML : ''; + + function extractMenuTree(ulElement) { + if (!ulElement) return []; + + const listItems = Array.from(ulElement.children).filter(el => el.tagName === 'LI'); + + return listItems.map(li => { + const link = li.querySelector(":scope > a"); + + const itemData = { + text: link ? link.textContent.trim() : '', + href: link ? link.href : '' + }; + + const subMenu = li.querySelector(":scope > ul[role='menu']"); + if (subMenu) { + itemData.sublinks = extractMenuTree(subMenu); + } + + return itemData; + }); + } + + const rootMenu = header.querySelector("#menu #menucategories nav ul[role='menu']"); + const menuData = extractMenuTree(rootMenu); + + const menuTop = header.querySelector("#menutop ul[role='menu']"); + const menuTopLinks = menuTop.querySelectorAll("li > a"); + const menuTopData = Array.from(menuTopLinks).map(link => ({ + text: link.textContent.trim(), + href: link.href + })); + + const itemCountBasket = parseInt(header.querySelector("#basketinfo .vc-basketinfoextended-numberofitems").textContent) || 0; + + const basket = { + itemCount: itemCountBasket, + link: header.querySelector("#basketinfo .vc-basketinfoextended-header").href || '/kosik' + } + + return { + logo, + customContentHeader, + menu: { + top: menuTopData, + main: menuData + }, + basket, + }; +})(); diff --git a/global/templates/header/style.css b/global/templates/header/style.css new file mode 100644 index 0000000..e69de29 diff --git a/global/templates/header/template.html b/global/templates/header/template.html new file mode 100644 index 0000000..353f3ac --- /dev/null +++ b/global/templates/header/template.html @@ -0,0 +1,792 @@ + diff --git a/homepage/route.regexpr b/homepage/route.regexpr new file mode 100644 index 0000000..7c04454 --- /dev/null +++ b/homepage/route.regexpr @@ -0,0 +1 @@ +^/$ diff --git a/homepage/style.css b/homepage/style.css new file mode 100644 index 0000000..ddf9493 --- /dev/null +++ b/homepage/style.css @@ -0,0 +1,6 @@ +#AjaxMainSection { + display: flex; + flex-direction: column; + gap: 1.5rem; + padding-top: 1.5rem; +} diff --git a/homepage/templates/banners_under_slider/replace_selector b/homepage/templates/banners_under_slider/replace_selector new file mode 100644 index 0000000..d2503ef --- /dev/null +++ b/homepage/templates/banners_under_slider/replace_selector @@ -0,0 +1 @@ +main#main #AjaxMainSection section.section_top_after diff --git a/homepage/templates/banners_under_slider/scrape.js b/homepage/templates/banners_under_slider/scrape.js new file mode 100644 index 0000000..ea41187 --- /dev/null +++ b/homepage/templates/banners_under_slider/scrape.js @@ -0,0 +1,20 @@ +(() => { + const main = document.querySelector("main#main #AjaxMainSection section.section_top_after .content"); + + const items = main.querySelectorAll("ul > li"); + + const data = Array.from(items).map((item) => { + const image = item.querySelector("img").src; + const alt = item.querySelector("img").getAttribute("title"); + + const content = item.querySelector("div").innerHTML; + + return { + image, + alt, + content, + }; + }); + + return data; +})(); diff --git a/homepage/templates/banners_under_slider/style.css b/homepage/templates/banners_under_slider/style.css new file mode 100644 index 0000000..a95ea21 --- /dev/null +++ b/homepage/templates/banners_under_slider/style.css @@ -0,0 +1,140 @@ +:root { + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --font-sans: 'Geist', 'Geist Fallback', ui-sans-serif, system-ui, sans-serif; + } + + .promo-cards-section { + font-family: var(--font-sans); + padding: 3rem 0; /* py-12 */ + } + @media (min-width: 1024px) { + .promo-cards-section { padding: 4rem 0; /* lg:py-16 */ } + } + + .promo-container { + max-width: 80rem; /* max-w-7xl */ + margin: 0 auto; + padding: 0 1rem; /* px-4 */ + } + @media (min-width: 640px) { .promo-container { padding: 0 1.5rem; /* sm:px-6 */ } } + @media (min-width: 1024px) { .promo-container { padding: 0 2rem; /* lg:px-8 */ } } + + .promo-grid { + display: grid; + grid-template-columns: 1fr; + gap: 1rem; /* gap-4 */ + } + @media (min-width: 768px) { + .promo-grid { + grid-template-columns: repeat(3, 1fr); /* md:grid-cols-3 */ + gap: 1.5rem; /* md:gap-6 */ + } + } + + .promo-card { + position: relative; + aspect-ratio: 3 / 2; + border-radius: 0.75rem; /* rounded-xl */ + overflow: hidden; + display: block; + text-decoration: none; + /* Acts as 'group' class */ + } + + .promo-card-img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.5s ease-in-out; + } + + .promo-card:hover .promo-card-img { + transform: scale(1.05); /* group-hover:scale-105 */ + } + + .promo-card-overlay { + position: absolute; + inset: 0; + background: linear-gradient(to top, color-mix(in srgb, var(--primary) 80%, transparent), transparent); + pointer-events: none; + z-index: 1; + } + + .promo-card-content { + position: absolute; + inset: 0; + padding: 1.5rem; /* p-6 */ + z-index: 2; + } + + /* + * RESET INJECTED HTML LAYOUT + * Overriding classes like .w-45, .fl-right, .h-100 to force the React layout + */ + .promo-card-content > div { + display: flex !important; + flex-direction: column !important; + align-items: center !important; + justify-content: flex-end !important; + width: 100% !important; + height: 100% !important; + float: none !important; + text-align: center !important; + } + + /* + * STYLE INJECTED HEADINGS + * Overriding inline styles like style="line-height: 1.6em;" + */ + .promo-card-content h1, + .promo-card-content h2, + .promo-card-content h3 { + font-size: 1.125rem !important; /* text-lg */ + font-weight: 700 !important; /* font-bold */ + color: var(--primary-foreground) !important; + margin: 0 0 1rem 0 !important; /* mb-4 */ + line-height: 1.2 !important; + text-align: center !important; + } + @media (min-width: 768px) { + .promo-card-content h1, + .promo-card-content h2, + .promo-card-content h3 { + font-size: 1.25rem !important; /* md:text-xl */ + } + } + + /* + * STYLE INJECTED BUTTON + * Targeting the .btn and .btn-primary classes + */ + .promo-card-content .btn { + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + padding: 0.5rem 1.5rem !important; /* px-6 py-2 */ + background-color: var(--accent) !important; + color: var(--accent-foreground) !important; + border-radius: 0.5rem !important; /* rounded-lg */ + font-weight: 500 !important; + font-size: 0.875rem !important; /* text-sm */ + text-decoration: none !important; + transition: background-color 0.2s !important; + margin: 0 auto !important; + border: none !important; + } + + /* Hover effect on the button when hovering anywhere on the card */ + .promo-card:hover .promo-card-content .btn { + background-color: color-mix(in srgb, var(--accent) 90%, transparent) !important; /* group-hover:bg-accent/90 */ + } + + /* Reset spacing on injected wrapper divs like .pt-1 */ + .promo-card-content .pt-1, + .promo-card-content .mt-1 { + padding: 0 !important; + margin: 0 !important; + } diff --git a/homepage/templates/banners_under_slider/template.html b/homepage/templates/banners_under_slider/template.html new file mode 100644 index 0000000..006b400 --- /dev/null +++ b/homepage/templates/banners_under_slider/template.html @@ -0,0 +1,21 @@ +
+
+
+ {{#each this}} +
+ {{this.alt}} +
+ +
+ {{{this.content}}} +
+
+ {{/each}} +
+
+
diff --git a/homepage/templates/first-slider/post_script.js b/homepage/templates/first-slider/post_script.js new file mode 100644 index 0000000..6c1885c --- /dev/null +++ b/homepage/templates/first-slider/post_script.js @@ -0,0 +1,107 @@ +document.addEventListener("DOMContentLoaded", () => { + const sliders = document.querySelectorAll(".js-slider-wrapper"); + + sliders.forEach((slider) => { + const track = slider.querySelector(".js-slider-track"); + let slides = Array.from(track.querySelectorAll(".slide")); + const prevBtn = slider.querySelector(".js-slider-prev"); + const nextBtn = slider.querySelector(".js-slider-next"); + const dotsContainer = slider.querySelector(".js-slider-dots"); + const dots = Array.from(slider.querySelectorAll(".slider-dot")); + + if (slides.length <= 1) { + if (prevBtn) prevBtn.style.display = "none"; + if (nextBtn) nextBtn.style.display = "none"; + if (dotsContainer) dotsContainer.style.display = "none"; + return; + } + + const firstClone = slides[0].cloneNode(true); + const lastClone = slides[slides.length - 1].cloneNode(true); + + track.appendChild(firstClone); + track.insertBefore(lastClone, slides[0]); + + const allSlides = track.querySelectorAll(".slide"); + + requestAnimationFrame(() => { + track.scrollTo({ left: track.clientWidth, behavior: "instant" }); + }); + + let scrollTimeout; + track.addEventListener("scroll", () => { + clearTimeout(scrollTimeout); + + scrollTimeout = setTimeout(() => { + const slideWidth = track.clientWidth; + const scrollLeft = track.scrollLeft; + + if ( + Math.abs(scrollLeft - slideWidth * (allSlides.length - 1)) < 5 + ) { + track.scrollTo({ left: slideWidth, behavior: "instant" }); + } else if (scrollLeft < 5) { + track.scrollTo({ + left: slideWidth * (allSlides.length - 2), + behavior: "instant", + }); + } + + let activeIndex = Math.round(track.scrollLeft / slideWidth) - 1; + if (activeIndex < 0) activeIndex = dots.length - 1; + if (activeIndex >= dots.length) activeIndex = 0; + + dots.forEach((d) => d.classList.remove("active")); + if (dots[activeIndex]) dots[activeIndex].classList.add("active"); + }, 50); + }); + + window.addEventListener("resize", () => { + const activeIndex = + dots.findIndex((d) => d.classList.contains("active")) + 1; + track.scrollTo({ + left: track.clientWidth * activeIndex, + behavior: "instant", + }); + }); + + if (nextBtn) { + nextBtn.addEventListener("click", () => { + track.scrollBy({ left: track.clientWidth, behavior: "smooth" }); + }); + } + + if (prevBtn) { + prevBtn.addEventListener("click", () => { + track.scrollBy({ left: -track.clientWidth, behavior: "smooth" }); + }); + } + + dots.forEach((dot, index) => { + dot.addEventListener("click", () => { + track.scrollTo({ + left: track.clientWidth * (index + 1), + behavior: "smooth", + }); + }); + }); + + let autoPlayTimer; + const startAutoPlay = () => { + clearInterval(autoPlayTimer); + autoPlayTimer = setInterval(() => { + if (slider.offsetWidth === 0) return; + track.scrollBy({ left: track.clientWidth, behavior: "smooth" }); + }, 4000); + }; + + const stopAutoPlay = () => clearInterval(autoPlayTimer); + + startAutoPlay(); + + slider.addEventListener("mouseenter", stopAutoPlay); + slider.addEventListener("mouseleave", startAutoPlay); + slider.addEventListener("touchstart", stopAutoPlay, { passive: true }); + slider.addEventListener("touchend", startAutoPlay); + }); +}); diff --git a/homepage/templates/first-slider/replace_selector b/homepage/templates/first-slider/replace_selector new file mode 100644 index 0000000..cb2fb10 --- /dev/null +++ b/homepage/templates/first-slider/replace_selector @@ -0,0 +1 @@ +main#main > #AjaxMainSection > .section_top diff --git a/homepage/templates/first-slider/scrape.js b/homepage/templates/first-slider/scrape.js new file mode 100644 index 0000000..1c598bb --- /dev/null +++ b/homepage/templates/first-slider/scrape.js @@ -0,0 +1,28 @@ +(() => { + const allBanners = document.querySelectorAll(` + .vc-content_slidebanner .owl-carousel .owl-stage .owl-item:not(.cloned) .item img, + .vc-content_slidebanner .owl-carousel > .item:not(.cloned) img + `); + + const allBannersResponsive = document.querySelectorAll(` + .vc-content_slidebanner--responsive .owl-carousel .owl-stage .owl-item:not(.cloned) .item img, + .vc-content_slidebanner--responsive .owl-carousel > .item:not(.cloned) img + `); + + const banners = Array.from(allBanners).map((banner) => { + const src = banner.getAttribute("data-src"); + const alt = banner.getAttribute("alt"); + return { src, alt }; + }); + + const bannersResponsive = Array.from(allBannersResponsive).map((banner) => { + const src = banner.getAttribute("data-src"); + const alt = banner.getAttribute("alt"); + return { src, alt }; + }); + + return { + banners, + bannersResponsive, + } +})(); diff --git a/homepage/templates/first-slider/style.css b/homepage/templates/first-slider/style.css new file mode 100644 index 0000000..8cce14f --- /dev/null +++ b/homepage/templates/first-slider/style.css @@ -0,0 +1,148 @@ +/* Base Container */ +.promo-section { + padding: 2rem 0; +} + +@media (min-width: 1024px) { + .promo-section { + padding: 3rem 0; + } +} + +.container { + max-width: var(--max-w-7xl, 80rem); + margin: 0 auto; + padding: 0 1rem; +} +@media (min-width: 640px) { + .container { + padding: 0 1.5rem; + } +} +@media (min-width: 1024px) { + .container { + padding: 0 2rem; + } +} + +/* Display Logic & Breakpoints (770px as requested) */ +.desktop-slider { + display: none; +} +.mobile-slider { + display: block; +} + +@media (min-width: 770px) { + .desktop-slider { + display: block; + } + .mobile-slider { + display: none; + } +} + +/* Slider Container */ +.slider-wrapper { + position: relative; + width: 100%; + border-radius: 0.75rem; + overflow: hidden; + box-shadow: + 0 4px 6px -1px rgba(0, 0, 0, 0.1), + 0 2px 4px -1px rgba(0, 0, 0, 0.06); +} + +/* Scroll Track */ +.slider-track { + display: flex; + width: 100%; + overflow-x: auto; + scroll-snap-type: x mandatory; + /* Removed CSS scroll-behavior: smooth so JS can perform 'instant' infinite jumps */ + -ms-overflow-style: none; + scrollbar-width: none; +} +.slider-track::-webkit-scrollbar { + display: none; +} + +/* Individual Slide */ +.slide { + flex: 0 0 100%; + scroll-snap-align: start; + position: relative; + width: 100%; +} + +/* Exact Aspect Ratios */ +.desktop-slider .slide { + aspect-ratio: 1920 / 640; +} +.mobile-slider .slide { + aspect-ratio: 1 / 1; +} + +.slide img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} + +/* Navigation Arrows */ +.slider-btn { + position: absolute; + top: 50%; + transform: translateY(-50%); + background: rgba(255, 255, 255, 0.8); + color: #1f2937; + border: none; + width: 2.5rem; + height: 2.5rem; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + z-index: 10; + transition: background 0.2s; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} +.slider-btn:hover { + background: rgba(255, 255, 255, 1); +} +.slider-btn svg { + width: 1.25rem; + height: 1.25rem; +} +.slider-btn.prev { + left: 1rem; +} +.slider-btn.next { + right: 1rem; +} + +/* Pagination Dots */ +.slider-dots { + position: absolute; + bottom: 1rem; + left: 50%; + transform: translateX(-50%); + display: flex; + gap: 0.5rem; + z-index: 10; +} +.slider-dot { + width: 0.625rem; + height: 0.625rem; + border-radius: 50%; + background: rgba(255, 255, 255, 0.4); + border: none; + cursor: pointer; + transition: all 0.2s ease-in-out; +} +.slider-dot.active { + background: rgba(255, 255, 255, 1); + transform: scale(1.2); +} diff --git a/homepage/templates/first-slider/template.html b/homepage/templates/first-slider/template.html new file mode 100644 index 0000000..8e2bf06 --- /dev/null +++ b/homepage/templates/first-slider/template.html @@ -0,0 +1,103 @@ +
+
+ +
+
+
+ {{#each banners}} +
+ {{this.alt}} +
+ {{/each}} +
+ + + + +
+ {{#each banners}} + + {{/each}} +
+
+
+ + +
+
+
+ {{#each bannersResponsive}} +
+ {{this.alt}} +
+ {{/each}} +
+ + + + +
+ {{#each bannersResponsive}} + + {{/each}} +
+
+
+
+
diff --git a/homepage/templates/section_middle_before/replace_selector b/homepage/templates/section_middle_before/replace_selector new file mode 100644 index 0000000..afb2b95 --- /dev/null +++ b/homepage/templates/section_middle_before/replace_selector @@ -0,0 +1 @@ +main#main #AjaxMainSection section.section_middle_before diff --git a/homepage/templates/section_middle_before/scrape.js b/homepage/templates/section_middle_before/scrape.js new file mode 100644 index 0000000..8b3613e --- /dev/null +++ b/homepage/templates/section_middle_before/scrape.js @@ -0,0 +1,31 @@ +(() => { + const main = document.querySelector("main#main #AjaxMainSection section.section_middle_before .vc-menu_categorytop"); + + const items = main.querySelectorAll("div.item > .inner"); + + const data = Array.from(items).map((item) => { + const titleA = item.querySelector("h2.title > a"); + const link = titleA.href; + const title = titleA.querySelector("span").textContent.trim(); + const img = titleA.querySelector("img").src; + const img_alt = titleA.querySelector("img").alt; + const subItems = item.querySelectorAll(".subitems > ul > li > a"); + const subItemsData = Array.from(subItems).map((subItem) => { + const subLink = subItem.href; + const subTitle = subItem.textContent.trim(); + return { title: subTitle, link: subLink }; + }); + + return { + title, + link, + img: { + src: img, + alt: img_alt + }, + subItems: subItemsData + }; + }); + + return data; +})(); diff --git a/homepage/templates/section_middle_before/style.css b/homepage/templates/section_middle_before/style.css new file mode 100644 index 0000000..646bee3 --- /dev/null +++ b/homepage/templates/section_middle_before/style.css @@ -0,0 +1,207 @@ +:root { + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --foreground: oklch(0.145 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --font-sans: "Geist", "Geist Fallback", ui-sans-serif, system-ui, sans-serif; +} + +.category-section { + font-family: var(--font-sans); + padding: 4rem 0; /* py-16 */ +} +@media (min-width: 1024px) { + .category-section { + padding: 6rem 0; /* lg:py-24 */ + } +} + +.category-container { + max-width: 80rem; /* max-w-7xl */ + margin: 0 auto; + padding: 0 1rem; /* px-4 */ +} +@media (min-width: 640px) { + .category-container { + padding: 0 1.5rem; /* sm:px-6 */ + } +} +@media (min-width: 1024px) { + .category-container { + padding: 0 2rem; /* lg:px-8 */ + } +} + +.category-header { + text-align: center; + margin-bottom: 3rem; /* mb-12 */ +} + +.category-header h2 { + font-size: 1.5rem; /* text-2xl */ + font-weight: 700; + color: var(--foreground); + margin: 0 0 1rem 0; /* mb-4 */ + line-height: 1.2; +} +@media (min-width: 768px) { + .category-header h2 { + font-size: 1.875rem; /* md:text-3xl */ + } +} + +.category-header p { + color: var(--muted-foreground); + max-width: 42rem; /* max-w-2xl */ + margin: 0 auto; + font-size: 1rem; + line-height: 1.5; +} + +/* + * RESPONSIVE GRID + * Mobile: 1 column + * Small (640px+): 2 columns + * Large (1024px+): 4 columns + */ +.category-grid { + display: grid; + grid-template-columns: 1fr; /* Default: 1 column on mobile */ + gap: 1rem; /* gap-4 */ +} +@media (min-width: 640px) { + .category-grid { + grid-template-columns: repeat(2, 1fr); /* sm:grid-cols-2 */ + } +} +@media (min-width: 768px) { + .category-grid { + gap: 1.5rem; /* md:gap-6 */ + } +} +@media (min-width: 1024px) { + .category-grid { + grid-template-columns: repeat(4, 1fr); /* lg:grid-cols-4 */ + } +} + +.category-card { + position: relative; + display: block; + aspect-ratio: 1 / 1; /* aspect-square */ + border-radius: 0.75rem; /* rounded-xl */ + overflow: hidden; + background-color: var(--secondary); + text-decoration: none; + /* Acts as Tailwind 'group' */ +} + +.category-img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.5s ease-in-out; +} + +.category-card:hover .category-img { + transform: scale(1.1); /* group-hover:scale-110 */ +} + +.category-overlay { + position: absolute; + inset: 0; + /* Equivalent to from-primary/90 via-primary/40 to-transparent */ + background: linear-gradient( + to top, + color-mix(in srgb, var(--primary) 90%, transparent) 0%, + color-mix(in srgb, var(--primary) 40%, transparent) 50%, + transparent 100% + ); + pointer-events: none; +} + +.category-content { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + justify-content: flex-end; + padding: 1.5rem; /* Generous padding since it's full width on mobile */ + z-index: 2; +} +@media (min-width: 640px) { + .category-content { + padding: 1rem; + } /* Tighter padding when 2 cols on small tablet */ +} +@media (min-width: 768px) { + .category-content { + padding: 1.5rem; /* md:p-6 */ + } +} + +.category-title { + font-size: 1.25rem; /* Larger by default on mobile since it's 1 column */ + font-weight: 700; + color: var(--primary-foreground); + margin: 0 0 0.25rem 0; /* mb-1 */ + line-height: 1.2; +} +@media (min-width: 640px) { + .category-title { + font-size: 1.125rem; + } /* text-lg when shrunk to 2 cols */ +} +@media (min-width: 768px) { + .category-title { + font-size: 1.25rem; /* md:text-xl */ + } +} + +.category-desc { + color: color-mix( + in srgb, + var(--primary-foreground) 70%, + transparent + ); /* text-primary-foreground/70 */ + font-size: 0.875rem; + margin: 0; + line-height: 1.4; +} +@media (min-width: 640px) { + .category-desc { + font-size: 0.75rem; + } /* text-xs */ +} +@media (min-width: 768px) { + .category-desc { + font-size: 0.875rem; /* md:text-sm */ + } +} + +.category-action { + display: flex; + align-items: center; + gap: 0.5rem; /* gap-2 */ + color: var(--accent); + font-size: 0.875rem; /* text-sm */ + font-weight: 500; + margin-top: 0.75rem; /* mt-3 */ + + /* Animation initial state */ + opacity: 0; + transform: translateY(0.5rem); /* translate-y-2 */ + transition: all 0.3s ease-in-out; +} + +.category-card:hover .category-action { + opacity: 1; /* group-hover:opacity-100 */ + transform: translateY(0); /* group-hover:translate-y-0 */ +} + +.category-action svg { + width: 1rem; /* w-4 */ + height: 1rem; /* h-4 */ +} diff --git a/homepage/templates/section_middle_before/template.html b/homepage/templates/section_middle_before/template.html new file mode 100644 index 0000000..163e52d --- /dev/null +++ b/homepage/templates/section_middle_before/template.html @@ -0,0 +1,41 @@ +
+
+
+

Procházejte kategorie

+

Najděte svůj styl v našich pečlivě vybraných kolekcích

+
+ + +
+
diff --git a/homepage/templates/section_middle_tabs/post_script.js b/homepage/templates/section_middle_tabs/post_script.js new file mode 100644 index 0000000..47a83cd --- /dev/null +++ b/homepage/templates/section_middle_tabs/post_script.js @@ -0,0 +1,23 @@ + +document.addEventListener('DOMContentLoaded', () => { + const tabBtns = document.querySelectorAll('.js-tab-btn'); + const tabPanes = document.querySelectorAll('.js-tab-pane'); + + tabBtns.forEach(btn => { + btn.addEventListener('click', () => { + // Remove active class from all buttons and panes + tabBtns.forEach(b => b.classList.remove('active')); + tabPanes.forEach(p => p.classList.remove('active')); + + // Add active class to clicked button + btn.classList.add('active'); + + // Show corresponding pane + const targetId = btn.getAttribute('data-target'); + const targetPane = document.getElementById(targetId); + if (targetPane) { + targetPane.classList.add('active'); + } + }); + }); +}); diff --git a/homepage/templates/section_middle_tabs/replace_selector b/homepage/templates/section_middle_tabs/replace_selector new file mode 100644 index 0000000..9bf7204 --- /dev/null +++ b/homepage/templates/section_middle_tabs/replace_selector @@ -0,0 +1 @@ +main#main #AjaxMainSection section.section_middle diff --git a/homepage/templates/section_middle_tabs/scrape.js b/homepage/templates/section_middle_tabs/scrape.js new file mode 100644 index 0000000..4b8fd89 --- /dev/null +++ b/homepage/templates/section_middle_tabs/scrape.js @@ -0,0 +1,89 @@ +(() => { + const main = document.querySelector("main#main #AjaxMainSection section.section_middle > .container > .inner > .vc-tabstemplate"); + + if (!main) return null; + + const tabs = main.querySelectorAll(".inner > nav > ul > li > a > span"); + const tabTexts = Array.from(tabs).map((tab) => tab.textContent.trim()); + + const body = main.querySelector(".body"); + + const finalData = { + names: tabTexts, + contents: {}, + }; + + for (let i = 0; i < tabTexts.length; i++) { + const idName = `Index_${i + 1}`; + + const items = body.querySelectorAll(`#${idName} .owl-item > article.commodityBox`); + + const itemsData = Array.from(items).map((item) => { + const productNode = item.querySelector("a.inner"); + + const link = productNode.getAttribute("href"); + + // UPDATED: Extracting background and text colors using getComputedStyle + const flagsElements = productNode.querySelectorAll(".flags > .flags-inner > .flag"); + const flags = Array.from(flagsElements).map((flag) => { + const styles = window.getComputedStyle(flag); + return { + text: flag.textContent.trim(), + backgroundColor: styles.backgroundColor, + textColor: styles.color + }; + }); + + const imageEl = productNode.querySelector(".image > img"); + const imageSrc = imageEl ? (imageEl.getAttribute("data-src") || imageEl.getAttribute("src")) : null; + const imageAlt = imageEl ? imageEl.getAttribute("alt") : null; + + const descriptionEl = productNode.querySelector(".annotation > p"); + const description = descriptionEl ? descriptionEl.textContent.trim() : null; + + const titleEl = productNode.querySelector(".title > span"); + const title = titleEl ? titleEl.textContent.trim() : null; + + const buyFormEl = productNode.querySelector(".buyForm"); + const buyFormContent = buyFormEl ? buyFormEl.innerHTML.trim() : null; + + const priceEl = productNode.querySelector(".pricing > .pricing-inner"); + + let priceDiscount = null; + let priceBeforeDiscount = null; + let priceHighlight = null; + + if (priceEl) { + const priceDiscountEl = priceEl.querySelector(".discount .number"); + priceDiscount = priceDiscountEl ? parseInt(priceDiscountEl.textContent.trim(), 10) : null; + + const priceBeforeDiscountEl = priceEl.querySelector(".price.beforeDiscount"); + priceBeforeDiscount = priceBeforeDiscountEl ? priceBeforeDiscountEl.textContent.trim().replace(/\s+/g, ' ') : null; + + const priceHighlightEl = priceEl.querySelector(".price.highlight"); + priceHighlight = priceHighlightEl ? priceHighlightEl.textContent.trim().replace(/\s+/g, ' ') : null; + } + + const availabilityEl = productNode.querySelector(".availability strong"); + const availability = availabilityEl ? availabilityEl.textContent.trim() : null; + + return { + title, + link, + flags, + imageSrc, + imageAlt, + description, + priceHighlight, + priceBeforeDiscount, + priceDiscount, + availability, + buyFormContent + }; + }); + + finalData.contents[tabTexts[i]] = itemsData; + } + + return finalData; +})(); diff --git a/homepage/templates/section_middle_tabs/style.css b/homepage/templates/section_middle_tabs/style.css new file mode 100644 index 0000000..7b0ab5e --- /dev/null +++ b/homepage/templates/section_middle_tabs/style.css @@ -0,0 +1,272 @@ +:root { + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --card: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --border: oklch(0.922 0 0); + --sale-bg: #ef4444; /* Red for discounts */ + --sale-fg: #ffffff; + --success-text: #10b981; /* Green for in-stock */ + --font-sans: "Geist", "Geist Fallback", ui-sans-serif, system-ui, sans-serif; +} + +.featured-section { + font-family: var(--font-sans); + padding: 4rem 0; /* py-16 */ + background-color: color-mix( + in srgb, + var(--secondary) 30%, + transparent + ); /* bg-secondary/30 */ +} +@media (min-width: 1024px) { + .featured-section { + padding: 6rem 0; /* lg:py-24 */ + } +} + +.container { + max-width: 80rem; /* max-w-7xl */ + margin: 0 auto; + padding: 0 1rem; /* px-4 */ +} +@media (min-width: 640px) { + .container { + padding: 0 1.5rem; /* sm:px-6 */ + } +} +@media (min-width: 1024px) { + .container { + padding: 0 2rem; /* lg:px-8 */ + } +} + +/* Tabs */ +.tabs-container { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + gap: 0.5rem; /* gap-2 */ + margin-bottom: 3rem; /* mb-12 */ +} + +.tab-btn { + padding: 0.5rem 1.5rem; /* px-6 py-2 */ + border-radius: 9999px; /* rounded-full */ + font-size: 0.875rem; /* text-sm */ + font-weight: 500; /* font-medium */ + cursor: pointer; + transition: all 0.2s ease; + background-color: var(--card); + color: var(--foreground); + border: 1px solid var(--border); +} + +.tab-btn:hover { + background-color: var(--secondary); +} + +.tab-btn.active { + background-color: var(--primary); + color: var(--primary-foreground); + border-color: var(--primary); +} + +/* Grid Layout & Tab Panes */ +.tab-pane { + visibility: hidden; + opacity: 0; + height: 0; + overflow: hidden; + transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out; +} + +.tab-pane.active { + visibility: visible; + opacity: 1; + height: auto; + overflow: visible; +} + +.product-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); /* grid-cols-2 */ + gap: 1rem; /* gap-4 */ +} +@media (min-width: 768px) { + .product-grid { + grid-template-columns: repeat(3, 1fr); /* md:grid-cols-3 */ + gap: 1.5rem; /* md:gap-6 */ + } +} +@media (min-width: 1024px) { + .product-grid { + grid-template-columns: repeat(4, 1fr); /* lg:grid-cols-4 */ + } +} + +/* Product Card */ +.product-card { + position: relative; + background-color: var(--card); + border-radius: 0.75rem; /* rounded-xl */ + overflow: hidden; + border: 1px solid var(--border); + transition: all 0.3s ease; + display: flex; + flex-direction: column; +} +.product-card:hover { + box-shadow: + 0 20px 25px -5px rgba(0, 0, 0, 0.1), + 0 8px 10px -6px rgba(0, 0, 0, 0.1); /* shadow-xl */ +} + +/* Badges */ +.product-badges { + position: absolute; + top: 0.75rem; /* top-3 */ + left: 0.75rem; /* left-3 */ + display: flex; + flex-direction: column; + gap: 0.5rem; /* gap-2 */ + z-index: 10; +} + +.badge { + padding: 0.25rem 0.5rem; /* px-2 py-1 */ + font-size: 0.75rem; /* text-xs */ + font-weight: 600; /* font-semibold */ + border-radius: 0.25rem; /* rounded */ + line-height: 1; + text-transform: uppercase; +} +.badge-discount { + background-color: var(--sale-bg); + color: var(--sale-fg); +} + +/* Image Area */ +.product-link { + text-decoration: none; + color: inherit; + display: block; + flex: 1; /* Pushes footer to the bottom */ +} + +.product-img-wrapper { + position: relative; + aspect-ratio: 4 / 5; + background-color: var(--secondary); + overflow: hidden; +} + +.product-img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.5s ease; +} +.product-card:hover .product-img { + transform: scale(1.05); +} + +/* Content Area */ +.product-info { + padding: 1rem; /* p-4 */ + display: flex; + flex-direction: column; +} + +.product-desc { + font-size: 0.75rem; /* text-xs */ + color: var(--muted-foreground); + margin: 0 0 0.25rem 0; /* mb-1 */ + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.product-title { + font-size: 1rem; + font-weight: 600; /* font-semibold */ + color: var(--foreground); + margin: 0 0 0.75rem 0; /* mb-3 */ + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + line-height: 1.3; + transition: color 0.2s; +} +.product-card:hover .product-title { + color: var(--accent); +} + +.product-pricing { + display: flex; + align-items: baseline; + gap: 0.5rem; /* gap-2 */ + margin-bottom: 0.75rem; /* mb-3 */ +} + +.price-current { + font-size: 1.125rem; /* text-lg */ + font-weight: 700; /* font-bold */ + color: var(--foreground); +} + +.price-original { + font-size: 0.875rem; /* text-sm */ + color: var(--muted-foreground); + text-decoration: line-through; +} + +/* Footer (Availability & Button) */ +.product-footer { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: auto; +} + +.product-availability { + font-size: 0.75rem; /* text-xs */ + font-weight: 500; + color: var(--muted-foreground); +} +/* Soft-matching text for Skladem */ +.product-availability[data-status*="Skladem"] { + color: var(--success-text); +} + +/* Style the injected raw form and button */ +.product-buy-form { + margin: 0; +} +.product-buy-form .btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.5rem 1rem; /* px-4 py-2 */ + background-color: var(--primary); + color: var(--primary-foreground); + border-radius: 0.5rem; /* rounded-lg */ + font-size: 0.875rem; /* text-sm */ + font-weight: 500; /* font-medium */ + border: none; + cursor: pointer; + transition: background-color 0.2s; + font-family: inherit; +} +.product-buy-form .btn:hover { + background-color: color-mix( + in srgb, + var(--primary) 90%, + transparent + ); /* hover:bg-primary/90 */ +} diff --git a/homepage/templates/section_middle_tabs/template.html b/homepage/templates/section_middle_tabs/template.html new file mode 100644 index 0000000..c7c7bba --- /dev/null +++ b/homepage/templates/section_middle_tabs/template.html @@ -0,0 +1,90 @@ +