Spaces:
Running
Running
π³ 12/03 - 06:48 - add new slide layout: comparison table
Browse files- editor.html +153 -0
editor.html
CHANGED
|
@@ -145,6 +145,10 @@
|
|
| 145 |
<i data-lucide="layout-grid" class="w-4 h-4"></i>
|
| 146 |
Grid
|
| 147 |
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
</div>
|
| 149 |
|
| 150 |
<!-- View Toggle -->
|
|
@@ -359,6 +363,14 @@
|
|
| 359 |
this.slides[this.currentSlide].imageTitle = 'Image Slide';
|
| 360 |
this.slides[this.currentSlide].image = 'technology';
|
| 361 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 362 |
|
| 363 |
this.renderEditor();
|
| 364 |
this.updatePreview();
|
|
@@ -584,6 +596,51 @@
|
|
| 584 |
</div>
|
| 585 |
</div>
|
| 586 |
`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 587 |
}
|
| 588 |
|
| 589 |
html += `</div>`;
|
|
@@ -596,6 +653,40 @@
|
|
| 596 |
this.updatePreview();
|
| 597 |
}
|
| 598 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 599 |
validateJSON(jsonString) {
|
| 600 |
// Skip validation if paused (but still track for manual validation)
|
| 601 |
if (this.validationPaused) {
|
|
@@ -742,6 +833,36 @@
|
|
| 742 |
</div>
|
| 743 |
</div>
|
| 744 |
`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 745 |
}
|
| 746 |
|
| 747 |
preview.innerHTML = content;
|
|
@@ -826,6 +947,38 @@
|
|
| 826 |
</div>
|
| 827 |
</div>
|
| 828 |
`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 829 |
}
|
| 830 |
|
| 831 |
container.innerHTML = content;
|
|
|
|
| 145 |
<i data-lucide="layout-grid" class="w-4 h-4"></i>
|
| 146 |
Grid
|
| 147 |
</button>
|
| 148 |
+
<button onclick="editor.setLayout('comparison')" class="tool-btn px-3 py-1.5 rounded-md text-sm font-medium text-gray-700 flex items-center gap-1" data-layout="comparison">
|
| 149 |
+
<i data-lucide="table" class="w-4 h-4"></i>
|
| 150 |
+
Compare
|
| 151 |
+
</button>
|
| 152 |
</div>
|
| 153 |
|
| 154 |
<!-- View Toggle -->
|
|
|
|
| 363 |
this.slides[this.currentSlide].imageTitle = 'Image Slide';
|
| 364 |
this.slides[this.currentSlide].image = 'technology';
|
| 365 |
}
|
| 366 |
+
if (layout === 'comparison' && !this.slides[this.currentSlide].columns) {
|
| 367 |
+
this.slides[this.currentSlide].columns = ['Feature', 'Our Solution', 'Competitors'];
|
| 368 |
+
this.slides[this.currentSlide].rows = [
|
| 369 |
+
{ feature: 'Performance', col1: 'β Superior', col2: 'β Limited' },
|
| 370 |
+
{ feature: 'Pricing', col1: 'β Affordable', col2: 'β Expensive' },
|
| 371 |
+
{ feature: 'Support', col1: 'β 24/7', col2: 'β Business hours' }
|
| 372 |
+
];
|
| 373 |
+
}
|
| 374 |
|
| 375 |
this.renderEditor();
|
| 376 |
this.updatePreview();
|
|
|
|
| 596 |
</div>
|
| 597 |
</div>
|
| 598 |
`;
|
| 599 |
+
} else if (slide.layout === 'comparison') {
|
| 600 |
+
html += `
|
| 601 |
+
<div class="col-span-2">
|
| 602 |
+
<label class="block text-sm font-medium text-gray-700 mb-1">Subtitle</label>
|
| 603 |
+
<input type="text" value="${slide.subtitle || ''}"
|
| 604 |
+
oninput="editor.updateField('subtitle', this.value)"
|
| 605 |
+
class="editor-input w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none">
|
| 606 |
+
</div>
|
| 607 |
+
<div class="col-span-2">
|
| 608 |
+
<label class="block text-sm font-medium text-gray-700 mb-2">Column Headers</label>
|
| 609 |
+
<div class="grid grid-cols-3 gap-3">
|
| 610 |
+
${(slide.columns || ['Feature', 'Our Solution', 'Competitors']).map((col, i) => `
|
| 611 |
+
<input type="text" value="${col}"
|
| 612 |
+
oninput="editor.updateColumn(${i}, this.value)"
|
| 613 |
+
class="editor-input w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 outline-none">
|
| 614 |
+
`).join('')}
|
| 615 |
+
</div>
|
| 616 |
+
</div>
|
| 617 |
+
<div class="col-span-2">
|
| 618 |
+
<div class="flex items-center justify-between mb-2">
|
| 619 |
+
<label class="block text-sm font-medium text-gray-700">Comparison Rows</label>
|
| 620 |
+
<button onclick="editor.addComparisonRow()" class="text-sm text-indigo-600 hover:text-indigo-700 font-medium">+ Add Row</button>
|
| 621 |
+
</div>
|
| 622 |
+
<div class="space-y-2">
|
| 623 |
+
${(slide.rows || []).map((row, i) => `
|
| 624 |
+
<div class="grid grid-cols-3 gap-3 p-3 bg-gray-50 rounded-lg border border-gray-200">
|
| 625 |
+
<input type="text" value="${row.feature}" placeholder="Feature name"
|
| 626 |
+
oninput="editor.updateComparisonRow(${i}, 'feature', this.value)"
|
| 627 |
+
class="editor-input w-full px-3 py-2 text-sm border border-gray-300 rounded focus:ring-2 focus:ring-indigo-500 outline-none">
|
| 628 |
+
<input type="text" value="${row.col1}" placeholder="Option 1"
|
| 629 |
+
oninput="editor.updateComparisonRow(${i}, 'col1', this.value)"
|
| 630 |
+
class="editor-input w-full px-3 py-2 text-sm border border-gray-300 rounded focus:ring-2 focus:ring-indigo-500 outline-none">
|
| 631 |
+
<div class="flex items-center gap-2">
|
| 632 |
+
<input type="text" value="${row.col2}" placeholder="Option 2"
|
| 633 |
+
oninput="editor.updateComparisonRow(${i}, 'col2', this.value)"
|
| 634 |
+
class="editor-input flex-1 px-3 py-2 text-sm border border-gray-300 rounded focus:ring-2 focus:ring-indigo-500 outline-none">
|
| 635 |
+
<button onclick="editor.removeComparisonRow(${i})" class="text-red-500 hover:text-red-700 p-1">
|
| 636 |
+
<i data-lucide="x" class="w-4 h-4"></i>
|
| 637 |
+
</button>
|
| 638 |
+
</div>
|
| 639 |
+
</div>
|
| 640 |
+
`).join('')}
|
| 641 |
+
</div>
|
| 642 |
+
</div>
|
| 643 |
+
`;
|
| 644 |
}
|
| 645 |
|
| 646 |
html += `</div>`;
|
|
|
|
| 653 |
this.updatePreview();
|
| 654 |
}
|
| 655 |
|
| 656 |
+
updateColumn(index, value) {
|
| 657 |
+
if (!this.slides[this.currentSlide].columns) {
|
| 658 |
+
this.slides[this.currentSlide].columns = ['Feature', 'Our Solution', 'Competitors'];
|
| 659 |
+
}
|
| 660 |
+
this.slides[this.currentSlide].columns[index] = value;
|
| 661 |
+
this.updatePreview();
|
| 662 |
+
}
|
| 663 |
+
|
| 664 |
+
updateComparisonRow(index, field, value) {
|
| 665 |
+
if (!this.slides[this.currentSlide].rows) {
|
| 666 |
+
this.slides[this.currentSlide].rows = [];
|
| 667 |
+
}
|
| 668 |
+
if (!this.slides[this.currentSlide].rows[index]) {
|
| 669 |
+
this.slides[this.currentSlide].rows[index] = { feature: '', col1: '', col2: '' };
|
| 670 |
+
}
|
| 671 |
+
this.slides[this.currentSlide].rows[index][field] = value;
|
| 672 |
+
this.updatePreview();
|
| 673 |
+
}
|
| 674 |
+
|
| 675 |
+
addComparisonRow() {
|
| 676 |
+
if (!this.slides[this.currentSlide].rows) {
|
| 677 |
+
this.slides[this.currentSlide].rows = [];
|
| 678 |
+
}
|
| 679 |
+
this.slides[this.currentSlide].rows.push({ feature: 'New Feature', col1: 'β Yes', col2: 'β No' });
|
| 680 |
+
this.renderEditor();
|
| 681 |
+
this.updatePreview();
|
| 682 |
+
}
|
| 683 |
+
|
| 684 |
+
removeComparisonRow(index) {
|
| 685 |
+
this.slides[this.currentSlide].rows.splice(index, 1);
|
| 686 |
+
this.renderEditor();
|
| 687 |
+
this.updatePreview();
|
| 688 |
+
}
|
| 689 |
+
|
| 690 |
validateJSON(jsonString) {
|
| 691 |
// Skip validation if paused (but still track for manual validation)
|
| 692 |
if (this.validationPaused) {
|
|
|
|
| 833 |
</div>
|
| 834 |
</div>
|
| 835 |
`;
|
| 836 |
+
} else if (slide.layout === 'comparison') {
|
| 837 |
+
const cols = slide.columns || ['Feature', 'Our Solution', 'Competitors'];
|
| 838 |
+
content = `
|
| 839 |
+
<div class="w-full h-full p-6 bg-white flex flex-col justify-center">
|
| 840 |
+
<div class="text-center space-y-1 mb-4">
|
| 841 |
+
<h2 class="text-xl font-bold text-gray-900">${slide.title}</h2>
|
| 842 |
+
${slide.subtitle ? `<p class="text-xs text-gray-600">${slide.subtitle}</p>` : ''}
|
| 843 |
+
</div>
|
| 844 |
+
<div class="overflow-hidden rounded-lg border border-gray-200">
|
| 845 |
+
<table class="w-full text-xs">
|
| 846 |
+
<thead>
|
| 847 |
+
<tr class="bg-indigo-50">
|
| 848 |
+
<th class="px-3 py-2 text-left font-semibold text-gray-900 border-b border-indigo-100">${cols[0]}</th>
|
| 849 |
+
<th class="px-3 py-2 text-center font-semibold text-indigo-700 border-b border-indigo-100">${cols[1]}</th>
|
| 850 |
+
<th class="px-3 py-2 text-center font-semibold text-gray-600 border-b border-indigo-100">${cols[2]}</th>
|
| 851 |
+
</tr>
|
| 852 |
+
</thead>
|
| 853 |
+
<tbody>
|
| 854 |
+
${(slide.rows || []).map((row, i) => `
|
| 855 |
+
<tr class="${i % 2 === 0 ? 'bg-white' : 'bg-gray-50'}">
|
| 856 |
+
<td class="px-3 py-2 font-medium text-gray-900 border-b border-gray-100">${row.feature}</td>
|
| 857 |
+
<td class="px-3 py-2 text-center text-indigo-600 border-b border-gray-100">${row.col1}</td>
|
| 858 |
+
<td class="px-3 py-2 text-center text-gray-500 border-b border-gray-100">${row.col2}</td>
|
| 859 |
+
</tr>
|
| 860 |
+
`).join('')}
|
| 861 |
+
</tbody>
|
| 862 |
+
</table>
|
| 863 |
+
</div>
|
| 864 |
+
</div>
|
| 865 |
+
`;
|
| 866 |
}
|
| 867 |
|
| 868 |
preview.innerHTML = content;
|
|
|
|
| 947 |
</div>
|
| 948 |
</div>
|
| 949 |
`;
|
| 950 |
+
} else if (slide.layout === 'comparison') {
|
| 951 |
+
const cols = slide.columns || ['Feature', 'Our Solution', 'Competitors'];
|
| 952 |
+
content = `
|
| 953 |
+
<div class="w-full h-full p-12 bg-white flex flex-col justify-center">
|
| 954 |
+
<div class="text-center space-y-2 mb-8">
|
| 955 |
+
<h2 class="text-4xl font-bold text-gray-900">${slide.title}</h2>
|
| 956 |
+
${slide.subtitle ? `<p class="text-xl text-gray-600">${slide.subtitle}</p>` : ''}
|
| 957 |
+
</div>
|
| 958 |
+
<div class="max-w-4xl mx-auto w-full">
|
| 959 |
+
<div class="overflow-hidden rounded-2xl border border-gray-200 shadow-sm">
|
| 960 |
+
<table class="w-full">
|
| 961 |
+
<thead>
|
| 962 |
+
<tr class="bg-indigo-50">
|
| 963 |
+
<th class="px-6 py-4 text-left text-sm font-semibold text-gray-900 border-b border-indigo-100 w-1/3">${cols[0]}</th>
|
| 964 |
+
<th class="px-6 py-4 text-center text-sm font-bold text-indigo-700 border-b border-indigo-100 w-1/3">${cols[1]}</th>
|
| 965 |
+
<th class="px-6 py-4 text-center text-sm font-semibold text-gray-600 border-b border-indigo-100 w-1/3">${cols[2]}</th>
|
| 966 |
+
</tr>
|
| 967 |
+
</thead>
|
| 968 |
+
<tbody>
|
| 969 |
+
${(slide.rows || []).map((row, i) => `
|
| 970 |
+
<tr class="${i % 2 === 0 ? 'bg-white' : 'bg-gray-50'} hover:bg-indigo-50/30 transition-colors">
|
| 971 |
+
<td class="px-6 py-4 text-sm font-medium text-gray-900 border-b border-gray-100">${row.feature}</td>
|
| 972 |
+
<td class="px-6 py-4 text-center text-sm font-semibold text-indigo-600 border-b border-gray-100">${row.col1}</td>
|
| 973 |
+
<td class="px-6 py-4 text-center text-sm text-gray-500 border-b border-gray-100">${row.col2}</td>
|
| 974 |
+
</tr>
|
| 975 |
+
`).join('')}
|
| 976 |
+
</tbody>
|
| 977 |
+
</table>
|
| 978 |
+
</div>
|
| 979 |
+
</div>
|
| 980 |
+
</div>
|
| 981 |
+
`;
|
| 982 |
}
|
| 983 |
|
| 984 |
container.innerHTML = content;
|