/* AccessoryScroll — vertical scroll-snap product viewer for accessories.
Each product occupies one full-height slide. Product images float freely
on the red background; a white info panel sits on the right with specs. */
/* ── Individual product slide ──────────────────────────────────────── */
const AccSlide = ({ lang, product, category, isActive }) => {
const productName = lang === 'el'
? (product.name_el || product.code)
: (product.name_en || product.code);
const catName = lang === 'el' ? category.label_el : category.label_en;
const images = product.images || [product.hero];
const specLabel = (s) => lang === 'el' ? (s.label_el || s.label) : (s.label_en || s.label);
const specValue = (s) => lang === 'el' ? (s.value_el || s.value) : (s.value_en || s.value);
// Replay the panel slide-in animation each time this slide becomes active
const panelRef = React.useRef(null);
React.useEffect(() => {
const el = panelRef.current;
if (!el || !isActive) return;
el.classList.remove('acc-panel-animate');
void el.offsetWidth; // force reflow
el.classList.add('acc-panel-animate');
}, [isActive]);
const imgCount = Math.min(images.length, 3);
return (
<>
{/* Floating images — cover the red background area */}
{images.slice(0, 3).map((img, i) => (
))}
{/* White info panel — right side */}
ENERGETICS
{catName}
{productName}
{t('code_label', lang)}
{product.code}
{product.specs.map((s, i) => (
{specLabel(s)}
{specValue(s)}
))}
>
);
};
/* ── Screen component ──────────────────────────────────────────────── */
const AccessoryScroll = ({ lang, categoryId }) => {
const cat = window.CATALOG;
const category = cat.categories[categoryId];
const allProducts = cat.getProductsByCategory(categoryId) || [];
const products = allProducts.filter(p => !p.placeholder);
const [currentIdx, setCurrentIdx] = React.useState(0);
const containerRef = React.useRef(null);
// Reset when category changes
React.useEffect(() => {
setCurrentIdx(0);
const container = containerRef.current;
if (container) container.scrollTop = 0;
}, [categoryId]);
// Scroll event — each slide is exactly clientHeight tall, so a simple
// Math.round(scrollTop / clientHeight) gives the current index reliably.
React.useEffect(() => {
const container = containerRef.current;
if (!container) return;
const onScroll = () => {
const h = container.clientHeight;
if (!h) return;
const idx = Math.min(
Math.round(container.scrollTop / h),
products.length - 1
);
setCurrentIdx(idx);
};
container.addEventListener('scroll', onScroll, { passive: true });
return () => container.removeEventListener('scroll', onScroll);
}, [products.length, categoryId]);
const scrollTo = (idx) => {
const container = containerRef.current;
if (!container) return;
container.scrollTo({ top: idx * container.clientHeight, behavior: 'smooth' });
};
// Placeholder state
if (products.length === 0) {
return (
{t('no_products', lang)}
{t('placeholder_text', lang)}
);
}
return (
{/* Snapping scroll container */}
{products.map((product, idx) => (
))}
{/* Dot navigation — right edge */}
{products.length > 1 && (
{products.map((_, i) => (
)}
{/* Scroll-down hint — disappears on last slide */}
{currentIdx < products.length - 1 && (
{lang === 'el' ? 'Σκρολάρετε για περισσότερα' : 'Scroll for more'}
)}
);
};
window.AccessoryScroll = AccessoryScroll;