aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/util/CurrentUserUtils.ts2
-rw-r--r--src/client/util/SettingsManager.tsx15
-rw-r--r--src/client/views/DocumentDecorations.tsx1
-rw-r--r--src/client/views/EditableView.scss2
-rw-r--r--src/client/views/EditableView.tsx17
-rw-r--r--src/client/views/FilterPanel.tsx110
-rw-r--r--src/client/views/StyleProvider.tsx5
-rw-r--r--src/client/views/global/globalScripts.ts15
-rw-r--r--src/client/views/nodes/DocumentView.scss6
-rw-r--r--src/client/views/nodes/DocumentView.tsx131
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.scss1
12 files changed, 201 insertions, 106 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 161aba6e1..5c913513a 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -444,6 +444,8 @@ export class DocumentOptions {
userBackgroundColor?: STRt = new StrInfo('background color associated with a Dash user (seen in header fields of shared documents)');
userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)');
}
+
+export const DocOptions = new DocumentOptions();
export namespace Docs {
export let newAccount: boolean = false;
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index dc988b04d..591bc7430 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -707,7 +707,7 @@ export class CurrentUserUtils {
CollectionViewType.Grid, CollectionViewType.NoteTaking]),
title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: 'setView(value, _readOnly_)'}},
{ title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, expertMode: false, width: 30, scripts: { onClick: 'pinWithView(altKey)'}, funcs: {hidden: "IsNoneSelected()"}},
- { title: "Header", icon: "heading", toolTip: "Header Color", btnType: ButtonType.ColorButton, expertMode: true, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'}, funcs: {hidden: "IsNoneSelected()"}},
+ { title: "Header", icon: "heading", toolTip: "Doc Titlebar Color", btnType: ButtonType.ColorButton, expertMode: true, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'} },
{ title: "Fill", icon: "fill-drip", toolTip: "Background Fill Color",btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 30, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'}, funcs: {hidden: "IsNoneSelected()"}}, // Only when a document is selected
{ title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode, true)'}, scripts: { onClick: '{ return toggleOverlay(_readOnly_); }'}}, // Only when floating document is selected in freeform
{ title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectionManager_selectedDocType(self.toolType, self.expertMode)'}, width: 30, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index dc852596f..f75322905 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -7,7 +7,7 @@ import { BsGoogle } from 'react-icons/bs';
import { FaFillDrip, FaPalette } from 'react-icons/fa';
import { Doc } from '../../fields/Doc';
import { DashVersion } from '../../fields/DocSymbols';
-import { BoolCast, Cast, StrCast } from '../../fields/Types';
+import { BoolCast, Cast, NumCast, StrCast } from '../../fields/Types';
import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils';
import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
import { DocServer } from '../DocServer';
@@ -269,6 +269,19 @@ export class SettingsManager extends React.Component<{}> {
size={Size.XSMALL}
color={SettingsManager.userColor}
/>
+ <Group formLabel="Title Height">
+ <NumberDropdown
+ number={NumCast(Doc.UserDoc().headerHeight, 30)}
+ color={SettingsManager.userColor}
+ numberDropdownType={'slider'}
+ min={6}
+ max={60}
+ step={2}
+ type={Type.TERT}
+ unit={'px'}
+ setNumber={val => console.log('GOT: ' + (Doc.UserDoc().headerHeight = val))}
+ />
+ </Group>
</div>
);
}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index f40d2ae8b..9dafb12fb 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -944,6 +944,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
key="rad"
className="documentDecorations-borderRadius"
style={{
+ opacity: 0.5,
background: `${this._isRounding ? Colors.MEDIUM_BLUE : SettingsManager.userColor}`,
transform: `translate(${radiusHandleLocation ?? 0}px, ${(radiusHandleLocation ?? 0) + (this._showNothing ? 0 : this._titleHeight)}px)`,
}}
diff --git a/src/client/views/EditableView.scss b/src/client/views/EditableView.scss
index f7c03caf9..27b260450 100644
--- a/src/client/views/EditableView.scss
+++ b/src/client/views/EditableView.scss
@@ -3,7 +3,7 @@
overflow-wrap: break-word;
word-wrap: break-word;
hyphens: auto;
- overflow: auto;
+ overflow: hidden;
height: 100%;
min-width: 20;
text-overflow: ellipsis;
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index ca4ffaf3a..ed7c544fc 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -283,11 +283,24 @@ export class EditableView extends React.Component<EditableProps> {
<div
className={`editableView-container-editing${this.props.oneLine ? '-oneLine' : ''}`}
ref={this._ref}
- style={{ display: this.props.display, textOverflow: this.props.overflow, minHeight: '10px', whiteSpace: this.props.oneLine ? 'nowrap' : 'pre-line', height: this.props.height, maxHeight: this.props.maxHeight }}
+ style={{
+ display: this.props.display, //
+ textOverflow: this.props.overflow,
+ minHeight: '10px',
+ whiteSpace: this.props.oneLine ? 'nowrap' : 'pre-line',
+ height: this.props.height,
+ maxHeight: this.props.maxHeight,
+ }}
//onPointerDown={this.stopPropagation}
onClick={this.onClick}
placeholder={this.props.placeholder}>
- <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize }}>{this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()}</span>
+ <span
+ style={{
+ fontStyle: this.props.fontStyle,
+ fontSize: this.props.fontSize,
+ }}>
+ {this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()}
+ </span>
</div>
);
}
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 0df88f970..cb5c9b085 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -7,7 +7,7 @@ import { CiCircleRemove } from 'react-icons/ci';
import Select from 'react-select';
import { Doc, DocListCast, Field, LinkedTo, StrListCast } from '../../fields/Doc';
import { RichTextField } from '../../fields/RichTextField';
-import { DocumentOptions, FInfo } from '../documents/Documents';
+import { DocOptions, DocumentOptions, FInfo } from '../documents/Documents';
import { DocumentManager } from '../util/DocumentManager';
import { UserOptions } from '../util/GroupManager';
import { SearchUtil } from '../util/SearchUtil';
@@ -18,6 +18,7 @@ import { Handle, Tick, TooltipRail, Track } from './nodes/SliderBox-components';
import { SettingsManager } from '../util/SettingsManager';
import { Id } from '../../fields/FieldSymbols';
import { List } from '../../fields/List';
+import { emptyFunction } from '../../Utils';
interface filterProps {
rootDoc: Doc;
@@ -25,8 +26,6 @@ interface filterProps {
@observer
export class FilterPanel extends React.Component<filterProps> {
- private _documentOptions: DocumentOptions = new DocumentOptions();
-
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(FilterPanel, fieldKey);
}
@@ -51,12 +50,10 @@ export class FilterPanel extends React.Component<filterProps> {
if (targetDoc) {
SearchUtil.foreachRecursiveDoc([this.targetDoc], (depth, doc) => allDocs.add(doc));
}
- console.log('this is all Docs' + Array.from(allDocs));
return Array.from(allDocs);
}
@computed get _allFacets() {
- // trace();
const noviceReqFields = ['author', 'tags', 'text', 'type', LinkedTo];
const noviceLayoutFields: string[] = []; //["_layout_curPage"];
const noviceFields = [...noviceReqFields, ...noviceLayoutFields];
@@ -68,11 +65,8 @@ export class FilterPanel extends React.Component<filterProps> {
.filter(key => key.indexOf('modificationDate') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('_')) || noviceFields.includes(key) || !Doc.noviceMode)
.sort();
- // console.log('THIS IS HERE ' + Doc.UserDoc().color + 'space ' + Doc.UserDoc().color);
noviceFields.forEach(key => sortedKeys.splice(sortedKeys.indexOf(key), 1));
- console.log('this is novice fields ' + noviceFields + 'and this is sorted Keys ' + sortedKeys);
-
return [...noviceFields, ...sortedKeys];
}
@@ -206,13 +200,7 @@ export class FilterPanel extends React.Component<filterProps> {
*/
@action
- facetClick = (facetHeader: string) => {
- // just when someone chooses a facet
-
- this._selectedFacetHeaders.add(facetHeader);
-
- return;
- };
+ facetClick = (facetHeader: string) => this._selectedFacetHeaders.add(facetHeader);
@action
sortingCurrentFacetValues = (facetHeader: string) => {
@@ -260,57 +248,59 @@ export class FilterPanel extends React.Component<filterProps> {
return nonNumbers / facetValues.length > 0.1 ? facetValues.sort() : facetValues.sort((n1: string, n2: string) => Number(n1) - Number(n2));
};
- render() {
- let filteredOptions: string[] = ['author', 'tags', 'text', 'acl-Guest', ...this._allFacets.filter(facet => facet[0] === facet.charAt(0).toUpperCase())];
+ @computed get fieldsDropdown() {
+ const filteredOptions = ['author', 'tags', 'text', 'acl-Guest', ...this._allFacets.filter(facet => facet[0] === facet.charAt(0).toUpperCase())];
- Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => {
- if (pair[1].filterable) {
- filteredOptions.push(pair[0]);
- }
- });
+ Object.entries(DocOptions)
+ .filter(opts => opts[1].filterable)
+ .forEach((pair: [string, FInfo]) => filteredOptions.push(pair[0]));
+ const options = filteredOptions.map(facet => ({ value: facet, label: facet }));
- let options = filteredOptions.map(facet => ({ value: facet, label: facet }));
+ return (
+ <Select
+ styles={{
+ control: (baseStyles, state) => ({
+ ...baseStyles,
+ color: SettingsManager.userColor,
+ background: SettingsManager.userBackgroundColor,
+ }),
+ placeholder: (baseStyles, state) => ({
+ ...baseStyles,
+ color: SettingsManager.userColor,
+ background: SettingsManager.userBackgroundColor,
+ }),
+ input: (baseStyles, state) => ({
+ ...baseStyles,
+ color: SettingsManager.userColor,
+ background: SettingsManager.userBackgroundColor,
+ }),
+ option: (baseStyles, state) => ({
+ ...baseStyles,
+ color: SettingsManager.userColor,
+ background: !state.isFocused ? SettingsManager.userBackgroundColor : SettingsManager.userVariantColor,
+ }),
+ menuList: (baseStyles, state) => ({
+ ...baseStyles,
+ backgroundColor: SettingsManager.userBackgroundColor,
+ }),
+ }}
+ placeholder={'add a filter'}
+ options={options}
+ isMulti={false}
+ onChange={val => this.facetClick((val as UserOptions).value)}
+ onKeyDown={e => e.stopPropagation()}
+ //onMenuClose={onClose}
+ value={null}
+ closeMenuOnSelect={true}
+ />
+ );
+ }
+ render() {
return (
<div className="filterBox-treeView">
<div className="filterBox-select">
- <div style={{ width: '100%' }}>
- <Select
- styles={{
- control: (baseStyles, state) => ({
- ...baseStyles,
- color: SettingsManager.userColor,
- background: SettingsManager.userBackgroundColor,
- }),
- placeholder: (baseStyles, state) => ({
- ...baseStyles,
- color: SettingsManager.userColor,
- background: SettingsManager.userBackgroundColor,
- }),
- input: (baseStyles, state) => ({
- ...baseStyles,
- color: SettingsManager.userColor,
- background: SettingsManager.userBackgroundColor,
- }),
- option: (baseStyles, state) => ({
- ...baseStyles,
- color: SettingsManager.userColor,
- background: !state.isFocused ? SettingsManager.userBackgroundColor : SettingsManager.userVariantColor,
- }),
- menuList: (baseStyles, state) => ({
- ...baseStyles,
- backgroundColor: SettingsManager.userBackgroundColor,
- }),
- }}
- placeholder="Add a filter..."
- options={options}
- isMulti={false}
- onChange={val => this.facetClick((val as UserOptions).value)}
- onKeyDown={e => e.stopPropagation()}
- value={null}
- closeMenuOnSelect={true}
- />
- </div>
+ <div style={{ width: '100%' }}>{this.fieldsDropdown}</div>
{/* THE FOLLOWING CODE SHOULD BE DEVELOPER FOR BOOLEAN EXPRESSION (AND / OR) */}
{/* <div className="filterBox-select-bool">
<select className="filterBox-selection" onChange={action(e => this.targetDoc && (this.targetDoc._childFilters_boolean = (e.target as any).value))} defaultValue={StrCast(this.targetDoc?.childFilters_boolean)}>
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 48c96d064..5ff743a30 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -90,6 +90,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
const boxBackground = property.includes(':box');
const fieldKey = props?.fieldKey ? props.fieldKey + '_' : isCaption ? 'caption_' : '';
const lockedPosition = () => doc && BoolCast(doc._lockedPosition);
+ const titleHeight = () => props?.styleProvider?.(doc, props, StyleProp.TitleHeight);
const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
const color = () => props?.styleProvider?.(doc, props, StyleProp.Color);
const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity);
@@ -137,7 +138,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
case StyleProp.FontWeight: return StrCast(doc?.[fieldKey + 'fontWeight'], StrCast(doc?._text_fontWeight, StrCast(Doc.UserDoc().fontWeight)));
case StyleProp.FillColor: return StrCast(doc?._fillColor, StrCast(doc?.fillColor, 'transparent'));
case StyleProp.ShowCaption:return doc?._type_collection === CollectionViewType.Carousel || props?.hideCaptions ? undefined : StrCast(doc?._layout_showCaption);
- case StyleProp.TitleHeight:return 15;
+ case StyleProp.TitleHeight:return (props?.ScreenToLocalTransform().Scale ?? 1)*(props?.NativeDimScaling?.()??1) * NumCast(Doc.UserDoc().headerHeight,30)
case StyleProp.ShowTitle:
return (
(doc &&
@@ -189,7 +190,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
doc?.type === DocumentType.LABEL) &&
layout_showTitle() &&
!StrCast(doc?.layout_showTitle).includes(':hover')
- ? 15
+ ? titleHeight()
: 0;
case StyleProp.BackgroundColor: {
if (DocumentView.LastPressedSidebarBtn === doc) return SettingsManager.userColor; // hack to indicate active menu panel item
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index d8ed93bd7..ced11447c 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -68,11 +68,18 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
// toggle: Set overlay status of selected document
ScriptingGlobals.add(function setHeaderColor(color?: string, checkResult?: boolean) {
if (checkResult) {
- return Doc.SharingDoc().headingColor;
+ return SelectionManager.Views().length ? StrCast(SelectionManager.Docs().lastElement().layout_headingColor) : Doc.SharingDoc().headingColor;
+ }
+ if (SelectionManager.Views().length) {
+ SelectionManager.Docs().forEach(doc => {
+ Doc.GetProto(doc).layout_headingColor = color;
+ doc.layout_showTitle = color === 'transparent' ? undefined : StrCast(doc.layout_showTitle, 'title');
+ });
+ } else {
+ Doc.SharingDoc().headingColor = undefined;
+ Doc.GetProto(Doc.SharingDoc()).headingColor = color;
+ Doc.UserDoc().layout_showTitle = color === 'transparent' ? undefined : StrCast(Doc.UserDoc().layout_showTitle, 'author_date');
}
- Doc.SharingDoc().headingColor = undefined;
- Doc.GetProto(Doc.SharingDoc()).headingColor = color;
- Doc.UserDoc().layout_showTitle = color === 'transparent' ? undefined : StrCast(Doc.UserDoc().layout_showTitle, 'author_date');
});
// toggle: Set overlay status of selected document
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index b25540dd3..874723895 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -24,6 +24,7 @@
width: 100%;
height: 100%;
border-radius: inherit;
+ overflow: hidden; // need this so that title will be clipped when borderRadius is set
// transition: outline 0.3s linear;
// background: $white; //overflow: hidden;
@@ -118,7 +119,7 @@
display: flex;
justify-content: center;
align-items: center;
-
+
.sharingIndicator {
height: 30px;
width: 30px;
@@ -185,6 +186,7 @@
text-overflow: ellipsis;
white-space: pre;
position: absolute;
+ display: flex; // this allows title field dropdown to be inline with editable title
}
.documentView-titleWrapper-hover {
@@ -214,7 +216,7 @@
.documentView-node:hover {
> .documentView-styleWrapper {
> .documentView-titleWrapper-hover {
- display: inline-block;
+ display: flex;
}
// > .documentView-contentsView {
// opacity: 0.5;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c2355e4f7..4a43ffe3e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -17,7 +17,7 @@ import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils';
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
import { DocServer } from '../../DocServer';
-import { Docs, DocUtils } from '../../documents/Documents';
+import { DocOptions, Docs, DocUtils, FInfo } from '../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { Networking } from '../../Network';
import { DictationManager } from '../../util/DictationManager';
@@ -54,6 +54,8 @@ import { PinProps, PresBox } from './trails/PresBox';
import React = require('react');
import { KeyValueBox } from './KeyValueBox';
import { LinkBox } from './LinkBox';
+import { FilterPanel } from '../FilterPanel';
+import { Dropdown, DropdownType, Type } from 'browndash-components';
const { Howl } = require('howler');
interface Window {
@@ -143,7 +145,7 @@ export interface DocComponentView {
annotationKey?: string;
getTitle?: () => string;
getCenter?: (xf: Transform) => { X: number; Y: number };
- screenBounds?: () => { left: number; top: number; right: number; bottom: number; center?:{X:number, Y:number} };
+ screenBounds?: () => { left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } };
ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number };
ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number };
snapPt?: (pt: { X: number; Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number; Y: number }; distance: number };
@@ -622,7 +624,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (this.props.Document === Doc.ActiveDashboard) {
e.stopPropagation();
e.preventDefault();
- alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you don't have permission to modify the destination." : 'Linking to document tabs not yet supported. Drop link on document content.');
+ alert(
+ (e.target as any)?.closest?.('*.lm_content')
+ ? "You can't perform this move most likely because you didn't drag the document's title bar to enable embedding in a different document."
+ : 'Linking to document tabs not yet supported. Drop link on document content.'
+ );
return true;
}
const linkdrag = de.complete.annoDragData ?? de.complete.linkDragData;
@@ -1068,6 +1074,41 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
};
captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => this.props?.styleProvider?.(doc, props, property + ':caption');
+ @observable _changingTitleField = false;
+ @observable _dropDownInnerWidth = 0;
+ fieldsDropdown = (inputOptions: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => {
+ const filteredOptions = new Set(inputOptions);
+ const scaling = this.titleHeight / 30; /* height of Dropdown */
+ Object.entries(DocOptions)
+ .filter(opts => opts[1].filterable)
+ .forEach((pair: [string, FInfo]) => filteredOptions.add(pair[0]));
+ filteredOptions.add(StrCast(this.layoutDoc.layout_showTitle));
+ const options = Array.from(filteredOptions)
+ .filter(f => f)
+ .map(facet => ({ val: facet, text: facet }));
+ return (
+ <div style={{ width: dropdownWidth }}>
+ <div
+ ref={action((r: any) => r && (this._dropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))}
+ onPointerDown={action(e => (this._changingTitleField = true))}
+ style={{ width: 'max-content', transformOrigin: 'left', transform: `scale(${scaling})` }}>
+ <Dropdown
+ activeChanged={action(isOpen => !isOpen && (this._changingTitleField = false))}
+ selectedVal={placeholder}
+ setSelectedVal={onChange}
+ color={SettingsManager.userColor}
+ background={SettingsManager.userVariantColor}
+ type={Type.TERT}
+ closeOnSelect={true}
+ dropdownType={DropdownType.SELECT}
+ items={options}
+ width={100}
+ fillWidth
+ />
+ </div>
+ </div>
+ );
+ };
@computed get innards() {
TraceMobx();
const showTitle = this.layout_showTitle?.split(':')[0];
@@ -1095,8 +1136,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
</div>
);
const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc;
- const background = StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.userBackgroundColor));
+ const background = StrCast(
+ this.layoutDoc.layout_headingColor,
+ StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(this.layoutDoc.layout_headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.userBackgroundColor)))
+ );
+ const dropdownWidth = this._titleRef.current?._editing || this._changingTitleField ? Math.max(10, (this._dropDownInnerWidth * this.titleHeight) / 30) : 0;
const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', '');
+ // displays a 'title' at the top of a document. The title contents default to the 'title' field, but can be changed to one or more fields by
+ // setting layout_showTitle using the format: field1[;field2[...][:hover]]
+ // from the UI, this is done by clicking the title field and prefixin the format with '#'. eg., #field1[;field2;...][:hover]
const titleView = !showTitle ? null : (
<div
className={`documentView-titleWrapper${showTitleHover ? '-hover' : ''}`}
@@ -1104,39 +1152,58 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
style={{
position: this.headerMargin ? 'relative' : 'absolute',
height: this.titleHeight,
- width: !this.headerMargin ? `calc(${sidebarWidthPercent || 100}% - 18px)` : (sidebarWidthPercent || 100) + '%', // leave room for annotation button
+ width: 100 - sidebarWidthPercent + '%',
color: background === 'transparent' ? SettingsManager.userColor : lightOrDark(background),
background,
pointerEvents: (!this.disableClickScriptFunc && this.onClickHandler) || this.Document.ignoreClick ? 'none' : this.isContentActive() || this.props.isDocumentActive?.() ? 'all' : undefined,
}}>
- <EditableView
- ref={this._titleRef}
- contents={showTitle
- .split(';')
- .map(field => field.trim())
- .map(field => targetDoc[field]?.toString())
- .join('\\')}
- display={'block'}
- fontSize={10}
- GetValue={() => {
- return showTitle.split(';').length === 1 ? showTitle + '=' + Field.toString(targetDoc[showTitle.split(';')[0]] as any as Field) : '#' + showTitle;
- }}
- SetValue={undoBatch((input: string) => {
- if (input?.startsWith('#')) {
- if (this.rootDoc.layout_showTitle) {
- this.rootDoc._layout_showTitle = input?.substring(1) ? input.substring(1) : undefined;
- } else if (!this.props.layout_showTitle) {
- Doc.UserDoc().layout_showTitle = input?.substring(1) ? input.substring(1) : 'author_date';
+ {!dropdownWidth
+ ? null
+ : this.fieldsDropdown(
+ [],
+ dropdownWidth,
+ StrCast(this.layoutDoc.layout_showTitle).split(':')[0],
+ action((field: string | number) => {
+ if (this.rootDoc.layout_showTitle) {
+ this.rootDoc._layout_showTitle = field;
+ } else if (!this.props.layout_showTitle) {
+ Doc.UserDoc().layout_showTitle = field;
+ }
+ this._changingTitleField = false;
+ }),
+ action(() => (this._changingTitleField = false))
+ )}
+ <div
+ style={{
+ width: `calc(100% - ${dropdownWidth}px)`,
+ minWidth: '100px',
+ color: this._titleRef.current?._editing || this._changingTitleField ? 'black' : undefined,
+ background: this._titleRef.current?._editing || this._changingTitleField ? 'yellow' : undefined,
+ }}>
+ <EditableView
+ ref={this._titleRef}
+ contents={showTitle
+ .split(';')
+ .map(field => targetDoc[field.trim()]?.toString())
+ .join(' \\ ')}
+ display="block"
+ oneLine={true}
+ fontSize={(this.titleHeight / 15) * 10}
+ GetValue={() => (showTitle.split(';').length !== 1 ? '#' + showTitle : Field.toKeyValueString(this.rootDoc, showTitle.split(';')[0]))}
+ SetValue={undoBatch((input: string) => {
+ if (input?.startsWith('#')) {
+ if (this.rootDoc.layout_showTitle) {
+ this.rootDoc._layout_showTitle = input?.substring(1);
+ } else if (!this.props.layout_showTitle) {
+ Doc.UserDoc().layout_showTitle = input?.substring(1) ?? 'author_date';
+ }
+ } else if (showTitle && !showTitle.includes('Date') && showTitle !== 'author') {
+ KeyValueBox.SetField(targetDoc, showTitle, input);
}
- } else {
- var value = input.replace(new RegExp(showTitle + '='), '') as string | number;
- if (showTitle !== 'title' && Number(value).toString() === value) value = Number(value);
- if (showTitle.includes('Date') || showTitle === 'author') return true;
- Doc.SetInPlace(targetDoc, showTitle, value, true);
- }
- return true;
- })}
- />
+ return true;
+ })}
+ />
+ </div>
</div>
);
return this.props.hideTitle || (!showTitle && !this.layout_showCaption) ? (
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss
index 6765e1dea..818c0cbe7 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.scss
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss
@@ -37,7 +37,6 @@ audiotag:hover {
background: inherit;
padding: 0;
border-width: 0px;
- border-radius: inherit;
border-color: $medium-gray;
box-sizing: border-box;
background-color: inherit;