diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/PropertiesView.tsx | 70 | ||||
-rw-r--r-- | src/client/views/nodes/trails/PresBox.scss | 36 | ||||
-rw-r--r-- | src/client/views/nodes/trails/PresBox.tsx | 591 |
3 files changed, 350 insertions, 347 deletions
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 42aa6782f..bed96f600 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -119,6 +119,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps // Pres Trails booleans: @observable openPresTransitions: boolean = true; @observable openPresProgressivize: boolean = false; + @observable openPresMedia: boolean = false; @observable openPresVisibilityAndDuration: boolean = false; @observable openAddSlide: boolean = false; @observable openSlideOptions: boolean = false; @@ -1936,74 +1937,74 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps </div> </div> {!selectedItem ? null : ( - <div className="propertiesView-presentationTrails"> + <div className="propertiesView-section"> <div - className="propertiesView-presentationTrails-title" + className="propertiesView-sectionTitle" onPointerDown={action(() => { - this.openPresTransitions = !this.openPresTransitions; + this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration; })} style={{ color: SnappingManager.userColor, - backgroundColor: this.openPresTransitions ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + backgroundColor: SnappingManager.userVariantColor, }}> - <FontAwesomeIcon style={{ alignSelf: 'center' }} icon="rocket" /> Transitions + Visibility <div className="propertiesView-presentationTrails-title-icon"> - <FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg" /> + <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg" /> </div> </div> - {this.openPresTransitions ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.transitionDropdown}</div> : null} + {this.openPresVisibilityAndDuration ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.visibilityDurationDropdown}</div> : null} </div> )} {!selectedItem ? null : ( - <div className="propertiesView-presentationTrails"> + <div className="propertiesView-section"> <div - className="propertiesView-presentationTrails-title" + className="propertiesView-sectionTitle" onPointerDown={action(() => { - this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration; + this.openPresProgressivize = !this.openPresProgressivize; })} style={{ color: SnappingManager.userColor, - backgroundColor: this.openPresVisibilityAndDuration ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + backgroundColor: SnappingManager.userVariantColor, }}> - <FontAwesomeIcon style={{ alignSelf: 'center' }} icon="rocket" /> Visibility + Progressivize <div className="propertiesView-presentationTrails-title-icon"> - <FontAwesomeIcon icon={this.openPresVisibilityAndDuration ? 'caret-down' : 'caret-right'} size="lg" /> + <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg" /> </div> </div> - {this.openPresVisibilityAndDuration ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.visibilityDurationDropdown}</div> : null} + {this.openPresProgressivize ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.progressivizeDropdown}</div> : null} </div> )} {!selectedItem ? null : ( - <div className="propertiesView-presentationTrails"> + <div className="propertiesView-section"> <div - className="propertiesView-presentationTrails-title" + className="propertiesView-sectionTitle" onPointerDown={action(() => { - this.openPresProgressivize = !this.openPresProgressivize; + this.openPresMedia = !this.openPresMedia; })} style={{ color: SnappingManager.userColor, - backgroundColor: this.openPresProgressivize ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + backgroundColor: SnappingManager.userVariantColor, }}> - <FontAwesomeIcon style={{ alignSelf: 'center' }} icon="rocket" /> Progressivize + Media <div className="propertiesView-presentationTrails-title-icon"> - <FontAwesomeIcon icon={this.openPresProgressivize ? 'caret-down' : 'caret-right'} size="lg" /> + <FontAwesomeIcon icon={this.openPresMedia ? 'caret-down' : 'caret-right'} size="lg" /> </div> </div> - {this.openPresProgressivize ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.progressivizeDropdown}</div> : null} + {this.openPresMedia ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.mediaDropdown}</div> : null} </div> )} {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? null : ( - <div className="propertiesView-presentationTrails"> + <div className="propertiesView-section"> <div - className="propertiesView-presentationTrails-title" + className="propertiesView-sectionTitle" onPointerDown={action(() => { this.openSlideOptions = !this.openSlideOptions; })} style={{ color: SnappingManager.userColor, - backgroundColor: this.openSlideOptions ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + backgroundColor: SnappingManager.userVariantColor, }}> - <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={type === DocumentType.AUDIO ? 'file-audio' : 'file-video'} /> {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'} + {type === DocumentType.AUDIO ? 'file-audio' : 'file-video'} <div className="propertiesView-presentationTrails-title-icon"> <FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg" /> </div> @@ -2011,6 +2012,25 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps {this.openSlideOptions ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.mediaOptionsDropdown}</div> : null} </div> )} + {!selectedItem ? null : ( + <div className="propertiesView-section"> + <div + className="propertiesView-sectionTitle" + onPointerDown={action(() => { + this.openPresTransitions = !this.openPresTransitions; + })} + style={{ + color: SnappingManager.userColor, + backgroundColor: SnappingManager.userVariantColor, + }}> + Transitions + <div className="propertiesView-presentationTrails-title-icon"> + <FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg" /> + </div> + </div> + {this.openPresTransitions ? <div className="propertiesView-presentationTrails-content">{PresBox.Instance.transitionDropdown}</div> : null} + </div> + )} </div> ); } diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss index a181687f8..e34e1b380 100644 --- a/src/client/views/nodes/trails/PresBox.scss +++ b/src/client/views/nodes/trails/PresBox.scss @@ -18,6 +18,7 @@ max-width: calc(100% - 25px); width: 100%; padding: 15px; + padding-left: 0px; } .pres-chat { @@ -100,6 +101,14 @@ gap: 4px; } +.presBox-switches { + display: flex; + width: 100%; + > div { + width: 100%; + } +} + .presBox-bezier-editor { border: 1px solid rgb(221, 221, 221); border-radius: 4px; @@ -302,7 +311,7 @@ } .presBox-toggles { - display: flex; + display: flow; overflow-x: auto; } @@ -387,7 +396,7 @@ font-size: 11; font-weight: 400; margin-top: 10px; - max-width: min(100px, 25%); + max-width: min(85px, 25%); width: 100%; } .presBox-springSlider { @@ -567,20 +576,17 @@ } .presBox-input { - border: none; background-color: transparent; - width: 40; - // padding: 8px; - // border-radius: 4px; - // width: 30; - // height: 100%; - // background: none; - // border: none; - // text-align: right; + text-align: center; + width: 100%; + height: 15px; + font-size: 10; } - - .presBox-input:focus { - outline: none; + .presBox-inputNumber { + border: none; + background-color: transparent; + width: 100%; + max-width: 25px; } .ribbon-frameSelector { @@ -784,7 +790,7 @@ font-weight: 200; height: 20; background-color: $white; - display: flex; + display: inline-flex; color: $black; border-radius: 5px; width: max-content; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 5dbf502d2..28afe1df4 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1,4 +1,4 @@ -import { Button, Dropdown, DropdownType, IconButton, Size, Toggle, ToggleType, Type } from '@dash/components'; +import { Button, Dropdown, DropdownType, IconButton, Size, Type } from '@dash/components'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import Slider from '@mui/material/Slider'; @@ -101,8 +101,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @observable _forceKeyEvents: boolean = false; @observable _showAIGallery = false; - @observable _showBezierEditor = false; - @observable _showSpringEditor = false; @observable _showPreview = true; @observable _easeDropdownVal = 'ease'; @@ -150,8 +148,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { setAnimationChat = action((input: string) => { this._animationChat = input; }); // prettier-ignore setIsLoading = action((input?: boolean) => { this._isLoading = !!input; }); // prettier-ignore 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]})`); @@ -390,7 +386,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { if (!first) { const presBulletTiming = 500; // bcz: hardwired for now Doc.linkFollowUnhighlight(); - Doc.HighlightDoc(listItemDoc); + Doc.linkFollowHighlight(listItemDoc); listItemDoc.presentation_effect = this.activeItem.presBulletEffect; listItemDoc.presentation_transition = presBulletTiming; listItemDoc.opacity = undefined; @@ -1612,20 +1608,22 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </Tooltip> </div> {[DocumentType.AUDIO, DocumentType.VID].includes(targetType as DocumentType) ? null : ( - <> - <div className="ribbon-doubleButton"> - <div className="presBox-subheading">Slide Duration</div> - <div className="ribbon-property" style={{ border: `solid 1px ${SnappingManager.userColor}` }}> - <input className="presBox-input" type="number" readOnly value={duration} onKeyDown={e => e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s + <div className="ribbon-doubleButton"> + <Tooltip title={<div>How long to view the slide before transitioning to the next slide</div>}> + <div className="presBox-subheading">DURATION</div> + </Tooltip> + <div className="presBox-subheading-slider"> + {PresBox.inputter('0.1', '0.1', '10', duration, targetType !== DocumentType.AUDIO, this.updateDurationTime)} + <div className="slider-headers"> + <div className="slider-text">Short</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 className="ribbon-property" style={{ border: `solid 1px ${SnappingManager.userColor}`, display: 'flex', maxWidth: 60, width: '100%' }}> + <input className="presBox-inputNumber" type="number" readOnly value={duration} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.updateDurationTime(e.target.value))} /> + <span>s</span> </div> - </> + </div> )} </div> </div> @@ -1633,28 +1631,62 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } return undefined; } - @computed get progressivizeDropdown() { + + @computed get mediaDropdown() { const { activeItem } = this; if (activeItem && this.targetDoc) { - const effect = activeItem.presBulletEffect ? activeItem.presBulletEffect : PresMovement.None; - const bulletEffect = (presEffect: PresEffect) => ( - <div - className={`presBox-dropdownOption ${activeItem.presentation_effect === presEffect || (presEffect === PresEffect.None && !activeItem.presentation_effect) ? 'active' : ''}`} - onPointerDown={StopEvent} - onClick={() => this.updateEffect(presEffect, true)}> - {presEffect} + return ( + <div className="presBox-option-block"> + <div className="presBox-ribbon presbox-toggles"> + <Tooltip title={<div className="dash-tooltip">Should first bullet be progressively disclosed or does it appear with slide.</div>}> + <div + className={`ribbon-toggle ${BoolCast(activeItem.presentation_playAudio) ? 'active' : ''}`} + style={{ + border: `solid 1px ${SnappingManager.userColor}`, + color: SnappingManager.userColor, + background: BoolCast(activeItem.presentation_playAudio) ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + }} + onClick={() => { + activeItem.presentation_playAudio = !BoolCast(activeItem.presentation_playAudio); + }}> + Play Audio Annotation + </div> + </Tooltip> + <Tooltip title={<div className="dash-tooltip">Should first bullet be progressively disclosed or does it appear with slide.</div>}> + <div + className={`ribbon-toggle ${BoolCast(activeItem.presentation_zoomText) ? 'active' : ''}`} + style={{ + border: `solid 1px ${SnappingManager.userColor}`, + color: SnappingManager.userColor, + background: BoolCast(activeItem.presentation_zoomText) ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + }} + onClick={() => { + activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText); + }}> + Zoom Text Selections + </div> + </Tooltip> + </div> </div> ); + } + return null; + } + @computed get progressivizeDropdown() { + const { activeItem } = this; + if (activeItem && this.targetDoc) { return ( <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 ${SnappingManager.userColor}` }} - type="checkbox" - onChange={() => { + <div className="presBox-toggles presBox-ribbon"> + <Tooltip title={<div className="dash-tooltip">whether progressivization is active for this slide</div>}> + <div + className={`ribbon-toggle ${Cast(activeItem.presentation_indexed, 'number', null) !== undefined ? 'active' : ''}`} + style={{ + border: `solid 1px ${SnappingManager.userColor}`, + color: SnappingManager.userColor, + background: Cast(activeItem.presentation_indexed, 'number', null) !== undefined ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + }} + onClick={() => { activeItem.presentation_indexed = activeItem.presentation_indexed === undefined ? 0 : undefined; activeItem.presentation_hideBefore = activeItem.presentation_indexed !== undefined; const tagDoc = PresBox.targetRenderedDoc(this.activeItem); @@ -1667,62 +1699,51 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { if (DocCast(activeItem.presentation_targetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`this.presentation_targetDoc.annotationOn?.["${dataField}"]`); else activeItem.data = ComputedField.MakeFunction(`this.presentation_targetDoc?.["${dataField}"]`); + }}> + Enable + </div> + </Tooltip> + <Tooltip title={<div className="dash-tooltip">Should first bullet be progressively disclosed or does it appear with slide.</div>}> + <div + className={`ribbon-toggle ${!NumCast(activeItem.presentation_indexedStart) ? 'active' : ''}`} + style={{ + border: `solid 1px ${SnappingManager.userColor}`, + color: SnappingManager.userColor, + background: !NumCast(activeItem.presentation_indexedStart) ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, }} - checked={Cast(activeItem.presentation_indexed, 'number', null) !== undefined} - /> - </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 ${SnappingManager.userColor}` }} - type="checkbox" - onChange={() => { + onClick={() => { 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 ${SnappingManager.userColor}` }} - type="checkbox" - onChange={() => { - activeItem.presBulletExpand = !activeItem.presBulletExpand; - }} - checked={BoolCast(activeItem.presBulletExpand)} - /> - </div> - - <div className="ribbon-box"> - Bullet Effect + }}> + All Bullets + </div> + </Tooltip> + <Tooltip title={<div className="dash-tooltip">Whether the active bullet expands when active.</div>}> <div - className="presBox-dropdown" - onClick={action(e => { - e.stopPropagation(); - this._openBulletEffectDropdown = !this._openBulletEffectDropdown; - })} + className={`ribbon-toggle ${BoolCast(activeItem.presBulletExpand) ? 'active' : ''}`} style={{ + border: `solid 1px ${SnappingManager.userColor}`, color: SnappingManager.userColor, - background: SnappingManager.userVariantColor, - borderBottomLeftRadius: this._openBulletEffectDropdown ? 0 : 5, - border: this._openBulletEffectDropdown ? `solid 2px ${SnappingManager.userVariantColor}` : `solid 1px ${SnappingManager.userColor}`, + background: BoolCast(activeItem.presBulletExpand) ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + }} + onClick={() => { + activeItem.presBulletExpand = !activeItem.presBulletExpand; }}> - {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: SnappingManager.userColor, background: SnappingManager.userBackgroundColor }} - onPointerDown={e => e.stopPropagation()}> - {Object.values(PresEffect) - .filter(v => isNaN(Number(v))) - .map(pEffect => bulletEffect(pEffect))} - </div> + Expand Active </div> - </div> + </Tooltip> </div> + <Dropdown + color={SnappingManager.userColor} + formLabel="Effect" + toolTip="Animation effect to use when bullet activates" + formLabelPlacement="left" + closeOnSelect + items={Object.values(PresEffect).map(v => ({ text: v.toString(), val: v }))} + selectedVal={StrCast(activeItem.presBulletEffect, PresMovement.None)} + setSelectedVal={val => this.updateEffect(val as PresEffect, true)} + dropdownType={DropdownType.SELECT} + type={Type.TERT} + /> </div> ); } @@ -1733,6 +1754,77 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { return <div />; } + /** + * This chatbox is for getting slide effect transition suggestions from gpt and visualizing them + */ + @computed get aiEffects() { + return ( + <div className="presBox-gpt-chat" style={{ display: SnappingManager.PropertiesWidth < 1 || !this._showAIGallery ? 'none' : undefined }}> + {/* Custom */} + <div className="pres-chat"> + <div className="pres-chatbox-container-ai"> + <ReactTextareaAutosize + 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 => { + this.stopDictation(); + e.stopPropagation(); + }} + /> + </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={SnappingManager.userVariantColor} + onClick={this.customizeAnimations} + /> + </div> + <div style={{ 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> + ); + } + @computed get transitionDropdown() { const { activeItem } = this; // Retrieving spring timing properties @@ -1827,29 +1919,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { this._openBulletEffectDropdown = false; })}> <div className="presBox-option-block"> - <Dropdown - color={SnappingManager.userColor} - formLabel="Navigation" - formLabelPlacement="left" - closeOnSelect - items={movementItems} - selectedVal={this.movementName(activeItem)} - setSelectedVal={val => this.updateMovement(val as PresMovement)} - dropdownType={DropdownType.SELECT} - type={Type.TERT} - /> - <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> <div className="ribbon-doubleButton"> - <div className="presBox-subheading">ZOOM/EFFECT TIME</div> + <Tooltip title={<div>How long the transition (view navigation and slide animation effect) lasts</div>}> + <div className="presBox-subheading">SPEED</div> + </Tooltip> <div className="presBox-subheading-slider"> {PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.updateTransitionTime)} <div className="slider-headers"> @@ -1858,153 +1931,55 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </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))} /> + <input className="presBox-inputNumber" type="number" readOnly value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> <span>s</span> </div> </div> - {/* Easing function */} <Dropdown color={SnappingManager.userColor} - formLabel="Timing Function" + formLabel="View" formLabelPlacement="left" closeOnSelect - items={easeItems} - selectedVal={this.activeItem.presentation_easeFunc ? (StrCast(this.activeItem.presentation_easeFunc).startsWith('cubic') ? 'custom' : StrCast(this.activeItem.presentation_easeFunc)) : 'ease'} - setSelectedVal={val => { - if (typeof val === 'string') { - if (val !== 'custom') { - this.setEaseFunc(this.activeItem, val); - } else { - this.setBezierEditorVisibility(true); - this.setEaseFunc(this.activeItem, TIMING_DEFAULT_MAPPINGS.ease); - } - } - }} + items={movementItems} + selectedVal={this.movementName(activeItem)} + setSelectedVal={val => this.updateMovement(val as PresMovement)} 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); - }}> - TIMING EDITOR - <FontAwesomeIcon icon={this._showBezierEditor ? 'chevron-down' : 'chevron-up'} /> + <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 className="presBox-inputNumber" readOnly type="number" value={zoom} onChange={e => this.updateZoom(e.target.value)} /> + <span>%</span> + </div> </div> + {/* Easing function */} + {[PresMovement.None, PresMovement.Jump, ''].includes(StrCast(activeItem.presentation_movement) as PresMovement) ? null : ( + <Dropdown + color={SnappingManager.userColor} + formLabel="Timing" + formLabelPlacement="left" + closeOnSelect + items={easeItems} + selectedVal={this.activeItem.presentation_easeFunc ? (StrCast(this.activeItem.presentation_easeFunc).startsWith('cubic') ? 'custom' : StrCast(this.activeItem.presentation_easeFunc)) : 'ease'} + setSelectedVal={val => typeof val === 'string' && this.setEaseFunc(this.activeItem, val !== 'custom' ? val : TIMING_DEFAULT_MAPPINGS.ease)} + dropdownType={DropdownType.SELECT} + type={Type.TERT} + /> + )} </div> </div> {/* Cubic bezier editor */} - {this._showBezierEditor && ( + {StrCast(activeItem.presentation_easeFunc).includes('cubic-bezier') && ( <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" 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="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 => { - this.stopDictation(); - e.stopPropagation(); - }} - /> - </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={SnappingManager.userVariantColor} - 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 className={`presBox-ribbon ${this._transitionTools && this.layoutDoc.presentation_status === PresStatus.Edit ? 'active' : ''}`} onPointerDown={StopEvent} @@ -2017,10 +1992,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { })}> <div className="presBox-option-block"> {/* Effect dropdown */} - <div> + <div style={{ display: 'flex' }}> <Dropdown color={SnappingManager.userColor} - formLabel="Slide Effect" + formLabel="Effect" + toolTip="Animation effect to apply when transitiong to slide" formLabelPlacement="left" closeOnSelect items={effectItems} @@ -2033,58 +2009,68 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { dropdownType={DropdownType.SELECT} type={Type.TERT} /> + + <div + className={`ribbon-toggle ${this._showAIGallery ? 'active' : ''}`} + style={{ + border: `solid 1px ${SnappingManager.userColor}`, + color: SnappingManager.userColor, + background: this._showAIGallery ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + }} + onClick={() => this.setShowAIGalleryVisibilty(!this._showAIGallery)}> + MORE + </div> </div> + {this.aiEffects} <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 className="ribbon-doubleButton"> + <div className="presBox-subheading">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> )} {effect !== PresEffect.Lightspeed && ( <> <Dropdown color={SnappingManager.userColor} - formLabel="Effect Timing" + formLabel="Springiness" formLabelPlacement="left" closeOnSelect items={effectTimings} @@ -2095,20 +2081,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { /> <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> - {/* Spring settings */} {/* No spring settings for jackinthebox (lightspeed) */} - {this._showSpringEditor && effect !== PresEffect.None && ( + {StrCast(activeItem.presentation_effectTiming).includes('custom') && effect !== PresEffect.None && ( <> <div className="presBox-springSlider"> <span>Tension</span> @@ -2150,30 +2124,35 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { )} </div> </div> + </div> - {/* Toggles */} - <div className="presBox-option-block"> - <Toggle - formLabel="Play Audio Annotation" - toggleType={ToggleType.SWITCH} - toggleStatus={BoolCast(activeItem.presentation_playAudio)} - onClick={() => { - activeItem.presentation_playAudio = !BoolCast(activeItem.presentation_playAudio); - }} - color={SnappingManager.userColor} - /> - <Toggle - formLabel="Zoom Text Selections" - toggleType={ToggleType.SWITCH} - toggleStatus={BoolCast(activeItem.presentation_zoomText)} - onClick={() => { - activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText); - }} + {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" /> - <Button text="Apply to all" type={Type.TERT} color={SnappingManager.userVariantColor} onClick={() => this.applyTo(this.childDocs)} /> + <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> - </div> + )} + + <Button text="Apply to all slides" type={Type.TERT} color={SnappingManager.userVariantColor} onClick={() => this.applyTo(this.childDocs)} /> </> ); } @@ -2199,7 +2178,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { <div id="startTime" className="slider-number" style={{ color: SnappingManager.userColor, backgroundColor: SnappingManager.userBackgroundColor }}> <input className="presBox-input" - style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }} type="number" readOnly value={NumCast(activeItem.config_clipStart).toFixed(2)} @@ -2226,7 +2204,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { <input className="presBox-input" onKeyDown={e => e.stopPropagation()} - style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }} type="number" readOnly value={configClipEnd.toFixed(2)} |