aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/PropertiesView.tsx3
-rw-r--r--src/client/views/nodes/trails/CubicBezierEditor.tsx95
-rw-r--r--src/client/views/nodes/trails/PresBox.scss10
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx466
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx3
-rw-r--r--src/client/views/nodes/trails/SlideEffect.scss5
-rw-r--r--src/client/views/nodes/trails/SlideEffect.tsx5
-rw-r--r--src/client/views/nodes/trails/SlideEffectPreview.tsx94
8 files changed, 273 insertions, 408 deletions
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 15974b9a7..a95477749 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1675,6 +1675,9 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
<div className="propertiesView" style={{ width: this._props.width }}>
<div className="propertiesView-sectionTitle" style={{ width: this._props.width }}>
Presentation
+ <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/features/trails/')}>
+ <IconButton icon={<FontAwesomeIcon icon="info-circle" />} color={SettingsManager.userColor} />
+ </div>
</div>
<div className="propertiesView-name" style={{ borderBottom: 0 }}>
{this.editableTitle}
diff --git a/src/client/views/nodes/trails/CubicBezierEditor.tsx b/src/client/views/nodes/trails/CubicBezierEditor.tsx
index e12fca20c..aba777e55 100644
--- a/src/client/views/nodes/trails/CubicBezierEditor.tsx
+++ b/src/client/views/nodes/trails/CubicBezierEditor.tsx
@@ -1,5 +1,4 @@
import React, { useEffect, useState } from 'react';
-import { StrCast } from '../../../../fields/Types';
type Props = {
setFunc: (newPoints: { p1: number[]; p2: number[] }) => void;
@@ -23,15 +22,14 @@ export const TIMING_DEFAULT_MAPPINGS = {
const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => {
const [animating, setAnimating] = useState(false);
- // Should let parent control state
- const [cPoints, setCPoints] = useState(
- currPoints
- ? currPoints
- : {
- p1: [0.25, 0.1],
- p2: [0.25, 1.0],
- }
- );
+ // const [cPoints, setCPoints] = useState(
+ // currPoints
+ // ? currPoints
+ // : {
+ // p1: [0.25, 0.1],
+ // p2: [0.25, 1.0],
+ // }
+ // );
const [c1Down, setC1Down] = useState(false);
const [c2Down, setC2Down] = useState(false);
@@ -73,11 +71,11 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => {
};
};
- useEffect(() => {
- if (!easeFunc.startsWith('cubic')) {
- setCPoints(convertToPoints(easeFunc));
- }
- }, [easeFunc]);
+ // useEffect(() => {
+ // if (!easeFunc.startsWith('cubic')) {
+ // setFunc(convertToPoints(easeFunc));
+ // }
+ // }, [easeFunc]);
useEffect(() => {
if (animating) {
@@ -93,25 +91,25 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => {
setC1Down(false);
});
const handlePointerMove = (e: PointerEvent) => {
- const newX = cPoints.p1[0] + e.movementX / EDITOR_WIDTH;
+ const newX = currPoints.p1[0] + e.movementX / EDITOR_WIDTH;
if (newX < 0 || newX > 1) {
return;
}
- setCPoints(prev => ({
- ...prev,
- p1: [roundToHundredth(prev.p1[0] + e.movementX / EDITOR_WIDTH), roundToHundredth(prev.p1[1] - e.movementY / EDITOR_WIDTH)],
- }));
+ // setCPoints(prev => ({
+ // ...prev,
+ // p1: [roundToHundredth(prev.p1[0] + e.movementX / EDITOR_WIDTH), roundToHundredth(prev.p1[1] - e.movementY / EDITOR_WIDTH)],
+ // }));
setFunc({
- ...cPoints,
- p1: [roundToHundredth(cPoints.p1[0] + e.movementX / EDITOR_WIDTH), roundToHundredth(cPoints.p1[1] - e.movementY / EDITOR_WIDTH)],
+ ...currPoints,
+ p1: [roundToHundredth(currPoints.p1[0] + e.movementX / EDITOR_WIDTH), roundToHundredth(currPoints.p1[1] - e.movementY / EDITOR_WIDTH)],
});
};
window.addEventListener('pointermove', handlePointerMove);
return () => window.removeEventListener('pointermove', handlePointerMove);
- }, [c1Down, cPoints]);
+ }, [c1Down, currPoints]);
useEffect(() => {
if (!c2Down) return;
@@ -119,38 +117,31 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => {
setC2Down(false);
});
const handlePointerMove = (e: PointerEvent) => {
- const newX = cPoints.p2[0] + e.movementX / EDITOR_WIDTH;
+ const newX = currPoints.p2[0] + e.movementX / EDITOR_WIDTH;
if (newX < 0 || newX > 1) {
return;
}
- setCPoints(prev => ({
- ...prev,
- p2: [roundToHundredth(prev.p2[0] + e.movementX / EDITOR_WIDTH), roundToHundredth(prev.p2[1] - e.movementY / EDITOR_WIDTH)],
- }));
+ // setCPoints(prev => ({
+ // ...prev,
+ // p2: [roundToHundredth(prev.p2[0] + e.movementX / EDITOR_WIDTH), roundToHundredth(prev.p2[1] - e.movementY / EDITOR_WIDTH)],
+ // }));
setFunc({
- ...cPoints,
- p2: [roundToHundredth(cPoints.p2[0] + e.movementX / EDITOR_WIDTH), roundToHundredth(cPoints.p2[1] - e.movementY / EDITOR_WIDTH)],
+ ...currPoints,
+ p2: [roundToHundredth(currPoints.p2[0] + e.movementX / EDITOR_WIDTH), roundToHundredth(currPoints.p2[1] - e.movementY / EDITOR_WIDTH)],
});
};
window.addEventListener('pointermove', handlePointerMove);
return () => window.removeEventListener('pointermove', handlePointerMove);
- }, [c2Down, cPoints]);
+ }, [c2Down, currPoints]);
return (
<div
- // onPointerDown={e => {
- // e.stopPropagation;
- // }}
onPointerMove={e => {
e.stopPropagation;
- }}
- // onPointerUp={e => {
- // e.stopPropagation;
- // }}
- >
+ }}>
<svg className="presBox-bezier-editor" width={`${CONTAINER_WIDTH}`} height={`${CONTAINER_WIDTH}`} xmlns="http://www.w3.org/2000/svg">
{/* Outlines */}
<line x1={`${0 + OFFSET}`} y1={`${EDITOR_WIDTH + OFFSET}`} x2={`${EDITOR_WIDTH + OFFSET}`} y2={`${0 + OFFSET}`} stroke="#c1c1c1" strokeWidth="1" />
@@ -158,9 +149,9 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => {
<rect x={`${0 + OFFSET}`} y={`${0 + OFFSET}`} width={EDITOR_WIDTH} height={EDITOR_WIDTH} stroke="#c5c5c5" fill="transparent" strokeWidth="1" />
{/* Editor */}
<path
- d={`M ${0 + OFFSET} ${EDITOR_WIDTH + OFFSET} C ${cPoints.p1[0] * EDITOR_WIDTH + OFFSET} ${EDITOR_WIDTH - cPoints.p1[1] * EDITOR_WIDTH + OFFSET}, ${
- cPoints.p2[0] * EDITOR_WIDTH + OFFSET
- } ${EDITOR_WIDTH - cPoints.p2[1] * EDITOR_WIDTH + OFFSET}, ${EDITOR_WIDTH + OFFSET} ${0 + OFFSET}`}
+ d={`M ${0 + OFFSET} ${EDITOR_WIDTH + OFFSET} C ${currPoints.p1[0] * EDITOR_WIDTH + OFFSET} ${EDITOR_WIDTH - currPoints.p1[1] * EDITOR_WIDTH + OFFSET}, ${
+ currPoints.p2[0] * EDITOR_WIDTH + OFFSET
+ } ${EDITOR_WIDTH - currPoints.p2[1] * EDITOR_WIDTH + OFFSET}, ${EDITOR_WIDTH + OFFSET} ${0 + OFFSET}`}
stroke="#ffffff"
fill="transparent"
/>
@@ -174,15 +165,15 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => {
}}
x1={`${0 + OFFSET}`}
y1={`${EDITOR_WIDTH + OFFSET}`}
- x2={`${cPoints.p1[0] * EDITOR_WIDTH + OFFSET}`}
- y2={`${EDITOR_WIDTH - cPoints.p1[1] * EDITOR_WIDTH + OFFSET}`}
+ x2={`${currPoints.p1[0] * EDITOR_WIDTH + OFFSET}`}
+ y2={`${EDITOR_WIDTH - currPoints.p1[1] * EDITOR_WIDTH + OFFSET}`}
stroke="#00000000"
strokeWidth="5"
/>
- <line x1={`${0 + OFFSET}`} y1={`${EDITOR_WIDTH + OFFSET}`} x2={`${cPoints.p1[0] * EDITOR_WIDTH + OFFSET}`} y2={`${EDITOR_WIDTH - cPoints.p1[1] * EDITOR_WIDTH + OFFSET}`} stroke="#ffffff" strokeWidth="1" />
+ <line x1={`${0 + OFFSET}`} y1={`${EDITOR_WIDTH + OFFSET}`} x2={`${currPoints.p1[0] * EDITOR_WIDTH + OFFSET}`} y2={`${EDITOR_WIDTH - currPoints.p1[1] * EDITOR_WIDTH + OFFSET}`} stroke="#ffffff" strokeWidth="1" />
<circle
- cx={`${cPoints.p1[0] * EDITOR_WIDTH + OFFSET}`}
- cy={`${EDITOR_WIDTH - cPoints.p1[1] * EDITOR_WIDTH + OFFSET}`}
+ cx={`${currPoints.p1[0] * EDITOR_WIDTH + OFFSET}`}
+ cy={`${EDITOR_WIDTH - currPoints.p1[1] * EDITOR_WIDTH + OFFSET}`}
r="5"
fill={`${c1Down ? '#3fa9ff' : '#ffffff'}`}
onPointerDown={e => {
@@ -204,15 +195,15 @@ const CubicBezierEditor = ({ setFunc, currPoints, easeFunc }: Props) => {
}}
x1={`${EDITOR_WIDTH + OFFSET}`}
y1={`${0 + OFFSET}`}
- x2={`${cPoints.p2[0] * EDITOR_WIDTH + OFFSET}`}
- y2={`${EDITOR_WIDTH - cPoints.p2[1] * EDITOR_WIDTH + OFFSET}`}
+ x2={`${currPoints.p2[0] * EDITOR_WIDTH + OFFSET}`}
+ y2={`${EDITOR_WIDTH - currPoints.p2[1] * EDITOR_WIDTH + OFFSET}`}
stroke="#00000000"
strokeWidth="5"
/>
- <line x1={`${EDITOR_WIDTH + OFFSET}`} y1={`${0 + OFFSET}`} x2={`${cPoints.p2[0] * EDITOR_WIDTH + OFFSET}`} y2={`${EDITOR_WIDTH - cPoints.p2[1] * EDITOR_WIDTH + OFFSET}`} stroke="#ffffff" strokeWidth="1" />
+ <line x1={`${EDITOR_WIDTH + OFFSET}`} y1={`${0 + OFFSET}`} x2={`${currPoints.p2[0] * EDITOR_WIDTH + OFFSET}`} y2={`${EDITOR_WIDTH - currPoints.p2[1] * EDITOR_WIDTH + OFFSET}`} stroke="#ffffff" strokeWidth="1" />
<circle
- cx={`${cPoints.p2[0] * EDITOR_WIDTH + OFFSET}`}
- cy={`${EDITOR_WIDTH - cPoints.p2[1] * EDITOR_WIDTH + OFFSET}`}
+ cx={`${currPoints.p2[0] * EDITOR_WIDTH + OFFSET}`}
+ cy={`${EDITOR_WIDTH - currPoints.p2[1] * EDITOR_WIDTH + OFFSET}`}
r="5"
fill={`${c2Down ? '#3fa9ff' : '#ffffff'}`}
onPointerDown={e => {
diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss
index 58c9b0b42..60d4e580d 100644
--- a/src/client/views/nodes/trails/PresBox.scss
+++ b/src/client/views/nodes/trails/PresBox.scss
@@ -1,7 +1,7 @@
@import '../../global/globalCssVariables.module.scss';
.presBox-gpt-chat {
- padding: 8px;
+ padding: 16px;
display: flex;
flex-direction: column;
gap: 1rem;
@@ -53,13 +53,11 @@
.presBox-effect-container {
cursor: pointer;
overflow: hidden;
- // position: relative;
width: 80px;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
- /* background-color: #1f2028; */
border: 1px solid rgb(118, 118, 118);
border-radius: 8px;
}
@@ -67,13 +65,9 @@
.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);
- // transform-origin: center;
}
// Bezier editor
@@ -95,7 +89,7 @@
display: flex;
flex-direction: column;
gap: 1rem;
- // padding: 8px;
+ padding: 16px;
}
.presBox-option-center {
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 4890c115b..02233d241 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -47,9 +47,9 @@ import { DictationManager } from '../../../util/DictationManager';
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, springPreviewColors } from './SpringUtils';
import SlideEffect from './SlideEffect';
+import { IoMdInformationCircleOutline } from 'react-icons/io';
export interface pinDataTypes {
scrollable?: boolean;
@@ -387,24 +387,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
setDictationContent = (value: string) => {
console.log('Dictation value', value);
this.setChatInput(value);
- // // Get the current cursor position
- // if (!this._inputref) return;
- // const cursorPosition = this._inputref.selectionStart;
- // const currentValue = this.chatInput;
-
- // // split before and after
- // const textBeforeCursor = currentValue.slice(0, cursorPosition);
- // const textAfterCursor = currentValue.slice(cursorPosition);
-
- // // insertion
- // const updatedText = textBeforeCursor + value + textAfterCursor;
-
- // // Update the textarea value
- // this.setChatInput(updatedText);
-
- // // set new cursor pos
- // const newCursorPosition = cursorPosition + value.length;
- // this._inputref.setSelectionRange(newCursorPosition, newCursorPosition);
};
@action
@@ -415,7 +397,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
try {
const res = await getSlideTransitionSuggestions(this.animationChat);
- console.log('GPT Result:', res);
if (typeof res === 'string') {
const resObj = JSON.parse(res);
console.log('Parsed GPT Result ', resObj);
@@ -448,11 +429,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
}
}
- console.log('current slide props', currSlideProperties);
+ console.log('current slide props ', currSlideProperties);
try {
const res = await gptTrailSlideCustomization(input, currSlideProperties);
- console.log('GPT Result:', res);
if (typeof res === 'string') {
const resObj = JSON.parse(res);
console.log('Parsed GPT Result ', resObj);
@@ -1798,46 +1778,51 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
let duration = activeItem.presentation_duration ? NumCast(activeItem.presentation_duration) / 1000 : 0;
if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration);
return (
- <div className="presBox-ribbon">
- <div className="presBox-toggles">
- <Tooltip title={<div className="dash-tooltip">Hide before presented</div>}>
- <div
- className={`ribbon-toggle ${activeItem.presentation_hideBefore ? 'active' : ''}`}
- style={{ border: `solid 1px ${SettingsManager.userColor}`, color: SettingsManager.userColor, background: activeItem.presentation_hideBefore ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor }}
- onClick={() => this.updateHideBefore(activeItem)}>
- Hide before
- </div>
- </Tooltip>
- <Tooltip title={<div className="dash-tooltip">{'Hide while presented'}</div>}>
- <div
- className={`ribbon-toggle ${activeItem.presentation_hide ? 'active' : ''}`}
- style={{ border: `solid 1px ${SettingsManager.userColor}`, color: SettingsManager.userColor, background: activeItem.presentation_hide ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor }}
- onClick={() => this.updateHide(activeItem)}>
- Hide
- </div>
- </Tooltip>
- <Tooltip title={<div className="dash-tooltip">{'Hide after presented'}</div>}>
- <div
- className={`ribbon-toggle ${activeItem.presentation_hideAfter ? 'active' : ''}`}
- style={{ border: `solid 1px ${SettingsManager.userColor}`, color: SettingsManager.userColor, background: activeItem.presentation_hideAfter ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor }}
- onClick={() => this.updateHideAfter(activeItem)}>
- Hide after
- </div>
- </Tooltip>
+ <div className="presBox-option-block">
+ <div className="presBox-ribbon">
+ <div className="presBox-toggles">
+ <Tooltip title={<div className="dash-tooltip">Hide before presented</div>}>
+ <div
+ className={`ribbon-toggle ${activeItem.presentation_hideBefore ? 'active' : ''}`}
+ style={{
+ border: `solid 1px ${SettingsManager.userColor}`,
+ color: SettingsManager.userColor,
+ background: activeItem.presentation_hideBefore ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
+ }}
+ onClick={() => this.updateHideBefore(activeItem)}>
+ Hide before
+ </div>
+ </Tooltip>
+ <Tooltip title={<div className="dash-tooltip">{'Hide while presented'}</div>}>
+ <div
+ className={`ribbon-toggle ${activeItem.presentation_hide ? 'active' : ''}`}
+ style={{ border: `solid 1px ${SettingsManager.userColor}`, color: SettingsManager.userColor, background: activeItem.presentation_hide ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor }}
+ onClick={() => this.updateHide(activeItem)}>
+ Hide
+ </div>
+ </Tooltip>
+ <Tooltip title={<div className="dash-tooltip">{'Hide after presented'}</div>}>
+ <div
+ className={`ribbon-toggle ${activeItem.presentation_hideAfter ? 'active' : ''}`}
+ style={{ border: `solid 1px ${SettingsManager.userColor}`, color: SettingsManager.userColor, background: activeItem.presentation_hideAfter ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor }}
+ onClick={() => this.updateHideAfter(activeItem)}>
+ Hide after
+ </div>
+ </Tooltip>
- <Tooltip title={<div className="dash-tooltip">{'Open in lightbox view'}</div>}>
- <div
- className="ribbon-toggle"
- style={{
- border: `solid 1px ${SettingsManager.userColor}`,
- color: SettingsManager.userColor,
- background: activeItem.presentation_openInLightbox ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
- }}
- onClick={() => this.updateOpenDoc(activeItem)}>
- Lightbox
- </div>
- </Tooltip>
- {/* <Tooltip title={<div className="dash-tooltip">Transition movement style</div>}>
+ <Tooltip title={<div className="dash-tooltip">{'Open in lightbox view'}</div>}>
+ <div
+ className="ribbon-toggle"
+ style={{
+ border: `solid 1px ${SettingsManager.userColor}`,
+ color: SettingsManager.userColor,
+ background: activeItem.presentation_openInLightbox ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
+ }}
+ onClick={() => this.updateOpenDoc(activeItem)}>
+ Lightbox
+ </div>
+ </Tooltip>
+ {/* <Tooltip title={<div className="dash-tooltip">Transition movement style</div>}>
<div
className="ribbon-toggle"
style={{ border: `solid 1px ${SettingsManager.userColor}`, color: SettingsManager.userColor, background: activeItem.presEaseFunc === 'ease' ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor }}
@@ -1845,15 +1830,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
{`${StrCast(activeItem.presEaseFunc, 'ease')}`}
</div>
</Tooltip> */}
- </div>
- {[DocumentType.AUDIO, DocumentType.VID].includes(targetType as any as DocumentType) ? null : (
- <>
- <div className="ribbon-doubleButton">
- <div className="presBox-subheading">Slide Duration</div>
- <div className="ribbon-property" style={{ border: `solid 1px ${SettingsManager.userColor}` }}>
- <input className="presBox-input" type="number" readOnly={true} value={duration} onKeyDown={e => e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s
- </div>
- {/* <div className="ribbon-propertyUpDown" style={{ color: SettingsManager.userBackgroundColor, background: SettingsManager.userColor }}>
+ </div>
+ {[DocumentType.AUDIO, DocumentType.VID].includes(targetType as any as DocumentType) ? null : (
+ <>
+ <div className="ribbon-doubleButton">
+ <div className="presBox-subheading">Slide Duration</div>
+ <div className="ribbon-property" style={{ border: `solid 1px ${SettingsManager.userColor}` }}>
+ <input className="presBox-input" type="number" readOnly={true} value={duration} onKeyDown={e => e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s
+ </div>
+ {/* <div className="ribbon-propertyUpDown" style={{ color: SettingsManager.userBackgroundColor, background: SettingsManager.userColor }}>
<div className="ribbon-propertyUpDownItem" onClick={() => this.updateDurationTime(String(duration), 1000)}>
<FontAwesomeIcon icon={'caret-up'} />
</div>
@@ -1861,15 +1846,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<FontAwesomeIcon icon={'caret-down'} />
</div>
</div> */}
- </div>
- {PresBox.inputter('0.1', '0.1', '20', duration, targetType !== DocumentType.AUDIO, this.updateDurationTime)}
- <div className={'slider-headers'} style={{ display: targetType === DocumentType.AUDIO ? 'none' : 'grid' }}>
- <div className="slider-text">Short</div>
- <div className="slider-text">Medium</div>
- <div className="slider-text">Long</div>
- </div>
- </>
- )}
+ </div>
+ {PresBox.inputter('0.1', '0.1', '20', duration, targetType !== DocumentType.AUDIO, this.updateDurationTime)}
+ <div className={'slider-headers'} style={{ display: targetType === DocumentType.AUDIO ? 'none' : 'grid' }}>
+ <div className="slider-text">Short</div>
+ <div className="slider-text">Medium</div>
+ <div className="slider-text">Long</div>
+ </div>
+ </>
+ )}
+ </div>
</div>
);
}
@@ -1887,74 +1873,76 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
);
return (
- <div className="presBox-ribbon">
- <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
- <div className="presBox-subheading">Progressivize Collection</div>
- <input
- className="presBox-checkbox"
- style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }}
- type="checkbox"
- onChange={() => {
- activeItem.presentation_indexed = activeItem.presentation_indexed === undefined ? 0 : undefined;
- activeItem.presentation_hideBefore = activeItem.presentation_indexed !== undefined;
- const tagDoc = PresBox.targetRenderedDoc(this.activeItem);
- const type = DocCast(tagDoc?.annotationOn)?.type ?? tagDoc.type;
- activeItem.presentation_indexedStart = type === DocumentType.COL ? 1 : 0;
- // a progressivized slide doesn't have sub-slides, but rather iterates over the data list of the target being progressivized.
- // to avoid creating a new slide to correspond to each of the target's data list, we create a computedField to refernce the target's data list.
- let dataField = Doc.LayoutFieldKey(tagDoc);
- if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '_annotations';
-
- if (DocCast(activeItem.presentation_targetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`this.presentation_targetDoc.annotationOn?.["${dataField}"]`);
- else activeItem.data = ComputedField.MakeFunction(`this.presentation_targetDoc?.["${dataField}"]`);
- }}
- checked={Cast(activeItem.presentation_indexed, 'number', null) !== undefined ? true : false}
- />
- </div>
- <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
- <div className="presBox-subheading">Progressivize First Bullet</div>
- <input
- className="presBox-checkbox"
- style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }}
- type="checkbox"
- onChange={() => (activeItem.presentation_indexedStart = activeItem.presentation_indexedStart ? 0 : 1)}
- checked={!NumCast(activeItem.presentation_indexedStart)}
- />
- </div>
- <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
- <div className="presBox-subheading">Expand Current Bullet</div>
- <input
- className="presBox-checkbox"
- style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }}
- type="checkbox"
- onChange={() => (activeItem.presBulletExpand = !activeItem.presBulletExpand)}
- checked={BoolCast(activeItem.presBulletExpand)}
- />
- </div>
+ <div className="presBox-option-block">
+ <div className="presBox-ribbon">
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Progressivize Collection</div>
+ <input
+ className="presBox-checkbox"
+ style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }}
+ type="checkbox"
+ onChange={() => {
+ activeItem.presentation_indexed = activeItem.presentation_indexed === undefined ? 0 : undefined;
+ activeItem.presentation_hideBefore = activeItem.presentation_indexed !== undefined;
+ const tagDoc = PresBox.targetRenderedDoc(this.activeItem);
+ const type = DocCast(tagDoc?.annotationOn)?.type ?? tagDoc.type;
+ activeItem.presentation_indexedStart = type === DocumentType.COL ? 1 : 0;
+ // a progressivized slide doesn't have sub-slides, but rather iterates over the data list of the target being progressivized.
+ // to avoid creating a new slide to correspond to each of the target's data list, we create a computedField to refernce the target's data list.
+ let dataField = Doc.LayoutFieldKey(tagDoc);
+ if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '_annotations';
+
+ if (DocCast(activeItem.presentation_targetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`this.presentation_targetDoc.annotationOn?.["${dataField}"]`);
+ else activeItem.data = ComputedField.MakeFunction(`this.presentation_targetDoc?.["${dataField}"]`);
+ }}
+ checked={Cast(activeItem.presentation_indexed, 'number', null) !== undefined ? true : false}
+ />
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Progressivize First Bullet</div>
+ <input
+ className="presBox-checkbox"
+ style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }}
+ type="checkbox"
+ onChange={() => (activeItem.presentation_indexedStart = activeItem.presentation_indexedStart ? 0 : 1)}
+ checked={!NumCast(activeItem.presentation_indexedStart)}
+ />
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Expand Current Bullet</div>
+ <input
+ className="presBox-checkbox"
+ style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }}
+ type="checkbox"
+ onChange={() => (activeItem.presBulletExpand = !activeItem.presBulletExpand)}
+ checked={BoolCast(activeItem.presBulletExpand)}
+ />
+ </div>
- <div className="ribbon-box">
- Bullet Effect
- <div
- className="presBox-dropdown"
- onClick={action(e => {
- e.stopPropagation();
- this._openBulletEffectDropdown = !this._openBulletEffectDropdown;
- })}
- style={{
- color: SettingsManager.userColor,
- background: SettingsManager.userVariantColor,
- borderBottomLeftRadius: this._openBulletEffectDropdown ? 0 : 5,
- border: this._openBulletEffectDropdown ? `solid 2px ${SettingsManager.userVariantColor}` : `solid 1px ${SettingsManager.userColor}`,
- }}>
- {effect?.toString()}
- <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openBulletEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
+ <div className="ribbon-box">
+ Bullet Effect
<div
- className={'presBox-dropdownOptions'}
- style={{ display: this._openBulletEffectDropdown ? 'grid' : 'none', color: SettingsManager.userColor, background: SettingsManager.userBackgroundColor }}
- onPointerDown={e => e.stopPropagation()}>
- {Object.values(PresEffect)
- .filter(v => isNaN(Number(v)))
- .map(effect => bulletEffect(effect))}
+ className="presBox-dropdown"
+ onClick={action(e => {
+ e.stopPropagation();
+ this._openBulletEffectDropdown = !this._openBulletEffectDropdown;
+ })}
+ style={{
+ color: SettingsManager.userColor,
+ background: SettingsManager.userVariantColor,
+ borderBottomLeftRadius: this._openBulletEffectDropdown ? 0 : 5,
+ border: this._openBulletEffectDropdown ? `solid 2px ${SettingsManager.userVariantColor}` : `solid 1px ${SettingsManager.userColor}`,
+ }}>
+ {effect?.toString()}
+ <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openBulletEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
+ <div
+ className={'presBox-dropdownOptions'}
+ style={{ display: this._openBulletEffectDropdown ? 'grid' : 'none', color: SettingsManager.userColor, background: SettingsManager.userBackgroundColor }}
+ onPointerDown={e => e.stopPropagation()}>
+ {Object.values(PresEffect)
+ .filter(v => isNaN(Number(v)))
+ .map(effect => bulletEffect(effect))}
+ </div>
</div>
</div>
</div>
@@ -2016,22 +2004,27 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
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 = activeItem.presentation_effect ? activeItem.presentation_effect : PresEffect.None;
+ const effect = StrCast(activeItem.presentation_effect) ? StrCast(activeItem.presentation_effect) : PresEffect.None;
+ const direction = StrCast(activeItem.presentation_effectDirection);
return (
<>
- {/* GPT Component */}
- {/* This chatbox is for customizing the properties of trails, like transition time, movement type (zoom, pan) */}
+ {/* This chatbox is for customizing the properties of trails, like transition time, movement type (zoom, pan) using GPT*/}
<div className="presBox-gpt-chat">
- <p>Customize with GPT</p>
+ <span style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
+ Customize Slide Properties{' '}
+ <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/features/trails/')}>
+ <IconButton icon={<FontAwesomeIcon icon="info-circle" />} color={SettingsManager.userColor} />
+ </div>
+ </span>
<div className="pres-chat">
<div className="pres-chatbox-container">
<ReactTextareaAutosize
- ref={r => (this._inputref = r)}
- minRows={1}
- placeholder="Customize..."
+ // ref={r => (this._inputref = r)}
+ // minRows={1}
+ placeholder="Describe how you would like to modify the slide properties."
className="pres-chatbox"
- autoFocus={true}
+ // autoFocus={true}
value={this.chatInput}
onChange={e => {
this.setChatInput(e.target.value);
@@ -2079,7 +2072,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this._openEffectDropdown = false;
this._openBulletEffectDropdown = false;
})}>
- <div className="presBox-option-block" style={{ padding: '16px' }}>
+ <div
+ className="presBox-option-block"
+ // style={{ padding: '16px' }}
+ >
Movement
<Dropdown
color={StrCast(Doc.UserDoc().userColor)}
@@ -2098,14 +2094,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="ribbon-property" style={{ border: `solid 1px ${SettingsManager.userColor}` }}>
<input className="presBox-input" readOnly={true} type="number" value={zoom} onChange={e => this.updateZoom(e.target.value)} />%
</div>
- {/* <div className="ribbon-propertyUpDown" style={{ color: SettingsManager.userBackgroundColor, background: SettingsManager.userColor }}>
- <div className="ribbon-propertyUpDownItem" onClick={() => this.updateZoom(String(zoom), 0.1)}>
- <FontAwesomeIcon icon={'caret-up'} />
- </div>
- <div className="ribbon-propertyUpDownItem" onClick={() => this.updateZoom(String(zoom), -0.1)}>
- <FontAwesomeIcon icon={'caret-down'} />
- </div>
- </div> */}
</div>
{PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)}
<div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
@@ -2113,14 +2101,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="ribbon-property" style={{ border: `solid 1px ${SettingsManager.userColor}` }}>
<input className="presBox-input" type="number" readOnly={true} value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s
</div>
- {/* <div className="ribbon-propertyUpDown" style={{ color: SettingsManager.userBackgroundColor, background: SettingsManager.userColor }}>
- <div className="ribbon-propertyUpDownItem" onClick={() => this.updateTransitionTime(String(transitionSpeed), 1000)}>
- <FontAwesomeIcon icon={'caret-up'} />
- </div>
- <div className="ribbon-propertyUpDownItem" onClick={() => this.updateTransitionTime(String(transitionSpeed), -1000)}>
- <FontAwesomeIcon icon={'caret-down'} />
- </div>
- </div> */}
</div>
{PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.updateTransitionTime)}
<div className={'slider-headers'}>
@@ -2129,61 +2109,59 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="slider-text">Slow</div>
</div>
{/* Easing function */}
- <div className="presBox-option-block presBox-option-center">
- <Dropdown
- color={StrCast(Doc.UserDoc().userColor)}
- formLabel={'Easing Function'}
- closeOnSelect={true}
- items={easeItems}
- selectedVal={this.activeItem.presEaseFunc ? (StrCast(this.activeItem.presEaseFunc).startsWith('cubic') ? 'custom' : StrCast(this.activeItem.presEaseFunc)) : 'ease'}
- setSelectedVal={val => {
- if (typeof val === 'string') {
- if (val !== 'custom') {
- this.setBezierEditorVisibility(true);
- this.setEaseFunc(this.activeItem, val);
- } else {
- this.setEaseFunc(this.activeItem, TIMING_DEFAULT_MAPPINGS.ease);
- }
+ <Dropdown
+ color={StrCast(Doc.UserDoc().userColor)}
+ formLabel={'Easing Function'}
+ closeOnSelect={true}
+ items={easeItems}
+ selectedVal={this.activeItem.presEaseFunc ? (StrCast(this.activeItem.presEaseFunc).startsWith('cubic') ? 'custom' : StrCast(this.activeItem.presEaseFunc)) : 'ease'}
+ setSelectedVal={val => {
+ 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 */}
- <div
- className="presBox-show-hide-dropdown"
- style={{ alignSelf: 'flex-start' }}
- onClick={e => {
- e.stopPropagation();
- this.setBezierEditorVisibility(!this.showBezierEditor);
- }}>
- {`${this.showBezierEditor ? 'Hide' : 'Show'} Timing Editor`}
- <FontAwesomeIcon icon={this.showBezierEditor ? 'chevron-up' : 'chevron-down'} />
- </div>
+ }
+ }}
+ dropdownType={DropdownType.SELECT}
+ type={Type.TERT}
+ />
+ {/* Custom */}
+ <div
+ className="presBox-show-hide-dropdown"
+ style={{ alignSelf: 'flex-start' }}
+ onClick={e => {
+ e.stopPropagation();
+ this.setBezierEditorVisibility(!this.showBezierEditor);
+ }}>
+ {`${this.showBezierEditor ? 'Hide' : 'Show'} Timing Editor`}
+ <FontAwesomeIcon icon={this.showBezierEditor ? 'chevron-up' : 'chevron-down'} />
</div>
</div>
</div>
- <div className="presBox-option-block">
- {this.showBezierEditor && (
- <>
- <p className="presBox-submenu-label" style={{ alignSelf: 'flex-start' }}>
- Custom Timing Function
- </p>
- <CubicBezierEditor setFunc={this.setBezierControlPoints} currPoints={this.currCPoints} easeFunc={StrCast(this.activeItem.presEaseFunc)} />
- </>
- )}
- </div>
+
+ {this.showBezierEditor && (
+ <div className="presBox-option-block" style={{ paddingTop: 0 }}>
+ <p className="presBox-submenu-label" style={{ alignSelf: 'flex-start' }}>
+ Custom Timing Function
+ </p>
+ <CubicBezierEditor setFunc={this.setBezierControlPoints} currPoints={this.currCPoints} easeFunc={StrCast(this.activeItem.presEaseFunc)} />
+ </div>
+ )}
+
{/* This chatbox is for getting slide effect transition suggestions from gpt and visualizing them */}
<div className="presBox-gpt-chat">
Effects
<div className="pres-chat">
<div className="pres-chatbox-container">
<ReactTextareaAutosize
- ref={r => (this._inputref2 = r)}
- minRows={1}
- placeholder="Get effect suggestions..."
+ // ref={r => (this._inputref2 = r)}
+ // minRows={1}
+ placeholder="Customize prompt for effect suggestions. Leave blank for random results."
className="pres-chatbox"
- autoFocus={true}
+ // autoFocus={true}
value={this.animationChat}
onChange={e => {
this.setAnimationChat(e.target.value);
@@ -2217,10 +2195,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this._openEffectDropdown = false;
this._openBulletEffectDropdown = false;
})}>
- <div className="presBox-option-block" style={{ padding: '16px' }}>
+ <div className="presBox-option-block">
+ Click on a box to apply the effect.
<div className="presBox-option-block presBox-option-center">
- {/* Chat for idea generation */}
-
{/* Preview Animations */}
<div className="presBox-effects">
{this.generatedAnimations.map((elem, i) => (
@@ -2269,13 +2246,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</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}
@@ -2395,9 +2365,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
valueLabelDisplay="auto"
/>
</div>
- <SpringAnimationPreview tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>
- <div style={{ width: '40px', height: '40px', backgroundColor: '#2e96ff', borderRadius: '4px' }}></div>
- </SpringAnimationPreview>
+ Preview Effect
+ <div className="presBox-option-block presBox-option-center">
+ <div className="presBox-effect-container">
+ <SlideEffect dir={direction as PresEffectDirection} presEffect={effect as PresEffect} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass} infinite>
+ <div className="presBox-effect-demo-box" style={{ backgroundColor: springPreviewColors[0] }}></div>
+ </SlideEffect>
+ </div>
+ </div>
</>
)}
</>
@@ -2405,26 +2380,23 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
{/* Toggles */}
- <Toggle
- formLabel={'Play Audio Annotation'}
- toggleType={ToggleType.SWITCH}
- toggleStatus={BoolCast(activeItem.presPlayAudio)}
- onClick={() => (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))}
- color={SettingsManager.userColor}
- />
- <Toggle
- formLabel={'Zoom Text Selections'}
- toggleType={ToggleType.SWITCH}
- toggleStatus={BoolCast(activeItem.presentation_zoomText)}
- onClick={() => (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))}
- color={SettingsManager.userColor}
- />
- <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 className="presBox-option-block">
+ <Toggle
+ formLabel={'Play Audio Annotation'}
+ toggleType={ToggleType.SWITCH}
+ toggleStatus={BoolCast(activeItem.presPlayAudio)}
+ onClick={() => (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))}
+ color={SettingsManager.userColor}
+ />
+ <Toggle
+ formLabel={'Zoom Text Selections'}
+ toggleType={ToggleType.SWITCH}
+ toggleStatus={BoolCast(activeItem.presentation_zoomText)}
+ onClick={() => (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))}
+ color={SettingsManager.userColor}
+ />
+ <Button text="Apply to all" type={Type.TERT} color={StrCast(Doc.UserDoc().userVariantColor)} onClick={() => this.applyTo(this.childDocs)} />
+ </div>
</div>
</>
);
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 268b1c803..1c6b38aeb 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -513,11 +513,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
</Tooltip>
);
items.push(
- <Tooltip key="edit" title={<div className="dash-tooltip">Edit</div>}>
+ <Tooltip key="customize-slide" title={<div className="dash-tooltip">Customize Slide</div>}>
<div
className={'slideButton'}
onClick={() => {
this.presBoxView?.regularSelect(this.slideDoc, this._itemRef.current!, this._dragRef.current!, true, false);
+ PresBox.Instance.navigateToActiveItem();
PresBox.Instance.openProperties();
PresBox.Instance.slideToModify = this.Document;
}}>
diff --git a/src/client/views/nodes/trails/SlideEffect.scss b/src/client/views/nodes/trails/SlideEffect.scss
index cadda0ccc..cc851354e 100644
--- a/src/client/views/nodes/trails/SlideEffect.scss
+++ b/src/client/views/nodes/trails/SlideEffect.scss
@@ -7,10 +7,6 @@
.flip-side {
position: absolute;
- // max-width: 500px;
- // max-height: 500px;
- // width: 350px;
- // height: 200px;
will-change: transform, opacity;
backface-visibility: hidden;
}
@@ -19,6 +15,5 @@
}
.flip-back {
- // Get the background color of node instead
// 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 e04f53f06..db2ac1ea0 100644
--- a/src/client/views/nodes/trails/SlideEffect.tsx
+++ b/src/client/views/nodes/trails/SlideEffect.tsx
@@ -27,7 +27,10 @@ const infiniteOptions = {
delay: 500,
};
-// TODO: add visibility detector when the slide comes into view
+/**
+ * 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 }: Props) {
const [springs, api] = useSpring(
() => ({
diff --git a/src/client/views/nodes/trails/SlideEffectPreview.tsx b/src/client/views/nodes/trails/SlideEffectPreview.tsx
deleted file mode 100644
index d4c16586a..000000000
--- a/src/client/views/nodes/trails/SlideEffectPreview.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import { useSpring, animated, easings } from '@react-spring/web';
-import React, { useEffect, useState } from 'react';
-
-interface Props {
- friction: number;
- tension: number;
- mass: number;
- children: React.ReactNode;
-}
-
-export default function SpringAnimationPreview({ friction, tension, mass, children }: Props) {
- const [springs, api] = useSpring(
- () => ({
- from: {
- x: 0,
- y: 0,
- opacity: 1,
- scale: 1,
- },
- config: {
- tension: tension,
- friction: friction,
- mass: mass,
- },
- onStart: () => {
- // console.log('started');
- },
- onRest: () => {
- // console.log('resting');
- },
- }),
- [tension, friction, mass]
- );
-
- // Whether the animation is currently playing
- const [animating, setAnimating] = useState(false);
-
- const bounceConfig = {
- from: {
- x: -50,
- y: 0,
- },
- to: [
- {
- x: 50,
- y: 0,
- config: {
- tension: tension,
- friction: friction,
- mass: mass,
- },
- },
- {
- x: -50,
- y: 0,
- config: {
- duration: 500,
- easing: easings.easeInOutCubic,
- },
- },
- ],
- };
-
- const animate = () => {
- api.start(bounceConfig);
- };
-
- useEffect(() => {
- animate();
- }, []);
-
- return (
- <div
- style={{
- width: '200px',
- height: '150px',
- borderRadius: '4px',
- border: '1px solid #696969',
- display: 'flex',
- justifyContent: 'center',
- alignItems: 'center',
- }}
- onPointerEnter={() => {
- animate();
- }}>
- <animated.div
- style={{
- ...springs,
- }}>
- {children}
- </animated.div>
- </div>
- );
-}