/* global React, PAPERS, BRANDS, FINISHES, COLOR_GROUPS, CATEGORIES, PaperCard, BrandStamp, Icon */ const { useState, useEffect, useMemo, useCallback, useRef } = React; function GalleryPage({ navigate, tweaks, cart, addToCart, compare, toggleCompare, openCompareModal, query, catalog, catalogLoading, catalogError }) { // ----- Filter state ----- const [activeCat, setActiveCat] = useState(query.cat || "all"); const [selBrands, setSelBrands] = useState(query.brand ? [query.brand] : []); const [selFinishes, setSelFinishes] = useState([]); const [selColors, setSelColors] = useState([]); const [gsmMin, setGsmMin] = useState(60); const [gsmMax, setGsmMax] = useState(350); const [sort, setSort] = useState("featured"); const [drawerOpen, setDrawerOpen] = useState(false); const [mobileAccOpen, setMobileAccOpen] = useState(false); const PAGE_SIZE = 12; const [page, setPage] = useState(1); var activePapers = catalog && catalog.length > 0 ? catalog : (window.PAPERS || []); var activeCategories = (catalog && catalog.length > 0 && catalog[0] && catalog[0].acc_id) ? (window.ACC_CATEGORIES || window.CATEGORIES) : window.CATEGORIES; // Reset activeCat kalau value lama tidak ada di activeCategories baru useEffect(() => { if (activeCat !== "all" && !activeCategories.find(c => c.id === activeCat)) { setActiveCat("all"); } }, [activeCategories]); // sync external query (e.g. nav links) useEffect(() => { if (query.cat) setActiveCat(query.cat); if (query.brand) setSelBrands([query.brand]); }, [query.cat, query.brand]); useEffect(() => { setPage(1); }, [activeCat, selBrands, selFinishes, selColors, gsmMin, gsmMax]); const toggleSet = (set, setSetter, val) => { setSetter(set.includes(val) ? set.filter(x => x !== val) : [...set, val]); }; // ----- Apply filters ----- const filtered = useMemo(() => { const cat = activeCategories.find(c => c.id === activeCat) || activeCategories[0]; let list = activePapers.filter(p => cat.match(p)); if (selBrands.length) list = list.filter(p => selBrands.includes(p.brand)); if (selFinishes.length) list = list.filter(p => selFinishes.includes(p.finish)); if (selColors.length) list = list.filter(p => selColors.includes(p.colorGroup)); list = list.filter(p => p.gsm >= gsmMin && p.gsm <= gsmMax); list = list.filter(p => (p.price_min || 0) >= 100 || Object.keys(p.price || {}).length > 0); if (sort === "price-asc") list = [...list].sort((a,b) => (a.price_min || 0) - (b.price_min || 0)); else if (sort === "price-desc") list = [...list].sort((a,b) => (b.price_min || 0) - (a.price_min || 0)); else if (sort === "gsm-asc") list = [...list].sort((a,b) => a.gsm - b.gsm); else if (sort === "gsm-desc") list = [...list].sort((a,b) => b.gsm - a.gsm); else if (sort === "featured") list = [...list].sort((a,b) => (b.featured?1:0) - (a.featured?1:0)); return list; }, [activePapers, activeCat, selBrands, selFinishes, selColors, gsmMin, gsmMax, sort]); const visiblePapers = filtered.slice(0, page * PAGE_SIZE); const hasMore = filtered.length > page * PAGE_SIZE; // ----- Counts per category ----- const catCounts = useMemo(() => { const o = {}; activeCategories.forEach(c => { o[c.id] = activePapers.filter(p => c.match(p)).length; }); return o; }, [activePapers, activeCategories]); // ----- Active filter chips ----- const activeChips = []; if (activeCat !== "all" && activeCategories.find(c=>c.id===activeCat)) activeChips.push({ label: activeCategories.find(c=>c.id===activeCat).label, clear: () => setActiveCat("all") }); selBrands.forEach(b => activeChips.push({ label: b, clear: () => setSelBrands(selBrands.filter(x => x !== b)) })); selFinishes.forEach(f => activeChips.push({ label: f, clear: () => setSelFinishes(selFinishes.filter(x => x !== f)) })); selColors.forEach(c => activeChips.push({ label: COLOR_GROUPS.find(g => g.id === c).label, clear: () => setSelColors(selColors.filter(x => x !== c)) })); if (gsmMin !== 60 || gsmMax !== 350) activeChips.push({ label: `${gsmMin}–${gsmMax}gsm`, clear: () => { setGsmMin(60); setGsmMax(350); } }); const clearAll = () => { setActiveCat("all"); setSelBrands([]); setSelFinishes([]); setSelColors([]); setGsmMin(60); setGsmMax(350); }; const filterPos = tweaks.filterPos || "left-rail"; const gridType = (catalog && catalog[0] && catalog[0].acc_id) ? "uniform" : (tweaks.gridType || "editorial"); const density = tweaks.density || "default"; // Hide sidebar on mobile — accordion handles filters there const [windowW, setWindowW] = useState(typeof window !== "undefined" ? window.innerWidth : 1200); useEffect(() => { const onResize = () => setWindowW(window.innerWidth); window.addEventListener("resize", onResize); return () => window.removeEventListener("resize", onResize); }, [activePapers, activeCategories]); const isMobile = windowW <= 980; const sidebarVisible = filterPos === "left-rail" && !isMobile; return (
{/* -------- HERO -------- */} {catalogLoading && (
Memuat catalog…
)} {catalogError && !catalogLoading && (
Menggunakan data lokal.
)} {/* -------- Top filter bar (categories) -------- */}
Browse {activeCategories.map(c => ( ))}
{filterPos === "top-bar" && ( )}
{/* -------- Mobile filter accordion -------- */}
Brand
{BRANDS.map(b => )}
Finish
{FINISHES.map(f => )}
Berat Kertas
{gsmMin} gsm{gsmMax} gsm
setGsmMin(Math.min(Number(e.target.value), gsmMax - 10))} style={{width:"100%", marginBottom:6}} /> setGsmMax(Math.max(Number(e.target.value), gsmMin + 10))} style={{width:"100%"}} />
Warna
{COLOR_GROUPS.map(g =>
{(selBrands.length + selFinishes.length + selColors.length + (gsmMin !== 60 || gsmMax !== 350 ? 1 : 0)) > 0 && ( )}
{/* -------- Main gallery body -------- */}
{sidebarVisible && ( )}
{/* Toolbar */}
{filtered.length} kertas {activeCat !== "all" && activeCategories.find(c=>c.id===activeCat) && <> · {activeCategories.find(c=>c.id===activeCat)?.label}}
Sort
{/* Active filter chips */} {activeChips.length > 0 && (
{activeChips.map((ch, i) => ( {ch.label} ))}
)} {/* Grid */} {filtered.length === 0 ? ( ) : (
{visiblePapers.map(p => ( navigate("/product/" + p.id)} onAddCart={() => addToCart(p)} onToggleCompare={() => toggleCompare(p)} isComparing={compare.some(x => x.id === p.id)} onRequestSample={(paper) => { addSampleToList(paper); navigate("/sample-request"); }} /> ))}
)} {hasMore && (
)}
{/* -------- Featured Fedrigoni banner -------- */} {/* -------- Sample kit strip -------- */}
); } // helper for "request sample" cta from card — stash in localStorage function addSampleToList(paper) { try { const cur = JSON.parse(localStorage.getItem("ip_samples") || "[]"); if (!cur.find(x => x.id === paper.id)) { cur.push({ id: paper.id, brand: paper.brand, name: paper.name, gsm: paper.gsm, finish: paper.finish, tone: paper.swatchTone }); localStorage.setItem("ip_samples", JSON.stringify(cur)); } } catch (e) {} } // ============================================================ // HERO // ============================================================ const HERO_WORDS = ["paper.", "texture.", "kraft.", "bamboo.", "felt.", "letterpress.", "arcoprint.", "swatch.", "premium."]; function TypedWord() { const prefersReduced = useRef( typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches ); const [display, setDisplay] = useState("paper."); const [phase, setPhase] = useState("hold"); const [idx, setIdx] = useState(0); useEffect(() => { let timeout; const word = HERO_WORDS[idx]; if (phase === "hold") { timeout = setTimeout(() => setPhase("delete"), 1800); } else if (phase === "delete") { if (display.length > 0) { timeout = setTimeout(() => setDisplay(d => d.slice(0, -1)), 55); } else { const next = (idx + 1) % HERO_WORDS.length; setIdx(next); setPhase("type"); } } else if (phase === "type") { const target = HERO_WORDS[idx]; if (display.length < target.length) { timeout = setTimeout(() => setDisplay(target.slice(0, display.length + 1)), 80); } else { setPhase("hold"); } } return () => clearTimeout(timeout); }, [phase, display, idx]); if (false && prefersReduced.current) { return paper.; } return ( {display} ); } function Hero() { return (
{/* Dashed flight path — clipped dalam hero bounds */} {/* Paper plane — posisi CSS, bukan SVG transform */}

Find

「 The Gallery 」 ペーパー

Specialty paper untuk designer, studio kreatif, dan brand yang peduli kualitas. Pre-cut A4 / A3 / SRA3 — MOQ 10 lembar.

302papers in stock
8categories
10min order
); } // ============================================================ // BRAND VALUES STRIP // ============================================================ function BrandValuesStrip() { return (
Pre-cut, siap pakai
A3+ pre-cut untuk semua kertas. Tidak perlu beli rim — order mulai 10 lembar.
Brand premium dunia
Mohawk, Conqueror, Fedrigoni, Antalis — kertas yang sama dipakai studio terbaik di Eropa dan Amerika.
Jakarta, kirim cepat
Stok tersedia di Jakarta. Jabodetabek 1–2 hari kerja, luar kota 3–5 hari.
); } // ============================================================ // FEATURED COLLECTIONS // ============================================================ function FeaturedCollections({ navigate }) { const collections = [ { id: 'fancy', label: 'Fancy Paper', desc: 'Kertas premium dengan tekstur dan finishing eksklusif — untuk karya yang benar-benar berkesan.', tone: '#F4EFE3', grain: 'felt', cat: 'fancy', count: '133 produk', }, { id: 'creative', label: 'Creative Paper', desc: 'Pilihan kreatif untuk desainer — warna, tekstur, dan permukaan yang tidak biasa.', tone: '#E8E0D0', grain: 'smooth', cat: 'creative', count: '51 produk', }, { id: 'standard', label: 'Standard Paper', desc: 'Kertas berkualitas untuk kebutuhan sehari-hari studio — reliable, konsisten, harga terjangkau.', tone: '#F0EBE0', grain: 'smooth', cat: 'standard', count: '21 produk', }, { id: 'eco', label: 'Eco Series', desc: 'Kertas ramah lingkungan — FSC certified, bamboo fiber, recycled content.', tone: '#E8EDE0', grain: 'fiber', cat: 'eco', count: 'Eco certified', eco: true, }, ]; return (
「 Collections 」

Browse by category

{collections.map(col => (
navigate('/gallery?cat=' + col.cat)} >
{col.eco && ( Eco · FSC )}
{col.label}
{col.desc}
{col.count}
))}
); } // ============================================================ // BRAND SPOTLIGHT — Mohawk // ============================================================ function BrandSpotlight({ navigate }) { return (
「 Featured Brand 」

The Mohawk
Collection

Pabrik kertas premium independen terbesar di Amerika Utara. Mohawk Via Felt, Superfine, Loop — kertas yang sama dipakai studio dan desainer terbaik di seluruh dunia, kini tersedia di Jakarta mulai 10 lembar.

25+produk Mohawk
90–300gsm range
USAorigin
MOHAWK VIA FELT · USA
); } // ============================================================ // FILTER PANEL // ============================================================ function FilterPanel({ selBrands, setSelBrands, toggleSet, selFinishes, setSelFinishes, selColors, setSelColors, gsmMin, setGsmMin, gsmMax, setGsmMax, onClose, showCloseBtn, }) { return ( <> {showCloseBtn && (
Filters
)}

Brand

{BRANDS.map(b => ( ))}

Weight (gsm)

{gsmMin} {gsmMax}
setGsmMin(Math.min(Number(e.target.value), gsmMax - 10))} /> setGsmMax(Math.max(Number(e.target.value), gsmMin + 10))} />
60 gsm350 gsm

Finish

{FINISHES.map(f => ( ))}

Color

{COLOR_GROUPS.map(g => (

Print method

); } // ============================================================ // EMPTY STATE // ============================================================ function EmptyState({ clearAll }) { return (
Tidak ada kertas yang cocok.

Coba longgarkan filter — atau biarkan kami pilihkan.

); } // ============================================================ // FEATURED FEDRIGONI BANNER // ============================================================ function FedrigoniBanner({ navigate }) { return (
{/* corner sticker */}
SINCE 1888 · ITALIA
Featured Collection

The Fedrigoni
Collection

Lebih dari 130 tahun, Fedrigoni adalah standar emas kertas Italia. Dari Arcoprint sampai Sirio Pearl — sekarang tersedia di Jakarta, dipotong sesuai kebutuhan, mulai 10 lembar.

6 series in stock 30+ colorways 90–350 gsm range
); } // ============================================================ // SAMPLE KIT STRIP // ============================================================ function SampleKitStrip({ navigate }) { return (
「 Free · Gratis 」

Belum yakin kertas yang mana? Pesan sample kit.

Kami kirim 8 lembar kertas pilihan kami (atau pilihan Anda) — gratis ongkir Jakarta, tinggal ditimang, dipegang, dicoba print sendiri.

); } Object.assign(window, { GalleryPage, Hero, FilterPanel, FedrigoniBanner, SampleKitStrip, BrandValuesStrip, FeaturedCollections, BrandSpotlight, addSampleToList, });