diff options
author | Sophie Zhang <sophie_zhang@brown.edu> | 2024-04-25 11:17:35 -0400 |
---|---|---|
committer | Sophie Zhang <sophie_zhang@brown.edu> | 2024-04-25 11:17:35 -0400 |
commit | 219f023202658414b09c5245c807c1bb6cdc4285 (patch) | |
tree | dcb26a3ef75790d2512301c18231ad84a80f447b /src | |
parent | 438de8877a3cc1a6b663d43d163704c3cc01bd4a (diff) |
ui framework for effect animations
Diffstat (limited to 'src')
-rw-r--r-- | src/client/apis/gpt/customization.ts | 26 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 12 | ||||
-rw-r--r-- | src/client/views/nodes/trails/PresBox.scss | 29 | ||||
-rw-r--r-- | src/client/views/nodes/trails/PresBox.tsx | 241 | ||||
-rw-r--r-- | src/client/views/nodes/trails/SlideEffect.scss | 2 | ||||
-rw-r--r-- | src/client/views/nodes/trails/SlideEffect.tsx | 86 | ||||
-rw-r--r-- | src/client/views/nodes/trails/SpringUtils.ts | 9 |
7 files changed, 259 insertions, 146 deletions
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<FieldViewProps & Document switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) { default: case PresEffect.None: return renderDoc; - case PresEffect.Zoom: return <SlideEffect doc={root} delay={transitionTime} dir={dir as PresEffectDirection} presEffect={PresEffect.Zoom} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> - case PresEffect.Fade: return <SlideEffect doc={root} delay={transitionTime} dir={dir as PresEffectDirection} presEffect={PresEffect.Fade} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> - case PresEffect.Flip: return <SlideEffect doc={root} delay={transitionTime} dir={dir as PresEffectDirection} presEffect={PresEffect.Flip} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> - case PresEffect.Rotate: return <SlideEffect doc={root} delay={transitionTime} dir={dir as PresEffectDirection} presEffect={PresEffect.Rotate} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> - case PresEffect.Bounce: return <SlideEffect doc={root} delay={transitionTime} dir={dir as PresEffectDirection} presEffect={PresEffect.Bounce} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> - case PresEffect.Roll: return <SlideEffect doc={root} delay={transitionTime} dir={dir as PresEffectDirection} presEffect={PresEffect.Roll} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> + case PresEffect.Zoom: return <SlideEffect doc={root} dir={dir as PresEffectDirection} presEffect={PresEffect.Zoom} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> + case PresEffect.Fade: return <SlideEffect doc={root} dir={dir as PresEffectDirection} presEffect={PresEffect.Fade} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> + case PresEffect.Flip: return <SlideEffect doc={root} dir={dir as PresEffectDirection} presEffect={PresEffect.Flip} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> + case PresEffect.Rotate: return <SlideEffect doc={root} dir={dir as PresEffectDirection} presEffect={PresEffect.Rotate} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> + case PresEffect.Bounce: return <SlideEffect doc={root} dir={dir as PresEffectDirection} presEffect={PresEffect.Bounce} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> + case PresEffect.Roll: return <SlideEffect doc={root} dir={dir as PresEffectDirection} presEffect={PresEffect.Roll} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> // keep as preset, doesn't really make sense with spring config case PresEffect.Lightspeed: return <JackInTheBox {...effectProps}>{renderDoc}</JackInTheBox>; } 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<FieldViewProps>() { 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<FieldViewProps>() { 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 ( <div @@ -1711,6 +1713,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { ); }; + // 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<FieldViewProps>() { onClick={() => (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} color={SettingsManager.userColor} /> - {/* <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> - <div className="presBox-subheading">Play Audio Annotation</div> - <input - className="presBox-checkbox" - style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }} - type="checkbox" - onChange={() => (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} - checked={BoolCast(activeItem.presPlayAudio)} - /> - </div> */} <Toggle formLabel={'Zoom Text Selections'} toggleType={ToggleType.SWITCH} @@ -2162,16 +2155,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { onClick={() => (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))} color={SettingsManager.userColor} /> - {/* <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> - <div className="presBox-subheading">Zoom Text Selections</div> - <input - className="presBox-checkbox" - style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }} - type="checkbox" - onChange={() => (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))} - checked={BoolCast(activeItem.presentation_zoomText)} - /> - </div> */} {/* Effect dropdown */} <Dropdown color={StrCast(Doc.UserDoc().userColor)} @@ -2187,100 +2170,136 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { dropdownType={DropdownType.SELECT} type={Type.TERT} /> - {/* <div - className="presBox-dropdown" - onClick={action(e => { - 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()} - <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} /> - <div - className="presBox-dropdownOptions" - id={'presBoxMovementDropdown'} - style={{ - color: SettingsManager.userColor, - background: SettingsManager.userBackgroundColor, - display: this._openEffectDropdown ? 'grid' : 'none', - }} - onPointerDown={e => e.stopPropagation()}> - {Object.values(PresEffect) - .filter(v => isNaN(Number(v))) - .map(effect => preseEffect(effect))} + {/* Effect generations */} + <div className="presBox-option-block presBox-option-center"> + {/* Chat for idea generation */} + <div className="presBox-gpt-chat"> + <p>Customize with GPT</p> + <div className="pres-chat"> + <div className="pres-chatbox-container"> + <ReactTextareaAutosize + ref={r => (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(); + }} + /> + <IconButton + type={Type.TERT} + color={this.isRecording ? '#2bcaff' : StrCast(Doc.UserDoc().userVariantColor)} + tooltip="Record" + icon={<BiMicrophone size={'16px'} />} + onClick={() => { + if (!this.isRecording) { + this.recordDictation(); + } else { + this.stopDictation(true); + } + }} + /> + </div> + <Button + style={{ alignSelf: 'flex-end' }} + text="Send" + type={Type.TERT} + icon={this.isLoading ? <ReactLoading type="spin" color={'#ffffff'} width={20} height={20} /> : <AiOutlineSend />} + iconPlacement="right" + color={StrCast(Doc.UserDoc().userVariantColor)} + onClick={() => { + this.customizeWithGPT(this.chatInput); + }} + /> + </div> </div> - </div> */} + {/* Preview Animations */} + <div className="presBox-effect-row"> + <div className="presBox-effect-container"> + <SlideEffect dir={PresEffectDirection.Left as PresEffectDirection} presEffect={PresEffect.Bounce} tension={100} friction={15} mass={1} infinite> + <div className="presBox-effect-demo-box"></div> + </SlideEffect> + </div> + <div className="presBox-effect-container"> + <SlideEffect dir={PresEffectDirection.Left as PresEffectDirection} presEffect={PresEffect.Fade} tension={100} friction={15} mass={1} infinite> + <div className="presBox-effect-demo-box" style={{ backgroundColor: '#4925ff' }}></div> + </SlideEffect> + </div> + </div> + <div className="presBox-effect-row"> + <div className="presBox-effect-container"> + <SlideEffect dir={PresEffectDirection.Left as PresEffectDirection} presEffect={PresEffect.Flip} tension={100} friction={15} mass={1} infinite> + <div className="presBox-effect-demo-box" style={{ top: 0, left: 0, backgroundColor: '#a825ff' }}></div> + </SlideEffect> + </div> + <div className="presBox-effect-container"> + <SlideEffect dir={PresEffectDirection.Left as PresEffectDirection} presEffect={PresEffect.Roll} tension={100} friction={15} mass={1} infinite> + <div className="presBox-effect-demo-box" style={{ backgroundColor: '#ff2599' }}></div> + </SlideEffect> + </div> + </div> + </div> {/* Effect direction */} {/* Only applies to certain effects */} - {effect === PresEffect.Flip || - effect === PresEffect.Bounce || - (effect === PresEffect.Roll && ( - <> - <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> - <div className="presBox-subheading">Effect direction</div> - <div className="ribbon-property" style={{ border: `solid 1px ${SettingsManager.userColor}` }}> - {StrCast(this.activeItem.presentation_effectDirection)} - </div> + {(effect === PresEffect.Flip || effect === PresEffect.Bounce || effect === PresEffect.Roll) && ( + <> + <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> + <div className="presBox-subheading">Effect direction</div> + <div className="ribbon-property" style={{ border: `solid 1px ${SettingsManager.userColor}` }}> + {StrCast(this.activeItem.presentation_effectDirection)} </div> - <div className="presBox-icon-list"> - <IconButton + </div> + <div className="presBox-icon-list"> + {/* <IconButton type={Type.TERT} color={activeItem.presentation_effectDirection === PresEffectDirection.Center ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor} tooltip="Center" icon={<FaCompressArrowsAlt size={'16px'} />} onClick={() => this.updateEffectDirection(PresEffectDirection.Center)} - /> - <IconButton - type={Type.TERT} - color={activeItem.presentation_effectDirection === PresEffectDirection.Left ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor} - tooltip="Left" - icon={<FaArrowRight size={'16px'} />} - onClick={() => this.updateEffectDirection(PresEffectDirection.Left)} - /> - <IconButton - type={Type.TERT} - color={activeItem.presentation_effectDirection === PresEffectDirection.Right ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor} - tooltip="Right" - icon={<FaArrowLeft size={'16px'} />} - onClick={() => this.updateEffectDirection(PresEffectDirection.Right)} - /> - {effect !== PresEffect.Roll && ( - <> - <IconButton - type={Type.TERT} - color={activeItem.presentation_effectDirection === PresEffectDirection.Top ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor} - tooltip="Top" - icon={<FaArrowDown size={'16px'} />} - onClick={() => this.updateEffectDirection(PresEffectDirection.Top)} - /> - <IconButton - type={Type.TERT} - color={activeItem.presentation_effectDirection === PresEffectDirection.Bottom ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor} - tooltip="Bottom" - icon={<FaArrowUp size={'16px'} />} - onClick={() => this.updateEffectDirection(PresEffectDirection.Bottom)} - /> - </> - )} - </div> - </> - ))} + /> */} + <IconButton + type={Type.TERT} + color={activeItem.presentation_effectDirection === PresEffectDirection.Left ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor} + tooltip="Left" + icon={<FaArrowRight size={'16px'} />} + onClick={() => this.updateEffectDirection(PresEffectDirection.Left)} + /> + <IconButton + type={Type.TERT} + color={activeItem.presentation_effectDirection === PresEffectDirection.Right ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor} + tooltip="Right" + icon={<FaArrowLeft size={'16px'} />} + onClick={() => this.updateEffectDirection(PresEffectDirection.Right)} + /> + {effect !== PresEffect.Roll && ( + <> + <IconButton + type={Type.TERT} + color={activeItem.presentation_effectDirection === PresEffectDirection.Top ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor} + tooltip="Top" + icon={<FaArrowDown size={'16px'} />} + onClick={() => this.updateEffectDirection(PresEffectDirection.Top)} + /> + <IconButton + type={Type.TERT} + color={activeItem.presentation_effectDirection === PresEffectDirection.Bottom ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor} + tooltip="Bottom" + icon={<FaArrowUp size={'16px'} />} + onClick={() => this.updateEffectDirection(PresEffectDirection.Bottom)} + /> + </> + )} + </div> + </> + )} {/* Spring settings */} {/* No spring settings for jackinthebox (lightspeed) */} - <div - className="presBox-show-hide-dropdown" - onClick={e => { - e.stopPropagation(); - this.setSpringEditorVisibility(!this.showSpringEditor); - }}> - {`${this.showSpringEditor ? 'Hide' : 'Show'} Spring Settings`} - <FontAwesomeIcon icon={this.showSpringEditor ? 'chevron-up' : 'chevron-down'} /> - </div> {effect !== PresEffect.Lightspeed && ( <> <Dropdown @@ -2298,6 +2317,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { dropdownType={DropdownType.SELECT} type={Type.TERT} /> + <div + className="presBox-show-hide-dropdown" + onClick={e => { + e.stopPropagation(); + this.setSpringEditorVisibility(!this.showSpringEditor); + }}> + {`${this.showSpringEditor ? 'Hide' : 'Show'} Spring Settings`} + <FontAwesomeIcon icon={this.showSpringEditor ? 'chevron-up' : 'chevron-down'} /> + </div> {this.showSpringEditor && ( <> <div>Tension</div> @@ -2363,11 +2391,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { )} {/* Effect spring settings */} </div> - <div className="ribbon-final-box"> + <Button text="Apply to all" type={Type.TERT} color={StrCast(Doc.UserDoc().userVariantColor)} onClick={() => this.applyTo(this.childDocs)} /> + {/* <div className="ribbon-final-box"> <div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}> Apply to all </div> - </div> + </div> */} </div> </> ); 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 <div className="flip-container" ref={ref}> {dir === PresEffectDirection.Bottom || dir === PresEffectDirection.Top ? ( <> - <animated.div className={'flip-side flip-back'} style={{ transform: to(springs.x, val => `perspective(600px) rotateX(${val}deg)`), width: NumCast(doc.width), height: NumCast(doc.height) }} /> - <animated.div className={'flip-side flip-front'} style={{ transform: to(springs.x, val => `perspective(600px) rotateX(${val}deg)`), rotateX: '180deg', width: NumCast(doc.width), height: NumCast(doc.height) }}> + <animated.div + className={'flip-side flip-back'} + style={{ + transform: to(springs.x, val => `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);', + }} + /> + <animated.div + className={'flip-side flip-front'} + style={{ transform: to(springs.x, val => `perspective(600px) rotateX(${val}deg)`), rotateX: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}> {children} </animated.div> </> ) : ( <> - <animated.div className={'flip-side flip-back'} style={{ transform: to(springs.x, val => `perspective(600px) rotateY(${val}deg)`), width: NumCast(doc.width), height: NumCast(doc.height) }} /> - <animated.div className={'flip-side flip-front'} style={{ transform: to(springs.x, val => `perspective(600px) rotateY(${val}deg)`), rotateY: '180deg', width: NumCast(doc.width), height: NumCast(doc.height) }}> + <animated.div + className={'flip-side flip-back'} + style={{ transform: to(springs.x, val => `perspective(600px) rotateY(${val}deg)`), width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }} + /> + <animated.div + className={'flip-side flip-front'} + style={{ transform: to(springs.x, val => `perspective(600px) rotateY(${val}deg)`), rotateY: '180deg', width: doc ? NumCast(doc.width) : DEFAULT_WIDTH, height: doc ? NumCast(doc.height) : DEFAULT_WIDTH }}> {children} </animated.div> </> @@ -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 <div>{getRenderDoc()}</div>; } 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 = [ { |