From f66eaad00dbfe27e8dbe28019d1148a70f6ba0d9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 3 Feb 2025 12:44:38 -0500 Subject: fixed defaults for roll animations effect. fixed hideBefore pres effect to not show Doc before effect starts --- src/client/views/nodes/trails/PresBox.tsx | 43 ++++++++++++++----------------- 1 file changed, 20 insertions(+), 23 deletions(-) (limited to 'src/client/views/nodes/trails') diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index f23b32a48..7ca0bbc8f 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1,7 +1,8 @@ +import { Button, Dropdown, DropdownType, IconButton, Toggle, ToggleType, Type } from '@dash/components'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import Slider from '@mui/material/Slider'; -import { Button, Dropdown, DropdownType, IconButton, Toggle, ToggleType, Type } from '@dash/components'; +import _ from 'lodash'; import { IReactionDisposer, ObservableSet, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -40,7 +41,7 @@ import { CollectionFreeFormPannableContents } from '../../collections/collection import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; -import { FocusViewOptions } from '../FocusViewOptions'; +import { FocusEffectDelay, FocusViewOptions } from '../FocusViewOptions'; import { OpenWhere, OpenWhereMod } from '../OpenWhere'; import { ScriptingBox } from '../ScriptingBox'; import CubicBezierEditor, { EaseFuncToPoints, TIMING_DEFAULT_MAPPINGS } from './CubicBezierEditor'; @@ -48,7 +49,6 @@ import './PresBox.scss'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; import SlideEffect from './SlideEffect'; import { AnimationSettings, SpringSettings, SpringType, easeItems, effectItems, effectTimings, movementItems, presEffectDefaultTimings, springMappings, springPreviewColors } from './SpringUtils'; -import _ from 'lodash'; @observer export class PresBox extends ViewBoxBaseComponent() { @@ -547,8 +547,10 @@ export class PresBox extends ViewBoxBaseComponent() { if (!group) this.clearSelectedArray(); this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); // Update selected array this.turnOffEdit(); - this.navigateToActiveItem(finished); // Handles movement to element only when presentationTrail is list - this.doHideBeforeAfter(); // Handles hide after/before + this.navigateToActiveItem((options: FocusViewOptions) => { + setTimeout(this.doHideBeforeAfter, FocusEffectDelay(options)); // Handles hide after/before + finished?.(); + }); // Handles movement to element only when presentationTrail is list } }); static pinDataTypes(target?: Doc): dataTypes { @@ -784,11 +786,9 @@ export class PresBox extends ViewBoxBaseComponent() { }); setTimeout( () => - Array.from(transitioned).forEach( - action(doc => { - doc._dataTransition = undefined; - }) - ), + Array.from(transitioned).forEach(doc => { + doc._dataTransition = undefined; + }), transTime + 10 ); } @@ -826,16 +826,16 @@ export class PresBox extends ViewBoxBaseComponent() { * a new tab. If presCollection is undefined it will open the document * on the right. */ - navigateToActiveItem = (afterNav?: () => void) => { + navigateToActiveItem = (afterNav?: (options: FocusViewOptions) => void) => { const { activeItem, targetDoc } = this; - const finished = () => { - afterNav?.(); + const finished = (options: FocusViewOptions) => { + afterNav?.(options); targetDoc[Animation] = undefined; }; const selViewCache = Array.from(this.selectedArray); const dragViewCache = Array.from(this._dragArray); const eleViewCache = Array.from(this._eleArray); - const resetSelection = action(() => { + const resetSelection = action((options: FocusViewOptions) => { if (!this._props.isSelected()) { const presDocView = DocumentView.getDocumentView(this.Document); if (presDocView) DocumentView.SelectView(presDocView, false); @@ -844,14 +844,14 @@ export class PresBox extends ViewBoxBaseComponent() { this._dragArray.splice(0, this._dragArray.length, ...dragViewCache); this._eleArray.splice(0, this._eleArray.length, ...eleViewCache); } - finished(); + finished(options); }); PresBox.NavigateToTarget(targetDoc, activeItem, resetSelection); }; public static PanelName = 'PRESBOX'; - static NavigateToTarget(targetDoc: Doc, activeItem: Doc, finished?: () => void) { + static NavigateToTarget(targetDoc: Doc, activeItem: Doc, finished?: (options: FocusViewOptions) => void) { if (activeItem.presentation_movement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) { (DocumentView.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.(); return; @@ -886,9 +886,9 @@ export class PresBox extends ViewBoxBaseComponent() { if (!DocumentView.getLightboxDocumentView(DocCast(targetDoc.annotationOn) ?? targetDoc)) { DocumentView.SetLightboxDoc(undefined); } - DocumentView.showDocument(targetDoc, options, finished); + DocumentView.showDocument(targetDoc, options, () => finished?.(options)); }); - } else finished?.(); + } else finished?.(options); } /** @@ -900,8 +900,8 @@ export class PresBox extends ViewBoxBaseComponent() { this.childDocs.forEach((doc, index) => { const curDoc = Cast(doc, Doc, null); const tagDoc = PresBox.targetRenderedDoc(curDoc); - const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, curDoc); - let opacity: Opt = index === this.itemIndex ? 1 : undefined; + const itemIndexes = this.getAllIndexes(this.tagDocs, curDoc); + let opacity = index === this.itemIndex ? 1 : undefined; if (curDoc.presentation_hide) { if (index !== this.itemIndex) { opacity = 1; @@ -913,9 +913,6 @@ export class PresBox extends ViewBoxBaseComponent() { opacity = 0; } else if (index === this.itemIndex || !curDoc.presentation_hideAfter) { opacity = 1; - setTimeout(() => { - tagDoc._dataTransition = undefined; - }, 1000); } } const hidingIndAft = -- cgit v1.2.3-70-g09d2 From deb038e6b659a1c7563ccc9df2ef51221c0492ea Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 3 Feb 2025 14:42:42 -0500 Subject: fixed pres animation of colection that's progresivized by removing dataTransition assignments that made no sense. --- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 26 ++++++++------------ src/client/views/nodes/trails/PresBox.tsx | 28 ++++++++++------------ 4 files changed, 25 insertions(+), 33 deletions(-) (limited to 'src/client/views/nodes/trails') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 69fdf52ff..3c31b584e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -232,7 +232,7 @@ export class CollectionFreeFormView extends CollectionSubView { const currentFrame = Cast(this.Document._currentFrame, 'number', null); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 68105f2f1..beea6ab3c 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -198,7 +198,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { this.animFields.forEach(val => { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a60415e43..0193fd328 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1390,8 +1390,8 @@ export class DocumentView extends DocComponent() { this.Document[Animation] = presEffect; this._animEffectTimer = setTimeout(() => { this.Document[Animation] = undefined; }, timeInMs); // prettier-ignore }; - public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => { - this._viewTimer = DocumentView.SetViewTransition([this.layoutDoc], transProp, timeInMs, this._viewTimer, afterTrans, dataTrans); + public setViewTransition = (transProp: string, timeInMs: number, dataTrans = false) => { + this._viewTimer = DocumentView.SetViewTransition([this.layoutDoc], transProp, timeInMs, this._viewTimer, dataTrans); }; public setCustomView = undoable((custom: boolean, layout: string): void => { @@ -1590,21 +1590,15 @@ export class DocumentView extends DocComponent() { ); } - public static SetViewTransition(docs: Doc[], transProp: string, timeInMs: number, timer?: NodeJS.Timeout | undefined, afterTrans?: () => void, dataTrans = false) { - docs.forEach(doc => { - doc._viewTransition = `${transProp} ${timeInMs}ms`; - dataTrans && (doc.dataTransition = `${transProp} ${timeInMs}ms`); - }); + public static SetViewTransition(docs: Doc[], transProp: string, timeInMs: number, timer?: NodeJS.Timeout | undefined, dataTrans = false) { + const setTrans = (transition?: string) => + docs.forEach(doc => { + doc._viewTransition = transition; + dataTrans && (doc.dataTransition = transition); + }); + setTrans(`${transProp} ${timeInMs}ms`); timer && clearTimeout(timer); - return setTimeout( - () => - docs.forEach(doc => { - doc._viewTransition = undefined; - dataTrans && (doc.dataTransition = 'inherit'); - afterTrans?.(); - }), - timeInMs + 10 - ); + return setTimeout(setTrans, timeInMs + 10); } // shows a stacking view collection (by default, but the user can change) of all documents linked to the source diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 7ca0bbc8f..68634076d 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -452,27 +452,25 @@ export class PresBox extends ViewBoxBaseComponent() { const progressiveReveal = (first: boolean) => { const presIndexed = Cast(this.activeItem?.presentation_indexed, 'number', null); if (presIndexed !== undefined) { - const targetRenderedDoc = PresBox.targetRenderedDoc(this.activeItem); - targetRenderedDoc._dataTransition = 'all 1s'; - targetRenderedDoc.opacity = 1; - setTimeout(() => { - targetRenderedDoc._dataTransition = 'inherit'; - }, 1000); const listItems = this.progressivizedItems(this.activeItem); - if (listItems && presIndexed < listItems.length) { + const listItemDoc = listItems?.[presIndexed]; + if (listItems && listItemDoc) { if (!first) { - const listItemDoc = listItems[presIndexed]; - const targetView = listItems && DocumentView.getFirstDocumentView(listItemDoc); + const presBulletTiming = 500; // bcz: hardwired for now Doc.linkFollowUnhighlight(); Doc.HighlightDoc(listItemDoc); listItemDoc.presentation_effect = this.activeItem.presBulletEffect; - listItemDoc.presentation_transition = 500; - targetView?.setAnimEffect(listItemDoc, 500); - if (targetView && this.activeItem.presBulletExpand) { - targetView.setAnimateScaling(1.2, 400); - Doc.AddUnHighlightWatcher(() => targetView?.setAnimateScaling(0, undefined)); - } + listItemDoc.presentation_transition = presBulletTiming; listItemDoc.opacity = undefined; + + const targetView = DocumentView.getFirstDocumentView(listItemDoc); + if (targetView) { + targetView.setAnimEffect(listItemDoc, presBulletTiming); + if (this.activeItem.presBulletExpand) { + targetView.setAnimateScaling(1.2, presBulletTiming * 0.8); + Doc.AddUnHighlightWatcher(() => targetView.setAnimateScaling(0, undefined)); + } + } this.activeItem.presentation_indexed = presIndexed + 1; } return true; -- cgit v1.2.3-70-g09d2 From e8c1107aebd660872018c472ff5017d873e4b626 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 3 Feb 2025 15:37:29 -0500 Subject: fixed crash switching to tree view in pres --- src/client/views/nodes/MapBox/MapAnchorMenu.tsx | 12 +++++++----- src/client/views/nodes/trails/PresBox.tsx | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src/client/views/nodes/trails') diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx index 87469b50e..cef202256 100644 --- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx @@ -109,7 +109,7 @@ export class MapAnchorMenu extends AntimodeMenu { return this._left > 0; } - constructor(props: any) { + constructor(props: AntimodeMenuProps) { super(props); makeObservable(this); MapAnchorMenu.Instance = this; @@ -117,10 +117,12 @@ export class MapAnchorMenu extends AntimodeMenu { } componentWillUnmount() { - this.destinationFeatures = []; - this.destinationSelected = false; - this.selectedDestinationFeature = undefined; - this.currentRouteInfoMap = undefined; + runInAction(() => { + this.destinationFeatures = []; + this.destinationSelected = false; + this.selectedDestinationFeature = undefined; + this.currentRouteInfoMap = undefined; + }); this._disposer?.(); } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 68634076d..e0de8e1fd 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1806,7 +1806,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get transitionDropdown() { const { activeItem } = this; // Retrieving spring timing properties - const timing = StrCast(activeItem.presentation_effectTiming); + const timing = StrCast(activeItem?.presentation_effectTiming); let timingConfig: SpringSettings | undefined; if (timing) { timingConfig = JSON.parse(timing); -- cgit v1.2.3-70-g09d2 From 68bf2f9e4141d8a99407ff4c6c02d44795c638de Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 4 Feb 2025 14:08:38 -0500 Subject: fixing up gpt and animation panel in presbox. --- src/client/apis/gpt/PresCustomization.ts | 115 ++++---- .../views/nodes/imageEditor/ImageEditorButtons.tsx | 3 +- src/client/views/nodes/trails/PresBox.tsx | 295 +++++++-------------- src/client/views/nodes/trails/SpringUtils.ts | 9 +- 4 files changed, 170 insertions(+), 252 deletions(-) (limited to 'src/client/views/nodes/trails') diff --git a/src/client/apis/gpt/PresCustomization.ts b/src/client/apis/gpt/PresCustomization.ts index 2262886a2..c465f098f 100644 --- a/src/client/apis/gpt/PresCustomization.ts +++ b/src/client/apis/gpt/PresCustomization.ts @@ -1,3 +1,5 @@ +import { PresEffect, PresEffectDirection } from '../../views/nodes/trails/PresEnums'; +import { AnimationSettingsProperties, easeItems } from '../../views/nodes/trails/SpringUtils'; import { openai } from './setup'; export enum CustomizationType { @@ -10,15 +12,17 @@ interface PromptInfo { } const prompts: { [key: string]: PromptInfo } = { trails: { - description: - 'We are customizing the properties and transition of a slide in a presentation. You are given the current properties of the slide in a json with the fields [title, presentation_transition, presentation_effect, config_zoom, presentation_effectDirection], as well as the prompt for how the user wants to change it. Return a json with the required fields: [title, presentation_transition, presentation_effect, config_zoom, presentation_effectDirection] by applying the changes in the prompt to the current state of the slide.', + description: `We are customizing the properties and transition of a slide in a presentation. + You are given the current properties of the slide in a json with the fields [title, presentation_transition, presentation_effect, config_zoom, presentation_effectDirection], + as well as the prompt for how the user wants to change it. + Return a json with the required fields: [title, presentation_transition, presentation_effect, config_zoom, presentation_effectDirection] by applying the changes in the prompt to the current state of the slide.`, features: [], }, }; // Allows you to register properties that are customizable export const addCustomizationProperty = (type: CustomizationType, name: string, description: string, values?: string[]) => { - values ? prompts[type].features.push({ name, description, values }) : prompts[type].features.push({ name, description }); + prompts[type].features.push({ name, description, ...(values ? { values } : {}) }); }; // All the registered fields, make sure to update during registration, this @@ -41,35 +45,34 @@ export const gptSlideProperties = [ // Registers slide properties const setupPresSlideCustomization = () => { - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'title', 'is the title/name of the slide.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_transition', 'is a number in milliseconds for how long it should take to transition/move to a slide.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_easeFunc', 'is the easing function for the movement to the slide.', ['Ease', 'Ease In', 'Ease Out', 'Ease Out', 'Ease In Out', 'Linear']); - - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_effect', 'is an effect applied to the slide when we transition to it.', ['None', 'Expand', 'Fade in', 'Bounce', 'Flip', 'Rotate', 'Roll']); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_effectDirection', 'is what direction the effect is applied.', ['Enter from left', 'Enter from right', 'Enter from bottom', 'Enter from Top', 'Enter from center']); - addCustomizationProperty( - CustomizationType.PRES_TRAIL_SLIDE, - 'presentation_effectTiming', - "is a json object of the format: {type: string, stiffness: number, damping: number, mass: number}. Type is always “custom”. Controls the spring-based timing of the presentation effect animation. Stiffness, damping, and mass control the physics-based properties of spring animations. This is used to create a more natural looking timing, bouncy effects, etc. Use spring physics to adjust these parameters to match the user's description of how they want to animate the effect." - ); - - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'config_zoom', 'is a number from 0 to 1.0 indicating the percentage we should zoom into the slide.'); - - // boolean values - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_playAudio', 'is a boolean value indicating if we should play audio when we go to the slide.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_zoomText', 'is a boolean value indicating if we should zoom into text selections when we go to the slide.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_hideBefore', 'is a boolean value indicating if we should hide the slide before going to it.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_hide', 'is a boolean value indicating if we should hide the slide during the presentation.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_hideAfter', 'is a boolean value indicating if we should hide the slide after going to it.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_openInLightbox', 'is a boolean value indicating if we should open the slide in an overlay or lightbox view during the presentation.'); -}; + const add = (name: string, val:string, opts?:string[]) => addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, name, val, opts); + const addBool = (name: string, val:string) => add(name, 'is a boolean value indicating if we should ' + val); + add('title', 'is the title/name of the slide.'); + add('config_zoom', 'is a number from 0 to 1.0 indicating the percentage we should zoom into the slide.'); + add('presentation_transition', 'is a number in milliseconds for how long it should take to transition/move to a slide.'); + add('presentation_easeFunc', 'is the easing function for the movement to the slide.', easeItems.filter(val => val.text !== 'Custom').map(val => val.text)) + add('presentation_effect', 'is an effect applied to the slide when we transition to it.', Object.keys(PresEffect)); + add('presentation_effectDirection','is what direction the effect is applied.', Object.keys(PresEffectDirection).filter(key => key !== PresEffectDirection.None)); + add('presentation_effectTiming', `is a json object of the format: {type: string, ${AnimationSettingsProperties.stiffness}: number, ${AnimationSettingsProperties.damping}: number, ${AnimationSettingsProperties.mass}: number}. + Type is always “custom”. Controls the spring-based timing of the presentation effect animation. + Stiffness, damping, and mass control the physics-based properties of spring animations. + This is used to create a more natural looking timing, bouncy effects, etc. + Use spring physics to adjust these parameters to match the user's description of how they want to animate the effect.`); + + + addBool('presentation_playAudio', 'play audio when we go to the slide.'); + addBool('presentation_zoomText', 'zoom into text selections when we go to the slide.'); + addBool('presentation_hideBefore', 'hide the slide before going to it.'); + addBool('presentation_hide', 'hide the slide during the presentation.'); + addBool('presentation_hideAfter', 'hide the slide after going to it.'); + addBool('presentation_openInLightbox', 'open the slide in an overlay or lightbox view during the presentation.'); +}; // prettier-ignore setupPresSlideCustomization(); -export const getSlideTransitionSuggestions = async (inputText: string) => { +export const getSlideTransitionSuggestions = (inputText: string) => { /** - * Prompt: Generate an entrance animations from slower and gentler - * to bouncier and more high energy + * Prompt: Generate entrance animations from slower and gentler to bouncier and more high energy * * Format: * { @@ -81,13 +84,19 @@ export const getSlideTransitionSuggestions = async (inputText: string) => { * } */ - const prompt = - "I want to generate four distinct types of slide effect animations. Return a json of the form {effect: string, direction: string, stiffness: number, damping: number, mass: number}[] with four elements. Effect is the type of animation; its only possible values are ['Expand', 'Fade in', 'Bounce', 'Flip', 'Rotate', 'Roll']. Direction is the direction that the animation starts from; its only possible values are ['Enter from left', 'Enter from right', 'Enter from bottom', 'Enter from Top', 'Enter from center']. Stiffness, damping, and mass control the physics-based properties of spring animations. This is used to create a more natural-looking timing, bouncy effects, etc. Use spring physics to adjust these parameters to animate the effect."; + const prompt = `I want to generate four distinct types of slide effect animations. + Return a json of the form { ${AnimationSettingsProperties.effect}: string, ${AnimationSettingsProperties.direction}: string, ${AnimationSettingsProperties.stiffness}: number, ${AnimationSettingsProperties.damping}: number, ${AnimationSettingsProperties.mass}: number}[] with four elements. + ${AnimationSettingsProperties.effect} is the type of animation; its only possible values are [${Object.keys(PresEffect).filter(key => key !== PresEffect.None).join(',')}]. + ${AnimationSettingsProperties.direction} is the direction that the animation starts from; + its only possible values are [${Object.values(PresEffectDirection).filter(key => key !== PresEffectDirection.None).join(',')}]. + ${AnimationSettingsProperties.stiffness}, ${AnimationSettingsProperties.damping}, and ${AnimationSettingsProperties.mass} control the physics-based properties of spring animations. + This is used to create a more natural-looking timing, bouncy effects, etc. + Use spring physics to adjust these parameters to animate the effect.`; // prettier-ignore const customInput = inputText ?? 'Make them as contrasting as possible with different effects and timings ranging from gentle to energetic.'; - try { - const response = await openai.chat.completions.create({ + return openai.chat.completions + .create({ model: 'gpt-4', messages: [ { role: 'system', content: prompt }, @@ -95,39 +104,33 @@ export const getSlideTransitionSuggestions = async (inputText: string) => { ], temperature: 0, max_tokens: 1000, + }) + .then(response => response.choices[0].message?.content ?? '') + .catch(err => { + console.log(err); + return 'Error connecting with API.'; }); - return response.choices[0].message?.content; - } catch (err) { - console.log(err); - return 'Error connecting with API.'; - } }; -export const gptTrailSlideCustomization = async (inputText: string, properties: any | any[]) => { - let prompt = prompts.trails.description; - - prompts.trails.features.forEach(feature => { - prompt += feature.name + ' ' + feature.description; - if (feature.values) { - prompt += `Its only possible values are [${feature.values.join(', ')}].`; - } - }); +export const gptTrailSlideCustomization = (inputText: string, properties: string) => { + const preamble = prompts.trails.description + prompts.trails.features.map(feature => feature.name + ' ' + feature.description + (feature.values ? `Its only possible values are [${feature.values.join(', ')}]` : '')).join('. '); - prompt += 'Set unchanged values to null and make sure you include new properties if they are specified in the prompt even if they do not exist in current properties. Please only return the json with the keys described and their values.'; + const prompt = `Set unchanged values to null and make sure you include new properties if they are specified in the prompt even if they do not exist in current properties. + Please only return the json with the keys described and their values.`; - try { - const response = await openai.chat.completions.create({ + return openai.chat.completions + .create({ model: 'gpt-4', messages: [ - { role: 'system', content: prompt }, - { role: 'user', content: `Prompt: ${inputText}, Current properties: ${JSON.stringify(properties)}` }, + { role: 'system', content: preamble + prompt }, + { role: 'user', content: `Prompt: ${inputText}, Current properties: ${properties}` }, ], temperature: 0, max_tokens: 1000, + }) + .then(response => response.choices[0].message?.content ?? '') + .catch(err => { + console.log(err); + return 'Error connecting with API.'; }); - return response.choices[0].message?.content; - } catch (err) { - console.log(err); - return 'Error connecting with API.'; - } }; diff --git a/src/client/views/nodes/imageEditor/ImageEditorButtons.tsx b/src/client/views/nodes/imageEditor/ImageEditorButtons.tsx index e810881a5..985dc914f 100644 --- a/src/client/views/nodes/imageEditor/ImageEditorButtons.tsx +++ b/src/client/views/nodes/imageEditor/ImageEditorButtons.tsx @@ -53,9 +53,8 @@ export function ApplyFuncButtons({ loading, onClick: getEdit, onReset, btnText } export function ImageToolButton(tool: ImageEditTool, isActive: boolean, selectTool: (type: ImageToolType) => void) { return ( -
+
@@ -1952,16 +1878,16 @@ export class PresBox extends ViewBoxBaseComponent() { style={{ alignSelf: 'flex-start' }} onClick={e => { e.stopPropagation(); - this.setBezierEditorVisibility(!this.showBezierEditor); + this.setBezierEditorVisibility(!this._showBezierEditor); }}> - {`${this.showBezierEditor ? 'Hide' : 'Show'} Timing Editor`} - + {`${this._showBezierEditor ? 'Hide' : 'Show'} Timing Editor`} +
{/* Cubic bezier editor */} - {this.showBezierEditor && ( + {this._showBezierEditor && (

Custom Timing Function @@ -1978,7 +1904,7 @@ export class PresBox extends ViewBoxBaseComponent() { { this.setAnimationChat(e.target.value); }} @@ -1992,7 +1918,7 @@ export class PresBox extends ViewBoxBaseComponent() { style={{ alignSelf: 'flex-end' }} text="Send" type={Type.TERT} - icon={this.isLoading ? : } + icon={this._isLoading ? : } iconPlacement="right" color={SnappingManager.userVariantColor} onClick={this.customizeAnimations} @@ -2107,12 +2033,7 @@ export class PresBox extends ViewBoxBaseComponent() { closeOnSelect items={effectTimings} selectedVal={timingConfig.type} - setSelectedVal={val => { - this.updateEffectTiming(activeItem, { - type: val as SpringType, - ...springMappings[val], - }); - }} + setSelectedVal={val => this.updateEffectTiming(activeItem, { type: val as SpringType, ...springMappings[val] })} dropdownType={DropdownType.SELECT} type={Type.TERT} /> @@ -2120,73 +2041,61 @@ export class PresBox extends ViewBoxBaseComponent() { className="presBox-show-hide-dropdown" onClick={e => { e.stopPropagation(); - this.setSpringEditorVisibility(!this.showSpringEditor); + this.setSpringEditorVisibility(!this._showSpringEditor); }}> - {`${this.showSpringEditor ? 'Hide' : 'Show'} Spring Settings`} - + {`${this._showSpringEditor ? 'Hide' : 'Show'} Spring Settings`} +

- {this.showSpringEditor && ( + {this._showSpringEditor && ( <>
Tension
-
{ - e.stopPropagation(); - }}> - e.stopPropagation()}> + {/* prettier-ignore */} + { - if (!timingConfig) return; - this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, stiffness: val as number }); - }} + onChange={(e, val) => timingConfig && this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, stiffness: val as number })} valueLabelDisplay="auto" />
Damping
-
{ - e.stopPropagation(); - }}> - e.stopPropagation()}> + {/* prettier-ignore */} + { - if (!timingConfig) return; - this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, damping: val as number }); - }} + onChange={(e, val) => timingConfig && this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, damping: val as number })} valueLabelDisplay="auto" />
Mass
-
{ - e.stopPropagation(); - }}> - e.stopPropagation()}> + {/* prettier-ignore */} + { - if (!timingConfig) return; - this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, mass: val as number }); - }} + onChange={(e, val) => timingConfig && this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, mass: val as number })} valueLabelDisplay="auto" />
- Preview Effect -
-
- -
- +
+
{/* presbox chatbox */} - {this.chatActive &&
} + {this._chatActive &&
}
); } diff --git a/src/client/views/nodes/trails/SpringUtils.ts b/src/client/views/nodes/trails/SpringUtils.ts index 73e1e14f1..044afbeb1 100644 --- a/src/client/views/nodes/trails/SpringUtils.ts +++ b/src/client/views/nodes/trails/SpringUtils.ts @@ -22,7 +22,14 @@ export interface SpringSettings { } // Overall config - +// Keeps these settings in sync with the AnimationSettings interface (used by gpt); +export enum AnimationSettingsProperties { + effect = 'effect', + direction = 'direction', + stiffness = 'stiffness', + damping = 'damping', + mass = 'mass', +} export interface AnimationSettings { effect: PresEffect; direction: PresEffectDirection; -- cgit v1.2.3-70-g09d2 From 382e09f606d94921dab460cc8c8564199bb0b70d Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 5 Feb 2025 17:10:20 -0500 Subject: cleanup of presbox properties. --- .../views/nodes/trails/CubicBezierEditor.tsx | 154 ++++--- src/client/views/nodes/trails/PresBox.scss | 83 +++- src/client/views/nodes/trails/PresBox.tsx | 475 +++++++++++---------- 3 files changed, 402 insertions(+), 310 deletions(-) (limited to 'src/client/views/nodes/trails') 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 ( -
{ - e.stopPropagation; - }}> - - {/* Outlines */} - - {/* Box Outline */} - - {/* Editor */} - - {/* Bottom left */} - { - 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" - /> - - { - e.stopPropagation(); - setC1Down(true); - }} - onPointerUp={() => { - setC1Down(false); - }} - /> - {/* Top right */} - { - 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" - /> - - { - e.stopPropagation(); - setC2Down(true); - }} - onPointerUp={() => { - setC2Down(false); - }} - /> - -
+ + {/* Outlines */} + + {/* Box Outline */} + + {/* Editor */} + + {/* Bottom left */} + { + 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" + /> + + { + e.stopPropagation(); + setC1Down(true); + }} + onPointerUp={() => { + setC1Down(false); + }} + /> + {/* Top right */} + { + 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" + /> + + { + e.stopPropagation(); + setC2Down(true); + }} + onPointerUp={() => { + setC2Down(false); + }} + /> + ); } 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() { @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() { 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() { 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() { return ( <> {/* This chatbox is for customizing the properties of trails, like transition time, movement type (zoom, pan) using GPT */} -
- +
+ Customize Slide Properties{' '}
window.open('https://brown-dash.github.io/Dash-Documentation/features/trails/#slide-customization')}> } color={SnappingManager.userColor} />
-
+
{ + 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() { />
+ {/* Movement */}
() { this._openEffectDropdown = false; this._openBulletEffectDropdown = false; })}> -
- Movement +
{ - this.updateMovement(val as PresMovement); - }} + setSelectedVal={val => this.updateMovement(val as PresMovement)} dropdownType={DropdownType.SELECT} type={Type.TERT} /> -
-
Zoom (% screen filled)
-
- this.updateZoom(e.target.value)} />% +
+ How much (%) of screen target should occupy
}> +
ZOOM %
+ +
{PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)}
+
+ this.updateZoom(e.target.value)} /> + %
- {PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)} -
-
Transition Time
-
- e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s +
+
ZOOM/EFFECT TIME
+
+ {PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.updateTransitionTime)} +
+
Fast
+
Slow
+
+
+
+ e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> + s
-
- {PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.updateTransitionTime)} -
-
Fast
-
Medium
-
Slow
{/* Easing function */} () { e.stopPropagation(); this.setBezierEditorVisibility(!this._showBezierEditor); }}> - {`${this._showBezierEditor ? 'Hide' : 'Show'} Timing Editor`} - + TIMING EDITOR +
{/* Cubic bezier editor */} {this._showBezierEditor && ( -
-

- Custom Timing Function -

+
)} + {effect === PresEffect.None ? null : ( +
+
{/* Toggles */} -- cgit v1.2.3-70-g09d2 From a23e4c26d23224b56ec51d73b38adeb2b54fed6d Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 6 Feb 2025 14:37:19 -0500 Subject: overhaul of presbox properties ui + fixing bugs with progressivize highlight expanding --- src/client/views/PropertiesView.tsx | 70 ++-- src/client/views/nodes/trails/PresBox.scss | 36 +- src/client/views/nodes/trails/PresBox.tsx | 591 ++++++++++++++--------------- 3 files changed, 350 insertions(+), 347 deletions(-) (limited to 'src/client/views/nodes/trails') 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
{!selectedItem ? null : ( -
+
{ - this.openPresTransitions = !this.openPresTransitions; + this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration; })} style={{ color: SnappingManager.userColor, - backgroundColor: this.openPresTransitions ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + backgroundColor: SnappingManager.userVariantColor, }}> -     Transitions + Visibility
- +
- {this.openPresTransitions ?
{PresBox.Instance.transitionDropdown}
: null} + {this.openPresVisibilityAndDuration ?
{PresBox.Instance.visibilityDurationDropdown}
: null}
)} {!selectedItem ? null : ( -
+
{ - this.openPresVisibilityAndDuration = !this.openPresVisibilityAndDuration; + this.openPresProgressivize = !this.openPresProgressivize; })} style={{ color: SnappingManager.userColor, - backgroundColor: this.openPresVisibilityAndDuration ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + backgroundColor: SnappingManager.userVariantColor, }}> -     Visibility + Progressivize
- +
- {this.openPresVisibilityAndDuration ?
{PresBox.Instance.visibilityDurationDropdown}
: null} + {this.openPresProgressivize ?
{PresBox.Instance.progressivizeDropdown}
: null}
)} {!selectedItem ? null : ( -
+
{ - this.openPresProgressivize = !this.openPresProgressivize; + this.openPresMedia = !this.openPresMedia; })} style={{ color: SnappingManager.userColor, - backgroundColor: this.openPresProgressivize ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + backgroundColor: SnappingManager.userVariantColor, }}> -     Progressivize + Media
- +
- {this.openPresProgressivize ?
{PresBox.Instance.progressivizeDropdown}
: null} + {this.openPresMedia ?
{PresBox.Instance.mediaDropdown}
: null}
)} {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? null : ( -
+
{ this.openSlideOptions = !this.openSlideOptions; })} style={{ color: SnappingManager.userColor, - backgroundColor: this.openSlideOptions ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor, + backgroundColor: SnappingManager.userVariantColor, }}> -     {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'} + {type === DocumentType.AUDIO ? 'file-audio' : 'file-video'}
@@ -2011,6 +2012,25 @@ export class PropertiesView extends ObservableReactComponent{PresBox.Instance.mediaOptionsDropdown}
: null}
)} + {!selectedItem ? null : ( +
+
{ + this.openPresTransitions = !this.openPresTransitions; + })} + style={{ + color: SnappingManager.userColor, + backgroundColor: SnappingManager.userVariantColor, + }}> + Transitions +
+ +
+
+ {this.openPresTransitions ?
{PresBox.Instance.transitionDropdown}
: null} +
+ )}
); } 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() { @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() { 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() { 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() {
{[DocumentType.AUDIO, DocumentType.VID].includes(targetType as DocumentType) ? null : ( - <> -
-
Slide Duration
-
- e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s +
+ How long to view the slide before transitioning to the next slide
}> +
DURATION
+ +
+ {PresBox.inputter('0.1', '0.1', '10', duration, targetType !== DocumentType.AUDIO, this.updateDurationTime)} +
+
Short
+
Long
- {PresBox.inputter('0.1', '0.1', '20', duration, targetType !== DocumentType.AUDIO, this.updateDurationTime)} -
-
Short
-
Medium
-
Long
+
+ e.stopPropagation()} onChange={action(e => this.updateDurationTime(e.target.value))} /> + s
- +
)}
@@ -1633,28 +1631,62 @@ export class PresBox extends ViewBoxBaseComponent() { } 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) => ( -
this.updateEffect(presEffect, true)}> - {presEffect} + return ( +
+
+ Should first bullet be progressively disclosed or does it appear with slide.
}> +
{ + activeItem.presentation_playAudio = !BoolCast(activeItem.presentation_playAudio); + }}> + Play Audio Annotation +
+ + Should first bullet be progressively disclosed or does it appear with slide.
}> +
{ + activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText); + }}> + Zoom Text Selections +
+ +
); + } + return null; + } + @computed get progressivizeDropdown() { + const { activeItem } = this; + if (activeItem && this.targetDoc) { return (
-
-
-
Progressivize Collection
- { +
+ whether progressivization is active for this slide
}> +
{ 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() { 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 +
+ + Should first bullet be progressively disclosed or does it appear with slide.
}> +
-
-
-
Progressivize First Bullet
- { + onClick={() => { activeItem.presentation_indexedStart = activeItem.presentation_indexedStart ? 0 : 1; - }} - checked={!NumCast(activeItem.presentation_indexedStart)} - /> -
-
-
Expand Current Bullet
- { - activeItem.presBulletExpand = !activeItem.presBulletExpand; - }} - checked={BoolCast(activeItem.presBulletExpand)} - /> -
- -
- Bullet Effect + }}> + All Bullets +
+ + Whether the active bullet expands when active.
}>
{ - 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()} - -
e.stopPropagation()}> - {Object.values(PresEffect) - .filter(v => isNaN(Number(v))) - .map(pEffect => bulletEffect(pEffect))} -
+ Expand Active
-
+
+ ({ 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} + />
); } @@ -1733,6 +1754,77 @@ export class PresBox extends ViewBoxBaseComponent() { return
; } + /** + * This chatbox is for getting slide effect transition suggestions from gpt and visualizing them + */ + @computed get aiEffects() { + return ( +
+ {/* Custom */} +
+
+ { + 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(); + }} + /> +
+
+
+ Click a box to use the effect. + {/* Preview Animations */} +
+ {this.generatedAnimations.map((elem, i) => ( +
{ + 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, + }); + }}> + +
+ +
+ ))} +
+
+
+ ); + } + @computed get transitionDropdown() { const { activeItem } = this; // Retrieving spring timing properties @@ -1827,29 +1919,10 @@ export class PresBox extends ViewBoxBaseComponent() { this._openBulletEffectDropdown = false; })}>
- this.updateMovement(val as PresMovement)} - dropdownType={DropdownType.SELECT} - type={Type.TERT} - /> -
- How much (%) of screen target should occupy
}> -
ZOOM %
- -
{PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)}
-
- this.updateZoom(e.target.value)} /> - % -
-
-
ZOOM/EFFECT TIME
+ How long the transition (view navigation and slide animation effect) lasts
}> +
SPEED
+
{PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.updateTransitionTime)}
@@ -1858,153 +1931,55 @@ export class PresBox extends ViewBoxBaseComponent() {
- e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> + e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s
- {/* Easing function */} { - 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 */} -
{ - e.stopPropagation(); - this.setBezierEditorVisibility(!this._showBezierEditor); - }}> - TIMING EDITOR - +
+ How much (%) of screen target should occupy
}> +
ZOOM %
+ +
{PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)}
+
+ this.updateZoom(e.target.value)} /> + % +
+ {/* Easing function */} + {[PresMovement.None, PresMovement.Jump, ''].includes(StrCast(activeItem.presentation_movement) as PresMovement) ? null : ( + typeof val === 'string' && this.setEaseFunc(this.activeItem, val !== 'custom' ? val : TIMING_DEFAULT_MAPPINGS.ease)} + dropdownType={DropdownType.SELECT} + type={Type.TERT} + /> + )}
{/* Cubic bezier editor */} - {this._showBezierEditor && ( + {StrCast(activeItem.presentation_easeFunc).includes('cubic-bezier') && (
)} - {effect === PresEffect.None ? null : ( -
-
-
- Click a box to use the effect. - {/* Preview Animations */} -
- {this.generatedAnimations.map((elem, i) => ( -
{ - 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, - }); - }}> - -
- -
- ))} -
-
-
-
() { })}>
{/* Effect dropdown */} -
+
() { dropdownType={DropdownType.SELECT} type={Type.TERT} /> + +
this.setShowAIGalleryVisibilty(!this._showAIGallery)}> + MORE +
+ {this.aiEffects}
{/* Effect direction */} {/* Only applies to certain effects */} {(effect === PresEffect.Flip || effect === PresEffect.Bounce || effect === PresEffect.Roll) && ( - <> -
-
EFFECT DIRECTION
-
-
- } - onClick={() => this.updateEffectDirection(PresEffectDirection.Left)} - /> - } - onClick={() => this.updateEffectDirection(PresEffectDirection.Right)} - /> - {effect !== PresEffect.Roll && ( - <> - } - onClick={() => this.updateEffectDirection(PresEffectDirection.Top)} - /> - } - onClick={() => this.updateEffectDirection(PresEffectDirection.Bottom)} - /> - - )} -
+
+
DIRECTION
+
+
+ } + onClick={() => this.updateEffectDirection(PresEffectDirection.Left)} + /> + } + onClick={() => this.updateEffectDirection(PresEffectDirection.Right)} + /> + {effect !== PresEffect.Roll && ( + <> + } + onClick={() => this.updateEffectDirection(PresEffectDirection.Top)} + /> + } + onClick={() => this.updateEffectDirection(PresEffectDirection.Bottom)} + /> + + )}
- +
)} {effect !== PresEffect.Lightspeed && ( <> () { />
- {/* Custom */} -
{ - e.stopPropagation(); - this.setSpringEditorVisibility(!this._showSpringEditor); - }}> - SPRING SETTINGS - -
- {/* Spring settings */} {/* No spring settings for jackinthebox (lightspeed) */} - {this._showSpringEditor && effect !== PresEffect.None && ( + {StrCast(activeItem.presentation_effectTiming).includes('custom') && effect !== PresEffect.None && ( <>
Tension @@ -2150,30 +2124,35 @@ export class PresBox extends ViewBoxBaseComponent() { )}
+
- {/* Toggles */} -
- { - activeItem.presentation_playAudio = !BoolCast(activeItem.presentation_playAudio); - }} - color={SnappingManager.userColor} - /> - { - activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText); - }} + {effect === PresEffect.None ? null : ( +
+
+ )} + +
{/* Easing function */} - {[PresMovement.None, PresMovement.Jump, ''].includes(StrCast(activeItem.presentation_movement) as PresMovement) ? null : ( + {!this.showEaseFunctions ? null : ( () {
{/* Cubic bezier editor */} - {StrCast(activeItem.presentation_easeFunc).includes('cubic-bezier') && ( + {this.showEaseFunctions && StrCast(activeItem.presentation_easeFunc).includes('cubic-bezier') && (
@@ -2066,7 +2070,7 @@ export class PresBox extends ViewBoxBaseComponent() {
)} - {effect !== PresEffect.Lightspeed && ( + {![PresEffect.Lightspeed, PresEffect.Fade, PresEffect.None, ''].includes(effect) && ( <> () {
e.stopPropagation()}> {/* prettier-ignore */} timingConfig && this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, stiffness: val as number })} - valueLabelDisplay="auto" - /> + value={timingConfig.stiffness} + onChange={(e, val) => timingConfig && this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, stiffness: val as number })} + valueLabelDisplay="auto" + />
@@ -2126,14 +2130,14 @@ export class PresBox extends ViewBoxBaseComponent() {
- {effect === PresEffect.None ? null : ( + {[PresEffect.None, PresEffect.Fade, ''].includes(effect) ? null : (