animot-presenter 0.2.8 → 0.2.9
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/dist/AnimotPresenter.svelte +102 -5
- package/dist/cdn/animot-presenter.esm.js +3485 -3436
- package/dist/cdn/animot-presenter.min.js +8 -8
- package/dist/types.d.ts +5 -0
- package/package.json +1 -1
|
@@ -433,6 +433,86 @@
|
|
|
433
433
|
}
|
|
434
434
|
}
|
|
435
435
|
|
|
436
|
+
// Reset presentation to first slide (snap all elements back to initial state)
|
|
437
|
+
async function resetToFirstSlide() {
|
|
438
|
+
if (isTransitioning) return;
|
|
439
|
+
isTransitioning = true;
|
|
440
|
+
clearAllTypewriterAnimations();
|
|
441
|
+
cancelMotionPathLoops();
|
|
442
|
+
const firstSlide = slides[0];
|
|
443
|
+
if (!firstSlide) { isTransitioning = false; return; }
|
|
444
|
+
|
|
445
|
+
for (const elementId of allElementIds) {
|
|
446
|
+
const targetEl = getElementInSlide(firstSlide, elementId);
|
|
447
|
+
const animated = animatedElements.get(elementId);
|
|
448
|
+
if (!animated) continue;
|
|
449
|
+
if (targetEl) {
|
|
450
|
+
animated.x.to(targetEl.position.x, { duration: 0 }); animated.y.to(targetEl.position.y, { duration: 0 });
|
|
451
|
+
animated.width.to(targetEl.size.width, { duration: 0 }); animated.height.to(targetEl.size.height, { duration: 0 });
|
|
452
|
+
animated.rotation.to(targetEl.rotation, { duration: 0 });
|
|
453
|
+
animated.skewX.to(targetEl.skewX ?? 0, { duration: 0 }); animated.skewY.to(targetEl.skewY ?? 0, { duration: 0 });
|
|
454
|
+
animated.tiltX.to(targetEl.tiltX ?? 0, { duration: 0 }); animated.tiltY.to(targetEl.tiltY ?? 0, { duration: 0 });
|
|
455
|
+
animated.perspective.to(targetEl.perspective ?? 1000, { duration: 0 });
|
|
456
|
+
animated.opacity.to((targetEl as any).opacity ?? 1, { duration: 0 });
|
|
457
|
+
animated.borderRadius.to((targetEl as any).borderRadius ?? 0, { duration: 0 });
|
|
458
|
+
animated.blur.to(targetEl.blur ?? 0, { duration: 0 });
|
|
459
|
+
animated.brightness.to(targetEl.brightness ?? 100, { duration: 0 });
|
|
460
|
+
animated.contrast.to(targetEl.contrast ?? 100, { duration: 0 });
|
|
461
|
+
animated.saturate.to(targetEl.saturate ?? 100, { duration: 0 });
|
|
462
|
+
animated.grayscale.to(targetEl.grayscale ?? 0, { duration: 0 });
|
|
463
|
+
if (targetEl.type === 'text' && animated.fontSize) animated.fontSize.to((targetEl as TextElement).fontSize, { duration: 0 });
|
|
464
|
+
if (targetEl.type === 'shape') {
|
|
465
|
+
const s = targetEl as ShapeElement;
|
|
466
|
+
if (animated.fillColor) animated.fillColor.to(s.fillColor, { duration: 0 });
|
|
467
|
+
if (animated.strokeColor) animated.strokeColor.to(s.strokeColor, { duration: 0 });
|
|
468
|
+
if (animated.strokeWidth) animated.strokeWidth.to(s.strokeWidth, { duration: 0 });
|
|
469
|
+
}
|
|
470
|
+
if (animated.motionPathProgress) animated.motionPathProgress.to(0, { duration: 0 });
|
|
471
|
+
} else {
|
|
472
|
+
animated.opacity.to(0, { duration: 0 });
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
for (const elementId of allElementIds) {
|
|
477
|
+
const targetEl = getElementInSlide(firstSlide, elementId);
|
|
478
|
+
if (targetEl) elementContent.set(elementId, JSON.parse(JSON.stringify(targetEl)));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const newPreviousCodeContent = new Map<string, string>();
|
|
482
|
+
for (const element of firstSlide.canvas.elements) {
|
|
483
|
+
if (element.type === 'code') newPreviousCodeContent.set(element.id, (element as CodeElement).code);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
for (const element of firstSlide.canvas.elements) {
|
|
487
|
+
if (element.type === 'code') {
|
|
488
|
+
const codeEl = element as CodeElement;
|
|
489
|
+
const key = `${codeEl.id}-${codeEl.code}-${codeEl.language}-${codeEl.showLineNumbers}`;
|
|
490
|
+
if (!codeHighlights.has(key)) {
|
|
491
|
+
const html = await highlightCode(codeEl.code, codeEl.language, codeEl.theme, { showLineNumbers: codeEl.showLineNumbers });
|
|
492
|
+
codeHighlights.set(key, html);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
codeHighlights = new Map(codeHighlights);
|
|
497
|
+
|
|
498
|
+
codeMorphState = new Map();
|
|
499
|
+
previousCodeContent = newPreviousCodeContent;
|
|
500
|
+
shapeMorphStates = new Map();
|
|
501
|
+
elementContent = new Map(elementContent);
|
|
502
|
+
currentSlideIndex = 0;
|
|
503
|
+
isTransitioning = false;
|
|
504
|
+
|
|
505
|
+
for (const element of firstSlide.canvas.elements) {
|
|
506
|
+
if (element.type === 'text') {
|
|
507
|
+
const textEl = element as TextElement;
|
|
508
|
+
if (textEl.animation?.mode === 'typewriter') startTypewriterAnimation(element.id, textEl.content, textEl.animation.typewriterSpeed || 50);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
animateMotionPaths(firstSlide);
|
|
513
|
+
onslidechange?.(0, slides.length);
|
|
514
|
+
}
|
|
515
|
+
|
|
436
516
|
// Animate to slide
|
|
437
517
|
async function animateToSlide(targetIndex: number) {
|
|
438
518
|
if (isTransitioning || targetIndex < 0 || targetIndex >= slides.length) return;
|
|
@@ -828,17 +908,34 @@
|
|
|
828
908
|
const slideDuration = durationOverride ?? currentSlide?.duration ?? 3000;
|
|
829
909
|
autoplayTimer = setTimeout(() => {
|
|
830
910
|
if (currentSlideIndex < slides.length - 1) animateToSlide(currentSlideIndex + 1);
|
|
831
|
-
else if (loop)
|
|
911
|
+
else if (loop) {
|
|
912
|
+
const loopMode = project?.settings?.loopMode ?? 'reset';
|
|
913
|
+
if (loopMode === 'transition') animateToSlide(0);
|
|
914
|
+
else resetToFirstSlide();
|
|
915
|
+
}
|
|
832
916
|
else isAutoplay = false;
|
|
833
917
|
}, slideDuration);
|
|
834
918
|
}
|
|
835
919
|
$effect(() => { if (isAutoplay && !isTransitioning) scheduleNextSlide(); });
|
|
836
920
|
$effect(() => () => clearAutoplayTimer());
|
|
837
921
|
|
|
922
|
+
function handleNextSlide() {
|
|
923
|
+
if (currentSlideIndex < slides.length - 1) {
|
|
924
|
+
animateToSlide(currentSlideIndex + 1);
|
|
925
|
+
} else if (loop) {
|
|
926
|
+
const loopMode = project?.settings?.loopMode ?? 'reset';
|
|
927
|
+
if (loopMode === 'transition') {
|
|
928
|
+
animateToSlide(0);
|
|
929
|
+
} else {
|
|
930
|
+
resetToFirstSlide();
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
838
935
|
// Keyboard
|
|
839
936
|
function handleKeyDown(e: KeyboardEvent) {
|
|
840
937
|
if (!keyboard) return;
|
|
841
|
-
if (e.key === 'ArrowRight' || e.key === ' ' || e.key === 'Enter') { e.preventDefault();
|
|
938
|
+
if (e.key === 'ArrowRight' || e.key === ' ' || e.key === 'Enter') { e.preventDefault(); handleNextSlide(); }
|
|
842
939
|
else if (e.key === 'ArrowLeft' || e.key === 'Backspace') { e.preventDefault(); animateToSlide(currentSlideIndex - 1); }
|
|
843
940
|
else if (e.key === 'Home') animateToSlide(0);
|
|
844
941
|
else if (e.key === 'End') animateToSlide(slides.length - 1);
|
|
@@ -884,7 +981,7 @@
|
|
|
884
981
|
|
|
885
982
|
// Public API (exposed via bind:this)
|
|
886
983
|
export async function goto(slideIndex: number) { await animateToSlide(slideIndex); }
|
|
887
|
-
export async function next() {
|
|
984
|
+
export async function next() { handleNextSlide(); }
|
|
888
985
|
export async function prev() { await animateToSlide(currentSlideIndex - 1); }
|
|
889
986
|
export function play() { isAutoplay = true; }
|
|
890
987
|
export function pause() { isAutoplay = false; clearAutoplayTimer(); }
|
|
@@ -1227,7 +1324,7 @@
|
|
|
1227
1324
|
<button class="animot-arrow animot-arrow-left" onclick={() => animateToSlide(currentSlideIndex - 1)} disabled={currentSlideIndex === 0 || isTransitioning} aria-label="Previous slide">
|
|
1228
1325
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 18l-6-6 6-6"/></svg>
|
|
1229
1326
|
</button>
|
|
1230
|
-
<button class="animot-arrow animot-arrow-right" onclick={() =>
|
|
1327
|
+
<button class="animot-arrow animot-arrow-right" onclick={() => handleNextSlide()} disabled={(!loop && currentSlideIndex === slides.length - 1) || isTransitioning} aria-label="Next slide">
|
|
1231
1328
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
|
|
1232
1329
|
</button>
|
|
1233
1330
|
{/if}
|
|
@@ -1238,7 +1335,7 @@
|
|
|
1238
1335
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
|
|
1239
1336
|
</button>
|
|
1240
1337
|
<span class="animot-slide-indicator">{currentSlideIndex + 1} / {slides.length}</span>
|
|
1241
|
-
<button onclick={() =>
|
|
1338
|
+
<button onclick={() => handleNextSlide()} disabled={(!loop && currentSlideIndex === slides.length - 1) || isTransitioning} aria-label="Next">
|
|
1242
1339
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
|
|
1243
1340
|
</button>
|
|
1244
1341
|
<button onclick={() => { isAutoplay = !isAutoplay; if (!isAutoplay) clearAutoplayTimer(); }} class:active={isAutoplay} aria-label={isAutoplay ? 'Pause' : 'Play'}>
|