lumina-slides 8.9.4 → 9.0.0

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.
Files changed (119) hide show
  1. package/LUMINA_LLM_EXAMPLES.json +234 -0
  2. package/README.md +18 -18
  3. package/dist/lumina-slides.js +13207 -12659
  4. package/dist/lumina-slides.umd.cjs +215 -215
  5. package/dist/style.css +1 -1
  6. package/package.json +5 -4
  7. package/src/App.vue +16 -0
  8. package/src/animation/index.ts +11 -0
  9. package/src/animation/registry.ts +126 -0
  10. package/src/animation/stagger.ts +95 -0
  11. package/src/animation/types.ts +53 -0
  12. package/src/components/LandingPage.vue +229 -0
  13. package/src/components/LuminaDeck.vue +224 -0
  14. package/src/components/LuminaSpeakerNotes.vue +701 -0
  15. package/src/components/base/BaseSlide.vue +122 -0
  16. package/src/components/base/LuminaElement.vue +67 -0
  17. package/src/components/base/VideoPlayer.vue +204 -0
  18. package/src/components/layouts/LayoutAuto.vue +71 -0
  19. package/src/components/layouts/LayoutChart.vue +287 -0
  20. package/src/components/layouts/LayoutCustom.vue +92 -0
  21. package/src/components/layouts/LayoutDiagram.vue +253 -0
  22. package/src/components/layouts/LayoutFeatures.vue +121 -0
  23. package/src/components/layouts/LayoutFlex.vue +172 -0
  24. package/src/components/layouts/LayoutFree.vue +62 -0
  25. package/src/components/layouts/LayoutHalf.vue +127 -0
  26. package/src/components/layouts/LayoutStatement.vue +74 -0
  27. package/src/components/layouts/LayoutSteps.vue +106 -0
  28. package/src/components/layouts/LayoutTimeline.vue +104 -0
  29. package/src/components/layouts/LayoutVideo.vue +41 -0
  30. package/src/components/parts/FlexBullets.vue +45 -0
  31. package/src/components/parts/FlexButton.vue +132 -0
  32. package/src/components/parts/FlexImage.vue +54 -0
  33. package/src/components/parts/FlexOrdered.vue +44 -0
  34. package/src/components/parts/FlexSpacer.vue +13 -0
  35. package/src/components/parts/FlexStepper.vue +59 -0
  36. package/src/components/parts/FlexText.vue +29 -0
  37. package/src/components/parts/FlexTimeline.vue +67 -0
  38. package/src/components/parts/FlexTitle.vue +39 -0
  39. package/src/components/parts/LuminaBackground.vue +100 -0
  40. package/src/components/site/LivePreview.vue +101 -0
  41. package/src/components/site/SiteApi.vue +301 -0
  42. package/src/components/site/SiteDashboard.vue +604 -0
  43. package/src/components/site/SiteDocs.vue +3267 -0
  44. package/src/components/site/SiteExamples.vue +65 -0
  45. package/src/components/site/SiteFooter.vue +6 -0
  46. package/src/components/site/SiteHome.vue +362 -0
  47. package/src/components/site/SiteNavBar.vue +122 -0
  48. package/src/components/site/SitePlayground.vue +389 -0
  49. package/src/components/site/SitePromptBuilder.vue +266 -0
  50. package/src/components/site/SiteUserMenu.vue +90 -0
  51. package/src/components/studio/ActionEditor.vue +108 -0
  52. package/src/components/studio/ArrayEditor.vue +124 -0
  53. package/src/components/studio/CollapsibleSection.vue +33 -0
  54. package/src/components/studio/ColorField.vue +22 -0
  55. package/src/components/studio/EditorCanvas.vue +326 -0
  56. package/src/components/studio/EditorLayoutFeatures.vue +18 -0
  57. package/src/components/studio/EditorLayoutFixed.vue +46 -0
  58. package/src/components/studio/EditorLayoutFlex.vue +133 -0
  59. package/src/components/studio/EditorLayoutHalf.vue +18 -0
  60. package/src/components/studio/EditorLayoutStatement.vue +18 -0
  61. package/src/components/studio/EditorLayoutSteps.vue +18 -0
  62. package/src/components/studio/EditorLayoutTimeline.vue +18 -0
  63. package/src/components/studio/EditorNode.vue +89 -0
  64. package/src/components/studio/FieldEditor.vue +133 -0
  65. package/src/components/studio/IconPicker.vue +109 -0
  66. package/src/components/studio/LayerItem.vue +117 -0
  67. package/src/components/studio/LuminaStudio.vue +30 -0
  68. package/src/components/studio/SaveSuccessModal.vue +138 -0
  69. package/src/components/studio/SlideNavigator.vue +373 -0
  70. package/src/components/studio/SliderField.vue +44 -0
  71. package/src/components/studio/StudioInspector.vue +595 -0
  72. package/src/components/studio/StudioJsonEditor.vue +191 -0
  73. package/src/components/studio/StudioLayers.vue +145 -0
  74. package/src/components/studio/StudioSettings.vue +514 -0
  75. package/src/components/studio/StudioSidebar.vue +29 -0
  76. package/src/components/studio/StudioToolbar.vue +222 -0
  77. package/src/components/studio/fieldLabels.ts +224 -0
  78. package/src/components/studio/inspectors/DiagramEdgeEditor.vue +77 -0
  79. package/src/components/studio/inspectors/DiagramNodeEditor.vue +117 -0
  80. package/src/components/studio/nodes/StudioDiagramNode.vue +138 -0
  81. package/src/composables/useAuth.ts +87 -0
  82. package/src/composables/useEditor.ts +224 -0
  83. package/src/composables/useElementState.ts +81 -0
  84. package/src/composables/useFlexLayout.ts +122 -0
  85. package/src/composables/useKeyboard.ts +45 -0
  86. package/src/composables/useLumina.ts +32 -0
  87. package/src/composables/useStudio.ts +87 -0
  88. package/src/composables/useSwipeNav.ts +53 -0
  89. package/src/composables/useTransition.ts +373 -0
  90. package/src/core/Lumina.ts +819 -0
  91. package/src/core/animationConfig.ts +251 -0
  92. package/src/core/compression.ts +34 -0
  93. package/src/core/elementController.ts +170 -0
  94. package/src/core/elementId.ts +27 -0
  95. package/src/core/elementResolver.ts +207 -0
  96. package/src/core/events.ts +53 -0
  97. package/src/core/fonts.ts +100 -0
  98. package/src/core/presets.ts +231 -0
  99. package/src/core/prompts.ts +272 -0
  100. package/src/core/schema.ts +478 -0
  101. package/src/core/speaker-channel.ts +250 -0
  102. package/src/core/store.ts +461 -0
  103. package/src/core/theme.ts +666 -0
  104. package/src/core/types.ts +1611 -0
  105. package/src/directives/vStudio.ts +45 -0
  106. package/src/index.ts +175 -0
  107. package/src/main.ts +17 -0
  108. package/src/router/index.ts +92 -0
  109. package/src/style/main.css +462 -0
  110. package/src/utils/deep.ts +127 -0
  111. package/src/utils/firebase.ts +184 -0
  112. package/src/utils/streaming.ts +134 -0
  113. package/src/views/DashboardView.vue +32 -0
  114. package/src/views/DeckView.vue +289 -0
  115. package/src/views/HomeView.vue +17 -0
  116. package/src/views/SiteLayout.vue +21 -0
  117. package/src/views/StudioView.vue +61 -0
  118. package/src/vite-env.d.ts +6 -0
  119. package/IMPLEMENTATION.md +0 -418
@@ -0,0 +1,191 @@
1
+ <template>
2
+ <div v-if="isOpen" class="fixed inset-0 z-[60] flex items-center justify-center p-4">
3
+ <!-- Backdrop -->
4
+ <div class="absolute inset-0 bg-black/80 backdrop-blur-md transition-opacity" @click="$emit('close')"></div>
5
+
6
+ <!-- Modal -->
7
+ <div
8
+ class="relative w-full max-w-4xl h-[80vh] bg-[#1a1a1a] border border-[#333] rounded-2xl shadow-2xl flex flex-col overflow-hidden transform transition-all animate-in fade-in zoom-in-95 duration-200">
9
+
10
+ <!-- Header -->
11
+ <div class="px-6 py-4 border-b border-[#333] flex items-center justify-between bg-[#222]">
12
+ <div class="flex items-center gap-4">
13
+ <div class="flex items-center gap-2">
14
+ <i class="ph-thin ph-code text-blue-400 text-lg"></i>
15
+ <h2 class="text-lg font-bold text-white tracking-wide">JSON EDITOR</h2>
16
+ </div>
17
+
18
+ <!-- Mode Switcher -->
19
+ <div class="flex bg-black/40 p-1 rounded-lg border border-white/5">
20
+ <button @click="mode = 'slide'"
21
+ :class="['px-3 py-1 text-[10px] font-bold uppercase tracking-wider rounded-md transition-all',
22
+ mode === 'slide' ? 'bg-blue-600 text-white shadow-lg' : 'text-white/40 hover:text-white']">
23
+ Current Slide
24
+ </button>
25
+ <button @click="mode = 'deck'"
26
+ :class="['px-3 py-1 text-[10px] font-bold uppercase tracking-wider rounded-md transition-all',
27
+ mode === 'deck' ? 'bg-blue-600 text-white shadow-lg' : 'text-white/40 hover:text-white']">
28
+ Full Deck
29
+ </button>
30
+ </div>
31
+ </div>
32
+
33
+ <div class="flex items-center gap-3">
34
+ <span v-if="error"
35
+ class="text-red-400 text-[10px] font-mono animate-pulse bg-red-400/10 px-2 py-1 rounded">
36
+ <i class="ph-thin ph-warning mr-1"></i> {{ error }}
37
+ </span>
38
+ <button @click="$emit('close')" class="text-white/40 hover:text-white transition-colors p-1">
39
+ <i class="ph-thin ph-x text-xl"></i>
40
+ </button>
41
+ </div>
42
+ </div>
43
+
44
+ <!-- Content Area -->
45
+ <div class="flex-1 flex overflow-hidden relative">
46
+ <!-- Line Numbers (Simulated) -->
47
+ <div
48
+ class="w-12 bg-black/20 border-r border-[#333] flex flex-col items-center py-4 text-[10px] font-mono text-white/20 select-none">
49
+ <div v-for="n in lineCount" :key="n" class="leading-relaxed h-5">{{ n }}</div>
50
+ </div>
51
+
52
+ <!-- Textarea -->
53
+ <div class="flex-1 relative group">
54
+ <textarea ref="textareaRef" v-model="jsonContent" spellcheck="false"
55
+ class="w-full h-full bg-transparent p-4 text-[13px] font-mono text-blue-100/90 leading-relaxed outline-none resize-none selection:bg-blue-500/30"
56
+ @input="validateJson" placeholder="{ ... }"></textarea>
57
+ </div>
58
+ </div>
59
+
60
+ <!-- Footer -->
61
+ <div class="px-6 py-4 border-t border-[#333] flex items-center justify-between bg-[#222]">
62
+ <div class="text-[10px] text-white/30 font-mono">
63
+ <i class="ph-thin ph-info mr-1"></i>
64
+ Changes are applied to the local store only. Remember to SAVE to the cloud.
65
+ </div>
66
+
67
+ <div class="flex items-center gap-3">
68
+ <button @click="$emit('close')"
69
+ class="px-5 py-2 text-sm font-medium text-white/60 hover:text-white hover:bg-white/5 rounded-lg transition-all">
70
+ Cancel
71
+ </button>
72
+ <button @click="handleApply" :disabled="!!error || !isDirty"
73
+ class="px-6 py-2 bg-blue-600 hover:bg-blue-500 disabled:bg-blue-900 disabled:opacity-50 text-white text-sm font-bold rounded-lg shadow-lg shadow-blue-900/20 transition-all flex items-center gap-2 active:scale-95">
74
+ <i class="ph-thin ph-check"></i>
75
+ APPLY CHANGES
76
+ </button>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ </div>
81
+ </template>
82
+
83
+ <script setup lang="ts">
84
+ import { ref, watch, computed } from 'vue';
85
+ import { useEditor } from '../../composables/useEditor';
86
+
87
+ const props = defineProps<{
88
+ isOpen: boolean;
89
+ }>();
90
+
91
+ const emit = defineEmits(['close']);
92
+
93
+ const editor = useEditor();
94
+ const mode = ref<'slide' | 'deck'>('slide');
95
+ const jsonContent = ref('');
96
+ const error = ref<string | null>(null);
97
+ const isDirty = ref(false);
98
+ const textareaRef = ref<HTMLTextAreaElement | null>(null);
99
+
100
+ // Get initial content
101
+ const refreshContent = () => {
102
+ try {
103
+ if (mode.value === 'slide') {
104
+ const index = editor.store.state.currentIndex;
105
+ const slide = editor.store.state.deck?.slides[index];
106
+ jsonContent.value = slide ? JSON.stringify(slide, null, 4) : '';
107
+ } else {
108
+ jsonContent.value = JSON.stringify(editor.store.state.deck, null, 4);
109
+ }
110
+ error.value = null;
111
+ isDirty.value = false;
112
+ } catch (e) {
113
+ console.error('Failed to stringify JSON', e);
114
+ }
115
+ };
116
+
117
+ // Auto-refresh when opening or switching mode
118
+ watch(() => props.isOpen, (open) => {
119
+ if (open) refreshContent();
120
+ });
121
+
122
+ watch(mode, refreshContent);
123
+
124
+ const lineCount = computed(() => {
125
+ return jsonContent.value.split('\n').length;
126
+ });
127
+
128
+ const validateJson = () => {
129
+ isDirty.value = true;
130
+ try {
131
+ JSON.parse(jsonContent.value);
132
+ error.value = null;
133
+ } catch (e: any) {
134
+ error.value = e.message;
135
+ }
136
+ };
137
+
138
+ const handleApply = () => {
139
+ try {
140
+ const parsed = JSON.parse(jsonContent.value);
141
+
142
+ if (mode.value === 'slide') {
143
+ const index = editor.store.state.currentIndex;
144
+ editor.store.updateNode(`slides.${index}`, parsed);
145
+ } else {
146
+ editor.store.updateNode('', parsed);
147
+ }
148
+
149
+ // editor.commit(); // Handled by watch
150
+ isDirty.value = false;
151
+ emit('close');
152
+ } catch (e: any) {
153
+ error.value = "Invalid JSON: " + e.message;
154
+ }
155
+ };
156
+ </script>
157
+
158
+ <style scoped>
159
+ .animate-in {
160
+ animation: enter 0.25s cubic-bezier(0.16, 1, 0.3, 1);
161
+ }
162
+
163
+ @keyframes enter {
164
+ from {
165
+ opacity: 0;
166
+ transform: translateY(10px) scale(0.98);
167
+ }
168
+
169
+ to {
170
+ opacity: 1;
171
+ transform: translateY(0) scale(1);
172
+ }
173
+ }
174
+
175
+ textarea::-webkit-scrollbar {
176
+ width: 8px;
177
+ }
178
+
179
+ textarea::-webkit-scrollbar-track {
180
+ background: transparent;
181
+ }
182
+
183
+ textarea::-webkit-scrollbar-thumb {
184
+ background: #333;
185
+ border-radius: 4px;
186
+ }
187
+
188
+ textarea::-webkit-scrollbar-thumb:hover {
189
+ background: #444;
190
+ }
191
+ </style>
@@ -0,0 +1,145 @@
1
+ <template>
2
+ <div class="flex flex-col h-full text-xs">
3
+ <!-- Header -->
4
+ <div
5
+ class="px-3 py-2 font-bold text-white/50 uppercase tracking-wider border-b border-[#333] flex items-center justify-between">
6
+ <span>Elements</span>
7
+ <span class="text-white/30 font-mono">Slide {{ currentSlideIndex + 1 }}</span>
8
+ </div>
9
+
10
+ <!-- Layer Tree -->
11
+ <div class="flex-1 overflow-y-auto p-2">
12
+ <template v-if="currentSlide">
13
+ <LayerItem :data="currentSlide" :path="`slides.${currentSlideIndex}`" />
14
+ </template>
15
+ <div v-else class="text-white/30 italic text-center mt-4">
16
+ No slide selected
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { computed, ref } from 'vue';
24
+ import { useEditor } from '../../composables/useEditor';
25
+ import LayerItem from './LayerItem.vue';
26
+
27
+ const editor = useEditor();
28
+
29
+ const slides = computed(() => editor.store.state.deck?.slides || []);
30
+ const totalSlides = computed(() => slides.value.length);
31
+ const currentSlideIndex = computed(() => editor.store.state.currentIndex);
32
+ const currentSlide = computed(() => slides.value[currentSlideIndex.value]);
33
+
34
+ const selectedLayout = ref('flex');
35
+
36
+ const availableLayouts = [
37
+ { value: 'flex', label: 'Flex (Free Layout)' },
38
+ { value: 'statement', label: 'Statement' },
39
+ { value: 'half', label: 'Half (Image + Content)' },
40
+ { value: 'features', label: 'Features Grid' },
41
+ { value: 'timeline', label: 'Timeline' },
42
+ { value: 'steps', label: 'Steps' },
43
+ ];
44
+
45
+ const goToSlide = (index: number) => {
46
+ editor.store.goto(index);
47
+ };
48
+
49
+ // CORRECT templates matching actual type definitions
50
+ const slideTemplates: Record<string, any> = {
51
+ 'flex': {
52
+ type: 'flex',
53
+ direction: 'horizontal',
54
+ gap: 'md',
55
+ padding: 'lg',
56
+ elements: [
57
+ {
58
+ type: 'content',
59
+ size: 'half',
60
+ halign: 'left',
61
+ valign: 'center',
62
+ elements: [
63
+ { type: 'title', text: 'New Slide', size: 'xl' },
64
+ { type: 'text', text: 'Start editing your content here.' }
65
+ ]
66
+ },
67
+ {
68
+ type: 'image',
69
+ size: 'half',
70
+ src: 'https://images.unsplash.com/photo-1557683316-973673baf926?w=800',
71
+ alt: 'Placeholder image',
72
+ fill: true,
73
+ rounded: 'lg'
74
+ }
75
+ ]
76
+ },
77
+ 'statement': {
78
+ type: 'statement',
79
+ tag: 'Tagline',
80
+ title: 'Big Statement Here',
81
+ subtitle: 'Supporting description text goes below the main statement.'
82
+ },
83
+ 'half': {
84
+ type: 'half',
85
+ imageSide: 'right',
86
+ image: 'https://images.unsplash.com/photo-1557683316-973673baf926?w=800',
87
+ tag: 'Category',
88
+ title: 'Split Layout Title',
89
+ paragraphs: [
90
+ 'First paragraph of content.',
91
+ 'Second paragraph with more details.'
92
+ ],
93
+ cta: 'Learn More'
94
+ },
95
+ 'features': {
96
+ type: 'features',
97
+ title: 'Key Features',
98
+ description: 'Discover what makes us different.',
99
+ features: [
100
+ { icon: 'star', title: 'Feature One', desc: 'Description of the first feature.' },
101
+ { icon: 'rocket', title: 'Feature Two', desc: 'Description of the second feature.' },
102
+ { icon: 'lightning', title: 'Feature Three', desc: 'Description of the third feature.' }
103
+ ]
104
+ },
105
+ 'timeline': {
106
+ type: 'timeline',
107
+ title: 'Our Journey',
108
+ subtitle: 'Key milestones in our history.',
109
+ timeline: [
110
+ { date: '2020', title: 'Founded', description: 'Company was established.' },
111
+ { date: '2022', title: 'Growth', description: 'Expanded to new markets.' },
112
+ { date: '2024', title: 'Today', description: 'Serving customers worldwide.' }
113
+ ]
114
+ },
115
+ 'steps': {
116
+ type: 'steps',
117
+ title: 'How It Works',
118
+ subtitle: 'Simple steps to get started.',
119
+ steps: [
120
+ { step: '1', title: 'Step One', description: 'First thing to do.' },
121
+ { step: '2', title: 'Step Two', description: 'Second thing to do.' },
122
+ { step: '3', title: 'Step Three', description: 'Final step.' }
123
+ ]
124
+ }
125
+ };
126
+
127
+ const addSlide = () => {
128
+ const template = slideTemplates[selectedLayout.value] || slideTemplates['flex'];
129
+ const newSlide = JSON.parse(JSON.stringify(template));
130
+
131
+ // Get current slides array and add new slide
132
+ const currentSlides = [...(editor.store.state.deck?.slides || [])];
133
+ currentSlides.push(newSlide);
134
+
135
+ // Update via patchDeck for proper reactivity
136
+ editor.store.patchDeck({ slides: currentSlides });
137
+ editor.commit();
138
+
139
+ // Navigate to the new slide after a small delay
140
+ const newIndex = currentSlides.length - 1;
141
+ setTimeout(() => {
142
+ editor.store.goto(newIndex);
143
+ }, 50);
144
+ };
145
+ </script>