/* ===== GLOBAL ===== */
.plp {
display: flex;
gap: 32px;
padding: 20px 0;
font-family: Arial, sans-serif;
color: #333;
align-items: flex-start;
}
/* ===== MOBILE TOP BAR ===== */
.plp-mobilebar{
display:none;
gap:12px;
align-items:center;
margin:0 0 14px;
}
.plp-filter-toggle{
border:1px solid #333;
background:#fff;
padding:10px 12px;
border-radius:10px;
cursor:pointer;
white-space:nowrap;
}
.plp-overlay{
display:none;
position:fixed;
inset:0;
background:rgba(0,0,0,.45);
z-index:9998;
}
.plp.is-open .plp-overlay{ display:block; }
/* ===== LEFT FILTER ===== */
.plp-filter {
width: 260px;
padding: 16px;
position: sticky;
top: 20px;
height: fit-content;
background: #fafafa;
border:1px solid #eee;
border-radius:12px;
}
/* Drawer header (mobile) */
.plp-filter-head{
display:none;
align-items:center;
justify-content:space-between;
gap:10px;
margin-bottom:8px;
}
.plp-filter-head strong{ font-size:14px; }
.plp-filter-close{
border:0;
background:transparent;
font-size:26px;
line-height:1;
cursor:pointer;
}
/* Filter action buttons (mobile) */
.plp-filter-actions{
display:none;
gap:10px;
margin-top:14px;
}
.plp-filter-btn{
flex:1;
padding:10px 12px;
border-radius:10px;
border:1px solid #333;
background:#fff;
cursor:pointer;
}
.plp-filter-btn.primary{
background:#333;
color:#fff;
}
.plp-filter h3 {
font-size: 15px;
margin: 18px 0 8px;
border-bottom: 1px solid #eee;
padding-bottom: 6px;
}
.plp-filter label {
display: block;
font-size: 14px;
margin-bottom: 6px;
cursor: pointer;
}
/* Color swatches */
.swatches {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
}
.swatch {
width: 22px;
height: 22px;
border-radius: 50%;
border: 1px solid #ccc;
cursor:pointer;
background:#fff;
}
.swatch.is-active{
outline:2px solid #333;
outline-offset:2px;
}
.swatch.white { background:#f5f5f0; }
.swatch.pink { background:#f2a7c6; }
.swatch.red { background:#9e2a2b; }
.swatch.yellow { background:#f2c94c; }
.swatch.purple { background:#8e7cc3; }
.swatch.coral { background:#f2997a; }
.swatch.green { background:#6fcf97; }
.swatch.mixed { background: linear-gradient(45deg,#f2a7c6,#f2c94c,#8e7cc3); }
.swatch.cream { background:#f7f3e8; }
.swatch.orange { background:#f2994a; }
.swatch.blue { background:#6fa8dc; }
.swatch.champagne { background:#efe1c6; }
.swatch.hotpink { background:#ff4fa3; }
.swatch.brown { background:#8d6e63; }
.swatch.peach { background:#f4b59f; }
.swatch.blush{ background:#f6c1cc; }
.swatch.burgundy{ background:#6b1f2b; }
.swatch.terracotta{ background:#c86b3c; }
.swatch.dusty-rose { background:#c89aa6; }
.swatch.mocha { background:#7a5a4a; }
.swatch.yellow-green { background:#a6d86f; }
.swatch.red-white{
background: linear-gradient(135deg, #c0392b 0 50%, #f5f5f0 50% 100%);
}
.swatch.green-white{
background: linear-gradient(135deg, #2ecc71 0 50%, #f5f5f0 50% 100%);
}
.swatch.light-blue { background:#8ec5ff; }
.swatch.bi-color{
background: linear-gradient(135deg, #f2a7c6 0 50%, #8e7cc3 50% 100%);
}
.swatch.variegated{
background:
radial-gradient(circle at 30% 30%, rgba(255,255,255,.7), transparent 45%),
linear-gradient(135deg, #6fcf97 0%, #f2c94c 35%, #f2a7c6 70%, #8e7cc3 100%);
}
/* ===== RIGHT CONTENT ===== */
.plp-main { flex: 1; min-width:0; }
/* Search */
.plp-search input {
width: 100%;
padding: 10px;
font-size: 14px;
}
.result-info {
font-size: 13px;
color: #666;
margin: 10px 0 24px;
}
/* ===== PRODUCT LIST ===== */
.plp-products {
display: grid;
grid-template-columns: repeat(3, minmax(0,1fr));
gap: 24px;
}
.product {
background: #fff;
padding: 12px;
border:1px solid #eee;
border-radius:12px;
transition: box-shadow .2s, transform .2s;
}
.product:hover {
box-shadow: 0 8px 24px rgba(0,0,0,0.08);
transform: translateY(-4px);
}
.product img {
width: 100%;
height: 190px;
object-fit: cover;
margin-bottom: 10px;
border-radius:10px;
}
.product h4 {
font-size: 15px;
margin: 6px 0 2px;
}
.product-sub {
font-size: 12px;
color: #777;
margin-bottom: 8px;
}
.product-specs {
list-style: none;
padding: 0;
margin: 0 0 14px;
font-size: 12.5px;
color: #666;
line-height: 1.6;
}
.product-cta {
display: block;
text-align: center;
padding: 9px;
border: 1px solid #333;
font-size: 13px;
text-decoration: none;
color: #333;
border-radius:10px;
}
.product-cta:hover {
background: #333;
color: #fff;
}
/* ===== PAGINATION ===== */
.plp-pagination {
margin-top: 36px;
text-align: right;
}
.plp-pagination span {
margin-left: 6px;
padding: 6px 10px;
border: 1px solid #ddd;
cursor: pointer;
}
/* ===== HOT SELLING ROW ===== */
.hot-selling-row {
margin-top: 64px;
padding-top: 32px;
border-top: 1px solid #eee;
}
.hot-selling-row h2 {
font-size: 20px;
margin-bottom: 20px;
}
.hot-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0,1fr));
gap: 20px;
}
.hot-card {
display:block;
padding: 12px;
background: #f7f7f7;
transition: box-shadow .2s;
text-decoration:none;
color:inherit;
border-radius:12px;
}
.hot-card:hover {
background: #fff;
box-shadow: 0 6px 20px rgba(0,0,0,0.08);
}
.hot-card img {
width: 100%;
height: 160px;
object-fit: cover;
border-radius:10px;
}
.hot-title {
font-size: 14px;
font-weight: bold;
margin-top: 8px;
}
.hot-meta {
font-size: 12px;
color: #666;
}
.hot-tag {
display: inline-block;
margin-top: 6px;
background: #c0392b;
color: #fff;
font-size: 11px;
padding: 3px 6px;
border-radius:999px;
}
/* ===== RESPONSIVE ===== */
@media (max-width: 980px){
.plp{ flex-direction:column; gap:16px; }
.plp-mobilebar{ display:flex; }
.plp-filter{
position:fixed;
top:0; left:0; bottom:0;
width:min(86vw, 340px);
transform:translateX(-110%);
transition:transform .18s ease;
z-index:9999;
border-radius:0;
overflow:auto;
}
.plp.is-open .plp-filter{ transform:translateX(0); }
.plp-filter-head{ display:flex; }
.plp-filter-actions{ display:flex; }
.plp-products{ grid-template-columns:repeat(2, minmax(0,1fr)); gap:14px; }
.hot-grid{ grid-template-columns:repeat(2, minmax(0,1fr)); }
}
@media (max-width: 560px){
.plp-products{ grid-template-columns:1fr; }
.hot-grid{ grid-template-columns:1fr; }
}
Filters
×
Danh mục
Hoa mẫu đơn cắt cành
Hoa hồng cắt cành
Hoa lan cắt cành
Hoa cẩm chướng cắt cành
Màu sắc
Chiều dài cành
30–40 cm
40–50 cm
50–60 cm
Hạng
Hạng A
Hạng AA
Giai đoạn
Tight
Giai đoạn nở bán phần
Nở hoàn toàn
Clear
Apply
Showing 0
🔥 Bán chạy · Sản phẩm bán sỉ được ưa chuộng
(function(){
const root = document.getElementById('plpRoot');
if(!root) return;
const overlay = root.querySelector('.plp-overlay');
const openBtn = root.querySelector('.plp-filter-toggle');
const closeBtn = root.querySelector('.plp-filter-close');
const list = root.querySelector('[data-list]');
const items = Array.from(root.querySelectorAll('.product'));
const countEl = root.querySelector('[data-count]');
const searchInputs = Array.from(root.querySelectorAll('[data-search]'));
const checks = Array.from(root.querySelectorAll('.plp-filter input[type="checkbox"]'));
const swatches = Array.from(root.querySelectorAll('.swatch[data-color]'));
const applyBtn = root.querySelector('[data-apply]');
const clearBtn = root.querySelector('[data-clear]');
function setOpen(isOpen){
root.classList.toggle('is-open', isOpen);
if(overlay) overlay.setAttribute('aria-hidden', isOpen ? 'false' : 'true');
document.body.style.overflow = isOpen ? 'hidden' : '';
}
function getSearch(){
const v = (searchInputs[0] && searchInputs[0].value) ? searchInputs[0].value : '';
return v.trim().toLowerCase();
}
function getChecked(name){
return checks.filter(c => c.name === name && c.checked).map(c => c.value);
}
function getColors(){
return swatches.filter(s => s.classList.contains('is-active')).map(s => s.dataset.color);
}
function inSet(val, set){
if(!set || set.length === 0) return true;
return set.includes(val);
}
function applyFilters(){
const q = getSearch();
const cats = getChecked('cat');
const stems = getChecked('stem');
const grades = getChecked('grade');
const stages = getChecked('stage');
const colors = getColors();
let shown = 0;
items.forEach(it => {
const name = (it.dataset.name || '').toLowerCase();
const ok =
(!q || name.includes(q)) &&
inSet(it.dataset.cat, cats) &&
inSet(it.dataset.stem, stems) &&
inSet(it.dataset.grade, grades) &&
inSet(it.dataset.stage, stages) &&
inSet(it.dataset.color, colors);
it.style.display = ok ? '' : 'none';
if(ok) shown++;
});
if(countEl) countEl.textContent = 'Showing ' + shown;
}
function clearAll(){
checks.forEach(c => c.checked = false);
swatches.forEach(s => s.classList.remove('is-active'));
searchInputs.forEach(i => i.value = '');
applyFilters();
}
/* Drawer events */
if(openBtn) openBtn.addEventListener('click', () => setOpen(true));
if(closeBtn) closeBtn.addEventListener('click', () => setOpen(false));
if(overlay) overlay.addEventListener('click', () => setOpen(false));
document.addEventListener('keydown', (e)=>{
if(e.key === 'Escape' && root.classList.contains('is-open')) setOpen(false);
});
if(applyBtn) applyBtn.addEventListener('click', ()=> setOpen(false));
if(clearBtn) clearBtn.addEventListener('click', clearAll);
/* Swatch toggle */
swatches.forEach(s => {
s.addEventListener('click', () => {
s.classList.toggle('is-active');
applyFilters();
});
});
/* Checkbox changes */
checks.forEach(c => c.addEventListener('change', applyFilters));
/* Search sync */
searchInputs.forEach(input => {
input.addEventListener('input', () => {
searchInputs.forEach(i => { if(i !== input) i.value = input.value; });
applyFilters();
});
});
/* init */
applyFilters();
})();