slide-builder / index.html
resumesearch's picture
make drastic improvements on every element of this application. make it a 10/10 enterprise application: "<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Slide Builder Plus</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: Arial, sans-serif; background: #f0f0f0; padding: 20px; } .container { max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } h1 { color: #333; margin-bottom: 20px; text-align: center; } .controls { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; } button { padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 14px; } button:hover { background: #0056b3; } button.danger { background: #dc3545; } button.danger:hover { background: #c82333; } button.success { background: #28a745; } button.success:hover { background: #218838; } button.secondary { background: #6c757d; } button.secondary:hover { background: #5a6268; } .preview { border: 2px solid #ddd; border-radius: 10px; padding: 40px; min-height: 400px; background: #fff; margin-bottom: 20px; } .preview.dark { background: #2d2d2d; color: white; } .preview.blue { background: #e3f2fd; } .slide-element { margin-bottom: 20px; padding: 10px; border: 1px dashed transparent; cursor: pointer; position: relative; } .slide-element:hover { border-color: #007bff; background: #f8f9fa; } .slide-element.selected { border: 2px solid #007bff; background: #e7f3ff; } .element-controls { position: absolute; top: 5px; right: 5px; display: none; gap: 5px; } .slide-element.selected .element-controls { display: flex; } .element-title { font-size: 48px; text-align: center; font-weight: bold; color: #333; } .preview.dark .element-title { color: white; } .element-heading { font-size: 32px; color: #444; margin-bottom: 10px; } .preview.dark .element-heading { color: #f0f0f0; } .element-text { font-size: 18px; line-height: 1.6; color: #666; } .preview.dark .element-text { color: #ccc; } .element-list { font-size: 18px; line-height: 1.8; color: #666; padding-left: 30px; } .preview.dark .element-list { color: #ccc; } .element-quote { font-size: 24px; font-style: italic; text-align: center; padding: 20px; border-left: 4px solid #007bff; background: rgba(0,123,255,0.05); } .element-divider { height: 2px; background: #ddd; margin: 20px 0; } .edit-panel { display: none; background: #f8f9fa; padding: 20px; border-radius: 10px; margin-bottom: 20px; } .edit-panel.active { display: block; } .edit-panel h3 { margin-bottom: 15px; color: #333; } textarea { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 5px; font-size: 14px; resize: vertical; } .export-panel { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 30px; border-radius: 10px; box-shadow: 0 5px 30px rgba(0,0,0,0.3); z-index: 1000; max-width: 90%; width: 800px; } .export-panel.active { display: block; } .overlay { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.5); z-index: 999; } .overlay.active { display: block; } .close-btn { float: right; background: #dc3545; padding: 5px 15px; } .close-btn:hover { background: #c82333; } #exportCode { width: 100%; height: 300px; margin: 20px 0; font-family: monospace; font-size: 12px; } .button-group { display: flex; gap: 10px; } .button-group button { flex: 1; } .info-box { background: #d1ecf1; border: 1px solid #bee5eb; padding: 15px; border-radius: 5px; margin-bottom: 20px; color: #0c5460; } .theme-buttons { display: flex; gap: 10px; margin-bottom: 20px; } .align-left { text-align: left; } .align-center { text-align: center; } .align-right { text-align: right; } .control-btn { padding: 5px 10px; font-size: 12px; background: white; color: #333; border: 1px solid #ddd; } .control-btn:hover { background: #f8f9fa; } select { padding: 5px; margin: 0 10px; border: 1px solid #ddd; border-radius: 3px; } </style> </head> <body> <div class="container"> <h1>📝 Slide Builder Plus</h1> <div class="info-box"> <strong>Quick Start:</strong> Click buttons to add elements, click elements to edit, apply themes, then export! </div> <div class="controls"> <button onclick="addTitle()">Add Title</button> <button onclick="addHeading()">Add Heading</button> <button onclick="addText()">Add Text</button> <button onclick="addList()">Add List</button> <button onclick="addQuote()">Add Quote</button> <button onclick="addDivider()">Add Divider</button> <button onclick="clearAll()" class="danger">Clear All</button> <button onclick="showExport()" class="success">Export HTML</button> </div> <div class="theme-buttons"> <strong>Theme:</strong> <button onclick="setTheme('default')" class="secondary">Default</button> <button onclick="setTheme('dark')" class="secondary">Dark</button> <button onclick="setTheme('blue')" class="secondary">Blue</button> </div> <div class="edit-panel" id="editPanel"> <button class="close-btn" onclick="closeEdit()">×</button> <h3>Edit Element</h3> <textarea id="editInput" rows="4" placeholder="Edit your content here..."></textarea> <div style="margin-top: 10px;"> <strong>Alignment:</strong> <button onclick="setAlign('left')">Left</button> <button onclick="setAlign('center')">Center</button> <button onclick="setAlign('right')">Right</button> </div> <button onclick="saveEdit()" style="margin-top: 10px;" class="success">Save Changes</button> </div> <div class="preview" id="preview"> <p style="text-align: center; color: #999;">Click buttons above to add content to your slide</p> </div> </div> <div class="overlay" id="overlay" onclick="closeExport()"></div> <div class="export-panel" id="exportPanel"> <button class="close-btn" onclick="closeExport()">×</button> <h3>Export Your Slide</h3> <p>Copy the HTML code below or download as a file:</p> <textarea id="exportCode" readonly></textarea> <div class="button-group"> <button onclick="copyCode()" class="success">Copy to Clipboard</button> <button onclick="downloadHTML()">Download HTML File</button> </div> </div> <script> // Global variables let elements = []; let selectedElement = null; let elementIdCounter = 0; let currentTheme = 'default'; // Add Title function addTitle() { const element = { id: elementIdCounter++, type: 'title', content: 'Your Awesome Title', align: 'center' }; elements.push(element); renderPreview(); } // Add Heading function addHeading() { const element = { id: elementIdCounter++, type: 'heading', content: 'Section Heading', align: 'left' }; elements.push(element); renderPreview(); } // Add Text function addText() { const element = { id: elementIdCounter++, type: 'text', content: 'Your paragraph text goes here. Click to edit and add your own content.', align: 'left' }; elements.push(element); renderPreview(); } // Add List function addList() { const element = { id: elementIdCounter++, type: 'list', content: 'First item\nSecond item\nThird item', align: 'left' }; elements.push(element); renderPreview(); } // Add Quote function addQuote() { const element = { id: elementIdCounter++, type: 'quote', content: 'The only way to do great work is to love what you do. - Steve Jobs', align: 'center' }; elements.push(element); renderPreview(); } // Add Divider function addDivider() { const element = { id: elementIdCounter++, type: 'divider', align: 'center' }; elements.push(element); renderPreview(); } // Clear All function clearAll() { if (confirm('Are you sure you want to clear all elements?')) { elements = []; renderPreview(); } } // Set Theme function setTheme(theme) { currentTheme = theme; const preview = document.getElementById('preview'); preview.className = 'preview ' + (theme !== 'default' ? theme : ''); } // Render Preview function renderPreview() { const preview = document.getElementById('preview'); if (elements.length === 0) { preview.innerHTML = '<p style="text-align: center; color: #999;">Click buttons above to add content to your slide</p>'; return; } preview.innerHTML = ''; elements.forEach(element => { const div = document.createElement('div'); div.className = 'slide-element'; div.onclick = () => selectElement(element.id); // Add controls const controls = document.createElement('div'); controls.className = 'element-controls'; controls.innerHTML = ` <button class="control-btn" onclick="event.stopPropagation(); moveUp(${element.id})">↑</button> <button class="control-btn" onclick="event.stopPropagation(); moveDown(${element.id})">↓</button> <button class="control-btn" onclick="event.stopPropagation(); deleteElement(${element.id})">×</button> `; div.appendChild(controls); // Add content wrapper with alignment const contentWrapper = document.createElement('div'); contentWrapper.className = 'align-' + element.align; switch(element.type) { case 'title': contentWrapper.innerHTML = `<h1 class="element-title">${element.content}</h1>`; break; case 'heading': contentWrapper.innerHTML = `<h2 class="element-heading">${element.content}</h2>`; break; case 'text': contentWrapper.innerHTML = `<p class="element-text">${element.content.replace(/\n/g, '<br>')}</p>`; break; case 'list': const items = element.content.split('\n').map(item => `<li>${item}</li>`).join(''); contentWrapper.innerHTML = `<ul class="element-list">${items}</ul>`; break; case 'quote': contentWrapper.innerHTML = `<blockquote class="element-quote">${element.content}</blockquote>`; break; case 'divider': contentWrapper.innerHTML = `<hr class="element-divider">`; break; } div.appendChild(contentWrapper); preview.appendChild(div); }); } // Select Element function selectElement(id) { selectedElement = elements.find(el => el.id === id); // Remove previous selection document.querySelectorAll('.slide-element').forEach(el => { el.classList.remove('selected'); }); // Add selection to clicked element event.currentTarget.classList.add('selected'); // Show edit panel for editable types if (selectedElement.type !== 'divider') { document.getElementById('editPanel').classList.add('active'); document.getElementById('editInput').value = selectedElement.content; } } // Close Edit function closeEdit() { document.getElementById('editPanel').classList.remove('active'); document.querySelectorAll('.slide-element').forEach(el => { el.classList.remove('selected'); }); selectedElement = null; } // Save Edit function saveEdit() { if (selectedElement) { selectedElement.content = document.getElementById('editInput').value; renderPreview(); closeEdit(); } } // Set Alignment function setAlign(alignment) { if (selectedElement) { selectedElement.align = alignment; renderPreview(); selectElement(selectedElement.id); } } // Delete Element function deleteElement(id) { elements = elements.filter(el => el.id !== id); renderPreview(); } // Move Up function moveUp(id) { const index = elements.findIndex(el => el.id === id); if (index > 0) { [elements[index], elements[index - 1]] = [elements[index - 1], elements[index]]; renderPreview(); } } // Move Down function moveDown(id) { const index = elements.findIndex(el => el.id === id); if (index < elements.length - 1) { [elements[index], elements[index + 1]] = [elements[index + 1], elements[index]]; renderPreview(); } } // Show Export function showExport() { const html = generateHTML(); document.getElementById('exportCode').value = html; document.getElementById('exportPanel').classList.add('active'); document.getElementById('overlay').classList.add('active'); } // Close Export function closeExport() { document.getElementById('exportPanel').classList.remove('active'); document.getElementById('overlay').classList.remove('active'); } // Generate HTML function generateHTML() { let content = ''; elements.forEach(element => { const alignClass = element.align !== 'left' ? ` style="text-align: ${element.align};"` : ''; switch(element.type) { case 'title': content += `<h1 style="font-size: 48px; text-align: ${element.align}; margin: 40px 0; color: ${currentTheme === 'dark' ? 'white' : '#333'};">${element.content}</h1>\n`; break; case 'heading': content += `<h2 style="font-size: 32px; text-align: ${element.align}; margin: 30px 0; color: ${currentTheme === 'dark' ? '#f0f0f0' : '#444'};">${element.content}</h2>\n`; break; case 'text': content += `<p style="font-size: 18px; line-height: 1.6; text-align: ${element.align}; margin: 20px 0; color: ${currentTheme === 'dark' ? '#ccc' : '#666'};">${element.content.replace(/\n/g, '<br>')}</p>\n`; break; case 'list': const items = element.content.split('\n').map(item => `<li>${item}</li>`).join('\n'); content += `<ul style="font-size: 18px; line-height: 1.8; text-align: ${element.align}; margin: 20px 0; padding-left: 30px; color: ${currentTheme === 'dark' ? '#ccc' : '#666'};">\n${items}\n</ul>\n`; break; case 'quote': content += `<blockquote style="font-size: 24px; font-style: italic; text-align: center; padding: 20px 40px; border-left: 4px solid #007bff; background: rgba(0,123,255,0.05); margin: 30px 0;">${element.content}</blockquote>\n`; break; case 'divider': content += `<hr style="border: none; height: 2px; background: #ddd; margin: 30px 0;">\n`; break; } }); const bgColor = currentTheme === 'dark' ? '#2d2d2d' : currentTheme === 'blue' ? '#e3f2fd' : '#f5f5f5'; const textColor = currentTheme === 'dark' ? 'white' : '#333'; return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>My Presentation Slide</title> <style> body { font-family: Arial, sans-serif; max-width: 1000px; margin: 0 auto; padding: 60px 40px; background: ${bgColor}; color: ${textColor}; } .slide { background: ${currentTheme === 'dark' ? '#1a1a1a' : 'white'}; padding: 60px; border-radius: 10px; box-shadow: 0 5px 30px rgba(0,0,0,0.1); min-height: 600px; display: flex; flex-direction: column; justify-content: center; } </style> </head> <body> <div class="slide"> ${content} </div> </body> </html>`; } // Copy Code function copyCode() { const textarea = document.getElementById('exportCode'); textarea.select(); document.execCommand('copy'); // Show feedback const button = event.target; const originalText = button.textContent; button.textContent = 'Copied!'; setTimeout(() => { button.textContent = originalText; }, 2000); } // Download HTML function downloadHTML() { const html = document.getElementById('exportCode').value; const blob = new Blob([html], { type: 'text/html' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'my-slide.html'; a.click(); window.URL.revokeObjectURL(url); } // Test on load window.onload = function() { console.log('Slide Builder Plus: Ready'); }; </script> </body> </html>" - Initial Deployment
a0eda66 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Slide Builder Pro | Enterprise Presentation Tool</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
},
secondary: {
50: '#f8fafc',
100: '#f1f5f9',
200: '#e2e8f0',
300: '#cbd5e1',
400: '#94a3b8',
500: '#64748b',
600: '#475569',
700: '#334155',
800: '#1e293b',
900: '#0f172a',
},
success: {
50: '#f0fdf4',
100: '#dcfce7',
200: '#bbf7d0',
300: '#86efac',
400: '#4ade80',
500: '#22c55e',
600: '#16a34a',
700: '#15803d',
800: '#166534',
900: '#14532d',
},
danger: {
50: '#fff1f2',
100: '#ffe4e6',
200: '#fecdd3',
300: '#fda4af',
400: '#fb7185',
500: '#f43f5e',
600: '#e11d48',
700: '#be123c',
800: '#9f1239',
900: '#881337',
},
warning: {
50: '#fffbeb',
100: '#fef3c7',
200: '#fde68a',
300: '#fcd34d',
400: '#fbbf24',
500: '#f59e0b',
600: '#d97706',
700: '#b45309',
800: '#92400e',
900: '#78350f',
},
}
}
}
}
</script>
<style>
.slide-element {
transition: all 0.2s ease;
}
.slide-element:hover {
transform: translateY(-2px);
}
.element-controls {
opacity: 0;
transition: opacity 0.2s ease;
}
.slide-element:hover .element-controls {
opacity: 1;
}
.preview-container {
min-height: 500px;
background-size: 40px 40px;
background-image: linear-gradient(to right, rgba(0, 0, 0, 0.03) 1px, transparent 1px),
linear-gradient(to bottom, rgba(0, 0, 0, 0.03) 1px, transparent 1px);
}
.dark .preview-container {
background-image: linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px),
linear-gradient(to bottom, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
}
.export-code {
font-family: 'Fira Code', monospace;
}
.slide-element.selected {
box-shadow: 0 0 0 2px theme('colors.primary.500');
}
.element-title {
background: linear-gradient(to right, theme('colors.primary.600'), theme('colors.primary.400'));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.dark .element-title {
background: linear-gradient(to right, theme('colors.primary.400'), theme('colors.primary.200'));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.element-quote {
border-left: 4px solid theme('colors.primary.500');
}
.dark .element-quote {
border-left: 4px solid theme('colors.primary.400');
}
.element-divider {
height: 2px;
background: linear-gradient(to right, transparent, theme('colors.primary.500'), transparent);
}
.dark .element-divider {
background: linear-gradient(to right, transparent, theme('colors.primary.400'), transparent);
}
.theme-preview {
width: 24px;
height: 24px;
border-radius: 4px;
}
.theme-preview.default {
background: linear-gradient(135deg, #ffffff 50%, #f3f4f6 50%);
}
.theme-preview.dark {
background: linear-gradient(135deg, #1e293b 50%, #0f172a 50%);
}
.theme-preview.blue {
background: linear-gradient(135deg, #e0f2fe 50%, #bae6fd 50%);
}
.theme-preview.gradient {
background: linear-gradient(135deg, #4f46e5 50%, #7c3aed 50%);
}
.theme-preview.modern {
background: linear-gradient(135deg, #f5f5f5 50%, #e5e5e5 50%);
}
.theme-preview.warm {
background: linear-gradient(135deg, #fef3c7 50%, #fde68a 50%);
}
.element-image-placeholder {
background-color: theme('colors.gray.100');
border: 2px dashed theme('colors.gray.300');
}
.dark .element-image-placeholder {
background-color: theme('colors.gray.800');
border: 2px dashed theme('colors.gray.700');
}
.tabs button.active {
position: relative;
}
.tabs button.active:after {
content: '';
position: absolute;
bottom: -1px;
left: 0;
right: 0;
height: 2px;
background-color: theme('colors.primary.500');
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
.toast {
animation: slideIn 0.3s ease-out, fadeOut 0.3s ease-out 2.7s forwards;
}
@keyframes slideIn {
from {
transform: translateY(20px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes fadeOut {
to {
opacity: 0;
}
}
</style>
</head>
<body class="bg-gray-50 dark:bg-gray-900 transition-colors duration-200">
<div class="fixed inset-0 overflow-y-auto">
<!-- Toast Notification -->
<div id="toast" class="fixed top-4 right-4 z-50 hidden">
<div class="toast bg-green-500 text-white px-4 py-3 rounded-lg shadow-lg flex items-center">
<i class="fas fa-check-circle mr-2"></i>
<span id="toast-message">Copied to clipboard!</span>
</div>
</div>
<!-- Main Container -->
<div class="min-h-screen flex flex-col">
<!-- Header -->
<header class="bg-white dark:bg-gray-800 shadow-sm">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
<div class="flex justify-between items-center">
<div class="flex items-center space-x-4">
<div class="flex items-center">
<i class="fas fa-sliders-h text-primary-500 text-2xl mr-2"></i>
<h1 class="text-xl font-bold text-gray-900 dark:text-white">Slide Builder Pro</h1>
</div>
<div class="hidden md:flex items-center space-x-1 text-sm">
<span class="text-gray-500 dark:text-gray-400">File</span>
<span class="text-gray-500 dark:text-gray-400">Edit</span>
<span class="text-gray-500 dark:text-gray-400">View</span>
<span class="text-gray-500 dark:text-gray-400">Help</span>
</div>
</div>
<div class="flex items-center space-x-4">
<button id="darkModeToggle" class="text-gray-500 dark:text-gray-400 hover:text-primary-500 dark:hover:text-primary-400">
<i class="fas fa-moon dark:hidden"></i>
<i class="fas fa-sun hidden dark:block"></i>
</button>
<button class="bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center">
<i class="fas fa-user-plus mr-2"></i>
<span>Share</span>
</button>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="flex-1">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
<!-- Left Sidebar -->
<div class="lg:col-span-3 space-y-6">
<!-- Elements Panel -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm p-4">
<h2 class="text-lg font-medium text-gray-900 dark:text-white mb-4 flex items-center">
<i class="fas fa-shapes mr-2 text-primary-500"></i>
Elements
</h2>
<div class="grid grid-cols-2 gap-3">
<button onclick="addTitle()" class="bg-gray-50 hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<i class="fas fa-heading text-primary-500 mb-1 text-lg"></i>
Title
</button>
<button onclick="addHeading()" class="bg-gray-50 hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<i class="fas fa-heading text-primary-500 mb-1 text-lg"></i>
Heading
</button>
<button onclick="addText()" class="bg-gray-50 hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<i class="fas fa-paragraph text-primary-500 mb-1 text-lg"></i>
Text
</button>
<button onclick="addList()" class="bg-gray-50 hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<i class="fas fa-list-ul text-primary-500 mb-1 text-lg"></i>
List
</button>
<button onclick="addQuote()" class="bg-gray-50 hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<i class="fas fa-quote-right text-primary-500 mb-1 text-lg"></i>
Quote
</button>
<button onclick="addDivider()" class="bg-gray-50 hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<i class="fas fa-grip-lines text-primary-500 mb-1 text-lg"></i>
Divider
</button>
<button onclick="addImage()" class="bg-gray-50 hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<i class="fas fa-image text-primary-500 mb-1 text-lg"></i>
Image
</button>
<button onclick="addCode()" class="bg-gray-50 hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<i class="fas fa-code text-primary-500 mb-1 text-lg"></i>
Code
</button>
</div>
</div>
<!-- Themes Panel -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm p-4">
<h2 class="text-lg font-medium text-gray-900 dark:text-white mb-4 flex items-center">
<i class="fas fa-palette mr-2 text-primary-500"></i>
Themes
</h2>
<div class="grid grid-cols-3 gap-3">
<button onclick="setTheme('default')" class="bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 border border-gray-200 dark:border-gray-600 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<div class="theme-preview default mb-1"></div>
Default
</button>
<button onclick="setTheme('dark')" class="bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 border border-gray-200 dark:border-gray-600 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<div class="theme-preview dark mb-1"></div>
Dark
</button>
<button onclick="setTheme('blue')" class="bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 border border-gray-200 dark:border-gray-600 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<div class="theme-preview blue mb-1"></div>
Blue
</button>
<button onclick="setTheme('gradient')" class="bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 border border-gray-200 dark:border-gray-600 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<div class="theme-preview gradient mb-1"></div>
Gradient
</button>
<button onclick="setTheme('modern')" class="bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 border border-gray-200 dark:border-gray-600 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<div class="theme-preview modern mb-1"></div>
Modern
</button>
<button onclick="setTheme('warm')" class="bg-white dark:bg-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 border border-gray-200 dark:border-gray-600 p-3 rounded-lg flex flex-col items-center text-sm font-medium transition-colors">
<div class="theme-preview warm mb-1"></div>
Warm
</button>
</div>
</div>
<!-- Export Panel -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm p-4">
<h2 class="text-lg font-medium text-gray-900 dark:text-white mb-4 flex items-center">
<i class="fas fa-file-export mr-2 text-primary-500"></i>
Export
</h2>
<div class="space-y-3">
<button onclick="showExport()" class="w-full bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center justify-center">
<i class="fas fa-file-code mr-2"></i>
Export HTML
</button>
<button onclick="showExportPPT()" class="w-full bg-gray-800 hover:bg-gray-900 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center justify-center">
<i class="fas fa-file-powerpoint mr-2"></i>
Export PPT
</button>
<button onclick="clearAll()" class="w-full bg-danger-500 hover:bg-danger-600 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center justify-center">
<i class="fas fa-trash-alt mr-2"></i>
Clear All
</button>
</div>
</div>
</div>
<!-- Main Editor Area -->
<div class="lg:col-span-6">
<!-- Edit Panel -->
<div id="editPanel" class="bg-white dark:bg-gray-800 rounded-lg shadow-sm mb-6 hidden">
<div class="border-b border-gray-200 dark:border-gray-700 px-4 py-3 flex justify-between items-center">
<h3 class="text-lg font-medium text-gray-900 dark:text-white">Edit Element</h3>
<button onclick="closeEdit()" class="text-gray-400 hover:text-gray-500 dark:hover:text-gray-300">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-4">
<textarea id="editInput" rows="4" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:text-white" placeholder="Edit your content here..."></textarea>
<div class="mt-4">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Alignment</label>
<div class="flex space-x-2">
<button onclick="setAlign('left')" class="flex-1 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 py-2 px-4 rounded-lg flex items-center justify-center">
<i class="fas fa-align-left mr-2"></i> Left
</button>
<button onclick="setAlign('center')" class="flex-1 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 py-2 px-4 rounded-lg flex items-center justify-center">
<i class="fas fa-align-center mr-2"></i> Center
</button>
<button onclick="setAlign('right')" class="flex-1 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 py-2 px-4 rounded-lg flex items-center justify-center">
<i class="fas fa-align-right mr-2"></i> Right
</button>
</div>
</div>
<div class="mt-4">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Text Style</label>
<div class="flex space-x-2">
<button onclick="toggleTextStyle('bold')" class="p-2 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 rounded-lg">
<i class="fas fa-bold"></i>
</button>
<button onclick="toggleTextStyle('italic')" class="p-2 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 rounded-lg">
<i class="fas fa-italic"></i>
</button>
<button onclick="toggleTextStyle('underline')" class="p-2 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 rounded-lg">
<i class="fas fa-underline"></i>
</button>
</div>
</div>
<button onclick="saveEdit()" class="mt-4 w-full bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center justify-center">
<i class="fas fa-save mr-2"></i>
Save Changes
</button>
</div>
</div>
<!-- Preview Area -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm overflow-hidden">
<div class="border-b border-gray-200 dark:border-gray-700 px-4 py-3 flex justify-between items-center">
<h3 class="text-lg font-medium text-gray-900 dark:text-white">Slide Preview</h3>
<div class="flex items-center space-x-2">
<button onclick="zoomOut()" class="p-1 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">
<i class="fas fa-search-minus"></i>
</button>
<span class="text-sm text-gray-500">100%</span>
<button onclick="zoomIn()" class="p-1 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">
<i class="fas fa-search-plus"></i>
</button>
</div>
</div>
<div class="p-6 preview-container bg-white dark:bg-gray-900" id="preview">
<p class="text-center text-gray-400 dark:text-gray-500 py-20">Click elements on the left to add content to your slide</p>
</div>
</div>
</div>
<!-- Right Sidebar -->
<div class="lg:col-span-3 space-y-6">
<!-- Properties Panel -->
<div id="propertiesPanel" class="bg-white dark:bg-gray-800 rounded-lg shadow-sm p-4">
<h2 class="text-lg font-medium text-gray-900 dark:text-white mb-4 flex items-center">
<i class="fas fa-sliders-h mr-2 text-primary-500"></i>
Properties
</h2>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Slide Title</label>
<input type="text" id="slideTitle" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:text-white" placeholder="Presentation Title">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Slide Size</label>
<select id="slideSize" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:text-white">
<option value="16:9">16:9 (Widescreen)</option>
<option value="4:3">4:3 (Standard)</option>
<option value="A4">A4 (Print)</option>
<option value="custom">Custom</option>
</select>
</div>
<div class="grid grid-cols-2 gap-3 hidden" id="customSizeFields">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Width (px)</label>
<input type="number" id="slideWidth" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:text-white" value="1200">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Height (px)</label>
<input type="number" id="slideHeight" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:text-white" value="675">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Background</label>
<div class="flex space-x-2">
<button onclick="setBackground('color')" class="flex-1 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 py-2 px-4 rounded-lg text-sm">
Color
</button>
<button onclick="setBackground('gradient')" class="flex-1 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 py-2 px-4 rounded-lg text-sm">
Gradient
</button>
<button onclick="setBackground('image')" class="flex-1 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 py-2 px-4 rounded-lg text-sm">
Image
</button>
</div>
</div>
<div id="bgColorPicker" class="mt-2">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Background Color</label>
<input type="color" id="backgroundColor" class="w-full h-10 rounded-lg border border-gray-300 dark:border-gray-600" value="#ffffff">
</div>
<div id="bgGradientPicker" class="mt-2 hidden">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Gradient</label>
<select id="gradientType" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:text-white mb-2">
<option value="linear">Linear</option>
<option value="radial">Radial</option>
</select>
<div class="grid grid-cols-2 gap-2 mb-2">
<input type="color" id="gradientColor1" class="w-full h-10 rounded-lg border border-gray-300 dark:border-gray-600" value="#4f46e5">
<input type="color" id="gradientColor2" class="w-full h-10 rounded-lg border border-gray-300 dark:border-gray-600" value="#7c3aed">
</div>
<button onclick="applyGradient()" class="w-full bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg text-sm font-medium">
Apply Gradient
</button>
</div>
</div>
</div>
<!-- History Panel -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm p-4">
<h2 class="text-lg font-medium text-gray-900 dark:text-white mb-4 flex items-center">
<i class="fas fa-history mr-2 text-primary-500"></i>
History
</h2>
<div class="space-y-2">
<div class="flex items-center justify-between p-2 bg-gray-50 dark:bg-gray-700 rounded-lg">
<span class="text-sm text-gray-700 dark:text-gray-300">Added Title</span>
<button class="text-primary-500 hover:text-primary-600 text-sm font-medium">Undo</button>
</div>
<div class="flex items-center justify-between p-2 bg-gray-50 dark:bg-gray-700 rounded-lg">
<span class="text-sm text-gray-700 dark:text-gray-300">Changed Theme</span>
<button class="text-primary-500 hover:text-primary-600 text-sm font-medium">Undo</button>
</div>
<div class="flex items-center justify-between p-2 bg-gray-50 dark:bg-gray-700 rounded-lg">
<span class="text-sm text-gray-700 dark:text-gray-300">Added Image</span>
<button class="text-primary-500 hover:text-primary-600 text-sm font-medium">Undo</button>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- Export Modal -->
<div id="exportModal" class="fixed inset-0 z-50 hidden flex items-center justify-center p-4">
<div class="absolute inset-0 bg-black bg-opacity-50" onclick="closeExport()"></div>
<div class="relative bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-4xl w-full max-h-[90vh] flex flex-col">
<div class="border-b border-gray-200 dark:border-gray-700 px-6 py-4 flex justify-between items-center">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white">Export Slide</h3>
<button onclick="closeExport()" class="text-gray-400 hover:text-gray-500 dark:hover:text-gray-300">
<i class="fas fa-times"></i>
</button>
</div>
<div class="p-6 overflow-auto flex-1">
<div class="tabs flex border-b border-gray-200 dark:border-gray-700 mb-4">
<button onclick="showExportTab('html')" class="px-4 py-2 text-sm font-medium text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 active">HTML</button>
<button onclick="showExportTab('ppt')" class="px-4 py-2 text-sm font-medium text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">PowerPoint</button>
<button onclick="showExportTab('pdf')" class="px-4 py-2 text-sm font-medium text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">PDF</button>
<button onclick="showExportTab('image')" class="px-4 py-2 text-sm font-medium text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">Image</button>
</div>
<div id="htmlExportTab" class="export-tab">
<p class="text-gray-600 dark:text-gray-400 mb-4">Copy the HTML code below or download as a file:</p>
<textarea id="exportCode" class="w-full h-64 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg font-mono text-sm dark:bg-gray-700 dark:text-white" readonly></textarea>
<div class="flex space-x-3 mt-4">
<button onclick="copyCode()" class="flex-1 bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center justify-center">
<i class="fas fa-copy mr-2"></i> Copy to Clipboard
</button>
<button onclick="downloadHTML()" class="flex-1 bg-gray-800 hover:bg-gray-900 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center justify-center">
<i class="fas fa-download mr-2"></i> Download HTML
</button>
</div>
</div>
<div id="pptExportTab" class="export-tab hidden">
<p class="text-gray-600 dark:text-gray-400 mb-4">Export your slide as a PowerPoint presentation:</p>
<div class="bg-gray-50 dark:bg-gray-700 p-4 rounded-lg mb-4">
<div class="flex items-center mb-3">
<input type="checkbox" id="includeNotes" class="h-4 w-4 text-primary-500 focus:ring-primary-500 border-gray-300 rounded dark:bg-gray-600 dark:border-gray-500">
<label for="includeNotes" class="ml-2 block text-sm text-gray-700 dark:text-gray-300">Include speaker notes</label>
</div>
<div class="flex items-center mb-3">
<input type="checkbox" id="includeTemplate" class="h-4 w-4 text-primary-500 focus:ring-primary-500 border-gray-300 rounded dark:bg-gray-600 dark:border-gray-500" checked>
<label for="includeTemplate" class="ml-2 block text-sm text-gray-700 dark:text-gray-300">Include template design</label>
</div>
<div class="flex items-center">
<input type="checkbox" id="optimizeImages" class="h-4 w-4 text-primary-500 focus:ring-primary-500 border-gray-300 rounded dark:bg-gray-600 dark:border-gray-500" checked>
<label for="optimizeImages" class="ml-2 block text-sm text-gray-700 dark:text-gray-300">Optimize images for PPT</label>
</div>
</div>
<button onclick="exportPPT()" class="w-full bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center justify-center">
<i class="fas fa-file-powerpoint mr-2"></i> Export PowerPoint
</button>
</div>
<div id="pdfExportTab" class="export-tab hidden">
<p class="text-gray-600 dark:text-gray-400 mb-4">Export your slide as a PDF document:</p>
<div class="bg-gray-50 dark:bg-gray-700 p-4 rounded-lg mb-4">
<div class="grid grid-cols-2 gap-4 mb-3">
<div>
<label class="block text-sm text-gray-700 dark:text-gray-300 mb-1">Page Size</label>
<select class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-600 dark:text-white">
<option>A4</option>
<option>Letter</option>
<option>A3</option>
</select>
</div>
<div>
<label class="block text-sm text-gray-700 dark:text-gray-300 mb-1">Orientation</label>
<select class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-600 dark:text-white">
<option>Portrait</option>
<option>Landscape</option>
</select>
</div>
</div>
<div class="flex items-center mb-3">
<input type="checkbox" id="includePageNumbers" class="h-4 w-4 text-primary-500 focus:ring-primary-500 border-gray-300 rounded dark:bg-gray-600 dark:border-gray-500">
<label for="includePageNumbers" class="ml-2 block text-sm text-gray-700 dark:text-gray-300">Include page numbers</label>
</div>
<div class="flex items-center">
<input type="checkbox" id="highQuality" class="h-4 w-4 text-primary-500 focus:ring-primary-500 border-gray-300 rounded dark:bg-gray-600 dark:border-gray-500" checked>
<label for="highQuality" class="ml-2 block text-sm text-gray-700 dark:text-gray-300">High quality (slower)</label>
</div>
</div>
<button onclick="exportPDF()" class="w-full bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center justify-center">
<i class="fas fa-file-pdf mr-2"></i> Export PDF
</button>
</div>
<div id="imageExportTab" class="export-tab hidden">
<p class="text-gray-600 dark:text-gray-400 mb-4">Export your slide as an image:</p>
<div class="bg-gray-50 dark:bg-gray-700 p-4 rounded-lg mb-4">
<div class="grid grid-cols-2 gap-4 mb-3">
<div>
<label class="block text-sm text-gray-700 dark:text-gray-300 mb-1">Format</label>
<select class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-600 dark:text-white">
<option>PNG</option>
<option>JPEG</option>
<option>SVG</option>
</select>
</div>
<div>
<label class="block text-sm text-gray-700 dark:text-gray-300 mb-1">Quality</label>
<select class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-600 dark:text-white">
<option>High (100%)</option>
<option>Medium (80%)</option>
<option>Low (60%)</option>
</select>
</div>
</div>
<div class="flex items-center">
<input type="checkbox" id="transparentBg" class="h-4 w-4 text-primary-500 focus:ring-primary-500 border-gray-300 rounded dark:bg-gray-600 dark:border-gray-500">
<label for="transparentBg" class="ml-2 block text-sm text-gray-700 dark:text-gray-300">Transparent background</label>
</div>
</div>
<button onclick="exportImage()" class="w-full bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center justify-center">
<i class="fas fa-image mr-2"></i> Export Image
</button>
</div>
</div>
</div>
</div>
</div>
<script>
// Global variables
let elements = [];
let selectedElement = null;
let elementIdCounter = 0;
let currentTheme = 'default';
let currentBackground = 'color';
let zoomLevel = 1;
let history = [];
let historyIndex = -1;
// Initialize the application
document.addEventListener('DOMContentLoaded', function() {
// Set up dark mode toggle
const darkModeToggle = document.getElementById('darkModeToggle');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (prefersDark) {
document.documentElement.classList.add('dark');
localStorage.setItem('darkMode', 'enabled');
}
darkModeToggle.addEventListener('click', function() {
document.documentElement.classList.toggle('dark');
if (document.documentElement.classList.contains('dark')) {
localStorage.setItem('darkMode', 'enabled');
} else {
localStorage.setItem('darkMode', 'disabled');
}
});
// Set up slide size selector
const slideSize = document.getElementById('slideSize');
slideSize.addEventListener('change', function() {
if (this.value === 'custom') {
document.getElementById('customSizeFields').classList.remove('hidden');
} else {
document.getElementById('customSizeFields').classList.add('hidden');
}
});
// Set up background type selector
document.getElementById('backgroundColor').addEventListener('input', function() {
document.getElementById('preview').style.backgroundColor = this.value;
});
// Initialize with a default title
addTitle();
});
// Add Title
function addTitle() {
const element = {
id: elementIdCounter++,
type: 'title',
content: 'Your Presentation Title',
align: 'center',
styles: {}
};
elements.push(element);
saveHistory();
renderPreview();
}
// Add Heading
function addHeading() {
const element = {
id: elementIdCounter++,
type: 'heading',
content: 'Section Heading',
align: 'left',
styles: {}
};
elements.push(element);
saveHistory();
renderPreview();
}
// Add Text
function addText() {
const element = {
id: elementIdCounter++,
type: 'text',
content: 'Your paragraph text goes here. Click to edit and add your own content.',
align: 'left',
styles: {}
};
elements.push(element);
saveHistory();
renderPreview();
}
// Add List
function addList() {
const element = {
id: elementIdCounter++,
type: 'list',
content: 'First item\nSecond item\nThird item',
align: 'left',
styles: {}
};
elements.push(element);
saveHistory();
renderPreview();
}
// Add Quote
function addQuote() {
const element = {
id: elementIdCounter++,
type: 'quote',
content: 'The only way to do great work is to love what you do. - Steve Jobs',
align: 'center',
styles: {}
};
elements.push(element);
saveHistory();
renderPreview();
}
// Add Divider
function addDivider() {
const element = {
id: elementIdCounter++,
type: 'divider',
align: 'center',
styles: {}
};
elements.push(element);
saveHistory();
renderPreview();
}
// Add Image
function addImage() {
const element = {
id: elementIdCounter++,
type: 'image',
content: 'https://via.placeholder.com/800x400?text=Click+to+upload+image',
align: 'center',
styles: {
width: '100%',
maxWidth: '800px'
}
};
elements.push(element);
saveHistory();
renderPreview();
}
// Add Code
function addCode() {
const element = {
id: elementIdCounter++,
type: 'code',
content: '// Your code here\nfunction helloWorld() {\n console.log("Hello, world!");\n}',
align: 'left',
styles: {},
language: 'javascript'
};
elements.push(element);
saveHistory();
renderPreview();
}
// Clear All
function clearAll() {
if (confirm('Are you sure you want to clear all elements? This cannot be undone.')) {
elements = [];
saveHistory();
renderPreview();
}
}
// Set Theme
function setTheme(theme) {
currentTheme = theme;
const preview = document.getElementById('preview');
// Remove all theme classes
preview.classList.remove('default', 'dark', 'blue', 'gradient', 'modern', 'warm');
// Add the selected theme class
if (theme !== 'default') {
preview.classList.add(theme);
}
// Update background based on theme
switch(theme) {
case 'dark':
preview.style.backgroundColor = '#1a1a1a';
break;
case 'blue':
preview.style.backgroundColor = '#e0f2fe';
break;
case 'gradient':
preview.style.background = 'linear-gradient(135deg, #4f46e5, #7c3aed)';
break;
case 'modern':
preview.style.backgroundColor = '#f5f5f5';
break;
case 'warm':
preview.style.backgroundColor = '#fef3c7';
break;
default:
preview.style.backgroundColor = '#ffffff';
}
saveHistory();
renderPreview();
}
// Set Background
function setBackground(type) {
currentBackground = type;
const bgColorPicker = document.getElementById('bgColorPicker');
const bgGradientPicker = document.getElementById('bgGradientPicker');
if (type === 'color') {
bgColorPicker.classList.remove('hidden');
bgGradientPicker.classList.add('hidden');
} else if (type === 'gradient') {
bgColorPicker.classList.add('hidden');
bgGradientPicker.classList.remove('hidden');
} else {
bgColorPicker.classList.add('hidden');
bgGradientPicker.classList.add('hidden');
// Handle image background
}
}
// Apply Gradient
function applyGradient() {
const gradientType = document.getElementById('gradientType').value;
const color1 = document.getElementById('gradientColor1').value;
const color2 = document.getElementById('gradientColor2').value;
if (gradientType === 'linear') {
document.getElementById('preview').style.background = `linear-gradient(135deg, ${color1}, ${color2})`;
} else {
document.getElementById('preview').style.background = `radial-gradient(circle, ${color1}, ${color2})`;
}
saveHistory();
}
// Render Preview
function renderPreview() {
const preview = document.getElementById('preview');
if (elements.length === 0) {
preview.innerHTML = '<p class="text-center text-gray-400 dark:text-gray-500 py-20">Click elements on the left to add content to your slide</p>';
return;
}
preview.innerHTML = '';
elements.forEach(element => {
const div = document.createElement('div');
div.className = `slide-element bg-white dark:bg-gray-800 rounded-lg p-4 mb-4 shadow-sm relative ${element.id === (selectedElement?.id) ? 'selected' : ''}`;
div.onclick = (e) => {
if (!e.target.closest('.element-controls button')) {
selectElement(element.id);
}
};
// Add controls
const controls = document.createElement('div');
controls.className = 'element-controls absolute top-2 right-2 flex space-x-1';
controls.innerHTML = `
<button class="bg-gray-200 hover:bg-gray-300 dark:bg-gray-600 dark:hover:bg-gray-500 text-gray-800 dark:text-gray-200 p-1 rounded" onclick="event.stopPropagation(); moveUp(${element.id})" title="Move up">
<i class="fas fa-arrow-up text-xs"></i>
</button>
<button class="bg-gray-200 hover:bg-gray-300 dark:bg-gray-600 dark:hover:bg-gray-500 text-gray-800 dark:text-gray-200 p-1 rounded" onclick="event.stopPropagation(); moveDown(${element.id})" title="Move down">
<i class="fas fa-arrow-down text-xs"></i>
</button>
<button class="bg-gray-200 hover:bg-gray-300 dark:bg-gray-600 dark:hover:bg-gray-500 text-gray-800 dark:text-gray-200 p-1 rounded" onclick="event.stopPropagation(); deleteElement(${element.id})" title="Delete">
<i class="fas fa-trash text-xs"></i>
</button>
`;
div.appendChild(controls);
// Add content wrapper with alignment
const contentWrapper = document.createElement('div');
contentWrapper.className = `text-${element.align}`;
switch(element.type) {
case 'title':
contentWrapper.innerHTML = `<h1 class="element-title text-4xl md:text-5xl font-bold mb-4">${element.content}</h1>`;
break;
case 'heading':
contentWrapper.innerHTML = `<h2 class="element-heading text-2xl md:text-3xl font-semibold mb-3 text-gray-800 dark:text-gray-200">${element.content}</h2>`;
break;
case 'text':
contentWrapper.innerHTML = `<p class="element-text text-base md:text-lg text-gray-700 dark:text-gray-300 mb-2">${element.content.replace(/\n/g, '<br>')}</p>`;
break;
case 'list':
const items = element.content.split('\n').filter(item => item.trim() !== '').map(item => `<li class="text-base md:text-lg text-gray-700 dark:text-gray-300 mb-1">${item}</li>`).join('');
contentWrapper.innerHTML = `<ul class="element-list space-y-1">${items}</ul>`;
break;
case 'quote':
contentWrapper.innerHTML = `<blockquote class="element-quote text-xl md:text-2xl text-gray-700 dark:text-gray-300 my-4 px-6 py-4 rounded-lg bg-gray-50 dark:bg-gray-700">${element.content}</blockquote>`;
break;
case 'divider':
contentWrapper.innerHTML = `<div class="element-divider my-6 w-full"></div>`;
break;
case 'image':
contentWrapper.innerHTML = `
<div class="flex justify-${element.align}">
<div class="element-image-placeholder rounded-lg overflow-hidden" style="width: ${element.styles.width || '100%'}; max-width: ${element.styles.maxWidth || '800px'};">
<img src="${element.content}" alt="Slide image" class="w-full h-auto">
</div>
</div>
`;
break;
case 'code':
contentWrapper.innerHTML = `
<div class="flex justify-${element.align}">
<pre class="bg-gray-800 text-gray-100 p-4 rounded-lg overflow-x-auto text-sm md:text-base" style="width: ${element.styles.width || '100%'};">
<code>${element.content}</code>
</pre>
</div>
`;
break;
}
// Apply custom styles
for (const [property, value] of Object.entries(element.styles)) {
if (property === 'fontWeight' && value === 'bold') {
contentWrapper.querySelector('h1, h2, p, li, blockquote, pre')?.classList.add('font-bold');
} else if (property === 'fontStyle' && value === 'italic') {
contentWrapper.querySelector('h1, h2, p, li, blockquote, pre')?.classList.add('italic');
} else if (property === 'textDecoration' && value === 'underline') {
contentWrapper.querySelector('h1, h2, p, li, blockquote, pre')?.classList.add('underline');
} else {
contentWrapper.querySelector('h1, h2, p, ul, li, blockquote, div, pre')?.style.setProperty(property, value);
}
}
div.appendChild(contentWrapper);
preview.appendChild(div);
});
}
// Select Element
function selectElement(id) {
selectedElement = elements.find(el => el.id === id);
// Remove previous selection
document.querySelectorAll('.slide-element').forEach(el => {
el.classList.remove('selected');
});
// Add selection to clicked element
event.currentTarget.classList.add('selected');
// Show edit panel for editable types
if (selectedElement.type !== 'divider') {
document.getElementById('editPanel').classList.remove('hidden');
document.getElementById('editInput').value = selectedElement.content;
} else {
document.getElementById('editPanel').classList.add('hidden');
}
}
// Close Edit
function closeEdit() {
document.getElementById('editPanel').classList.add('hidden');
document.querySelectorAll('.slide-element').forEach(el => {
el.classList.remove('selected');
});
selectedElement = null;
}
// Save Edit
function saveEdit() {
if (selectedElement) {
selectedElement.content = document.getElementById('editInput').value;
saveHistory();
renderPreview();
closeEdit();
}
}
// Set Alignment
function setAlign(alignment) {
if (selectedElement) {
selectedElement.align = alignment;
saveHistory();
renderPreview();
selectElement(selectedElement.id);
}
}
// Toggle Text Style
function toggleTextStyle(style) {
if (selectedElement) {
switch(style) {
case 'bold':
if (selectedElement.styles.fontWeight === 'bold') {
delete selectedElement.styles.fontWeight;
} else {
selectedElement.styles.fontWeight = 'bold';
}
break;
case 'italic':
if (selectedElement.styles.fontStyle === 'italic') {
delete selectedElement.styles.fontStyle;
} else {
selectedElement.styles.fontStyle = 'italic';
}
break;
case 'underline':
if (selectedElement.styles.textDecoration === 'underline') {
delete selectedElement.styles.textDecoration;
} else {
selectedElement.styles.textDecoration = 'underline';
}
break;
}
saveHistory();
renderPreview();
selectElement(selectedElement.id);
}
}
// Delete Element
function deleteElement(id) {
elements = elements.filter(el => el.id !== id);
saveHistory();
renderPreview();
}
// Move Up
function moveUp(id) {
const index = elements.findIndex(el => el.id === id);
if (index > 0) {
[elements[index], elements[index - 1]] = [elements[index - 1], elements[index]];
saveHistory();
renderPreview();
selectElement(id);
}
}
// Move Down
function moveDown(id) {
const index = elements.findIndex(el => el.id === id);
if (index < elements.length - 1) {
[elements[index], elements[index + 1]] = [elements[index + 1], elements[index]];
saveHistory();
renderPreview();
selectElement(id);
}
}
// Zoom In
function zoomIn() {
if (zoomLevel < 1.5) {
zoomLevel += 0.1;
document.getElementById('preview').style.transform = `scale(${zoomLevel})`;
document.querySelector('#preview').parentElement.style.overflow = 'auto';
updateZoomDisplay();
}
}
// Zoom Out
function zoomOut() {
if (zoomLevel > 0.7) {
zoomLevel -= 0.1;
document.getElementById('preview').style.transform = `scale(${zoomLevel})`;
if (zoomLevel === 1) {
document.querySelector('#preview').parentElement.style.overflow = 'hidden';
}
updateZoomDisplay();
}
}
// Update Zoom Display
function updateZoomDisplay() {
document.querySelector('#preview').parentElement.querySelector('span').textContent = `${Math.round(zoomLevel * 100)}%`;
}
// Show Export
function showExport() {
const html = generateHTML();
document.getElementById('exportCode').value = html;
document.getElementById('exportModal').classList.remove('hidden');
showExportTab('html');
}
// Show Export PPT
function showExportPPT() {
const html = generateHTML();
document.getElementById('exportCode').value = html;
document.getElementById('exportModal').classList.remove('hidden');
showExportTab('ppt');
}
// Close Export
function closeExport() {
document.getElementById('exportModal').classList.add('hidden');
}
// Show Export Tab
function showExportTab(tabName) {
document.querySelectorAll('.export-tab').forEach(tab => {
tab.classList.add('hidden');
});
document.getElementById(`${tabName}ExportTab`).classList.remove('hidden');
document.querySelectorAll('.tabs button').forEach(button => {
button.classList.remove('active');
});
event.currentTarget.classList.add('active');
}
// Generate HTML
function generateHTML() {
let content = '';
elements.forEach(element => {
const alignStyle = element.align !== 'left' ? ` style="text-align: ${element.align};"` : '';
switch(element.type) {
case 'title':
content += `<h1${alignStyle} class="text-5xl font-bold mb-8" style="color: ${currentTheme === 'dark' ? 'white' : '#1e293b'}; background: linear-gradient(to right, ${currentTheme === 'dark' ? '#38bdf8, #7dd3fc' : '#0ea5e9, #38bdf8'}); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">${element.content}</h1>\n`;
break;
case 'heading':
content += `<h2${alignStyle} class="text-3xl font-semibold mb-6" style="color: ${currentTheme === 'dark' ? '#f1f5f9' : '#1e293b'};">${element.content}</h2>\n`;
break;
case 'text':
content += `<p${alignStyle} class="text-lg mb-4" style="color: ${currentTheme === 'dark' ? '#cbd5e1' : '#475569'};">${element.content.replace(/\n/g, '<br>')}</p>\n`;
break;
case 'list':
const items = element.content.split('\n').filter(item => item.trim() !== '').map(item => `<li class="mb-2" style="color: ${currentTheme === 'dark' ? '#cbd5e1' : '#475569'};">${item}</li>`).join('\n');
content += `<ul${alignStyle} class="list-disc pl-6 mb-6">\n${items}\n</ul>\n`;
break;
case 'quote':
content += `<blockquote${alignStyle} class="text-xl italic px-8 py-4 my-6 border-l-4" style="border-color: ${currentTheme === 'dark' ? '#7dd3fc' : '#0ea5e9'}; color: ${currentTheme === 'dark' ? '#e2e8f0' : '#334155'}; background-color: ${currentTheme === 'dark' ? 'rgba(30, 41, 59, 0.5)' : 'rgba(226, 232, 240, 0.5)'};">${element.content}</blockquote>\n`;
break;
case 'divider':
content += `<div${alignStyle} class="my-8"><hr style="border: none; height: 2px; background: linear-gradient(to right, transparent, ${currentTheme === 'dark' ? '#7dd3fc' : '#0ea5e9'}, transparent);"></div>\n`;
break;
case 'image':
content += `<div${alignStyle}><img src="${element.content}" alt="Slide image" style="max-width: 100%; height: auto; border-radius: 0.5rem;"></div>\n`;
break;
case 'code':
content += `<div${alignStyle}><pre class="bg-gray-800 text-gray-100 p-4 rounded-lg overflow-x-auto"><code>${element.content}</code></pre></div>\n`;
break;
}
});
const bgColor = currentTheme === 'dark' ? '#1a1a1a' :
currentTheme === 'blue' ? '#e0f2fe' :
currentTheme === 'gradient' ? 'linear-gradient(135deg, #4f46e5, #7c3aed)' :
currentTheme === 'modern' ? '#f5f5f5' :
currentTheme === 'warm' ? '#fef3c7' : '#ffffff';
const textColor = currentTheme === 'dark' ? 'white' : '#1e293b';
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${document.getElementById('slideTitle').value || 'My Presentation Slide'}</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
background: ${bgColor};
color: ${textColor};
padding: 2rem;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.slide {
background: ${currentTheme === 'dark' ? '#0f172a' : 'white'};
padding: 4rem;
border-radius: 1rem;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
max-width: 1200px;
width: 100%;
min-height: 600px;
}
</style>
</head>
<body>
<div class="slide">
${content}
</div>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=resumesearch/slide-builder" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>