Skip to main content
Glama
layout-generator.ts11.6 kB
import { callGemini, isGeminiAvailable } from '../utils/gemini.js'; interface LayoutRequest { type: 'dashboard' | 'landing' | 'blog' | 'ecommerce' | 'portfolio' | 'documentation'; sections: string[]; complexity?: 'simple' | 'medium' | 'complex'; framework?: 'html' | 'react' | 'vue' | 'svelte'; } const LAYOUT_TEMPLATES = { dashboard: { simple: { structure: ['header', 'sidebar', 'main'], gridTemplate: 'grid-rows-[auto_1fr] grid-cols-[250px_1fr]' }, medium: { structure: ['header', 'sidebar', 'main', 'footer'], gridTemplate: 'grid-rows-[auto_1fr_auto] grid-cols-[250px_1fr]' }, complex: { structure: ['header', 'sidebar', 'main', 'aside', 'footer'], gridTemplate: 'grid-rows-[auto_1fr_auto] grid-cols-[250px_1fr_300px]' } }, landing: { simple: { structure: ['header', 'hero', 'footer'], gridTemplate: 'grid-rows-[auto_1fr_auto]' }, medium: { structure: ['header', 'hero', 'features', 'cta', 'footer'], gridTemplate: 'grid-rows-[auto_auto_auto_auto_auto]' }, complex: { structure: ['header', 'hero', 'features', 'testimonials', 'pricing', 'cta', 'footer'], gridTemplate: 'grid-rows-[auto_auto_auto_auto_auto_auto_auto]' } } }; export async function createLayout(args: LayoutRequest) { try { const { type, sections, complexity = 'medium', framework = 'html' } = args; let layoutCode = ''; if (isGeminiAvailable()) { const prompt = `Generate a complete ${complexity} ${type} layout using Tailwind CSS with the following specifications: Layout Type: ${type} Sections: ${sections.join(', ')} Complexity: ${complexity} Framework: ${framework} Requirements: 1. Create a fully responsive layout using Tailwind CSS 2. Include proper semantic HTML structure 3. Use modern CSS Grid and Flexbox techniques 4. Implement mobile-first responsive design 5. Include placeholder content that's realistic for a ${type} 6. Add proper spacing, typography, and visual hierarchy 7. Include interactive elements with hover states 8. Ensure accessibility with proper ARIA labels 9. Use appropriate color scheme and styling ${framework === 'react' ? 'Generate as React functional components with TypeScript' : ''} ${framework === 'vue' ? 'Generate as Vue 3 composition API components' : ''} ${framework === 'svelte' ? 'Generate as Svelte components' : ''} For ${type} layout, focus on: ${getLayoutFocusPoints(type)} Return complete, production-ready code with proper structure and styling.`; layoutCode = await callGemini(prompt); } else { layoutCode = generateTemplateLayout(type, sections, complexity, framework); } // Clean up the generated code layoutCode = layoutCode.replace(/```[\w]*\n?/g, '').trim(); return { content: [ { type: 'text', text: `# ${type.charAt(0).toUpperCase() + type.slice(1)} Layout - ${complexity.charAt(0).toUpperCase() + complexity.slice(1)} Complexity ## Generated Layout \`\`\`${framework === 'html' ? 'html' : framework} ${layoutCode} \`\`\` ## Layout Features - **Type**: ${type} - **Complexity**: ${complexity} - **Framework**: ${framework} - **Sections**: ${sections.join(', ')} ## Responsive Breakpoints - **Mobile**: Base styles (< 640px) - **Tablet**: sm: prefix (≥ 640px) - **Desktop**: md: prefix (≥ 768px) - **Large**: lg: prefix (≥ 1024px) - **Extra Large**: xl: prefix (≥ 1280px) ## Customization Tips - Adjust color scheme by modifying color classes - Change spacing with different padding/margin classes - Modify typography with font size and weight classes - Add animations with transition and transform classes - Customize breakpoints for different responsive behavior ## Accessibility Features - Semantic HTML structure - Proper heading hierarchy - ARIA labels where appropriate - Keyboard navigation support - Screen reader friendly content ## Performance Considerations - Optimized class usage - Minimal custom CSS required - Efficient responsive design - Fast rendering with Tailwind's utility-first approach` } ] }; } catch (error) { console.error('Layout generation error:', error); throw new Error(`Failed to create layout: ${error instanceof Error ? error.message : 'Unknown error'}`); } } function getLayoutFocusPoints(type: string): string { switch (type) { case 'dashboard': return '- Data visualization areas\n- Navigation and filtering\n- Sidebar navigation\n- Content hierarchy\n- Action buttons and controls'; case 'landing': return '- Hero section with compelling CTA\n- Feature highlights\n- Social proof elements\n- Clear value proposition\n- Conversion optimization'; case 'blog': return '- Content readability\n- Article layout and typography\n- Navigation and categories\n- Author information\n- Related posts'; case 'ecommerce': return '- Product showcase\n- Shopping cart integration\n- Search and filtering\n- Trust indicators\n- Purchase flow optimization'; case 'portfolio': return '- Project showcases\n- About section\n- Contact information\n- Skills and experience\n- Visual appeal and creativity'; case 'documentation': return '- Clear information hierarchy\n- Search functionality\n- Table of contents\n- Code examples\n- Easy navigation'; default: return '- Clean, modern design\n- User-friendly navigation\n- Responsive layout\n- Accessible content'; } } function generateTemplateLayout( type: string, sections: string[], complexity: string, framework: string ): string { const template = LAYOUT_TEMPLATES[type as keyof typeof LAYOUT_TEMPLATES]; if (!template) { return generateGenericLayout(sections, framework); } const layoutConfig = template[complexity as keyof typeof template]; if (framework === 'react') { return generateReactLayout(type, sections, layoutConfig); } else if (framework === 'vue') { return generateVueLayout(type, sections, layoutConfig); } else { return generateHTMLLayout(type, sections, layoutConfig); } } function generateHTMLLayout(type: string, sections: string[], config: any): string { let html = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>${type.charAt(0).toUpperCase() + type.slice(1)} Layout</title> <script src="https://cdn.tailwindcss.com"></script> </head> <body class="min-h-screen bg-gray-50"> <div class="min-h-screen grid ${config.gridTemplate}">`; sections.forEach(section => { switch (section) { case 'header': html += ` <header class="bg-white shadow-sm border-b border-gray-200 px-6 py-4 col-span-full"> <div class="flex items-center justify-between"> <h1 class="text-xl font-semibold text-gray-900">${type.charAt(0).toUpperCase() + type.slice(1)}</h1> <nav class="hidden md:flex space-x-6"> <a href="#" class="text-gray-600 hover:text-gray-900">Home</a> <a href="#" class="text-gray-600 hover:text-gray-900">About</a> <a href="#" class="text-gray-600 hover:text-gray-900">Contact</a> </nav> </div> </header>`; break; case 'sidebar': html += ` <aside class="bg-white border-r border-gray-200 p-6"> <nav class="space-y-2"> <a href="#" class="block px-3 py-2 text-gray-700 hover:bg-gray-100 rounded">Dashboard</a> <a href="#" class="block px-3 py-2 text-gray-700 hover:bg-gray-100 rounded">Analytics</a> <a href="#" class="block px-3 py-2 text-gray-700 hover:bg-gray-100 rounded">Settings</a> </nav> </aside>`; break; case 'main': html += ` <main class="p-6 overflow-auto"> <div class="max-w-7xl mx-auto"> <h2 class="text-2xl font-bold text-gray-900 mb-6">Main Content</h2> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <div class="bg-white p-6 rounded-lg shadow"> <h3 class="text-lg font-medium mb-2">Card 1</h3> <p class="text-gray-600">Content goes here...</p> </div> <div class="bg-white p-6 rounded-lg shadow"> <h3 class="text-lg font-medium mb-2">Card 2</h3> <p class="text-gray-600">Content goes here...</p> </div> <div class="bg-white p-6 rounded-lg shadow"> <h3 class="text-lg font-medium mb-2">Card 3</h3> <p class="text-gray-600">Content goes here...</p> </div> </div> </div> </main>`; break; case 'footer': html += ` <footer class="bg-gray-800 text-white p-6 col-span-full"> <div class="max-w-7xl mx-auto text-center"> <p>&copy; 2024 ${type.charAt(0).toUpperCase() + type.slice(1)}. All rights reserved.</p> </div> </footer>`; break; default: html += ` <section class="p-6"> <h2 class="text-xl font-semibold mb-4">${section.charAt(0).toUpperCase() + section.slice(1)}</h2> <p class="text-gray-600">Content for ${section} section...</p> </section>`; } }); html += ` </div> </body> </html>`; return html; } function generateReactLayout(type: string, sections: string[], config: any): string { return `import React from 'react'; interface ${type.charAt(0).toUpperCase() + type.slice(1)}LayoutProps { children?: React.ReactNode; } export function ${type.charAt(0).toUpperCase() + type.slice(1)}Layout({ children }: ${type.charAt(0).toUpperCase() + type.slice(1)}LayoutProps) { return ( <div className="min-h-screen grid ${config.gridTemplate}"> ${sections.map(section => generateReactSection(section)).join('\n ')} </div> ); } export default ${type.charAt(0).toUpperCase() + type.slice(1)}Layout;`; } function generateReactSection(section: string): string { switch (section) { case 'header': return `<header className="bg-white shadow-sm border-b border-gray-200 px-6 py-4 col-span-full"> <div className="flex items-center justify-between"> <h1 className="text-xl font-semibold text-gray-900">Dashboard</h1> <nav className="hidden md:flex space-x-6"> <a href="#" className="text-gray-600 hover:text-gray-900">Home</a> <a href="#" className="text-gray-600 hover:text-gray-900">About</a> </nav> </div> </header>`; case 'main': return `<main className="p-6 overflow-auto"> {children} </main>`; default: return `<section className="p-6"> <h2 className="text-xl font-semibold mb-4">${section.charAt(0).toUpperCase() + section.slice(1)}</h2> </section>`; } } function generateVueLayout(type: string, sections: string[], config: any): string { return `<template> <div class="min-h-screen grid ${config.gridTemplate}"> ${sections.map(section => `<${section.charAt(0).toUpperCase() + section.slice(1)}Section />`).join('\n ')} </div> </template> <script setup lang="ts"> // Import section components here </script>`; } function generateGenericLayout(sections: string[], framework: string): string { if (framework === 'react') { return `<div className="min-h-screen"> ${sections.map(section => `<${section} />`).join('\n ')} </div>`; } else { return `<div class="min-h-screen"> ${sections.map(section => `<section class="p-6"> <h2 class="text-xl font-semibold mb-4">${section.charAt(0).toUpperCase() + section.slice(1)}</h2> </section>`).join('\n ')} </div>`; } }

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Tai-DT/mcp-tailwind-gemini'

If you have feedback or need assistance with the MCP directory API, please join our Discord server