lumina-slides 9.0.6 → 9.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/dist/lumina-slides.js +6451 -6424
- package/dist/lumina-slides.umd.cjs +192 -196
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/layouts/LayoutFeatures.vue +3 -1
- package/src/components/layouts/LayoutSteps.vue +3 -1
- package/src/components/site/SiteDocs.vue +54 -0
- package/src/components/studio/StudioEmbedRoot.vue +5 -2
- package/src/components/studio/StudioJsonEditor.vue +10 -3
- package/src/components/studio/StudioToolbar.vue +10 -9
- package/src/utils/prepareDeckForExport.ts +47 -0
|
@@ -83,6 +83,7 @@
|
|
|
83
83
|
<script setup lang="ts">
|
|
84
84
|
import { ref, watch, computed } from 'vue';
|
|
85
85
|
import { useEditor } from '../../composables/useEditor';
|
|
86
|
+
import { prepareDeckForExport } from '../../utils/prepareDeckForExport';
|
|
86
87
|
|
|
87
88
|
const props = defineProps<{
|
|
88
89
|
isOpen: boolean;
|
|
@@ -97,15 +98,21 @@ const error = ref<string | null>(null);
|
|
|
97
98
|
const isDirty = ref(false);
|
|
98
99
|
const textareaRef = ref<HTMLTextAreaElement | null>(null);
|
|
99
100
|
|
|
100
|
-
// Get initial content
|
|
101
|
+
// Get initial content (same format as export: ids added, dragKey removed)
|
|
101
102
|
const refreshContent = () => {
|
|
102
103
|
try {
|
|
104
|
+
const deck = editor.store.state.deck;
|
|
105
|
+
if (!deck) {
|
|
106
|
+
jsonContent.value = mode.value === 'deck' ? '{}' : '';
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const prepared = prepareDeckForExport(deck);
|
|
103
110
|
if (mode.value === 'slide') {
|
|
104
111
|
const index = editor.store.state.currentIndex;
|
|
105
|
-
const slide =
|
|
112
|
+
const slide = prepared.slides?.[index];
|
|
106
113
|
jsonContent.value = slide ? JSON.stringify(slide, null, 4) : '';
|
|
107
114
|
} else {
|
|
108
|
-
jsonContent.value = JSON.stringify(
|
|
115
|
+
jsonContent.value = JSON.stringify(prepared, null, 4);
|
|
109
116
|
}
|
|
110
117
|
error.value = null;
|
|
111
118
|
isDirty.value = false;
|
|
@@ -83,12 +83,13 @@
|
|
|
83
83
|
</template>
|
|
84
84
|
|
|
85
85
|
<script setup lang="ts">
|
|
86
|
-
import { computed, ref, onMounted, watch
|
|
87
|
-
import {
|
|
86
|
+
import { computed, inject, ref, onMounted, watch } from 'vue';
|
|
87
|
+
import { routeLocationKey } from 'vue-router';
|
|
88
88
|
import { useEditor } from '../../composables/useEditor';
|
|
89
89
|
import { useAuth } from '../../composables/useAuth';
|
|
90
90
|
import { saveDeck, updateDeck } from '../../utils/firebase';
|
|
91
91
|
import type { Deck } from '../../core/types';
|
|
92
|
+
import { prepareDeckForExport } from '../../utils/prepareDeckForExport';
|
|
92
93
|
// import SaveSuccessModal from './SaveSuccessModal.vue';
|
|
93
94
|
import StudioJsonEditor from './StudioJsonEditor.vue';
|
|
94
95
|
|
|
@@ -96,7 +97,7 @@ const props = withDefaults(defineProps<{ embedMode?: boolean }>(), { embedMode:
|
|
|
96
97
|
const emit = defineEmits<{ save: [deck: Deck] }>();
|
|
97
98
|
|
|
98
99
|
const editor = useEditor();
|
|
99
|
-
const route =
|
|
100
|
+
const route = inject(routeLocationKey) ?? { params: {} as Record<string, string | string[]> };
|
|
100
101
|
const { user } = useAuth();
|
|
101
102
|
const isSaving = ref(false);
|
|
102
103
|
// const showSaveModal = ref(false);
|
|
@@ -160,10 +161,10 @@ const addElement = (type: string) => {
|
|
|
160
161
|
};
|
|
161
162
|
|
|
162
163
|
const emitSave = () => {
|
|
163
|
-
const rawDeck =
|
|
164
|
+
const rawDeck = editor.store.state.deck;
|
|
164
165
|
if (!rawDeck) return;
|
|
165
166
|
isSaving.value = true;
|
|
166
|
-
const deckCopy =
|
|
167
|
+
const deckCopy = prepareDeckForExport(rawDeck);
|
|
167
168
|
emit('save', deckCopy);
|
|
168
169
|
isSaving.value = false;
|
|
169
170
|
};
|
|
@@ -171,14 +172,13 @@ const emitSave = () => {
|
|
|
171
172
|
const saveToFirestore = async () => {
|
|
172
173
|
isSaving.value = true;
|
|
173
174
|
try {
|
|
174
|
-
|
|
175
|
-
const rawDeck = toRaw(editor.store.state.deck);
|
|
175
|
+
const rawDeck = editor.store.state.deck;
|
|
176
176
|
if (!rawDeck) {
|
|
177
177
|
alert('No deck found to save.');
|
|
178
178
|
return;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
const deckToSave =
|
|
181
|
+
const deckToSave = prepareDeckForExport(rawDeck);
|
|
182
182
|
|
|
183
183
|
|
|
184
184
|
|
|
@@ -226,7 +226,8 @@ const exportDeck = () => {
|
|
|
226
226
|
const deck = editor.store.state.deck;
|
|
227
227
|
if (!deck) return;
|
|
228
228
|
|
|
229
|
-
const
|
|
229
|
+
const deckForExport = prepareDeckForExport(deck);
|
|
230
|
+
const json = JSON.stringify(deckForExport, null, 2);
|
|
230
231
|
const blob = new Blob([json], { type: 'application/json' });
|
|
231
232
|
const url = URL.createObjectURL(blob);
|
|
232
233
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prepares a deck for export: strips internal dragKey and adds explicit element ids.
|
|
3
|
+
* Used by Studio export, save, and JSON view.
|
|
4
|
+
* - slide.ids: path → id for every element
|
|
5
|
+
* - each element object that can have an id (features[i], timeline[i], elements[i], nodes[i], etc.) gets id set
|
|
6
|
+
*/
|
|
7
|
+
import { toRaw } from 'vue';
|
|
8
|
+
import type { Deck, BaseSlideData } from '../core/types';
|
|
9
|
+
import { getElementPaths, resolveId, pathToKey, getValueAt } from '../core/elementResolver';
|
|
10
|
+
|
|
11
|
+
/** Recursively remove all dragKey properties from an object (mutates in place). */
|
|
12
|
+
export function stripDragKeys(obj: unknown): void {
|
|
13
|
+
if (obj == null || typeof obj !== 'object') return;
|
|
14
|
+
if (Array.isArray(obj)) {
|
|
15
|
+
obj.forEach(stripDragKeys);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
delete (obj as Record<string, unknown>)['dragKey'];
|
|
19
|
+
Object.values(obj as Record<string, unknown>).forEach(stripDragKeys);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Prepare deck for export: clone, strip dragKey, add slide.ids, and set id on each element object. */
|
|
23
|
+
export function prepareDeckForExport(deck: Deck): Deck {
|
|
24
|
+
const clone = JSON.parse(JSON.stringify(toRaw(deck))) as Deck;
|
|
25
|
+
stripDragKeys(clone);
|
|
26
|
+
const slides = clone.slides ?? [];
|
|
27
|
+
slides.forEach((slide: BaseSlideData, slideIndex: number) => {
|
|
28
|
+
const paths = getElementPaths(slide);
|
|
29
|
+
if (paths.length === 0) return;
|
|
30
|
+
const slideAny = slide as { ids?: Record<string, string> };
|
|
31
|
+
if (!slideAny.ids) slideAny.ids = {};
|
|
32
|
+
paths.forEach((path) => {
|
|
33
|
+
const pathKey = pathToKey(path);
|
|
34
|
+
const resolvedId = resolveId(slide, slideIndex, path);
|
|
35
|
+
slideAny.ids![pathKey] = resolvedId;
|
|
36
|
+
|
|
37
|
+
// Set id on the element object when it's an object (e.g. features[0], elements[0], nodes[0])
|
|
38
|
+
if (path.length > 0 && path[0] !== 'slide') {
|
|
39
|
+
const value = getValueAt(slide, path);
|
|
40
|
+
if (value != null && typeof value === 'object' && !Array.isArray(value)) {
|
|
41
|
+
(value as Record<string, string>).id = resolvedId;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
return clone;
|
|
47
|
+
}
|