From d8863c3188cf0c4647b70d3dc9ec5f2fffe5525c Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Thu, 4 Apr 2024 11:21:28 -0400 Subject: zoom fade rotate --- src/client/views/nodes/trails/SpringUtils.ts | 111 +++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/client/views/nodes/trails/SpringUtils.ts (limited to 'src/client/views/nodes/trails/SpringUtils.ts') diff --git a/src/client/views/nodes/trails/SpringUtils.ts b/src/client/views/nodes/trails/SpringUtils.ts new file mode 100644 index 000000000..5feb1628a --- /dev/null +++ b/src/client/views/nodes/trails/SpringUtils.ts @@ -0,0 +1,111 @@ +import { PresEffect, PresMovement } from './PresEnums'; + +// the type of slide effect timing (spring-driven) +export enum SpringType { + DEFAULT = 'default', + GENTLE = 'gentle', + BOUNCY = 'bouncy', + CUSTOM = 'custom', + QUICK = 'quick', +} + +// settings that control slide effect spring settings +export interface SpringSettings { + type: SpringType; + stiffness: number; + damping: number; + mass: number; +} + +export const easeItems = [ + { + text: 'Ease', + val: 'ease', + }, + { + text: 'Ease In', + val: 'ease-in', + }, + { + text: 'Ease Out', + val: 'ease-out', + }, + { + text: 'Ease In Out', + val: 'ease-in-out', + }, + { + text: 'Linear', + val: 'linear', + }, + { + text: 'Custom', + val: 'custom', + }, +]; + +export const movementItems = [ + { text: 'None', val: PresMovement.None }, + { text: 'Center', val: PresMovement.Center }, + { text: 'Zoom', val: PresMovement.Zoom }, + { text: 'Pan', val: PresMovement.Pan }, + { text: 'Jump', val: PresMovement.Jump }, +]; + +export const effectItems = Object.values(PresEffect) + .filter(v => isNaN(Number(v))) + .map(effect => ({ + text: effect, + val: effect, + })); + +export const effectTimings = [ + { text: 'Default', val: SpringType.DEFAULT }, + { + text: 'Gentle', + val: SpringType.GENTLE, + }, + { + text: 'Quick', + val: SpringType.QUICK, + }, + { + text: 'Bouncy', + val: SpringType.BOUNCY, + }, + { + text: 'Custom', + val: SpringType.CUSTOM, + }, +]; + +// Maps spring names to spring parameters +export const springMappings: { + [key: string]: { stiffness: number; damping: number; mass: number }; +} = { + default: { + stiffness: 600, + damping: 15, + mass: 1, + }, + gentle: { + stiffness: 100, + damping: 15, + mass: 1, + }, + quick: { + stiffness: 300, + damping: 20, + mass: 1, + }, + bouncy: { + stiffness: 600, + damping: 15, + mass: 1, + }, + custom: { + stiffness: 100, + damping: 10, + mass: 1, + }, +}; -- cgit v1.2.3-70-g09d2 From 6e3f78c394e0703465344705987ce3fd4bedd756 Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Tue, 9 Apr 2024 17:28:52 -0400 Subject: setting a default timing for certain effects --- src/client/views/nodes/trails/PresBox.tsx | 4 ++- src/client/views/nodes/trails/SpringUtils.ts | 48 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) (limited to 'src/client/views/nodes/trails/SpringUtils.ts') diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index d3abaddd9..3f546cdd7 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -48,7 +48,7 @@ import CubicBezierEditor, { TIMING_DEFAULT_MAPPINGS } from './CubicBezierEditor' import Slider from '@mui/material/Slider'; import { FaArrowDown, FaArrowLeft, FaArrowRight, FaArrowUp, FaCompressArrowsAlt } from 'react-icons/fa'; import SpringAnimationPreview from './SlideEffectPreview'; -import { effectTimings, SpringType, springMappings, effectItems, easeItems, movementItems, SpringSettings } from './SpringUtils'; +import { effectTimings, SpringType, springMappings, effectItems, easeItems, movementItems, SpringSettings, presEffectDefaultTimings } from './SpringUtils'; export interface pinDataTypes { scrollable?: boolean; @@ -2156,6 +2156,8 @@ export class PresBox extends ViewBoxBaseComponent() { selectedVal={effect?.toString()} setSelectedVal={val => { this.updateEffect(val as PresEffect, false); + // set default spring options for that effect + this.updateEffectTiming(activeItem, presEffectDefaultTimings[val as keyof typeof presEffectDefaultTimings]); }} dropdownType={DropdownType.SELECT} type={Type.TERT} diff --git a/src/client/views/nodes/trails/SpringUtils.ts b/src/client/views/nodes/trails/SpringUtils.ts index 5feb1628a..caadf4220 100644 --- a/src/client/views/nodes/trails/SpringUtils.ts +++ b/src/client/views/nodes/trails/SpringUtils.ts @@ -59,6 +59,54 @@ export const effectItems = Object.values(PresEffect) val: effect, })); +export const presEffectDefaultTimings: { + [key: string]: SpringSettings; +} = { + Zoom: { type: SpringType.GENTLE, stiffness: 100, damping: 15, mass: 1 }, + Bounce: { + type: SpringType.BOUNCY, + stiffness: 600, + damping: 15, + mass: 1, + }, + Lightspeed: { + type: SpringType.GENTLE, + stiffness: 100, + damping: 15, + mass: 1, + }, + Fade: { + type: SpringType.GENTLE, + stiffness: 100, + damping: 15, + mass: 1, + }, + Flip: { + type: SpringType.GENTLE, + stiffness: 100, + damping: 15, + mass: 1, + }, + Rotate: { + type: SpringType.GENTLE, + stiffness: 100, + damping: 15, + mass: 1, + }, + Roll: { + type: SpringType.GENTLE, + stiffness: 100, + damping: 15, + mass: 1, + }, + None: { + type: SpringType.GENTLE, + stiffness: 100, + damping: 15, + mass: 1, + }, +}; + export const effectTimings = [ { text: 'Default', val: SpringType.DEFAULT }, { -- cgit v1.2.3-70-g09d2 From 43569b25466aa9bcf19f0f78c6ccd0928c98ab05 Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Wed, 10 Apr 2024 15:26:32 -0400 Subject: fix: naming, cleaning --- src/client/views/nodes/DocumentView.tsx | 22 +++++------ src/client/views/nodes/trails/PresBox.tsx | 2 +- src/client/views/nodes/trails/SlideEffect.tsx | 44 ++++++++-------------- .../views/nodes/trails/SlideEffectPreview.tsx | 44 +--------------------- src/client/views/nodes/trails/SpringUtils.ts | 9 +++-- 5 files changed, 35 insertions(+), 86 deletions(-) (limited to 'src/client/views/nodes/trails/SpringUtils.ts') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 01c1de137..1e71e2a99 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -50,8 +50,8 @@ import { KeyValueBox } from './KeyValueBox'; import { LinkAnchorBox } from './LinkAnchorBox'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { PresEffect, PresEffectDirection } from './trails'; -import SlideEffect, { EffectType } from './trails/SlideEffect'; -import { SpringSettings, SpringType } from './trails/SpringUtils'; +import SlideEffect from './trails/SlideEffect'; +import { SpringSettings, SpringType, springMappings } from './trails/SpringUtils'; interface Window { MediaRecorder: MediaRecorder; } @@ -1016,10 +1016,8 @@ export class DocumentViewInternal extends DocComponent{renderDoc} - case PresEffect.Fade: return {renderDoc} + case PresEffect.Zoom: return {renderDoc} + case PresEffect.Fade: return {renderDoc} case PresEffect.Flip: return {renderDoc}; - case PresEffect.Rotate: return {renderDoc} - // Changed to move in since anything can be "bouncy" - case PresEffect.Bounce: return {renderDoc} + case PresEffect.Rotate: return {renderDoc} + // Potential change to move in since anything can be "bouncy" + case PresEffect.Bounce: return {renderDoc} case PresEffect.Roll: return {renderDoc}; - case PresEffect.Lightspeed: return {renderDoc}; + // case PresEffect.Lightspeed: return {renderDoc}; } // switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) { // default: diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 3f546cdd7..3b712a4af 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1907,7 +1907,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (!timingConfig) { timingConfig = { - type: SpringType.DEFAULT, + type: SpringType.GENTLE, // stiffness: 300, // damping: 12, // mass: 2, diff --git a/src/client/views/nodes/trails/SlideEffect.tsx b/src/client/views/nodes/trails/SlideEffect.tsx index 7e2985a6a..e3423069b 100644 --- a/src/client/views/nodes/trails/SlideEffect.tsx +++ b/src/client/views/nodes/trails/SlideEffect.tsx @@ -1,18 +1,10 @@ -import { Button } from '@mui/material'; import { useSpring, animated, easings, to } from '@react-spring/web'; import React, { useEffect, useState } from 'react'; -import { PresEffectDirection } from './PresEnums'; - -export enum EffectType { - ZOOM = 'zoom', - FADE = 'fade', - BOUNCE = 'bounce', - ROTATE = 'rotate', -} +import { PresEffect, PresEffectDirection } from './PresEnums'; interface Props { dir: PresEffectDirection; - effectType: EffectType; + presEffect: PresEffect; friction: number; tension: number; mass: number; @@ -20,7 +12,7 @@ interface Props { } // TODO: add visibility detector when the slide comes into view -export default function SpringAnimation({ dir, friction, tension, mass, effectType, children }: Props) { +export default function SpringAnimation({ dir, friction, tension, mass, presEffect: presEffect, children }: Props) { const [springs, api] = useSpring( () => ({ from: { @@ -53,14 +45,12 @@ export default function SpringAnimation({ dir, friction, tension, mass, effectTy x: 0, y: 0, opacity: 1, - // opacity: 0, }, to: { scale: 1, x: 0, y: 0, opacity: 1, - // opacity: 1, config: { tension: tension, friction: friction, @@ -164,36 +154,34 @@ export default function SpringAnimation({ dir, friction, tension, mass, effectTy ], }; - const handleClick = () => { - if (effectType === EffectType.BOUNCE) { + const flipConfig = {}; + + const startAnimation = () => { + if (presEffect === PresEffect.Bounce) { api.start(bounceConfig); - } else if (effectType === EffectType.ZOOM) { + } else if (presEffect === PresEffect.Zoom) { api.start(zoomConfig); - } else if (effectType === EffectType.ROTATE) { + } else if (presEffect === PresEffect.Rotate) { api.start(rotateConfig); - } else if (effectType === EffectType.FADE) { + } else if (presEffect === PresEffect.Fade) { api.start(fadeConfig); } }; + const flipRender = () => {}; + useEffect(() => { + // TODO: Control start with slide visibility instead setTimeout(() => { - handleClick(); + startAnimation(); }, 200); }, []); return ( -
{ - // handleClick(); - // }} - > - {effectType !== EffectType.ROTATE ? ( +
+ {presEffect !== PresEffect.Rotate ? ( {children} diff --git a/src/client/views/nodes/trails/SlideEffectPreview.tsx b/src/client/views/nodes/trails/SlideEffectPreview.tsx index aacb37b48..d4c16586a 100644 --- a/src/client/views/nodes/trails/SlideEffectPreview.tsx +++ b/src/client/views/nodes/trails/SlideEffectPreview.tsx @@ -1,4 +1,3 @@ -import { Button } from '@mui/material'; import { useSpring, animated, easings } from '@react-spring/web'; import React, { useEffect, useState } from 'react'; @@ -24,10 +23,10 @@ export default function SpringAnimationPreview({ friction, tension, mass, childr mass: mass, }, onStart: () => { - console.log('started'); + // console.log('started'); }, onRest: () => { - console.log('resting'); + // console.log('resting'); }, }), [tension, friction, mass] @@ -36,38 +35,6 @@ export default function SpringAnimationPreview({ friction, tension, mass, childr // Whether the animation is currently playing const [animating, setAnimating] = useState(false); - const zoomConfig = { - from: { - x: 0, - y: 0, - opacity: 0, - scale: 0, - }, - to: [ - { - x: 0, - y: 0, - opacity: 1, - scale: 1, - config: { - tension: tension, - friction: friction, - mass: mass, - }, - }, - { - opacity: 0, - scale: 0, - x: 0, - y: 0, - config: { - duration: 500, - easing: easings.easeInOutCubic, - }, - }, - ], - }; - const bounceConfig = { from: { x: -50, @@ -116,13 +83,6 @@ export default function SpringAnimationPreview({ friction, tension, mass, childr onPointerEnter={() => { animate(); }}> - {/* style={{ - width: "50px", - height: "50px", - backgroundColor: "#ff6d6d", - borderRadius: "4px", - ...springs, - }} */} isNaN(Number(v))) .map(effect => ({ @@ -59,6 +61,7 @@ export const effectItems = Object.values(PresEffect) val: effect, })); +// Maps each PresEffect to the default timing configuration export const presEffectDefaultTimings: { [key: string]: SpringSettings; } = { @@ -107,8 +110,8 @@ export const presEffectDefaultTimings: { }, }; +// Dropdown items of timings for the effect export const effectTimings = [ - { text: 'Default', val: SpringType.DEFAULT }, { text: 'Gentle', val: SpringType.GENTLE, -- cgit v1.2.3-70-g09d2 From 219f023202658414b09c5245c807c1bb6cdc4285 Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Thu, 25 Apr 2024 11:17:35 -0400 Subject: ui framework for effect animations --- src/client/apis/gpt/customization.ts | 26 ++- src/client/views/nodes/DocumentView.tsx | 12 +- src/client/views/nodes/trails/PresBox.scss | 29 +++ src/client/views/nodes/trails/PresBox.tsx | 241 ++++++++++++++----------- src/client/views/nodes/trails/SlideEffect.scss | 2 +- src/client/views/nodes/trails/SlideEffect.tsx | 86 ++++++--- src/client/views/nodes/trails/SpringUtils.ts | 9 + 7 files changed, 259 insertions(+), 146 deletions(-) (limited to 'src/client/views/nodes/trails/SpringUtils.ts') diff --git a/src/client/apis/gpt/customization.ts b/src/client/apis/gpt/customization.ts index 8960bc651..a1ab2bd5f 100644 --- a/src/client/apis/gpt/customization.ts +++ b/src/client/apis/gpt/customization.ts @@ -39,8 +39,27 @@ const setupPresSlideCustomization = () => { setupPresSlideCustomization(); -export const gptTrailSlideCustomization = async (inputText: string, properties: any) => { - console.log('properties', properties); +export const getSlideTransitionSuggestions = async (inputText: string, properties: any) => { + /** + * Prompt: Generate an entrance animations from slower and gentler + * to bouncier and more high energy + * + * Format: + * { + * name: Slow Fade, Quick Flip, Springy + * effect: BOUNCE + * effectDirection: LEFT + * timingConfig: { + * + * + * + * } + * } + */ + const res = await new Promise(resolve => resolve('result')); +}; + +export const gptTrailSlideCustomization = async (inputText: string, properties: any | any[], applyToWhole?: boolean) => { let prompt = prompts.trails.description; prompts.trails.features.forEach(feature => { @@ -50,9 +69,6 @@ export const gptTrailSlideCustomization = async (inputText: string, properties: } }); - // prompt += - // 'title is the title/name of the slide. presentation_transition is a number in milliseconds for how long it should take to transition/move to a slide. presentation_effect is an effect applied to the slide when we transition to it. Its only possible values are: [None, Fade in, Flip, Rotate, Bounce, Roll]. presentation_effectDirection is what direction the effect is applied. Its only possible values are: [Enter from left, Enter from right, Enter from bottom, Enter from Top, Enter from center]. config_zoom is a number from 0 to 1.0 indicating the percentage we should zoom into the slide.'; - prompt += 'Set unchanged values to null. Please only return the json with these keys and their values.'; console.log('messages', [ diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 801d96b35..b372c1927 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1031,12 +1031,12 @@ export class DocumentViewInternal extends DocComponent{renderDoc} - case PresEffect.Fade: return {renderDoc} - case PresEffect.Flip: return {renderDoc} - case PresEffect.Rotate: return {renderDoc} - case PresEffect.Bounce: return {renderDoc} - case PresEffect.Roll: return {renderDoc} + case PresEffect.Zoom: return {renderDoc} + case PresEffect.Fade: return {renderDoc} + case PresEffect.Flip: return {renderDoc} + case PresEffect.Rotate: return {renderDoc} + case PresEffect.Bounce: return {renderDoc} + case PresEffect.Roll: return {renderDoc} // keep as preset, doesn't really make sense with spring config case PresEffect.Lightspeed: return {renderDoc}; } diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss index adc59d812..09de4b0f4 100644 --- a/src/client/views/nodes/trails/PresBox.scss +++ b/src/client/views/nodes/trails/PresBox.scss @@ -36,6 +36,35 @@ overflow-y: hidden; } +// Effect Animations + +.presBox-effect-row { + display: flex; + gap: 4px; + margin: 4px; +} + +.presBox-effect-container { + overflow: hidden; + position: relative; + width: 80px; + height: 80px; + /* background-color: #1f2028; */ + border: 1px solid rgb(118, 118, 118); + border-radius: 8px; +} + +.presBox-effect-demo-box { + width: 40px; + height: 40px; + position: absolute; + top: 20px; + left: 20px; + border-radius: 4px; + // default bg + background-color: rgb(37, 161, 255); +} + // Bezier editor .presBox-show-hide-dropdown { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 5ce010cf7..9644935b2 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -49,6 +49,7 @@ import Slider from '@mui/material/Slider'; import { FaArrowDown, FaArrowLeft, FaArrowRight, FaArrowUp, FaCompressArrowsAlt } from 'react-icons/fa'; import SpringAnimationPreview from './SlideEffectPreview'; import { effectTimings, SpringType, springMappings, effectItems, easeItems, movementItems, SpringSettings, presEffectDefaultTimings } from './SpringUtils'; +import SlideEffect from './SlideEffect'; export interface pinDataTypes { scrollable?: boolean; @@ -1322,7 +1323,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.updateCurrentPresentation(DocCast(doc.embedContainer)); }; - //Command click + // Command click @action multiSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => { if (!this.selectedArray.has(doc)) { @@ -1666,6 +1667,7 @@ export class PresBox extends ViewBoxBaseComponent() { PresBox._sliderBatch.end(); document.removeEventListener('pointerup', PresBox.endBatch, true); }; + public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void, hmargin?: number) => { return (
() { ); }; + // Applies the slide transiiton settings to all docs in the array @undoBatch applyTo = (array: Doc[]) => { this.updateMovement(this.activeItem.presentation_movement as PresMovement, true); @@ -2145,16 +2148,6 @@ export class PresBox extends ViewBoxBaseComponent() { onClick={() => (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} color={SettingsManager.userColor} /> - {/*
-
Play Audio Annotation
- (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} - checked={BoolCast(activeItem.presPlayAudio)} - /> -
*/} () { onClick={() => (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))} color={SettingsManager.userColor} /> - {/*
-
Zoom Text Selections
- (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))} - checked={BoolCast(activeItem.presentation_zoomText)} - /> -
*/} {/* Effect dropdown */} () { dropdownType={DropdownType.SELECT} type={Type.TERT} /> - {/*
{ - e.stopPropagation(); - this._openEffectDropdown = !this._openEffectDropdown; - })} - style={{ - color: SettingsManager.userColor, - background: SettingsManager.userVariantColor, - borderBottomLeftRadius: this._openEffectDropdown ? 0 : 5, - border: this._openEffectDropdown ? `solid 2px ${SettingsManager.userVariantColor}` : `solid 1px ${SettingsManager.userColor}`, - }}> - {effect?.toString()} - -
e.stopPropagation()}> - {Object.values(PresEffect) - .filter(v => isNaN(Number(v))) - .map(effect => preseEffect(effect))} + {/* Effect generations */} +
+ {/* Chat for idea generation */} +
+

Customize with GPT

+
+
+ (this._inputref = r)} + minRows={1} + placeholder="Customize..." + className="pres-chatbox" + autoFocus={true} + value={this.chatInput} + onChange={e => { + this.setChatInput(e.target.value); + }} + onKeyDown={e => { + this.stopDictation(true); + e.stopPropagation(); + }} + /> + } + onClick={() => { + if (!this.isRecording) { + this.recordDictation(); + } else { + this.stopDictation(true); + } + }} + /> +
+
-
*/} + {/* Preview Animations */} +
+
+ +
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
{/* Effect direction */} {/* Only applies to certain effects */} - {effect === PresEffect.Flip || - effect === PresEffect.Bounce || - (effect === PresEffect.Roll && ( - <> -
-
Effect direction
-
- {StrCast(this.activeItem.presentation_effectDirection)} -
+ {(effect === PresEffect.Flip || effect === PresEffect.Bounce || effect === PresEffect.Roll) && ( + <> +
+
Effect direction
+
+ {StrCast(this.activeItem.presentation_effectDirection)}
-
- +
+ {/* } onClick={() => this.updateEffectDirection(PresEffectDirection.Center)} - /> - } - onClick={() => this.updateEffectDirection(PresEffectDirection.Left)} - /> - } - onClick={() => this.updateEffectDirection(PresEffectDirection.Right)} - /> - {effect !== PresEffect.Roll && ( - <> - } - onClick={() => this.updateEffectDirection(PresEffectDirection.Top)} - /> - } - onClick={() => this.updateEffectDirection(PresEffectDirection.Bottom)} - /> - - )} -
- - ))} + /> */} + } + onClick={() => this.updateEffectDirection(PresEffectDirection.Left)} + /> + } + onClick={() => this.updateEffectDirection(PresEffectDirection.Right)} + /> + {effect !== PresEffect.Roll && ( + <> + } + onClick={() => this.updateEffectDirection(PresEffectDirection.Top)} + /> + } + onClick={() => this.updateEffectDirection(PresEffectDirection.Bottom)} + /> + + )} +
+ + )} {/* Spring settings */} {/* No spring settings for jackinthebox (lightspeed) */} -
{ - e.stopPropagation(); - this.setSpringEditorVisibility(!this.showSpringEditor); - }}> - {`${this.showSpringEditor ? 'Hide' : 'Show'} Spring Settings`} - -
{effect !== PresEffect.Lightspeed && ( <> () { dropdownType={DropdownType.SELECT} type={Type.TERT} /> +
{ + e.stopPropagation(); + this.setSpringEditorVisibility(!this.showSpringEditor); + }}> + {`${this.showSpringEditor ? 'Hide' : 'Show'} Spring Settings`} + +
{this.showSpringEditor && ( <>
Tension
@@ -2363,11 +2391,12 @@ export class PresBox extends ViewBoxBaseComponent() { )} {/* Effect spring settings */}
-
+
*/}
); diff --git a/src/client/views/nodes/trails/SlideEffect.scss b/src/client/views/nodes/trails/SlideEffect.scss index 144052c1f..cadda0ccc 100644 --- a/src/client/views/nodes/trails/SlideEffect.scss +++ b/src/client/views/nodes/trails/SlideEffect.scss @@ -20,5 +20,5 @@ .flip-back { // Get the background color of node instead - background-color: rgb(223, 223, 223); + // background-color: rgb(223, 223, 223); } diff --git a/src/client/views/nodes/trails/SlideEffect.tsx b/src/client/views/nodes/trails/SlideEffect.tsx index bd667b925..251649d6a 100644 --- a/src/client/views/nodes/trails/SlideEffect.tsx +++ b/src/client/views/nodes/trails/SlideEffect.tsx @@ -7,20 +7,26 @@ import { NumCast } from '../../../../fields/Types'; interface Props { // pass in doc to extract width, height, bg - doc: Doc; - // wait for the transition movement to end before starting effect - delay: number; + doc?: Doc; dir: PresEffectDirection; presEffect: PresEffect; friction: number; tension: number; mass: number; children: React.ReactNode; + infinite?: boolean; } +const DEFAULT_WIDTH = 40; +const PREVIEW_OFFSET = 60; +const ACTUAL_OFFSET = 200; +const infiniteOptions = { + loop: true, + delay: 500, +}; + // TODO: add visibility detector when the slide comes into view -export default function SpringAnimation({ doc, delay, dir, friction, tension, mass, presEffect, children }: Props) { - console.log('delay:', delay); +export default function SpringAnimation({ doc, dir, friction, tension, mass, presEffect, children, infinite }: Props) { const [springs, api] = useSpring( () => ({ from: { @@ -34,12 +40,8 @@ export default function SpringAnimation({ doc, delay, dir, friction, tension, ma friction: friction, mass: mass, }, - onStart: () => { - console.log('started'); - }, - onRest: () => { - console.log('resting'); - }, + onStart: () => {}, + onRest: () => {}, }), [tension, friction, mass] ); @@ -110,7 +112,7 @@ export default function SpringAnimation({ doc, delay, dir, friction, tension, ma return { from: { opacity: 0, - x: -200, + x: infinite ? -PREVIEW_OFFSET : -ACTUAL_OFFSET, y: 0, }, }; @@ -118,7 +120,7 @@ export default function SpringAnimation({ doc, delay, dir, friction, tension, ma return { from: { opacity: 0, - x: 200, + x: infinite ? PREVIEW_OFFSET : ACTUAL_OFFSET, y: 0, }, }; @@ -127,7 +129,7 @@ export default function SpringAnimation({ doc, delay, dir, friction, tension, ma from: { opacity: 0, x: 0, - y: -200, + y: infinite ? -PREVIEW_OFFSET : -ACTUAL_OFFSET, }, }; case PresEffectDirection.Bottom: @@ -135,7 +137,7 @@ export default function SpringAnimation({ doc, delay, dir, friction, tension, ma from: { opacity: 0, x: 0, - y: 200, + y: infinite ? PREVIEW_OFFSET : ACTUAL_OFFSET, }, }; default: @@ -164,6 +166,7 @@ export default function SpringAnimation({ doc, delay, dir, friction, tension, ma }, }, ], + loop: true, }; const flipConfig = { @@ -196,7 +199,7 @@ export default function SpringAnimation({ doc, delay, dir, friction, tension, ma from: { opacity: 0, x: 100, - y: -120, + y: 120, }, }; case PresEffectDirection.Top: @@ -246,35 +249,41 @@ export default function SpringAnimation({ doc, delay, dir, friction, tension, ma opacity: 0, }, to: [], - loop: true, }; // Switch animation depending on slide effect const startAnimation = () => { + let config: any = zoomConfig; switch (presEffect) { case PresEffect.Bounce: - api.start(bounceConfig); + config = bounceConfig; break; case PresEffect.Zoom: - api.start(zoomConfig); + config = zoomConfig; break; case PresEffect.Rotate: - api.start(rotateConfig); + config = rotateConfig; break; case PresEffect.Fade: - api.start(fadeConfig); + config = fadeConfig; break; case PresEffect.Flip: - api.start(flipConfig); + config = flipConfig; break; case PresEffect.Roll: - api.start(rollConfig); + config = rollConfig; break; case PresEffect.Lightspeed: break; default: break; } + + if (infinite) { + config = { ...config, ...infiniteOptions }; + } + + api.start(config); }; // const flipRender = () => { @@ -308,15 +317,30 @@ export default function SpringAnimation({ doc, delay, dir, friction, tension, ma
{dir === PresEffectDirection.Bottom || dir === PresEffectDirection.Top ? ( <> - `perspective(600px) rotateX(${val}deg)`), width: NumCast(doc.width), height: NumCast(doc.height) }} /> - `perspective(600px) rotateX(${val}deg)`), rotateX: '180deg', width: NumCast(doc.width), height: NumCast(doc.height) }}> + `perspective(600px) rotateX(${val}deg)`), + width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, + height: doc ? NumCast(doc.height) : DEFAULT_WIDTH, + backgroundColor: infinite ? '#a825ff' : 'rgb(223, 223, 223);', + }} + /> + `perspective(600px) rotateX(${val}deg)`), rotateX: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}> {children} ) : ( <> - `perspective(600px) rotateY(${val}deg)`), width: NumCast(doc.width), height: NumCast(doc.height) }} /> - `perspective(600px) rotateY(${val}deg)`), rotateY: '180deg', width: NumCast(doc.width), height: NumCast(doc.height) }}> + `perspective(600px) rotateY(${val}deg)`), width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }} + /> + `perspective(600px) rotateY(${val}deg)`), rotateY: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}> {children} @@ -350,7 +374,7 @@ export default function SpringAnimation({ doc, delay, dir, friction, tension, ma // }, []); useEffect(() => { - if (!inView) return; + if (infinite || !inView) return; console.log('in view'); // TODO: Control start with slide visibility instead setTimeout(() => { @@ -358,5 +382,11 @@ export default function SpringAnimation({ doc, delay, dir, friction, tension, ma }, 100); }, [inView]); + useEffect(() => { + if (infinite) { + startAnimation(); + } + }, []); + return
{getRenderDoc()}
; } diff --git a/src/client/views/nodes/trails/SpringUtils.ts b/src/client/views/nodes/trails/SpringUtils.ts index 0518e0623..42a0add84 100644 --- a/src/client/views/nodes/trails/SpringUtils.ts +++ b/src/client/views/nodes/trails/SpringUtils.ts @@ -16,6 +16,15 @@ export interface SpringSettings { mass: number; } +// Overall config + +export interface AnimationSettings { + effect: PresEffect; + stiffness: number; + damping: number; + mass: number; +} + // Options in the movement easing dropdown export const easeItems = [ { -- cgit v1.2.3-70-g09d2 From b42ad09912393ec1ae5799100bdf7a5786055a55 Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Thu, 2 May 2024 11:44:31 -0400 Subject: focus --- src/client/views/nodes/DocumentView.tsx | 12 +- .../views/nodes/trails/CubicBezierEditor.tsx | 21 +- src/client/views/nodes/trails/PresBox.tsx | 356 +++++++++++---------- src/client/views/nodes/trails/SlideEffect.tsx | 1 + src/client/views/nodes/trails/SpringUtils.ts | 1 + 5 files changed, 202 insertions(+), 189 deletions(-) (limited to 'src/client/views/nodes/trails/SpringUtils.ts') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 8c9318743..b372c1927 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1031,12 +1031,12 @@ export class DocumentViewInternal extends DocComponent{renderDoc} - case PresEffect.Fade: return {renderDoc} - case PresEffect.Flip: return {renderDoc} - case PresEffect.Rotate: return {renderDoc} - case PresEffect.Bounce: return {renderDoc} - case PresEffect.Roll: return {renderDoc} + case PresEffect.Zoom: return {renderDoc} + case PresEffect.Fade: return {renderDoc} + case PresEffect.Flip: return {renderDoc} + case PresEffect.Rotate: return {renderDoc} + case PresEffect.Bounce: return {renderDoc} + case PresEffect.Roll: return {renderDoc} // keep as preset, doesn't really make sense with spring config case PresEffect.Lightspeed: return {renderDoc}; } diff --git a/src/client/views/nodes/trails/CubicBezierEditor.tsx b/src/client/views/nodes/trails/CubicBezierEditor.tsx index f1a0a16ec..db3eb2e26 100644 --- a/src/client/views/nodes/trails/CubicBezierEditor.tsx +++ b/src/client/views/nodes/trails/CubicBezierEditor.tsx @@ -41,7 +41,6 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => { }; const convertToPoints = (func: string) => { - console.log('getting curr c points'); let strPoints = func ? func : 'ease'; if (!strPoints.startsWith('cubic')) { switch (func) { @@ -64,13 +63,11 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => { strPoints = 'cubic-bezier(0.25, 0.1, 0.25, 1.0)'; } } - console.log('str points', strPoints); const components = strPoints .split('(')[1] .split(')')[0] .split(',') .map(elem => parseFloat(elem)); - console.log('bezier components', components); return { p1: [components[0], components[1]], p2: [components[2], components[3]], @@ -145,15 +142,15 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => { return (
{ - // e.stopPropagation; - // }} - // onPointerMove={e => { - // e.stopPropagation; - // }} - // onPointerUp={e => { - // e.stopPropagation; - // }} + // onPointerDown={e => { + // e.stopPropagation; + // }} + onPointerMove={e => { + e.stopPropagation; + }} + // onPointerUp={e => { + // e.stopPropagation; + // }} > {/* Outlines */} diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index d03e2c41e..964b793bd 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -40,7 +40,7 @@ import ReactLoading from 'react-loading'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; import ReactTextareaAutosize from 'react-textarea-autosize'; import { Button, Dropdown, DropdownType, IconButton, Toggle, ToggleType, Type } from 'browndash-components'; -import { BiMicrophone, BiX } from 'react-icons/bi'; +import { BiMicrophone } from 'react-icons/bi'; import { AiOutlineSend } from 'react-icons/ai'; import { getSlideTransitionSuggestions, gptSlideProperties, gptTrailSlideCustomization } from '../../../apis/gpt/customization'; import { DictationManager } from '../../../util/DictationManager'; @@ -48,7 +48,7 @@ import CubicBezierEditor, { TIMING_DEFAULT_MAPPINGS } from './CubicBezierEditor' import Slider from '@mui/material/Slider'; import { FaArrowDown, FaArrowLeft, FaArrowRight, FaArrowUp, FaCompressArrowsAlt } from 'react-icons/fa'; import SpringAnimationPreview from './SlideEffectPreview'; -import { effectTimings, SpringType, springMappings, effectItems, easeItems, movementItems, SpringSettings, presEffectDefaultTimings, AnimationSettings } from './SpringUtils'; +import { effectTimings, SpringType, springMappings, effectItems, easeItems, movementItems, SpringSettings, presEffectDefaultTimings, AnimationSettings, springPreviewColors } from './SpringUtils'; import SlideEffect from './SlideEffect'; export interface pinDataTypes { @@ -129,30 +129,31 @@ export class PresBox extends ViewBoxBaseComponent() { @observable isLoading: boolean = false; @observable generatedAnimations: AnimationSettings[] = [ - // { - // effect: PresEffect.Bounce, - // stiffness: 400, - // damping: 15, - // mass: 1, - // }, - // { - // effect: PresEffect.Fade, - // stiffness: 100, - // damping: 15, - // mass: 1, - // }, - // { - // effect: PresEffect.Flip, - // stiffness: 100, - // damping: 15, - // mass: 1, - // }, - // { - // effect: PresEffect.Roll, - // stiffness: 100, - // damping: 15, - // mass: 1, - // }, + // default presets + { + effect: PresEffect.Bounce, + stiffness: 400, + damping: 15, + mass: 1, + }, + { + effect: PresEffect.Fade, + stiffness: 100, + damping: 15, + mass: 1, + }, + { + effect: PresEffect.Flip, + stiffness: 100, + damping: 15, + mass: 1, + }, + { + effect: PresEffect.Roll, + stiffness: 100, + damping: 15, + mass: 1, + }, ]; @action @@ -2080,6 +2081,53 @@ export class PresBox extends ViewBoxBaseComponent() { />
+
+
+
+ (this._inputref2 = r)} + minRows={1} + placeholder="Get transition suggestions..." + className="pres-chatbox" + autoFocus={true} + value={this.animationChat} + onChange={e => { + this.setAnimationChat(e.target.value); + }} + onKeyDown={e => { + this.stopDictation(true); + e.stopPropagation(); + }} + /> + {/* (this._inputref2 = r)} + minRows={1} + placeholder="Get animation suggestions..." + className="pres-chatbox" + autoFocus={true} + value={this.animationChat} + onChange={e => { + this.setAnimationChat(e.target.value); + }} + onKeyDown={e => { + this.stopDictation(true); + e.stopPropagation(); + }} + /> */} +
+
+
() { this._openEffectDropdown = false; this._openBulletEffectDropdown = false; })}> -
- Movement - { - this.updateMovement(val as PresMovement); - }} - dropdownType={DropdownType.SELECT} - type={Type.TERT} - /> -
-
Zoom (% screen filled)
-
- this.updateZoom(e.target.value)} />% -
- {/*
-
this.updateZoom(String(zoom), 0.1)}> - -
-
this.updateZoom(String(zoom), -0.1)}> - -
-
*/} -
- {PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)} -
-
Transition Time
-
- e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s -
- {/*
-
this.updateTransitionTime(String(transitionSpeed), 1000)}> - -
-
this.updateTransitionTime(String(transitionSpeed), -1000)}> - -
-
*/} -
- {PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.updateTransitionTime)} -
-
Fast
-
Medium
-
Slow
-
- {/* Easing function */} -
- { - if (typeof val === 'string') { - if (val !== 'custom') { - this.setBezierEditorVisibility(true); - this.setEaseFunc(this.activeItem, val); - } else { - this.setEaseFunc(this.activeItem, TIMING_DEFAULT_MAPPINGS.ease); - } - } - }} - dropdownType={DropdownType.SELECT} - type={Type.TERT} - /> - {/* Custom */} -
{ - e.stopPropagation(); - this.setBezierEditorVisibility(!this.showBezierEditor); - }}> - {`${this.showBezierEditor ? 'Hide' : 'Show'} Timing Editor`} - -
- {this.showBezierEditor && ( - <> -

- Custom Timing Function -

- - - )} -
-
Effects - (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} - color={SettingsManager.userColor} - /> - (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))} - color={SettingsManager.userColor} - /> {/* Effect dropdown */} () { {/* Effect generations */}
{/* Chat for idea generation */} -
-

Customize with GPT

-
-
{ - StopEvent(e); - }}> - (this._inputref2 = r)} - minRows={1} - placeholder="Get animation suggestions..." - className="pres-chatbox" - autoFocus={true} - value={this.animationChat} - onChange={e => { - this.setAnimationChat(e.target.value); - }} - onKeyDown={e => { - this.stopDictation(true); - e.stopPropagation(); - }} - /> -
-
-
+ {/* Preview Animations */}
{this.generatedAnimations.map((elem, i) => ( @@ -2267,8 +2174,8 @@ export class PresBox extends ViewBoxBaseComponent() { mass: elem.mass, }); }}> - -
+ +
))} @@ -2418,8 +2325,115 @@ export class PresBox extends ViewBoxBaseComponent() { )} )} - {/* Effect spring settings */}
+ {/* Movement */} +
+ Movement + { + this.updateMovement(val as PresMovement); + }} + dropdownType={DropdownType.SELECT} + type={Type.TERT} + /> +
+
Zoom (% screen filled)
+
+ this.updateZoom(e.target.value)} />% +
+ {/*
+
this.updateZoom(String(zoom), 0.1)}> + +
+
this.updateZoom(String(zoom), -0.1)}> + +
+
*/} +
+ {PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)} +
+
Transition Time
+
+ e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s +
+ {/*
+
this.updateTransitionTime(String(transitionSpeed), 1000)}> + +
+
this.updateTransitionTime(String(transitionSpeed), -1000)}> + +
+
*/} +
+ {PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.updateTransitionTime)} +
+
Fast
+
Medium
+
Slow
+
+ {/* Easing function */} +
+ { + if (typeof val === 'string') { + if (val !== 'custom') { + this.setBezierEditorVisibility(true); + this.setEaseFunc(this.activeItem, val); + } else { + this.setEaseFunc(this.activeItem, TIMING_DEFAULT_MAPPINGS.ease); + } + } + }} + dropdownType={DropdownType.SELECT} + type={Type.TERT} + /> + {/* Custom */} +
{ + e.stopPropagation(); + this.setBezierEditorVisibility(!this.showBezierEditor); + }}> + {`${this.showBezierEditor ? 'Hide' : 'Show'} Timing Editor`} + +
+ {this.showBezierEditor && ( + <> +

+ Custom Timing Function +

+ + + )} +
+
+ + {/* Toggles */} + (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} + color={SettingsManager.userColor} + /> + (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))} + color={SettingsManager.userColor} + />
}> -
this.updateEaseFunc(activeItem)}> - {`${StrCast(activeItem.presEaseFunc, 'ease')}`} -
- */}
{[DocumentType.AUDIO, DocumentType.VID].includes(targetType as any as DocumentType) ? null : ( <> @@ -1838,14 +1807,6 @@ export class PresBox extends ViewBoxBaseComponent() {
e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s
- {/*
-
this.updateDurationTime(String(duration), 1000)}> - -
-
this.updateDurationTime(String(duration), -1000)}> - -
-
*/}
{PresBox.inputter('0.1', '0.1', '20', duration, targetType !== DocumentType.AUDIO, this.updateDurationTime)}
@@ -2020,11 +1981,8 @@ export class PresBox extends ViewBoxBaseComponent() {
(this._inputref = r)} - // minRows={1} placeholder="Describe how you would like to modify the slide properties." className="pres-chatbox" - // autoFocus={true} value={this.chatInput} onChange={e => { this.setChatInput(e.target.value); @@ -2118,9 +2076,9 @@ export class PresBox extends ViewBoxBaseComponent() { setSelectedVal={val => { if (typeof val === 'string') { if (val !== 'custom') { - this.setBezierEditorVisibility(true); this.setEaseFunc(this.activeItem, val); } else { + this.setBezierEditorVisibility(true); this.setEaseFunc(this.activeItem, TIMING_DEFAULT_MAPPINGS.ease); } } @@ -2157,11 +2115,8 @@ export class PresBox extends ViewBoxBaseComponent() {
(this._inputref2 = r)} - // minRows={1} placeholder="Customize prompt for effect suggestions. Leave blank for random results." className="pres-chatbox" - // autoFocus={true} value={this.animationChat} onChange={e => { this.setAnimationChat(e.target.value); @@ -2206,6 +2161,7 @@ export class PresBox extends ViewBoxBaseComponent() { className="presBox-effect-container" onClick={() => { this.updateEffect(elem.effect, false); + this.updateEffectDirection(elem.direction); this.updateEffectTiming(this.activeItem, { type: SpringType.CUSTOM, stiffness: elem.stiffness, @@ -2213,7 +2169,7 @@ export class PresBox extends ViewBoxBaseComponent() { mass: elem.mass, }); }}> - +
@@ -2569,23 +2525,6 @@ export class PresBox extends ViewBoxBaseComponent() { />
On slide change
- {/*
- activeItem.mediaStop = "afterSlide"} - checked={activeItem.mediaStop === "afterSlide"} - /> -
- After chosen slide - -
-
*/}
diff --git a/src/client/views/nodes/trails/SpringUtils.ts b/src/client/views/nodes/trails/SpringUtils.ts index 5f1c0c6a9..757f27e18 100644 --- a/src/client/views/nodes/trails/SpringUtils.ts +++ b/src/client/views/nodes/trails/SpringUtils.ts @@ -1,4 +1,4 @@ -import { PresEffect, PresMovement } from './PresEnums'; +import { PresEffect, PresEffectDirection, PresMovement } from './PresEnums'; export const springPreviewColors = ['rgb(37, 161, 255)', 'rgb(99, 37, 255)', 'rgb(182, 37, 255)', 'rgb(255, 37, 168)']; // the type of slide effect timing (spring-driven) @@ -21,6 +21,7 @@ export interface SpringSettings { export interface AnimationSettings { effect: PresEffect; + direction: PresEffectDirection; stiffness: number; damping: number; mass: number; -- cgit v1.2.3-70-g09d2 From ca3f52a9a973f856a8fb667170d0c0dd423b5e4f Mon Sep 17 00:00:00 2001 From: Sophie Zhang Date: Tue, 14 May 2024 14:47:05 -0400 Subject: docs --- src/client/views/nodes/trails/CubicBezierEditor.tsx | 6 ++++-- src/client/views/nodes/trails/PresBox.tsx | 4 +++- src/client/views/nodes/trails/SpringUtils.ts | 4 ++++ 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes/trails/SpringUtils.ts') diff --git a/src/client/views/nodes/trails/CubicBezierEditor.tsx b/src/client/views/nodes/trails/CubicBezierEditor.tsx index 5f348ddd9..a5e21259a 100644 --- a/src/client/views/nodes/trails/CubicBezierEditor.tsx +++ b/src/client/views/nodes/trails/CubicBezierEditor.tsx @@ -7,7 +7,7 @@ type Props = { }; const ANIMATION_DURATION = 750; -const ANIMATION_TIMING_FUNC = 'cubic-bezier(0.3, .2, .2, 1.4)'; + const CONTAINER_WIDTH = 200; const EDITOR_WIDTH = 100; const OFFSET = (CONTAINER_WIDTH - EDITOR_WIDTH) / 2; @@ -21,8 +21,9 @@ export const TIMING_DEFAULT_MAPPINGS = { }; /** - * Visual editor for a bezier curve with draggable control points + * Visual editor for a bezier curve with draggable control points. * */ + const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => { const [animating, setAnimating] = useState(false); const [c1Down, setC1Down] = useState(false); @@ -96,6 +97,7 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => { return () => window.removeEventListener('pointermove', handlePointerMove); }, [c1Down, currPoints]); + // Sets up pointer events for moving the control points useEffect(() => { if (!c2Down) return; window.addEventListener('pointerup', () => { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 2d4a25ff4..632636c85 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1974,7 +1974,7 @@ export class PresBox extends ViewBoxBaseComponent() {
Customize Slide Properties{' '} -
window.open('https://brown-dash.github.io/Dash-Documentation/features/trails/#customizing-slide-transitions')}> +
window.open('https://brown-dash.github.io/Dash-Documentation/features/trails/#transitions')}> } color={SettingsManager.userColor} />
@@ -2100,6 +2100,7 @@ export class PresBox extends ViewBoxBaseComponent() {
+ {/* Cubic bezier editor */} {this.showBezierEditor && (

@@ -2140,6 +2141,7 @@ export class PresBox extends ViewBoxBaseComponent() { />

+
Date: Thu, 16 May 2024 19:52:13 -0400 Subject: refactor/cleanup of pres animations. changed effects to start halfway through a zoom transition. --- src/client/apis/gpt/customization.ts | 18 +- src/client/documents/Documents.ts | 1 + src/client/util/DocumentManager.ts | 6 +- src/client/views/PinFuncs.ts | 2 +- src/client/views/PropertiesView.tsx | 2 +- src/client/views/animationtimeline/Timeline.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 18 +- src/client/views/nodes/trails/PresBox.tsx | 50 +-- src/client/views/nodes/trails/PresEnums.ts | 2 +- src/client/views/nodes/trails/SlideEffect.scss | 2 +- src/client/views/nodes/trails/SlideEffect.tsx | 402 +++++------------------- src/client/views/nodes/trails/SpringUtils.ts | 2 +- 12 files changed, 134 insertions(+), 373 deletions(-) (limited to 'src/client/views/nodes/trails/SpringUtils.ts') diff --git a/src/client/apis/gpt/customization.ts b/src/client/apis/gpt/customization.ts index 61b666bd3..2262886a2 100644 --- a/src/client/apis/gpt/customization.ts +++ b/src/client/apis/gpt/customization.ts @@ -25,13 +25,13 @@ export const addCustomizationProperty = (type: CustomizationType, name: string, // includes most fields but is not yet fully comprehensive export const gptSlideProperties = [ 'title', + 'config_zoom', 'presentation_transition', - 'presEaseFunc', + 'presentation_easeFunc', 'presentation_effect', 'presentation_effectDirection', - 'presEffectTiming', - 'config_zoom', - 'presPlayAudio', + 'presentation_effectTiming', + 'presentation_playAudio', 'presentation_zoomText', 'presentation_hideBefore', 'presentation_hide', @@ -43,20 +43,20 @@ export const gptSlideProperties = [ const setupPresSlideCustomization = () => { addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'title', 'is the title/name of the slide.'); addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_transition', 'is a number in milliseconds for how long it should take to transition/move to a slide.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presEaseFunc', 'is the easing function for the movement to the slide.', ['Ease', 'Ease In', 'Ease Out', 'Ease Out', 'Ease In Out', 'Linear']); + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_easeFunc', 'is the easing function for the movement to the slide.', ['Ease', 'Ease In', 'Ease Out', 'Ease Out', 'Ease In Out', 'Linear']); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_effect', 'is an effect applied to the slide when we transition to it.', ['None', 'Zoom', 'Fade in', 'Bounce', 'Flip', 'Rotate', 'Roll']); + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_effect', 'is an effect applied to the slide when we transition to it.', ['None', 'Expand', 'Fade in', 'Bounce', 'Flip', 'Rotate', 'Roll']); addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_effectDirection', 'is what direction the effect is applied.', ['Enter from left', 'Enter from right', 'Enter from bottom', 'Enter from Top', 'Enter from center']); addCustomizationProperty( CustomizationType.PRES_TRAIL_SLIDE, - 'presEffectTiming', + 'presentation_effectTiming', "is a json object of the format: {type: string, stiffness: number, damping: number, mass: number}. Type is always “custom”. Controls the spring-based timing of the presentation effect animation. Stiffness, damping, and mass control the physics-based properties of spring animations. This is used to create a more natural looking timing, bouncy effects, etc. Use spring physics to adjust these parameters to match the user's description of how they want to animate the effect." ); addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'config_zoom', 'is a number from 0 to 1.0 indicating the percentage we should zoom into the slide.'); // boolean values - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presPlayAudio', 'is a boolean value indicating if we should play audio when we go to the slide.'); + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_playAudio', 'is a boolean value indicating if we should play audio when we go to the slide.'); addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_zoomText', 'is a boolean value indicating if we should zoom into text selections when we go to the slide.'); addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_hideBefore', 'is a boolean value indicating if we should hide the slide before going to it.'); addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_hide', 'is a boolean value indicating if we should hide the slide during the presentation.'); @@ -82,7 +82,7 @@ export const getSlideTransitionSuggestions = async (inputText: string) => { */ const prompt = - "I want to generate four distinct types of slide effect animations. Return a json of the form {effect: string, direction: string, stiffness: number, damping: number, mass: number}[] with four elements. Effect is the type of animation; its only possible values are ['Zoom', 'Fade in', 'Bounce', 'Flip', 'Rotate', 'Roll']. Direction is the direction that the animation starts from; its only possible values are ['Enter from left', 'Enter from right', 'Enter from bottom', 'Enter from Top', 'Enter from center']. Stiffness, damping, and mass control the physics-based properties of spring animations. This is used to create a more natural-looking timing, bouncy effects, etc. Use spring physics to adjust these parameters to animate the effect."; + "I want to generate four distinct types of slide effect animations. Return a json of the form {effect: string, direction: string, stiffness: number, damping: number, mass: number}[] with four elements. Effect is the type of animation; its only possible values are ['Expand', 'Fade in', 'Bounce', 'Flip', 'Rotate', 'Roll']. Direction is the direction that the animation starts from; its only possible values are ['Enter from left', 'Enter from right', 'Enter from bottom', 'Enter from Top', 'Enter from center']. Stiffness, damping, and mass control the physics-based properties of spring animations. This is used to create a more natural-looking timing, bouncy effects, etc. Use spring physics to adjust these parameters to animate the effect."; const customInput = inputText ?? 'Make them as contrasting as possible with different effects and timings ranging from gentle to energetic.'; diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 1c18c0d84..24dd5cf37 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -343,6 +343,7 @@ export class DocumentOptions { config_map?: STRt = new StrInfo('text location of map', false); config_panX?: NUMt = new NumInfo('panX saved as a view spec', false); config_panY?: NUMt = new NumInfo('panY saved as a view spec', false); + config_zoom?: NUMt = new NumInfo('zoom saved as a view spec', false); config_viewScale?: NUMt = new NumInfo('viewScale saved as a view Spec', false); presentation_transition?: NUMt = new NumInfo('the time taken for the transition TO a document', false); presentation_duration?: NUMt = new NumInfo('the duration of the slide in presentation view', false); diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 09a8194ca..8ad6ddf47 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -338,11 +338,13 @@ export class DocumentManager { // viewSpec !== docView.Document && docView.ComponentView?.focus?.(viewSpec, options); PresBox.restoreTargetDocView(docView, viewSpec, options.zoomTime ?? 500); - Doc.linkFollowHighlight(viewSpec ? [docView.Document, viewSpec] : docView.Document, undefined, options.effect); + // if there's an options.effect, it will be handled from linkFollowHighlight. We delay the start of + // the highlight so that the target document can be somewhat centered so that the effect/highlight will be seen + // bcz: should this delay be an options parameter? + setTimeout(() => Doc.linkFollowHighlight(viewSpec ? [docView.Document, viewSpec] : docView.Document, undefined, options.effect), (options.zoomTime ?? 0) * 0.5); if (options.playMedia) docView.ComponentView?.playFrom?.(NumCast(docView.Document._layout_currentTimecode)); if (options.playAudio) DocumentManager.playAudioAnno(docView.Document); if (options.toggleTarget && (!options.didMove || docView.Document.hidden)) docView.Document.hidden = !docView.Document.hidden; - if (options.effect) docView.Document[Animation] = options.effect; if (options.zoomTextSelections && Doc.IsUnhighlightTimerSet() && contextView && targetDoc.text_html) { // if the docView is a text anchor, the contextView is the PDF/Web/Text doc diff --git a/src/client/views/PinFuncs.ts b/src/client/views/PinFuncs.ts index 3d998ecaf..430455644 100644 --- a/src/client/views/PinFuncs.ts +++ b/src/client/views/PinFuncs.ts @@ -54,7 +54,7 @@ export function PinDocView(pinDocIn: Doc, pinProps: PinProps, targetDoc: Doc) { pinDoc.config_width = NumCast(targetDoc.width); pinDoc.config_height = NumCast(targetDoc.height); } - if (pinProps.pinAudioPlay) pinDoc.presPlayAudio = true; + if (pinProps.pinAudioPlay) pinDoc.presentation_playAudio = true; if (pinProps.pinData) { pinDoc.config_pinData = pinProps.pinData.scrollable || diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index df4ed98ac..024db82a4 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1487,7 +1487,7 @@ export class PropertiesView extends ObservableReactComponent this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.followLinkAnimEffect, 'default')}> - {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => ( + {[PresEffect.None, PresEffect.Expand, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => ( diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index c4d35330b..d9ff21035 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -547,7 +547,7 @@ export class Timeline extends ObservableReactComponent {
{this.drawTicks()}
-
+
{[...this.children, this._props.Document].map(doc => ( diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6f9e14c1b..c59cd0ee4 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -934,7 +934,7 @@ export class DocumentViewInternal extends DocComponent - {this._componentView?.isUnstyledView?.() ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} + {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} {borderPath?.jsx}
); @@ -958,7 +958,7 @@ export class DocumentViewInternal extends DocComponent{renderDoc} - // case PresEffect.Fade: return {renderDoc} + case PresEffect.Expand: return {renderDoc} + case PresEffect.Flip: return {renderDoc} + case PresEffect.Rotate: return {renderDoc} + case PresEffect.Bounce: return {renderDoc} + case PresEffect.Roll: return {renderDoc} + // case PresEffect.Fade: return {renderDoc} case PresEffect.Fade: return {renderDoc} - case PresEffect.Flip: return {renderDoc} - case PresEffect.Rotate: return {renderDoc} - case PresEffect.Bounce: return {renderDoc} - case PresEffect.Roll: return {renderDoc} // keep as preset, doesn't really make sense with spring config case PresEffect.Lightspeed: return {renderDoc}; case PresEffect.None: @@ -1416,7 +1416,7 @@ export class DocumentView extends DocComponent() {
console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} />
, - { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Zoom } as any as Doc, + { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Expand } as any as Doc, this.Document )}
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 69d03ac2e..101f28ae7 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -185,7 +185,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get currCPoints() { - const strPoints = this.activeItem.presEaseFunc ? StrCast(this.activeItem.presEaseFunc) : 'ease'; + const strPoints = this.activeItem.presentation_easeFunc ? StrCast(this.activeItem.presentation_easeFunc) : 'ease'; return EaseFuncToPoints(strPoints); } @@ -858,9 +858,9 @@ export class PresBox extends ViewBoxBaseComponent() { effect: activeItem, noSelect: true, openLocation: targetDoc.type === DocumentType.PRES ? ((OpenWhere.replace + ':' + PresBox.PanelName) as OpenWhere) : OpenWhere.addLeft, - easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any, + easeFunc: StrCast(activeItem.presentation_easeFunc, 'ease') as any, zoomTextSelections: BoolCast(activeItem.presentation_zoomText), - playAudio: BoolCast(activeItem.presPlayAudio), + playAudio: BoolCast(activeItem.presentation_playAudio), playMedia: activeItem.presentation_mediaStart === 'auto', }; if (activeItem.presentation_openInLightbox) { @@ -1575,16 +1575,16 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch updateEaseFunc = (activeItem: Doc) => { - activeItem.presEaseFunc = activeItem.presEaseFunc === 'linear' ? 'ease' : 'linear'; + activeItem.presentation_easeFunc = activeItem.presentation_easeFunc === 'linear' ? 'ease' : 'linear'; this.selectedArray.forEach(doc => { - doc.presEaseFunc = activeItem.presEaseFunc; + doc.presentation_easeFunc = activeItem.presentation_easeFunc; }); }; setEaseFunc = (activeItem: Doc, easeFunc: string) => { - activeItem.presEaseFunc = easeFunc; + activeItem.presentation_easeFunc = easeFunc; this.selectedArray.forEach(doc => { - doc.presEaseFunc = activeItem.presEaseFunc; + doc.presentation_easeFunc = activeItem.presentation_easeFunc; }); }; @@ -1602,9 +1602,9 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch updateEffectTiming = (activeItem: Doc, timing: SpringSettings) => { - activeItem.presEffectTiming = JSON.stringify(timing); + activeItem.presentation_effectTiming = JSON.stringify(timing); this.selectedArray.forEach(doc => { - doc.presEffectTiming = activeItem.presEffectTiming; + doc.presentation_effectTiming = activeItem.presentation_effectTiming; }); }; @@ -1829,7 +1829,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get transitionDropdown() { const { activeItem } = this; // Retrieving spring timing properties - const timing = StrCast(activeItem.presEffectTiming); + const timing = StrCast(activeItem.presentation_effectTiming); let timingConfig: SpringSettings | undefined; if (timing) { timingConfig = JSON.parse(timing); @@ -1847,8 +1847,8 @@ export class PresBox extends ViewBoxBaseComponent() { if (activeItem && this.targetDoc) { const transitionSpeed = activeItem.presentation_transition ? NumCast(activeItem.presentation_transition) / 1000 : 0.5; const zoom = NumCast(activeItem.config_zoom, 1) * 100; - const effect = StrCast(activeItem.presentation_effect) ? StrCast(activeItem.presentation_effect) : PresEffect.None; - const direction = StrCast(activeItem.presentation_effectDirection); + const effect = StrCast(activeItem.presentation_effect) ? (StrCast(activeItem.presentation_effect) as any as PresEffect) : PresEffect.None; + const direction = StrCast(activeItem.presentation_effectDirection) as PresEffectDirection; return ( <> @@ -1876,7 +1876,7 @@ export class PresBox extends ViewBoxBaseComponent() { /> } onClick={() => { @@ -1894,7 +1894,7 @@ export class PresBox extends ViewBoxBaseComponent() { type={Type.TERT} icon={this.isLoading ? : } iconPlacement="right" - color={StrCast(Doc.UserDoc().userVariantColor)} + color={SnappingManager.userVariantColor} onClick={() => { this.stopDictation(); this.customizeWithGPT(this.chatInput); @@ -1919,7 +1919,7 @@ export class PresBox extends ViewBoxBaseComponent() { > Movement () {
{/* Easing function */} { if (typeof val === 'string') { if (val !== 'custom') { @@ -2017,7 +2017,7 @@ export class PresBox extends ViewBoxBaseComponent() { type={Type.TERT} icon={this.isLoading ? : } iconPlacement="right" - color={StrCast(Doc.UserDoc().userVariantColor)} + color={SnappingManager.userVariantColor} onClick={this.customizeAnimations} />
@@ -2053,7 +2053,7 @@ export class PresBox extends ViewBoxBaseComponent() { mass: elem.mass, }); }}> - +
@@ -2062,7 +2062,7 @@ export class PresBox extends ViewBoxBaseComponent() {
{/* Effect dropdown */} () { {effect !== PresEffect.Lightspeed && ( <> () { Preview Effect
- +
@@ -2224,9 +2224,9 @@ export class PresBox extends ViewBoxBaseComponent() { { - activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio); + activeItem.presentation_playAudio = !BoolCast(activeItem.presentation_playAudio); }} color={SnappingManager.userColor} /> @@ -2239,7 +2239,7 @@ export class PresBox extends ViewBoxBaseComponent() { }} color={SnappingManager.userColor} /> -
diff --git a/src/client/views/nodes/trails/PresEnums.ts b/src/client/views/nodes/trails/PresEnums.ts index 564829d54..67cad9c5d 100644 --- a/src/client/views/nodes/trails/PresEnums.ts +++ b/src/client/views/nodes/trails/PresEnums.ts @@ -7,7 +7,7 @@ export enum PresMovement { } export enum PresEffect { - Zoom = 'Zoom', + Expand = 'Expand', Lightspeed = 'Lightspeed', Fade = 'Fade in', Flip = 'Flip', diff --git a/src/client/views/nodes/trails/SlideEffect.scss b/src/client/views/nodes/trails/SlideEffect.scss index cc851354e..aa2e5bbd9 100644 --- a/src/client/views/nodes/trails/SlideEffect.scss +++ b/src/client/views/nodes/trails/SlideEffect.scss @@ -8,7 +8,7 @@ .flip-side { position: absolute; will-change: transform, opacity; - backface-visibility: hidden; + // backface-visibility: hidden; } .flip-front { diff --git a/src/client/views/nodes/trails/SlideEffect.tsx b/src/client/views/nodes/trails/SlideEffect.tsx index 03cd88f45..00039e3cb 100644 --- a/src/client/views/nodes/trails/SlideEffect.tsx +++ b/src/client/views/nodes/trails/SlideEffect.tsx @@ -5,358 +5,116 @@ import { Doc } from '../../../../fields/Doc'; import { NumCast } from '../../../../fields/Types'; import { PresEffect, PresEffectDirection } from './PresEnums'; import './SlideEffect.scss'; +import { emptyFunction } from '../../../../Utils'; interface SlideEffectProps { - // pass in doc to extract width, height, bg - doc?: Doc; + doc?: Doc; // pass in doc to extract width, height, bg dir: PresEffectDirection; presEffect: PresEffect; - // stiffness (figma) = tension (react-spring) - tension: number; - // damping (figma) = friction (react-spring) - friction: number; - mass: number; + springSettings: { + stiffness: number; + damping: number; + mass: number; + }; children: React.ReactNode; infinite?: boolean; + startOpacity?: number; // set to zero to linearly fade in while animating } const DEFAULT_WIDTH = 40; const PREVIEW_OFFSET = 60; const ACTUAL_OFFSET = 200; -const infiniteOptions = { - loop: true, - delay: 500, -}; /** * This component wraps around the doc to create an effect animation, and also wraps the preview animations * for the effects as well. */ -export default function SpringAnimation({ doc, dir, friction, tension, mass, presEffect, children, infinite }: SlideEffectProps) { - const [springs, api] = useSpring( - () => ({ - from: { - x: 0, - y: 0, - opacity: 0, - scale: 1, - }, - config: { - tension, - friction, - mass, - }, - onStart: () => {}, - onRest: () => {}, - }), - [tension, friction, mass] - ); - const [ref, inView] = useInView({ - once: true, - }); - - const zoomConfig = { - from: { - scale: 0, - x: 0, - y: 0, - opacity: 1, - }, - to: { - scale: 1, - x: 0, - y: 0, - opacity: 1, - config: { - tension: tension, - friction: friction, - mass: mass, - }, - }, +export default function SpringAnimation({ doc, dir, springSettings, presEffect, children, infinite, startOpacity }: SlideEffectProps) { + const expandConfig = { + to: { scale: 1, x: 0, y: 0 }, + from: { scale: 0, x: 0, y: 0 }, }; - const fadeConfig = { - from: { - opacity: 0, - scale: 1, - x: 0, - y: 0, - }, - to: { - opacity: 1, - scale: 1, - x: 0, - y: 0, - config: { - tension: tension, - friction: friction, - mass: mass, - }, - }, + to: { x: 0, y: 0 }, + from: { x: 0, y: 0 }, }; - const rotateConfig = { - from: { - x: 0, - }, - to: { - x: 360, - config: { - tension: tension, - friction: friction, - mass: mass, - }, - }, + to: { x: 360, y: 0 }, + from: { x: 0, y: 0 }, }; - - const getBounceConfigFrom = () => { - switch (dir) { - case PresEffectDirection.Left: - return { - from: { - opacity: 0, - x: infinite ? -PREVIEW_OFFSET : -ACTUAL_OFFSET, - y: 0, - }, - }; - case PresEffectDirection.Right: - return { - from: { - opacity: 0, - x: infinite ? PREVIEW_OFFSET : ACTUAL_OFFSET, - y: 0, - }, - }; - case PresEffectDirection.Top: - return { - from: { - opacity: 0, - x: 0, - y: infinite ? -PREVIEW_OFFSET : -ACTUAL_OFFSET, - }, - }; - case PresEffectDirection.Bottom: - return { - from: { - opacity: 0, - x: 0, - y: infinite ? PREVIEW_OFFSET : ACTUAL_OFFSET, - }, - }; - default: - // no movement for center - return { - from: { - opacity: 0, - x: 0, - y: 0, - }, - }; - } - }; - - const bounceConfig = { - ...getBounceConfigFrom(), - to: [ - { - opacity: 1, - x: 0, - y: 0, - config: { - tension: tension, - friction: friction, - mass: mass, - }, - }, - ], - }; - const flipConfig = { - from: { - x: 0, - }, - to: { - x: 180, - config: { - tension: tension, - friction: friction, - mass: mass, - }, - }, + to: { x: 180, y: 0 }, + from: { x: 0, y: 0 }, }; - - // only left and right for now - const getRollConfigFrom = () => { - switch (dir) { - case PresEffectDirection.Left: - return { - from: { - opacity: 0, - x: -100, - y: -120, - }, - }; - case PresEffectDirection.Right: - return { - from: { - opacity: 0, - x: 100, - y: 120, - }, - }; - case PresEffectDirection.Top: - return { - from: { - opacity: 0, - x: -100, - y: -120, - }, - }; - case PresEffectDirection.Bottom: - return { - from: { - opacity: 0, - x: -100, - y: -120, - }, - }; - default: - // no movement for center - return { - from: { - opacity: 0, - x: 0, - y: 0, - }, - }; - } + const bounceConfig = { + to: { x: 0, y: 0 }, + from: (() => { + const offset = infinite ? PREVIEW_OFFSET : ACTUAL_OFFSET; + switch (dir) { + case PresEffectDirection.Left: return { x: -offset, y: 0, }; + case PresEffectDirection.Right: return { x: offset, y: 0, }; + case PresEffectDirection.Top: return { x: 0, y: -offset, }; + case PresEffectDirection.Bottom:return { x: 0, y: offset, }; + default: return { x: 0, y: 0, }; // no movement for center + }})(), // prettier-ignore }; - const rollConfig = { - ...getRollConfigFrom(), - to: { - opacity: 1, - x: 0, - y: 0, - config: { - tension: tension, - friction: friction, - mass: mass, - }, - }, + to: { x: 0, y: 0 }, + from: (() => { + switch (dir) { + case PresEffectDirection.Left: return { x: -100, y: -120, }; + case PresEffectDirection.Right: return { x: 100, y: 120, }; + case PresEffectDirection.Top: return { x: -100, y: -120, }; + case PresEffectDirection.Bottom: return { x: -100, y: -120, }; + default: return { x: 0, y: 0, }; // no movement for center + }})(), // prettier-ignore }; - // Switch animation depending on slide effect - const startAnimation = () => { - api.stop(); - let config: any = zoomConfig; + // prettier-ignore + const effectConfig = (() => { switch (presEffect) { - case PresEffect.Bounce: - config = bounceConfig; - break; - case PresEffect.Zoom: - config = zoomConfig; - break; - case PresEffect.Rotate: - config = rotateConfig; - break; - case PresEffect.Fade: - config = fadeConfig; - break; - case PresEffect.Flip: - config = flipConfig; - break; - case PresEffect.Roll: - config = rollConfig; - break; - case PresEffect.Lightspeed: - break; - default: - break; - } - - if (infinite) { - config = { ...config, ...infiniteOptions }; - } + case PresEffect.Fade: return fadeConfig; + case PresEffect.Bounce: return bounceConfig; + case PresEffect.Rotate: return rotateConfig; + case PresEffect.Flip: return flipConfig; + case PresEffect.Roll: return rollConfig; + case PresEffect.Lightspeed: return { from: {}, to: {} }; + case PresEffect.Expand: + default: return expandConfig; + } // prettier-ignore + })(); - api.start(config); - }; - - const getRenderDoc = () => { - switch (presEffect) { - case PresEffect.Rotate: - return ( - `rotate(${val}deg)`) }}> - {children} - - ); - case PresEffect.Flip: - return ( - // Pass in doc dimensions -
- {dir === PresEffectDirection.Bottom || dir === PresEffectDirection.Top ? ( - <> - `perspective(600px) rotateX(${val}deg)`), - width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, - height: doc ? NumCast(doc.height) : DEFAULT_WIDTH, - backgroundColor: infinite ? '#a825ff' : 'rgb(223, 223, 223);', - }} - /> - `perspective(600px) rotateX(${val}deg)`), rotateX: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}> - {children} - - - ) : ( - <> - `perspective(600px) rotateY(${val}deg)`), width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }} - /> - `perspective(600px) rotateY(${val}deg)`), rotateY: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}> - {children} - - - )} -
- ); - case PresEffect.Roll: - return ( - `translate3d(${val}%, 0, 0) rotate3d(0, 0, 1, ${val2}deg)`) }}> - {children} - - ); - default: - return ( - - {children} - - ); - } - }; - - useEffect(() => { - if (infinite || !inView) return; - setTimeout(() => { - startAnimation(); - }, 100); - }, [inView]); + const [springs, api] = useSpring( + () => ({ + to: { ...effectConfig.to, opacity: 1 }, + from: { ...effectConfig.from, opacity: startOpacity ?? 1 }, + config: { tension: springSettings.stiffness, friction: springSettings.damping, mass: springSettings.mass }, + onStart: emptyFunction, + onRest: emptyFunction, + }), + [springSettings] + ); + const [ref, inView] = useInView({ + once: true, + }); useEffect(() => { - if (infinite) { - startAnimation(); + if (inView) { + api.start({ loop: infinite, delay: infinite ? 500 : 0 }); } - }, [presEffect, tension, friction, mass]); - - return
{getRenderDoc()}
; + }, [inView]); + const animatedDiv = (style: any) => ( + `${val}`) }}> + {children} + + ); + const [width, height] = [NumCast(doc?.width, DEFAULT_WIDTH), NumCast(doc?.height, DEFAULT_WIDTH)]; + const flipAxis = dir === PresEffectDirection.Bottom || dir === PresEffectDirection.Top ? 'X' : 'Y'; + const [rotateX, rotateY] = flipAxis === 'X' ? ['180deg', undefined] : [undefined, '180deg']; + switch (presEffect) { + case PresEffect.Flip: return animatedDiv({ transform: to(springs.x, val => `perspective(600px) rotate${flipAxis}(${val}deg)`), width, height, rotateX, rotateY }) + case PresEffect.Rotate:return animatedDiv({ transform: to(springs.x, val => `rotate(${val}deg)`) }); + case PresEffect.Roll: return animatedDiv({ transform: to([springs.x, springs.y], (val, val2) => `translate3d(${val}%, 0, 0) rotate3d(0, 0, 1, ${val2}deg)`) }); + default: return animatedDiv(springs); + } // prettier-ignore } diff --git a/src/client/views/nodes/trails/SpringUtils.ts b/src/client/views/nodes/trails/SpringUtils.ts index bfb22c46a..73e1e14f1 100644 --- a/src/client/views/nodes/trails/SpringUtils.ts +++ b/src/client/views/nodes/trails/SpringUtils.ts @@ -80,7 +80,7 @@ export const effectItems = Object.values(PresEffect) export const presEffectDefaultTimings: { [key: string]: SpringSettings; } = { - Zoom: { type: SpringType.GENTLE, stiffness: 100, damping: 15, mass: 1 }, + Expand: { type: SpringType.GENTLE, stiffness: 100, damping: 15, mass: 1 }, Bounce: { type: SpringType.BOUNCY, stiffness: 600, -- cgit v1.2.3-70-g09d2