aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/components/src/components/Button/Button.scss5
-rw-r--r--packages/components/src/components/IconButton/IconButton.scss5
-rw-r--r--src/client/util/DictationManager.ts39
-rw-r--r--src/client/views/DocViewUtils.ts3
-rw-r--r--src/client/views/DocumentButtonBar.tsx2
-rw-r--r--src/client/views/DocumentDecorations.tsx4
-rw-r--r--src/client/views/StyleProvider.scss5
-rw-r--r--src/client/views/StyleProvider.tsx18
-rw-r--r--src/client/views/TagsView.scss6
-rw-r--r--src/client/views/TagsView.tsx21
-rw-r--r--src/client/views/nodes/DocumentView.tsx12
-rw-r--r--src/client/views/nodes/IconTagBox.scss1
-rw-r--r--src/client/views/nodes/IconTagBox.tsx69
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx4
14 files changed, 100 insertions, 94 deletions
diff --git a/packages/components/src/components/Button/Button.scss b/packages/components/src/components/Button/Button.scss
index b2fb48344..c86db9fad 100644
--- a/packages/components/src/components/Button/Button.scss
+++ b/packages/components/src/components/Button/Button.scss
@@ -63,13 +63,16 @@
filter: opacity(0);
&.active {
- filter: opacity(0.5);
+ filter: opacity(0.3);
}
}
&:hover {
.background {
filter: opacity(0.3);
+ &.active {
+ filter: opacity(0);
+ }
}
}
}
diff --git a/packages/components/src/components/IconButton/IconButton.scss b/packages/components/src/components/IconButton/IconButton.scss
index 3f0dd26ea..f95d94ae4 100644
--- a/packages/components/src/components/IconButton/IconButton.scss
+++ b/packages/components/src/components/IconButton/IconButton.scss
@@ -54,13 +54,16 @@
filter: opacity(0);
&.active {
- filter: opacity(0.5);
+ filter: opacity(0.3);
}
}
&:hover {
.background {
filter: opacity(0.3);
+ &.active {
+ filter: opacity(0);
+ }
}
}
}
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 44fbda319..2eef3da0e 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -356,23 +356,16 @@ export namespace DictationManager {
action: (target: DocumentView, matches: RegExpExecArray) => {
const count = interpretNumber(matches[1]);
const what = matches[2];
- const dataDoc = Doc.GetProto(target.Document);
- const fieldKey = 'data';
- if (isNaN(count)) {
- return;
- }
- for (let i = 0; i < count; i++) {
- let created: Doc | undefined;
- switch (what) {
- case 'image':
- created = Docs.Create.ImageDocument('https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg');
- break;
- case 'nested collection':
- created = Docs.Create.FreeformDocument([], {});
- break;
- default:
+ if (!isNaN(count)) {
+ for (let i = 0; i < count; i++) {
+ const created = (() => {
+ switch (what) {
+ case 'image': return Docs.Create.ImageDocument('https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg');
+ case 'nested collection':return Docs.Create.FreeformDocument([], {});
+ } // prettier-ignore
+ })();
+ created && Doc.AddDocToList(target.dataDoc, Doc.LayoutFieldKey(target.Document), created);
}
- created && Doc.AddDocToList(dataDoc, fieldKey, created);
}
},
restrictTo: [DocumentType.COL],
@@ -388,13 +381,15 @@ export namespace DictationManager {
},
];
}
- export function recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) {
+ export function recordAudioAnnotation(doc: Doc, fieldIn: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) {
+ const field = '$' + fieldIn + '_audioAnnotations';
let gumStream: MediaStream | undefined;
let recorder: MediaRecorder | undefined;
navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
- let audioTextAnnos = Cast(dataDoc[field + '_audioAnnotations_text'], listSpec('string'), null);
+ let audioTextAnnos = Cast(doc[field + '_text'], listSpec('string'), null);
if (audioTextAnnos) audioTextAnnos.push('');
- else audioTextAnnos = dataDoc[field + '_audioAnnotations_text'] = new List<string>(['']);
+ else audioTextAnnos = doc[field + '_text'] = new List<string>(['']);
+ doc._layout_showTags = true;
DictationManager.Controls.listen({
interimHandler: value => { audioTextAnnos[audioTextAnnos.length - 1] = value; }, // prettier-ignore
continuous: { indefinite: false },
@@ -415,16 +410,16 @@ export namespace DictationManager {
const [{ result }] = await Networking.UploadFilesToServer({ file: file as Blob & { name: string; lastModified: number; webkitRelativePath: string } });
if (!(result instanceof Error)) {
const audioField = new AudioField(result.accessPaths.agnostic.client);
- const audioAnnos = Cast(dataDoc[field + '_audioAnnotations'], listSpec(AudioField), null);
+ const audioAnnos = Cast(doc[field], listSpec(AudioField), null);
if (audioAnnos) audioAnnos.push(audioField);
- else dataDoc[field + '_audioAnnotations'] = new List([audioField]);
+ else doc[field] = new List([audioField]);
}
};
recorder.start();
const stopFunc = () => {
recorder?.stop();
DictationManager.Controls.stop(/* false */);
- dataDoc.audioAnnoState = AudioAnnoState.stopped;
+ doc._audioAnnoState = AudioAnnoState.stopped;
gumStream?.getAudioTracks()[0].stop();
};
if (onRecording) onRecording(stopFunc);
diff --git a/src/client/views/DocViewUtils.ts b/src/client/views/DocViewUtils.ts
index 1f5f29c7e..5710187b5 100644
--- a/src/client/views/DocViewUtils.ts
+++ b/src/client/views/DocViewUtils.ts
@@ -1,6 +1,3 @@
-/* eslint-disable prefer-destructuring */
-/* eslint-disable default-param-last */
-/* eslint-disable no-use-before-define */
import { runInAction } from 'mobx';
import { Doc, SetActiveAudioLinker } from '../../fields/Doc';
import { DocUtils } from '../documents/DocUtils';
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index b17dbc93d..9a57a5e6c 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -358,7 +358,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
view =>
view &&
DictationManager.recordAudioAnnotation(
- view.dataDoc,
+ view.Document,
view.LayoutFieldKey,
stopFunc => {
this._stopFunc = stopFunc;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 7842c233a..875eb45e0 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -834,7 +834,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
<div key="c" className="documentDecorations-centerCont" />
<div key="r" className="documentDecorations-rightResizer" onPointerDown={this.onPointerDown} />
<div key="bl" className="documentDecorations-bottomLeftResizer" onPointerDown={this.onPointerDown} />
- <div key="b" className="documentDecorations-bottomResizer" onPointerDown={this.onPointerDown} />
+ {(seldocview.TagPanelHeight ?? 0) > 30 ? null : <div key="b" className="documentDecorations-bottomResizer" onPointerDown={this.onPointerDown} />}
<div key="br" className="documentDecorations-bottomRightResizer" onPointerDown={this.onPointerDown} />
</>
)}
@@ -866,7 +866,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
top: 30, // offset by height of documentButtonBar so that items can be clicked without overlap interference
transform: `translate(${-this._resizeBorderWidth / 2 + 10}px, ${this._resizeBorderWidth + bounds.b - bounds.y + this._titleHeight}px) `,
}}>
- {DocumentView.Selected().length > 1 ? <TagsView Views={DocumentView.Selected()} /> : null}
+ {DocumentView.Selected().length > 1 ? <TagsView Views={DocumentView.Selected()} background={SnappingManager.userBackgroundColor ?? ''} /> : null}
</div>
</div>
diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss
index 501b9a292..99796f1fb 100644
--- a/src/client/views/StyleProvider.scss
+++ b/src/client/views/StyleProvider.scss
@@ -1,5 +1,4 @@
.styleProvider-filter,
-.styleProvider-audio,
.styleProvider-paint,
.styleProvider-paint-selected,
.styleProvider-lock {
@@ -32,9 +31,6 @@
margin: auto !important;
}
}
-.styleProvider-audio {
- right: 40;
-}
.styleProvider-paint-selected,
.styleProvider-paint {
top: 15;
@@ -43,7 +39,6 @@
right: -40;
}
.styleProvider-lock:hover,
-.styleProvider-audio:hover,
.styleProvider-filter:hover {
opacity: 1;
}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index a59d39cfb..432a05146 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -1,7 +1,6 @@
import { Dropdown, DropdownType, IconButton, IListItemProps, Shadows, Size, Type } from '@dash/components';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Tooltip } from '@mui/material';
import { action, untracked } from 'mobx';
import { extname } from 'path';
import * as React from 'react';
@@ -9,11 +8,11 @@ import { BsArrowDown, BsArrowDownUp, BsArrowUp } from 'react-icons/bs';
import { FaFilter } from 'react-icons/fa';
import { ClientUtils, DashColor, lightOrDark } from '../../ClientUtils';
import { Doc, Opt, StrListCast } from '../../fields/Doc';
+import { DocLayout } from '../../fields/DocSymbols';
import { Id } from '../../fields/FieldSymbols';
import { InkInkTool } from '../../fields/InkField';
import { ScriptField } from '../../fields/ScriptField';
import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../fields/Types';
-import { AudioAnnoState } from '../../server/SharedMediaTypes';
import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
import { IsFollowLinkScript } from '../documents/DocUtils';
import { SnappingManager } from '../util/SnappingManager';
@@ -26,7 +25,6 @@ import { FieldViewProps } from './nodes/FieldView';
import { StyleProp } from './StyleProp';
import './StyleProvider.scss';
import { styleProviderQuiz } from './StyleProviderQuiz';
-import { DocLayout } from '../../fields/DocSymbols';
function toggleLockedPosition(doc: Doc) {
UndoManager.RunInBatch(() => Doc.toggleLockedPosition(doc), 'toggleBackground');
@@ -387,26 +385,12 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
</div>
);
};
- const audio = () => {
- const audioAnnoState = (audioDoc: Doc) => StrCast(audioDoc.audioAnnoState, AudioAnnoState.stopped);
- const audioAnnosCount = (audioDoc: Doc) => StrListCast(audioDoc[fieldKey + 'audioAnnotations']).length;
- if (!doc || renderDepth === -1 || !audioAnnosCount(doc)) return null;
- const audioIconColors: { [key: string]: string } = { playing: 'green', stopped: 'blue' };
- return (
- <Tooltip title={<div>{StrListCast(doc[fieldKey + 'audioAnnotations_text']).lastElement()}</div>}>
- <div className="styleProvider-audio" onPointerDown={() => DocumentView.getFirstDocumentView(doc)?.playAnnotation()}>
- <FontAwesomeIcon className="documentView-audioFont" style={{ color: audioIconColors[audioAnnoState(doc)] }} icon='file-audio' size="sm" />
- </div>
- </Tooltip>
- );
- };
return (
<>
{paint()}
{lock()}
{filter()}
- {audio()}
</>
);
}
diff --git a/src/client/views/TagsView.scss b/src/client/views/TagsView.scss
index b21d303fb..231d5e11a 100644
--- a/src/client/views/TagsView.scss
+++ b/src/client/views/TagsView.scss
@@ -12,7 +12,7 @@
.tagsView-list {
display: flex;
flex-wrap: wrap;
- height: 1;
+ height: 100%;
.iconButton-container {
min-height: unset !important;
}
@@ -57,10 +57,6 @@
align-items: center;
}
-.tagsView-editing-box {
- margin-top: 20px;
-}
-
.tagsView-input-box {
margin: auto;
align-self: center;
diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx
index f1bcaac2c..39c952483 100644
--- a/src/client/views/TagsView.tsx
+++ b/src/client/views/TagsView.tsx
@@ -1,5 +1,5 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Button, Colors, IconButton } from '@dash/components';
+import { Button, Colors, IconButton, Type } from '@dash/components';
import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import React from 'react';
@@ -20,6 +20,7 @@ import { DocumentView } from './nodes/DocumentView';
import { FaceRecognitionHandler } from './search/FaceRecognitionHandler';
import { IconTagBox } from './nodes/IconTagBox';
import { Id } from '../../fields/FieldSymbols';
+import { StyleProp } from './StyleProp';
/**
* The TagsView is a metadata input/display panel shown at the bottom of a DocumentView in a freeform collection.
@@ -254,6 +255,7 @@ export class TagItem extends ObservableReactComponent<TagItemProps> {
interface TagViewProps {
Views: DocumentView[];
+ background: string;
}
/**
@@ -269,7 +271,7 @@ export class TagsView extends ObservableReactComponent<TagViewProps> {
@observable _panelHeightDirty = 0;
@observable _currentInput = '';
- @observable _isEditing = !StrListCast(this.View.dataDoc.tags).length;
+ @observable _isEditing: boolean | undefined = undefined;
_heightDisposer: IReactionDisposer | undefined;
_lastXf = this.View.screenToContentsTransform();
@@ -295,7 +297,9 @@ export class TagsView extends ObservableReactComponent<TagViewProps> {
}
@computed get isEditing() {
- return this._isEditing && (this._props.Views.length > 1 || (DocumentView.Selected().length === 1 && DocumentView.Selected().includes(this.View)));
+ const selected = DocumentView.Selected().length === 1 && DocumentView.Selected().includes(this.View);
+ if (this._isEditing === undefined) return selected && !StrListCast(this.View.dataDoc.tags).length && !StrListCast(this.View.dataDoc[Doc.LayoutFieldKey(this.View.Document) + '_audioAnnotations_text']).length;
+ return this._isEditing && (this._props.Views.length > 1 || selected);
}
/**
@@ -349,7 +353,7 @@ export class TagsView extends ObservableReactComponent<TagViewProps> {
ref={r => r && new ResizeObserver(action(() => this._props.Views.length === 1 && (this.View.TagPanelHeight = Math.max(0, (r?.getBoundingClientRect().height ?? 0) - this.InsetDist)))).observe(r)}
style={{
display: SnappingManager.IsResizing === this.View.Document[Id] ? 'none' : undefined,
- backgroundColor: this.isEditing ? Colors.LIGHT_GRAY : Colors.TRANSPARENT,
+ backgroundColor: this.isEditing ? this._props.background : Colors.TRANSPARENT,
borderColor: this.isEditing ? Colors.BLACK : Colors.TRANSPARENT,
height: !this._props.Views.lastElement()?.isSelected() ? 0 : undefined,
}}>
@@ -361,14 +365,17 @@ export class TagsView extends ObservableReactComponent<TagViewProps> {
tooltip="Close Menu"
onPointerDown={e =>
setupMoveUpEvents(this, e, returnFalse, emptyFunction, upEv => {
- this.setToEditing(!this._isEditing);
+ this.setToEditing(!this.isEditing);
upEv.stopPropagation();
})
}
- icon={<FontAwesomeIcon icon={this._isEditing ? 'chevron-up' : 'chevron-down'} size="sm" />}
+ type={Type.TERT}
+ background="transparent"
+ color={this.View._props.styleProvider?.(this.View.Document, this.View.ComponentView?._props, StyleProp.FontColor) as string}
+ icon={<FontAwesomeIcon icon={this.isEditing ? 'chevron-up' : 'chevron-down'} size="sm" />}
/>
)}
- <IconTagBox Views={this._props.Views} IsEditing={this._isEditing} />
+ <IconTagBox Views={this._props.Views} IsEditing={this.isEditing} />
{Array.from(tagsList)
.filter(tag => (tag.startsWith('#') || tag.startsWith('@')) && !Doc.MyFilterHotKeys.some(key => key.toolType === tag))
.map(tag => (
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c3026d7be..070a13103 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -750,7 +750,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewProps & Field
transform: `scale(${this.uiBtnScaling})`,
bottom: Number.isNaN(this.maxWidgetSize) ? undefined : this.maxWidgetSize,
}}>
- {this._props.DocumentView?.() && !this._props.docViewPath().slice(-2)[0].ComponentView?.isUnstyledView?.() ? <TagsView Views={[this._props.DocumentView?.()]} /> : null}
+ {this._props.DocumentView?.() && !this._props.docViewPath().slice(-2)[0].ComponentView?.isUnstyledView?.() ? <TagsView background={this.backgroundBoxColor} Views={[this._props.DocumentView?.()]} /> : null}
</div>
) : (
<>
@@ -774,7 +774,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewProps & Field
ref={r => this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}>
<div className="documentView-editorView-resizer" />
{this._componentView?.componentAIView?.() ?? null}
- {this._props.DocumentView?.() ? <TagsView Views={[this._props.DocumentView?.()]} /> : null}
+ {this._props.DocumentView?.() ? <TagsView background={this.backgroundBoxColor} Views={[this._props.DocumentView?.()]} /> : null}
</div>
</>
)}
@@ -1319,7 +1319,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
}
public playAnnotation = () => {
- const audioAnnoState = this.dataDoc.audioAnnoState ?? AudioAnnoState.stopped;
+ const audioAnnoState = this.Document._audioAnnoState ?? AudioAnnoState.stopped;
const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '_audioAnnotations'], listSpec(AudioField), null);
const anno = audioAnnos?.lastElement();
if (anno instanceof AudioField) {
@@ -1331,13 +1331,13 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
autoplay: true,
loop: false,
volume: 0.5,
- onend: action(() => { this.dataDoc.audioAnnoState = AudioAnnoState.stopped; }), // prettier-ignore
+ onend: action(() => { this.Document._audioAnnoState = AudioAnnoState.stopped; }), // prettier-ignore
});
- this.dataDoc.audioAnnoState = AudioAnnoState.playing;
+ this.Document._audioAnnoState = AudioAnnoState.playing;
break;
case AudioAnnoState.playing:
(this.dataDoc[AudioPlay] as Howl)?.stop();
- this.dataDoc.audioAnnoState = AudioAnnoState.stopped;
+ this.Document._audioAnnoState = AudioAnnoState.stopped;
break;
default:
}
diff --git a/src/client/views/nodes/IconTagBox.scss b/src/client/views/nodes/IconTagBox.scss
index 202b0c701..d6cf95958 100644
--- a/src/client/views/nodes/IconTagBox.scss
+++ b/src/client/views/nodes/IconTagBox.scss
@@ -4,7 +4,6 @@
display: flex;
position: relative;
pointer-events: none;
- background-color: rgb(218, 218, 218);
border-radius: 50px;
align-items: center;
gap: 5px;
diff --git a/src/client/views/nodes/IconTagBox.tsx b/src/client/views/nodes/IconTagBox.tsx
index ddabd61e1..e3924eca7 100644
--- a/src/client/views/nodes/IconTagBox.tsx
+++ b/src/client/views/nodes/IconTagBox.tsx
@@ -1,22 +1,23 @@
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import React from 'react';
-import { returnFalse, setupMoveUpEvents } from '../../../ClientUtils';
-import { emptyFunction } from '../../../Utils';
-import { Doc } from '../../../fields/Doc';
+import { Doc, StrListCast } from '../../../fields/Doc';
import { StrCast } from '../../../fields/Types';
+import { AudioAnnoState } from '../../../server/SharedMediaTypes';
import { undoable } from '../../util/UndoManager';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { TagItem } from '../TagsView';
import { DocumentView } from './DocumentView';
import './IconTagBox.scss';
+import { Size, Toggle, ToggleType, Type } from '@dash/components';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { StyleProp } from '../StyleProp';
export interface IconTagProps {
Views: DocumentView[];
- IsEditing: boolean;
+ IsEditing: boolean | undefined;
}
/**
@@ -52,13 +53,46 @@ export class IconTagBox extends ObservableReactComponent<IconTagProps> {
* @param key metadata icon button
* @returns an icon for the metdata button
*/
- getButtonIcon = (doc: Doc, key: Doc): JSX.Element => {
+ getButtonIcon = (dv: DocumentView, key: Doc): JSX.Element => {
const icon = StrCast(key.icon) as IconProp;
const tag = StrCast(key.toolType);
- const isActive = TagItem.docHasTag(doc, tag);
- const color = isActive ? '#4476f7' : '#323232'; // TODO should use theme colors
+ const color = dv._props.styleProvider?.(dv.layoutDoc, dv.ComponentView?._props, StyleProp.FontColor) as string;
+ return (
+ <Toggle
+ tooltip={`Click to add/remove the tag ${tag}`}
+ toggleStatus={TagItem.docHasTag(dv.Document, tag)}
+ toggleType={ToggleType.BUTTON}
+ icon={<FontAwesomeIcon className={`fontIconBox-icon-${ToggleType.BUTTON}`} icon={icon} color={color} />}
+ size={Size.XSMALL}
+ type={Type.PRIM}
+ onClick={() => this.setIconTag(tag, !TagItem.docHasTag(this.View.Document, tag))}
+ color={color}
+ />
+ );
+ };
- return <FontAwesomeIcon icon={icon} style={{ color, height: '20px', width: '20px' }} />;
+ /**
+ * Displays a button to play audio annotations on the document.
+ * NOTE: This should be generalized -- audio should
+ * @returns
+ */
+ renderAudioButtons = (dv: DocumentView, anno: string) => {
+ const fcolor = dv._props.styleProvider?.(dv.layoutDoc, dv.ComponentView?._props, StyleProp.FontColor) as string;
+ const audioIconColors: { [key: string]: string } = { playing: 'green', stopped: fcolor ?? 'blue', recording: 'red' };
+ const audioAnnoState = (audioDoc: Doc) => StrCast(audioDoc.audioAnnoState, AudioAnnoState.stopped);
+ const color = audioIconColors[audioAnnoState(this.View.Document)];
+ return (
+ <Toggle
+ tooltip={`click to play:${anno}`}
+ toggleStatus={true}
+ toggleType={ToggleType.BUTTON}
+ icon={<FontAwesomeIcon className={`fontIconBox-icon-${ToggleType.BUTTON}`} icon="file-audio" color={color} />}
+ size={Size.XSMALL}
+ type={Type.PRIM}
+ onClick={() => this.View?.playAnnotation()}
+ color={color}
+ />
+ );
};
/**
@@ -69,22 +103,15 @@ export class IconTagBox extends ObservableReactComponent<IconTagProps> {
.map(key => ({ key, tag: StrCast(key.toolType) }))
.filter(({ tag }) => this._props.IsEditing || TagItem.docHasTag(this.View.Document, tag) || (DocumentView.Selected().length === 1 && this.View.IsSelected))
.map(({ key, tag }) => (
- <Tooltip key={tag} title={<div className="dash-tooltip">Click to add/remove this card from the {tag} group</div>}>
- <button
- type="button"
- onPointerDown={e =>
- setupMoveUpEvents(this, e, returnFalse, emptyFunction, clickEv => {
- this.setIconTag(tag, !TagItem.docHasTag(this.View.Document, tag));
- clickEv.stopPropagation();
- })
- }>
- {this.getButtonIcon(this.View.Document, key)}
- </button>
+ <Tooltip key={tag} title={<div className="dash-tooltip">Click to add/remove the {tag} tag</div>}>
+ {this.getButtonIcon(this.View, key)}
</Tooltip>
)); // prettier-ignore
- return !buttons.length ? null : (
+ const audioannos = StrListCast(this.View.Document[Doc.LayoutFieldKey(this.View.Document) + '_audioAnnotations_text']);
+ return !buttons.length && !audioannos.length ? null : (
<div className="card-button-container" style={{ fontSize: '50px' }}>
+ {audioannos.length ? this.renderAudioButtons(this.View, audioannos.lastElement()) : null}
{buttons}
</div>
);
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 51b9a4333..6955e5401 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -17,7 +17,7 @@ import { BsMarkdownFill } from 'react-icons/bs';
import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, ClientUtils, DivWidth, returnFalse, returnZero, setupMoveUpEvents, simMouseEvent, smoothScroll, StopEvent } from '../../../../ClientUtils';
import { DateField } from '../../../../fields/DateField';
import { CreateLinkToActiveAudio, Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../../fields/Doc';
-import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, DocData, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols';
+import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols';
import { Id, ToString } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
@@ -246,7 +246,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
anchor.followLinkAudio = true;
let stopFunc: () => void = emptyFunction;
target.$mediaState = mediaState.Recording;
- DictationManager.recordAudioAnnotation(target[DocData], Doc.LayoutFieldKey(target), stop => { stopFunc = stop }); // prettier-ignore
+ DictationManager.recordAudioAnnotation(target, Doc.LayoutFieldKey(target), stop => { stopFunc = stop }); // prettier-ignore
const reactionDisposer = reaction(
() => target.mediaState,