diff --git a/Procfile b/Procfile
new file mode 100644
index 0000000..9cca0c1
--- /dev/null
+++ b/Procfile
@@ -0,0 +1 @@
+web: npm run build && npm preview
\ No newline at end of file
diff --git a/public/themes-manifest.json b/public/themes-manifest.json
index 1a6fd53..1a35452 100644
--- a/public/themes-manifest.json
+++ b/public/themes-manifest.json
@@ -15,5 +15,5 @@
"hasMasterSlide": true
}
},
- "generated": "2025-09-12T14:15:01.593Z"
+ "generated": "2025-09-24T21:37:00.344Z"
}
\ No newline at end of file
diff --git a/src/components/presentations/PresentationEditor.tsx b/src/components/presentations/PresentationEditor.tsx
index b1b8788..5fc75b4 100644
--- a/src/components/presentations/PresentationEditor.tsx
+++ b/src/components/presentations/PresentationEditor.tsx
@@ -40,7 +40,7 @@ export const PresentationEditor: React.FC = () => {
confirmDelete
} = useDialog();
- const { duplicateSlide, deleteSlide, saving } = useSlideOperations({
+ const { duplicateSlide, deleteSlide, reorderSlides, saving } = useSlideOperations({
presentation,
presentationId: presentationId || '',
onPresentationUpdate: setPresentation,
@@ -176,6 +176,7 @@ export const PresentationEditor: React.FC = () => {
onEditSlide={(slideId) => navigate(`/presentations/${presentationId}/slide/${slideId}/edit`)}
onDuplicateSlide={duplicateSlide}
onDeleteSlide={deleteSlide}
+ onReorderSlides={reorderSlides}
/>
diff --git a/src/components/presentations/SlidesSidebar.tsx b/src/components/presentations/SlidesSidebar.tsx
index 0395033..8e56a54 100644
--- a/src/components/presentations/SlidesSidebar.tsx
+++ b/src/components/presentations/SlidesSidebar.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useState } from 'react';
import type { Slide } from '../../types/presentation.ts';
import { SlideThumbnail } from './shared/SlideThumbnail.tsx';
import './SlidesSidebar.css';
@@ -13,6 +13,7 @@ interface SlidesSidebarProps {
onEditSlide: (slideId: string) => void;
onDuplicateSlide: (index: number) => void;
onDeleteSlide: (index: number) => void;
+ onReorderSlides: (fromIndex: number, toIndex: number) => void;
}
export const SlidesSidebar: React.FC
= ({
@@ -24,8 +25,58 @@ export const SlidesSidebar: React.FC = ({
onAddSlide,
onEditSlide,
onDuplicateSlide,
- onDeleteSlide
+ onDeleteSlide,
+ onReorderSlides
}) => {
+ const [draggedIndex, setDraggedIndex] = useState(null);
+ const [dragOverIndex, setDragOverIndex] = useState(null);
+
+ const handleDragStart = (e: React.DragEvent, index: number) => {
+ if (saving) return;
+
+ setDraggedIndex(index);
+ e.dataTransfer.effectAllowed = 'move';
+ e.dataTransfer.setData('text/plain', index.toString());
+
+ // Add drag image
+ if (e.currentTarget instanceof HTMLElement) {
+ e.currentTarget.style.opacity = '0.5';
+ }
+ };
+
+ const handleDragEnd = (e: React.DragEvent) => {
+ if (e.currentTarget instanceof HTMLElement) {
+ e.currentTarget.style.opacity = '';
+ }
+ setDraggedIndex(null);
+ setDragOverIndex(null);
+ };
+
+ const handleDragOver = (e: React.DragEvent, index: number) => {
+ e.preventDefault();
+ e.dataTransfer.dropEffect = 'move';
+
+ if (draggedIndex !== null && index !== draggedIndex) {
+ setDragOverIndex(index);
+ }
+ };
+
+ const handleDragLeave = () => {
+ setDragOverIndex(null);
+ };
+
+ const handleDrop = (e: React.DragEvent, toIndex: number) => {
+ e.preventDefault();
+
+ const fromIndex = draggedIndex;
+ if (fromIndex !== null && fromIndex !== toIndex && !saving) {
+ onReorderSlides(fromIndex, toIndex);
+ }
+
+ setDraggedIndex(null);
+ setDragOverIndex(null);
+ };
+
return (