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,224 @@
1
+ <template>
2
+ <div class="h-full w-full relative flex flex-col text-white overflow-hidden" data-lumina-root
3
+ style="background-color: var(--lumina-colors-background, #030303); color: var(--lumina-colors-text, #ffffff);">
4
+
5
+ <!-- DYNAMIC BACKGROUND -->
6
+ <LuminaBackground :orb-color="slide?.meta?.orbColor" :orb-pos="orbPosition" />
7
+
8
+ <!-- INSPECTOR TOGGLE -->
9
+ <div v-if="isDebug" class="absolute top-0 right-0 p-6 z-50 flex gap-4 pointer-events-auto">
10
+ <button @click="ui.showJson = !ui.showJson"
11
+ class="w-8 h-8 rounded-full glass-panel flex items-center justify-center text-gray-400 hover:text-white transition"
12
+ title="JSON"><i class="ph-thin ph-code text-xs"></i></button>
13
+ </div>
14
+
15
+ <!-- JSON INSPECTOR -->
16
+ <transition name="fade">
17
+ <div v-if="ui.showJson" class="fixed inset-0 z-[100] flex justify-end" @click.self="ui.showJson = false">
18
+ <!-- Backdrop -->
19
+ <div class="absolute inset-0 bg-black/20 backdrop-blur-sm transition-opacity"
20
+ @click="ui.showJson = false">
21
+ </div>
22
+
23
+ <!-- Panel -->
24
+ <div
25
+ class="relative h-full w-full md:w-[450px] bg-[#0a0a0a]/95 border-l border-white/10 shadow-2xl overflow-auto text-left flex flex-col transform transition-transform duration-300">
26
+
27
+ <!-- Header -->
28
+ <div class="p-6 pb-2 border-b border-white/5 flex items-center justify-between shrink-0">
29
+ <span class="text-xs font-bold text-gray-400 uppercase tracking-widest">Slide Data</span>
30
+ <button @click="ui.showJson = false"
31
+ class="w-8 h-8 rounded-full bg-white/5 hover:bg-white/10 flex items-center justify-center text-white/50 hover:text-white transition">
32
+ <i class="ph-thin ph-x"></i>
33
+ </button>
34
+ </div>
35
+
36
+ <!-- Content -->
37
+ <div class="p-6">
38
+ <pre
39
+ class="text-[10px] font-mono text-green-400 whitespace-pre-wrap">{{ JSON.stringify(slide, null, 2) }}</pre>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ </transition>
44
+
45
+ <!-- VIEWPORT -->
46
+ <main ref="viewport" class="flex-1 min-h-0 w-full relative overflow-y-auto overflow-x-hidden z-10 scroll-smooth touch-pan-y pb-24 md:pb-0"
47
+ @touchstart="onTouchStart" @touchend="onTouchEnd">
48
+ <transition :css="false" @leave="onLeave" @enter="onEnter" mode="out-in">
49
+ <component v-if="currentSlideComponent" :is="currentSlideComponent" :key="index" :data="slide"
50
+ :slide-index="index" @action="handleAction" class="min-h-full w-full">
51
+ </component>
52
+ </transition>
53
+ </main>
54
+
55
+ <!-- NAV BAR: fixed on mobile so controls stay visible (container can exceed 100vh); absolute on md+ -->
56
+ <div v-if="uiOptions?.visible"
57
+ class="fixed md:absolute bottom-0 left-0 right-0 w-full z-40 px-8 py-6 pb-[max(1.5rem,env(safe-area-inset-bottom))] bg-gradient-to-t from-black/60 via-black/20 to-transparent flex justify-between items-end pointer-events-none">
58
+ <div v-if="uiOptions?.showSlideCount" class="pointer-events-auto text-left">
59
+ <h2 class="text-[10px] font-bold tracking-[0.2em] uppercase mb-1"
60
+ :style="{ color: 'var(--lumina-color-muted)' }">{{ deckTitle }}</h2>
61
+ <div class="flex items-center gap-2 text-sm font-mono"
62
+ :style="{ color: 'var(--lumina-color-text-safe, var(--lumina-color-text))', opacity: 0.8 }">
63
+ <span>{{ (index + 1).toString().padStart(2, '0') }}</span>
64
+ <div v-if="uiOptions?.showProgressBar" class="h-px w-8"
65
+ :style="{ backgroundColor: 'var(--lumina-color-text-safe, var(--lumina-color-text))', opacity: 0.3 }">
66
+ </div>
67
+ <span>{{ total.toString().padStart(2, '0') }}</span>
68
+ </div>
69
+ </div>
70
+ <!-- Spacer if count hidden -->
71
+ <div v-else class="flex-1"></div>
72
+
73
+ <div v-if="uiOptions?.showControls" class="pointer-events-auto flex gap-3">
74
+ <!-- Notes Toggle (Sync Window) -->
75
+ <button v-if="slide?.notes" @click="openSpeakerNotes"
76
+ class="w-12 h-12 rounded-full glass-panel hover:bg-white/10 flex items-center justify-center transition active:scale-95"
77
+ title="Open Speaker View">
78
+ <i class="ph-thin ph-presentation text-sm text-gray-400 hover:text-white"></i>
79
+ </button>
80
+
81
+ <button @click="prev"
82
+ :class="['w-12 h-12 rounded-full glass-panel hover:bg-white/10 flex items-center justify-center transition active:scale-95', (!hasPrev || !isNavEnabled) ? 'opacity-30 cursor-not-allowed' : '']"
83
+ :disabled="!hasPrev || !isNavEnabled"><i class="ph-thin ph-arrow-left"></i></button>
84
+ <button @click="next"
85
+ :class="['w-12 h-12 rounded-full bg-white text-black hover:scale-105 flex items-center justify-center transition shadow-lg active:scale-95', (!hasNext || !isNavEnabled) ? 'opacity-30 cursor-not-allowed' : '']"
86
+ :disabled="!hasNext || !isNavEnabled"><i class="ph-thin ph-arrow-right"></i></button>
87
+ </div>
88
+ </div>
89
+ </div>
90
+ </template>
91
+
92
+ <script setup lang="ts">
93
+ import { ref, computed, watch, inject } from 'vue';
94
+ import { useLumina } from '../composables/useLumina';
95
+ import { useKeyboard } from '../composables/useKeyboard';
96
+ import { useSwipeNav } from '../composables/useSwipeNav';
97
+ import { bus } from '../core/events';
98
+ import gsap from 'gsap';
99
+ import { StoreKey } from '../core/store';
100
+ import { resolveTransitionConfig } from '../core/animationConfig';
101
+ import LuminaBackground from './parts/LuminaBackground.vue';
102
+
103
+ // Composable Integration
104
+ const { slide, index, total, next, prev, options } = useLumina();
105
+
106
+ const viewport = ref<HTMLElement | null>(null);
107
+
108
+ const store = inject(StoreKey)!;
109
+
110
+ const hasNext = computed(() => store.hasNext());
111
+ const hasPrev = computed(() => store.hasPrev());
112
+ const deckTitle = computed(() => store.state.deck?.meta?.title);
113
+ const uiOptions = computed(() => store.state.options.ui);
114
+ const isNavEnabled = computed(() => store.state.options.navigation);
115
+
116
+ useKeyboard();
117
+ const { onTouchStart, onTouchEnd } = useSwipeNav();
118
+
119
+ // Random orb position state
120
+ const currentOrbPosition = ref({ top: '-20%', left: '-10%' });
121
+
122
+ // Function to generate random orb position
123
+ const generateRandomOrbPosition = () => {
124
+ // Generate true random positions within a safe range to keep the 80vw orb visible
125
+ // Range: -20% to 60% provides good coverage without losing the orb
126
+ const randomRange = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1) + min);
127
+
128
+ return {
129
+ top: `${randomRange(-25, 65)}%`,
130
+ left: `${randomRange(-25, 65)}%`
131
+ };
132
+ };
133
+
134
+ // Watch for slide index changes to update orb position
135
+ watch(index, (newIndex, oldIndex) => {
136
+ // First slide (index 0) keeps default position
137
+ if (newIndex === 0) {
138
+ currentOrbPosition.value = { top: '-20%', left: '-10%' };
139
+ } else if (oldIndex !== undefined) {
140
+ // Only randomize when actually navigating between slides (not on initial load)
141
+ currentOrbPosition.value = generateRandomOrbPosition();
142
+ }
143
+
144
+ // Reset scroll position
145
+ if (viewport.value) {
146
+ viewport.value.scrollTop = 0;
147
+ }
148
+ }, { immediate: true });
149
+
150
+ const ui = ref({ showJson: false }); // Removed showNotes
151
+ const engine = inject('LuminaEngine') as any;
152
+
153
+ const openSpeakerNotes = () => {
154
+ if (engine && typeof engine.openSpeakerNotes === 'function') {
155
+ engine.openSpeakerNotes();
156
+ } else {
157
+ console.warn('Lumina Engine not found or openSpeakerNotes not available');
158
+ alert('Speaker notes require the full Lumina Engine environment.');
159
+ }
160
+ };
161
+
162
+ const isDebug = computed(() => options.debug);
163
+
164
+ const currentSlideComponent = computed(() => {
165
+ if (!slide.value || !slide.value.type) return null;
166
+ return `layout-${slide.value.type}`;
167
+ });
168
+
169
+ const orbPosition = computed(() => ({
170
+ top: slide.value?.meta?.orbPos?.top || currentOrbPosition.value.top,
171
+ left: slide.value?.meta?.orbPos?.left || currentOrbPosition.value.left,
172
+ }));
173
+
174
+ const handleAction = (payload: any) => {
175
+ bus.emit('action', payload);
176
+ };
177
+
178
+
179
+
180
+ // --- Viewport Transitions ---
181
+ const onEnter = (el: Element, done: () => void) => {
182
+ const element = el as HTMLElement;
183
+ const vm = (el as any).__vue_app__ || (el as any).__vue_parent__ || (el as any)?.__vueParentComponent?.proxy;
184
+
185
+ // Set initial opacity to 1 so the slide container is visible
186
+ element.style.opacity = '1';
187
+
188
+ // Trigger internal content animations
189
+ if (vm && typeof vm.animateIn === 'function') {
190
+ vm.animateIn();
191
+ }
192
+
193
+ done();
194
+ };
195
+
196
+ const onLeave = async (el: Element, done: () => void) => {
197
+ const cfg = resolveTransitionConfig(store, undefined);
198
+ if (cfg.enabled === false) {
199
+ done();
200
+ return;
201
+ }
202
+
203
+ const vm = (el as any).__vue_app__ || (el as any).__vue_parent__ || (el as any)?.__vueParentComponent?.proxy;
204
+ if (vm && typeof vm.animateOut === 'function') {
205
+ await vm.animateOut();
206
+ }
207
+
208
+ const { durationOut, easeOut, type } = cfg;
209
+ const tl = gsap.timeline({ onComplete: done });
210
+
211
+ if (type === 'fade') {
212
+ tl.to(el, { opacity: 0, duration: durationOut });
213
+ } else if (type === 'zoom') {
214
+ tl.to(el, { opacity: 0, scale: 0.95, filter: 'blur(10px)', duration: durationOut });
215
+ } else {
216
+ tl.to(el, {
217
+ opacity: 0,
218
+ y: -30,
219
+ duration: durationOut,
220
+ ease: easeOut
221
+ });
222
+ }
223
+ };
224
+ </script>