(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:
George Gevoian
2023-09-21 12:57:58 -04:00
parent d1826987bb
commit 273b976cab
87 changed files with 979 additions and 651 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
`);

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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')
)
);
);
});
}),
);
}

View File

@@ -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};
`);

View File

@@ -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;
}
`);

View File

@@ -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;
`);

View File

@@ -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};

View File

@@ -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,

View File

@@ -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;
`);

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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();
})

View File

@@ -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);

View File

@@ -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';
}
/**

View File

@@ -172,7 +172,7 @@ const cssDecimalsBox = styled('div', `
margin-right: 16px;
}
&-disabled {
background-color: ${theme.rightPanelToggleButtonDisabledBg};
opacity: 0.4;
pointer-events: none;
}
`);

View File

@@ -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}
}
`);

View File

@@ -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;

View File

@@ -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')

View File

@@ -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};
}
`);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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) {