/** * Layout Renderer * Phase 5: Sites Renderer & Publishing * * Renders different layout types for sites using shared components. */ import React from 'react'; import type { SiteDefinition } from '../types'; import { renderTemplate } from './templateEngine'; import { DefaultLayout, MinimalLayout, MagazineLayout, EcommerceLayout, PortfolioLayout, BlogLayout, CorporateLayout, } from '@shared/layouts'; export type LayoutType = | 'default' | 'minimal' | 'magazine' | 'ecommerce' | 'portfolio' | 'blog' | 'corporate'; /** * Render site layout based on site definition. */ export function renderLayout(siteDefinition: SiteDefinition): React.ReactElement { const layoutType = siteDefinition.layout as LayoutType; switch (layoutType) { case 'minimal': return renderMinimalLayout(siteDefinition); case 'magazine': return renderMagazineLayout(siteDefinition); case 'ecommerce': return renderEcommerceLayout(siteDefinition); case 'portfolio': return renderPortfolioLayout(siteDefinition); case 'blog': return renderBlogLayout(siteDefinition); case 'corporate': return renderCorporateLayout(siteDefinition); case 'default': default: return renderDefaultLayout(siteDefinition); } } /** * Default layout: Standard header, content, footer. * Uses shared DefaultLayout component with fully styled modern design. */ function renderDefaultLayout(siteDefinition: SiteDefinition): React.ReactElement { // Find home page for hero const homePage = siteDefinition.pages.find(p => p.slug === 'home'); const heroBlock = homePage?.blocks?.find(b => b.type === 'hero'); const hero: React.ReactNode = heroBlock ? (renderTemplate(heroBlock) as React.ReactNode) : undefined; // Render all pages as sections (excluding hero from home page if it exists) const sections = siteDefinition.pages .filter((page) => page.status !== 'draft') .map((page) => { // Filter out hero block if it's the home page (already rendered as hero) const blocksToRender = page.slug === 'home' && heroBlock ? page.blocks?.filter(b => b.type !== 'hero') || [] : page.blocks || []; return (
{page.slug !== 'home' &&

{page.title}

} {blocksToRender.length > 0 ? ( blocksToRender.map((block, index) => (
{renderTemplate(block)}
)) ) : page.slug !== 'home' ? (

No content available for this page.

) : null}
); }); return ( ); } /** * Minimal layout: Clean, minimal design. * Uses shared MinimalLayout component. */ function renderMinimalLayout(siteDefinition: SiteDefinition): React.ReactElement { const mainContent = ( <> {siteDefinition.pages .filter((page) => page.status !== 'draft') .map((page) => (

{page.title}

{page.blocks && page.blocks.length > 0 ? ( page.blocks.map((block, index) => (
{renderTemplate(block)}
)) ) : null}
))} ); return ( {mainContent} ); } /** * Magazine layout: Editorial, content-focused. * Uses shared MagazineLayout component. */ function renderMagazineLayout(siteDefinition: SiteDefinition): React.ReactElement { const mainContent = ( <> {siteDefinition.pages .filter((page) => page.status !== 'draft') .map((page) => (
{page.blocks && page.blocks.length > 0 ? ( page.blocks.map((block, index) => (
{renderTemplate(block)}
)) ) : null}
))} ); return ( ); } /** * Ecommerce layout: Product-focused. * Uses shared EcommerceLayout component. */ function renderEcommerceLayout(siteDefinition: SiteDefinition): React.ReactElement { const mainContent = ( <> {siteDefinition.pages .filter((page) => page.status !== 'draft') .map((page) => (
{page.blocks && page.blocks.length > 0 ? ( page.blocks.map((block, index) => (
{renderTemplate(block)}
)) ) : null}
))} ); return ( ); } /** * Portfolio layout: Showcase. * Uses shared PortfolioLayout component. */ function renderPortfolioLayout(siteDefinition: SiteDefinition): React.ReactElement { const mainContent = ( <> {siteDefinition.pages .filter((page) => page.status !== 'draft') .map((page) => (
{page.blocks && page.blocks.length > 0 ? ( page.blocks.map((block, index) => (
{renderTemplate(block)}
)) ) : null}
))} ); return ( ); } /** * Blog layout: Content-first. * Uses shared BlogLayout component. */ function renderBlogLayout(siteDefinition: SiteDefinition): React.ReactElement { const mainContent = ( <> {siteDefinition.pages .filter((page) => page.status !== 'draft') .map((page) => (
{page.blocks && page.blocks.length > 0 ? ( page.blocks.map((block, index) => (
{renderTemplate(block)}
)) ) : null}
))} ); return ( ); } /** * Corporate layout: Business. * Uses shared CorporateLayout component. */ function renderCorporateLayout(siteDefinition: SiteDefinition): React.ReactElement { const mainContent = ( <> {siteDefinition.pages .filter((page) => page.status !== 'draft') .map((page) => (
{page.blocks && page.blocks.length > 0 ? ( page.blocks.map((block, index) => (
{renderTemplate(block)}
)) ) : null}
))} ); return ( ); } // Note: Navigation and page rendering are now handled within each layout component