diff options
-rw-r--r-- | src/client/views/collections/CollectionStackedTimeline.tsx | 11 | ||||
-rw-r--r-- | src/client/views/nodes/AudioBox.scss | 61 | ||||
-rw-r--r-- | src/client/views/nodes/AudioBox.tsx | 129 | ||||
-rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 10 |
4 files changed, 108 insertions, 103 deletions
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 8608700aa..0ef6f852a 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -354,6 +354,13 @@ export class CollectionStackedTimeline extends CollectionSubView< // determine x coordinate of drop and assign it to the documents being dragged --- see internalDocDrop of collectionFreeFormView.tsx for how it's done when dropping onto a 2D freeform view + const x = docDragData.offset[0]; + const timelineContentWidth = this.props.PanelWidth(); + for (let i = 0; i < docDragData.droppedDocuments.length; i++) { + const d = docDragData.droppedDocuments[i]; + d._timecodeToShow = x / timelineContentWidth * this.props.trimDuration + NumCast(d._timecodeToShow); + d._timecodeToHide = x / timelineContentWidth * this.props.trimDuration + NumCast(d._timecodeToHide); + } return true; } @@ -573,14 +580,14 @@ export class CollectionStackedTimeline extends CollectionSubView< const left = this.props.trimming ? (start / this.duration) * timelineContentWidth : Math.max((start - this.trimStart) / this.props.trimDuration * timelineContentWidth, 0); - const top = (d.level / maxLevel) * this.timelineContentHeight(); + const top = (d.level / maxLevel) * this.timelineContentHeight() + 15; const timespan = end - start; let width = (timespan / this.props.trimDuration) * timelineContentWidth; width = (!this.props.trimming && left == 0) ? width - ((this.trimStart - start) / this.props.trimDuration * timelineContentWidth) : width; width = (!this.props.trimming && this.trimEnd < end) ? width - ((end - this.trimEnd) / this.props.trimDuration * timelineContentWidth) : width; - const height = this.timelineContentHeight() / maxLevel + const height = (this.timelineContentHeight()) / maxLevel; return this.props.Document.hideAnchors ? null : ( <div className={"collectionStackedTimeline-marker-timeline"} diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss index cf9d97128..6adda4730 100644 --- a/src/client/views/nodes/AudioBox.scss +++ b/src/client/views/nodes/AudioBox.scss @@ -45,23 +45,24 @@ } .audiobox-record-interactive, - .audiobox-record { - pointer-events: all; - width: 100%; - height: 100%; - position: inherit; - display: flex; - position: relative; - cursor: default; + .audiobox-record { + pointer-events: all; + cursor: pointer; + width: 100%; + height: 100%; + position: relative; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + gap: 10px; + color: white; + font-weight: bold; + } - .audiobox-record { - pointer-events: none; - color: white; - display: flex; - align-items: center; - justify-content: center; - font-size: $large-header; - } + .audiobox-record { + pointer-events: none; + } .recording { margin-top: auto; @@ -132,26 +133,6 @@ pointer-events: all; } - .audiobox-record-interactive, - .audiobox-record { - pointer-events: all; - cursor: pointer; - width: 100%; - height: 100%; - position: relative; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - gap: 10px; - color: white; - font-weight: bold; - } - - .audiobox-record { - pointer-events: none; - } - .recording { margin-top: auto; margin-bottom: auto; @@ -281,6 +262,12 @@ .audioBox-total-time { right: 2px; } + + .audiobox-zoom { + bottom: 0; + left: 30px; + width: 70px; + } } } } @@ -305,4 +292,4 @@ .audiobox-container-interactive .audiobox-controls .audiobox-player .audiobox-buttons { width: 70px; } -}
\ No newline at end of file +} diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index c79828470..830c73278 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -33,6 +33,7 @@ import { FieldView, FieldViewProps } from "./FieldView"; import { LinkDocPreview } from "./LinkDocPreview"; import { faLessThan } from "@fortawesome/free-solid-svg-icons"; import { Colors } from "../global/globalEnums"; +import e = require("connect-flash"); declare class MediaRecorder { constructor(e: any); // whatever MediaRecorder has @@ -336,8 +337,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent< (this.layoutDoc.dontAutoPlayFollowedLinks ? "" : "Don't") + " play when link is selected", event: () => - (this.layoutDoc.dontAutoPlayFollowedLinks = - !this.layoutDoc.dontAutoPlayFollowedLinks), + (this.layoutDoc.dontAutoPlayFollowedLinks = + !this.layoutDoc.dontAutoPlayFollowedLinks), icon: "expand-arrows-alt", }); funcs.push({ @@ -637,77 +638,77 @@ export class AudioBox extends ViewBoxAnnotatableComponent< </div> </div> ) : ( - <div - className={`audiobox-record${interactive}`} - style={{ backgroundColor: Colors.DARK_GRAY }} - > - <FontAwesomeIcon icon="microphone" /> + <div + className={`audiobox-record${interactive}`} + style={{ backgroundColor: Colors.DARK_GRAY }} + > + <FontAwesomeIcon icon="microphone" /> RECORD - </div> - )} + </div> + )} </div> ) : ( + <div + className="audiobox-controls" + style={{ + pointerEvents: + this._isAnyChildContentActive || this.props.isContentActive() + ? "all" + : "none", + }} + > + <div className="audiobox-dictation" /> <div - className="audiobox-controls" - style={{ - pointerEvents: - this._isAnyChildContentActive || this.props.isContentActive() - ? "all" - : "none", - }} + className="audiobox-player" + style={{ height: `${AudioBox.heightPercent}%` }} > - <div className="audiobox-dictation" /> <div - className="audiobox-player" - style={{ height: `${AudioBox.heightPercent}%` }} + className="audiobox-buttons" + title={this.mediaState === "paused" ? "play" : "pause"} + onClick={this.mediaState === "paused" ? this.Play : this.Pause} > - <div - className="audiobox-buttons" - title={this.mediaState === "paused" ? "play" : "pause"} - onClick={this.mediaState === "paused" ? this.Play : this.Pause} - > - {" "} - <FontAwesomeIcon - icon={this.mediaState === "paused" ? "play" : "pause"} - size={"1x"} - /> - </div> - <div - className="audiobox-buttons" - title={this._trimming ? "finish" : "trim"} - onClick={this._trimming ? this.finishTrim : this.startTrim} - > - <FontAwesomeIcon - icon={this._trimming ? "check" : "cut"} - size={"1x"} - /> - </div> - <div - className="audiobox-timeline" - style={{ - top: 0, - height: `100%`, - left: AudioBox.playheadWidth, - width: `calc(100% - ${AudioBox.playheadWidth}px)`, - background: "white", - }} - > - {this.renderTimeline} - </div> - {this.audio} - <div className="audioBox-current-time"> - {this._trimming ? - formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode))) - : formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this._trimStart)))} - </div> - <div className="audioBox-total-time"> - {this._trimming || !this._trimEnd ? - formatTime(Math.round(NumCast(this.duration))) - : formatTime(Math.round(NumCast(this.trimDuration)))} - </div> + {" "} + <FontAwesomeIcon + icon={this.mediaState === "paused" ? "play" : "pause"} + size={"1x"} + /> + </div> + <div + className="audiobox-buttons" + title={this._trimming ? "finish" : "trim"} + onClick={this._trimming ? this.finishTrim : this.startTrim} + > + <FontAwesomeIcon + icon={this._trimming ? "check" : "cut"} + size={"1x"} + /> + </div> + <div + className="audiobox-timeline" + style={{ + top: 0, + height: `100%`, + left: AudioBox.playheadWidth, + width: `calc(100% - ${AudioBox.playheadWidth}px)`, + background: "white", + }} + > + {this.renderTimeline} + </div> + {this.audio} + <div className="audioBox-current-time"> + {this._trimming ? + formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode))) + : formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this._trimStart)))} + </div> + <div className="audioBox-total-time"> + {this._trimming || !this._trimEnd ? + formatTime(Math.round(NumCast(this.duration))) + : formatTime(Math.round(NumCast(this.trimDuration)))} </div> </div> - )} + </div> + )} </div> ); } diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 90de3227f..7dd82ad13 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -60,9 +60,17 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp @observable _playTimer?: NodeJS.Timeout = undefined; @observable _fullScreen = false; @observable _playing = false; + @observable _trimming: boolean = false; + @observable _trimStart: number = NumCast(this.layoutDoc.clipStart) ? NumCast(this.layoutDoc.clipStart) : 0; + @observable _trimEnd: number = NumCast(this.layoutDoc.clipEnd) ? NumCast(this.layoutDoc.clipEnd) + : this.duration; + @computed get links() { return DocListCast(this.dataDoc.links); } @computed get heightPercent() { return NumCast(this.layoutDoc._timelineHeightPercent, 100); } @computed get duration() { return NumCast(this.dataDoc[this.fieldKey + "-duration"]); } + @computed get trimDuration() { + return this._trimming && this._trimEnd ? this.duration : this._trimEnd - this._trimStart; + } private get transition() { return this._clicking ? "left 0.5s, width 0.5s, height 0.5s" : ""; } public get player(): HTMLVideoElement | null { return this._videoRef; } @@ -200,6 +208,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp @action updateTimecode = () => { this.player && (this.layoutDoc._currentTimecode = this.player.currentTime); + this.layoutDoc.clipEnd = this.layoutDoc.clipEnd ? Math.min(this.duration, NumCast(this.layoutDoc.clipEnd)) : this.duration; + this._trimEnd = this._trimEnd ? Math.min(this.duration, this._trimEnd) : this.duration; try { this._youtubePlayer && (this.layoutDoc._currentTimecode = this._youtubePlayer.getCurrentTime?.()); } catch (e) { |