/** * Generates the TqCategoriesMegamenu wrapper — the "Category Menu" primitive * (``). A single "Shop by Category" dropdown built from * the `categoriesData` taxonomy (a flat `{ id, name, parentId, order, icon? }[]` * baked in at export). Every category is a real `` linking to the * products-list page with `?=`, so the whole tree is crawlable and * SSR-rendered; the button only toggles the panel's visibility. A selected * parent id matches its whole subtree via the products' materialized * `category_filter_ids`. */ export const generateCategoriesMegamenuComponentCode = (): string => { return `import React, { useState } from 'react' import { useRouter } from 'next/router' const sanitizeSvg = (svg) => { if (typeof svg !== 'string' || !svg.trim()) { return '' } return svg .replace(//gi, '') .replace(/\\son\\w+\\s*=\\s*("[^"]*"|'[^']*'|[^\\s>]+)/gi, '') .replace(/javascript:/gi, '') } // Resolve a category's name/description to \`locale\` from its \`translations\` // map (baked in verbatim at export, alongside the main-language fields), // falling back to the main-language values when there's no override yet. const resolveCategoryLocale = (cat, locale) => { const override = locale && cat.translations ? cat.translations[locale] : null if (!override) { return cat } return Object.assign({}, cat, { name: override.name || cat.name, description: override.description || cat.description, }) } const buildCategoryTree = (categories, locale) => { const list = (Array.isArray(categories) ? categories : []).map((cat) => resolveCategoryLocale(cat, locale) ) const ids = new Set(list.map((cat) => cat.id)) const byParent = {} list.forEach((cat) => { const key = cat.parentId && ids.has(cat.parentId) ? cat.parentId : '__root__' if (!byParent[key]) { byParent[key] = [] } byParent[key].push(cat) }) const sortNodes = (a, b) => (a.order || 0) - (b.order || 0) || String(a.name || '').localeCompare(String(b.name || '')) const build = (key, seen) => (byParent[key] || []) .slice() .sort(sortNodes) .filter((cat) => !seen.has(cat.id)) .map((cat) => { seen.add(cat.id) return Object.assign({}, cat, { children: build(cat.id, seen) }) }) return build('__root__', new Set()) } // categoriesData / productsListHref / paramKey / buttonLabel / previewOpen are // destructured so they never leak onto the DOM through {...rest}. previewOpen is // an editor-only flag — the store always starts collapsed. const TqCategoriesMegamenu = ({ id, categoriesData = [], productsListHref = '/products-list', paramKey = 'categoryFilter', buttonLabel = 'Shop by Category', previewOpen, ...rest }) => { const router = useRouter() const [open, setOpen] = useState(false) const tree = buildCategoryTree(categoriesData, router.locale) const hrefFor = (categoryId) => productsListHref + '?' + paramKey + '=' + encodeURIComponent(categoryId) const renderNodes = (nodes, depth) => nodes.map((cat) => (
{cat.icon ? ( ) : null} {cat.name} {cat.children && cat.children.length ? renderNodes(cat.children, depth + 1) : null}
)) return (
{tree.length ? ( renderNodes(tree, 0) ) : (
No categories yet
)}
) } export default TqCategoriesMegamenu ` }