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
JavaScript
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();
}