@brunoalz/smartgesti-site-editor 1.7.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/engine/export/exporters/sections/BlogPostExporters.d.ts.map +1 -1
  2. package/dist/engine/export/exporters/sections/BlogPostExporters.js +585 -227
  3. package/dist/engine/export/exporters/sections/BlogPostExporters.js.map +1 -1
  4. package/dist/engine/plugins/builtin/blog/manifest.d.ts.map +1 -1
  5. package/dist/engine/plugins/builtin/blog/manifest.js +264 -112
  6. package/dist/engine/plugins/builtin/blog/manifest.js.map +1 -1
  7. package/dist/engine/plugins/contentHydration.js +93 -77
  8. package/dist/engine/plugins/contentHydration.js.map +1 -1
  9. package/dist/engine/registry/blocks/sections/blogCategoryFilter.d.ts.map +1 -1
  10. package/dist/engine/registry/blocks/sections/blogCategoryFilter.js +0 -1
  11. package/dist/engine/registry/blocks/sections/blogCategoryFilter.js.map +1 -1
  12. package/dist/engine/registry/blocks/sections/blogPostGrid.d.ts.map +1 -1
  13. package/dist/engine/registry/blocks/sections/blogPostGrid.js +321 -6
  14. package/dist/engine/registry/blocks/sections/blogPostGrid.js.map +1 -1
  15. package/dist/engine/registry/blocks/sections/blogRecentPosts.d.ts.map +1 -1
  16. package/dist/engine/registry/blocks/sections/blogRecentPosts.js +11 -2
  17. package/dist/engine/registry/blocks/sections/blogRecentPosts.js.map +1 -1
  18. package/dist/engine/registry/blocks/sections/blogTagCloud.d.ts.map +1 -1
  19. package/dist/engine/registry/blocks/sections/blogTagCloud.js +0 -1
  20. package/dist/engine/registry/blocks/sections/blogTagCloud.js.map +1 -1
  21. package/dist/engine/render/renderers/sections/BlogPostCardRenderer.d.ts.map +1 -1
  22. package/dist/engine/render/renderers/sections/BlogPostCardRenderer.js +35 -33
  23. package/dist/engine/render/renderers/sections/BlogPostCardRenderer.js.map +1 -1
  24. package/dist/engine/render/renderers/sections/BlogPostGridRenderer.d.ts.map +1 -1
  25. package/dist/engine/render/renderers/sections/BlogPostGridRenderer.js +251 -66
  26. package/dist/engine/render/renderers/sections/BlogPostGridRenderer.js.map +1 -1
  27. package/dist/engine/render/renderers/sections/BlogRecentPostsRenderer.d.ts.map +1 -1
  28. package/dist/engine/render/renderers/sections/BlogRecentPostsRenderer.js +31 -30
  29. package/dist/engine/render/renderers/sections/BlogRecentPostsRenderer.js.map +1 -1
  30. package/dist/engine/schema/siteDocument.d.ts +36 -1
  31. package/dist/engine/schema/siteDocument.d.ts.map +1 -1
  32. package/dist/engine/schema/siteDocument.js.map +1 -1
  33. package/dist/engine/shared/iconUtils.d.ts +25 -0
  34. package/dist/engine/shared/iconUtils.d.ts.map +1 -0
  35. package/dist/engine/shared/iconUtils.js +43 -0
  36. package/dist/engine/shared/iconUtils.js.map +1 -0
  37. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.js","sources":["../../../../../src/engine/plugins/builtin/blog/manifest.ts"],"sourcesContent":["/**\n * Blog Plugin Manifest\n * Plugin para blog com posts, categorias e tags.\n *\n * onActivate:\n * 1. Injeta seção blogPostGrid na home page (antes do footer)\n * 2. Cria página \"Blog\" com navbar + grid de posts + footer\n * 3. Cria página \"Post\" com navbar + detalhe do post + footer\n *\n * onDeactivate:\n * 1. Remove a seção injetada na home page\n * 2. Remove as páginas do plugin\n */\n\nimport type { PluginRegistration } from \"../../types\";\nimport type { SiteDocument, Block, BlockType } from \"../../../schema/siteDocument\";\nimport { pluginRegistry } from \"../../pluginRegistry\";\nimport { logger } from \"../../../../utils/logger\";\n\n// ─── ID usado para a seção de blog injetada na home page ───\nconst BLOG_HOME_SECTION_ID = \"plugin-blog-home-grid\";\n\n// ─── Sample blog cards para preview ───\nconst SAMPLE_BLOG_CARDS = [\n {\n title: \"Feira de Ciências 2026: Inovação e Criatividade\",\n excerpt:\n \"Nossos alunos apresentaram projetos incríveis na Feira de Ciências deste ano. Confira os destaques e premiações!\",\n image:\n \"https://images.unsplash.com/photo-1567168544230-3b9e5ec47659?w=800&h=400&fit=crop\",\n category: \"Eventos\",\n date: \"05 Fev 2026\",\n linkHref: \"/site/p/blog/feira-de-ciencias-2026\",\n linkText: \"Ler mais\",\n },\n {\n title: \"Matrículas Abertas para o Segundo Semestre\",\n excerpt:\n \"Garanta a vaga do seu filho na melhor escola da região. Condições especiais para matrículas antecipadas.\",\n image:\n \"https://images.unsplash.com/photo-1523050854058-8df90110c9f1?w=800&h=400&fit=crop\",\n category: \"Institucional\",\n date: \"01 Fev 2026\",\n linkHref: \"/site/p/blog/matriculas-segundo-semestre\",\n linkText: \"Ler mais\",\n },\n {\n title: \"5 Dicas para Preparar seu Filho para o Ano Letivo\",\n excerpt:\n \"Dicas práticas para uma transição tranquila e um início de ano produtivo para toda a família.\",\n image:\n \"https://images.unsplash.com/photo-1503676260728-1c00da094a0b?w=800&h=400&fit=crop\",\n category: \"Educação\",\n date: \"28 Jan 2026\",\n linkHref: \"/site/p/blog/dicas-preparar-ano-letivo\",\n linkText: \"Ler mais\",\n },\n];\n\n// ─── Conteúdo HTML rico para o post de exemplo ───\nconst SAMPLE_POST_CONTENT = `\n<h2>O que é a Feira de Ciências?</h2>\n<p>A Feira de Ciências é um evento anual que celebra a curiosidade, a pesquisa e a criatividade dos nossos alunos. Nesta edição especial de 2026, recebemos mais de <strong>500 visitantes</strong> e contamos com a participação de todas as turmas do Ensino Fundamental e Médio.</p>\n<p>Este ano, o tema central foi <em>\"Ciência e Sustentabilidade\"</em>, incentivando os estudantes a desenvolverem projetos que aliassem inovação tecnológica com responsabilidade ambiental.</p>\n\n<h2>Destaques da Edição 2026</h2>\n<p>Entre os mais de 50 projetos apresentados, alguns se destacaram pela originalidade e impacto:</p>\n<ul>\n <li><strong>Jardim Sustentável Inteligente</strong> — Alunos do 5º ano desenvolveram um sistema de irrigação automática usando sensores de umidade e placa Arduino.</li>\n <li><strong>Robótica Educacional</strong> — A turma do 8º ano criou um robô que auxilia no ensino de matemática para crianças do 1º ao 3º ano.</li>\n <li><strong>Energia Solar na Escola</strong> — Projeto do 2º ano do Ensino Médio demonstrou como painéis solares poderiam reduzir em 40% o consumo de energia da escola.</li>\n</ul>\n\n<blockquote>\n <p>\"A Feira de Ciências é um dos momentos mais importantes do nosso calendário escolar. Ver a dedicação e o brilho nos olhos dos alunos ao apresentarem seus projetos nos enche de orgulho e nos motiva a continuar investindo em educação de qualidade.\"</p>\n <p><strong>— Prof. Maria Silva, Coordenadora Pedagógica</strong></p>\n</blockquote>\n\n<h2>Premiações</h2>\n<p>O júri, composto por professores universitários e profissionais da área de tecnologia, selecionou os três melhores projetos:</p>\n<ol>\n <li><strong>1º Lugar:</strong> Jardim Sustentável Inteligente (5º ano)</li>\n <li><strong>2º Lugar:</strong> Energia Solar na Escola (2º EM)</li>\n <li><strong>3º Lugar:</strong> Robótica Educacional (8º ano)</li>\n</ol>\n\n<h2>Próximos Passos</h2>\n<p>Os três projetos finalistas representarão nossa escola na <strong>Feira Regional de Ciências</strong>, que acontecerá em março na capital. Os alunos já estão se preparando para levar suas apresentações a um público ainda maior.</p>\n<p>Parabéns a todos os participantes, professores orientadores e famílias que apoiaram essa jornada de descobertas!</p>\n`.trim();\n\n/**\n * Deep-clone um bloco com novo ID\n */\nfunction cloneBlock(block: Block, newId: string): Block {\n const cloned: Block = JSON.parse(JSON.stringify(block));\n return { ...cloned, id: newId };\n}\n\nexport const blogPlugin: PluginRegistration = {\n manifest: {\n id: \"blog\",\n version: \"1.0.0\",\n name: \"Blog\",\n description: \"Blog com posts, categorias e tags\",\n icon: \"FileText\",\n\n capabilities: {\n blocks: [\"blogPostCard\", \"blogPostGrid\", \"blogPostDetail\", \"blogCategoryFilter\", \"blogSearchBar\", \"blogRecentPosts\", \"blogTagCloud\"],\n\n pageTemplates: [\n {\n id: \"blog-listing\",\n name: \"Blog\",\n slug: \"blog\",\n pluginId: \"blog\",\n structure: [],\n dataSource: {\n provider: \"blog-posts\",\n mode: \"list\",\n },\n },\n {\n id: \"blog-post\",\n name: \"Post\",\n slug: \"blog/:slug\",\n pluginId: \"blog\",\n structure: [],\n dataSource: {\n provider: \"blog-posts\",\n mode: \"single\",\n paramMapping: { slug: \":slug\" },\n },\n editRestrictions: {\n nonRemovable: true,\n },\n },\n ],\n\n dataSchemas: [\n {\n type: \"blog-post\",\n label: \"Blog Post\",\n fields: [\n { name: \"title\", type: \"string\", required: true, label: \"Title\" },\n { name: \"slug\", type: \"string\", required: true, label: \"Slug\" },\n { name: \"excerpt\", type: \"string\", label: \"Excerpt\" },\n { name: \"content\", type: \"richtext\", required: true, label: \"Content\" },\n { name: \"featuredImage\", type: \"image\", label: \"Featured Image\" },\n { name: \"category\", type: \"string\", label: \"Category\" },\n { name: \"tags\", type: \"array\", label: \"Tags\" },\n { name: \"authorVariant\", type: \"string\", label: \"Author Variant\" },\n { name: \"readingTime\", type: \"number\", label: \"Reading Time\" },\n { name: \"metaTitle\", type: \"string\", label: \"Meta Title (SEO)\" },\n { name: \"metaDescription\", type: \"string\", label: \"Meta Description (SEO)\" },\n { name: \"ogImage\", type: \"image\", label: \"Open Graph Image\" },\n ],\n },\n ],\n\n contentProviders: [\"blog-posts\", \"blog-categories\"],\n },\n\n restrictions: {\n lockedFields: {\n blogPostDetail: [\"content\", \"date\"],\n },\n requiredPages: [\"blog-listing\", \"blog-post\"],\n },\n },\n\n onActivate(document: SiteDocument): SiteDocument {\n logger.debug(\"Blog plugin activating...\");\n\n const existingPageIds = new Set(document.pages.map((p) => p.id));\n const newPages = [...document.pages];\n\n // ── Encontrar home page para clonar navbar/footer ──\n const homePage =\n document.pages.find((p) => p.slug === \"home\") || document.pages[0];\n\n const homeNavbar = homePage?.structure.find((b) => b.type === \"navbar\");\n const homeFooter = homePage?.structure.find((b) => b.type === \"footer\");\n\n // ── 1. Adicionar link \"Blog\" à navbar da home page ──\n // Preserva os links existentes e apenas insere \"Blog\" antes do último item.\n if (homePage && homeNavbar) {\n const homeIdx = newPages.findIndex((p) => p.id === homePage.id);\n if (homeIdx >= 0) {\n const navbarProps = homeNavbar.props as Record<string, any>;\n const existingLinks: Array<{ text: string; href: string }> =\n Array.isArray(navbarProps.links) ? [...navbarProps.links] : [];\n const hasBlogLink = existingLinks.some(\n (l) => l.href === \"/p/blog\",\n );\n\n if (!hasBlogLink) {\n // Inserir \"Blog\" antes do último link (geralmente \"Contato\")\n const insertIdx = existingLinks.length > 0 ? existingLinks.length - 1 : 0;\n existingLinks.splice(insertIdx, 0, { text: \"Blog\", href: \"/p/blog\" });\n\n // Atualizar navbar na home page com o novo link\n const updatedStructure = newPages[homeIdx].structure.map((b) => {\n if (b.id === homeNavbar.id) {\n return { ...b, props: { ...b.props, links: existingLinks } } as Block;\n }\n return b;\n });\n newPages[homeIdx] = { ...newPages[homeIdx], structure: updatedStructure };\n logger.debug(\"Blog link added to home navbar\");\n\n // Atualizar referência para que clones nas páginas do blog usem navbar com link\n // (homeNavbar é const, então criamos a versão atualizada para uso nos clones)\n (homeNavbar as any).props = { ...navbarProps, links: existingLinks };\n }\n }\n }\n\n // ── 2. Injetar seção de blog na home page (antes do footer) ──\n if (homePage) {\n const homeIdx = newPages.findIndex((p) => p.id === homePage.id);\n const alreadyInjected = homePage.structure.some(\n (b) => b.id === BLOG_HOME_SECTION_ID,\n );\n\n if (homeIdx >= 0 && !alreadyInjected) {\n const blogHomeSection: Block = {\n id: BLOG_HOME_SECTION_ID,\n type: \"blogPostGrid\",\n props: {\n title: \"Blog\",\n subtitle: \"Últimas publicações\",\n columns: 3,\n cards: SAMPLE_BLOG_CARDS,\n variant: \"default\",\n showViewAll: true,\n viewAllText: \"Ver todos os posts\",\n viewAllHref: \"/site/p/blog\",\n },\n } as Block;\n\n const updatedStructure = [...newPages[homeIdx].structure];\n const footerIdx = updatedStructure.findIndex(\n (b) => b.type === \"footer\",\n );\n\n if (footerIdx >= 0) {\n updatedStructure.splice(footerIdx, 0, blogHomeSection);\n } else {\n updatedStructure.push(blogHomeSection);\n }\n\n newPages[homeIdx] = {\n ...newPages[homeIdx],\n structure: updatedStructure,\n };\n logger.debug(\"Blog section injected into home page\");\n }\n }\n\n // ── 3. Criar página \"Blog\" (listagem completa) ──\n if (!existingPageIds.has(\"blog\")) {\n const blogPageStructure: Block[] = [];\n\n // Navbar clonada da home\n if (homeNavbar) {\n blogPageStructure.push(cloneBlock(homeNavbar, \"blog-page-navbar\"));\n }\n\n // Hero banner do blog\n blogPageStructure.push({\n id: \"blog-page-hero\",\n type: \"hero\",\n props: {\n title: \"Blog\",\n subtitle: \"Novidades & Publicações\",\n description:\n \"Acompanhe as últimas novidades, eventos e conquistas da nossa comunidade escolar.\",\n variant: \"centered\",\n align: \"center\",\n overlay: true,\n overlayColor: \"rgba(79, 70, 229, 0.9)\",\n background: \"#4f46e5\",\n minHeight: \"280px\",\n },\n } as Block);\n\n // Search bar\n blogPageStructure.push({\n id: \"blog-search-bar\",\n type: \"blogSearchBar\",\n props: {\n placeholder: \"Buscar posts...\",\n variant: \"simple\",\n showIcon: true,\n searchUrl: \"/site/p/blog\",\n },\n } as Block);\n\n // Category filter\n blogPageStructure.push({\n id: \"blog-category-filter\",\n type: \"blogCategoryFilter\",\n props: {\n title: \"\",\n categories: SAMPLE_BLOG_CARDS.map((c) => ({\n name: c.category,\n slug: c.category.toLowerCase().replace(/\\s+/g, \"-\"),\n count: 1,\n })),\n variant: \"chips\",\n showCount: false,\n showAll: true,\n allLabel: \"Todas\",\n filterUrl: \"/site/p/blog\",\n },\n } as Block);\n\n // Grid de posts\n blogPageStructure.push({\n id: \"blog-grid-main\",\n type: \"blogPostGrid\",\n props: {\n title: \"\",\n subtitle: \"\",\n columns: 3,\n cards: SAMPLE_BLOG_CARDS,\n variant: \"default\",\n showViewAll: false,\n viewAllText: \"Ver todos\",\n viewAllHref: \"/site/p/blog\",\n },\n } as Block);\n\n // Footer clonado da home\n if (homeFooter) {\n blogPageStructure.push(cloneBlock(homeFooter, \"blog-page-footer\"));\n }\n\n newPages.push({\n id: \"blog\",\n name: \"Blog\",\n slug: \"blog\",\n pluginId: \"blog\",\n pageTemplateId: \"blog-listing\",\n structure: blogPageStructure,\n dataSource: {\n provider: \"blog-posts\",\n mode: \"list\",\n defaultParams: { limit: 15 },\n },\n });\n logger.debug(\"Blog listing page created\");\n }\n\n // ── 4. Criar página \"Post\" (detalhe com sidebar) ──\n if (!existingPageIds.has(\"blog-post\")) {\n const postPageStructure: Block[] = [];\n\n if (homeNavbar) {\n const navClone = cloneBlock(homeNavbar, \"post-page-navbar\");\n // Garantir navbar fixa no topo (position:fixed) mesmo se home não tem\n (navClone.props as Record<string, any>).sticky = true;\n postPageStructure.push(navClone);\n }\n\n // Grid layout: conteúdo principal + sidebar (com container e espaçamento)\n // paddingTop compensa a navbar fixa (position:fixed sai do fluxo)\n // cols: 2 para que \"Iguais\" funcione corretamente (2 filhos = 2 colunas)\n postPageStructure.push({\n id: \"blog-detail-layout\",\n type: \"grid\",\n props: {\n cols: 2,\n colTemplate: \"1fr 320px\",\n gap: \"2.5rem\",\n maxWidth: \"1200px\",\n padding: \"2rem\",\n paddingTop: \"6rem\",\n paddingBottom: \"6rem\",\n bg: \"var(--sg-bg)\",\n children: [\n // Coluna principal: blogPostDetail\n {\n id: \"blog-detail-main\",\n type: \"blogPostDetail\",\n props: {\n title: \"Feira de Ciências 2026: Inovação e Criatividade\",\n content: SAMPLE_POST_CONTENT,\n featuredImage:\n \"https://images.unsplash.com/photo-1567168544230-3b9e5ec47659?w=1200&h=600&fit=crop\",\n date: \"05 Fev 2026\",\n category: \"Eventos\",\n authorVariant: \"inline\",\n readingTime: \"5 min de leitura\",\n tags: [\"Feira de Ciências\", \"Eventos\", \"Sustentabilidade\", \"Projetos\"],\n showFeaturedImage: true,\n showAuthor: true,\n showDate: true,\n showTags: true,\n showReadingTime: true,\n contentMaxWidth: \"720px\",\n },\n },\n // Sidebar: stack vertical com widgets (sticky por padrão)\n {\n id: \"blog-detail-sidebar\",\n type: \"stack\",\n props: {\n direction: \"col\",\n gap: \"1.5rem\",\n sticky: true,\n stickyOffset: \"100px\",\n paddingBottom: \"6rem\",\n children: [\n {\n id: \"blog-sidebar-search\",\n type: \"blogSearchBar\",\n props: {\n placeholder: \"Buscar posts...\",\n variant: \"simple\",\n showIcon: true,\n searchUrl: \"/site/p/blog\",\n borderRadius: \"0.75rem\",\n shadow: \"sm\",\n },\n },\n {\n id: \"blog-sidebar-categories\",\n type: \"blogCategoryFilter\",\n props: {\n title: \"Categorias\",\n categories: SAMPLE_BLOG_CARDS.map((c) => ({\n name: c.category,\n slug: c.category.toLowerCase().replace(/\\s+/g, \"-\"),\n count: 1,\n })),\n variant: \"list\",\n showCount: true,\n showAll: true,\n allLabel: \"Todas\",\n filterUrl: \"/site/p/blog\",\n linkColor: \"#374151\",\n linkHoverColor: \"#2563eb\",\n borderRadius: \"0.75rem\",\n shadow: \"sm\",\n },\n },\n {\n id: \"blog-sidebar-recent\",\n type: \"blogRecentPosts\",\n props: {\n title: \"Posts Recentes\",\n count: 5,\n showThumbnail: true,\n showDate: true,\n showCategory: false,\n posts: SAMPLE_BLOG_CARDS.map((c) => ({\n title: c.title,\n slug: c.linkHref.replace(\"/site/p/blog/\", \"\"),\n date: c.date,\n image: c.image,\n category: c.category,\n })),\n linkColor: \"#374151\",\n linkHoverColor: \"#2563eb\",\n borderRadius: \"0.75rem\",\n shadow: \"sm\",\n },\n },\n {\n id: \"blog-sidebar-tags\",\n type: \"blogTagCloud\",\n props: {\n title: \"Tags\",\n tags: [\n { name: \"Eventos\", count: 3 },\n { name: \"Educação\", count: 2 },\n { name: \"Institucional\", count: 1 },\n { name: \"Sustentabilidade\", count: 1 },\n ],\n variant: \"badges\",\n linkColor: \"#374151\",\n linkHoverColor: \"#2563eb\",\n borderRadius: \"0.75rem\",\n shadow: \"sm\",\n },\n },\n ],\n },\n },\n ] as Block[],\n },\n } as Block);\n\n if (homeFooter) {\n postPageStructure.push(cloneBlock(homeFooter, \"post-page-footer\"));\n }\n\n newPages.push({\n id: \"blog-post\",\n name: \"Post\",\n slug: \"blog/:slug\",\n pluginId: \"blog\",\n pageTemplateId: \"blog-post\",\n isDynamic: true,\n structure: postPageStructure,\n dataSource: {\n provider: \"blog-posts\",\n mode: \"single\",\n paramMapping: { slug: \":slug\" },\n },\n editRestrictions: {\n nonRemovable: true,\n },\n });\n logger.debug(\"Blog post detail page created with sidebar layout\");\n }\n\n return {\n ...document,\n pages: newPages,\n };\n },\n\n onDeactivate(document: SiteDocument): SiteDocument {\n logger.debug(\"Blog plugin deactivating...\");\n\n const newPages = document.pages\n // Remover páginas do plugin\n .filter((page) => page.pluginId !== \"blog\")\n // Remover seção de blog injetada + link \"Blog\" da navbar\n .map((page) => {\n let structure = page.structure;\n\n // Remover seção de blog injetada\n const hasInjected = structure.some(\n (b) => b.id === BLOG_HOME_SECTION_ID,\n );\n if (hasInjected) {\n structure = structure.filter(\n (b) => b.id !== BLOG_HOME_SECTION_ID,\n );\n }\n\n // Remover link \"Blog\" (/p/blog) da navbar\n structure = structure.map((b) => {\n if (b.type !== \"navbar\") return b;\n const props = b.props as Record<string, any>;\n const links: Array<{ text: string; href: string }> = Array.isArray(props.links) ? props.links : [];\n const filtered = links.filter((l) => l.href !== \"/p/blog\");\n if (filtered.length !== links.length) {\n return { ...b, props: { ...props, links: filtered } } as Block;\n }\n return b;\n });\n\n if (structure !== page.structure) {\n return { ...page, structure };\n }\n return page;\n });\n\n logger.debug(\n `Removed ${document.pages.length - newPages.length} blog page(s) and injected section`,\n );\n\n return {\n ...document,\n pages: newPages,\n };\n },\n\n getEditorRestrictions(blockType: BlockType) {\n if (blockType === \"blogPostDetail\") {\n return {\n lockedFields: [\"content\", \"date\"],\n };\n }\n if (blockType === \"blogCategoryFilter\") {\n return {\n lockedFields: [\"categories\"],\n };\n }\n if (blockType === \"blogRecentPosts\") {\n return {\n lockedFields: [\"posts\"],\n };\n }\n if (blockType === \"blogTagCloud\") {\n return {\n lockedFields: [\"tags\"],\n };\n }\n return undefined;\n },\n};\n\n// Auto-registrar o plugin (side effect — como os blocos fazem com componentRegistry)\npluginRegistry.register(blogPlugin);\n"],"names":["BLOG_HOME_SECTION_ID","SAMPLE_BLOG_CARDS","SAMPLE_POST_CONTENT","cloneBlock","block","newId","blogPlugin","document","logger","existingPageIds","p","newPages","homePage","homeNavbar","b","homeFooter","homeIdx","navbarProps","existingLinks","l","insertIdx","updatedStructure","alreadyInjected","blogHomeSection","footerIdx","blogPageStructure","c","postPageStructure","navClone","page","structure","props","links","filtered","blockType","pluginRegistry"],"mappings":"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"}
1
+ {"version":3,"file":"manifest.js","sources":["../../../../../src/engine/plugins/builtin/blog/manifest.ts"],"sourcesContent":["/**\n * Blog Plugin Manifest\n * Plugin para blog com posts, categorias e tags.\n *\n * onActivate:\n * 1. Injeta seção blogPostGrid na home page (antes do footer)\n * 2. Cria página \"Blog\" com navbar + grid de posts + footer\n * 3. Cria página \"Post\" com navbar + detalhe do post + footer\n *\n * onDeactivate:\n * 1. Remove a seção injetada na home page\n * 2. Remove as páginas do plugin\n */\n\nimport type { PluginRegistration } from \"../../types\";\nimport type { SiteDocument, Block, BlockType } from \"../../../schema/siteDocument\";\nimport { pluginRegistry } from \"../../pluginRegistry\";\nimport { logger } from \"../../../../utils/logger\";\n\n// ─── ID usado para a seção de blog injetada na home page ───\nconst BLOG_HOME_SECTION_ID = \"plugin-blog-home-grid\";\n\n// ─── Sample blog cards para preview ───\nconst SAMPLE_BLOG_CARDS = [\n {\n title: \"Feira de Ciências 2026: Inovação e Criatividade\",\n excerpt:\n \"Nossos alunos apresentaram projetos incríveis na Feira de Ciências deste ano. Confira os destaques e premiações!\",\n image:\n \"https://images.unsplash.com/photo-1532094349884-543bc11b234d?w=800&h=400&fit=crop\",\n category: \"Eventos\",\n date: \"05 Fev 2026\",\n linkHref: \"/site/p/blog/feira-de-ciencias-2026\",\n linkText: \"Ler mais\",\n },\n {\n title: \"Matrículas Abertas para o Segundo Semestre\",\n excerpt:\n \"Garanta a vaga do seu filho na melhor escola da região. Condições especiais para matrículas antecipadas.\",\n image:\n \"https://images.unsplash.com/photo-1427504494785-3a9ca7044f45?w=800&h=400&fit=crop\",\n category: \"Institucional\",\n date: \"01 Fev 2026\",\n linkHref: \"/site/p/blog/matriculas-segundo-semestre\",\n linkText: \"Ler mais\",\n },\n {\n title: \"5 Dicas para Preparar seu Filho para o Ano Letivo\",\n excerpt:\n \"Dicas práticas para uma transição tranquila e um início de ano produtivo para toda a família.\",\n image:\n \"https://images.unsplash.com/photo-1503676260728-1c00da094a0b?w=800&h=400&fit=crop\",\n category: \"Educação\",\n date: \"28 Jan 2026\",\n linkHref: \"/site/p/blog/dicas-preparar-ano-letivo\",\n linkText: \"Ler mais\",\n },\n {\n title: \"Projeto de Robótica Conquista Prêmio Regional\",\n excerpt:\n \"Nossa equipe de robótica conquistou o primeiro lugar na competição regional. Saiba como foi essa jornada!\",\n image:\n \"https://images.unsplash.com/photo-1485827404703-89b55fcc595e?w=800&h=400&fit=crop\",\n category: \"Conquistas\",\n date: \"22 Jan 2026\",\n linkHref: \"/site/p/blog/robotica-premio-regional\",\n linkText: \"Ler mais\",\n },\n {\n title: \"Como a Tecnologia Transforma a Educação\",\n excerpt:\n \"Descubra como ferramentas digitais e metodologias ativas estão revolucionando o aprendizado em sala de aula.\",\n image:\n \"https://images.unsplash.com/photo-1509062522246-3755977927d7?w=800&h=400&fit=crop\",\n category: \"Educação\",\n date: \"18 Jan 2026\",\n linkHref: \"/site/p/blog/tecnologia-educacao\",\n linkText: \"Ler mais\",\n },\n {\n title: \"Calendário Escolar 2026: Datas Importantes\",\n excerpt:\n \"Confira todas as datas importantes do ano letivo 2026, incluindo feriados, provas e eventos especiais.\",\n image:\n \"https://images.unsplash.com/photo-1506784983877-45594efa4cbe?w=800&h=400&fit=crop\",\n category: \"Institucional\",\n date: \"10 Jan 2026\",\n linkHref: \"/site/p/blog/calendario-escolar-2026\",\n linkText: \"Ler mais\",\n },\n {\n title: \"Atividades Extracurriculares: Inscrições Abertas\",\n excerpt:\n \"Música, esportes, artes e idiomas. Conheça as atividades disponíveis e inscreva seu filho!\",\n image:\n \"https://images.unsplash.com/photo-1571260899304-425eee4c7efc?w=800&h=400&fit=crop\",\n category: \"Novidades\",\n date: \"05 Jan 2026\",\n linkHref: \"/site/p/blog/atividades-extracurriculares\",\n linkText: \"Ler mais\",\n },\n {\n title: \"Parceria com Universidades para Projetos de Pesquisa\",\n excerpt:\n \"Alunos do Ensino Médio agora podem participar de projetos de iniciação científica em parceria com universidades da região.\",\n image:\n \"https://images.unsplash.com/photo-1541339907198-e08756dedf3f?w=800&h=400&fit=crop\",\n category: \"Conquistas\",\n date: \"28 Dez 2025\",\n linkHref: \"/site/p/blog/parceria-universidades\",\n linkText: \"Ler mais\",\n },\n {\n title: \"Semana da Leitura: Escritores Visitam a Escola\",\n excerpt:\n \"Autores renomados da literatura infanto-juvenil participaram de bate-papos e oficinas com nossos alunos.\",\n image:\n \"https://images.unsplash.com/photo-1481627834876-b7833e8f5570?w=800&h=400&fit=crop\",\n category: \"Eventos\",\n date: \"20 Dez 2025\",\n linkHref: \"/site/p/blog/semana-leitura\",\n linkText: \"Ler mais\",\n },\n {\n title: \"Olimpíada de Matemática: Resultados Impressionantes\",\n excerpt:\n \"Nossos alunos conquistaram 5 medalhas de ouro e 8 de prata na Olimpíada Regional de Matemática 2025.\",\n image:\n \"https://images.unsplash.com/photo-1635070041078-e363dbe005cb?w=800&h=400&fit=crop\",\n category: \"Conquistas\",\n date: \"15 Dez 2025\",\n linkHref: \"/site/p/blog/olimpiada-matematica\",\n linkText: \"Ler mais\",\n },\n {\n title: \"Nova Biblioteca Digital para Alunos e Professores\",\n excerpt:\n \"A escola lança plataforma digital com mais de 10.000 livros, artigos e materiais didáticos acessíveis de qualquer dispositivo.\",\n image:\n \"https://images.unsplash.com/photo-1524995997946-a1c2e315a42f?w=800&h=400&fit=crop\",\n category: \"Novidades\",\n date: \"10 Dez 2025\",\n linkHref: \"/site/p/blog/biblioteca-digital\",\n linkText: \"Ler mais\",\n },\n {\n title: \"Formatura do Ensino Médio: Celebrando Conquistas\",\n excerpt:\n \"Uma noite emocionante de celebração para os formandos de 2025. Confira os melhores momentos da cerimônia.\",\n image:\n \"https://images.unsplash.com/photo-1523580846011-d3a5bc25702b?w=800&h=400&fit=crop\",\n category: \"Eventos\",\n date: \"05 Dez 2025\",\n linkHref: \"/site/p/blog/formatura-2025\",\n linkText: \"Ler mais\",\n },\n {\n title: \"Projeto Horta Escolar: Aprendendo com a Natureza\",\n excerpt:\n \"Alunos do Fundamental cultivam alimentos orgânicos e aprendem sobre sustentabilidade, nutrição e trabalho em equipe.\",\n image:\n \"https://images.unsplash.com/photo-1416879595882-3373a0480b5b?w=800&h=400&fit=crop\",\n category: \"Educação\",\n date: \"28 Nov 2025\",\n linkHref: \"/site/p/blog/horta-escolar\",\n linkText: \"Ler mais\",\n },\n];\n\n// ─── Conteúdo HTML rico para o post de exemplo ───\nconst SAMPLE_POST_CONTENT = `\n<h2>O que é a Feira de Ciências?</h2>\n<p>A Feira de Ciências é um evento anual que celebra a curiosidade, a pesquisa e a criatividade dos nossos alunos. Nesta edição especial de 2026, recebemos mais de <strong>500 visitantes</strong> e contamos com a participação de todas as turmas do Ensino Fundamental e Médio.</p>\n<p>Este ano, o tema central foi <em>\"Ciência e Sustentabilidade\"</em>, incentivando os estudantes a desenvolverem projetos que aliassem inovação tecnológica com responsabilidade ambiental.</p>\n\n<h2>Destaques da Edição 2026</h2>\n<p>Entre os mais de 50 projetos apresentados, alguns se destacaram pela originalidade e impacto:</p>\n<ul>\n <li><strong>Jardim Sustentável Inteligente</strong> — Alunos do 5º ano desenvolveram um sistema de irrigação automática usando sensores de umidade e placa Arduino.</li>\n <li><strong>Robótica Educacional</strong> — A turma do 8º ano criou um robô que auxilia no ensino de matemática para crianças do 1º ao 3º ano.</li>\n <li><strong>Energia Solar na Escola</strong> — Projeto do 2º ano do Ensino Médio demonstrou como painéis solares poderiam reduzir em 40% o consumo de energia da escola.</li>\n</ul>\n\n<blockquote>\n <p>\"A Feira de Ciências é um dos momentos mais importantes do nosso calendário escolar. Ver a dedicação e o brilho nos olhos dos alunos ao apresentarem seus projetos nos enche de orgulho e nos motiva a continuar investindo em educação de qualidade.\"</p>\n <p><strong>— Prof. Maria Silva, Coordenadora Pedagógica</strong></p>\n</blockquote>\n\n<h2>Premiações</h2>\n<p>O júri, composto por professores universitários e profissionais da área de tecnologia, selecionou os três melhores projetos:</p>\n<ol>\n <li><strong>1º Lugar:</strong> Jardim Sustentável Inteligente (5º ano)</li>\n <li><strong>2º Lugar:</strong> Energia Solar na Escola (2º EM)</li>\n <li><strong>3º Lugar:</strong> Robótica Educacional (8º ano)</li>\n</ol>\n\n<h2>Próximos Passos</h2>\n<p>Os três projetos finalistas representarão nossa escola na <strong>Feira Regional de Ciências</strong>, que acontecerá em março na capital. Os alunos já estão se preparando para levar suas apresentações a um público ainda maior.</p>\n<p>Parabéns a todos os participantes, professores orientadores e famílias que apoiaram essa jornada de descobertas!</p>\n`.trim();\n\n/**\n * Deep-clone um bloco com novo ID\n */\nfunction cloneBlock(block: Block, newId: string): Block {\n const cloned: Block = JSON.parse(JSON.stringify(block));\n return { ...cloned, id: newId };\n}\n\nexport const blogPlugin: PluginRegistration = {\n manifest: {\n id: \"blog\",\n version: \"1.0.0\",\n name: \"Blog\",\n description: \"Blog com posts, categorias e tags\",\n icon: \"FileText\",\n\n capabilities: {\n blocks: [\"blogPostCard\", \"blogPostGrid\", \"blogPostDetail\", \"blogCategoryFilter\", \"blogSearchBar\", \"blogRecentPosts\", \"blogTagCloud\"],\n\n pageTemplates: [\n {\n id: \"blog-listing\",\n name: \"Blog\",\n slug: \"blog\",\n pluginId: \"blog\",\n structure: [],\n dataSource: {\n provider: \"blog-posts\",\n mode: \"list\",\n },\n },\n {\n id: \"blog-post\",\n name: \"Post\",\n slug: \"blog/:slug\",\n pluginId: \"blog\",\n structure: [],\n dataSource: {\n provider: \"blog-posts\",\n mode: \"single\",\n paramMapping: { slug: \":slug\" },\n },\n editRestrictions: {\n nonRemovable: true,\n },\n },\n ],\n\n dataSchemas: [\n {\n type: \"blog-post\",\n label: \"Blog Post\",\n fields: [\n { name: \"title\", type: \"string\", required: true, label: \"Title\" },\n { name: \"slug\", type: \"string\", required: true, label: \"Slug\" },\n { name: \"excerpt\", type: \"string\", label: \"Excerpt\" },\n { name: \"content\", type: \"richtext\", required: true, label: \"Content\" },\n { name: \"featuredImage\", type: \"image\", label: \"Featured Image\" },\n { name: \"category\", type: \"string\", label: \"Category\" },\n { name: \"tags\", type: \"array\", label: \"Tags\" },\n { name: \"authorVariant\", type: \"string\", label: \"Author Variant\" },\n { name: \"readingTime\", type: \"number\", label: \"Reading Time\" },\n { name: \"metaTitle\", type: \"string\", label: \"Meta Title (SEO)\" },\n { name: \"metaDescription\", type: \"string\", label: \"Meta Description (SEO)\" },\n { name: \"ogImage\", type: \"image\", label: \"Open Graph Image\" },\n ],\n },\n ],\n\n contentProviders: [\"blog-posts\", \"blog-categories\"],\n },\n\n restrictions: {\n lockedFields: {\n blogPostDetail: [\"content\", \"date\"],\n },\n requiredPages: [\"blog-listing\", \"blog-post\"],\n },\n },\n\n onActivate(document: SiteDocument): SiteDocument {\n logger.debug(\"Blog plugin activating...\");\n\n const existingPageIds = new Set(document.pages.map((p) => p.id));\n const newPages = [...document.pages];\n\n // ── Encontrar home page para clonar navbar/footer ──\n const homePage =\n document.pages.find((p) => p.slug === \"home\") || document.pages[0];\n\n const homeNavbar = homePage?.structure.find((b) => b.type === \"navbar\");\n const homeFooter = homePage?.structure.find((b) => b.type === \"footer\");\n\n // ── 1. Adicionar link \"Blog\" à navbar da home page ──\n // Preserva os links existentes e apenas insere \"Blog\" antes do último item.\n if (homePage && homeNavbar) {\n const homeIdx = newPages.findIndex((p) => p.id === homePage.id);\n if (homeIdx >= 0) {\n const navbarProps = homeNavbar.props as Record<string, any>;\n let existingLinks: Array<{ text: string; href: string }> =\n Array.isArray(navbarProps.links) ? [...navbarProps.links] : [];\n\n // Limpar link antigo com href errado (/p/blog sem /site prefix)\n existingLinks = existingLinks.filter((l) => l.href !== \"/p/blog\");\n\n const hasBlogLink = existingLinks.some(\n (l) => l.href === \"/site/p/blog\",\n );\n\n if (!hasBlogLink) {\n // Inserir \"Blog\" antes do último link (geralmente \"Contato\")\n const insertIdx = existingLinks.length > 0 ? existingLinks.length - 1 : 0;\n existingLinks.splice(insertIdx, 0, { text: \"Blog\", href: \"/site/p/blog\" });\n\n // Atualizar navbar na home page com o novo link\n const updatedStructure = newPages[homeIdx].structure.map((b) => {\n if (b.id === homeNavbar.id) {\n return { ...b, props: { ...b.props, links: existingLinks } } as Block;\n }\n return b;\n });\n newPages[homeIdx] = { ...newPages[homeIdx], structure: updatedStructure };\n logger.debug(\"Blog link added to home navbar\");\n\n // Atualizar referência para que clones nas páginas do blog usem navbar com link\n // (homeNavbar é const, então criamos a versão atualizada para uso nos clones)\n (homeNavbar as any).props = { ...navbarProps, links: existingLinks };\n }\n }\n }\n\n // ── 2. Injetar seção de blog na home page (antes do footer) ──\n if (homePage) {\n const homeIdx = newPages.findIndex((p) => p.id === homePage.id);\n const alreadyInjected = homePage.structure.some(\n (b) => b.id === BLOG_HOME_SECTION_ID,\n );\n\n if (homeIdx >= 0 && !alreadyInjected) {\n const blogHomeSection: Block = {\n id: BLOG_HOME_SECTION_ID,\n type: \"blogPostGrid\",\n props: {\n title: \"Blog\",\n subtitle: \"Últimas publicações\",\n columns: 3,\n cards: SAMPLE_BLOG_CARDS.slice(0, 3),\n variant: \"default\",\n showViewAll: true,\n viewAllText: \"Ver todos os posts\",\n viewAllHref: \"/site/p/blog\",\n },\n } as Block;\n\n const updatedStructure = [...newPages[homeIdx].structure];\n const footerIdx = updatedStructure.findIndex(\n (b) => b.type === \"footer\",\n );\n\n if (footerIdx >= 0) {\n updatedStructure.splice(footerIdx, 0, blogHomeSection);\n } else {\n updatedStructure.push(blogHomeSection);\n }\n\n newPages[homeIdx] = {\n ...newPages[homeIdx],\n structure: updatedStructure,\n };\n logger.debug(\"Blog section injected into home page\");\n }\n }\n\n // ── 3. Criar página \"Blog\" (listagem — layout magazine com sidebar) ──\n if (!existingPageIds.has(\"blog\")) {\n const blogPageStructure: Block[] = [];\n\n // Navbar clonada da home\n if (homeNavbar) {\n blogPageStructure.push(cloneBlock(homeNavbar, \"blog-page-navbar\"));\n }\n\n // Extrair categorias únicas dos sample cards\n const uniqueCategories = [...new Set(SAMPLE_BLOG_CARDS.map((c) => c.category))];\n\n // Grid layout: conteúdo principal (magazine) + sidebar\n blogPageStructure.push({\n id: \"blog-listing-layout\",\n type: \"grid\",\n props: {\n cols: 2,\n colTemplate: \"1fr 320px\",\n gap: \"2.5rem\",\n maxWidth: \"1200px\",\n padding: \"2rem\",\n paddingTop: \"7rem\",\n paddingBottom: \"6rem\",\n bg: \"var(--sg-bg)\",\n children: [\n // Coluna principal: blogPostGrid com variant \"magazine\"\n {\n id: \"blog-grid-main\",\n type: \"blogPostGrid\",\n props: {\n title: \"\",\n subtitle: \"\",\n columns: 3,\n cards: SAMPLE_BLOG_CARDS,\n variant: \"magazine\",\n showViewAll: false,\n },\n },\n // Sidebar: stack vertical com widgets\n {\n id: \"blog-listing-sidebar\",\n type: \"stack\",\n props: {\n direction: \"col\",\n gap: \"1.5rem\",\n sticky: true,\n stickyOffset: \"100px\",\n children: [\n {\n id: \"blog-listing-search\",\n type: \"blogSearchBar\",\n props: {\n placeholder: \"Buscar posts...\",\n variant: \"simple\",\n showIcon: true,\n searchUrl: \"/site/p/blog\",\n borderRadius: \"0.75rem\",\n shadow: \"sm\",\n },\n },\n {\n id: \"blog-listing-categories\",\n type: \"blogCategoryFilter\",\n props: {\n title: \"Categorias\",\n categories: uniqueCategories.map((name) => ({\n name,\n slug: name.toLowerCase().replace(/\\s+/g, \"-\"),\n count: SAMPLE_BLOG_CARDS.filter((c) => c.category === name).length,\n })),\n variant: \"list\",\n showCount: true,\n showAll: true,\n allLabel: \"Todas\",\n filterUrl: \"/site/p/blog\",\n linkColor: \"#374151\",\n linkHoverColor: \"#2563eb\",\n borderRadius: \"0.75rem\",\n shadow: \"sm\",\n },\n },\n {\n id: \"blog-listing-recent\",\n type: \"blogRecentPosts\",\n props: {\n title: \"Posts Recentes\",\n count: 5,\n showThumbnail: true,\n showDate: true,\n showCategory: false,\n posts: SAMPLE_BLOG_CARDS.map((c) => ({\n title: c.title,\n slug: c.linkHref.replace(\"/site/p/blog/\", \"\"),\n date: c.date,\n image: c.image,\n category: c.category,\n })),\n linkColor: \"#374151\",\n linkHoverColor: \"#2563eb\",\n borderRadius: \"0.75rem\",\n shadow: \"sm\",\n },\n },\n {\n id: \"blog-listing-tags\",\n type: \"blogTagCloud\",\n props: {\n title: \"Tags\",\n tags: [\n { name: \"Eventos\", count: 3 },\n { name: \"Educação\", count: 4 },\n { name: \"Institucional\", count: 2 },\n { name: \"Tecnologia\", count: 2 },\n { name: \"Conquistas\", count: 1 },\n { name: \"Sustentabilidade\", count: 1 },\n ],\n variant: \"badges\",\n linkColor: \"#374151\",\n linkHoverColor: \"#2563eb\",\n borderRadius: \"0.75rem\",\n shadow: \"sm\",\n },\n },\n ],\n },\n },\n ] as Block[],\n },\n } as Block);\n\n // Footer clonado da home\n if (homeFooter) {\n blogPageStructure.push(cloneBlock(homeFooter, \"blog-page-footer\"));\n }\n\n newPages.push({\n id: \"blog\",\n name: \"Blog\",\n slug: \"blog\",\n pluginId: \"blog\",\n pageTemplateId: \"blog-listing\",\n structure: blogPageStructure,\n dataSource: {\n provider: \"blog-posts\",\n mode: \"list\",\n defaultParams: { limit: 15 },\n },\n });\n logger.debug(\"Blog listing page created with magazine layout\");\n }\n\n // ── 4. Criar página \"Post\" (detalhe com sidebar) ──\n if (!existingPageIds.has(\"blog-post\")) {\n const postPageStructure: Block[] = [];\n\n if (homeNavbar) {\n postPageStructure.push(cloneBlock(homeNavbar, \"post-page-navbar\"));\n }\n\n // Grid layout: conteúdo principal + sidebar (com container e espaçamento)\n // paddingTop compensa a navbar fixa (position:fixed sai do fluxo)\n // cols: 2 para que \"Iguais\" funcione corretamente (2 filhos = 2 colunas)\n postPageStructure.push({\n id: \"blog-detail-layout\",\n type: \"grid\",\n props: {\n cols: 2,\n colTemplate: \"1fr 320px\",\n gap: \"2.5rem\",\n maxWidth: \"1200px\",\n padding: \"2rem\",\n paddingTop: \"7rem\",\n paddingBottom: \"6rem\",\n bg: \"var(--sg-bg)\",\n children: [\n // Coluna principal: blogPostDetail\n {\n id: \"blog-detail-main\",\n type: \"blogPostDetail\",\n props: {\n title: \"Feira de Ciências 2026: Inovação e Criatividade\",\n content: SAMPLE_POST_CONTENT,\n featuredImage:\n \"https://images.unsplash.com/photo-1532094349884-543bc11b234d?w=1200&h=600&fit=crop\",\n date: \"05 Fev 2026\",\n category: \"Eventos\",\n authorVariant: \"inline\",\n readingTime: \"5 min de leitura\",\n tags: [\"Feira de Ciências\", \"Eventos\", \"Sustentabilidade\", \"Projetos\"],\n showFeaturedImage: true,\n showAuthor: true,\n showDate: true,\n showTags: true,\n showReadingTime: true,\n contentMaxWidth: \"720px\",\n },\n },\n // Sidebar: stack vertical com widgets (sticky por padrão)\n {\n id: \"blog-detail-sidebar\",\n type: \"stack\",\n props: {\n direction: \"col\",\n gap: \"1.5rem\",\n sticky: true,\n stickyOffset: \"100px\",\n children: [\n {\n id: \"blog-sidebar-search\",\n type: \"blogSearchBar\",\n props: {\n placeholder: \"Buscar posts...\",\n variant: \"simple\",\n showIcon: true,\n searchUrl: \"/site/p/blog\",\n borderRadius: \"0.75rem\",\n shadow: \"sm\",\n },\n },\n {\n id: \"blog-sidebar-categories\",\n type: \"blogCategoryFilter\",\n props: {\n title: \"Categorias\",\n categories: SAMPLE_BLOG_CARDS.map((c) => ({\n name: c.category,\n slug: c.category.toLowerCase().replace(/\\s+/g, \"-\"),\n count: 1,\n })),\n variant: \"list\",\n showCount: true,\n showAll: true,\n allLabel: \"Todas\",\n filterUrl: \"/site/p/blog\",\n linkColor: \"#374151\",\n linkHoverColor: \"#2563eb\",\n borderRadius: \"0.75rem\",\n shadow: \"sm\",\n },\n },\n {\n id: \"blog-sidebar-recent\",\n type: \"blogRecentPosts\",\n props: {\n title: \"Posts Recentes\",\n count: 5,\n showThumbnail: true,\n showDate: true,\n showCategory: false,\n posts: SAMPLE_BLOG_CARDS.map((c) => ({\n title: c.title,\n slug: c.linkHref.replace(\"/site/p/blog/\", \"\"),\n date: c.date,\n image: c.image,\n category: c.category,\n })),\n linkColor: \"#374151\",\n linkHoverColor: \"#2563eb\",\n borderRadius: \"0.75rem\",\n shadow: \"sm\",\n },\n },\n {\n id: \"blog-sidebar-tags\",\n type: \"blogTagCloud\",\n props: {\n title: \"Tags\",\n tags: [\n { name: \"Eventos\", count: 3 },\n { name: \"Educação\", count: 2 },\n { name: \"Institucional\", count: 1 },\n { name: \"Sustentabilidade\", count: 1 },\n ],\n variant: \"badges\",\n linkColor: \"#374151\",\n linkHoverColor: \"#2563eb\",\n borderRadius: \"0.75rem\",\n shadow: \"sm\",\n },\n },\n ],\n },\n },\n ] as Block[],\n },\n } as Block);\n\n if (homeFooter) {\n postPageStructure.push(cloneBlock(homeFooter, \"post-page-footer\"));\n }\n\n newPages.push({\n id: \"blog-post\",\n name: \"Post\",\n slug: \"blog/:slug\",\n pluginId: \"blog\",\n pageTemplateId: \"blog-post\",\n isDynamic: true,\n structure: postPageStructure,\n dataSource: {\n provider: \"blog-posts\",\n mode: \"single\",\n paramMapping: { slug: \":slug\" },\n },\n editRestrictions: {\n nonRemovable: true,\n },\n });\n logger.debug(\"Blog post detail page created with sidebar layout\");\n }\n\n return {\n ...document,\n pages: newPages,\n };\n },\n\n onDeactivate(document: SiteDocument): SiteDocument {\n logger.debug(\"Blog plugin deactivating...\");\n\n const newPages = document.pages\n // Remover páginas do plugin\n .filter((page) => page.pluginId !== \"blog\")\n // Remover seção de blog injetada + link \"Blog\" da navbar\n .map((page) => {\n let structure = page.structure;\n\n // Remover seção de blog injetada\n const hasInjected = structure.some(\n (b) => b.id === BLOG_HOME_SECTION_ID,\n );\n if (hasInjected) {\n structure = structure.filter(\n (b) => b.id !== BLOG_HOME_SECTION_ID,\n );\n }\n\n // Remover link \"Blog\" (/site/p/blog) da navbar\n structure = structure.map((b) => {\n if (b.type !== \"navbar\") return b;\n const props = b.props as Record<string, any>;\n const links: Array<{ text: string; href: string }> = Array.isArray(props.links) ? props.links : [];\n const filtered = links.filter((l) => l.href !== \"/site/p/blog\" && l.href !== \"/p/blog\");\n if (filtered.length !== links.length) {\n return { ...b, props: { ...props, links: filtered } } as Block;\n }\n return b;\n });\n\n if (structure !== page.structure) {\n return { ...page, structure };\n }\n return page;\n });\n\n logger.debug(\n `Removed ${document.pages.length - newPages.length} blog page(s) and injected section`,\n );\n\n return {\n ...document,\n pages: newPages,\n };\n },\n\n getEditorRestrictions(blockType: BlockType) {\n if (blockType === \"blogPostDetail\") {\n return {\n lockedFields: [\"content\", \"date\"],\n };\n }\n if (blockType === \"blogCategoryFilter\") {\n return {\n lockedFields: [\"categories\"],\n };\n }\n if (blockType === \"blogRecentPosts\") {\n return {\n lockedFields: [\"posts\"],\n };\n }\n if (blockType === \"blogTagCloud\") {\n return {\n lockedFields: [\"tags\"],\n };\n }\n return undefined;\n },\n};\n\n// Auto-registrar o plugin (side effect — como os blocos fazem com componentRegistry)\npluginRegistry.register(blogPlugin);\n"],"names":["BLOG_HOME_SECTION_ID","SAMPLE_BLOG_CARDS","SAMPLE_POST_CONTENT","cloneBlock","block","newId","blogPlugin","document","logger","existingPageIds","p","newPages","homePage","homeNavbar","b","homeFooter","homeIdx","navbarProps","existingLinks","l","insertIdx","updatedStructure","alreadyInjected","blogHomeSection","footerIdx","blogPageStructure","uniqueCategories","c","name","postPageStructure","page","structure","props","links","filtered","blockType","pluginRegistry"],"mappings":"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"}
@@ -1,55 +1,71 @@
1
- import { logger as f } from "../../utils/logger.js";
2
- async function R(t, n, r, e) {
1
+ import { logger as m } from "../../utils/logger.js";
2
+ async function T(t, a, r, e) {
3
3
  if (!t.dataSource)
4
4
  return t;
5
- const { provider: a, mode: s, paramMapping: c } = t.dataSource, d = n.get(a);
5
+ const { provider: n, mode: i, paramMapping: u } = t.dataSource, d = a.get(n);
6
6
  if (!d)
7
- return f.warn(
8
- `ContentProvider "${a}" not found for page "${t.id}". Rendering with static props.`
7
+ return m.warn(
8
+ `ContentProvider "${n}" not found for page "${t.id}". Rendering with static props.`
9
9
  ), t;
10
10
  try {
11
- if (s === "list")
11
+ if (i === "list")
12
12
  return await C(t, d, e);
13
- if (s === "single") {
14
- const p = $(c, r);
15
- return p ? await I(t, d, p) : (f.warn(
13
+ if (i === "single") {
14
+ const p = D(u, r);
15
+ return p ? await I(t, d, p) : (m.warn(
16
16
  `Could not resolve ID/slug for page "${t.id}" from URL params. Using static props.`
17
17
  ), t);
18
18
  }
19
19
  return t;
20
20
  } catch (p) {
21
- return f.error(`Error hydrating page "${t.id}":`, p), t;
21
+ return m.error(`Error hydrating page "${t.id}":`, p), t;
22
22
  }
23
23
  }
24
- function v(t, n) {
25
- const e = `/site/p/${t.slug && t.slug !== "home" ? t.slug : "blog"}`, a = new URLSearchParams(), s = n?.filter;
26
- return s?.search && a.set("busca", s.search), s?.category && a.set("categoria", s.category), a.toString() ? `${e}?${a.toString()}` : e;
24
+ function B(t, a) {
25
+ const e = `/site/p/${t.slug && t.slug !== "home" ? t.slug : "blog"}`, n = new URLSearchParams(), i = a?.filter;
26
+ return i?.search && n.set("busca", i.search), i?.category && n.set("categoria", i.category), n.toString() ? `${e}?${n.toString()}` : e;
27
27
  }
28
- async function C(t, n, r) {
28
+ async function C(t, a, r) {
29
29
  const e = {
30
30
  limit: 12,
31
31
  ...t.dataSource?.defaultParams,
32
32
  ...r
33
- }, a = await n.fetchList(e), s = (a.items || []).map((i) => n.toBlockProps(i)), c = !!t.dataSource?.defaultParams?._noPagination, d = Math.ceil((a.total || 0) / (a.limit || e.limit || 12)), p = !c && d > 1 ? {
34
- currentPage: a.page || 1,
33
+ }, n = await a.fetchList(e), i = (n.items || []).map((o) => a.toBlockProps(o)), u = !!t.dataSource?.defaultParams?._noPagination, d = Math.ceil((n.total || 0) / (n.limit || e.limit || 12)), p = !u && d > 1 ? {
34
+ currentPage: n.page || 1,
35
35
  totalPages: d,
36
- paginationBaseUrl: v(t, r)
37
- } : void 0, m = t.structure.map((i) => {
38
- let l = P(i, s, p);
39
- return l = h(l, s), l;
36
+ paginationBaseUrl: B(t, r)
37
+ } : void 0, h = (n.items || []).slice(0, 5).map((o) => {
38
+ const s = o.data;
39
+ return {
40
+ title: s.title ?? "",
41
+ slug: o.slug,
42
+ date: o.metadata?.publishedAt ? new Date(o.metadata.publishedAt).toLocaleDateString("pt-BR", { day: "2-digit", month: "short", year: "numeric" }) : void 0,
43
+ image: s.featuredImage ?? void 0,
44
+ category: s.category ?? void 0
45
+ };
46
+ }), c = /* @__PURE__ */ new Map();
47
+ for (const o of n.items || []) {
48
+ const s = o.data.tags;
49
+ if (s)
50
+ for (const g of s)
51
+ c.set(g, (c.get(g) ?? 0) + 1);
52
+ }
53
+ const l = Array.from(c.entries()).map(([o, s]) => ({ name: o, count: s })).sort((o, s) => s.count - o.count), f = t.structure.map((o) => {
54
+ let s = w(o, i, p);
55
+ return s = A(s, i), s = y(s, h), s = P(s, l), s;
40
56
  });
41
57
  return {
42
58
  ...t,
43
- structure: m
59
+ structure: f
44
60
  };
45
61
  }
46
- function P(t, n, r) {
62
+ function w(t, a, r) {
47
63
  if (t.type === "blogPostGrid")
48
64
  return {
49
65
  ...t,
50
66
  props: {
51
67
  ...t.props,
52
- cards: n,
68
+ cards: a,
53
69
  ...r ? {
54
70
  currentPage: r.currentPage,
55
71
  totalPages: r.totalPages,
@@ -63,54 +79,54 @@ function P(t, n, r) {
63
79
  props: {
64
80
  ...e,
65
81
  children: e.children.map(
66
- (a) => P(a, n, r)
82
+ (n) => w(n, a, r)
67
83
  )
68
84
  }
69
85
  } : t;
70
86
  }
71
- async function I(t, n, r) {
72
- const e = await n.fetchById(r);
87
+ async function I(t, a, r) {
88
+ const e = await a.fetchById(r);
73
89
  if (!e)
74
- return f.warn(`Content item "${r}" not found. Using static props.`), t;
75
- const a = n.toBlockProps(e);
76
- let s = [], c = [], d = [];
90
+ return m.warn(`Content item "${r}" not found. Using static props.`), t;
91
+ const n = a.toBlockProps(e);
92
+ let i = [], u = [], d = [];
77
93
  try {
78
- const l = (await n.fetchList({ limit: 10, sort: "published_at" })).items || [];
79
- d = l.map((o) => n.toBlockProps(o)), s = l.filter((o) => o.slug !== r && o.slug).slice(0, 5).map((o) => {
80
- const u = o.data;
94
+ const l = (await a.fetchList({ limit: 10, sort: "published_at" })).items || [];
95
+ d = l.map((o) => a.toBlockProps(o)), i = l.filter((o) => o.slug !== r && o.slug).slice(0, 5).map((o) => {
96
+ const s = o.data;
81
97
  return {
82
- title: u.title ?? "",
98
+ title: s.title ?? "",
83
99
  slug: o.slug,
84
100
  date: o.metadata?.publishedAt ? new Date(o.metadata.publishedAt).toLocaleDateString("pt-BR", { day: "2-digit", month: "short", year: "numeric" }) : void 0,
85
- image: u.featuredImage ?? void 0,
86
- category: u.category ?? void 0
101
+ image: s.featuredImage ?? void 0,
102
+ category: s.category ?? void 0
87
103
  };
88
104
  });
89
- const g = /* @__PURE__ */ new Map();
105
+ const f = /* @__PURE__ */ new Map();
90
106
  for (const o of l) {
91
- const u = o.data.tags;
92
- if (u)
93
- for (const y of u)
94
- g.set(y, (g.get(y) ?? 0) + 1);
107
+ const s = o.data.tags;
108
+ if (s)
109
+ for (const g of s)
110
+ f.set(g, (f.get(g) ?? 0) + 1);
95
111
  }
96
- c = Array.from(g.entries()).map(([o, u]) => ({ name: o, count: u })).sort((o, u) => u.count - o.count);
97
- } catch (i) {
98
- f.warn(`Failed to fetch sidebar data for page "${t.id}":`, i);
112
+ u = Array.from(f.entries()).map(([o, s]) => ({ name: o, count: s })).sort((o, s) => s.count - o.count);
113
+ } catch (c) {
114
+ m.warn(`Failed to fetch sidebar data for page "${t.id}":`, c);
99
115
  }
100
- const p = t.structure.map((i) => w(i, a, e)).map((i) => A(i, s)).map((i) => B(i, c)).map((i) => h(i, d)), m = S(e, a);
116
+ const p = t.structure.map((c) => v(c, n, e)).map((c) => y(c, i)).map((c) => P(c, u)).map((c) => A(c, d)), h = S(e, n);
101
117
  return {
102
118
  ...t,
103
119
  structure: p,
104
- ...m ? { seo: m } : {}
120
+ ...h ? { seo: h } : {}
105
121
  };
106
122
  }
107
- function w(t, n, r) {
123
+ function v(t, a, r) {
108
124
  if (t.type === "blogPostDetail")
109
125
  return {
110
126
  ...t,
111
127
  props: {
112
128
  ...t.props,
113
- ...n,
129
+ ...a,
114
130
  // Preserve metadata
115
131
  _contentItemId: r.id,
116
132
  _contentItemSlug: r.slug
@@ -121,7 +137,7 @@ function w(t, n, r) {
121
137
  ...t,
122
138
  props: {
123
139
  ...t.props,
124
- ...n
140
+ ...a
125
141
  }
126
142
  };
127
143
  const e = t.props;
@@ -130,28 +146,28 @@ function w(t, n, r) {
130
146
  props: {
131
147
  ...e,
132
148
  children: e.children.map(
133
- (a) => w(a, n, r)
149
+ (n) => v(n, a, r)
134
150
  )
135
151
  }
136
152
  } : t;
137
153
  }
138
- function S(t, n) {
139
- const r = t.metadata?.seo, e = r?.metaTitle || n.metaTitle || n.title, a = r?.metaDescription || n.metaDescription || n.excerpt, s = r?.ogImage || n.ogImage || n.featuredImage;
140
- if (!(!e && !a && !s))
154
+ function S(t, a) {
155
+ const r = t.metadata?.seo, e = r?.metaTitle || a.metaTitle || a.title, n = r?.metaDescription || a.metaDescription || a.excerpt, i = r?.ogImage || a.ogImage || a.featuredImage;
156
+ if (!(!e && !n && !i))
141
157
  return {
142
158
  metaTitle: e,
143
- metaDescription: a,
144
- ogImage: s,
159
+ metaDescription: n,
160
+ ogImage: i,
145
161
  ogType: "article"
146
162
  };
147
163
  }
148
- function A(t, n) {
164
+ function y(t, a) {
149
165
  if (t.type === "blogRecentPosts")
150
166
  return {
151
167
  ...t,
152
168
  props: {
153
169
  ...t.props,
154
- posts: n
170
+ posts: a
155
171
  }
156
172
  };
157
173
  const r = t.props;
@@ -160,18 +176,18 @@ function A(t, n) {
160
176
  props: {
161
177
  ...r,
162
178
  children: r.children.map(
163
- (e) => A(e, n)
179
+ (e) => y(e, a)
164
180
  )
165
181
  }
166
182
  } : t;
167
183
  }
168
- function B(t, n) {
184
+ function P(t, a) {
169
185
  if (t.type === "blogTagCloud")
170
186
  return {
171
187
  ...t,
172
188
  props: {
173
189
  ...t.props,
174
- tags: n
190
+ tags: a
175
191
  }
176
192
  };
177
193
  const r = t.props;
@@ -180,28 +196,28 @@ function B(t, n) {
180
196
  props: {
181
197
  ...r,
182
198
  children: r.children.map(
183
- (e) => B(e, n)
199
+ (e) => P(e, a)
184
200
  )
185
201
  }
186
202
  } : t;
187
203
  }
188
- function h(t, n) {
204
+ function A(t, a) {
189
205
  if (t.type === "blogCategoryFilter") {
190
206
  const e = /* @__PURE__ */ new Map();
191
- for (const s of n) {
192
- const c = s.category;
193
- c && e.set(c, (e.get(c) || 0) + 1);
207
+ for (const i of a) {
208
+ const u = i.category;
209
+ u && e.set(u, (e.get(u) || 0) + 1);
194
210
  }
195
- const a = Array.from(e.entries()).map(([s, c]) => ({
196
- name: s,
197
- slug: s,
198
- count: c
211
+ const n = Array.from(e.entries()).map(([i, u]) => ({
212
+ name: i,
213
+ slug: i,
214
+ count: u
199
215
  }));
200
216
  return {
201
217
  ...t,
202
218
  props: {
203
219
  ...t.props,
204
- categories: a
220
+ categories: n
205
221
  }
206
222
  };
207
223
  }
@@ -211,27 +227,27 @@ function h(t, n) {
211
227
  props: {
212
228
  ...r,
213
229
  children: r.children.map(
214
- (e) => h(e, n)
230
+ (e) => A(e, a)
215
231
  )
216
232
  }
217
233
  } : t;
218
234
  }
219
- function $(t, n) {
220
- if (!(!t || !n)) {
235
+ function D(t, a) {
236
+ if (!(!t || !a)) {
221
237
  for (const r of ["slug", "id"]) {
222
238
  const e = t[r];
223
239
  if (e) {
224
- const a = e.startsWith(":") ? e.slice(1) : e, s = n[a];
225
- if (s) return s;
240
+ const n = e.startsWith(":") ? e.slice(1) : e, i = a[n];
241
+ if (i) return i;
226
242
  }
227
243
  }
228
244
  for (const r of Object.values(t)) {
229
- const e = r.startsWith(":") ? r.slice(1) : r, a = n[e];
230
- if (a) return a;
245
+ const e = r.startsWith(":") ? r.slice(1) : r, n = a[e];
246
+ if (n) return n;
231
247
  }
232
248
  }
233
249
  }
234
250
  export {
235
- R as hydratePageWithContent
251
+ T as hydratePageWithContent
236
252
  };
237
253
  //# sourceMappingURL=contentHydration.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contentHydration.js","sources":["../../../src/engine/plugins/contentHydration.ts"],"sourcesContent":["/**\n * Content Hydration\n * Hydrates page blocks with data from ContentProviders before rendering.\n *\n * This works at the data level, before either rendering pipeline\n * (React renderers or HTML exporters) processes the blocks.\n */\n\nimport { logger } from \"../../utils/logger\";\nimport type { SitePage, Block, PageSeoConfig } from \"../schema/siteDocument\";\nimport type { ContentProvider, ContentItem, ContentListParams } from \"./types\";\n\n/**\n * Map of provider type → ContentProvider instance\n */\nexport type ContentProviderMap = Map<string, ContentProvider>;\n\n/**\n * Hydrates a page's blocks with data from ContentProviders.\n *\n * For pages with a dataSource:\n * - mode \"list\": fetches list and populates grid blocks' `cards` prop\n * - mode \"single\": fetches single item and spreads props onto detail blocks\n *\n * Returns a new page with hydrated block props (original page is not mutated).\n */\nexport async function hydratePageWithContent(\n page: SitePage,\n providers: ContentProviderMap,\n urlParams?: Record<string, string>,\n fetchParams?: ContentListParams,\n): Promise<SitePage> {\n // No dataSource → return page as-is\n if (!page.dataSource) {\n return page;\n }\n\n const { provider: providerType, mode, paramMapping } = page.dataSource;\n const provider = providers.get(providerType);\n\n if (!provider) {\n logger.warn(\n `ContentProvider \"${providerType}\" not found for page \"${page.id}\". Rendering with static props.`,\n );\n return page;\n }\n\n try {\n if (mode === \"list\") {\n return await hydrateListPage(page, provider, fetchParams);\n }\n\n if (mode === \"single\") {\n // Resolve the ID/slug from URL params\n const idOrSlug = resolveIdFromParams(paramMapping, urlParams);\n if (!idOrSlug) {\n logger.warn(\n `Could not resolve ID/slug for page \"${page.id}\" from URL params. Using static props.`,\n );\n return page;\n }\n return await hydrateSinglePage(page, provider, idOrSlug);\n }\n\n return page;\n } catch (error) {\n logger.error(`Error hydrating page \"${page.id}\":`, error);\n return page;\n }\n}\n\n/**\n * Pagination metadata passed from hydration to grid blocks.\n */\ninterface PaginationMeta {\n currentPage: number;\n totalPages: number;\n paginationBaseUrl: string;\n}\n\n/**\n * Builds a pagination base URL from the page slug and current filter params.\n * Preserves search/category so pagination links keep the active filters.\n * Uses /site/p/ prefix to match the consumer route pattern (same as viewAllHref, linkHref).\n */\nfunction buildPaginationBaseUrl(\n page: SitePage,\n fetchParams?: ContentListParams,\n): string {\n // Always paginate on the blog listing page — home page widget points to blog page\n const slug = page.slug && page.slug !== \"home\" ? page.slug : \"blog\";\n const basePath = `/site/p/${slug}`;\n\n const params = new URLSearchParams();\n const filter = fetchParams?.filter as Record<string, string> | undefined;\n if (filter?.search) params.set(\"busca\", filter.search);\n if (filter?.category) params.set(\"categoria\", filter.category);\n\n return params.toString() ? `${basePath}?${params.toString()}` : basePath;\n}\n\n/**\n * Hydrates a list-mode page: fetches items and populates grid blocks.\n */\nasync function hydrateListPage(\n page: SitePage,\n provider: ContentProvider,\n fetchParams?: ContentListParams,\n): Promise<SitePage> {\n const params: ContentListParams = {\n limit: 12,\n ...page.dataSource?.defaultParams,\n ...fetchParams,\n };\n\n const result = await provider.fetchList(params);\n\n // Convert items to block props (empty array if no results — shows empty state, never mock data)\n const cardProps = (result.items || []).map((item) => provider.toBlockProps(item));\n\n // Build pagination metadata (only when there are multiple pages)\n // _noPagination flag suppresses pagination for synthetic dataSource (e.g., home page blog widget)\n const noPagination = !!(page.dataSource?.defaultParams as Record<string, unknown> | undefined)?._noPagination;\n const totalPages = Math.ceil((result.total || 0) / (result.limit || params.limit || 12));\n const pagination: PaginationMeta | undefined = !noPagination && totalPages > 1\n ? {\n currentPage: result.page || 1,\n totalPages,\n paginationBaseUrl: buildPaginationBaseUrl(page, fetchParams),\n }\n : undefined;\n\n // Hydrate all grid blocks and category filters on the page\n const hydratedStructure = page.structure.map((block) => {\n let hydrated = hydrateGridBlock(block, cardProps, pagination);\n hydrated = hydrateCategoryFilterBlock(hydrated, cardProps);\n return hydrated;\n });\n\n return {\n ...page,\n structure: hydratedStructure,\n };\n}\n\n/**\n * Hydrates grid blocks (blogPostGrid, etc.) with card data and pagination.\n */\nfunction hydrateGridBlock(\n block: Block,\n cardProps: Record<string, unknown>[],\n pagination?: PaginationMeta,\n): Block {\n // Direct match: blogPostGrid gets cards + pagination populated\n if (block.type === \"blogPostGrid\") {\n return {\n ...block,\n props: {\n ...block.props,\n cards: cardProps,\n ...(pagination ? {\n currentPage: pagination.currentPage,\n totalPages: pagination.totalPages,\n paginationBaseUrl: pagination.paginationBaseUrl,\n } : {}),\n },\n };\n }\n\n // Recurse into children for nested structures\n const props = block.props as Record<string, unknown>;\n if (props.children && Array.isArray(props.children)) {\n return {\n ...block,\n props: {\n ...props,\n children: (props.children as Block[]).map((child) =>\n hydrateGridBlock(child, cardProps, pagination),\n ),\n },\n };\n }\n\n return block;\n}\n\n/**\n * Hydrates a single-mode page: fetches one item and populates detail blocks.\n * Also fetches sidebar data (recent posts, tags, categories) for widgets.\n */\nasync function hydrateSinglePage(\n page: SitePage,\n provider: ContentProvider,\n idOrSlug: string,\n): Promise<SitePage> {\n const item = await provider.fetchById(idOrSlug);\n\n if (!item) {\n logger.warn(`Content item \"${idOrSlug}\" not found. Using static props.`);\n return page;\n }\n\n const blockProps = provider.toBlockProps(item);\n\n // Fetch recent posts for sidebar widgets\n let recentPosts: Array<{ title: string; slug: string; date?: string; image?: string; category?: string }> = [];\n let tagCloud: Array<{ name: string; count: number }> = [];\n let sidebarCardProps: Record<string, unknown>[] = [];\n\n try {\n const recentResult = await provider.fetchList({ limit: 10, sort: 'published_at' });\n const allItems = recentResult.items || [];\n\n // Map to card props for category filter hydration\n sidebarCardProps = allItems.map((i) => provider.toBlockProps(i));\n\n // Map recent posts (exclude current post)\n recentPosts = allItems\n .filter((i) => i.slug !== idOrSlug && i.slug)\n .slice(0, 5)\n .map((i) => {\n const d = i.data as Record<string, any>;\n return {\n title: (d.title as string) ?? '',\n slug: i.slug as string,\n date: i.metadata?.publishedAt\n ? new Date(i.metadata.publishedAt).toLocaleDateString('pt-BR', { day: '2-digit', month: 'short', year: 'numeric' })\n : undefined,\n image: (d.featuredImage as string) ?? undefined,\n category: (d.category as string) ?? undefined,\n };\n });\n\n // Extract tags from all posts\n const allTags = new Map<string, number>();\n for (const i of allItems) {\n const tags = (i.data as Record<string, any>).tags as string[] | undefined;\n if (tags) {\n for (const tag of tags) {\n allTags.set(tag, (allTags.get(tag) ?? 0) + 1);\n }\n }\n }\n tagCloud = Array.from(allTags.entries())\n .map(([name, count]) => ({ name, count }))\n .sort((a, b) => b.count - a.count);\n } catch (err) {\n logger.warn(`Failed to fetch sidebar data for page \"${page.id}\":`, err);\n }\n\n // Hydrate all blocks on the page\n const hydratedStructure = page.structure\n .map((block) => hydrateDetailBlock(block, blockProps, item))\n .map((block) => hydrateRecentPostsBlock(block, recentPosts))\n .map((block) => hydrateTagCloudBlock(block, tagCloud))\n .map((block) => hydrateCategoryFilterBlock(block, sidebarCardProps));\n\n // Extract SEO from content item and set on page\n const seo = extractSeoFromContent(item, blockProps);\n\n return {\n ...page,\n structure: hydratedStructure,\n ...(seo ? { seo } : {}),\n };\n}\n\n/**\n * Hydrates detail blocks (blogPostDetail, etc.) with item data.\n */\nfunction hydrateDetailBlock(\n block: Block,\n blockProps: Record<string, unknown>,\n item: ContentItem,\n): Block {\n if (block.type === \"blogPostDetail\") {\n return {\n ...block,\n props: {\n ...block.props,\n ...blockProps,\n // Preserve metadata\n _contentItemId: item.id,\n _contentItemSlug: item.slug,\n },\n };\n }\n\n // Also hydrate blogPostCard blocks that reference the same item\n if (block.type === \"blogPostCard\") {\n return {\n ...block,\n props: {\n ...block.props,\n ...blockProps,\n },\n };\n }\n\n // Recurse into children\n const props = block.props as Record<string, unknown>;\n if (props.children && Array.isArray(props.children)) {\n return {\n ...block,\n props: {\n ...props,\n children: (props.children as Block[]).map((child) =>\n hydrateDetailBlock(child, blockProps, item),\n ),\n },\n };\n }\n\n return block;\n}\n\n/**\n * Extracts SEO configuration from a ContentItem and block props.\n * Priority: item.metadata.seo > blockProps (metaTitle/title, metaDescription/excerpt, ogImage/featuredImage)\n */\nfunction extractSeoFromContent(\n item: ContentItem,\n blockProps: Record<string, unknown>,\n): PageSeoConfig | undefined {\n const seoMeta = item.metadata?.seo;\n\n const metaTitle = seoMeta?.metaTitle || (blockProps.metaTitle as string) || (blockProps.title as string);\n const metaDescription = seoMeta?.metaDescription || (blockProps.metaDescription as string) || (blockProps.excerpt as string);\n const ogImage = seoMeta?.ogImage || (blockProps.ogImage as string) || (blockProps.featuredImage as string);\n\n if (!metaTitle && !metaDescription && !ogImage) {\n return undefined;\n }\n\n return {\n metaTitle,\n metaDescription,\n ogImage,\n ogType: \"article\",\n };\n}\n\n/**\n * Hydrates blogRecentPosts blocks with recent post data.\n */\nfunction hydrateRecentPostsBlock(\n block: Block,\n recentPosts: Array<{ title: string; slug: string; date?: string; image?: string; category?: string }>,\n): Block {\n if (block.type === \"blogRecentPosts\") {\n return {\n ...block,\n props: {\n ...block.props,\n posts: recentPosts,\n },\n } as Block;\n }\n\n // Recurse into children\n const props = block.props as Record<string, unknown>;\n if (props.children && Array.isArray(props.children)) {\n return {\n ...block,\n props: {\n ...props,\n children: (props.children as Block[]).map((child) =>\n hydrateRecentPostsBlock(child, recentPosts),\n ),\n },\n } as Block;\n }\n\n return block;\n}\n\n/**\n * Hydrates blogTagCloud blocks with tag data.\n */\nfunction hydrateTagCloudBlock(\n block: Block,\n tags: Array<{ name: string; count: number }>,\n): Block {\n if (block.type === \"blogTagCloud\") {\n return {\n ...block,\n props: {\n ...block.props,\n tags,\n },\n } as Block;\n }\n\n // Recurse into children\n const props = block.props as Record<string, unknown>;\n if (props.children && Array.isArray(props.children)) {\n return {\n ...block,\n props: {\n ...props,\n children: (props.children as Block[]).map((child) =>\n hydrateTagCloudBlock(child, tags),\n ),\n },\n } as Block;\n }\n\n return block;\n}\n\n/**\n * Hydrates blogCategoryFilter blocks with category data extracted from posts.\n */\nfunction hydrateCategoryFilterBlock(\n block: Block,\n cardProps: Record<string, unknown>[],\n): Block {\n if (block.type === \"blogCategoryFilter\") {\n // Extract unique categories from posts with counts\n const categoryMap = new Map<string, number>();\n for (const card of cardProps) {\n const cat = card.category as string;\n if (cat) {\n categoryMap.set(cat, (categoryMap.get(cat) || 0) + 1);\n }\n }\n\n const categories = Array.from(categoryMap.entries()).map(([name, count]) => ({\n name,\n slug: name,\n count,\n }));\n\n return {\n ...block,\n props: {\n ...block.props,\n categories,\n },\n };\n }\n\n // Recurse into children\n const props = block.props as Record<string, unknown>;\n if (props.children && Array.isArray(props.children)) {\n return {\n ...block,\n props: {\n ...props,\n children: (props.children as Block[]).map((child) =>\n hydrateCategoryFilterBlock(child, cardProps),\n ),\n },\n };\n }\n\n return block;\n}\n\n/**\n * Resolves the item ID/slug from URL params using paramMapping.\n * e.g., paramMapping: { slug: \":slug\" }, urlParams: { slug: \"my-post\" } → \"my-post\"\n */\nfunction resolveIdFromParams(\n paramMapping?: Record<string, string>,\n urlParams?: Record<string, string>,\n): string | undefined {\n if (!paramMapping || !urlParams) return undefined;\n\n // Try slug first, then id\n for (const key of [\"slug\", \"id\"]) {\n const paramPattern = paramMapping[key];\n if (paramPattern) {\n // Extract param name from pattern (e.g., \":slug\" → \"slug\")\n const paramName = paramPattern.startsWith(\":\")\n ? paramPattern.slice(1)\n : paramPattern;\n const value = urlParams[paramName];\n if (value) return value;\n }\n }\n\n // Fallback: return first available param value\n for (const paramPattern of Object.values(paramMapping)) {\n const paramName = paramPattern.startsWith(\":\")\n ? paramPattern.slice(1)\n : paramPattern;\n const value = urlParams[paramName];\n if (value) return value;\n }\n\n return undefined;\n}\n"],"names":["hydratePageWithContent","page","providers","urlParams","fetchParams","providerType","mode","paramMapping","provider","logger","hydrateListPage","idOrSlug","resolveIdFromParams","hydrateSinglePage","error","buildPaginationBaseUrl","basePath","params","filter","result","cardProps","item","noPagination","totalPages","pagination","hydratedStructure","block","hydrated","hydrateGridBlock","hydrateCategoryFilterBlock","props","child","blockProps","recentPosts","tagCloud","sidebarCardProps","allItems","i","d","allTags","tags","tag","name","count","a","b","err","hydrateDetailBlock","hydrateRecentPostsBlock","hydrateTagCloudBlock","seo","extractSeoFromContent","seoMeta","metaTitle","metaDescription","ogImage","categoryMap","card","cat","categories","key","paramPattern","paramName","value"],"mappings":"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"}
1
+ {"version":3,"file":"contentHydration.js","sources":["../../../src/engine/plugins/contentHydration.ts"],"sourcesContent":["/**\n * Content Hydration\n * Hydrates page blocks with data from ContentProviders before rendering.\n *\n * This works at the data level, before either rendering pipeline\n * (React renderers or HTML exporters) processes the blocks.\n */\n\nimport { logger } from \"../../utils/logger\";\nimport type { SitePage, Block, PageSeoConfig } from \"../schema/siteDocument\";\nimport type { ContentProvider, ContentItem, ContentListParams } from \"./types\";\n\n/**\n * Map of provider type → ContentProvider instance\n */\nexport type ContentProviderMap = Map<string, ContentProvider>;\n\n/**\n * Hydrates a page's blocks with data from ContentProviders.\n *\n * For pages with a dataSource:\n * - mode \"list\": fetches list and populates grid blocks' `cards` prop\n * - mode \"single\": fetches single item and spreads props onto detail blocks\n *\n * Returns a new page with hydrated block props (original page is not mutated).\n */\nexport async function hydratePageWithContent(\n page: SitePage,\n providers: ContentProviderMap,\n urlParams?: Record<string, string>,\n fetchParams?: ContentListParams,\n): Promise<SitePage> {\n // No dataSource → return page as-is\n if (!page.dataSource) {\n return page;\n }\n\n const { provider: providerType, mode, paramMapping } = page.dataSource;\n const provider = providers.get(providerType);\n\n if (!provider) {\n logger.warn(\n `ContentProvider \"${providerType}\" not found for page \"${page.id}\". Rendering with static props.`,\n );\n return page;\n }\n\n try {\n if (mode === \"list\") {\n return await hydrateListPage(page, provider, fetchParams);\n }\n\n if (mode === \"single\") {\n // Resolve the ID/slug from URL params\n const idOrSlug = resolveIdFromParams(paramMapping, urlParams);\n if (!idOrSlug) {\n logger.warn(\n `Could not resolve ID/slug for page \"${page.id}\" from URL params. Using static props.`,\n );\n return page;\n }\n return await hydrateSinglePage(page, provider, idOrSlug);\n }\n\n return page;\n } catch (error) {\n logger.error(`Error hydrating page \"${page.id}\":`, error);\n return page;\n }\n}\n\n/**\n * Pagination metadata passed from hydration to grid blocks.\n */\ninterface PaginationMeta {\n currentPage: number;\n totalPages: number;\n paginationBaseUrl: string;\n}\n\n/**\n * Builds a pagination base URL from the page slug and current filter params.\n * Preserves search/category so pagination links keep the active filters.\n * Uses /site/p/ prefix to match the consumer route pattern (same as viewAllHref, linkHref).\n */\nfunction buildPaginationBaseUrl(\n page: SitePage,\n fetchParams?: ContentListParams,\n): string {\n // Always paginate on the blog listing page — home page widget points to blog page\n const slug = page.slug && page.slug !== \"home\" ? page.slug : \"blog\";\n const basePath = `/site/p/${slug}`;\n\n const params = new URLSearchParams();\n const filter = fetchParams?.filter as Record<string, string> | undefined;\n if (filter?.search) params.set(\"busca\", filter.search);\n if (filter?.category) params.set(\"categoria\", filter.category);\n\n return params.toString() ? `${basePath}?${params.toString()}` : basePath;\n}\n\n/**\n * Hydrates a list-mode page: fetches items and populates grid blocks.\n */\nasync function hydrateListPage(\n page: SitePage,\n provider: ContentProvider,\n fetchParams?: ContentListParams,\n): Promise<SitePage> {\n const params: ContentListParams = {\n limit: 12,\n ...page.dataSource?.defaultParams,\n ...fetchParams,\n };\n\n const result = await provider.fetchList(params);\n\n // Convert items to block props (empty array if no results — shows empty state, never mock data)\n const cardProps = (result.items || []).map((item) => provider.toBlockProps(item));\n\n // Build pagination metadata (only when there are multiple pages)\n // _noPagination flag suppresses pagination for synthetic dataSource (e.g., home page blog widget)\n const noPagination = !!(page.dataSource?.defaultParams as Record<string, unknown> | undefined)?._noPagination;\n const totalPages = Math.ceil((result.total || 0) / (result.limit || params.limit || 12));\n const pagination: PaginationMeta | undefined = !noPagination && totalPages > 1\n ? {\n currentPage: result.page || 1,\n totalPages,\n paginationBaseUrl: buildPaginationBaseUrl(page, fetchParams),\n }\n : undefined;\n\n // Build recent posts for sidebar blogRecentPosts widget\n const recentPosts = (result.items || []).slice(0, 5).map((i) => {\n const d = i.data as Record<string, any>;\n return {\n title: (d.title as string) ?? '',\n slug: i.slug as string,\n date: i.metadata?.publishedAt\n ? new Date(i.metadata.publishedAt).toLocaleDateString('pt-BR', { day: '2-digit', month: 'short', year: 'numeric' })\n : undefined,\n image: (d.featuredImage as string) ?? undefined,\n category: (d.category as string) ?? undefined,\n };\n });\n\n // Extract tags from all posts for sidebar blogTagCloud widget\n const allTags = new Map<string, number>();\n for (const i of (result.items || [])) {\n const tags = (i.data as Record<string, any>).tags as string[] | undefined;\n if (tags) {\n for (const tag of tags) {\n allTags.set(tag, (allTags.get(tag) ?? 0) + 1);\n }\n }\n }\n const tagCloud = Array.from(allTags.entries())\n .map(([name, count]) => ({ name, count }))\n .sort((a, b) => b.count - a.count);\n\n // Hydrate all grid blocks, category filters, recent posts and tag cloud on the page\n const hydratedStructure = page.structure.map((block) => {\n let hydrated = hydrateGridBlock(block, cardProps, pagination);\n hydrated = hydrateCategoryFilterBlock(hydrated, cardProps);\n hydrated = hydrateRecentPostsBlock(hydrated, recentPosts);\n hydrated = hydrateTagCloudBlock(hydrated, tagCloud);\n return hydrated;\n });\n\n return {\n ...page,\n structure: hydratedStructure,\n };\n}\n\n/**\n * Hydrates grid blocks (blogPostGrid, etc.) with card data and pagination.\n */\nfunction hydrateGridBlock(\n block: Block,\n cardProps: Record<string, unknown>[],\n pagination?: PaginationMeta,\n): Block {\n // Direct match: blogPostGrid gets cards + pagination populated\n if (block.type === \"blogPostGrid\") {\n return {\n ...block,\n props: {\n ...block.props,\n cards: cardProps,\n ...(pagination ? {\n currentPage: pagination.currentPage,\n totalPages: pagination.totalPages,\n paginationBaseUrl: pagination.paginationBaseUrl,\n } : {}),\n },\n };\n }\n\n // Recurse into children for nested structures\n const props = block.props as Record<string, unknown>;\n if (props.children && Array.isArray(props.children)) {\n return {\n ...block,\n props: {\n ...props,\n children: (props.children as Block[]).map((child) =>\n hydrateGridBlock(child, cardProps, pagination),\n ),\n },\n };\n }\n\n return block;\n}\n\n/**\n * Hydrates a single-mode page: fetches one item and populates detail blocks.\n * Also fetches sidebar data (recent posts, tags, categories) for widgets.\n */\nasync function hydrateSinglePage(\n page: SitePage,\n provider: ContentProvider,\n idOrSlug: string,\n): Promise<SitePage> {\n const item = await provider.fetchById(idOrSlug);\n\n if (!item) {\n logger.warn(`Content item \"${idOrSlug}\" not found. Using static props.`);\n return page;\n }\n\n const blockProps = provider.toBlockProps(item);\n\n // Fetch recent posts for sidebar widgets\n let recentPosts: Array<{ title: string; slug: string; date?: string; image?: string; category?: string }> = [];\n let tagCloud: Array<{ name: string; count: number }> = [];\n let sidebarCardProps: Record<string, unknown>[] = [];\n\n try {\n const recentResult = await provider.fetchList({ limit: 10, sort: 'published_at' });\n const allItems = recentResult.items || [];\n\n // Map to card props for category filter hydration\n sidebarCardProps = allItems.map((i) => provider.toBlockProps(i));\n\n // Map recent posts (exclude current post)\n recentPosts = allItems\n .filter((i) => i.slug !== idOrSlug && i.slug)\n .slice(0, 5)\n .map((i) => {\n const d = i.data as Record<string, any>;\n return {\n title: (d.title as string) ?? '',\n slug: i.slug as string,\n date: i.metadata?.publishedAt\n ? new Date(i.metadata.publishedAt).toLocaleDateString('pt-BR', { day: '2-digit', month: 'short', year: 'numeric' })\n : undefined,\n image: (d.featuredImage as string) ?? undefined,\n category: (d.category as string) ?? undefined,\n };\n });\n\n // Extract tags from all posts\n const allTags = new Map<string, number>();\n for (const i of allItems) {\n const tags = (i.data as Record<string, any>).tags as string[] | undefined;\n if (tags) {\n for (const tag of tags) {\n allTags.set(tag, (allTags.get(tag) ?? 0) + 1);\n }\n }\n }\n tagCloud = Array.from(allTags.entries())\n .map(([name, count]) => ({ name, count }))\n .sort((a, b) => b.count - a.count);\n } catch (err) {\n logger.warn(`Failed to fetch sidebar data for page \"${page.id}\":`, err);\n }\n\n // Hydrate all blocks on the page\n const hydratedStructure = page.structure\n .map((block) => hydrateDetailBlock(block, blockProps, item))\n .map((block) => hydrateRecentPostsBlock(block, recentPosts))\n .map((block) => hydrateTagCloudBlock(block, tagCloud))\n .map((block) => hydrateCategoryFilterBlock(block, sidebarCardProps));\n\n // Extract SEO from content item and set on page\n const seo = extractSeoFromContent(item, blockProps);\n\n return {\n ...page,\n structure: hydratedStructure,\n ...(seo ? { seo } : {}),\n };\n}\n\n/**\n * Hydrates detail blocks (blogPostDetail, etc.) with item data.\n */\nfunction hydrateDetailBlock(\n block: Block,\n blockProps: Record<string, unknown>,\n item: ContentItem,\n): Block {\n if (block.type === \"blogPostDetail\") {\n return {\n ...block,\n props: {\n ...block.props,\n ...blockProps,\n // Preserve metadata\n _contentItemId: item.id,\n _contentItemSlug: item.slug,\n },\n };\n }\n\n // Also hydrate blogPostCard blocks that reference the same item\n if (block.type === \"blogPostCard\") {\n return {\n ...block,\n props: {\n ...block.props,\n ...blockProps,\n },\n };\n }\n\n // Recurse into children\n const props = block.props as Record<string, unknown>;\n if (props.children && Array.isArray(props.children)) {\n return {\n ...block,\n props: {\n ...props,\n children: (props.children as Block[]).map((child) =>\n hydrateDetailBlock(child, blockProps, item),\n ),\n },\n };\n }\n\n return block;\n}\n\n/**\n * Extracts SEO configuration from a ContentItem and block props.\n * Priority: item.metadata.seo > blockProps (metaTitle/title, metaDescription/excerpt, ogImage/featuredImage)\n */\nfunction extractSeoFromContent(\n item: ContentItem,\n blockProps: Record<string, unknown>,\n): PageSeoConfig | undefined {\n const seoMeta = item.metadata?.seo;\n\n const metaTitle = seoMeta?.metaTitle || (blockProps.metaTitle as string) || (blockProps.title as string);\n const metaDescription = seoMeta?.metaDescription || (blockProps.metaDescription as string) || (blockProps.excerpt as string);\n const ogImage = seoMeta?.ogImage || (blockProps.ogImage as string) || (blockProps.featuredImage as string);\n\n if (!metaTitle && !metaDescription && !ogImage) {\n return undefined;\n }\n\n return {\n metaTitle,\n metaDescription,\n ogImage,\n ogType: \"article\",\n };\n}\n\n/**\n * Hydrates blogRecentPosts blocks with recent post data.\n */\nfunction hydrateRecentPostsBlock(\n block: Block,\n recentPosts: Array<{ title: string; slug: string; date?: string; image?: string; category?: string }>,\n): Block {\n if (block.type === \"blogRecentPosts\") {\n return {\n ...block,\n props: {\n ...block.props,\n posts: recentPosts,\n },\n } as Block;\n }\n\n // Recurse into children\n const props = block.props as Record<string, unknown>;\n if (props.children && Array.isArray(props.children)) {\n return {\n ...block,\n props: {\n ...props,\n children: (props.children as Block[]).map((child) =>\n hydrateRecentPostsBlock(child, recentPosts),\n ),\n },\n } as Block;\n }\n\n return block;\n}\n\n/**\n * Hydrates blogTagCloud blocks with tag data.\n */\nfunction hydrateTagCloudBlock(\n block: Block,\n tags: Array<{ name: string; count: number }>,\n): Block {\n if (block.type === \"blogTagCloud\") {\n return {\n ...block,\n props: {\n ...block.props,\n tags,\n },\n } as Block;\n }\n\n // Recurse into children\n const props = block.props as Record<string, unknown>;\n if (props.children && Array.isArray(props.children)) {\n return {\n ...block,\n props: {\n ...props,\n children: (props.children as Block[]).map((child) =>\n hydrateTagCloudBlock(child, tags),\n ),\n },\n } as Block;\n }\n\n return block;\n}\n\n/**\n * Hydrates blogCategoryFilter blocks with category data extracted from posts.\n */\nfunction hydrateCategoryFilterBlock(\n block: Block,\n cardProps: Record<string, unknown>[],\n): Block {\n if (block.type === \"blogCategoryFilter\") {\n // Extract unique categories from posts with counts\n const categoryMap = new Map<string, number>();\n for (const card of cardProps) {\n const cat = card.category as string;\n if (cat) {\n categoryMap.set(cat, (categoryMap.get(cat) || 0) + 1);\n }\n }\n\n const categories = Array.from(categoryMap.entries()).map(([name, count]) => ({\n name,\n slug: name,\n count,\n }));\n\n return {\n ...block,\n props: {\n ...block.props,\n categories,\n },\n };\n }\n\n // Recurse into children\n const props = block.props as Record<string, unknown>;\n if (props.children && Array.isArray(props.children)) {\n return {\n ...block,\n props: {\n ...props,\n children: (props.children as Block[]).map((child) =>\n hydrateCategoryFilterBlock(child, cardProps),\n ),\n },\n };\n }\n\n return block;\n}\n\n/**\n * Resolves the item ID/slug from URL params using paramMapping.\n * e.g., paramMapping: { slug: \":slug\" }, urlParams: { slug: \"my-post\" } → \"my-post\"\n */\nfunction resolveIdFromParams(\n paramMapping?: Record<string, string>,\n urlParams?: Record<string, string>,\n): string | undefined {\n if (!paramMapping || !urlParams) return undefined;\n\n // Try slug first, then id\n for (const key of [\"slug\", \"id\"]) {\n const paramPattern = paramMapping[key];\n if (paramPattern) {\n // Extract param name from pattern (e.g., \":slug\" → \"slug\")\n const paramName = paramPattern.startsWith(\":\")\n ? paramPattern.slice(1)\n : paramPattern;\n const value = urlParams[paramName];\n if (value) return value;\n }\n }\n\n // Fallback: return first available param value\n for (const paramPattern of Object.values(paramMapping)) {\n const paramName = paramPattern.startsWith(\":\")\n ? paramPattern.slice(1)\n : paramPattern;\n const value = urlParams[paramName];\n if (value) return value;\n }\n\n return undefined;\n}\n"],"names":["hydratePageWithContent","page","providers","urlParams","fetchParams","providerType","mode","paramMapping","provider","logger","hydrateListPage","idOrSlug","resolveIdFromParams","hydrateSinglePage","error","buildPaginationBaseUrl","basePath","params","filter","result","cardProps","item","noPagination","totalPages","pagination","recentPosts","i","d","allTags","tags","tag","tagCloud","name","count","a","b","hydratedStructure","block","hydrated","hydrateGridBlock","hydrateCategoryFilterBlock","hydrateRecentPostsBlock","hydrateTagCloudBlock","props","child","blockProps","sidebarCardProps","allItems","err","hydrateDetailBlock","seo","extractSeoFromContent","seoMeta","metaTitle","metaDescription","ogImage","categoryMap","card","cat","categories","key","paramPattern","paramName","value"],"mappings":"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"}