update
This commit is contained in:
103
template/javascript/cart.html
Normal file
103
template/javascript/cart.html
Normal file
@@ -0,0 +1,103 @@
|
||||
<script>
|
||||
// ── Helpers ──────────────────────────────────────────────────────────────
|
||||
function formatPrice(n) {
|
||||
return Number(n).toLocaleString('vi-VN') + '₫';
|
||||
}
|
||||
|
||||
// cartItems cần global để các onclick inline gọi được
|
||||
var cartItems = {};
|
||||
|
||||
// ── Update total ─────────────────────────────────────────────────────────
|
||||
function updateCartTotal() {
|
||||
var total = 0;
|
||||
Object.values(cartItems).forEach(function (item) {
|
||||
if (item.price > 0) total += item.price * item.qty;
|
||||
});
|
||||
var totalEl = document.getElementById('cart-total');
|
||||
if (totalEl) totalEl.textContent = formatPrice(total);
|
||||
}
|
||||
|
||||
// ── Quantity controls ─────────────────────────────────────────────────────
|
||||
function cartInc(id) {
|
||||
var item = cartItems[id];
|
||||
if (!item) return;
|
||||
item.qty++;
|
||||
item.el.dataset.qty = item.qty;
|
||||
item.el.querySelector('.item-qty').textContent = item.qty;
|
||||
if (item.price > 0) {
|
||||
item.el.querySelector('.item-total-price').textContent = formatPrice(item.price * item.qty);
|
||||
}
|
||||
updateCartTotal();
|
||||
}
|
||||
|
||||
function cartDec(id) {
|
||||
var item = cartItems[id];
|
||||
if (!item || item.qty <= 1) return;
|
||||
item.qty--;
|
||||
item.el.dataset.qty = item.qty;
|
||||
item.el.querySelector('.item-qty').textContent = item.qty;
|
||||
if (item.price > 0) {
|
||||
item.el.querySelector('.item-total-price').textContent = formatPrice(item.price * item.qty);
|
||||
}
|
||||
updateCartTotal();
|
||||
}
|
||||
|
||||
// ── Remove item ──────────────────────────────────────────────────────────
|
||||
function cartRemove(id) {
|
||||
var item = cartItems[id];
|
||||
if (!item) return;
|
||||
if (!confirm('Bạn có chắc muốn xóa sản phẩm này khỏi giỏ hàng?')) return;
|
||||
item.el.closest('.cart-item-wrap').remove();
|
||||
delete cartItems[id];
|
||||
updateCartTotal();
|
||||
}
|
||||
|
||||
// ── Delivery tab switch ───────────────────────────────────────────────────
|
||||
function switchTab(tab) {
|
||||
var tabDelivery = document.getElementById('tab-delivery');
|
||||
var tabPickup = document.getElementById('tab-pickup');
|
||||
if (tab === 'delivery') {
|
||||
tabDelivery.className = 'h-[46px] w-[392px] text-[14px] font-medium bg-[#f3f4f6] border-b-2 border-[#e7000b] text-[#e7000b] rounded-tl-lg rounded-tr-lg';
|
||||
tabPickup.className = 'h-[46px] w-[408px] text-[14px] font-medium text-[#4a5565] border-b-2 border-transparent';
|
||||
} else {
|
||||
tabPickup.className = 'h-[46px] w-[408px] text-[14px] font-medium bg-[#f3f4f6] border-b-2 border-[#e7000b] text-[#e7000b] rounded-tl-lg rounded-tr-lg';
|
||||
tabDelivery.className = 'h-[46px] w-[392px] text-[14px] font-medium text-[#4a5565] border-b-2 border-transparent';
|
||||
}
|
||||
}
|
||||
|
||||
// ── Init sau khi DOM sẵn sàng ────────────────────────────────────────────
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
// Build cart state từ DOM
|
||||
document.querySelectorAll('.cart-item').forEach(function (el) {
|
||||
var id = el.dataset.id;
|
||||
var price = parseInt(el.dataset.price) || 0;
|
||||
var qty = parseInt(el.dataset.qty) || 1;
|
||||
cartItems[id] = { el: el, price: price, qty: qty };
|
||||
});
|
||||
|
||||
// Format giá từng item (số thô → "1.850.000₫")
|
||||
document.querySelectorAll('.cart-item').forEach(function (el) {
|
||||
var id = el.dataset.id;
|
||||
var item = cartItems[id];
|
||||
if (!item) return;
|
||||
if (item.price > 0) {
|
||||
var priceEl = el.querySelector('.item-total-price');
|
||||
if (priceEl) priceEl.textContent = formatPrice(item.price * item.qty);
|
||||
}
|
||||
var marketEl = el.querySelector('.item-market-price');
|
||||
if (marketEl) {
|
||||
var raw = parseInt(marketEl.textContent) || 0;
|
||||
if (raw > 0) marketEl.textContent = formatPrice(raw);
|
||||
}
|
||||
});
|
||||
|
||||
// Format tổng tiền
|
||||
var totalEl = document.getElementById('cart-total');
|
||||
if (totalEl) {
|
||||
var raw = parseInt(totalEl.textContent.replace(/\D/g, '')) || 0;
|
||||
totalEl.textContent = formatPrice(raw);
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -1,83 +0,0 @@
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/monaco-editor@0.34.1/min/vs/editor/editor.main.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/monaco-editor@0.34.1/min/vs/loader.js"></script>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
require.config({ paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.34.1/min/vs' } });
|
||||
require(['vs/editor/editor.main'], function () {
|
||||
|
||||
monaco.editor.defineTheme('myCustomTheme', {
|
||||
base: 'vs',
|
||||
inherit: true,
|
||||
rules: [
|
||||
{ token: 'tag', foreground: '4CAF50', fontStyle: 'bold' }, // Màu cam cho thẻ HTML
|
||||
{ token: 'attribute.name', foreground: 'e00000' }, // Màu xanh lá cho thuộc tính
|
||||
{ token: 'attribute.value', foreground: 'e00000' }, // Màu vàng cho giá trị thuộc tính
|
||||
{ token: 'string', foreground: 'e00000' }, // Màu xanh dương cho chuỗi
|
||||
{ token: 'comment', foreground: '#4CAF50', fontStyle: 'italic' },
|
||||
],
|
||||
colors: {
|
||||
'editor.foreground': '#000000',
|
||||
'editorGutter.background': '#f6f6f6',
|
||||
'editor.lineNumber.foreground': '#000000',
|
||||
}
|
||||
})
|
||||
|
||||
monaco.editor.create(document.getElementById('tpl_editor'), {
|
||||
value: `<section class= "section-breakcrumb routing py-12 line-clamp" >
|
||||
<div class="global-breadcrumb container">
|
||||
<ol itemscope="" itemtype="http://schema.org/BreadcrumbList" class="list-style-none
|
||||
d- flex">
|
||||
<li class="routing-link" itemprop="itemListElement" itemscope="" itemtype="http://schema.org/ListItem">
|
||||
<a href="/" itemprop="item" class="nopad-l">
|
||||
<span itemprop="name">Trang chủ</span>
|
||||
</a>
|
||||
<meta itemprop="position" content="1">
|
||||
</li>
|
||||
|
||||
<li class="routing-link" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">
|
||||
<a href="{{ path.url }}" itemprop="item" class="nopad-l">
|
||||
<span itemprop="name"> {{ path.name }} </span>
|
||||
</a>
|
||||
<meta itemprop="position" content="{{ counter }}" />
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
|
||||
<ol itemscope="" itemtype="http://schema.org/BreadcrumbList" class="list-style-none d-flex">
|
||||
<li class="routing-link" itemprop="itemListElement" itemscope="" itemtype="http://schema.org/ListItem">
|
||||
<a href="/" itemprop="item" class="nopad-l">
|
||||
<span itemprop="name">Trang chủ</span>
|
||||
</a>
|
||||
<meta itemprop="position" content="1">
|
||||
</li>
|
||||
|
||||
`,
|
||||
language: 'html',
|
||||
theme: 'myCustomTheme',
|
||||
automaticLayout: true,
|
||||
minimap: { enabled: false },
|
||||
autoClosingBrackets: true,
|
||||
autoClosingQuotes: true,
|
||||
autoIndent: true,
|
||||
wordWrap: 'on',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
function open_template_list(id) {
|
||||
var $template = $('#template_list_' + id)
|
||||
if ($template.prop('open')) {
|
||||
$('#template_list_' + id).prop('open', false);
|
||||
} else {
|
||||
$('#template_list_' + id).prop('open', true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function show_older_version() {
|
||||
$('#older_version').toggle()
|
||||
}
|
||||
</script>
|
||||
@@ -31,8 +31,8 @@
|
||||
prevEl: el.querySelector(".swiper-button-prev"),
|
||||
},
|
||||
breakpoints: {
|
||||
1280: { slidesPerView: 4 },
|
||||
1600: { slidesPerView: 5 },
|
||||
1200: { slidesPerView: 5 },
|
||||
1600: { slidesPerView: 6 },
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
@@ -12,45 +12,12 @@
|
||||
|
||||
{% if global.view == 'home' %}
|
||||
{% include javascript/product_list %}
|
||||
{% elsif global.view == 'detail' %}
|
||||
{% include javascript/product-detail %}
|
||||
{% endif %}
|
||||
|
||||
{% include javascript/product_form %}
|
||||
{% elsif global.module == 'cart' %}
|
||||
|
||||
{% elsif global.module == 'deal' %}
|
||||
{% include javascript/cart %}
|
||||
|
||||
{% include javascript/product_form %}
|
||||
|
||||
{% elsif global.module == 'marketing' %}
|
||||
|
||||
{% include javascript/marketing_form %}
|
||||
|
||||
{% elsif global.module == 'brand' %}
|
||||
|
||||
{% include javascript/brand %}
|
||||
|
||||
{% elsif global.module == 'report' %}
|
||||
|
||||
{% include javascript/visitor %}
|
||||
|
||||
{% elsif global.module == 'system' %}
|
||||
|
||||
{% include javascript/system %}
|
||||
|
||||
{% elsif global.module == 'page' %}
|
||||
|
||||
{% include javascript/page %}
|
||||
|
||||
{% elsif global.module == 'template' and global.view == 'edit-template' %}
|
||||
|
||||
{% include javascript/edit_template %}
|
||||
|
||||
{% elsif global.module == 'tag' and global.view == 'add' %}
|
||||
|
||||
{% include javascript/tag %}
|
||||
|
||||
{% elsif global.module == 'shipping2' %}
|
||||
|
||||
{% include javascript/shipping2 %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
226
template/javascript/product-detail.html
Normal file
226
template/javascript/product-detail.html
Normal file
@@ -0,0 +1,226 @@
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Swiper Thumbs Gallery
|
||||
if (typeof Swiper !== "undefined") {
|
||||
var thumbsSwiper = new Swiper(".product-thumbs-swiper", {
|
||||
spaceBetween: 8,
|
||||
slidesPerView: "auto",
|
||||
freeMode: true,
|
||||
watchSlidesProgress: true,
|
||||
})
|
||||
new Swiper(".product-main-swiper", {
|
||||
spaceBetween: 0,
|
||||
thumbs: { swiper: thumbsSwiper },
|
||||
})
|
||||
}
|
||||
|
||||
// Fancybox
|
||||
if (typeof Fancybox !== "undefined") {
|
||||
Fancybox.bind("[data-fancybox='product-gallery']")
|
||||
}
|
||||
|
||||
// Tab switching
|
||||
var tabBtnSpec = document.getElementById("tab-btn-spec")
|
||||
var tabBtnInfo = document.getElementById("tab-btn-info")
|
||||
var tabContentSpec = document.getElementById("tab-content-spec")
|
||||
var tabContentInfo = document.getElementById("tab-content-info")
|
||||
var descriptionContent = document.getElementById("product-description-content")
|
||||
var descriptionFade = document.getElementById("product-description-fade")
|
||||
var toggleDescriptionBtn = document.getElementById("btn-toggle-description")
|
||||
var descriptionCollapsedHeight = 420
|
||||
var isDescriptionExpanded = false
|
||||
|
||||
function setActiveTab(active) {
|
||||
if (active === "spec") {
|
||||
tabBtnSpec.className = "w-[205px] h-10 rounded-[4px] border border-[#0084ff] bg-[#edf7ff] text-[16px] text-[#0084ff] font-bold tracking-[-0.32px]"
|
||||
tabBtnInfo.className = "w-[205px] h-10 rounded-[4px] border border-[#e6e6e6] bg-white text-[16px] text-black font-bold tracking-[-0.32px]"
|
||||
tabContentSpec.classList.remove("hidden")
|
||||
tabContentInfo.classList.add("hidden")
|
||||
} else {
|
||||
tabBtnInfo.className = "w-[205px] h-10 rounded-[4px] border border-[#0084ff] bg-[#edf7ff] text-[16px] text-[#0084ff] font-bold tracking-[-0.32px]"
|
||||
tabBtnSpec.className = "w-[205px] h-10 rounded-[4px] border border-[#e6e6e6] bg-white text-[16px] text-black font-bold tracking-[-0.32px]"
|
||||
tabContentInfo.classList.remove("hidden")
|
||||
tabContentSpec.classList.add("hidden")
|
||||
requestAnimationFrame(syncDescriptionToggle)
|
||||
}
|
||||
}
|
||||
|
||||
function syncDescriptionToggle() {
|
||||
if (!descriptionContent || !toggleDescriptionBtn || !descriptionFade || !tabContentInfo) return
|
||||
if (tabContentInfo.classList.contains("hidden")) return
|
||||
|
||||
var fullHeight = descriptionContent.scrollHeight
|
||||
if (fullHeight <= descriptionCollapsedHeight + 8) {
|
||||
descriptionContent.style.maxHeight = "none"
|
||||
descriptionFade.classList.add("hidden")
|
||||
toggleDescriptionBtn.classList.add("hidden")
|
||||
return
|
||||
}
|
||||
|
||||
toggleDescriptionBtn.classList.remove("hidden")
|
||||
|
||||
if (isDescriptionExpanded) {
|
||||
descriptionContent.style.maxHeight = fullHeight + "px"
|
||||
toggleDescriptionBtn.textContent = "Thu gọn"
|
||||
descriptionFade.classList.add("hidden")
|
||||
} else {
|
||||
descriptionContent.style.maxHeight = descriptionCollapsedHeight + "px"
|
||||
toggleDescriptionBtn.textContent = "Xem thêm"
|
||||
descriptionFade.classList.remove("hidden")
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToDescription() {
|
||||
if (!tabContentInfo) return
|
||||
var offsetTop = tabContentInfo.getBoundingClientRect().top + window.pageYOffset - 80
|
||||
window.scrollTo({
|
||||
top: offsetTop > 0 ? offsetTop : 0,
|
||||
behavior: "smooth",
|
||||
})
|
||||
}
|
||||
|
||||
if (tabBtnSpec && tabBtnInfo && tabContentSpec && tabContentInfo) {
|
||||
tabBtnSpec.addEventListener("click", function () { setActiveTab("spec") })
|
||||
tabBtnInfo.addEventListener("click", function () { setActiveTab("info") })
|
||||
}
|
||||
|
||||
if (toggleDescriptionBtn) {
|
||||
toggleDescriptionBtn.addEventListener("click", function () {
|
||||
var wasExpanded = isDescriptionExpanded
|
||||
isDescriptionExpanded = !isDescriptionExpanded
|
||||
syncDescriptionToggle()
|
||||
if (wasExpanded) {
|
||||
setTimeout(scrollToDescription, 60)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (tabContentInfo && !tabContentInfo.classList.contains("hidden")) {
|
||||
requestAnimationFrame(syncDescriptionToggle)
|
||||
}
|
||||
window.addEventListener("load", syncDescriptionToggle)
|
||||
|
||||
var installOptionGroup = document.getElementById("install-option-group")
|
||||
var installOptions = installOptionGroup ? Array.prototype.slice.call(installOptionGroup.querySelectorAll(".js-install-option")) : []
|
||||
var selectedAddonInput = document.getElementById("selected-addon-id")
|
||||
|
||||
function setInstallOptionActive(activeOption) {
|
||||
if (!activeOption) return
|
||||
|
||||
installOptions.forEach(function (option) {
|
||||
var isActive = option === activeOption
|
||||
option.classList.toggle("is-selected", isActive)
|
||||
option.classList.toggle("border-[#e4057c]", isActive)
|
||||
option.classList.toggle("bg-[#fff6f6]", isActive)
|
||||
option.classList.toggle("border-[#e2e2e2]", !isActive)
|
||||
option.classList.toggle("bg-white", !isActive)
|
||||
option.setAttribute("aria-checked", isActive ? "true" : "false")
|
||||
|
||||
var radio = option.querySelector(".js-install-radio")
|
||||
var radioDot = option.querySelector(".js-install-radio-dot")
|
||||
var selectedDot = option.querySelector(".js-install-selected-dot")
|
||||
|
||||
if (radio) {
|
||||
radio.classList.toggle("border-[#a0045c]", isActive)
|
||||
radio.classList.toggle("border-[#a9a9a9]", !isActive)
|
||||
}
|
||||
if (radioDot) {
|
||||
radioDot.classList.toggle("hidden", !isActive)
|
||||
}
|
||||
if (selectedDot) {
|
||||
selectedDot.classList.toggle("hidden", !isActive)
|
||||
}
|
||||
})
|
||||
|
||||
if (selectedAddonInput) {
|
||||
selectedAddonInput.value = activeOption.getAttribute("data-addon-id") || ""
|
||||
}
|
||||
}
|
||||
|
||||
if (installOptions.length > 0) {
|
||||
installOptions.forEach(function (option) {
|
||||
option.addEventListener("click", function () {
|
||||
setInstallOptionActive(option)
|
||||
})
|
||||
option.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault()
|
||||
setInstallOptionActive(option)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
var defaultOption = installOptionGroup.querySelector(".js-install-option.is-selected") || installOptions[0]
|
||||
setInstallOptionActive(defaultOption)
|
||||
}
|
||||
|
||||
function closeCartPopup() {
|
||||
var popup = document.getElementById("cart-popup")
|
||||
if (!popup) return
|
||||
popup.classList.add("hidden")
|
||||
popup.style.display = "none"
|
||||
document.body.classList.remove("overflow-hidden")
|
||||
}
|
||||
|
||||
function showAddToCartPopup(button) {
|
||||
var popup = document.getElementById("cart-popup")
|
||||
|
||||
if (!popup) {
|
||||
// Fallback for pages without the global popup container.
|
||||
var toast = document.getElementById("cart-toast")
|
||||
if (toast) {
|
||||
toast.classList.remove("hidden")
|
||||
setTimeout(function () { toast.classList.add("hidden") }, 3000)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var productName = button.getAttribute("data-product-name") || ""
|
||||
var productImage = button.getAttribute("data-product-image") || ""
|
||||
var productPrice = button.getAttribute("data-product-price") || "Liên hệ"
|
||||
|
||||
var popupImg = document.getElementById("cart-popup-img")
|
||||
var popupName = document.getElementById("cart-popup-name")
|
||||
var popupPrice = document.getElementById("cart-popup-price")
|
||||
|
||||
if (popupImg) popupImg.src = productImage
|
||||
if (popupName) popupName.textContent = productName
|
||||
if (popupPrice) popupPrice.textContent = productPrice
|
||||
|
||||
popup.classList.remove("hidden")
|
||||
popup.style.display = "flex"
|
||||
document.body.classList.add("overflow-hidden")
|
||||
}
|
||||
|
||||
window.closeCartPopup = closeCartPopup
|
||||
|
||||
var cartPopup = document.getElementById("cart-popup")
|
||||
if (cartPopup) {
|
||||
cartPopup.addEventListener("click", function (event) {
|
||||
if (event.target === cartPopup) {
|
||||
closeCartPopup()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Escape") {
|
||||
closeCartPopup()
|
||||
}
|
||||
})
|
||||
|
||||
var addToCartBtn = document.getElementById("btn-add-to-cart")
|
||||
if (addToCartBtn) {
|
||||
addToCartBtn.addEventListener("click", function () {
|
||||
showAddToCartPopup(addToCartBtn)
|
||||
})
|
||||
}
|
||||
|
||||
var buyNowBtn = document.getElementById("btn-buy-now")
|
||||
if (buyNowBtn) {
|
||||
buyNowBtn.addEventListener("click", function () {
|
||||
window.location.href = "/cart"
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user