diff options
-rw-r--r-- | src/client/views/nodes/trails/CubicBezierEditor.tsx | 154 | ||||
-rw-r--r-- | src/client/views/nodes/trails/PresBox.scss | 83 | ||||
-rw-r--r-- | src/client/views/nodes/trails/PresBox.tsx | 475 |
3 files changed, 402 insertions, 310 deletions
diff --git a/src/client/views/nodes/trails/CubicBezierEditor.tsx b/src/client/views/nodes/trails/CubicBezierEditor.tsx index e1ad1e6e5..627b77184 100644 --- a/src/client/views/nodes/trails/CubicBezierEditor.tsx +++ b/src/client/views/nodes/trails/CubicBezierEditor.tsx @@ -118,84 +118,82 @@ function CubicBezierEditor({ setFunc, currPoints }: Props) { }, [c2Down, currPoints]); return ( - <div - onPointerMove={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" /> - {/* Box Outline */} - <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 ${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" - /> - {/* Bottom left */} - <line - onPointerDown={() => { - setC1Down(true); - }} - onPointerUp={() => { - setC1Down(false); - }} - x1={`${0 + OFFSET}`} - y1={`${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={`${currPoints.p1[0] * EDITOR_WIDTH + OFFSET}`} y2={`${EDITOR_WIDTH - currPoints.p1[1] * EDITOR_WIDTH + OFFSET}`} stroke="#ffffff" strokeWidth="1" /> - <circle - cx={`${currPoints.p1[0] * EDITOR_WIDTH + OFFSET}`} - cy={`${EDITOR_WIDTH - currPoints.p1[1] * EDITOR_WIDTH + OFFSET}`} - r="5" - fill={`${c1Down ? '#3fa9ff' : '#ffffff'}`} - onPointerDown={e => { - e.stopPropagation(); - setC1Down(true); - }} - onPointerUp={() => { - setC1Down(false); - }} - /> - {/* Top right */} - <line - onPointerDown={e => { - e.stopPropagation(); - setC2Down(true); - }} - onPointerUp={() => { - setC2Down(false); - }} - x1={`${EDITOR_WIDTH + OFFSET}`} - y1={`${0 + 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={`${currPoints.p2[0] * EDITOR_WIDTH + OFFSET}`} y2={`${EDITOR_WIDTH - currPoints.p2[1] * EDITOR_WIDTH + OFFSET}`} stroke="#ffffff" strokeWidth="1" /> - <circle - cx={`${currPoints.p2[0] * EDITOR_WIDTH + OFFSET}`} - cy={`${EDITOR_WIDTH - currPoints.p2[1] * EDITOR_WIDTH + OFFSET}`} - r="5" - fill={`${c2Down ? '#3fa9ff' : '#ffffff'}`} - onPointerDown={e => { - e.stopPropagation(); - setC2Down(true); - }} - onPointerUp={() => { - setC2Down(false); - }} - /> - </svg> - </div> + <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" /> + {/* Box Outline */} + <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 ${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" + /> + {/* Bottom left */} + <line + onPointerDown={() => { + setC1Down(true); + }} + onPointerMove={e => { + e.stopPropagation; + }} + onPointerUp={() => { + setC1Down(false); + }} + x1={`${0 + OFFSET}`} + y1={`${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={`${currPoints.p1[0] * EDITOR_WIDTH + OFFSET}`} y2={`${EDITOR_WIDTH - currPoints.p1[1] * EDITOR_WIDTH + OFFSET}`} stroke="#ffffff" strokeWidth="1" /> + <circle + cx={`${currPoints.p1[0] * EDITOR_WIDTH + OFFSET}`} + cy={`${EDITOR_WIDTH - currPoints.p1[1] * EDITOR_WIDTH + OFFSET}`} + r="5" + fill={`${c1Down ? '#3fa9ff' : '#ffffff'}`} + onPointerDown={e => { + e.stopPropagation(); + setC1Down(true); + }} + onPointerUp={() => { + setC1Down(false); + }} + /> + {/* Top right */} + <line + onPointerDown={e => { + e.stopPropagation(); + setC2Down(true); + }} + onPointerUp={() => { + setC2Down(false); + }} + x1={`${EDITOR_WIDTH + OFFSET}`} + y1={`${0 + 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={`${currPoints.p2[0] * EDITOR_WIDTH + OFFSET}`} y2={`${EDITOR_WIDTH - currPoints.p2[1] * EDITOR_WIDTH + OFFSET}`} stroke="#ffffff" strokeWidth="1" /> + <circle + cx={`${currPoints.p2[0] * EDITOR_WIDTH + OFFSET}`} + cy={`${EDITOR_WIDTH - currPoints.p2[1] * EDITOR_WIDTH + OFFSET}`} + r="5" + fill={`${c2Down ? '#3fa9ff' : '#ffffff'}`} + onPointerDown={e => { + e.stopPropagation(); + setC2Down(true); + }} + onPointerUp={() => { + setC2Down(false); + }} + /> + </svg> ); } diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss index 60d4e580d..a181687f8 100644 --- a/src/client/views/nodes/trails/PresBox.scss +++ b/src/client/views/nodes/trails/PresBox.scss @@ -5,11 +5,24 @@ display: flex; flex-direction: column; gap: 1rem; + .presBox-gpt-chat-span { + display: flex; + align-items: center; + gap: 8px; + } + textarea { + width: 100%; + } +} +.presBox-subheading-slider { + max-width: calc(100% - 25px); + width: 100%; + padding: 15px; } .pres-chat { display: flex; - flex-direction: column; + flex-direction: row; gap: 8px; } @@ -18,30 +31,38 @@ gap: 8px; } -.pres-chatbox-container { - padding: 16px; +.pres-chatbox-container, +.pres-chatbox-container-ai { + width: 100%; + padding-left: 16px; + padding-right: 16px; outline: 1px solid #999999; - border-radius: 16px; + border-radius: 5px; display: flex; align-items: center; justify-content: space-between; + overflow: auto; + max-height: 200px; + .pres-chatbox { + outline: none; + border: none; + resize: none; + font-family: Verdana, Geneva, sans-serif; + background-color: transparent; + overflow-y: hidden; + } } -.pres-chatbox { - outline: none; - border: none; - resize: none; - font-family: Verdana, Geneva, sans-serif; - background-color: transparent; - overflow-y: hidden; +.pres-chatbox-container-ai { + padding-left: 8px; + padding-right: 8px; + margin-left: 8px; } - // Effect Animations .presBox-effects { - display: grid; - grid-template-columns: auto auto; - gap: 8px; + display: flow; + margin: auto; } .presBox-effect-row { @@ -55,7 +76,7 @@ overflow: hidden; width: 80px; height: 80px; - display: flex; + display: inline-flex; justify-content: center; align-items: center; border: 1px solid rgb(118, 118, 118); @@ -74,7 +95,6 @@ .presBox-show-hide-dropdown { cursor: pointer; - padding: 8px 0; display: flex; align-items: center; gap: 4px; @@ -96,6 +116,18 @@ align-items: center; } +.presBox-previewContainer { + display: flex; + align-items: center; + width: fit-content; + margin: auto; + grid-template-columns: auto auto; + grid-gap: 10px; + .presBox-option-block { + padding: 0px; + } +} + .presBox-cont { cursor: auto; position: absolute; @@ -280,6 +312,9 @@ font-family: Roboto; z-index: 100; transition: 0.7s; + .form-wrapper.left .formLabel { + width: 100px; + } .ribbon-doubleButton { display: flex; @@ -352,6 +387,18 @@ font-size: 11; font-weight: 400; margin-top: 10px; + max-width: min(100px, 25%); + width: 100%; + } + .presBox-springSlider { + display: grid; + column-count: 2; + grid-template-columns: min(60px, 25%) calc(100% - min(60px, 25%) - min(5px, 10%)); + grid-gap: min(5px, 10%); + > span { + overflow: hidden; + text-overflow: ellipsis; + } } @media screen and (-webkit-min-device-pixel-ratio: 0) { @@ -459,7 +506,7 @@ justify-content: space-between; width: 100%; height: max-content; - grid-template-columns: auto auto auto; + grid-template-columns: auto auto; grid-template-rows: max-content; font-weight: 100; margin-top: 3px; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 3919ac3a8..5dbf502d2 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -100,8 +100,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @observable _presKeyEvents: boolean = false; @observable _forceKeyEvents: boolean = false; + @observable _showAIGallery = false; @observable _showBezierEditor = false; - @observable _showSpringEditor = true; + @observable _showSpringEditor = false; @observable _showPreview = true; @observable _easeDropdownVal = 'ease'; @@ -151,6 +152,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { setIsRecording = action((input: boolean) => { this._isRecording = input; }); // prettier-ignore setBezierEditorVisibility = action((visible: boolean) => { this._showBezierEditor = visible; }); // prettier-ignore setSpringEditorVisibility = action((visible: boolean) => { this._showSpringEditor = visible; }); // prettier-ignore + setShowAIGalleryVisibilty = action((visible: boolean) => { this._showAIGallery = visible; }); // prettier-ignore setBezierControlPoints = action((newPoints: { p1: number[]; p2: number[] }) => { this.setEaseFunc(this.activeItem, `cubic-bezier(${newPoints.p1[0]}, ${newPoints.p1[1]}, ${newPoints.p2[0]}, ${newPoints.p2[1]})`); }); @@ -1735,19 +1737,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { const { activeItem } = this; // Retrieving spring timing properties const timing = StrCast(activeItem?.presentation_effectTiming); - let timingConfig: SpringSettings | undefined; - if (timing) { - timingConfig = JSON.parse(timing); - } - - if (!timingConfig) { - timingConfig = { - type: SpringType.GENTLE, - stiffness: 100, - damping: 15, - mass: 1, - }; - } + const timingConfig: SpringSettings = timing + ? JSON.parse(timing) + : { + type: SpringType.GENTLE, + stiffness: 100, + damping: 15, + mass: 1, + }; if (activeItem && this.targetDoc) { const transitionSpeed = activeItem.presentation_transition ? NumCast(activeItem.presentation_transition) / 1000 : 0.5; @@ -1758,20 +1755,32 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { return ( <> {/* This chatbox is for customizing the properties of trails, like transition time, movement type (zoom, pan) using GPT */} - <div className="presBox-gpt-chat"> - <span style={{ display: 'flex', alignItems: 'center', gap: '8px' }}> + <div className="presBox-gpt-chat" style={{ display: SnappingManager.PropertiesWidth < 1 ? 'none' : undefined }}> + <span className="presBox-gpt-chat-span"> Customize Slide Properties{' '} <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/features/trails/#slide-customization')}> <IconButton icon={<FontAwesomeIcon icon="info-circle" />} color={SnappingManager.userColor} /> </div> </span> <div className="pres-chat"> - <div className="pres-chatbox-container"> + <div className="pres-chatbox-container-ai"> <ReactTextareaAutosize - placeholder="Describe how you would like to modify the slide properties." + placeholder="Describe how to modify the slide properties." className="pres-chatbox" + ref={r => { + setTimeout(() => { + if (r && !r.textContent) { + r.style.height = ''; + r.style.height = r.scrollHeight + 'px'; + } + }); + }} value={this._chatInput} - onChange={e => this.setChatInput(e.target.value)} + onChange={e => { + e.currentTarget.style.height = ''; + e.currentTarget.style.height = e.currentTarget.scrollHeight + 'px'; + this.setChatInput(e.target.value); + }} onKeyDown={e => { this.stopDictation(); e.stopPropagation(); @@ -1805,6 +1814,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { /> </div> </div> + {/* Movement */} <div className={`presBox-ribbon ${this._transitionTools && this.layoutDoc.presentation_status === PresStatus.Edit ? 'active' : ''}`} @@ -1816,46 +1826,47 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { this._openEffectDropdown = false; this._openBulletEffectDropdown = false; })}> - <div - className="presBox-option-block" - // style={{ padding: '16px' }} - > - Movement + <div className="presBox-option-block"> <Dropdown color={SnappingManager.userColor} - formLabel="Movement" + formLabel="Navigation" + formLabelPlacement="left" closeOnSelect items={movementItems} selectedVal={this.movementName(activeItem)} - setSelectedVal={val => { - this.updateMovement(val as PresMovement); - }} + setSelectedVal={val => this.updateMovement(val as PresMovement)} dropdownType={DropdownType.SELECT} type={Type.TERT} /> - <div className="ribbon-doubleButton" style={{ display: activeItem.presentation_movement === PresMovement.Zoom ? 'inline-flex' : 'none' }}> - <div className="presBox-subheading">Zoom (% screen filled)</div> - <div className="ribbon-property" style={{ border: `solid 1px ${SnappingManager.userColor}` }}> - <input className="presBox-input" readOnly type="number" value={zoom} onChange={e => this.updateZoom(e.target.value)} />% + <div className="ribbon-doubleButton" style={{ display: activeItem.presentation_movement === PresMovement.Zoom ? undefined : 'none' }}> + <Tooltip title={<div>How much (%) of screen target should occupy</div>}> + <div className="presBox-subheading">ZOOM %</div> + </Tooltip> + <div className="presBox-subheading-slider">{PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)}</div> + <div className="ribbon-property" style={{ border: `solid 1px ${SnappingManager.userColor}`, display: 'flex', maxWidth: 60, width: '100%' }}> + <input style={{ maxWidth: 25 }} className="presBox-input" readOnly type="number" value={zoom} onChange={e => this.updateZoom(e.target.value)} /> + <span>%</span> </div> </div> - {PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)} - <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> - <div className="presBox-subheading">Transition Time</div> - <div className="ribbon-property" style={{ border: `solid 1px ${SnappingManager.userColor}` }}> - <input className="presBox-input" type="number" readOnly value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s + <div className="ribbon-doubleButton"> + <div className="presBox-subheading">ZOOM/EFFECT TIME</div> + <div className="presBox-subheading-slider"> + {PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.updateTransitionTime)} + <div className="slider-headers"> + <div className="slider-text">Fast</div> + <div className="slider-text">Slow</div> + </div> + </div> + <div className="ribbon-property" style={{ border: `solid 1px ${SnappingManager.userColor}`, display: 'flex', maxWidth: 60, width: '100%' }}> + <input style={{ maxWidth: 25 }} className="presBox-input" type="number" readOnly value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> + <span>s</span> </div> - </div> - {PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.updateTransitionTime)} - <div className="slider-headers"> - <div className="slider-text">Fast</div> - <div className="slider-text">Medium</div> - <div className="slider-text">Slow</div> </div> {/* Easing function */} <Dropdown color={SnappingManager.userColor} - formLabel="Easing Function" + formLabel="Timing Function" + formLabelPlacement="left" closeOnSelect items={easeItems} selectedVal={this.activeItem.presentation_easeFunc ? (StrCast(this.activeItem.presentation_easeFunc).startsWith('cubic') ? 'custom' : StrCast(this.activeItem.presentation_easeFunc)) : 'ease'} @@ -1880,32 +1891,75 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { e.stopPropagation(); this.setBezierEditorVisibility(!this._showBezierEditor); }}> - {`${this._showBezierEditor ? 'Hide' : 'Show'} Timing Editor`} - <FontAwesomeIcon icon={this._showBezierEditor ? 'chevron-up' : 'chevron-down'} /> + TIMING EDITOR + <FontAwesomeIcon icon={this._showBezierEditor ? 'chevron-down' : 'chevron-up'} /> </div> </div> </div> {/* Cubic bezier editor */} {this._showBezierEditor && ( - <div className="presBox-option-block" style={{ paddingTop: 0 }}> - <p className="presBox-submenu-label" style={{ alignSelf: 'flex-start' }}> - Custom Timing Function - </p> + <div className="presBox-option-block" style={{ paddingTop: 0, alignItems: 'center' }}> <CubicBezierEditor setFunc={this.setBezierControlPoints} currPoints={this.currCPoints} /> </div> )} + {effect === PresEffect.None ? null : ( + <div className="presBox-previewContainer"> + <Button + type={Type.TERT} + tooltip="show preview of slide animation effect" + size={Size.SMALL} + color={SnappingManager.userColor} + background={'transparent'} + onClick={action(() => { + this._showPreview = false; + setTimeout(action(() => { this._showPreview = true; }) ); // prettier-ignore + })} + text="Preview Effect" + /> + <div className="presBox-option-block presBox-option-center"> + <div className="presBox-effect-container"> + {!this._showPreview ? null : ( + <SlideEffect dir={direction} presEffect={effect} springSettings={timingConfig}> + <div className="presBox-effect-demo-box" style={{ backgroundColor: springPreviewColors[0] }} /> + </SlideEffect> + )} + </div> + </div> + </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"> + <div className="presBox-gpt-chat" style={{ display: SnappingManager.PropertiesWidth < 1 ? 'none' : undefined }}> + {/* Custom */} + <div + className="presBox-show-hide-dropdown" + style={{ alignSelf: 'flex-start' }} + onClick={e => { + e.stopPropagation(); + this.setShowAIGalleryVisibilty(!this._showAIGallery); + }}> + AI EFFECTS + <FontAwesomeIcon icon={this._showAIGallery ? 'chevron-down' : 'chevron-up'} /> + </div> + <div className="pres-chat" style={{ display: this._showAIGallery ? undefined : 'none' }}> + <div className="pres-chatbox-container-ai"> <ReactTextareaAutosize - placeholder="Customize prompt for effect suggestions. Leave blank for random results." + placeholder="Use AI to suggest effects. Leave blank for random results." className="pres-chatbox" + ref={r => { + setTimeout(() => { + if (r && !r.textContent) { + r.style.height = ''; + r.style.height = r.scrollHeight + 'px'; + } + }); + }} value={this._animationChat} onChange={e => { + e.currentTarget.style.height = ''; + e.currentTarget.style.height = e.currentTarget.scrollHeight + 'px'; this.setAnimationChat(e.target.value); }} onKeyDown={e => { @@ -1924,6 +1978,31 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { onClick={this.customizeAnimations} /> </div> + <div style={{ display: this._showAIGallery ? 'flex' : 'none', alignItems: 'center' }}> + Click a box to use the effect. + {/* Preview Animations */} + <div className="presBox-effects"> + {this.generatedAnimations.map((elem, i) => ( + <div + key={i} + className="presBox-effect-container" + onClick={() => { + this.updateEffect(elem.effect, false); + this.updateEffectDirection(elem.direction); + this.updateEffectTiming(this.activeItem, { + type: SpringType.CUSTOM, + stiffness: elem.stiffness, + damping: elem.damping, + mass: elem.mass, + }); + }}> + <SlideEffect dir={elem.direction} presEffect={elem.effect} springSettings={elem} infinite> + <div className="presBox-effect-demo-box" style={{ backgroundColor: springPreviewColors[i] }} /> + </SlideEffect> + </div> + ))} + </div> + </div> </div> <div @@ -1937,171 +2016,139 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { this._openBulletEffectDropdown = false; })}> <div className="presBox-option-block"> - Click on a box to apply the effect. - <div className="presBox-option-block presBox-option-center"> - {/* Preview Animations */} - <div className="presBox-effects"> - {this.generatedAnimations.map((elem, i) => ( - <div - key={i} - className="presBox-effect-container" - onClick={() => { - this.updateEffect(elem.effect, false); - this.updateEffectDirection(elem.direction); - this.updateEffectTiming(this.activeItem, { - type: SpringType.CUSTOM, - stiffness: elem.stiffness, - damping: elem.damping, - mass: elem.mass, - }); - }}> - <SlideEffect dir={elem.direction} presEffect={elem.effect} springSettings={elem} infinite> - <div className="presBox-effect-demo-box" style={{ backgroundColor: springPreviewColors[i] }} /> - </SlideEffect> - </div> - ))} - </div> - </div> {/* Effect dropdown */} - <Dropdown - color={SnappingManager.userColor} - formLabel="Slide Effect" - closeOnSelect - items={effectItems} - 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} - /> - {/* 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 ${SnappingManager.userColor}` }}> - {StrCast(this.activeItem.presentation_effectDirection)} + <div> + <Dropdown + color={SnappingManager.userColor} + formLabel="Slide Effect" + formLabelPlacement="left" + closeOnSelect + items={effectItems} + 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} + /> + </div> + <div className="presBox-gpt-chat"> + {/* Effect direction */} + {/* Only applies to certain effects */} + {(effect === PresEffect.Flip || effect === PresEffect.Bounce || effect === PresEffect.Roll) && ( + <> + <div className="ribbon-doubleButton"> + <div className="presBox-subheading">EFFECT DIRECTION</div> + <div style={{ width: '100%' }}> + <div className="presBox-icon-list" style={{ width: 'fit-content', margin: 'auto' }}> + <IconButton + type={Type.TERT} + color={activeItem.presentation_effectDirection === PresEffectDirection.Left ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor} + tooltip="Left" + icon={<FaArrowRight size="16px" />} + onClick={() => this.updateEffectDirection(PresEffectDirection.Left)} + /> + <IconButton + type={Type.TERT} + color={activeItem.presentation_effectDirection === PresEffectDirection.Right ? SnappingManager.userVariantColor : SnappingManager.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 ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor} + tooltip="Top" + icon={<FaArrowDown size="16px" />} + onClick={() => this.updateEffectDirection(PresEffectDirection.Top)} + /> + <IconButton + type={Type.TERT} + color={activeItem.presentation_effectDirection === PresEffectDirection.Bottom ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor} + tooltip="Bottom" + icon={<FaArrowUp size="16px" />} + onClick={() => this.updateEffectDirection(PresEffectDirection.Bottom)} + /> + </> + )} + </div> + </div> </div> - </div> - <div className="presBox-icon-list"> - <IconButton - type={Type.TERT} - color={activeItem.presentation_effectDirection === PresEffectDirection.Left ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor} - tooltip="Left" - icon={<FaArrowRight size="16px" />} - onClick={() => this.updateEffectDirection(PresEffectDirection.Left)} - /> - <IconButton + </> + )} + {effect !== PresEffect.Lightspeed && ( + <> + <Dropdown + color={SnappingManager.userColor} + formLabel="Effect Timing" + formLabelPlacement="left" + closeOnSelect + items={effectTimings} + selectedVal={timingConfig.type} + setSelectedVal={val => this.updateEffectTiming(activeItem, { type: val as SpringType, ...springMappings[val] })} + dropdownType={DropdownType.SELECT} type={Type.TERT} - color={activeItem.presentation_effectDirection === PresEffectDirection.Right ? SnappingManager.userVariantColor : SnappingManager.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 ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor} - tooltip="Top" - icon={<FaArrowDown size="16px" />} - onClick={() => this.updateEffectDirection(PresEffectDirection.Top)} - /> - <IconButton - type={Type.TERT} - color={activeItem.presentation_effectDirection === PresEffectDirection.Bottom ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor} - tooltip="Bottom" - icon={<FaArrowUp size="16px" />} - onClick={() => this.updateEffectDirection(PresEffectDirection.Bottom)} - /> - </> - )} - </div> - </> - )} - {/* Spring settings */} - {/* No spring settings for jackinthebox (lightspeed) */} - {effect !== PresEffect.Lightspeed && ( - <> - <Dropdown - color={SnappingManager.userColor} - formLabel="Effect Timing" - closeOnSelect - items={effectTimings} - selectedVal={timingConfig.type} - setSelectedVal={val => this.updateEffectTiming(activeItem, { type: val as SpringType, ...springMappings[val] })} - 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> - <div onPointerDown={e => e.stopPropagation()}> - {/* prettier-ignore */} - <Slider min={1} max={1000} step={5} size="small" - value={timingConfig.stiffness} - onChange={(e, val) => timingConfig && this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, stiffness: val as number })} - valueLabelDisplay="auto" - /> - </div> - <div>Damping</div> - <div onPointerDown={e => e.stopPropagation()}> - {/* prettier-ignore */} - <Slider min={1} max={100} step={1} size="small" - value={timingConfig.damping} - onChange={(e, val) => timingConfig && this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, damping: val as number })} - valueLabelDisplay="auto" - /> - </div> - <div>Mass</div> - <div onPointerDown={e => e.stopPropagation()}> - {/* prettier-ignore */} - <Slider min={1} max={10} step={1} size="small" - value={timingConfig.mass} - onChange={(e, val) => timingConfig && this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, mass: val as number })} - valueLabelDisplay="auto" - /> + + <div style={{ display: SnappingManager.PropertiesWidth < 1 ? 'none' : undefined }}> + {/* Custom */} + <div + className="presBox-show-hide-dropdown" + style={{ display: effect !== PresEffect.None ? undefined : 'none' }} + onClick={e => { + e.stopPropagation(); + this.setSpringEditorVisibility(!this._showSpringEditor); + }}> + SPRING SETTINGS + <FontAwesomeIcon icon={this._showSpringEditor ? 'chevron-down' : 'chevron-up'} /> </div> - <div style={{ display: 'flex', alignItems: 'center'}}> - <Button - type={Type.TERT} - tooltip="show preview of slide animation effect" - size={Size.SMALL} - color={SnappingManager.userColor} - background={'transparent'} - onClick={action(() => { - this._showPreview = false; - setTimeout(action(() => { this._showPreview = true; }) );// prettier-ignore - })} - text={'Preview of: ' + effect + ', ' + direction} - /> - <div className="presBox-option-block presBox-option-center"> - <div className="presBox-effect-container"> - {!this._showPreview ? null : ( - <SlideEffect dir={direction} presEffect={effect} springSettings={timingConfig}> - <div className="presBox-effect-demo-box" style={{ backgroundColor: springPreviewColors[0] }} /> - </SlideEffect> - )} + {/* Spring settings */} + {/* No spring settings for jackinthebox (lightspeed) */} + {this._showSpringEditor && effect !== PresEffect.None && ( + <> + <div className="presBox-springSlider"> + <span>Tension</span> + <div onPointerDown={e => e.stopPropagation()}> + {/* prettier-ignore */} + <Slider min={1} max={1000} step={5} size="small" + value={timingConfig.stiffness} + onChange={(e, val) => timingConfig && this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, stiffness: val as number })} + valueLabelDisplay="auto" + /> + </div> </div> - </div> - </div> - </> - )} - </> - )} + <div className="presBox-springSlider"> + <span>Damping</span> + <div onPointerDown={e => e.stopPropagation()}> + {/* prettier-ignore */} + <Slider min={1} max={100} step={1} size="small" + value={timingConfig.damping} + onChange={(e, val) => timingConfig && this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, damping: val as number })} + valueLabelDisplay="auto" + /> + </div> + </div> + <div className="presBox-springSlider"> + <span>Mass</span> + <div onPointerDown={e => e.stopPropagation()}> + {/* prettier-ignore */} + <Slider min={1} max={10} step={1} size="small" + value={timingConfig.mass} + onChange={(e, val) => timingConfig && this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, mass: val as number })} + valueLabelDisplay="auto" + /> + </div> + </div> + </> + )} + </div> + </> + )} + </div> </div> {/* Toggles */} |