promptslide 0.2.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 (39) hide show
  1. package/dist/index.d.ts +377 -0
  2. package/dist/index.js +963 -0
  3. package/dist/index.js.map +1 -0
  4. package/package.json +65 -0
  5. package/src/commands/build.mjs +73 -0
  6. package/src/commands/create.mjs +197 -0
  7. package/src/commands/preview.mjs +22 -0
  8. package/src/commands/studio.mjs +27 -0
  9. package/src/core/animated.tsx +153 -0
  10. package/src/core/animation-config.ts +98 -0
  11. package/src/core/animation-context.tsx +54 -0
  12. package/src/core/index.ts +73 -0
  13. package/src/core/layouts/shared-footer.tsx +43 -0
  14. package/src/core/morph.tsx +153 -0
  15. package/src/core/slide-deck.tsx +430 -0
  16. package/src/core/slide-error-boundary.tsx +50 -0
  17. package/src/core/theme-context.tsx +48 -0
  18. package/src/core/transitions.ts +200 -0
  19. package/src/core/types.ts +136 -0
  20. package/src/core/use-slide-navigation.ts +142 -0
  21. package/src/core/utils.ts +8 -0
  22. package/src/index.mjs +70 -0
  23. package/src/utils/ansi.mjs +5 -0
  24. package/src/utils/colors.mjs +44 -0
  25. package/src/utils/prompts.mjs +50 -0
  26. package/src/utils/tsconfig.mjs +35 -0
  27. package/src/vite/config.mjs +40 -0
  28. package/src/vite/plugin.mjs +66 -0
  29. package/templates/default/AGENTS.md +453 -0
  30. package/templates/default/README.md +35 -0
  31. package/templates/default/package.json +26 -0
  32. package/templates/default/public/logo.svg +7 -0
  33. package/templates/default/src/App.tsx +11 -0
  34. package/templates/default/src/deck-config.ts +8 -0
  35. package/templates/default/src/globals.css +157 -0
  36. package/templates/default/src/layouts/slide-layout-centered.tsx +59 -0
  37. package/templates/default/src/slides/slide-example.tsx +53 -0
  38. package/templates/default/src/slides/slide-title.tsx +27 -0
  39. package/templates/default/src/theme.ts +8 -0
package/dist/index.js ADDED
@@ -0,0 +1,963 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
5
+ // src/core/animation-config.ts
6
+ var SLIDE_TRANSITION_DURATION = 0.3;
7
+ var MORPH_DURATION = 0.8;
8
+ var STEP_ANIMATION_DURATION = 0.4;
9
+ var STAGGER_DELAY = 0.1;
10
+ var EASE_DEFAULT = "easeInOut";
11
+ var EASE_OUT = "easeOut";
12
+ var EASE_IN = "easeIn";
13
+ var EASE_MORPH = [0.4, 0, 0.2, 1];
14
+ var SPRING_SNAPPY = {
15
+ type: "spring",
16
+ stiffness: 300,
17
+ damping: 30
18
+ };
19
+ var SPRING_SMOOTH = {
20
+ type: "spring",
21
+ stiffness: 200,
22
+ damping: 25
23
+ };
24
+ var SPRING_BOUNCY = {
25
+ type: "spring",
26
+ stiffness: 400,
27
+ damping: 20
28
+ };
29
+ var SLIDE_TRANSITION = {
30
+ duration: SLIDE_TRANSITION_DURATION,
31
+ ease: EASE_DEFAULT
32
+ };
33
+ var MORPH_TRANSITION = {
34
+ duration: MORPH_DURATION,
35
+ ease: EASE_MORPH
36
+ };
37
+ var STEP_TRANSITION = {
38
+ ...SPRING_SNAPPY
39
+ };
40
+ var SLIDE_DISTANCE = 100;
41
+ var ELEMENT_SLIDE_DISTANCE = 30;
42
+ var SLIDE_DIMENSIONS = {
43
+ width: 1280,
44
+ height: 720,
45
+ aspectRatio: 16 / 9
46
+ };
47
+
48
+ // src/core/animation-context.tsx
49
+ import { createContext, useContext, useMemo } from "react";
50
+ import { jsx } from "react/jsx-runtime";
51
+ var AnimationContext = createContext({
52
+ currentStep: 0,
53
+ totalSteps: 0,
54
+ showAllAnimations: false
55
+ });
56
+ function AnimationProvider({
57
+ children,
58
+ currentStep,
59
+ totalSteps,
60
+ showAllAnimations = false
61
+ }) {
62
+ const value = useMemo(
63
+ () => ({
64
+ currentStep,
65
+ totalSteps,
66
+ showAllAnimations
67
+ }),
68
+ [currentStep, totalSteps, showAllAnimations]
69
+ );
70
+ return /* @__PURE__ */ jsx(AnimationContext.Provider, { value, children });
71
+ }
72
+ function useAnimationContext() {
73
+ return useContext(AnimationContext);
74
+ }
75
+
76
+ // src/core/animated.tsx
77
+ import { motion } from "framer-motion";
78
+ import { jsx as jsx2 } from "react/jsx-runtime";
79
+ var animationVariants = {
80
+ fade: {
81
+ hidden: { opacity: 0 },
82
+ visible: { opacity: 1 }
83
+ },
84
+ "slide-up": {
85
+ hidden: { opacity: 0, y: ELEMENT_SLIDE_DISTANCE },
86
+ visible: { opacity: 1, y: 0 }
87
+ },
88
+ "slide-down": {
89
+ hidden: { opacity: 0, y: -ELEMENT_SLIDE_DISTANCE },
90
+ visible: { opacity: 1, y: 0 }
91
+ },
92
+ "slide-left": {
93
+ hidden: { opacity: 0, x: ELEMENT_SLIDE_DISTANCE },
94
+ visible: { opacity: 1, x: 0 }
95
+ },
96
+ "slide-right": {
97
+ hidden: { opacity: 0, x: -ELEMENT_SLIDE_DISTANCE },
98
+ visible: { opacity: 1, x: 0 }
99
+ },
100
+ scale: {
101
+ hidden: { opacity: 0, scale: 0.8 },
102
+ visible: { opacity: 1, scale: 1 }
103
+ }
104
+ };
105
+ function Animated({
106
+ step,
107
+ animation = "slide-up",
108
+ duration = STEP_ANIMATION_DURATION,
109
+ delay = 0,
110
+ className,
111
+ children
112
+ }) {
113
+ const { currentStep, showAllAnimations } = useAnimationContext();
114
+ const isVisible = showAllAnimations || currentStep >= step;
115
+ return /* @__PURE__ */ jsx2(
116
+ motion.div,
117
+ {
118
+ initial: "hidden",
119
+ animate: isVisible ? "visible" : "hidden",
120
+ variants: animationVariants[animation],
121
+ transition: {
122
+ ...SPRING_SNAPPY,
123
+ duration,
124
+ delay: isVisible ? delay : 0
125
+ },
126
+ className,
127
+ children
128
+ }
129
+ );
130
+ }
131
+ function AnimatedGroup({
132
+ startStep,
133
+ animation = "slide-up",
134
+ staggerDelay = STAGGER_DELAY,
135
+ className,
136
+ children
137
+ }) {
138
+ const { currentStep, showAllAnimations } = useAnimationContext();
139
+ const childArray = Array.isArray(children) ? children : [children];
140
+ const isVisible = showAllAnimations || currentStep >= startStep;
141
+ const containerVariants = {
142
+ hidden: {},
143
+ visible: {
144
+ transition: {
145
+ staggerChildren: staggerDelay
146
+ }
147
+ }
148
+ };
149
+ return /* @__PURE__ */ jsx2(
150
+ motion.div,
151
+ {
152
+ initial: "hidden",
153
+ animate: isVisible ? "visible" : "hidden",
154
+ variants: containerVariants,
155
+ className,
156
+ children: childArray.map((child, index) => /* @__PURE__ */ jsx2(motion.div, { variants: animationVariants[animation], children: child }, index))
157
+ }
158
+ );
159
+ }
160
+
161
+ // src/core/transitions.ts
162
+ var fadeVariants = {
163
+ enter: { opacity: 0 },
164
+ center: { opacity: 1 },
165
+ exit: { opacity: 0 }
166
+ };
167
+ var slideLeftVariants = {
168
+ enter: { x: SLIDE_DISTANCE, opacity: 0 },
169
+ center: { x: 0, opacity: 1 },
170
+ exit: { x: -SLIDE_DISTANCE, opacity: 0 }
171
+ };
172
+ var slideRightVariants = {
173
+ enter: { x: -SLIDE_DISTANCE, opacity: 0 },
174
+ center: { x: 0, opacity: 1 },
175
+ exit: { x: SLIDE_DISTANCE, opacity: 0 }
176
+ };
177
+ var slideUpVariants = {
178
+ enter: { y: SLIDE_DISTANCE, opacity: 0 },
179
+ center: { y: 0, opacity: 1 },
180
+ exit: { y: -SLIDE_DISTANCE, opacity: 0 }
181
+ };
182
+ var slideDownVariants = {
183
+ enter: { y: -SLIDE_DISTANCE, opacity: 0 },
184
+ center: { y: 0, opacity: 1 },
185
+ exit: { y: SLIDE_DISTANCE, opacity: 0 }
186
+ };
187
+ var zoomVariants = {
188
+ enter: { scale: 0.8, opacity: 0 },
189
+ center: { scale: 1, opacity: 1 },
190
+ exit: { scale: 1.2, opacity: 0 }
191
+ };
192
+ var zoomFadeVariants = {
193
+ enter: { scale: 0.95, opacity: 0 },
194
+ center: { scale: 1, opacity: 1 },
195
+ exit: { scale: 1.05, opacity: 0 }
196
+ };
197
+ var morphVariants = {
198
+ enter: {
199
+ opacity: 0,
200
+ zIndex: 1
201
+ },
202
+ center: {
203
+ opacity: 1,
204
+ zIndex: 1,
205
+ transition: {
206
+ opacity: { delay: 0.05, duration: 0.25 }
207
+ }
208
+ },
209
+ exit: {
210
+ opacity: 0,
211
+ zIndex: 0,
212
+ transition: {
213
+ opacity: { duration: MORPH_DURATION, ease: EASE_MORPH }
214
+ }
215
+ }
216
+ };
217
+ var noneVariants = {
218
+ enter: {},
219
+ center: {},
220
+ exit: {}
221
+ };
222
+ var SLIDE_VARIANTS = {
223
+ fade: fadeVariants,
224
+ "slide-left": slideLeftVariants,
225
+ "slide-right": slideRightVariants,
226
+ "slide-up": slideUpVariants,
227
+ "slide-down": slideDownVariants,
228
+ zoom: zoomVariants,
229
+ "zoom-fade": zoomFadeVariants,
230
+ morph: morphVariants,
231
+ none: noneVariants
232
+ };
233
+ function createDirectionalVariants(axis = "x") {
234
+ return (direction) => ({
235
+ enter: {
236
+ [axis]: direction > 0 ? SLIDE_DISTANCE : -SLIDE_DISTANCE,
237
+ opacity: 0
238
+ },
239
+ center: {
240
+ [axis]: 0,
241
+ opacity: 1
242
+ },
243
+ exit: {
244
+ [axis]: direction < 0 ? SLIDE_DISTANCE : -SLIDE_DISTANCE,
245
+ opacity: 0
246
+ }
247
+ });
248
+ }
249
+ var directionalSlideX = createDirectionalVariants("x");
250
+ var directionalSlideY = createDirectionalVariants("y");
251
+ function getSlideVariants(config, direction = 1) {
252
+ const type = typeof config === "string" ? config : config.type;
253
+ const directional = typeof config === "object" ? config.directional : false;
254
+ if (directional && (type === "slide-left" || type === "slide-right")) {
255
+ return directionalSlideX(direction);
256
+ }
257
+ if (directional && (type === "slide-up" || type === "slide-down")) {
258
+ return directionalSlideY(direction);
259
+ }
260
+ return SLIDE_VARIANTS[type];
261
+ }
262
+ function getSlideTransition(config) {
263
+ if (!config) return SLIDE_TRANSITION;
264
+ const type = typeof config === "string" ? config : config.type;
265
+ const defaultDuration = type === "morph" ? MORPH_DURATION : SLIDE_TRANSITION_DURATION;
266
+ const duration = typeof config === "object" && config.duration ? config.duration : defaultDuration;
267
+ return {
268
+ ...SLIDE_TRANSITION,
269
+ duration
270
+ };
271
+ }
272
+ var DEFAULT_SLIDE_TRANSITION = "fade";
273
+
274
+ // src/core/morph.tsx
275
+ import { motion as motion2 } from "framer-motion";
276
+ import { jsx as jsx3 } from "react/jsx-runtime";
277
+ function Morph({
278
+ layoutId,
279
+ transition = MORPH_TRANSITION,
280
+ className,
281
+ children
282
+ }) {
283
+ return /* @__PURE__ */ jsx3(
284
+ motion2.div,
285
+ {
286
+ layout: true,
287
+ layoutId,
288
+ initial: false,
289
+ transition,
290
+ className,
291
+ children
292
+ }
293
+ );
294
+ }
295
+ function MorphGroup({
296
+ groupId,
297
+ transition = MORPH_TRANSITION,
298
+ className,
299
+ children
300
+ }) {
301
+ return /* @__PURE__ */ jsx3(
302
+ motion2.div,
303
+ {
304
+ layout: true,
305
+ layoutId: groupId,
306
+ initial: false,
307
+ transition,
308
+ className,
309
+ children
310
+ }
311
+ );
312
+ }
313
+ function MorphItem({
314
+ id,
315
+ prefix,
316
+ transition = MORPH_TRANSITION,
317
+ className,
318
+ children
319
+ }) {
320
+ const layoutId = prefix ? `${prefix}-${id}` : id;
321
+ return /* @__PURE__ */ jsx3(
322
+ motion2.div,
323
+ {
324
+ layout: true,
325
+ layoutId,
326
+ initial: false,
327
+ transition,
328
+ className,
329
+ children
330
+ }
331
+ );
332
+ }
333
+ function MorphText({
334
+ layoutId,
335
+ as: Component = "span",
336
+ transition = MORPH_TRANSITION,
337
+ className,
338
+ children
339
+ }) {
340
+ const MotionComponent = motion2[Component];
341
+ return /* @__PURE__ */ jsx3(
342
+ MotionComponent,
343
+ {
344
+ layout: true,
345
+ layoutId,
346
+ initial: false,
347
+ transition,
348
+ className,
349
+ children
350
+ }
351
+ );
352
+ }
353
+
354
+ // src/core/use-slide-navigation.ts
355
+ import { useCallback, useEffect, useState } from "react";
356
+ function useSlideNavigation({
357
+ slides,
358
+ initialSlide = 0,
359
+ onSlideChange
360
+ }) {
361
+ const [currentSlide, setCurrentSlide] = useState(initialSlide);
362
+ const [animationStep, setAnimationStep] = useState(0);
363
+ const [navState, setNavState] = useState({
364
+ status: "idle",
365
+ direction: 0
366
+ });
367
+ const [queuedAction, setQueuedAction] = useState(null);
368
+ const totalSteps = slides[currentSlide]?.steps ?? 0;
369
+ const onTransitionComplete = useCallback(() => {
370
+ setNavState((prev) => {
371
+ if (prev.status === "transitioning") {
372
+ return { status: "idle", direction: 0 };
373
+ }
374
+ return prev;
375
+ });
376
+ }, []);
377
+ const advance = useCallback(() => {
378
+ if (navState.status === "transitioning") {
379
+ setQueuedAction("advance");
380
+ return;
381
+ }
382
+ const currentTotalSteps = slides[currentSlide]?.steps ?? 0;
383
+ if (animationStep >= currentTotalSteps) {
384
+ const nextSlide = (currentSlide + 1) % slides.length;
385
+ setNavState({ status: "transitioning", direction: 1 });
386
+ setAnimationStep(0);
387
+ setCurrentSlide(nextSlide);
388
+ onSlideChange?.(nextSlide);
389
+ } else {
390
+ setAnimationStep((prev) => prev + 1);
391
+ }
392
+ }, [navState.status, animationStep, currentSlide, slides, onSlideChange]);
393
+ const goBack = useCallback(() => {
394
+ if (navState.status === "transitioning") {
395
+ setQueuedAction("goBack");
396
+ return;
397
+ }
398
+ if (animationStep <= 0) {
399
+ const prevSlide = (currentSlide - 1 + slides.length) % slides.length;
400
+ const prevSlideSteps = slides[prevSlide]?.steps ?? 0;
401
+ setNavState({ status: "transitioning", direction: -1 });
402
+ setAnimationStep(prevSlideSteps);
403
+ setCurrentSlide(prevSlide);
404
+ onSlideChange?.(prevSlide);
405
+ } else {
406
+ setAnimationStep((prev) => prev - 1);
407
+ }
408
+ }, [navState.status, animationStep, currentSlide, slides, onSlideChange]);
409
+ const goToSlide = useCallback(
410
+ (index) => {
411
+ if (index < 0 || index >= slides.length || index === currentSlide) {
412
+ return;
413
+ }
414
+ const direction = index > currentSlide ? 1 : -1;
415
+ setNavState({ status: "transitioning", direction });
416
+ setAnimationStep(0);
417
+ setCurrentSlide(index);
418
+ onSlideChange?.(index);
419
+ },
420
+ [currentSlide, slides.length, onSlideChange]
421
+ );
422
+ useEffect(() => {
423
+ if (navState.status === "idle" && queuedAction !== null) {
424
+ setQueuedAction(null);
425
+ if (queuedAction === "advance") {
426
+ advance();
427
+ } else if (queuedAction === "goBack") {
428
+ goBack();
429
+ }
430
+ }
431
+ }, [navState.status, queuedAction, advance, goBack]);
432
+ return {
433
+ currentSlide,
434
+ animationStep,
435
+ totalSteps,
436
+ direction: navState.direction,
437
+ isTransitioning: navState.status !== "idle",
438
+ showAllAnimations: navState.direction === -1 && navState.status === "transitioning",
439
+ advance,
440
+ goBack,
441
+ goToSlide,
442
+ onTransitionComplete
443
+ };
444
+ }
445
+
446
+ // src/core/theme-context.tsx
447
+ import { createContext as createContext2, useContext as useContext2, useMemo as useMemo2 } from "react";
448
+ import { jsx as jsx4 } from "react/jsx-runtime";
449
+ var ThemeContext = createContext2(null);
450
+ function useTheme() {
451
+ return useContext2(ThemeContext);
452
+ }
453
+ function buildCssOverrides(theme) {
454
+ const style = {};
455
+ if (theme.colors?.primary) style["--primary"] = theme.colors.primary;
456
+ if (theme.colors?.primaryForeground) style["--primary-foreground"] = theme.colors.primaryForeground;
457
+ if (theme.colors?.secondary) style["--secondary"] = theme.colors.secondary;
458
+ if (theme.colors?.secondaryForeground) style["--secondary-foreground"] = theme.colors.secondaryForeground;
459
+ if (theme.colors?.accent) style["--accent"] = theme.colors.accent;
460
+ if (theme.colors?.accentForeground) style["--accent-foreground"] = theme.colors.accentForeground;
461
+ if (theme.fonts?.heading) style["--font-heading"] = theme.fonts.heading;
462
+ if (theme.fonts?.body) style["--font-body"] = theme.fonts.body;
463
+ return style;
464
+ }
465
+ function SlideThemeProvider({ theme, children }) {
466
+ const cssOverrides = useMemo2(() => buildCssOverrides(theme), [theme]);
467
+ return /* @__PURE__ */ jsx4(ThemeContext.Provider, { value: theme, children: /* @__PURE__ */ jsx4("div", { style: cssOverrides, className: "contents", children }) });
468
+ }
469
+
470
+ // src/core/layouts/shared-footer.tsx
471
+ import { jsx as jsx5, jsxs } from "react/jsx-runtime";
472
+ function SlideFooter({ slideNumber, totalSlides, variant = "default" }) {
473
+ const theme = useTheme();
474
+ if (!theme) return null;
475
+ const logoUrl = variant === "light" ? theme.logo?.fullLight ?? theme.logo?.full : theme.logo?.full;
476
+ const textClass = variant === "light" ? "text-white/70" : "text-muted-foreground";
477
+ const nameClass = variant === "light" ? "text-white font-semibold" : "text-foreground font-semibold";
478
+ return /* @__PURE__ */ jsxs("div", { className: `mt-4 flex shrink-0 items-center justify-between text-sm ${textClass}`, children: [
479
+ /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-3 tracking-tight ${nameClass}`, children: [
480
+ logoUrl && /* @__PURE__ */ jsx5(
481
+ "img",
482
+ {
483
+ src: logoUrl,
484
+ alt: `${theme.name} Logo`,
485
+ className: "h-8 w-auto"
486
+ }
487
+ ),
488
+ /* @__PURE__ */ jsx5("span", { className: "text-lg", children: theme.name })
489
+ ] }),
490
+ /* @__PURE__ */ jsxs("div", { className: "font-mono", children: [
491
+ slideNumber,
492
+ " / ",
493
+ totalSlides
494
+ ] })
495
+ ] });
496
+ }
497
+
498
+ // src/core/slide-deck.tsx
499
+ import { AnimatePresence, LayoutGroup, motion as motion3 } from "framer-motion";
500
+ import { ChevronLeft, ChevronRight, Download, Grid3X3, List, Maximize, Monitor } from "lucide-react";
501
+ import { useCallback as useCallback2, useEffect as useEffect2, useRef, useState as useState2 } from "react";
502
+
503
+ // src/core/slide-error-boundary.tsx
504
+ import React from "react";
505
+ import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
506
+ var SlideErrorBoundary = class extends React.Component {
507
+ constructor() {
508
+ super(...arguments);
509
+ __publicField(this, "state", { hasError: false, error: null });
510
+ }
511
+ static getDerivedStateFromError(error) {
512
+ return { hasError: true, error };
513
+ }
514
+ componentDidCatch(error, errorInfo) {
515
+ console.error(
516
+ `[PromptSlide] Slide ${this.props.slideIndex + 1}${this.props.slideTitle ? ` ("${this.props.slideTitle}")` : ""} crashed:`,
517
+ error,
518
+ errorInfo
519
+ );
520
+ }
521
+ render() {
522
+ if (this.state.hasError) {
523
+ return /* @__PURE__ */ jsxs2("div", { className: "flex h-full w-full flex-col items-center justify-center bg-red-950/20 p-12", children: [
524
+ /* @__PURE__ */ jsxs2("div", { className: "mb-4 text-lg font-semibold text-red-400", children: [
525
+ "Slide ",
526
+ this.props.slideIndex + 1,
527
+ " Error",
528
+ this.props.slideTitle && /* @__PURE__ */ jsxs2("span", { className: "ml-2 font-normal text-red-400/70", children: [
529
+ "(",
530
+ this.props.slideTitle,
531
+ ")"
532
+ ] })
533
+ ] }),
534
+ /* @__PURE__ */ jsx6("div", { className: "max-w-2xl text-center font-mono text-sm break-words text-red-300/80", children: this.state.error?.message ?? "Unknown error" })
535
+ ] });
536
+ }
537
+ return this.props.children;
538
+ }
539
+ };
540
+
541
+ // src/core/utils.ts
542
+ import { clsx } from "clsx";
543
+ import { twMerge } from "tailwind-merge";
544
+ function cn(...inputs) {
545
+ return twMerge(clsx(inputs));
546
+ }
547
+
548
+ // src/core/slide-deck.tsx
549
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
550
+ function SlideDeck({ slides, transition, directionalTransition }) {
551
+ const [viewMode, setViewMode] = useState2("slide");
552
+ const [isPresentationMode, setIsPresentationMode] = useState2(false);
553
+ const [scale, setScale] = useState2(1);
554
+ const containerRef = useRef(null);
555
+ const {
556
+ currentSlide,
557
+ animationStep,
558
+ totalSteps,
559
+ direction,
560
+ showAllAnimations,
561
+ advance,
562
+ goBack,
563
+ goToSlide,
564
+ onTransitionComplete
565
+ } = useSlideNavigation({
566
+ slides
567
+ });
568
+ const togglePresentationMode = useCallback2(async () => {
569
+ if (!document.fullscreenElement) {
570
+ await document.documentElement.requestFullscreen();
571
+ } else {
572
+ await document.exitFullscreen();
573
+ }
574
+ }, []);
575
+ useEffect2(() => {
576
+ const handleFullscreenChange = () => {
577
+ setIsPresentationMode(!!document.fullscreenElement);
578
+ };
579
+ document.addEventListener("fullscreenchange", handleFullscreenChange);
580
+ return () => document.removeEventListener("fullscreenchange", handleFullscreenChange);
581
+ }, []);
582
+ useEffect2(() => {
583
+ const calculateScale = () => {
584
+ if (!isPresentationMode) {
585
+ setScale(1);
586
+ return;
587
+ }
588
+ const viewportWidth = window.innerWidth;
589
+ const viewportHeight = window.innerHeight;
590
+ const scaleX = viewportWidth / SLIDE_DIMENSIONS.width;
591
+ const scaleY = viewportHeight / SLIDE_DIMENSIONS.height;
592
+ setScale(Math.min(scaleX, scaleY));
593
+ };
594
+ calculateScale();
595
+ window.addEventListener("resize", calculateScale);
596
+ return () => window.removeEventListener("resize", calculateScale);
597
+ }, [isPresentationMode]);
598
+ const handleExportPdf = () => {
599
+ const previousMode = viewMode;
600
+ setViewMode("list");
601
+ setTimeout(() => {
602
+ const handleAfterPrint = () => {
603
+ setViewMode(previousMode);
604
+ window.removeEventListener("afterprint", handleAfterPrint);
605
+ };
606
+ window.addEventListener("afterprint", handleAfterPrint);
607
+ window.print();
608
+ }, 100);
609
+ };
610
+ useEffect2(() => {
611
+ const handleKeyDown = (e) => {
612
+ if (e.key === "f" || e.key === "F") {
613
+ togglePresentationMode();
614
+ return;
615
+ }
616
+ if (e.key === "g" || e.key === "G") {
617
+ setViewMode((prev) => prev === "grid" ? "slide" : "grid");
618
+ return;
619
+ }
620
+ if (viewMode !== "slide") return;
621
+ if (e.key === "ArrowRight" || e.key === " ") {
622
+ e.preventDefault();
623
+ advance();
624
+ } else if (e.key === "ArrowLeft") {
625
+ e.preventDefault();
626
+ goBack();
627
+ }
628
+ };
629
+ window.addEventListener("keydown", handleKeyDown);
630
+ return () => window.removeEventListener("keydown", handleKeyDown);
631
+ }, [advance, goBack, viewMode, togglePresentationMode]);
632
+ const currentSlideTransition = slides[currentSlide]?.transition;
633
+ const transitionType = currentSlideTransition ?? transition ?? DEFAULT_SLIDE_TRANSITION;
634
+ const isDirectional = directionalTransition ?? false;
635
+ const slideVariants = getSlideVariants(
636
+ { type: transitionType, directional: isDirectional },
637
+ direction
638
+ );
639
+ const CurrentSlideComponent = slides[currentSlide].component;
640
+ return /* @__PURE__ */ jsxs3("div", { className: "min-h-screen w-full bg-neutral-950 text-foreground", children: [
641
+ /* @__PURE__ */ jsx7("style", { children: `
642
+ @media print {
643
+ @page {
644
+ size: 1920px 1080px;
645
+ margin: 0;
646
+ }
647
+ html,
648
+ body {
649
+ width: 100%;
650
+ height: 100%;
651
+ margin: 0 !important;
652
+ padding: 0 !important;
653
+ overflow: visible !important;
654
+ }
655
+ body {
656
+ print-color-adjust: exact;
657
+ -webkit-print-color-adjust: exact;
658
+ background: transparent !important;
659
+ }
660
+ }
661
+ ` }),
662
+ /* @__PURE__ */ jsxs3(
663
+ "div",
664
+ {
665
+ className: cn(
666
+ "fixed top-4 right-4 z-50 flex gap-1 rounded-lg border border-neutral-800 bg-neutral-950/90 p-1 backdrop-blur-sm print:hidden",
667
+ isPresentationMode && "hidden"
668
+ ),
669
+ children: [
670
+ /* @__PURE__ */ jsx7(
671
+ "button",
672
+ {
673
+ onClick: () => setViewMode("slide"),
674
+ className: cn(
675
+ "rounded-md p-2 text-neutral-400 transition-colors hover:bg-neutral-800 hover:text-white",
676
+ viewMode === "slide" && "bg-neutral-800 text-white"
677
+ ),
678
+ title: "Presentation View",
679
+ children: /* @__PURE__ */ jsx7(Monitor, { className: "h-4 w-4" })
680
+ }
681
+ ),
682
+ /* @__PURE__ */ jsx7(
683
+ "button",
684
+ {
685
+ onClick: () => setViewMode("list"),
686
+ className: cn(
687
+ "rounded-md p-2 text-neutral-400 transition-colors hover:bg-neutral-800 hover:text-white",
688
+ viewMode === "list" && "bg-neutral-800 text-white"
689
+ ),
690
+ title: "List View",
691
+ children: /* @__PURE__ */ jsx7(List, { className: "h-4 w-4" })
692
+ }
693
+ ),
694
+ /* @__PURE__ */ jsx7(
695
+ "button",
696
+ {
697
+ onClick: () => setViewMode("grid"),
698
+ className: cn(
699
+ "rounded-md p-2 text-neutral-400 transition-colors hover:bg-neutral-800 hover:text-white",
700
+ viewMode === "grid" && "bg-neutral-800 text-white"
701
+ ),
702
+ title: "Grid View",
703
+ children: /* @__PURE__ */ jsx7(Grid3X3, { className: "h-4 w-4" })
704
+ }
705
+ ),
706
+ /* @__PURE__ */ jsx7("div", { className: "mx-1 w-px bg-neutral-800" }),
707
+ /* @__PURE__ */ jsx7(
708
+ "button",
709
+ {
710
+ onClick: handleExportPdf,
711
+ className: "rounded-md p-2 text-neutral-400 transition-colors hover:bg-neutral-800 hover:text-white",
712
+ title: "Download PDF",
713
+ children: /* @__PURE__ */ jsx7(Download, { className: "h-4 w-4" })
714
+ }
715
+ ),
716
+ /* @__PURE__ */ jsx7(
717
+ "button",
718
+ {
719
+ onClick: togglePresentationMode,
720
+ className: "rounded-md p-2 text-neutral-400 transition-colors hover:bg-neutral-800 hover:text-white",
721
+ title: "Present (F)",
722
+ children: /* @__PURE__ */ jsx7(Maximize, { className: "h-4 w-4" })
723
+ }
724
+ )
725
+ ]
726
+ }
727
+ ),
728
+ viewMode === "slide" && /* @__PURE__ */ jsxs3(
729
+ "div",
730
+ {
731
+ ref: containerRef,
732
+ role: "presentation",
733
+ tabIndex: isPresentationMode ? 0 : void 0,
734
+ className: cn(
735
+ "flex h-screen w-full flex-col items-center justify-center overflow-hidden print:hidden",
736
+ isPresentationMode ? "bg-black p-0" : "p-4 md:p-8"
737
+ ),
738
+ onClick: isPresentationMode ? advance : void 0,
739
+ onKeyDown: isPresentationMode ? (e) => {
740
+ if (e.key === "Enter" || e.key === " ") advance();
741
+ } : void 0,
742
+ children: [
743
+ /* @__PURE__ */ jsx7(LayoutGroup, { id: "slide-deck", children: isPresentationMode ? /* @__PURE__ */ jsx7(
744
+ "div",
745
+ {
746
+ className: "pointer-events-none relative overflow-hidden bg-black",
747
+ style: {
748
+ width: SLIDE_DIMENSIONS.width,
749
+ height: SLIDE_DIMENSIONS.height,
750
+ transform: `scale(${scale})`,
751
+ transformOrigin: "center center"
752
+ },
753
+ children: /* @__PURE__ */ jsx7(AnimatePresence, { initial: false, children: /* @__PURE__ */ jsx7(
754
+ motion3.div,
755
+ {
756
+ variants: slideVariants,
757
+ initial: "enter",
758
+ animate: "center",
759
+ exit: "exit",
760
+ transition: SLIDE_TRANSITION,
761
+ onAnimationComplete: (definition) => {
762
+ if (definition === "center") {
763
+ onTransitionComplete();
764
+ }
765
+ },
766
+ className: "absolute inset-0 h-full w-full",
767
+ children: /* @__PURE__ */ jsx7(
768
+ AnimationProvider,
769
+ {
770
+ currentStep: animationStep,
771
+ totalSteps,
772
+ showAllAnimations,
773
+ children: /* @__PURE__ */ jsx7(
774
+ SlideErrorBoundary,
775
+ {
776
+ slideIndex: currentSlide,
777
+ slideTitle: slides[currentSlide]?.title,
778
+ children: /* @__PURE__ */ jsx7(
779
+ CurrentSlideComponent,
780
+ {
781
+ slideNumber: currentSlide + 1,
782
+ totalSlides: slides.length
783
+ }
784
+ )
785
+ }
786
+ )
787
+ }
788
+ )
789
+ },
790
+ currentSlide
791
+ ) })
792
+ }
793
+ ) : /* @__PURE__ */ jsx7("div", { className: "relative aspect-video w-full max-w-7xl overflow-hidden rounded-xl border border-neutral-800 bg-black shadow-2xl", children: /* @__PURE__ */ jsx7(AnimatePresence, { initial: false, children: /* @__PURE__ */ jsx7(
794
+ motion3.div,
795
+ {
796
+ variants: slideVariants,
797
+ initial: "enter",
798
+ animate: "center",
799
+ exit: "exit",
800
+ transition: SLIDE_TRANSITION,
801
+ onAnimationComplete: (definition) => {
802
+ if (definition === "center") {
803
+ onTransitionComplete();
804
+ }
805
+ },
806
+ className: "absolute inset-0 h-full w-full",
807
+ children: /* @__PURE__ */ jsx7(
808
+ AnimationProvider,
809
+ {
810
+ currentStep: animationStep,
811
+ totalSteps,
812
+ showAllAnimations,
813
+ children: /* @__PURE__ */ jsx7(
814
+ SlideErrorBoundary,
815
+ {
816
+ slideIndex: currentSlide,
817
+ slideTitle: slides[currentSlide]?.title,
818
+ children: /* @__PURE__ */ jsx7(
819
+ CurrentSlideComponent,
820
+ {
821
+ slideNumber: currentSlide + 1,
822
+ totalSlides: slides.length
823
+ }
824
+ )
825
+ }
826
+ )
827
+ }
828
+ )
829
+ },
830
+ currentSlide
831
+ ) }) }) }),
832
+ !isPresentationMode && /* @__PURE__ */ jsxs3("div", { className: "mt-6 flex items-center gap-4", children: [
833
+ /* @__PURE__ */ jsx7(
834
+ "button",
835
+ {
836
+ onClick: goBack,
837
+ className: "rounded-full border border-neutral-800 bg-black/50 p-2 text-neutral-400 backdrop-blur-sm transition-colors hover:bg-neutral-900 hover:text-white",
838
+ children: /* @__PURE__ */ jsx7(ChevronLeft, { className: "h-5 w-5" })
839
+ }
840
+ ),
841
+ /* @__PURE__ */ jsxs3("div", { className: "flex min-w-[4rem] flex-col items-center", children: [
842
+ /* @__PURE__ */ jsxs3("span", { className: "font-mono text-sm text-neutral-500", children: [
843
+ currentSlide + 1,
844
+ " / ",
845
+ slides.length
846
+ ] }),
847
+ slides[currentSlide]?.title && /* @__PURE__ */ jsx7("span", { className: "mt-0.5 text-xs text-neutral-600", children: slides[currentSlide].title })
848
+ ] }),
849
+ /* @__PURE__ */ jsx7(
850
+ "button",
851
+ {
852
+ onClick: advance,
853
+ className: "rounded-full border border-neutral-800 bg-black/50 p-2 text-neutral-400 backdrop-blur-sm transition-colors hover:bg-neutral-900 hover:text-white",
854
+ children: /* @__PURE__ */ jsx7(ChevronRight, { className: "h-5 w-5" })
855
+ }
856
+ )
857
+ ] })
858
+ ]
859
+ }
860
+ ),
861
+ viewMode === "grid" && /* @__PURE__ */ jsx7("div", { className: "mx-auto max-w-7xl p-8 pt-16 print:hidden", children: /* @__PURE__ */ jsx7("div", { className: "grid grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-4", children: slides.map((slideConfig, index) => {
862
+ const SlideComponent = slideConfig.component;
863
+ const prevSection = index > 0 ? slides[index - 1]?.section : void 0;
864
+ const showSectionHeader = slideConfig.section && slideConfig.section !== prevSection;
865
+ return /* @__PURE__ */ jsxs3("div", { className: showSectionHeader ? "col-span-full" : void 0, children: [
866
+ showSectionHeader && /* @__PURE__ */ jsx7("h3", { className: "mt-4 mb-3 text-xs font-bold tracking-[0.2em] text-neutral-500 uppercase first:mt-0", children: slideConfig.section }),
867
+ /* @__PURE__ */ jsxs3(
868
+ "button",
869
+ {
870
+ onClick: () => {
871
+ goToSlide(index);
872
+ setViewMode("slide");
873
+ },
874
+ className: "group relative aspect-video w-full overflow-hidden rounded-lg border border-neutral-800 bg-black shadow-sm transition-all hover:border-primary hover:shadow-lg hover:shadow-primary/10",
875
+ children: [
876
+ /* @__PURE__ */ jsx7(
877
+ "div",
878
+ {
879
+ className: "h-full w-full origin-top-left scale-[0.25]",
880
+ style: { width: "400%", height: "400%" },
881
+ children: /* @__PURE__ */ jsx7(SlideErrorBoundary, { slideIndex: index, slideTitle: slideConfig.title, children: /* @__PURE__ */ jsx7(SlideComponent, { slideNumber: index + 1, totalSlides: slides.length }) })
882
+ }
883
+ ),
884
+ /* @__PURE__ */ jsx7("div", { className: "absolute inset-0 bg-black/0 transition-colors group-hover:bg-black/20" }),
885
+ /* @__PURE__ */ jsx7("div", { className: "absolute bottom-2 left-2 rounded bg-black/70 px-2 py-1 text-xs font-medium text-white", children: slideConfig.title ? `${index + 1}. ${slideConfig.title}` : index + 1 })
886
+ ]
887
+ }
888
+ )
889
+ ] }, index);
890
+ }) }) }),
891
+ /* @__PURE__ */ jsx7(
892
+ "div",
893
+ {
894
+ className: cn(
895
+ "mx-auto max-w-7xl p-8 pt-16",
896
+ "print:m-0 print:block print:max-w-none print:p-0",
897
+ viewMode === "list" ? "block" : "hidden print:block"
898
+ ),
899
+ children: /* @__PURE__ */ jsx7("div", { className: "grid grid-cols-1 gap-8 print:block", children: slides.map((slideConfig, index) => {
900
+ const SlideComponent = slideConfig.component;
901
+ return /* @__PURE__ */ jsx7(
902
+ "div",
903
+ {
904
+ className: "aspect-video w-full overflow-hidden rounded-xl border border-neutral-800 bg-black shadow-sm print:relative print:m-0 print:h-[1080px] print:w-[1920px] print:break-after-page print:overflow-hidden print:rounded-none print:border-0 print:shadow-none",
905
+ children: /* @__PURE__ */ jsx7("div", { className: "h-full w-full print:h-[720px] print:w-[1280px] print:origin-top-left print:scale-[1.5]", children: /* @__PURE__ */ jsx7(
906
+ AnimationProvider,
907
+ {
908
+ currentStep: slideConfig.steps,
909
+ totalSteps: slideConfig.steps,
910
+ showAllAnimations: true,
911
+ children: /* @__PURE__ */ jsx7(SlideErrorBoundary, { slideIndex: index, slideTitle: slideConfig.title, children: /* @__PURE__ */ jsx7(SlideComponent, { slideNumber: index + 1, totalSlides: slides.length }) })
912
+ }
913
+ ) })
914
+ },
915
+ index
916
+ );
917
+ }) })
918
+ }
919
+ )
920
+ ] });
921
+ }
922
+ export {
923
+ Animated,
924
+ AnimatedGroup,
925
+ AnimationProvider,
926
+ DEFAULT_SLIDE_TRANSITION,
927
+ EASE_DEFAULT,
928
+ EASE_IN,
929
+ EASE_MORPH,
930
+ EASE_OUT,
931
+ ELEMENT_SLIDE_DISTANCE,
932
+ MORPH_DURATION,
933
+ MORPH_TRANSITION,
934
+ Morph,
935
+ MorphGroup,
936
+ MorphItem,
937
+ MorphText,
938
+ SLIDE_DIMENSIONS,
939
+ SLIDE_DISTANCE,
940
+ SLIDE_TRANSITION,
941
+ SLIDE_TRANSITION_DURATION,
942
+ SLIDE_VARIANTS,
943
+ SPRING_BOUNCY,
944
+ SPRING_SMOOTH,
945
+ SPRING_SNAPPY,
946
+ STAGGER_DELAY,
947
+ STEP_ANIMATION_DURATION,
948
+ STEP_TRANSITION,
949
+ SlideDeck,
950
+ SlideErrorBoundary,
951
+ SlideFooter,
952
+ SlideThemeProvider,
953
+ cn,
954
+ createDirectionalVariants,
955
+ directionalSlideX,
956
+ directionalSlideY,
957
+ getSlideTransition,
958
+ getSlideVariants,
959
+ useAnimationContext,
960
+ useSlideNavigation,
961
+ useTheme
962
+ };
963
+ //# sourceMappingURL=index.js.map