diff options
-rw-r--r-- | src/client/views/nodes/trails/PresBox.scss | 28 | ||||
-rw-r--r-- | src/client/views/nodes/trails/PresBox.tsx | 402 |
2 files changed, 236 insertions, 194 deletions
diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss index 5fc356299..dd0007d82 100644 --- a/src/client/views/nodes/trails/PresBox.scss +++ b/src/client/views/nodes/trails/PresBox.scss @@ -1,5 +1,33 @@ @import '../../global/globalCssVariables.module.scss'; +.pres-chat { + // padding: 8px; + display: flex; + flex-direction: column; + gap: 8px; + // display: flex; + // align-items: center; + // gap: 16px; +} + +.pres-chatbox-container { + padding: 16px; + outline: 1px solid #999999; + border-radius: 16px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.pres-chatbox { + outline: none; + border: none; + resize: none; + font-family: Verdana, Geneva, sans-serif; + background-color: transparent; + overflow-y: hidden; +} + .presBox-cont { cursor: auto; position: absolute; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index ba80facce..7d78d4648 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -38,7 +38,7 @@ import './PresBox.scss'; import ReactLoading from 'react-loading'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; import ReactTextareaAutosize from 'react-textarea-autosize'; -import { Dropdown, IconButton, Type } from 'browndash-components'; +import { Button, Dropdown, IconButton, Type } from 'browndash-components'; import { BiMicrophone, BiX } from 'react-icons/bi'; import { AiOutlineSend } from 'react-icons/ai'; import { gptSlideProperties, gptTrailSlideCustomization } from '../../../apis/gpt/customization'; @@ -131,7 +131,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @action public setChatActive = (active: boolean) => { - this.chatActive = active; + this.toggleProperties(); }; @action @@ -307,7 +307,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @action customizeWithGPT = async (input: string) => { - console.log('Slide to modify', this.slideToModify); // const testInput = 'change title to Customized Slide, transition for 2.3s with fade in effect'; // if (!this.slideToModify) return; this.setIsRecording(false); @@ -315,7 +314,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { let currSlideProperties: { [key: string]: any } = {}; for (const key of gptSlideProperties) { - currSlideProperties[key] = this.activeItem[key]; + if (this.activeItem[key]) { + currSlideProperties[key] = this.activeItem[key]; + } else { + // default values + if (key === 'presentation_transition') { + currSlideProperties[key] = 500; + } else if (key === 'config_zoom') { + currSlideProperties[key] = 1.0; + } + } } console.log('current slide props', currSlideProperties); @@ -847,8 +855,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { navigateToActiveItem = (afterNav?: () => void) => { const activeItem: Doc = this.activeItem; console.log('active item', activeItem); - // GPT update - this.slideToModify = activeItem; + const targetDoc: Doc = this.targetDoc; const finished = () => { afterNav?.(); @@ -1797,6 +1804,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } return null; } + + @computed get gptDropdown() { + const activeItem = this.activeItem; + return <div></div>; + } + @computed get transitionDropdown() { const activeItem = this.activeItem; const preseEffect = (effect: PresEffect) => ( @@ -1829,19 +1842,77 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { const zoom = NumCast(activeItem.config_zoom, 1) * 100; const effect = activeItem.presentation_effect ? activeItem.presentation_effect : PresMovement.None; return ( - <div - className={`presBox-ribbon ${this._transitionTools && this.layoutDoc.presentation_status === PresStatus.Edit ? 'active' : ''}`} - onPointerDown={StopEvent} - onPointerUp={StopEvent} - onClick={action(e => { - e.stopPropagation(); - this._openMovementDropdown = false; - this._openEffectDropdown = false; - this._openBulletEffectDropdown = false; - })}> - <div className="ribbon-box"> - Movement - {/* <Dropdown + <> + {/* GPT Component */} + <div style={{ padding: '8px' }}> + Customize with GPT + <div className="pres-chat"> + <div className="pres-chatbox-container"> + <ReactTextareaAutosize + ref={r => (this._inputref = r)} + minRows={1} + placeholder="Customize..." + className="pres-chatbox" + autoFocus={true} + value={this.chatInput} + onChange={e => { + this.setChatInput(e.target.value); + }} + onKeyDown={e => { + this.stopDictation(true); + e.stopPropagation(); + }} + /> + <IconButton + type={Type.TERT} + color={this.isRecording ? '#2bcaff' : StrCast(Doc.UserDoc().userVariantColor)} + tooltip="Record" + icon={<BiMicrophone size={'16px'} />} + onClick={() => { + if (!this.isRecording) { + this.recordDictation(); + } else { + this.stopDictation(true); + } + }} + /> + </div> + <Button + style={{ alignSelf: 'flex-end' }} + text="Send" + type={Type.TERT} + icon={this.isLoading ? <ReactLoading type="spin" color={'#ffffff'} width={20} height={20} /> : <AiOutlineSend />} + iconPlacement="right" + color={StrCast(Doc.UserDoc().userVariantColor)} + onClick={() => { + this.customizeWithGPT(this.chatInput); + }} + /> + + {/* <IconButton + type={Type.TERT} + color={!this.isLoading ? StrCast(Doc.UserDoc().userVariantColor) : '#7c7c7c'} + tooltip="Send" + icon={<AiOutlineSend size={'16px'} />} + onClick={() => { + this.customizeWithGPT(this.chatInput); + }} + /> */} + </div> + </div> + <div + className={`presBox-ribbon ${this._transitionTools && this.layoutDoc.presentation_status === PresStatus.Edit ? 'active' : ''}`} + onPointerDown={StopEvent} + onPointerUp={StopEvent} + onClick={action(e => { + e.stopPropagation(); + this._openMovementDropdown = false; + this._openEffectDropdown = false; + this._openBulletEffectDropdown = false; + })}> + <div className="ribbon-box"> + Movement + {/* <Dropdown color={StrCast(Doc.UserDoc().userColor)} formLabel={'Type'} closeOnSelect={true} @@ -1854,142 +1925,143 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { type={Type.TERT} fillWidth /> */} - <div - className="presBox-dropdown" - onClick={action(e => { - e.stopPropagation(); - this._openMovementDropdown = !this._openMovementDropdown; - })} - style={{ - color: SettingsManager.userColor, - background: SettingsManager.userVariantColor, - borderBottomLeftRadius: this._openMovementDropdown ? 0 : 5, - border: this._openMovementDropdown ? `solid 2px ${SettingsManager.userVariantColor}` : `solid 1px ${SettingsManager.userColor}`, - }}> - {this.movementName(activeItem)} - <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openMovementDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} /> <div - className="presBox-dropdownOptions" - id={'presBoxMovementDropdown'} - onPointerDown={StopEvent} + className="presBox-dropdown" + onClick={action(e => { + e.stopPropagation(); + this._openMovementDropdown = !this._openMovementDropdown; + })} style={{ color: SettingsManager.userColor, - background: SettingsManager.userBackgroundColor, - display: this._openMovementDropdown ? 'grid' : 'none', + background: SettingsManager.userVariantColor, + borderBottomLeftRadius: this._openMovementDropdown ? 0 : 5, + border: this._openMovementDropdown ? `solid 2px ${SettingsManager.userVariantColor}` : `solid 1px ${SettingsManager.userColor}`, }}> - {presMovement(PresMovement.None)} - {presMovement(PresMovement.Center)} - {presMovement(PresMovement.Zoom)} - {presMovement(PresMovement.Pan)} - {presMovement(PresMovement.Jump)} - </div> - </div> - <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 ${SettingsManager.userColor}` }}> - <input className="presBox-input" type="number" readOnly={true} value={zoom} onChange={e => this.updateZoom(e.target.value)} />% + {this.movementName(activeItem)} + <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openMovementDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} /> + <div + className="presBox-dropdownOptions" + id={'presBoxMovementDropdown'} + onPointerDown={StopEvent} + style={{ + color: SettingsManager.userColor, + background: SettingsManager.userBackgroundColor, + display: this._openMovementDropdown ? 'grid' : 'none', + }}> + {presMovement(PresMovement.None)} + {presMovement(PresMovement.Center)} + {presMovement(PresMovement.Zoom)} + {presMovement(PresMovement.Pan)} + {presMovement(PresMovement.Jump)} + </div> </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 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 ${SettingsManager.userColor}` }}> + <input className="presBox-input" type="number" readOnly={true} value={zoom} onChange={e => this.updateZoom(e.target.value)} />% </div> - <div className="ribbon-propertyUpDownItem" onClick={() => this.updateZoom(String(zoom), -0.1)}> - <FontAwesomeIcon icon={'caret-down'} /> + <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> - </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 ${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'} /> + {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 ${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-propertyUpDownItem" onClick={() => this.updateTransitionTime(String(transitionSpeed), -1000)}> - <FontAwesomeIcon icon={'caret-down'} /> + <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', '100', 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> </div> - {PresBox.inputter('0.1', '0.1', '100', 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> - </div> - <div className="ribbon-box"> - Effects - <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> - <div className="presBox-subheading">Play Audio Annotation</div> - <input - className="presBox-checkbox" - style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }} - type="checkbox" - onChange={() => (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} - checked={BoolCast(activeItem.presPlayAudio)} - /> - </div> - <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> - <div className="presBox-subheading">Zoom Text Selections</div> - <input - className="presBox-checkbox" - style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }} - type="checkbox" - onChange={() => (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))} - checked={BoolCast(activeItem.presentation_zoomText)} - /> - </div> - <div - className="presBox-dropdown" - onClick={action(e => { - e.stopPropagation(); - this._openEffectDropdown = !this._openEffectDropdown; - })} - style={{ - color: SettingsManager.userColor, - background: SettingsManager.userVariantColor, - borderBottomLeftRadius: this._openEffectDropdown ? 0 : 5, - border: this._openEffectDropdown ? `solid 2px ${SettingsManager.userVariantColor}` : `solid 1px ${SettingsManager.userColor}`, - }}> - {effect?.toString()} - <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} /> + <div className="ribbon-box"> + Effects + <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> + <div className="presBox-subheading">Play Audio Annotation</div> + <input + className="presBox-checkbox" + style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }} + type="checkbox" + onChange={() => (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} + checked={BoolCast(activeItem.presPlayAudio)} + /> + </div> + <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> + <div className="presBox-subheading">Zoom Text Selections</div> + <input + className="presBox-checkbox" + style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }} + type="checkbox" + onChange={() => (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))} + checked={BoolCast(activeItem.presentation_zoomText)} + /> + </div> <div - className="presBox-dropdownOptions" - id={'presBoxMovementDropdown'} + className="presBox-dropdown" + onClick={action(e => { + e.stopPropagation(); + this._openEffectDropdown = !this._openEffectDropdown; + })} style={{ color: SettingsManager.userColor, - background: SettingsManager.userBackgroundColor, - display: this._openEffectDropdown ? 'grid' : 'none', - }} - onPointerDown={e => e.stopPropagation()}> - {Object.values(PresEffect) - .filter(v => isNaN(Number(v))) - .map(effect => preseEffect(effect))} + background: SettingsManager.userVariantColor, + borderBottomLeftRadius: this._openEffectDropdown ? 0 : 5, + border: this._openEffectDropdown ? `solid 2px ${SettingsManager.userVariantColor}` : `solid 1px ${SettingsManager.userColor}`, + }}> + {effect?.toString()} + <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} /> + <div + className="presBox-dropdownOptions" + id={'presBoxMovementDropdown'} + style={{ + color: SettingsManager.userColor, + background: SettingsManager.userBackgroundColor, + display: this._openEffectDropdown ? 'grid' : 'none', + }} + onPointerDown={e => e.stopPropagation()}> + {Object.values(PresEffect) + .filter(v => isNaN(Number(v))) + .map(effect => preseEffect(effect))} + </div> </div> - </div> - <div className="ribbon-doubleButton" style={{ display: effect === PresEffectDirection.None ? 'none' : 'inline-flex' }}> - <div className="presBox-subheading">Effect direction</div> - <div className="ribbon-property" style={{ border: `solid 1px ${SettingsManager.userColor}` }}> - {StrCast(this.activeItem.presentation_effectDirection)} + <div className="ribbon-doubleButton" style={{ display: effect === PresEffectDirection.None ? 'none' : 'inline-flex' }}> + <div className="presBox-subheading">Effect direction</div> + <div className="ribbon-property" style={{ border: `solid 1px ${SettingsManager.userColor}` }}> + {StrCast(this.activeItem.presentation_effectDirection)} + </div> + </div> + <div className="effectDirection" style={{ display: effect === PresEffectDirection.None ? 'none' : 'grid', width: 40 }}> + {presDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} + {presDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})} + {presDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})} + {presDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})} + {presDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })} </div> </div> - <div className="effectDirection" style={{ display: effect === PresEffectDirection.None ? 'none' : 'grid', width: 40 }}> - {presDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} - {presDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})} - {presDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})} - {presDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})} - {presDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })} - </div> - </div> - <div className="ribbon-final-box"> - <div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}> - Apply to all + <div className="ribbon-final-box"> + <div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}> + Apply to all + </div> </div> </div> - </div> + </> ); } } @@ -2764,65 +2836,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } */} </div> {/* presbox chatbox */} - {this.chatActive && ( - <div className="presBox-chatbox"> - <div style={{ alignSelf: 'flex-end' }}> - {this.isLoading ? ( - <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} width={14} height={14} /> - ) : ( - <IconButton - type={Type.PRIM} - color={StrCast(Doc.UserDoc().userVariantColor)} - tooltip="Close" - icon={<BiX size={'16px'} />} - onClick={() => { - this.setChatActive(false); - }} - /> - )} - </div> - <ReactTextareaAutosize - ref={r => (this._inputref = r)} - minRows={3} - placeholder="Customize..." - className="pres-chatbox" - autoFocus={true} - value={this.chatInput} - onChange={e => { - this.setChatInput(e.target.value); - }} - onKeyDown={e => { - this.stopDictation(true); - e.stopPropagation(); - }} - /> - {/* <input className="chatbox" placeholder="Customize..." value={this.chatInput} onChange={e => this.setChatInput(e.target.value)} /> */} - <div style={{ alignSelf: 'flex-end', display: 'flex', gap: '8px' }}> - <IconButton - type={Type.TERT} - color={this.isRecording ? 'red' : StrCast(Doc.UserDoc().userVariantColor)} - tooltip="Record" - icon={<BiMicrophone size={'16px'} />} - onClick={() => { - if (!this.isRecording) { - this.recordDictation(); - } else { - this.stopDictation(true); - } - }} - /> - <IconButton - type={Type.TERT} - color={!this.isLoading ? StrCast(Doc.UserDoc().userVariantColor) : '#7c7c7c'} - tooltip="Send" - icon={<AiOutlineSend size={'16px'} />} - onClick={() => { - this.customizeWithGPT(this.chatInput); - }} - /> - </div> - </div> - )} + {this.chatActive && <div className="presBox-chatbox"></div>} </div> ); } |