Create What You Imagine,
Find What You Need

Personalized flags, custom t-shirts, tote bags, coffee mugs, keychains & unique gifts for every occasion.

Fully Customizable
Free Shipping
Fast Production
Satisfaction Guaranteed
Shop By Occasion
Best Sellers
See All →
No products yet
Who Are You Shopping For?
Top Trending
See All →
No products yet
Browse Categories
All Categories →
New Arrivals
See All →
No products yet
Occasions
Shop
All Products
Custom Blog Account Cart
Ready to Create Something Special?
Subscribe for 10% off your first order and early access to new designs.
Or start shopping now →
var ph = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Crect fill='%23f5f5f5' width='400' height='400'/%3E%3Ctext x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' font-family='sans-serif' font-size='14' fill='%23999'%3E"; /* ===== Helper: resolve image URL ===== */ function resolveImg(path) { if (!path) return ''; return path.startsWith('http') ? path : 'https://trinmama.com' + path; } /* ===== Helper: get product thumbnail ===== */ function getProductThumb(p) { try { var pic = p.product_picture; if (pic) return resolveImg(pic.thumb_picture || pic.picture || ''); } catch(e) {} return ''; } /* ===== Helper: product detail URL ===== */ function productDetailUrl(p) { return 'product.html?id=' + (p.id || ''); } /* ===== Stars HTML ===== */ function starsHTML(r) { var n = Math.floor(r); var s = ''; for (var i = 0; i < n; i++) s += '★'; if (r % 1 >= 0.5) s += '★'; return '' + s + ''; } /* ===== Badge HTML (kept for backward compat) ===== */ function badgeHTML(badge) { if (!badge) return ''; var cls = badge === 'bestseller' ? 'product-card__badge--bestseller' : badge === 'new' ? 'product-card__badge--new' : 'product-card__badge--sale'; var txt = badge === 'bestseller' ? 'Best Seller' : badge === 'new' ? 'New' : 'Sale'; return '' + txt + ''; } /* ===== Render product row (uses shared product-card) ===== */ function renderProductRow(elId, list, defaultBadge) { var el = document.getElementById(elId); if (!el) return; el.innerHTML = list.map(function(p) { return window.renderProductCard(p); }).join(''); } /* ===== Fallback Data ===== */ /* Product/occasion/category data loaded from API below */ /* ===== Recipients (static) ===== */ var recipients = [ { name: 'For Her', sub: 'Flags, Tees, Mugs', img: 'images/666aa4f976458667f0be19f81ab24b9c.png', kw: 'women+girl+grandma+nurse+teacher+sister+aunt' }, { name: 'For Him', sub: 'Tees, Accessories', img: 'images/28cd1983f0de830bf5c78d2510d8772c.png', kw: 'dad+grandpa+father+man+brother+uncle+boy' }, { name: 'For Couples', sub: 'Matching Sets', img: 'images/f7933e63be11567e4d770cdac041c853.png', kw: 'family+couple+matching+anniversary+wedding+love+pair' }, { name: 'For Kids', sub: 'Fun Tees', img: 'images/732adf1d978345faaa1b9293cd715c18.png', kw: 'teacher+kid+nurse+silly+funny+baby+toddler+children' }, { name: 'Pet Lovers', sub: 'Pet Designs', img: 'images/f8bbc57bd4a36f9dd9fa706e4a5ed226.png', kw: 'pet+dog+cat+portrait+animal+puppy+kitten' }, { name: 'For Mom', sub: 'Totes, Mugs, Tees', img: 'images/723eb67ce486ac0b388a2bd84a7c466c.png', kw: 'mom+mother+grandma+mama+mommy' } ]; /* ===== Render static recipients ===== */ document.getElementById('recipients').innerHTML = recipients.map(function(r) { return '' + '
' + r.name + '
' + '
' + r.name + '
' + '
' + r.sub + '
'; }).join(''); /* ===== Hero Carousel ===== */ var heroSlideIndex = 0; var heroSlideTimer = null; var heroSlideImages = []; function initHero(pictures) { var wrap = document.getElementById('heroImgWrap'); var dots = document.getElementById('heroDots'); if (!wrap || !pictures || !pictures.length) return; heroSlideImages = pictures.map(function(p) { return { src: resolveImg(p.path || p.image || ''), link: p.link || '', title: p.title || '' }; }); // 只插入 img,保留 dots var existingDots = document.getElementById('heroDots'); wrap.innerHTML = heroSlideImages.map(function(item, i) { return '' + item.title + ''; }).join(''); if (existingDots) wrap.appendChild(existingDots); if (heroSlideImages.length > 1) { var prevBtn = document.createElement('button'); prevBtn.className = 'hero-banner__arrow hero-banner__arrow--prev'; prevBtn.innerHTML = '\u276E'; prevBtn.setAttribute('aria-label', 'Previous slide'); prevBtn.addEventListener('click', function(e) { e.stopPropagation(); prevHeroSlide(); }); wrap.appendChild(prevBtn); var nextBtn = document.createElement('button'); nextBtn.className = 'hero-banner__arrow hero-banner__arrow--next'; nextBtn.innerHTML = '\u276F'; nextBtn.setAttribute('aria-label', 'Next slide'); nextBtn.addEventListener('click', function(e) { e.stopPropagation(); nextHeroSlide(); }); wrap.appendChild(nextBtn); } if (heroSlideImages.length > 1 && dots) { dots.innerHTML = heroSlideImages.map(function(_, i) { return ''; }).join(''); dots.addEventListener('click', function(e) { var dot = e.target.closest('.hero-banner__dot'); if (dot) { heroSlideIndex = parseInt(dot.dataset.i); showHeroSlide(); resetHeroTimer(); } }); } else if (dots) { dots.innerHTML = ''; } if (heroSlideImages.length > 1) { heroSlideTimer = setInterval(function() { heroSlideIndex = (heroSlideIndex + 1) % heroSlideImages.length; showHeroSlide(); }, 6000); } wrap.style.cursor = 'pointer'; wrap.addEventListener('click', function() { var cur = heroSlideImages[heroSlideIndex]; if (cur && cur.link) window.location.href = cur.link; }); } function prevHeroSlide() { heroSlideIndex = (heroSlideIndex - 1 + heroSlideImages.length) % heroSlideImages.length; showHeroSlide(); resetHeroTimer(); } function nextHeroSlide() { heroSlideIndex = (heroSlideIndex + 1) % heroSlideImages.length; showHeroSlide(); resetHeroTimer(); } function showHeroSlide() { var slides = document.querySelectorAll('#heroImgWrap img'); var dots = document.querySelectorAll('.hero-banner__dot'); slides.forEach(function(img, i) { img.classList.toggle('active', i === heroSlideIndex); }); dots.forEach(function(dot, i) { dot.classList.toggle('active', i === heroSlideIndex); }); } function resetHeroTimer() { if (heroSlideTimer) clearInterval(heroSlideTimer); heroSlideTimer = setInterval(function() { heroSlideIndex = (heroSlideIndex + 1) % heroSlideImages.length; showHeroSlide(); }, 6000); } /* ===== Announcement Bar: handled by global-nav.js?v=20260624 */ /* ===== Main Data Loading ===== */ async function loadHome() { console.log('[loadHome] called'); try { var result = await Home.getData(); console.log('[loadHome] result:', result); var homeData = (result && result.data) ? result.data : (result || {}); var adData = homeData.ad || {}; var carousel = adData.carousel && adData.carousel.pictures ? adData.carousel.pictures : []; // 1) Hero Carousel if (carousel.length) { initHero(carousel); } // 3) Free shipping threshold if (homeData.free_shipping_threshold) { var shipEl = document.getElementById('freeShipAmt'); if (shipEl) shipEl.textContent = '$' + homeData.free_shipping_threshold + '+'; } // 4) Shop By Occasion - try themes/categories from API var themes = homeData.themes || homeData.categories || []; if (themes.length) { document.getElementById('occasionScroll').innerHTML = themes.map(function(t) { var pic = t.picture || t.icon || t.image || t.pic || ''; var src = pic ? (pic.startsWith('http') ? pic : resolveImg(pic)) : (ph + encodeURIComponent(t.name || 'Theme') + "%3C/text%3E%3C/svg%3E"); var count = t.product_count || ''; return '' + '' + (t.name || '') + '' + '
' + (t.name || '') + '
' + '
' + (count ? count + ' Gifts' : '') + '
'; }).join(''); } // 5) Browse Categories - from category_product var categoryProduct = homeData.category_product || []; if (categoryProduct.length) { document.getElementById('catGrid').innerHTML = categoryProduct.slice(0, 8).map(function(cat) { var pic = cat.category_pic_thumb || cat.category_pic || cat.icon || cat.image || ''; var src = pic ? (pic.startsWith('http') ? pic : resolveImg(pic)) : (ph + encodeURIComponent(cat.category_name || 'Category') + "%3C/text%3E%3C/svg%3E"); var name = cat.category_name || cat.name || ''; if (!pic) return ''; var href = window.categoryUrl ? window.categoryUrl(cat) : 'products.html?cat=' + cat.id; return '' + '' + name + '' + '
' + name + '
'; }).filter(Boolean).join(''); } // 6) Top Trending - from hot_sale_product var hotProducts = homeData.hot_sale_product || []; if (hotProducts.length >= 2) { renderProductRow('trendingScroll', hotProducts.slice(0, 16)); } // 7) Best Sellers - from best_product var bestProducts = homeData.best_product || []; if (bestProducts.length >= 2) { renderProductRow('bestsellerScroll', bestProducts.slice(0, 16), 'bestseller'); } // 8) New Arrivals - from new_product var newProducts = homeData.new_product || []; if (newProducts.length >= 2) { renderProductRow('newArrivalsScroll', newProducts.slice(0, 16), 'new'); } // Navigation handled by global-nav.js?v=20260624 // Show empty hints for sections with no data var emptyHint = '
No products yet
'; if (!hotProducts.length) { var ts = document.getElementById('trendingScroll'); if (ts && !ts.children.length) ts.innerHTML = emptyHint; } if (!bestProducts.length) { var bs = document.getElementById('bestsellerScroll'); if (bs && !bs.children.length) bs.innerHTML = emptyHint; } if (!newProducts.length) { var na = document.getElementById('newArrivalsScroll'); if (na && !na.children.length) na.innerHTML = emptyHint; } } catch(err) { console.warn('Home API load failed, using static fallback:', err); } } /* ===== Init ===== */ try { if (typeof updateCartBadge === 'function') updateCartBadge(); } catch(e) {} // Load Shop By Occasion cards (nav handled by global-nav.js?v=20260624 (async function loadOccasionCards() { try { var res = await fetch('/api/v1/product-themes'); var json = await res.json(); var themes = (json && json.data) || []; if (!themes.length) return; themes.sort(function(a, b) { return a.sort_num - b.sort_num; }); var themePageMap = { 'america-250':'america250.html', 'father-day':'fathers-day.html', 'pet-lovers':'pet-lover.html', 'family':'family-gifts.html', 'sports':'sports.html', 'Soccer Nation 2026':'soccer-nation.html', 'zodiac-star-signs':'zodiac-star-signs.html', 'graduation-2026':'graduation-2026.html', 'wedding':'wedding.html' }; var scroll = document.getElementById('occasionScroll'); if (!scroll) return; var items = themes.map(function(t) { var banner = t.banner_thumb || t.banner || t.picture || t.image || ''; var src = banner ? resolveImg(banner) : ''; var name = t.title || t.name || ''; var link = themePageMap[t.name] || 'products.html?theme=' + (t.name || t.id); if (!src) return ''; return '' + '' + name + '' + '
' + name + '
'; }).filter(Boolean).join(''); if (!items) items = '
No occasions yet
'; scroll.innerHTML = items; } catch(e) { console.warn('Occasion cards load failed:', e); } })(); // Hamburger mobile menu toggle var hamburger = document.getElementById('hamburger'); var mobileMenu = document.getElementById('mobileMenu'); if (hamburger && mobileMenu) { hamburger.addEventListener('click', function() { var isOpen = this.classList.toggle('active'); mobileMenu.classList.toggle('open', isOpen); this.setAttribute('aria-expanded', isOpen); }); } // Dropdown open on mobile tap document.querySelectorAll('.nav__dropdown > span, .nav__dropdown > a').forEach(function(trigger) { trigger.addEventListener('click', function(e) { if (window.innerWidth <= 768 && !e.metaKey && !e.ctrlKey && !e.shiftKey) { e.preventDefault(); var parent = this.parentElement; parent.classList.toggle('open'); } }); }); // Inject scroll arrows document.querySelectorAll('.occasion-scroll, .recipient-grid, .cat-quick-grid').forEach(function(el) { if (el.closest('.scroll-wrap')) return; var wrap = document.createElement('div'); wrap.className = 'scroll-wrap'; el.parentNode.insertBefore(wrap, el); wrap.appendChild(el); var left = document.createElement('button'); left.className = 'scroll-arrow scroll-arrow--left scroll-arrow--hidden'; left.innerHTML = '❮'; left.setAttribute('aria-label', 'Scroll left'); var right = document.createElement('button'); right.className = 'scroll-arrow scroll-arrow--right'; right.innerHTML = '❯'; right.setAttribute('aria-label', 'Scroll right'); wrap.appendChild(left); wrap.appendChild(right); var _raf = null; function updateArrows() { if (_raf) return; _raf = requestAnimationFrame(function() { _raf = null; left.classList.toggle('scroll-arrow--hidden', el.scrollLeft <= 5); right.classList.toggle('scroll-arrow--hidden', el.scrollLeft + el.clientWidth >= el.scrollWidth - 5); }); } el.addEventListener('scroll', updateArrows, { passive: true }); updateArrows(); // Re-check when content is loaded dynamically var mo = new MutationObserver(updateArrows); mo.observe(el, { childList: true, subtree: true }); left.addEventListener('click', function() { el.scrollBy({ left: -el.clientWidth * 0.6, behavior: 'smooth' }); }); right.addEventListener('click', function() { el.scrollBy({ left: el.clientWidth * 0.6, behavior: 'smooth' }); }); }); // Load home data (nav handled by global-nav.js?v=20260624 loadHome(); })();