aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/AudioWaveform.tsx3
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.scss3
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx10
-rw-r--r--src/client/views/nodes/AudioBox.scss349
-rw-r--r--src/client/views/nodes/AudioBox.tsx120
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx4
6 files changed, 163 insertions, 326 deletions
diff --git a/src/client/views/AudioWaveform.tsx b/src/client/views/AudioWaveform.tsx
index 7b9b1aa81..ca1dd6f36 100644
--- a/src/client/views/AudioWaveform.tsx
+++ b/src/client/views/AudioWaveform.tsx
@@ -38,7 +38,6 @@ export class AudioWaveform extends React.Component<AudioWaveformProps> {
this._disposer?.();
}
componentDidMount() {
- console.log("new waveform");
this._disposer = reaction(() => ({ clipStart: this.clipStart, clipEnd: this.clipEnd, fieldKey: this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor), zoomFactor: this.props.zoomFactor }),
({ clipStart, clipEnd, fieldKey, zoomFactor }) => {
if (!this.props.layoutDoc[fieldKey]) {
@@ -65,8 +64,6 @@ export class AudioWaveform extends React.Component<AudioWaveformProps> {
const decodedAudioData = rawDecodedAudioData.slice(Math.floor(startInd * rawDecodedAudioData.length), Math.floor(endInd * rawDecodedAudioData.length));
const numBuckets = Math.floor(AudioWaveform.NUMBER_OF_BUCKETS * zoomFactor);
- console.log(numBuckets);
-
const bucketDataSize = Math.floor(
decodedAudioData.length / numBuckets
);
diff --git a/src/client/views/collections/CollectionStackedTimeline.scss b/src/client/views/collections/CollectionStackedTimeline.scss
index 0ec5f9aef..34679e9e3 100644
--- a/src/client/views/collections/CollectionStackedTimeline.scss
+++ b/src/client/views/collections/CollectionStackedTimeline.scss
@@ -4,9 +4,8 @@
position: absolute;
width: 100%;
height: 100%;
+ background: $off-white;
z-index: 1000;
- top: 0px;
- // overflow-x: scroll;
::-webkit-scrollbar {
position: relative;
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 5c02611bb..c79d21418 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -153,7 +153,6 @@ export class CollectionStackedTimeline extends CollectionSubView<
@action
public setZoom(zoom: number) {
this._zoomFactor = zoom;
- // console.log(this._timeline?.scrollWidth);
}
anchorStart = (anchor: Doc) => NumCast(anchor._timecodeToShow, NumCast(anchor[this.props.startTag]));
@@ -534,8 +533,9 @@ export class CollectionStackedTimeline extends CollectionSubView<
);
}
@computed get renderAudioWaveform() {
+ console.log(this.props.mediaPath)
return !this.props.mediaPath ? null : (
- <div className="collectionStackedTimeline-waveform" style={{ width: `${this.zoomFactor * 100}%`, overflowX: "scroll" }}>
+ <div className="collectionStackedTimeline-waveform">
<AudioWaveform
rawDuration={this.props.rawDuration}
duration={this.clipDuration}
@@ -580,7 +580,7 @@ export class CollectionStackedTimeline extends CollectionSubView<
ref={(timeline: HTMLDivElement | null) => (this._timeline = timeline)}
onClick={(e) => this.isContentActive() && StopEvent(e)}
onPointerDown={(e) => this.isContentActive() && this.onPointerDownTimeline(e)}
- onPointerEnter={(e) => { console.log("scroll"); e.preventDefault(); e.stopPropagation(); }}
+ style={{ height: this.props.PanelHeight(), width: this.props.PanelWidth() }}
>
{drawAnchors.map((d) => {
@@ -591,10 +591,10 @@ export class CollectionStackedTimeline extends CollectionSubView<
);
if (end < this.clipStart || start > this.clipEnd) return (null);
const left = Math.max((start - this.clipStart) / this.clipDuration * timelineContentWidth, 0);
- const top = (d.level / maxLevel) * this.timelineContentHeight();
+ const top = (d.level / maxLevel) * this.props.PanelHeight();
const timespan = Math.max(0, end - this.clipStart) - Math.max(0, start - this.clipStart);
const width = (timespan / this.clipDuration) * timelineContentWidth;
- const height = this.timelineContentHeight() / maxLevel;
+ const height = this.props.PanelHeight() / 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 a2fdd38e5..391507796 100644
--- a/src/client/views/nodes/AudioBox.scss
+++ b/src/client/views/nodes/AudioBox.scss
@@ -1,283 +1,144 @@
@import "../global/globalCssVariables.scss";
-.audiobox-container,
-.audiobox-container-interactive {
+.audiobox-container {
width: 100%;
height: 100%;
position: inherit;
display: flex;
position: relative;
cursor: default;
+}
+
+.audiobox-recorder {
+ display: flex;
+ flex-direction: row;
+ overflow: hidden;
+ width: 100%;
+ height: 100%;
+ cursor: pointer;
- .audiobox-buttons {
+ .audiobox-dictation {
+ width: 40px;
+ background: $medium-gray;
+ color: $dark-gray;
display: flex;
- width: 100%;
+ justify-content: center;
align-items: center;
- .audiobox-dictation {
- position: relative;
- width: 30px;
- height: 100%;
- align-items: center;
- display: inherit;
- background: $medium-gray;
- left: 0px;
- color: $dark-gray;
- &:hover {
- color: $black;
- cursor: pointer;
- }
+ &:hover {
+ color: $black;
}
}
- .audiobox-control,
- .audiobox-control-interactive {
- top: 0;
- max-height: 32px;
+ .audiobox-start-record {
+ color: $white;
+ background: $dark-gray;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: $body-text;
width: 100%;
- display: inline-block;
- pointer-events: none;
- }
+ height: 100%;
+ gap: 5px;
- .audiobox-control-interactive {
- pointer-events: all;
+ &:hover {
+ background: $black;
+ }
}
- .audiobox-record-interactive,
- .audiobox-record {
- pointer-events: all;
- cursor: pointer;
- width: 100%;
- height: 100%;
- position: relative;
+ .recording-controls {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
- gap: 10px;
- color: white;
- font-weight: bold;
- background-color: $dark-gray;
- }
-
- .audiobox-record {
- pointer-events: none;
- }
-
- .recording {
- margin-top: auto;
- margin-bottom: auto;
+ gap: 5px;
width: 100%;
height: 100%;
- position: relative;
- padding-right: 5px;
- display: flex;
- background-color: $medium-blue;
+ background: $dark-gray;
+ color: white;
- .time {
- position: relative;
- width: 100%;
+ .record-timecode {
font-size: $large-header;
- text-align: center;
}
- .recording-buttons {
- position: relative;
- margin-top: auto;
- margin-bottom: auto;
- color: $dark-gray;
- &:hover {
- color: $black;
- }
- }
-
- .time,
- .recording-buttons {
+ .record-button {
+ cursor: pointer;
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ background: $dark-gray;
display: flex;
align-items: center;
- padding: 5px;
- }
- }
- .audiobox-buttons {
- display: flex;
- width: 100%;
- align-items: center;
- height: 100%;
+ justify-content: center;
- .audiobox-dictation {
- position: relative;
- width: 30px;
- height: 100%;
- align-items: center;
- display: inherit;
- background: $medium-gray;
- left: 0px;
- color: $dark-gray;
+ svg {
+ width: 15px;
+ }
&:hover {
- color: $black;
- cursor: pointer;
+ background: $black;
}
}
}
+}
- .audiobox-control,
- .audiobox-control-interactive {
- top: 0;
- max-height: 32px;
- width: 100%;
- display: inline-block;
- pointer-events: none;
- }
-
- .audiobox-control-interactive {
- pointer-events: all;
- }
+.audiobox-file {
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ align-items: space-between;
+ background: $dark-gray;
+ width: 100%;
+ height: 100%;
+ color: $white;
- .recording {
- margin-top: auto;
- margin-bottom: auto;
- width: 100%;
- height: 100%;
- position: relative;
- padding-right: 5px;
+ .audiobox-controls {
display: flex;
flex-direction: row;
- justify-content: center;
+ justify-content: space-between;
align-items: center;
- gap: 7px;
- background-color: $medium-blue;
- padding: 10px;
-
- .time {
- position: relative;
- height: 100%;
- width: 100%;
- font-size: 16px;
- text-align: center;
- display: flex;
- justify-content: center;
- align-items: center;
- font-weight: bold;
- }
-
- .buttons {
- cursor: pointer;
- position: relative;
- margin-top: auto;
- margin-bottom: auto;
- width: 25px;
- width: 25px;
- padding: 5px;
- color: $dark-gray;
-
- &:hover {
- color: $black;
- }
- }
- }
-
- .audiobox-controls {
width: 100%;
- height: 100%;
- position: relative;
- display: flex;
- background: $dark-gray;
-
- .audiobox-dictation {
- position: absolute;
- width: 40px;
- height: 100%;
- align-items: center;
- display: inherit;
- background: $medium-gray;
- left: 0px;
- }
+ height: 30px;
- .audiobox-player {
- margin-top: auto;
- margin-bottom: auto;
- width: 100%;
- position: relative;
- padding-right: 5px;
+ .controls-left {
display: flex;
- flex-direction: column;
- justify-content: center;
+ flex-direction: row;
+ width: 100px;
- .audiobox-buttons {
- position: relative;
- margin-top: auto;
- margin-bottom: auto;
- width: 30px;
- height: 30px;
+ .audiobox-button {
+ margin: 2.5px;
+ cursor: pointer;
+ width: 25px;
+ height: 25px;
border-radius: 50%;
- background-color: $dark-gray;
- color: $white;
+ background: $dark-gray;
display: flex;
align-items: center;
justify-content: center;
- left: 5px;
-
- &:hover {
- background-color: $black;
- }
svg {
- width: 100%;
- position: absolute;
- border-width: "thin";
- border-color: "white";
+ width: 15px;
}
- }
-
- .audiobox-dictation {
- position: relative;
- margin-top: auto;
- margin-bottom: auto;
- width: 25px;
- align-items: center;
- display: inherit;
- background: $medium-gray;
- }
-
- .audiobox-timeline {
- position: absolute;
- top: 0;
- background: white;
- height: 100%;
- width: 100%;
- z-index: 1000;
- overflow: hidden;
- border-right: 5px solid black;
- }
-
- .audioBox-total-time,
- .audioBox-current-time {
- position: absolute;
- font-size: $small-text;
- top: 100%;
- color: $white;
- }
- .audioBox-current-time {
- left: 42px;
+ &:hover {
+ background: $black;
+ }
}
+ }
- .audioBox-total-time {
- right: 2px;
- }
+ .controls-right {
+ display: flex;
+ flex-direction: row;
- .toolbar-slider {
- position: absolute;
- top: 75px;
- left: 70px;
+ svg {
+ width: 10px;
}
input[type="range"] {
- width: calc(100% - 100px);
- height: 16px;
+ width: 70px;
-webkit-appearance: none;
background: none;
+ margin: 5px;
}
input[type="range"]:focus {
@@ -286,52 +147,46 @@
input[type="range"]::-webkit-slider-runnable-track {
width: 100%;
- height: 5px;
+ height: 6px;
cursor: pointer;
box-shadow: 0;
- background: #dfdfdf;
+ background: $light-gray;
border-radius: 3px;
}
input[type="range"]::-webkit-slider-thumb {
box-shadow: 0;
border: 0;
- height: 7px;
- width: 7px;
+ height: 10px;
+ width: 10px;
border-radius: 10px;
- background: #4476f7;
+ background: $medium-blue;
cursor: pointer;
-webkit-appearance: none;
- margin: -1px;
- }
-
- .audiobox-zoom {
- bottom: 0;
- left: 30px;
- width: 70px;
+ margin: -2px;
}
}
}
-}
-@media only screen and (max-device-width: 480px) {
- .audiobox-dictation {
- font-size: 5em;
- display: flex;
- width: 100;
- justify-content: center;
- flex-direction: column;
- align-items: center;
- }
+ .audiobox-playback {
+ width: 100%;
+ height: calc(100% - 50px);
- .audiobox-container .audiobox-record,
- .audiobox-container-interactive .audiobox-record {
- font-size: 3em;
+ .audiobox-timeline {
+ height: 100%;
+ width: 100%;
+ background: $white;
+ }
}
- .audiobox-container .audiobox-controls .audiobox-player .audiobox-buttons,
- .audiobox-container .audiobox-controls .audiobox-player .audiobox-dictation,
- .audiobox-container-interactive .audiobox-controls .audiobox-player .audiobox-buttons {
- width: 70px;
+ .audiobox-timecodes {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+ height: 20px;
+ padding: 3px;
+ font-size: $small-text;
}
}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index f2001adcd..48e324971 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -43,8 +43,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
AudioBox._scrubTime = timeInMillisFrom1970;
});
public static Enabled = false;
- static playheadWidth = 40; // width of playhead
- static heightPercent = 75; // height of timeline in percent of height of audioBox.
+ static topControlsHeight = 30; // width of playhead
+ static bottomControlsHeight = 20; // height of timeline in percent of height of audioBox.
static zoomInterval = 0.1;
@observable static _scrubTime = 0;
@@ -338,19 +338,13 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
timelineWhenChildContentsActiveChanged = (isActive: boolean) =>
this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive)
timelineScreenToLocal = () =>
- this.props
- .ScreenToLocalTransform()
- .translate(
- -AudioBox.playheadWidth,
- (-(100 - AudioBox.heightPercent) / 200) * this.props.PanelHeight()
- )
+ this.props.ScreenToLocalTransform().translate(0, -AudioBox.bottomControlsHeight)
setPlayheadTime = (time: number) => this._ele!.currentTime = this.layoutDoc._currentTimecode = time;
playing = () => this.mediaState === media_state.Playing;
isActiveChild = () => this._isAnyChildContentActive;
- timelineWidth = () => this.props.PanelWidth() - AudioBox.playheadWidth;
- timelineHeight = () => (this.props.PanelHeight() * (AudioBox.heightPercent / 100)) *// panelHeight * heightPercent is player height
- (AudioBox.heightPercent / 100) // * heightPercent is timeline height (as per css inline)
+ timelineWidth = () => this.props.PanelWidth();
+ timelineHeight = () => (this.props.PanelHeight() - (AudioBox.topControlsHeight + AudioBox.bottomControlsHeight))
@undoBatch
finishTrim = () => { // hides trim controls and displays new clip
@@ -365,6 +359,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
onClipPointerDown = (e: React.PointerEvent) => {
+ e.stopPropagation();
this.timeline && setupMoveUpEvents(this, e, returnFalse, returnFalse, action((e: PointerEvent, doubleTap?: boolean) => {
if (doubleTap) {
this.startTrim(TrimScope.All);
@@ -392,90 +387,81 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
@computed get recordingControls() {
- return <div className="audiobox-buttons">
+ return <div className="audiobox-recorder">
<div className="audiobox-dictation" onClick={this.onFile}>
<FontAwesomeIcon
- style={{ width: "30px" }}
- icon="file-alt"
- size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
+ size="2x"
+ icon="file-alt" />
</div>
{[media_state.Recording, media_state.Playing].includes(this.mediaState) ?
- <div className="recording" onClick={e => e.stopPropagation()}>
- <div className="recording-buttons" onClick={this.Record}>
+ <div className="recording-controls" onClick={e => e.stopPropagation()}>
+ <div className="record-button" onClick={this.Record}>
<FontAwesomeIcon
- icon="stop"
- size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
+ size="2x"
+ icon="stop" />
</div>
- <div className="recording-buttons"
- onClick={this._paused ? this.recordPlay : this.recordPause}
- >
+ <div className="record-button" onClick={this._paused ? this.recordPlay : this.recordPause}>
<FontAwesomeIcon
- icon={this._paused ? "play" : "pause"}
- size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
+ size="2x"
+ icon={this._paused ? "play" : "pause"} />
</div>
- <div className="time">
+ <div className="record-timecode">
{formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode)))}
</div>
</div>
:
- <div className={`audiobox-record${this.props.isContentActive() ? "-interactive" : ""}`}>
+ <div className="audiobox-start-record">
<FontAwesomeIcon icon="microphone" />
RECORD
</div>}
- </div>;
+ </div>
}
@computed get playbackControls() {
- return <div className="audiobox-controls"
- style={{ pointerEvents: this._isAnyChildContentActive || this.props.isContentActive() ? "all" : "none", }}
- >
- <div className="audiobox-dictation" />
- <div className="audiobox-player"
- style={{ height: `${AudioBox.heightPercent}%` }}
- >
- <div className="audiobox-buttons"
- title={this.mediaState === media_state.Paused ? "play" : "pause"}
- onClick={this.mediaState === media_state.Paused ? this.Play : this.Pause}
- >
- {" "}
- <FontAwesomeIcon
- icon={this.mediaState === media_state.Paused ? "play" : "pause"}
- size={"1x"} />
- </div>
+ return <div className="audiobox-file" style={{ pointerEvents: this._isAnyChildContentActive || this.props.isContentActive() ? "all" : "none", }}>
+ <div className="audiobox-controls">
+ <div className="controls-left">
+ <div className="audiobox-button"
+ title={this.mediaState === media_state.Paused ? "play" : "pause"}
+ onPointerDown={this.mediaState === media_state.Paused ? this.Play : this.Pause}>
+ <FontAwesomeIcon icon={this.mediaState === media_state.Paused ? "play" : "pause"} size={"1x"} />
+ </div>
- <div className="audiobox-buttons"
- title={this.timeline?.IsTrimming !== TrimScope.None ? "finish" : "trim"}
- onPointerDown={this.onClipPointerDown}
- >
- <FontAwesomeIcon
- icon={this.timeline?.IsTrimming !== TrimScope.None ? "check" : "cut"}
- size={"1x"} />
+ <div className="audiobox-button"
+ title={this.timeline?.IsTrimming !== TrimScope.None ? "finish" : "trim"}
+ onPointerDown={this.onClipPointerDown}>
+ <FontAwesomeIcon icon={this.timeline?.IsTrimming !== TrimScope.None ? "check" : "cut"} size={"1x"} />
+ </div>
</div>
+ <div className="controls-right">
+ <FontAwesomeIcon icon={["fas", "search"]} />
+ <input type="range" step="0.1" min="1" max="5" value={this.timeline?._zoomFactor}
+ className="toolbar-slider" id="zoom-slider"
+ onPointerDown={(e: React.PointerEvent) => { e.stopPropagation(); }}
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => { this.zoom(Number(e.target.value)); }}
+ />
+ </div>
+ </div>
- <div className="audiobox-timeline"
- style={{
- left: AudioBox.playheadWidth,
- width: `calc(100% - ${AudioBox.playheadWidth}px)`,
- }}
- >
+ <div className="audiobox-playback">
+ <div className="audiobox-timeline">
{this.renderTimeline}
</div>
- {this.audio}
- <div className="audioBox-current-time">
- {this.timeline && formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this.timeline.clipStart)))}
- </div>
+ </div>
- {/* <input type="range" step="0.1" min="1" max="5" value={this.timeline?._zoomFactor}
- className="toolbar-slider" id="zoom-slider"
- onPointerDown={(e: React.PointerEvent) => { e.stopPropagation(); }}
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => { this.zoom(e.target.value); }}
- /> */}
+ {this.audio}
- <div className="audioBox-total-time">
+ <div className="audiobox-timecodes">
+ <div className="timecode-current">
+ {this.timeline && formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this.timeline.clipStart)))}
+ </div>
+ <div className="timecode-duration">
{this.timeline && formatTime(Math.round(NumCast(this.timeline?.clipDuration)))}
</div>
</div>
- </div>;
+
+
+ </div>
}
@computed get renderTimeline() {
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index d80fb44cf..d47e8340c 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -89,8 +89,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
};
const displayDoc = (which: string) => {
var whichDoc = Cast(this.dataDoc[which], Doc, null);
- if (whichDoc?.type === DocumentType.MARKER) whichDoc = Cast(whichDoc.annotationOn, Doc, null);
- const targetDoc = Cast(whichDoc.annotationOn, Doc, null) ?? whichDoc;
+ // if (whichDoc?.type === DocumentType.MARKER) whichDoc = Cast(whichDoc.annotationOn, Doc, null);
+ const targetDoc = Cast(whichDoc?.annotationOn, Doc, null) ?? whichDoc;
return whichDoc ? <>
<DocumentView
ref={(r) => {