UNPKG

hatch-slidev-builder-mcp

Version:

A comprehensive MCP server for creating Slidev presentations with component library, interactive elements, and team collaboration features

181 lines (162 loc) 5.12 kB
import * as fs from 'fs-extra'; import * as path from 'path'; export async function createSlide(args) { const { deckPath, slideType, content, layout, position } = args; try { const slidesPath = path.join(deckPath, 'slides.md'); if (!await fs.pathExists(slidesPath)) { throw new Error(`Slides file not found at ${slidesPath}`); } const slidesContent = await fs.readFile(slidesPath, 'utf-8'); const slides = slidesContent.split(/\n---\n/); let newSlideContent = ''; const slideLayout = layout || getDefaultLayout(slideType); // Generate slide content based on type switch (slideType) { case 'title': newSlideContent = generateTitleSlide(content, slideLayout); break; case 'content': newSlideContent = generateContentSlide(content, slideLayout); break; case 'two-column': newSlideContent = generateTwoColumnSlide(content, slideLayout); break; case 'image': newSlideContent = generateImageSlide(content, slideLayout); break; case 'chart': newSlideContent = generateChartSlide(content, slideLayout); break; case 'interactive': newSlideContent = generateInteractiveSlide(content, slideLayout); break; case 'custom': newSlideContent = content.body || ''; break; } // Insert slide at specified position or at the end const insertPosition = position !== undefined ? position + 1 : slides.length; slides.splice(insertPosition, 0, newSlideContent); // Write back to file const updatedContent = slides.join('\n---\n'); await fs.writeFile(slidesPath, updatedContent); return { content: [ { type: 'text', text: `✅ Successfully added ${slideType} slide to presentation\n\n` + `📁 Deck Path: ${deckPath}\n` + `📋 Layout: ${slideLayout}\n` + `📍 Position: ${insertPosition}\n` + `📊 Total Slides: ${slides.length}` } ] }; } catch (error) { throw new Error(`Failed to create slide: ${error instanceof Error ? error.message : String(error)}`); } } function getDefaultLayout(slideType) { const layouts = { title: 'cover', content: 'default', 'two-column': 'two-cols', image: 'image-right', chart: 'center', interactive: 'default', custom: 'default' }; return layouts[slideType] || 'default'; } function generateTitleSlide(content, layout) { return ` layout: ${layout} background: linear-gradient(135deg, #00A651, #004225) class: text-white --- # ${content.title || 'Title Slide'} ${content.subtitle ? `## ${content.subtitle}` : ''} ### ${new Date().toLocaleDateString()} `.trim(); } function generateContentSlide(content, layout) { return ` layout: ${layout} --- # ${content.title || 'Content Slide'} ${content.body || ` - Key point 1 - Key point 2 - Key point 3 - Key point 4 `} `.trim(); } function generateTwoColumnSlide(content, layout) { return ` layout: ${layout} --- # ${content.title || 'Two Column Slide'} <div class="grid grid-cols-2 gap-8"> <div> ${content.leftColumn || 'Left column content'} </div> <div> ${content.rightColumn || 'Right column content'} </div> </div> `.trim(); } function generateImageSlide(content, layout) { return ` layout: ${layout} --- # ${content.title || 'Image Slide'} <div class="flex justify-center items-center h-full"> <img src="${content.image || '/placeholder.jpg'}" alt="${content.title}" class="max-h-96 rounded-lg shadow-lg" /> </div> `.trim(); } function generateChartSlide(content, layout) { return ` layout: ${layout} --- # ${content.title || 'Chart Slide'} <div class="chart-container flex justify-center items-center h-full"> <div class="w-full max-w-4xl"> <!-- Chart will be embedded here --> <div class="bg-gray-100 p-8 rounded-lg text-center"> <h3 class="text-xl mb-4">Chart: ${content.chart || 'Sample Chart'}</h3> <p class="text-gray-600">Chart content will be generated by Python integration</p> </div> </div> </div> `.trim(); } function generateInteractiveSlide(content, layout) { return ` layout: ${layout} --- # ${content.title || 'Interactive Slide'} <InteractiveArrows /> <script setup> import { ref, onMounted } from 'vue' // Interactive component setup const interactiveData = ref({}) onMounted(() => { // Initialize interactive elements console.log('Interactive slide loaded') }) </script> <style> .interactive-element { transition: all 0.3s ease; } .interactive-element:hover { transform: scale(1.05); } </style> `.trim(); }