mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Polish dark mode and remove beta tag
Summary: Polishes support for dark mode and enables syncing with the OS theme by default. Test Plan: Manual. Reviewers: JakubSerafin Reviewed By: JakubSerafin Subscribers: JakubSerafin Differential Revision: https://phab.getgrist.com/D4041
This commit is contained in:
@@ -1,20 +1,20 @@
|
||||
var dispose = require('../lib/dispose');
|
||||
const {theme} = require('app/client/ui2018/cssVars');
|
||||
const {CellStyle} = require('app/client/widgets/CellStyle');
|
||||
const {dom} = require('grainjs');
|
||||
|
||||
/**
|
||||
* AbstractWidget - The base of the inheritance tree for widgets.
|
||||
* @param {Function} field - The RowModel for this view field.
|
||||
* @param {string|undefined} options.defaultTextColor - A hex value to set the default text color
|
||||
* for the widget. Omit defaults to '#000000'.
|
||||
* @param {string|undefined} options.defaultTextColor - CSS value of the default
|
||||
* text color for the widget. Defaults to the current theme's cell fg color.
|
||||
*
|
||||
*/
|
||||
function AbstractWidget(field, opts = {}) {
|
||||
this.field = field;
|
||||
this.options = field.widgetOptionsJson;
|
||||
const {defaultTextColor = '#000000'} = opts;
|
||||
this.defaultTextColor = defaultTextColor;
|
||||
this.valueFormatter = this.field.visibleColFormatter;
|
||||
this.defaultTextColor = opts.defaultTextColor || '#000000';
|
||||
this.defaultTextColor = opts.defaultTextColor ?? theme.cellFg.toString();
|
||||
}
|
||||
dispose.makeDisposable(AbstractWidget);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import {selectFiles, uploadFiles} from 'app/client/lib/uploads';
|
||||
import {DocData} from 'app/client/models/DocData';
|
||||
import {MetaTableData} from 'app/client/models/TableData';
|
||||
import {basicButton, basicButtonLink, cssButtonGroup} from 'app/client/ui2018/buttons';
|
||||
import {colors, testId, vars} from 'app/client/ui2018/cssVars';
|
||||
import {testId, theme, vars} from 'app/client/ui2018/cssVars';
|
||||
import {editableLabel} from 'app/client/ui2018/editableLabel';
|
||||
import {icon} from 'app/client/ui2018/icons';
|
||||
import {IModalControl, modal} from 'app/client/ui2018/modals';
|
||||
@@ -315,12 +315,12 @@ const cssCloseButton = styled('div', `
|
||||
padding: 6px;
|
||||
border-radius: 32px;
|
||||
cursor: pointer;
|
||||
background-color: ${colors.light};
|
||||
--icon-color: ${colors.lightGreen};
|
||||
background-color: ${theme.attachmentsEditorButtonBg};
|
||||
--icon-color: ${theme.attachmentsEditorButtonFg};
|
||||
|
||||
&:hover {
|
||||
background-color: ${colors.mediumGreyOpaque};
|
||||
--icon-color: ${colors.darkGreen};
|
||||
background-color: ${theme.attachmentsEditorButtonHoverBg};
|
||||
--icon-color: ${theme.attachmentsEditorButtonHoverFg};
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -336,10 +336,10 @@ const cssTitle = styled('div', `
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
outline: 1px solid ${colors.slate};
|
||||
outline: 1px solid ${theme.lightText};
|
||||
}
|
||||
&:focus-within {
|
||||
outline: 1px solid ${colors.darkGreen};
|
||||
outline: 1px solid ${theme.controlFg};
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -362,13 +362,14 @@ const cssFileButtons = styled(cssButtonGroup, `
|
||||
`);
|
||||
|
||||
const cssButton = styled(basicButton, `
|
||||
background-color: ${colors.light};
|
||||
color: ${theme.attachmentsEditorButtonFg};
|
||||
background-color: ${theme.attachmentsEditorButtonBg};
|
||||
font-weight: normal;
|
||||
padding: 0 16px;
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
border-left: 1px solid ${colors.darkGrey};
|
||||
border-left: 1px solid ${theme.attachmentsEditorButtonBorder};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -376,13 +377,14 @@ const cssButton = styled(basicButton, `
|
||||
border: none;
|
||||
}
|
||||
&:hover {
|
||||
background-color: ${colors.mediumGreyOpaque};
|
||||
border-color: ${colors.darkGrey};
|
||||
color: ${theme.attachmentsEditorButtonHoverFg};
|
||||
background-color: ${theme.attachmentsEditorButtonHoverBg};
|
||||
border-color: ${theme.attachmentsEditorButtonBorder};
|
||||
}
|
||||
`);
|
||||
|
||||
const cssButtonIcon = styled(icon, `
|
||||
--icon-color: ${colors.slate};
|
||||
--icon-color: ${theme.attachmentsEditorButtonIcon};
|
||||
margin-right: 4px;
|
||||
`);
|
||||
|
||||
@@ -397,11 +399,11 @@ const cssNextArrow = styled('div', `
|
||||
padding: 6px;
|
||||
border-radius: 32px;
|
||||
cursor: pointer;
|
||||
background-color: ${colors.lightGreen};
|
||||
--icon-color: ${colors.light};
|
||||
background-color: ${theme.controlPrimaryBg};
|
||||
--icon-color: ${theme.controlPrimaryFg};
|
||||
|
||||
&:hover {
|
||||
background-color: ${colors.darkGreen};
|
||||
background-color: ${theme.controlPrimaryHoverBg};
|
||||
}
|
||||
&-left {
|
||||
transform: rotateY(180deg);
|
||||
@@ -453,7 +455,7 @@ const cssDetails = styled('div', `
|
||||
`);
|
||||
|
||||
const cssDragArea = styled(cssContent, `
|
||||
border: 2px dashed ${colors.mediumGreyOpaque};
|
||||
border: 2px dashed ${theme.attachmentsEditorBorder};
|
||||
height: calc(100% - 96px);
|
||||
margin-top: 64px;
|
||||
padding: 0px;
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as commands from 'app/client/components/commands';
|
||||
import {dragOverClass} from 'app/client/lib/dom';
|
||||
import {selectFiles, uploadFiles} from 'app/client/lib/uploads';
|
||||
import {cssRow} from 'app/client/ui/RightPanelStyles';
|
||||
import {colors, testId, vars} from 'app/client/ui2018/cssVars';
|
||||
import {colors, testId, theme, vars} from 'app/client/ui2018/cssVars';
|
||||
import {NewAbstractWidget} from 'app/client/widgets/NewAbstractWidget';
|
||||
import {encodeQueryParams} from 'app/common/gutil';
|
||||
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
||||
@@ -191,16 +191,16 @@ const cssAttachmentIcon = styled('div.glyphicon.glyphicon-paperclip', `
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
padding: 2px;
|
||||
background-color: #D0D0D0;
|
||||
color: white;
|
||||
background-color: ${theme.attachmentsCellIconBg};
|
||||
color: ${theme.attachmentsCellIconFg};
|
||||
border-radius: 2px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 0 1px white;
|
||||
box-shadow: 0 0 0 1px ${theme.cellEditorBg};
|
||||
z-index: 1;
|
||||
|
||||
&:hover {
|
||||
background-color: #3290BF;
|
||||
background-color: ${theme.attachmentsCellIconHoverBg};
|
||||
}
|
||||
|
||||
&-hover {
|
||||
@@ -222,12 +222,12 @@ const cssAttachmentPreview = styled('div', `
|
||||
justify-content: center;
|
||||
z-index: 0;
|
||||
&:hover {
|
||||
border-color: ${colors.lightGreen};
|
||||
border-color: ${theme.cursor};
|
||||
}
|
||||
`);
|
||||
|
||||
const cssSizeLabel = styled('div', `
|
||||
color: ${colors.slate};
|
||||
color: ${theme.lightText};
|
||||
margin-right: 9px;
|
||||
`);
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export class CellStyle extends Disposable {
|
||||
constructor(
|
||||
private _field: ViewFieldRec,
|
||||
private _gristDoc: GristDoc,
|
||||
private _defaultTextColor: string
|
||||
private _defaultTextColor: string|undefined
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -51,21 +51,26 @@ export class CellStyle extends Disposable {
|
||||
});
|
||||
return colorSelect(
|
||||
{
|
||||
textColor: new ColorOption(
|
||||
{ color: headerTextColor, defaultColor: this._defaultTextColor, noneText: 'default' }
|
||||
),
|
||||
fillColor: new ColorOption(
|
||||
{ color: headerFillColor, allowsNone: true, noneText: 'none' }
|
||||
),
|
||||
textColor: new ColorOption({
|
||||
color: headerTextColor,
|
||||
defaultColor: theme.tableHeaderFg.toString(),
|
||||
noneText: 'default',
|
||||
}),
|
||||
fillColor: new ColorOption({
|
||||
color: headerFillColor,
|
||||
allowsNone: true,
|
||||
noneText: 'none',
|
||||
}),
|
||||
fontBold: headerFontBold,
|
||||
fontItalic: headerFontItalic,
|
||||
fontUnderline: headerFontUnderline,
|
||||
fontStrikethrough: headerFontStrikethrough
|
||||
}, {
|
||||
onSave: () => options.save(),
|
||||
onRevert: () => options.revert(),
|
||||
placeholder: use => use(hasMixedStyle) ? t('Mixed style') : t('Default header style')
|
||||
}
|
||||
},
|
||||
{
|
||||
onSave: () => options.save(),
|
||||
onRevert: () => options.revert(),
|
||||
placeholder: use => use(hasMixedStyle) ? t('Mixed style') : t('Default header style')
|
||||
}
|
||||
);
|
||||
}),
|
||||
)];
|
||||
@@ -97,12 +102,16 @@ export class CellStyle extends Disposable {
|
||||
});
|
||||
return colorSelect(
|
||||
{
|
||||
textColor: new ColorOption(
|
||||
{ color: textColor, defaultColor: this._defaultTextColor, noneText: 'default'}
|
||||
),
|
||||
fillColor: new ColorOption(
|
||||
{ color: fillColor, allowsNone: true, noneText: 'none'}
|
||||
),
|
||||
textColor: new ColorOption({
|
||||
color: textColor,
|
||||
defaultColor: this._defaultTextColor,
|
||||
noneText: 'default',
|
||||
}),
|
||||
fillColor: new ColorOption({
|
||||
color: fillColor,
|
||||
allowsNone: true,
|
||||
noneText: 'none',
|
||||
}),
|
||||
fontBold: fontBold,
|
||||
fontItalic: fontItalic,
|
||||
fontUnderline: fontUnderline,
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
position: relative;
|
||||
width: 3px;
|
||||
height: 12px;
|
||||
background-color: var(--grist-actual-cell-color, #606060);
|
||||
border: 1px solid var(--grist-actual-cell-color, #606060);
|
||||
background-color: var(--grist-actual-cell-color, var(--grist-theme-toggle-checkbox-fg, #606060));
|
||||
border: 1px solid var(--grist-actual-cell-color, var(--grist-theme-toggle-checkbox-fg, #606060));
|
||||
left: 3px;
|
||||
top: -5px;
|
||||
}
|
||||
@@ -52,7 +52,7 @@
|
||||
position: relative;
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
background-color: var(--grist-actual-cell-color, #606060);
|
||||
border: 1px solid var(--grist-actual-cell-color, #606060);
|
||||
background-color: var(--grist-actual-cell-color, var(--grist-theme-toggle-checkbox-fg, #606060));
|
||||
border: 1px solid var(--grist-actual-cell-color, var(--grist-theme-toggle-checkbox-fg, #606060));
|
||||
top: 7px;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ const {ACIndexImpl, buildHighlightedDom} = require('app/client/lib/ACIndex');
|
||||
const {ChoiceItem, cssChoiceList, cssMatchText, cssPlusButton,
|
||||
cssPlusIcon} = require('app/client/widgets/ChoiceListEditor');
|
||||
const {menuCssClass} = require('app/client/ui2018/menus');
|
||||
const {testId, colors} = require('app/client/ui2018/cssVars');
|
||||
const {testId, theme} = require('app/client/ui2018/cssVars');
|
||||
const {choiceToken, cssChoiceACItem} = require('app/client/widgets/ChoiceToken');
|
||||
const {dom, styled} = require('grainjs');
|
||||
const {icon} = require('../ui2018/icons');
|
||||
@@ -34,7 +34,13 @@ _.extend(ChoiceEditor.prototype, TextEditor.prototype);
|
||||
|
||||
ChoiceEditor.prototype.getCellValue = function() {
|
||||
const selectedItem = this.autocomplete && this.autocomplete.getSelectedItem();
|
||||
return selectedItem ? selectedItem.label : TextEditor.prototype.getCellValue.call(this);
|
||||
if (selectedItem) {
|
||||
return selectedItem.label;
|
||||
} else if (this.textInput.value.trim() === '') {
|
||||
return null;
|
||||
} else {
|
||||
return TextEditor.prototype.getCellValue.call(this);
|
||||
}
|
||||
}
|
||||
|
||||
ChoiceEditor.prototype.renderACItem = function(item, highlightFunc) {
|
||||
@@ -60,7 +66,7 @@ ChoiceEditor.prototype.attach = function(cellElem) {
|
||||
// Don't create autocomplete if readonly.
|
||||
if (this.options.readonly) { return; }
|
||||
|
||||
const acItems = this.choices.map(c => new ChoiceItem(c, false));
|
||||
const acItems = this.choices.map(c => new ChoiceItem(c, false, false));
|
||||
const acIndex = new ACIndexImpl(acItems);
|
||||
const acOptions = {
|
||||
popperOptions: {
|
||||
@@ -100,7 +106,7 @@ ChoiceEditor.prototype.maybeShowAddNew = function(result, text) {
|
||||
const trimmedText = text.trim();
|
||||
if (!this.enableAddNew || !trimmedText) { return result; }
|
||||
|
||||
const addNewItem = new ChoiceItem(trimmedText, false, true);
|
||||
const addNewItem = new ChoiceItem(trimmedText, false, false, true);
|
||||
if (result.items.find((item) => item.cleanText === addNewItem.cleanText)) {
|
||||
return result;
|
||||
}
|
||||
@@ -112,7 +118,7 @@ ChoiceEditor.prototype.maybeShowAddNew = function(result, text) {
|
||||
}
|
||||
|
||||
const cssChoiceEditIcon = styled(icon, `
|
||||
background-color: ${colors.slate};
|
||||
background-color: ${theme.lightText};
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
@@ -33,17 +33,19 @@ export class ChoiceListCell extends ChoiceTextBox {
|
||||
if (!val) { return null; }
|
||||
// Handle any unexpected values we might get (non-array, or array with non-strings).
|
||||
const tokens: unknown[] = Array.isArray(val) ? val : [val];
|
||||
return tokens.map(token =>
|
||||
choiceToken(
|
||||
String(token),
|
||||
return tokens.map(token => {
|
||||
const isBlank = String(token).trim() === '';
|
||||
return choiceToken(
|
||||
isBlank ? '[Blank]' : String(token),
|
||||
{
|
||||
...(choiceOptionsByName.get(String(token)) || {}),
|
||||
invalid: !choiceSet.has(String(token)),
|
||||
blank: String(token).trim() === '',
|
||||
},
|
||||
dom.cls(cssToken.className),
|
||||
testId('choice-list-cell-token')
|
||||
)
|
||||
);
|
||||
);
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export class ChoiceItem implements ACItem, IToken {
|
||||
constructor(
|
||||
public label: string,
|
||||
public isInvalid: boolean, // If set, this token is not one of the valid choices.
|
||||
public isBlank: boolean, // If set, this token is blank.
|
||||
public isNew?: boolean, // If set, this is a choice to be added to the config.
|
||||
) {}
|
||||
}
|
||||
@@ -50,7 +51,7 @@ export class ChoiceListEditor extends NewBaseEditor {
|
||||
const choices: string[] = options.field.widgetOptionsJson.peek().choices || [];
|
||||
this._choiceOptionsByName = options.field.widgetOptionsJson
|
||||
.peek().choiceOptions || {};
|
||||
const acItems = choices.map(c => new ChoiceItem(c, false));
|
||||
const acItems = choices.map(c => new ChoiceItem(c, false, false));
|
||||
const choiceSet = new Set(choices);
|
||||
|
||||
const acIndex = new ACIndexImpl<ChoiceItem>(acItems);
|
||||
@@ -67,21 +68,26 @@ export class ChoiceListEditor extends NewBaseEditor {
|
||||
// If starting to edit by typing in a string, ignore previous tokens.
|
||||
const cellValue = decodeObject(options.cellValue);
|
||||
const startLabels: unknown[] = options.editValue !== undefined || !Array.isArray(cellValue) ? [] : cellValue;
|
||||
const startTokens = startLabels.map(label => new ChoiceItem(String(label), !choiceSet.has(String(label))));
|
||||
const startTokens = startLabels.map(label => new ChoiceItem(
|
||||
String(label),
|
||||
!choiceSet.has(String(label)),
|
||||
String(label).trim() === ''
|
||||
));
|
||||
|
||||
this._tokenField = TokenField.ctor<ChoiceItem>().create(this, {
|
||||
initialValue: startTokens,
|
||||
renderToken: item => [
|
||||
item.label,
|
||||
item.isBlank ? '[Blank]' : item.label,
|
||||
dom.style('background-color', getRenderFillColor(this._choiceOptionsByName[item.label])),
|
||||
dom.style('color', getRenderTextColor(this._choiceOptionsByName[item.label])),
|
||||
dom.cls('font-bold', this._choiceOptionsByName[item.label]?.fontBold ?? false),
|
||||
dom.cls('font-underline', this._choiceOptionsByName[item.label]?.fontUnderline ?? false),
|
||||
dom.cls('font-italic', this._choiceOptionsByName[item.label]?.fontItalic ?? false),
|
||||
dom.cls('font-strikethrough', this._choiceOptionsByName[item.label]?.fontStrikethrough ?? false),
|
||||
cssChoiceToken.cls('-invalid', item.isInvalid)
|
||||
cssChoiceToken.cls('-invalid', item.isInvalid),
|
||||
cssChoiceToken.cls('-blank', item.isBlank),
|
||||
],
|
||||
createToken: label => new ChoiceItem(label, !choiceSet.has(label)),
|
||||
createToken: label => new ChoiceItem(label, !choiceSet.has(label), label.trim() === ''),
|
||||
acOptions,
|
||||
openAutocompleteOnFocus: true,
|
||||
readonly : options.readonly,
|
||||
@@ -222,7 +228,7 @@ export class ChoiceListEditor extends NewBaseEditor {
|
||||
const trimmedText = text.trim();
|
||||
if (!this._enableAddNew || !trimmedText) { return result; }
|
||||
|
||||
const addNewItem = new ChoiceItem(trimmedText, false, true);
|
||||
const addNewItem = new ChoiceItem(trimmedText, false, false, true);
|
||||
if (result.items.find((item) => item.cleanText === addNewItem.cleanText)) {
|
||||
return result;
|
||||
}
|
||||
@@ -277,7 +283,7 @@ export const cssToken = styled(tokenFieldStyles.cssToken, `
|
||||
white-space: pre;
|
||||
|
||||
&.selected {
|
||||
box-shadow: inset 0 0 0 1px ${colors.lightGreen};
|
||||
box-shadow: inset 0 0 0 1px ${theme.choiceTokenSelectedBorder};
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -341,7 +347,7 @@ export const cssChoiceList = styled('div', `
|
||||
|
||||
const cssReadonlyStyle = styled('div', `
|
||||
padding-left: 16px;
|
||||
background: white;
|
||||
background: ${theme.cellEditorBg};
|
||||
`);
|
||||
|
||||
export const cssMatchText = styled('span', `
|
||||
@@ -349,20 +355,21 @@ export const cssMatchText = styled('span', `
|
||||
`);
|
||||
|
||||
export const cssPlusButton = styled('div', `
|
||||
display: inline-block;
|
||||
display: flex;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 20px;
|
||||
margin-right: 8px;
|
||||
text-align: center;
|
||||
background-color: ${colors.lightGreen};
|
||||
color: ${colors.light};
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: ${theme.autocompleteAddNewCircleBg};
|
||||
color: ${theme.autocompleteAddNewCircleFg};
|
||||
|
||||
.selected > & {
|
||||
background-color: ${colors.darkGreen};
|
||||
background-color: ${theme.autocompleteAddNewCircleSelectedBg};
|
||||
}
|
||||
`);
|
||||
|
||||
export const cssPlusIcon = styled(icon, `
|
||||
background-color: ${colors.light};
|
||||
background-color: ${theme.autocompleteAddNewCircleFg};
|
||||
`);
|
||||
|
||||
@@ -2,7 +2,7 @@ import {IToken, TokenField} from 'app/client/lib/TokenField';
|
||||
import {cssBlockedCursor} from 'app/client/ui/RightPanelStyles';
|
||||
import {basicButton, primaryButton} from 'app/client/ui2018/buttons';
|
||||
import {colorButton, ColorOption} from 'app/client/ui2018/ColorSelect';
|
||||
import {colors, testId, theme} from 'app/client/ui2018/cssVars';
|
||||
import {testId, theme} from 'app/client/ui2018/cssVars';
|
||||
import {editableLabel} from 'app/client/ui2018/editableLabel';
|
||||
import {icon} from 'app/client/ui2018/icons';
|
||||
import {ChoiceOptionsByName, IChoiceOptions} from 'app/client/widgets/ChoiceTextBox';
|
||||
@@ -492,7 +492,7 @@ const cssListBoxInactive = styled(cssListBox, `
|
||||
border: 1px solid ${theme.choiceEntryBorderHover};
|
||||
}
|
||||
&-disabled {
|
||||
opacity: 0.6;
|
||||
opacity: 0.4;
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -501,8 +501,8 @@ const cssListRow = styled('div', `
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
padding: 4px 8px;
|
||||
color: ${colors.dark};
|
||||
background-color: ${colors.mediumGreyOpaque};
|
||||
color: ${theme.choiceTokenFg};
|
||||
background-color: ${theme.choiceTokenBg};
|
||||
border-radius: 3px;
|
||||
text-overflow: ellipsis;
|
||||
`);
|
||||
@@ -521,7 +521,7 @@ const cssToken = styled(cssListRow, `
|
||||
cursor: grab;
|
||||
|
||||
&.selected {
|
||||
background-color: ${colors.darkGrey};
|
||||
background-color: ${theme.choiceTokenSelectedBg};
|
||||
}
|
||||
&.token-dragging {
|
||||
pointer-events: none;
|
||||
@@ -619,8 +619,9 @@ const cssDeleteButton = styled('div', `
|
||||
`);
|
||||
|
||||
const cssDeleteIcon = styled(icon, `
|
||||
--icon-color: ${colors.slate};
|
||||
--icon-color: ${theme.text};
|
||||
opacity: 0.6;
|
||||
&:hover {
|
||||
--icon-color: ${colors.dark};
|
||||
opacity: 1.0;
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -4,10 +4,10 @@ import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
||||
import {KoSaveableObservable} from 'app/client/models/modelUtil';
|
||||
import {Style} from 'app/client/models/Styles';
|
||||
import {cssLabel, cssRow} from 'app/client/ui/RightPanelStyles';
|
||||
import {colors, testId} from 'app/client/ui2018/cssVars';
|
||||
import {testId, theme} from 'app/client/ui2018/cssVars';
|
||||
import {icon} from 'app/client/ui2018/icons';
|
||||
import {ChoiceListEntry} from 'app/client/widgets/ChoiceListEntry';
|
||||
import {choiceToken, DEFAULT_FILL_COLOR, DEFAULT_TEXT_COLOR} from 'app/client/widgets/ChoiceToken';
|
||||
import {choiceToken, DEFAULT_BACKGROUND_COLOR, DEFAULT_COLOR} from 'app/client/widgets/ChoiceToken';
|
||||
import {NTextBox} from 'app/client/widgets/NTextBox';
|
||||
import {Computed, dom, styled} from 'grainjs';
|
||||
|
||||
@@ -18,11 +18,11 @@ export type ChoiceOptionsByName = Map<string, IChoiceOptions | undefined>;
|
||||
const t = makeT('ChoiceTextBox');
|
||||
|
||||
export function getRenderFillColor(choiceOptions?: IChoiceOptions) {
|
||||
return choiceOptions?.fillColor ?? DEFAULT_FILL_COLOR;
|
||||
return choiceOptions?.fillColor ?? DEFAULT_BACKGROUND_COLOR;
|
||||
}
|
||||
|
||||
export function getRenderTextColor(choiceOptions?: IChoiceOptions) {
|
||||
return choiceOptions?.textColor ?? DEFAULT_TEXT_COLOR;
|
||||
return choiceOptions?.textColor ?? DEFAULT_COLOR;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,7 +157,7 @@ const cssChoiceText = styled('div', `
|
||||
`);
|
||||
|
||||
const cssChoiceEditIcon = styled(icon, `
|
||||
background-color: ${colors.slate};
|
||||
background-color: ${theme.lightText};
|
||||
display: block;
|
||||
height: inherit;
|
||||
`);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import {Style} from 'app/client/models/Styles';
|
||||
import {colors, theme, vars} from 'app/client/ui2018/cssVars';
|
||||
import {theme, vars} from 'app/client/ui2018/cssVars';
|
||||
import {dom, DomContents, DomElementArg, styled} from 'grainjs';
|
||||
|
||||
export const DEFAULT_FILL_COLOR = colors.mediumGreyOpaque.value!;
|
||||
export const DEFAULT_TEXT_COLOR = '#000000';
|
||||
export const DEFAULT_BACKGROUND_COLOR = theme.choiceTokenBg.toString();
|
||||
export const DEFAULT_COLOR = theme.choiceTokenFg.toString();
|
||||
|
||||
export interface IChoiceTokenOptions extends Style {
|
||||
invalid?: boolean;
|
||||
blank?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,16 +30,17 @@ export function choiceToken(
|
||||
...args: DomElementArg[]
|
||||
): DomContents {
|
||||
const {fillColor, textColor, fontBold, fontItalic, fontUnderline,
|
||||
fontStrikethrough, invalid} = options;
|
||||
fontStrikethrough, invalid, blank} = options;
|
||||
return cssChoiceToken(
|
||||
label,
|
||||
dom.style('background-color', fillColor ?? DEFAULT_FILL_COLOR),
|
||||
dom.style('color', textColor ?? DEFAULT_TEXT_COLOR),
|
||||
dom.style('background-color', fillColor ?? DEFAULT_BACKGROUND_COLOR),
|
||||
dom.style('color', textColor ?? DEFAULT_COLOR),
|
||||
dom.cls('font-bold', fontBold ?? false),
|
||||
dom.cls('font-underline', fontUnderline ?? false),
|
||||
dom.cls('font-italic', fontItalic ?? false),
|
||||
dom.cls('font-strikethrough', fontStrikethrough ?? false),
|
||||
invalid ? cssChoiceToken.cls('-invalid') : null,
|
||||
blank ? cssChoiceToken.cls('-blank') : null,
|
||||
...args
|
||||
);
|
||||
}
|
||||
@@ -52,8 +54,12 @@ export const cssChoiceToken = styled('div', `
|
||||
white-space: pre;
|
||||
|
||||
&-invalid {
|
||||
background-color: white !important;
|
||||
box-shadow: inset 0 0 0 1px ${colors.error};
|
||||
color: ${theme.choiceTokenInvalidFg} !important;
|
||||
background-color: ${theme.choiceTokenInvalidBg} !important;
|
||||
box-shadow: inset 0 0 0 1px ${theme.choiceTokenInvalidBorder};
|
||||
}
|
||||
&-blank {
|
||||
color: ${theme.lightText} !important;
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -70,7 +76,7 @@ export const cssChoiceACItem = styled('li', `
|
||||
cursor: pointer;
|
||||
|
||||
&.selected {
|
||||
background-color: ${theme.autocompleteChoiceSelectedBg};
|
||||
background-color: ${theme.autocompleteItemSelectedBg};
|
||||
}
|
||||
&-with-new {
|
||||
scroll-margin-bottom: ${ADD_NEW_HEIGHT};
|
||||
|
||||
@@ -33,6 +33,14 @@
|
||||
box-shadow: 0 2px 20px 0 var(--grist-theme-menu-shadow, rgba(38, 38, 51, 0.6));
|
||||
}
|
||||
|
||||
.datepicker-dropdown.datepicker-orient-top:after {
|
||||
border-top: 6px solid var(--grist-theme-menu-bg, #fff);
|
||||
}
|
||||
|
||||
.datepicker-dropdown.datepicker-orient-bottom:after {
|
||||
border-bottom: 6px solid var(--grist-theme-menu-bg, #fff);
|
||||
}
|
||||
|
||||
.datepicker .prev:hover,
|
||||
.datepicker .next:hover,
|
||||
.datepicker .datepicker-switch:hover,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {isDesktop} from 'app/client/lib/browserInfo';
|
||||
import {colors} from 'app/client/ui2018/cssVars';
|
||||
import {colors, theme} from 'app/client/ui2018/cssVars';
|
||||
import {icon} from 'app/client/ui2018/icons';
|
||||
import {IEditorCommandGroup} from 'app/client/widgets/NewBaseEditor';
|
||||
import {dom, styled} from 'grainjs';
|
||||
@@ -25,7 +25,7 @@ const cssFinishBtn = styled('div', `
|
||||
padding: 8px;
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
--icon-color: white;
|
||||
--icon-color: ${theme.controlPrimaryFg};
|
||||
`);
|
||||
|
||||
const cssCancelBtn = styled(cssFinishBtn, `
|
||||
@@ -34,7 +34,7 @@ const cssCancelBtn = styled(cssFinishBtn, `
|
||||
`);
|
||||
|
||||
const cssSaveBtn = styled(cssFinishBtn, `
|
||||
--icon-background-color: ${colors.lightGreen};
|
||||
--icon-background-color: ${theme.controlPrimaryBg};
|
||||
right: -40px;
|
||||
`);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {makeT} from 'app/client/lib/localization';
|
||||
import {ITooltipControl, showTooltip, tooltipCloseButton} from 'app/client/ui/tooltips';
|
||||
import {colors, testId} from 'app/client/ui2018/cssVars';
|
||||
import {testId, theme} from 'app/client/ui2018/cssVars';
|
||||
import {icon} from 'app/client/ui2018/icons';
|
||||
import {cssLink} from 'app/client/ui2018/links';
|
||||
import {dom, styled} from 'grainjs';
|
||||
@@ -29,7 +29,7 @@ export function showTooltipToCreateFormula(editorDom: HTMLElement, convert: () =
|
||||
const cssConvertTooltip = styled('div', `
|
||||
display: flex;
|
||||
align-items: center;
|
||||
--icon-color: ${colors.lightGreen};
|
||||
--icon-color: ${theme.controlFg};
|
||||
|
||||
& > .${cssLink.className} {
|
||||
margin-left: 8px;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
.transform_editor {
|
||||
width: 90%;
|
||||
margin: 5px auto;
|
||||
border: 1px solid #DDDDDD;
|
||||
min-height: 28px;
|
||||
margin: 8px 16px;
|
||||
padding: 5px 6px;
|
||||
background-color: var(--grist-theme-ace-editor-bg, white);
|
||||
border: 1px solid var(--grist-theme-input-border, #D9D9D9);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.transform_menu {
|
||||
padding: 5px 0;
|
||||
margin: 5px;
|
||||
border-top: 1px solid rgba(200, 200, 200, .3);
|
||||
border-bottom: 1px solid rgba(200, 200, 200, .3);
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.fieldbuilder_settings {
|
||||
|
||||
@@ -20,6 +20,7 @@ import { CombinedStyle, Style } from 'app/client/models/Styles';
|
||||
import { COMMENTS } from 'app/client/models/features';
|
||||
import { FieldSettingsMenu } from 'app/client/ui/FieldMenus';
|
||||
import { cssBlockedCursor, cssLabel, cssRow } from 'app/client/ui/RightPanelStyles';
|
||||
import { textButton } from 'app/client/ui2018/buttons';
|
||||
import { buttonSelect, cssButtonSelect } from 'app/client/ui2018/buttonSelect';
|
||||
import { theme } from 'app/client/ui2018/cssVars';
|
||||
import { IOptionFull, menu, select } from 'app/client/ui2018/menus';
|
||||
@@ -308,6 +309,7 @@ export class FieldBuilder extends Disposable {
|
||||
grainjsDom.cls('tour-type-selector'),
|
||||
grainjsDom.cls(cssBlockedCursor.className, use =>
|
||||
use(this.origColumn.disableModifyBase) ||
|
||||
use(this._isTransformingFormula) ||
|
||||
(use(this.field.config.multiselect) && !use(allFormulas))
|
||||
),
|
||||
),
|
||||
@@ -415,18 +417,18 @@ export class FieldBuilder extends Disposable {
|
||||
this.columnTransform.finalize().catch(reportError);
|
||||
}
|
||||
}),
|
||||
kf.row(
|
||||
15, kf.label(t('Apply Formula to Data')),
|
||||
3, kf.buttonGroup(
|
||||
kf.checkButton(transformButton,
|
||||
dom('span.glyphicon.glyphicon-flash'),
|
||||
dom.testId("FieldBuilder_editTransform"),
|
||||
testId('edit-transform'),
|
||||
kd.toggleClass('disabled', () => this._isTransformingType() || this.origColumn.isFormula() ||
|
||||
this.origColumn.disableModifyBase())
|
||||
)
|
||||
)
|
||||
),
|
||||
cssRow(
|
||||
textButton(t('Apply Formula to Data'),
|
||||
dom.on('click', () => transformButton(true)),
|
||||
kd.hide(this._isTransformingFormula),
|
||||
kd.boolAttr('disabled', () =>
|
||||
this._isTransformingType() ||
|
||||
this.origColumn.isFormula() ||
|
||||
this.origColumn.disableModifyBase() ||
|
||||
this.field.config.multiselect()),
|
||||
dom.testId("FieldBuilder_editTransform"),
|
||||
testId('edit-transform'),
|
||||
)),
|
||||
kd.maybe(this._isTransformingFormula, () => {
|
||||
return this.columnTransform!.buildDom();
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DataRowModel } from 'app/client/models/DataRowModel';
|
||||
import { ViewFieldRec } from 'app/client/models/entities/ViewFieldRec';
|
||||
import { constructUrl } from 'app/client/models/gristUrlState';
|
||||
import { colors, testId } from 'app/client/ui2018/cssVars';
|
||||
import { testId, theme } from 'app/client/ui2018/cssVars';
|
||||
import { cssIconBackground, icon } from 'app/client/ui2018/icons';
|
||||
import { cssHoverIn, gristLink } from 'app/client/ui2018/links';
|
||||
import { NTextBox } from 'app/client/widgets/NTextBox';
|
||||
@@ -15,7 +15,7 @@ import { Computed, dom, styled } from 'grainjs';
|
||||
*/
|
||||
export class HyperLinkTextBox extends NTextBox {
|
||||
constructor(field: ViewFieldRec) {
|
||||
super(field, {defaultTextColor: colors.lightGreen.value});
|
||||
super(field, {defaultTextColor: theme.link.toString()});
|
||||
}
|
||||
|
||||
public buildDom(row: DataRowModel) {
|
||||
@@ -49,7 +49,7 @@ function _formatValue(value: CellValue): string {
|
||||
}
|
||||
|
||||
const cssFieldClip = styled('div.field_clip', `
|
||||
color: var(--grist-actual-cell-color, ${colors.lightGreen});
|
||||
color: var(--grist-actual-cell-color, ${theme.link});
|
||||
`);
|
||||
|
||||
const cssHoverOnField = cssHoverIn(cssFieldClip.className);
|
||||
|
||||
@@ -7,6 +7,7 @@ import {GristDoc} from 'app/client/components/GristDoc';
|
||||
import {DocData} from 'app/client/models/DocData';
|
||||
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
||||
import {SaveableObjObservable} from 'app/client/models/modelUtil';
|
||||
import {theme} from 'app/client/ui2018/cssVars';
|
||||
import {CellStyle} from 'app/client/widgets/CellStyle';
|
||||
import {BaseFormatter} from 'app/common/ValueFormatter';
|
||||
import {
|
||||
@@ -19,7 +20,10 @@ import {
|
||||
} from 'grainjs';
|
||||
|
||||
export interface Options {
|
||||
// A hex value to set the default widget text color. Default to '#000000' if omitted.
|
||||
/**
|
||||
* CSS value of the default widget text color. Defaults to the current theme's
|
||||
* cell fg color.
|
||||
*/
|
||||
defaultTextColor?: string;
|
||||
}
|
||||
|
||||
@@ -44,13 +48,13 @@ export abstract class NewAbstractWidget extends Disposable {
|
||||
protected valueFormatter: Observable<BaseFormatter>;
|
||||
protected textColor: Observable<string>;
|
||||
protected fillColor: Observable<string>;
|
||||
protected readonly defaultTextColor: string;
|
||||
protected readonly defaultTextColor: string|undefined = this._opts.defaultTextColor
|
||||
?? theme.cellFg.toString();
|
||||
|
||||
constructor(protected field: ViewFieldRec, opts: Options = {}) {
|
||||
constructor(protected field: ViewFieldRec, private _opts: Options = {}) {
|
||||
super();
|
||||
this.options = field.widgetOptionsJson;
|
||||
this.valueFormatter = fromKo(field.formatter);
|
||||
this.defaultTextColor = opts?.defaultTextColor || '#000000';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -172,7 +172,7 @@ const cssDecimalsBox = styled('div', `
|
||||
margin-right: 16px;
|
||||
}
|
||||
&-disabled {
|
||||
background-color: ${theme.rightPanelToggleButtonDisabledBg};
|
||||
opacity: 0.4;
|
||||
pointer-events: none;
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -2,7 +2,7 @@ import {makeT} from 'app/client/lib/localization';
|
||||
import {DataRowModel} from 'app/client/models/DataRowModel';
|
||||
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
||||
import {cssLabel, cssRow} from 'app/client/ui/RightPanelStyles';
|
||||
import {colors, hideInPrintView, testId} from 'app/client/ui2018/cssVars';
|
||||
import {hideInPrintView, testId, theme} from 'app/client/ui2018/cssVars';
|
||||
import {icon} from 'app/client/ui2018/icons';
|
||||
import {IOptionFull, select} from 'app/client/ui2018/menus';
|
||||
import {NTextBox} from 'app/client/widgets/NTextBox';
|
||||
@@ -119,12 +119,12 @@ export class Reference extends NTextBox {
|
||||
|
||||
const cssRefIcon = styled(icon, `
|
||||
float: left;
|
||||
background-color: ${colors.slate};
|
||||
--icon-color: ${theme.lightText};
|
||||
margin: -1px 2px 2px 0;
|
||||
`);
|
||||
|
||||
const cssRef = styled('div.field_clip', `
|
||||
&-blank {
|
||||
color: ${colors.slate}
|
||||
color: ${theme.lightText}
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ACResults, buildHighlightedDom, HighlightFunc, normalizeText } from 'ap
|
||||
import { Autocomplete } from 'app/client/lib/autocomplete';
|
||||
import { ICellItem } from 'app/client/models/ColumnACIndexes';
|
||||
import { reportError } from 'app/client/models/errors';
|
||||
import { colors, testId, theme, vars } from 'app/client/ui2018/cssVars';
|
||||
import { testId, theme, vars } from 'app/client/ui2018/cssVars';
|
||||
import { icon } from 'app/client/ui2018/icons';
|
||||
import { menuCssClass } from 'app/client/ui2018/menus';
|
||||
import { FieldOptions } from 'app/client/widgets/NewBaseEditor';
|
||||
@@ -181,6 +181,8 @@ const cssRefItem = styled('li', `
|
||||
scroll-margin-bottom: ${addNewHeight};
|
||||
}
|
||||
&-new {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: ${theme.lightText};
|
||||
position: sticky;
|
||||
bottom: 0px;
|
||||
@@ -195,26 +197,27 @@ const cssRefItem = styled('li', `
|
||||
`);
|
||||
|
||||
export const cssPlusButton = styled('div', `
|
||||
display: inline-block;
|
||||
display: flex;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 20px;
|
||||
margin-right: 8px;
|
||||
text-align: center;
|
||||
background-color: ${colors.lightGreen};
|
||||
color: ${colors.light};
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: ${theme.autocompleteAddNewCircleBg};
|
||||
color: ${theme.autocompleteAddNewCircleFg};
|
||||
|
||||
.selected > & {
|
||||
background-color: ${colors.darkGreen};
|
||||
background-color: ${theme.autocompleteAddNewCircleSelectedBg};
|
||||
}
|
||||
`);
|
||||
|
||||
export const cssPlusIcon = styled(icon, `
|
||||
background-color: ${colors.light};
|
||||
background-color: ${theme.autocompleteAddNewCircleFg};
|
||||
`);
|
||||
|
||||
const cssRefEditIcon = styled(icon, `
|
||||
background-color: ${colors.slate};
|
||||
background-color: ${theme.lightText};
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {DataRowModel} from 'app/client/models/DataRowModel';
|
||||
import {colors, testId} from 'app/client/ui2018/cssVars';
|
||||
import {testId} from 'app/client/ui2018/cssVars';
|
||||
import {isList} from 'app/common/gristTypes';
|
||||
import {dom} from 'grainjs';
|
||||
import {cssChoiceList, cssToken} from "app/client/widgets/ChoiceListCell";
|
||||
@@ -51,7 +51,7 @@ export class ReferenceList extends Reference {
|
||||
return choiceToken(
|
||||
isBlankReference ? '[Blank]' : token,
|
||||
{
|
||||
textColor: isBlankReference ? colors.slate.value : undefined
|
||||
blank: isBlankReference,
|
||||
},
|
||||
dom.cls(cssToken.className),
|
||||
testId('ref-list-cell-token')
|
||||
|
||||
@@ -298,7 +298,6 @@ const cssTokenField = styled(tokenFieldStyles.cssTokenField, `
|
||||
padding: 0 3px;
|
||||
height: min-content;
|
||||
min-height: 22px;
|
||||
color: black;
|
||||
flex-wrap: wrap;
|
||||
`);
|
||||
|
||||
@@ -307,13 +306,14 @@ const cssToken = styled(tokenFieldStyles.cssToken, `
|
||||
margin: 2px;
|
||||
line-height: 16px;
|
||||
white-space: pre;
|
||||
color: ${theme.choiceTokenFg};
|
||||
|
||||
&.selected {
|
||||
box-shadow: inset 0 0 0 1px ${colors.lightGreen};
|
||||
box-shadow: inset 0 0 0 1px ${theme.choiceTokenSelectedBorder};
|
||||
}
|
||||
|
||||
&-blank {
|
||||
color: ${colors.slate};
|
||||
color: ${theme.lightText};
|
||||
}
|
||||
`);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
background-color: var(--grist-theme-switch-slider-fg, #ccc);
|
||||
border-radius: 17px;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
width: 13px;
|
||||
left: 2px;
|
||||
bottom: 2px;
|
||||
background-color: white;
|
||||
background-color: var(--grist-theme-switch-circle-fg, white);
|
||||
border-radius: 17px;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,10 @@
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.celleditor_text_editor::placeholder {
|
||||
color: var(--grist-theme-cell-editor-placeholder-fg, unset);
|
||||
}
|
||||
|
||||
.celleditor_content_measure {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
||||
@@ -3,6 +3,7 @@ import { DataRowModel } from 'app/client/models/DataRowModel';
|
||||
import { ViewFieldRec } from 'app/client/models/entities/ViewFieldRec';
|
||||
import { KoSaveableObservable } from 'app/client/models/modelUtil';
|
||||
import { NewAbstractWidget, Options } from 'app/client/widgets/NewAbstractWidget';
|
||||
import { theme } from 'app/client/ui2018/cssVars';
|
||||
import { dom } from 'grainjs';
|
||||
|
||||
/**
|
||||
@@ -28,7 +29,7 @@ abstract class ToggleBase extends NewAbstractWidget {
|
||||
|
||||
export class ToggleCheckBox extends ToggleBase {
|
||||
constructor(field: ViewFieldRec, _options: Options = {}) {
|
||||
super(field, {defaultTextColor: '#606060'});
|
||||
super(field, {defaultTextColor: theme.toggleCheckboxFg.toString()});
|
||||
}
|
||||
|
||||
public buildDom(row: DataRowModel) {
|
||||
|
||||
Reference in New Issue
Block a user