feat: Refreshing header state
This commit is contained in:
@@ -0,0 +1 @@
|
||||
.section_footer_before
|
||||
@@ -0,0 +1,34 @@
|
||||
(() => {
|
||||
const parseMethodsBlock = (wrapperSelector, boxSelector) => {
|
||||
const container = document.querySelector(wrapperSelector);
|
||||
if (!container) return null;
|
||||
|
||||
const titleEl = container.querySelector(`${boxSelector} h2 span`);
|
||||
const title = titleEl ? titleEl.textContent.trim() : null;
|
||||
|
||||
const descEl = container.querySelector(`${boxSelector} .box-in p`);
|
||||
const description = descEl ? descEl.textContent.trim() : null;
|
||||
|
||||
const imageElements = container.querySelectorAll(`${boxSelector} .box-in .ico span img`);
|
||||
const methods = Array.from(imageElements).map((img) => {
|
||||
return {
|
||||
name: img.getAttribute('alt') || null,
|
||||
imageSrc: img.getAttribute('data-src') || img.getAttribute('src') || null
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
methods
|
||||
};
|
||||
};
|
||||
|
||||
const paymentMethods = parseMethodsBlock('.section_footer_before .vc-content_paymentmethods', '.box-payment');
|
||||
const deliveryMethods = parseMethodsBlock('.section_footer_before .vc-content_deliverymethods', '.box-delivery');
|
||||
|
||||
return {
|
||||
paymentMethods,
|
||||
deliveryMethods
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,109 @@
|
||||
:root {
|
||||
--card: oklch(1 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);
|
||||
--border: oklch(0.922 0 0);
|
||||
--font-sans: "Geist", "Geist Fallback", ui-sans-serif, system-ui, sans-serif;
|
||||
}
|
||||
|
||||
.methods-section {
|
||||
font-family: var(--font-sans);
|
||||
padding: 3rem 0; /* py-12 */
|
||||
background-color: var(--card);
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
@media (min-width: 1024px) {
|
||||
.methods-section {
|
||||
padding: 4rem 0; /* lg:py-16 */
|
||||
}
|
||||
}
|
||||
|
||||
.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 */
|
||||
}
|
||||
}
|
||||
|
||||
.methods-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 3rem; /* gap-12 */
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.methods-grid {
|
||||
grid-template-columns: repeat(2, 1fr); /* md:grid-cols-2 */
|
||||
}
|
||||
}
|
||||
|
||||
/* Header & Description */
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem; /* gap-2 */
|
||||
font-size: 1.125rem; /* text-lg */
|
||||
font-weight: 600; /* font-semibold */
|
||||
color: var(--foreground);
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.section-header svg {
|
||||
width: 1.25rem; /* w-5 */
|
||||
height: 1.25rem; /* h-5 */
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.section-desc {
|
||||
font-size: 0.875rem;
|
||||
color: var(--muted-foreground);
|
||||
margin: 0 0 1.5rem 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Items Wrapper */
|
||||
.items-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem; /* gap-4 */
|
||||
}
|
||||
|
||||
.item-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem; /* gap-3 */
|
||||
padding: 0.75rem 1rem; /* px-4 py-3 */
|
||||
background-color: var(--secondary);
|
||||
border-radius: 0.5rem; /* rounded-lg */
|
||||
border: 1px solid transparent;
|
||||
transition:
|
||||
background-color 0.2s,
|
||||
border-color 0.2s;
|
||||
}
|
||||
.item-card:hover {
|
||||
background-color: color-mix(in srgb, var(--secondary) 80%, transparent);
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
.item-img {
|
||||
height: 1.5rem; /* h-6 roughly */
|
||||
width: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-size: 0.875rem; /* text-sm */
|
||||
font-weight: 500; /* font-medium */
|
||||
color: var(--foreground);
|
||||
margin: 0;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<section class="methods-section">
|
||||
<div class="container">
|
||||
<div class="methods-grid">
|
||||
<!-- Payment Methods -->
|
||||
{{#if paymentMethods}}
|
||||
<div>
|
||||
<h3 class="section-header">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<rect width="20" height="14" x="2" y="5" rx="2"></rect>
|
||||
<line x1="2" x2="22" y1="10" y2="10"></line>
|
||||
</svg>
|
||||
{{#if paymentMethods.title}}{{paymentMethods.title}}{{else}}Platební
|
||||
metody{{/if}}
|
||||
</h3>
|
||||
|
||||
{{#if paymentMethods.description}}
|
||||
<p class="section-desc">{{paymentMethods.description}}</p>
|
||||
{{/if}}
|
||||
|
||||
<div class="items-list">
|
||||
{{#each paymentMethods.methods}}
|
||||
<div class="item-card">
|
||||
{{#if this.imageSrc}}
|
||||
<img
|
||||
src="{{this.imageSrc}}"
|
||||
alt="{{this.name}}"
|
||||
class="item-img"
|
||||
loading="lazy"
|
||||
/>
|
||||
{{/if}}
|
||||
<span class="item-name">{{this.name}}</span>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<!-- Delivery Methods -->
|
||||
{{#if deliveryMethods}}
|
||||
<div>
|
||||
<h3 class="section-header">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path
|
||||
d="M14 18V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v11a1 1 0 0 0 1 1h2"
|
||||
></path>
|
||||
<path d="M15 18H9"></path>
|
||||
<path
|
||||
d="M19 18h2a1 1 0 0 0 1-1v-3.65a1 1 0 0 0-.22-.624l-3.48-4.35A1 1 0 0 0 17.52 8H14"
|
||||
></path>
|
||||
<circle cx="17" cy="18" r="2"></circle>
|
||||
<circle cx="7" cy="18" r="2"></circle>
|
||||
</svg>
|
||||
{{#if
|
||||
deliveryMethods.title}}{{deliveryMethods.title}}{{else}}Doručovací
|
||||
metody{{/if}}
|
||||
</h3>
|
||||
|
||||
{{#if deliveryMethods.description}}
|
||||
<p class="section-desc">{{deliveryMethods.description}}</p>
|
||||
{{/if}}
|
||||
|
||||
<div class="items-list">
|
||||
{{#each deliveryMethods.methods}}
|
||||
<div class="item-card">
|
||||
{{#if this.imageSrc}}
|
||||
<img
|
||||
src="{{this.imageSrc}}"
|
||||
alt="{{this.name}}"
|
||||
class="item-img"
|
||||
loading="lazy"
|
||||
/>
|
||||
{{/if}}
|
||||
<span class="item-name">{{this.name}}</span>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,2 @@
|
||||
template_replacer:
|
||||
replace_type: "hide"
|
||||
@@ -0,0 +1,22 @@
|
||||
document.querySelectorAll(".new-products-section .product-buy-form").forEach(form => {
|
||||
const originalFormId = form.dataset.originalId;
|
||||
|
||||
const submitButton = form.querySelector("button");
|
||||
|
||||
submitButton.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const form = document.getElementById(originalFormId).querySelector("form");
|
||||
if (form) {
|
||||
form.dispatchEvent(new Event('submit', {
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
}));
|
||||
|
||||
// TODO: This is awful i know but idk a better way to do this for now
|
||||
setTimeout(() => {
|
||||
window.Rerender.rerenderComponent("HEADER_RERENDER");
|
||||
}, 2000)
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1 +1 @@
|
||||
main#main #AjaxMainSection section.section_middle .vc-commodity_attribute
|
||||
main#main #AjaxMainSection section.section_middle > .container > .inner > .vc-commodity_attribute
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
|
||||
// Select all products, ignoring carousel initialization wrappers to ensure we get everything
|
||||
const items = container.querySelectorAll("article.commodityBox");
|
||||
|
||||
|
||||
const itemsData = Array.from(items).map((item) => {
|
||||
const productNode = item.querySelector("a.inner");
|
||||
const link = productNode ? productNode.getAttribute("href") : null;
|
||||
|
||||
|
||||
// Extract flags and their computed styles
|
||||
const flagsElements = productNode.querySelectorAll(".flags > .flags-inner > .flag");
|
||||
const flags = Array.from(flagsElements).map((flag) => {
|
||||
@@ -40,6 +40,8 @@
|
||||
// Extract buy form HTML
|
||||
const buyFormEl = productNode.querySelector(".buyForm");
|
||||
const buyFormContent = buyFormEl ? buyFormEl.innerHTML.trim() : null;
|
||||
const id = "button-action-id-" + crypto.randomUUID();
|
||||
buyFormEl.setAttribute("id", id);
|
||||
|
||||
// Extract pricing details
|
||||
const priceEl = productNode.querySelector(".pricing > .pricing-inner");
|
||||
@@ -50,7 +52,7 @@
|
||||
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;
|
||||
|
||||
@@ -73,7 +75,8 @@
|
||||
priceBeforeDiscount,
|
||||
priceDiscount,
|
||||
availability,
|
||||
buyFormContent
|
||||
buyFormContent,
|
||||
buyFormId: id
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -182,9 +182,6 @@
|
||||
line-height: 1.3;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.product-card:hover .product-title {
|
||||
color: var(--accent); /* group-hover:text-accent */
|
||||
}
|
||||
|
||||
.product-pricing {
|
||||
display: flex;
|
||||
|
||||
@@ -61,8 +61,7 @@
|
||||
{{#if (eq this.availability "Skladem")}}✓ {{/if}}{{this.availability}}
|
||||
</span>
|
||||
|
||||
<div class="product-buy-form">
|
||||
<!-- Injects the parsed <form> or <button> code directly -->
|
||||
<div class="product-buy-form" data-original-id="{{this.buyFormId}}">
|
||||
{{{this.buyFormContent}}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
template_replacer:
|
||||
replace_type: "hide"
|
||||
@@ -1,18 +1,14 @@
|
||||
|
||||
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) {
|
||||
@@ -20,4 +16,27 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll(".featured-section .product-buy-form").forEach(form => {
|
||||
const originalFormId = form.dataset.originalId;
|
||||
|
||||
const submitButton = form.querySelector("button");
|
||||
|
||||
submitButton.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const form = document.getElementById(originalFormId).querySelector("form");
|
||||
if (form) {
|
||||
form.dispatchEvent(new Event('submit', {
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
}));
|
||||
|
||||
// TODO: This is awful i know but idk a better way to do this for now
|
||||
setTimeout(() => {
|
||||
window.Rerender.rerenderComponent("HEADER_RERENDER");
|
||||
}, 2000)
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
|
||||
for (let i = 0; i < tabTexts.length; i++) {
|
||||
const idName = `Index_${i + 1}`;
|
||||
|
||||
|
||||
const items = body.querySelectorAll(`#${idName} article.commodityBox`);
|
||||
|
||||
|
||||
const itemsData = Array.from(items).map((item) => {
|
||||
const productNode = item.querySelector("a.inner");
|
||||
|
||||
const link = productNode.getAttribute("href");
|
||||
|
||||
|
||||
const flagsElements = productNode.querySelectorAll(".flags > .flags-inner > .flag");
|
||||
const flags = Array.from(flagsElements).map((flag) => {
|
||||
const styles = window.getComputedStyle(flag);
|
||||
@@ -45,9 +45,11 @@
|
||||
|
||||
const buyFormEl = productNode.querySelector(".buyForm");
|
||||
const buyFormContent = buyFormEl ? buyFormEl.innerHTML.trim() : null;
|
||||
const id = "button-action-id-" + crypto.randomUUID();
|
||||
buyFormEl.setAttribute("id", id);
|
||||
|
||||
const priceEl = productNode.querySelector(".pricing > .pricing-inner");
|
||||
|
||||
|
||||
let priceDiscount = null;
|
||||
let priceBeforeDiscount = null;
|
||||
let priceHighlight = null;
|
||||
@@ -55,7 +57,7 @@
|
||||
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;
|
||||
|
||||
@@ -77,7 +79,8 @@
|
||||
priceBeforeDiscount,
|
||||
priceDiscount,
|
||||
availability,
|
||||
buyFormContent
|
||||
buyFormContent,
|
||||
buyFormId: id
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -203,9 +203,6 @@
|
||||
line-height: 1.3;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.product-card:hover .product-title {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.product-pricing {
|
||||
display: flex;
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
{{/if}}{{this.availability}}
|
||||
</span>
|
||||
|
||||
<div class="product-buy-form">{{{this.buyFormContent}}}</div>
|
||||
<div class="product-buy-form" data-original-id="{{this.buyFormId}}">{{{this.buyFormContent}}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user