(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
pull/684/head
George Gevoian 8 months ago
parent d1826987bb
commit 273b976cab

@ -16,7 +16,7 @@ const cssMemoInput = styled('input', `
border-radius: 3px; border-radius: 3px;
border: 1px solid transparent; border: 1px solid transparent;
cursor: pointer; cursor: pointer;
color: ${theme.accentText}; color: ${theme.controlFg};
background-color: ${theme.inputBg}; background-color: ${theme.inputBg};
caret-color : ${theme.inputFg}; caret-color : ${theme.inputFg};
font: 12px 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace; font: 12px 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
@ -29,7 +29,7 @@ const cssMemoInput = styled('input', `
&:not(&-disabled):focus-within { &:not(&-disabled):focus-within {
outline: none !important; outline: none !important;
cursor: text; cursor: text;
box-shadow: inset 0 0 0 1px ${theme.accentBorder}; box-shadow: inset 0 0 0 1px ${theme.controlFg};
border-color: ${theme.accentBorder}; border-color: ${theme.controlFg};
} }
`); `);

@ -1,4 +1,4 @@
import {colors} from 'app/client/ui2018/cssVars'; import {theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons'; import {icon} from 'app/client/ui2018/icons';
import {IOption, select} from 'app/client/ui2018/menus'; import {IOption, select} from 'app/client/ui2018/menus';
import {MaybeObsArray, Observable, styled} from 'grainjs'; import {MaybeObsArray, Observable, styled} from 'grainjs';
@ -19,7 +19,7 @@ export const cssSelect = styled(select, `
cursor: pointer; cursor: pointer;
&:hover, &:focus, &.weasel-popup-open, &-active { &:hover, &:focus, &.weasel-popup-open, &-active {
border: 1px solid ${colors.darkGrey}; border: 1px solid ${theme.selectButtonBorder};
box-shadow: none; box-shadow: none;
} }
`); `);

@ -2,7 +2,7 @@
* Implements a widget showing 3-state boxes for permissions * Implements a widget showing 3-state boxes for permissions
* (for Allow / Deny / Pass-Through). * (for Allow / Deny / Pass-Through).
*/ */
import {colors, testId} from 'app/client/ui2018/cssVars'; import {colors, testId, theme} from 'app/client/ui2018/cssVars';
import {cssIconButton, icon} from 'app/client/ui2018/icons'; import {cssIconButton, icon} from 'app/client/ui2018/icons';
import {menu, menuIcon, menuItem} from 'app/client/ui2018/menus'; import {menu, menuIcon, menuItem} from 'app/client/ui2018/menus';
import {PartialPermissionSet, PartialPermissionValue} from 'app/common/ACLPermissions'; import {PartialPermissionSet, PartialPermissionValue} from 'app/common/ACLPermissions';
@ -155,8 +155,8 @@ const cssBit = styled('div', `
border-radius: 2px; border-radius: 2px;
font-size: 13px; font-size: 13px;
font-weight: 500; font-weight: 500;
border: 1px dashed ${colors.darkGrey}; border: 1px dashed ${theme.accessRulesTableBodyLightFg};
color: ${colors.darkGrey}; color: ${theme.accessRulesTableBodyLightFg};
cursor: pointer; cursor: pointer;
display: flex; display: flex;

@ -2,6 +2,16 @@
background-color: var(--grist-theme-ace-editor-bg, white); background-color: var(--grist-theme-ace-editor-bg, white);
} }
.ace_editor .ace_placeholder {
font-family: Monaco, Menlo, "Ubuntu Mono", Consolas, "Source Code Pro", source-code-pro, monospace;
font-size: 11px;
color: var(--grist-theme-text-light, #929299);
font-style: italic;
white-space: nowrap;
opacity: 1.0;
transform: none;
}
.ace_grist_link_hidden { .ace_grist_link_hidden {
display: none; display: none;
} }

@ -31,7 +31,7 @@
} }
.action_desc { .action_desc {
color: var(--grist-theme-document-history-activity-text-light, unset); color: var(--grist-theme-document-history-activity-text, unset);
} }
.action_log_item.undone > .action_info, .action_log_item.undone > .action_info,
@ -68,37 +68,38 @@
text-align: center; text-align: center;
margin-top: 0; margin-top: 0;
padding-top: 0; padding-top: 0;
color: var(--grist-theme-document-history-activity-text, #000); color: var(--grist-theme-document-history-activity-text-light, #333);
} }
.action_log_table td { .action_log_table td {
border-left: 1px solid #888; border: 1px solid var(--grist-theme-document-history-table-border, lightgray);
border-right: 1px solid #888;
border-bottom: 1px solid #888;
border-top: 1px solid #888;
cursor: pointer; cursor: pointer;
} }
.action_log_table th { .action_log_table th {
border-top: 1px solid #ccc; border-top: 1px solid var(--grist-theme-document-history-table-border-light, #D9D9D9);
border-left: 1px solid #ccc; border-left: 1px solid var(--grist-theme-document-history-table-border-light, #D9D9D9);
border-right: 1px solid #ccc; border-right: 1px solid var(--grist-theme-document-history-table-border-light, #D9D9D9);
color: #888; color: var(--grist-theme-document-history-table-header-fg, #000);
} }
.action_log_table th:first-child { .action_log_table th:first-child {
border: none; border: none;
border-bottom: 1px solid #ccc; border-bottom: 1px solid var(--grist-theme-document-history-table-border-light, #D9D9D9);
} }
.action_log_table td:first-child { .action_log_table td:first-child {
border: none; border: none;
border-left: 1px solid #ccc; border-left: 1px solid var(--grist-theme-document-history-table-border-light, #D9D9D9);
border-bottom: 1px solid #ccc; border-bottom: 1px solid var(--grist-theme-document-history-table-border-light, #D9D9D9);
color: #888; color: var(--grist-theme-document-history-table-header-fg, #000);
cursor: inherit; cursor: inherit;
} }
.action_log_table td:not(:first-child) {
background-color: var(--grist-theme-table-body-bg);
}
.action_log_table td, .action_log_table th { .action_log_table td, .action_log_table th {
padding-left: 3px; padding-left: 3px;
padding-right: 3px; padding-right: 3px;
@ -127,3 +128,7 @@
.action_comment { .action_comment {
display: none; display: none;
} }
.action_info {
color: var(--grist-theme-document-history-activity-text-light, #929299);
}

@ -10,15 +10,15 @@ import * as ko from 'knockout';
import koArray from 'app/client/lib/koArray'; import koArray from 'app/client/lib/koArray';
import {KoArray} from 'app/client/lib/koArray'; import {KoArray} from 'app/client/lib/koArray';
import * as koDom from 'app/client/lib/koDom'; import * as koDom from 'app/client/lib/koDom';
import * as koForm from 'app/client/lib/koForm';
import {GristDoc} from 'app/client/components/GristDoc'; import {GristDoc} from 'app/client/components/GristDoc';
import {ActionGroup} from 'app/common/ActionGroup'; import {ActionGroup} from 'app/common/ActionGroup';
import {ActionSummary, asTabularDiffs, defunctTableName, getAffectedTables, import {ActionSummary, asTabularDiffs, defunctTableName, getAffectedTables,
LabelDelta} from 'app/common/ActionSummary'; LabelDelta} from 'app/common/ActionSummary';
import {CellDelta, TabularDiff} from 'app/common/TabularDiff'; import {CellDelta, TabularDiff} from 'app/common/TabularDiff';
import {DomContents, IDomComponent} from 'grainjs'; import {DomContents, fromKo, IDomComponent} from 'grainjs';
import {makeT} from 'app/client/lib/localization'; import {makeT} from 'app/client/lib/localization';
import {labeledSquareCheckbox} from 'app/client/ui2018/checkbox';
/** /**
* *
@ -230,10 +230,12 @@ export class ActionLog extends dispose.Disposable implements IDomComponent {
this._loadActionSummaries().catch(() => gristNotify(t("Action Log failed to load"))); this._loadActionSummaries().catch(() => gristNotify(t("Action Log failed to load")));
return dom('div.action_log', return dom('div.action_log',
{tabIndex: '-1'}, {tabIndex: '-1'},
dom('div.preference_item', dom('div',
koForm.checkbox(this._showAllTables, labeledSquareCheckbox(fromKo(this._showAllTables),
dom.testId('ActionLog_allTables'), t('All tables'),
dom('span.preference_desc', 'All tables'))), dom.testId('ActionLog_allTables'),
),
),
dom('div.action_log_load', dom('div.action_log_load',
koDom.show(() => this._loading()), koDom.show(() => this._loading()),
'Loading...'), 'Loading...'),

@ -97,6 +97,8 @@ export class ColumnTransform extends Disposable {
})); }));
} }
return this.editor.buildDom((aceObj: any) => { return this.editor.buildDom((aceObj: any) => {
aceObj.setOptions({placeholder: 'Enter formula.'});
aceObj.setHighlightActiveLine(false);
this.editor.adjustContentToWidth(); this.editor.adjustContentToWidth();
this.editor.attachSaveCommand(); this.editor.attachSaveCommand();
aceObj.on('change', () => { aceObj.on('change', () => {

@ -97,8 +97,25 @@
margin-right: 2px; margin-right: 2px;
} }
.detail-buttons {
display: flex;
align-items: center;
gap: 4px;
}
.detail-left, .detail-right, .detail-add-btn {
--icon-color: var(--grist-theme-control-secondary-fg, #929299);
padding: 3px;
border-radius: 4px;
}
.detail-left.disabled, .detail-right.disabled, .detail-add-btn.disabled { .detail-left.disabled, .detail-right.disabled, .detail-add-btn.disabled {
cursor: default !important; --icon-color: var(--grist-theme-control-secondary-disabled-fg, #D9D9D9);
}
.detail-button:not(.disabled):hover {
cursor: pointer;
background-color: var(--grist-theme-hover, rgba(217,217,217,0.6));
} }
.detail-add-grp { .detail-add-grp {

@ -6,6 +6,7 @@ const kd = require('app/client/lib/koDom');
const koDomScrolly = require('app/client/lib/koDomScrolly'); const koDomScrolly = require('app/client/lib/koDomScrolly');
const {renderAllRows} = require('app/client/components/Printing'); const {renderAllRows} = require('app/client/components/Printing');
const {isNarrowScreen} = require('app/client/ui2018/cssVars'); const {isNarrowScreen} = require('app/client/ui2018/cssVars');
const {icon} = require('app/client/ui2018/icons');
require('app/client/lib/koUtil'); // Needed for subscribeInit. require('app/client/lib/koUtil'); // Needed for subscribeInit.
@ -381,28 +382,29 @@ DetailView.prototype.buildTitleControls = function() {
kd.text(() => this._isAddRow() ? 'Add record' : kd.text(() => this._isAddRow() ? 'Add record' :
`${this.cursor.rowIndex() + 1} of ${this.getLastDataRowIndex() + 1}`) `${this.cursor.rowIndex() + 1} of ${this.getLastDataRowIndex() + 1}`)
), ),
dom('div.btn-group.btn-group-xs', dom('div.detail-buttons',
dom('div.btn.btn-default.detail-left', dom('div.detail-button.detail-left',
dom('span.glyphicon.glyphicon-chevron-left'), icon('ArrowLeft'),
dom.on('click', () => { this.cursor.rowIndex(this.cursor.rowIndex() - 1); }), dom.on('click', () => { this.cursor.rowIndex(this.cursor.rowIndex() - 1); }),
kd.toggleClass('disabled', () => this.cursor.rowIndex() === 0) kd.toggleClass('disabled', () => this.cursor.rowIndex() === 0),
dom.testId('detailView_detail_left'),
), ),
dom('div.btn.btn-default.detail-right', dom('div.detail-button.detail-right',
dom('span.glyphicon.glyphicon-chevron-right'), icon('ArrowRight'),
dom.on('click', () => { this.cursor.rowIndex(this.cursor.rowIndex() + 1); }), dom.on('click', () => { this.cursor.rowIndex(this.cursor.rowIndex() + 1); }),
kd.toggleClass('disabled', () => this.cursor.rowIndex() >= this.viewData.all().length - 1) kd.toggleClass('disabled', () => this.cursor.rowIndex() >= this.viewData.all().length - 1),
) dom.testId('detailView_detail_right'),
), ),
dom('div.btn-group.btn-group-xs.detail-add-grp', dom('div.detail-button.detail-add-btn',
dom('div.btn.btn-default.detail-add-btn', icon('Plus'),
dom('span.glyphicon.glyphicon-plus'),
dom.on('click', () => { dom.on('click', () => {
let addRowIndex = this.viewData.getRowIndex('new'); let addRowIndex = this.viewData.getRowIndex('new');
this.cursor.rowIndex(addRowIndex); this.cursor.rowIndex(addRowIndex);
}), }),
kd.toggleClass('disabled', () => this.viewData.getRowId(this.cursor.rowIndex()) === 'new') kd.toggleClass('disabled', () => this.viewData.getRowId(this.cursor.rowIndex()) === 'new'),
) dom.testId('detailView_detail_add'),
) ),
),
)) ))
); );
}; };

@ -71,7 +71,7 @@
width: 4rem; /* Also should match width for .gridview_header_corner, and the overlay elements */ width: 4rem; /* Also should match width for .gridview_header_corner, and the overlay elements */
flex: none; flex: none;
border-bottom: 1px solid var(--grist-theme-table-header-border-dark, var(--grist-color-dark-grey)); border-bottom: 1px solid var(--grist-theme-table-header-border, lightgray);
color: var(--grist-theme-table-header-fg, unset); color: var(--grist-theme-table-header-fg, unset);
background-color: var(--grist-theme-table-header-bg, var(--grist-color-light-grey)); background-color: var(--grist-theme-table-header-bg, var(--grist-color-light-grey));
z-index: 20; /* goes over data cells */ z-index: 20; /* goes over data cells */
@ -102,7 +102,7 @@
* do not want !important, as it interferes with row selection. * do not want !important, as it interferes with row selection.
*/ */
.gridview_data_row_num { .gridview_data_row_num {
background-color: var(--grist-theme-table-header-bg , var(--grist-color-light-grey)) !important; background-color: var(--grist-color-light-grey) !important;
} }
.gridview_header_backdrop_top { .gridview_header_backdrop_top {
display: none; display: none;
@ -111,7 +111,7 @@
display: none; display: none;
} }
.gridview_data_header { .gridview_data_header {
background-color: var(--grist-theme-table-header-bg, var(--grist-color-light-grey)) !important; background-color: var(--grist-color-light-grey) !important;
} }
.print-widget .gridview_header_backdrop_left, .print-widget .gridview_data_corner_overlay { .print-widget .gridview_header_backdrop_left, .print-widget .gridview_data_corner_overlay {
display: none; display: none;
@ -127,15 +127,15 @@
display: table-header-group; display: table-header-group;
break-inside: avoid; break-inside: avoid;
position: static; position: static;
border-top: 1px solid var(--grist-theme-table-header-border-dark, var(--grist-color-dark-grey)); border-top: 1px solid var(--grist-color-dark-grey);
border-left: 1px solid var(--grist-theme-table-header-border-dark, var(--grist-color-dark-grey)); border-left: 1px solid var(--grist-color-dark-grey);
} }
.print-widget .gridview_data_header { .print-widget .gridview_data_header {
padding-left: 4rem !important; padding-left: 4rem !important;
} }
.print-widget .gridview_data_pane .print-all-rows { .print-widget .gridview_data_pane .print-all-rows {
display: table-row-group; display: table-row-group;
border-left: 1px solid var(--grist-theme-table-body-border, var(--grist-color-dark-grey)); border-left: 1px solid var(--grist-color-dark-grey);
} }
.print-widget .gridview_data_pane .print-row { .print-widget .gridview_data_pane .print-row {
display: table-row; display: table-row;

@ -1,44 +0,0 @@
.preference_mask {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 10;
background-color: rgba(1, 1, 1, 0.3);
}
.preference_window {
position: absolute;
background-color: white;
display: inline-block;
padding: 10px 20px;
width: 60%;
margin: 20%;
box-shadow: 0px 1px 3px 0px rgba(0,0,0,0.8);
}
.preference_title {
color: #546e7a;
text-align: left;
border-bottom: 1px solid rgba(0,0,0,.12);
font-family: 'Roboto', Helvetica, Arial, sans-serif;
width: 100%;
height: 40px;
}
.preference_content {
width: 100%;
font-size: 1.4rem;
}
.preference_desc {
color: var(--grist-theme-document-history-activity-text, unset);
margin-left: 5px;
cursor: pointer;
font-weight: normal;
}
.preference_footer > .kf_elem {
flex: 1 1 100%;
}

@ -152,7 +152,7 @@ const cssSectionWrapper = styled('div', `
border-bottom-right-radius: 0px; border-bottom-right-radius: 0px;
& .viewsection_content { & .viewsection_content {
margin: 0px; margin: 0px;
margin-top: 12px; margin-top: 8px;
} }
& .viewsection_title { & .viewsection_title {
padding: 0px 12px; padding: 0px 12px;

@ -4,14 +4,13 @@ import * as tableUtil from 'app/client/lib/tableUtil';
import {ColumnRec, DocModel, ViewFieldRec} from 'app/client/models/DocModel'; import {ColumnRec, DocModel, ViewFieldRec} from 'app/client/models/DocModel';
import {KoSaveableObservable} from 'app/client/models/modelUtil'; import {KoSaveableObservable} from 'app/client/models/modelUtil';
import {cssFieldEntry, cssFieldLabel} from 'app/client/ui/VisibleFieldsConfig'; import {cssFieldEntry, cssFieldLabel} from 'app/client/ui/VisibleFieldsConfig';
import {colors, testId} from 'app/client/ui2018/cssVars'; import {testId, theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons'; import {icon} from 'app/client/ui2018/icons';
import {menuText} from 'app/client/ui2018/menus'; import {menu, menuItem, menuText} from 'app/client/ui2018/menus';
import {FieldBuilder} from 'app/client/widgets/FieldBuilder'; import {FieldBuilder} from 'app/client/widgets/FieldBuilder';
import * as gutil from 'app/common/gutil'; import * as gutil from 'app/common/gutil';
import {Disposable, dom, fromKo, styled} from 'grainjs'; import {Disposable, dom, fromKo, styled} from 'grainjs';
import ko from 'knockout'; import ko from 'knockout';
import {menu, menuItem} from 'popweasel';
import {makeT} from 'app/client/lib/localization'; import {makeT} from 'app/client/lib/localization';
const t = makeT('RefSelect'); const t = makeT('RefSelect');
@ -89,7 +88,7 @@ export class RefSelect extends Disposable {
testId('ref-select'), testId('ref-select'),
dom.forEach(fromKo(this._added.getObservable()), (col) => dom.forEach(fromKo(this._added.getObservable()), (col) =>
cssFieldEntry( cssFieldEntry(
cssFieldLabel(dom.text(col.label)), cssColumnLabel(dom.text(col.label)),
cssRemoveIcon('Remove', cssRemoveIcon('Remove',
dom.on('click', () => this._removeFormulaField(col)), dom.on('click', () => this._removeFormulaField(col)),
testId('ref-select-remove'), testId('ref-select-remove'),
@ -233,15 +232,15 @@ const cssEmptyMenuText = styled(menuText, `
const cssAddLink = styled('div', ` const cssAddLink = styled('div', `
display: flex; display: flex;
cursor: pointer; cursor: pointer;
color: ${colors.lightGreen}; color: ${theme.controlFg};
--icon-color: ${colors.lightGreen}; --icon-color: ${theme.controlFg};
&:not(:first-child) { &:not(:first-child) {
margin-top: 8px; margin-top: 8px;
} }
&:hover, &:focus, &:active { &:hover, &:focus, &:active {
color: ${colors.darkGreen}; color: ${theme.controlHoverFg};
--icon-color: ${colors.darkGreen}; --icon-color: ${theme.controlHoverFg};
} }
`); `);
@ -258,3 +257,7 @@ const cssRemoveIcon = styled(icon, `
display: block; display: block;
} }
`); `);
const cssColumnLabel = styled(cssFieldLabel, `
line-height: 16px;
`);

@ -6,7 +6,7 @@ import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
import {UserError} from 'app/client/models/errors'; import {UserError} from 'app/client/models/errors';
import {ALL, RowsChanged, SortedRowSet} from "app/client/models/rowset"; import {ALL, RowsChanged, SortedRowSet} from "app/client/models/rowset";
import {showTransientTooltip} from 'app/client/ui/tooltips'; import {showTransientTooltip} from 'app/client/ui/tooltips';
import {colors, isNarrowScreen, isNarrowScreenObs, theme, vars} from 'app/client/ui2018/cssVars'; import {isNarrowScreen, isNarrowScreenObs, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons'; import {icon} from 'app/client/ui2018/icons';
import {CellValue} from 'app/common/DocActions'; import {CellValue} from 'app/common/DocActions';
import {isEmptyList, isListType, isRefListType} from "app/common/gristTypes"; import {isEmptyList, isListType, isRefListType} from "app/common/gristTypes";
@ -314,7 +314,7 @@ const cssSummaryPart = styled('div', `
left: 0; left: 0;
bottom: 0; bottom: 0;
right: 0; right: 0;
background-color: ${colors.mediumGrey}; background-color: ${theme.tableCellSummaryBg};
opacity: 0.8; opacity: 0.8;
z-index: -1; z-index: -1;
} }

@ -160,9 +160,10 @@ export async function prepTransformColInfo(docModel: DocModel, origCol: ColumnRe
// trouble than desired behavior. For many choices, recommend using a Ref to helper table. // trouble than desired behavior. For many choices, recommend using a Ref to helper table.
const columnData = tableData.getDistinctValues(sourceCol.colId(), 100); const columnData = tableData.getDistinctValues(sourceCol.colId(), 100);
if (columnData) { if (columnData) {
columnData.delete(""); const choices = Array.from(columnData, String).filter((choice) => {
columnData.delete(null); return choice !== null && choice.trim() !== '';
widgetOptions = {...widgetOptions, choices: Array.from(columnData, String)}; });
widgetOptions = {...widgetOptions, choices};
} }
} }
break; break;
@ -178,11 +179,12 @@ export async function prepTransformColInfo(docModel: DocModel, origCol: ColumnRe
value = String(decodeObject(value)).trim(); value = String(decodeObject(value)).trim();
const tags: unknown[] = (value.startsWith('[') && gutil.safeJsonParse(value, null)) || csvDecodeRow(value); const tags: unknown[] = (value.startsWith('[') && gutil.safeJsonParse(value, null)) || csvDecodeRow(value);
for (const tag of tags) { for (const tag of tags) {
choices.add(String(tag).trim()); const choice = String(tag).trim();
if (choice === '') { continue; }
choices.add(choice);
if (choices.size > 100) { break; } // Don't suggest excessively many choices. if (choices.size > 100) { break; } // Don't suggest excessively many choices.
} }
} }
choices.delete("");
widgetOptions = {...widgetOptions, choices: Array.from(choices)}; widgetOptions = {...widgetOptions, choices: Array.from(choices)};
} }
break; break;

@ -131,13 +131,12 @@ ViewConfigTab.prototype._buildAdvancedSettingsDom = function() {
kd.style('margin-top', '1.5rem') kd.style('margin-top', '1.5rem')
), ),
kf.row(kd.hide(isCollapsed), kf.row(kd.hide(isCollapsed),
kf.label('Table ', dom('b', kd.text(table.tableId)), ':') dom('div', primaryButton(
),
kf.row(kd.hide(isCollapsed),
kf.buttonGroup(kf.button(() => this._makeOnDemand(table),
kd.text(() => table.onDemand() ? t("Unmark On-Demand") : t("Make On-Demand")), kd.text(() => table.onDemand() ? t("Unmark On-Demand") : t("Make On-Demand")),
dom.testId('ViewConfig_onDemandBtn') kd.style('margin-top', '1rem'),
)) dom.on('click', () => this._makeOnDemand(table)),
dom.testId('ViewConfig_onDemandBtn'),
)),
), ),
]; ];
}); });

@ -9,14 +9,15 @@
align-items: center; align-items: center;
gap: 8px; gap: 8px;
align-self: flex-start; align-self: flex-start;
margin-top: -1px;
} }
.viewsection_title { .viewsection_title {
align-items: center;
flex-shrink: 0; flex-shrink: 0;
cursor: default; cursor: default;
height: 24px; min-height: 24px;
margin-left: -16px; /* to include drag handle that shows up on hover */ margin-left: -16px; /* to include drag handle that shows up on hover */
margin-bottom: 4px;
white-space: nowrap; white-space: nowrap;
} }

@ -456,7 +456,7 @@ const cssLayoutWrapper = styled('div', `
} }
&-active .viewsection_content { &-active .viewsection_content {
margin: 0px; margin: 0px;
margin-top: 12px; margin-top: 8px;
} }
&-active .viewsection_title { &-active .viewsection_title {
padding: 0px 12px; padding: 0px 12px;

@ -7,7 +7,7 @@ import {cssIcon} from 'app/client/ui/RightPanelStyles';
import {makeCollapsedLayoutMenu} from 'app/client/ui/ViewLayoutMenu'; import {makeCollapsedLayoutMenu} from 'app/client/ui/ViewLayoutMenu';
import {cssDotsIconWrapper, cssMenu, viewSectionMenu} from 'app/client/ui/ViewSectionMenu'; import {cssDotsIconWrapper, cssMenu, viewSectionMenu} from 'app/client/ui/ViewSectionMenu';
import {buildWidgetTitle} from 'app/client/ui/WidgetTitle'; import {buildWidgetTitle} from 'app/client/ui/WidgetTitle';
import {colors, isNarrowScreenObs, mediaSmall, testId, theme} from 'app/client/ui2018/cssVars'; import {isNarrowScreenObs, mediaSmall, testId, theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons'; import {icon} from 'app/client/ui2018/icons';
import {menu} from 'app/client/ui2018/menus'; import {menu} from 'app/client/ui2018/menus';
import {getWidgetTypes} from "app/client/ui/widgetTypesMap"; import {getWidgetTypes} from "app/client/ui/widgetTypesMap";
@ -128,7 +128,6 @@ const cssTestClick = styled(`div`, `
`); `);
const cssSigmaIcon = styled(icon, ` const cssSigmaIcon = styled(icon, `
bottom: 1px;
margin-right: 5px; margin-right: 5px;
background-color: ${theme.lightText} background-color: ${theme.lightText}
`); `);
@ -186,8 +185,7 @@ const cssViewLeafInactive = styled('div', `
// z-index ensure it's above the resizer line, since it's hard to grab otherwise // z-index ensure it's above the resizer line, since it's hard to grab otherwise
const cssDragIcon = styled(icon, ` const cssDragIcon = styled(icon, `
visibility: hidden; visibility: hidden;
--icon-color: ${colors.slate}; --icon-color: ${theme.lightText};
top: -1px;
z-index: 100; z-index: 100;
.viewsection_title:hover &.layout_grabbable { .viewsection_title:hover &.layout_grabbable {
@ -204,7 +202,7 @@ const cssResizing = styled('div', `
`); `);
const cssMiniSection = styled('div.mini_section_container', ` const cssMiniSection = styled('div.mini_section_container', `
--icon-color: ${colors.lightGreen}; --icon-color: ${theme.accentIcon};
display: flex; display: flex;
align-items: center; align-items: center;
padding-right: 8px; padding-right: 8px;

@ -350,7 +350,8 @@ const cssBehavioralPromptModal = styled('div', `
@media ${mediaXSmall} { @media ${mediaXSmall} {
& { & {
width: 320px; /* Allocate 32px of space for the left and right margins. */
width: calc(100% - 64px);
} }
} }
`); `);

@ -12,6 +12,7 @@
border-style: none; border-style: none;
border-color: var(--grist-theme-table-body-border, var(--grist-color-dark-grey)); border-color: var(--grist-theme-table-body-border, var(--grist-color-dark-grey));
border-left-style: solid; /* left border, against rownumbers div, always on */ border-left-style: solid; /* left border, against rownumbers div, always on */
border-left-color: var(--grist-theme-table-header-border, lightgray);
border-bottom-width: 1px; /* style: none, set by record-hlines*/ border-bottom-width: 1px; /* style: none, set by record-hlines*/
/* Record background is white (or theme default) by default. /* Record background is white (or theme default) by default.
It gets overridden by the add row, zebra stripes. It gets overridden by the add row, zebra stripes.
@ -203,11 +204,11 @@
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
/* Column headers always show vertical gridlines, to make it clear how to resize them */ /* Column headers always show vertical gridlines, to make it clear how to resize them */
border-right-color: var(--grist-theme-table-header-border-dark, var(--grist-color-dark-grey)); border-right-color: var(--grist-theme-table-header-border, lightgray);
} }
.column_names.record { .column_names.record {
border-left-color: var(--grist-theme-table-header-border, var(--grist-color-dark-grey)); border-left-color: var(--grist-theme-table-header-border, lightgray);
} }
.column_name.selected > .selection { .column_name.selected > .selection {

@ -3,6 +3,7 @@ import {ACIndex, ACItem, ACResults, buildHighlightedDom, normalizeText} from "ap
import {cssSelectItem} from "app/client/lib/ACSelect"; import {cssSelectItem} from "app/client/lib/ACSelect";
import {Autocomplete, IAutocompleteOptions} from "app/client/lib/autocomplete"; import {Autocomplete, IAutocompleteOptions} from "app/client/lib/autocomplete";
import {colors, testId, theme} from "app/client/ui2018/cssVars"; import {colors, testId, theme} from "app/client/ui2018/cssVars";
import {icon} from "app/client/ui2018/icons";
import {menuCssClass} from "app/client/ui2018/menus"; import {menuCssClass} from "app/client/ui2018/menus";
import { import {
cssEmailInput, cssEmailInput,
@ -104,7 +105,7 @@ export function buildACMemberEmail(
const renderSearchItem = (item: ACUserItem, highlightFunc: any): HTMLLIElement => (item?.isNew ? cssSelectItem( const renderSearchItem = (item: ACUserItem, highlightFunc: any): HTMLLIElement => (item?.isNew ? cssSelectItem(
cssMemberListItem( cssMemberListItem(
cssUserImagePlus( cssUserImagePlus(
"+", cssPlusIcon('Plus'),
cssUserImage.cls("-large"), cssUserImage.cls("-large"),
cssUserImagePlus.cls('-invalid', (use) => !use(enableAdd), cssUserImagePlus.cls('-invalid', (use) => !use(enableAdd),
)), )),
@ -199,3 +200,8 @@ const cssUserImagePlus = styled(cssUserImage, `
color: ${theme.menuItemSelectedBg}; color: ${theme.menuItemSelectedBg};
} }
`); `);
const cssPlusIcon = styled(icon, `
width: 20px;
height: 20px;
`);

@ -652,14 +652,14 @@ const cssToken = styled('div', `
position: relative; position: relative;
flex: none; flex: none;
border-radius: 3px; border-radius: 3px;
background-color: ${colors.mediumGreyOpaque}; background-color: ${theme.choiceTokenBg};
padding: 4px; padding: 4px;
margin: 3px 2px; margin: 3px 2px;
user-select: none; user-select: none;
cursor: grab; cursor: grab;
&.selected { &.selected {
background-color: ${colors.darkGrey}; background-color: ${theme.choiceTokenSelectedBg};
} }
&.token-dragging { &.token-dragging {
pointer-events: none; pointer-events: none;
@ -710,7 +710,7 @@ const cssDragTarget = styled('div', `
&:hover::after { &:hover::after {
content: ""; content: "";
position: absolute; position: absolute;
background-color: ${colors.lightGreen}; background-color: ${theme.controlFg};
width: 2px; width: 2px;
top: 0px; top: 0px;
bottom: 0px; bottom: 0px;
@ -740,7 +740,7 @@ const cssVerticalDragTarget = styled('div', `
&:hover::after { &:hover::after {
content: ""; content: "";
position: absolute; position: absolute;
background-color: ${colors.lightGreen}; background-color: ${theme.controlFg};
height: 2px; height: 2px;
top: -5px; top: -5px;
bottom: 0px; bottom: 0px;

@ -335,6 +335,7 @@ div:hover > .kf_tooltip {
color: #606060; color: #606060;
overflow: hidden; overflow: hidden;
margin-top: 3px;
padding: 1px; padding: 1px;
} }
@ -362,11 +363,11 @@ div:hover > .kf_tooltip {
} }
.kf_spinner_arrow.up { .kf_spinner_arrow.up {
border-top: none; border-top: none;
border-bottom: 5px solid #606060; border-bottom: 5px solid var(--grist-theme-numeric-spinner-fg, #606060);
margin: 2px auto; margin: 2px auto;
} }
.kf_spinner_arrow.down { .kf_spinner_arrow.down {
border-top: 5px solid #606060; border-top: 5px solid var(--grist-theme-numeric-spinner-fg, #606060);
border-bottom: none; border-bottom: none;
margin: 1px auto 2px auto; margin: 1px auto 2px auto;
} }

@ -26,6 +26,7 @@ import {getGristConfig} from 'app/common/urlUtils';
import {getOrgName, isTemplatesOrg, Organization, OrgError, UserAPI, UserAPIImpl} from 'app/common/UserAPI'; import {getOrgName, isTemplatesOrg, Organization, OrgError, UserAPI, UserAPIImpl} from 'app/common/UserAPI';
import {getUserPrefObs, getUserPrefsObs, markAsSeen, markAsUnSeen} from 'app/client/models/UserPrefs'; import {getUserPrefObs, getUserPrefsObs, markAsSeen, markAsUnSeen} from 'app/client/models/UserPrefs';
import {bundleChanges, Computed, Disposable, Observable, subscribe} from 'grainjs'; import {bundleChanges, Computed, Disposable, Observable, subscribe} from 'grainjs';
import isEqual from 'lodash/isEqual';
const t = makeT('AppModel'); const t = makeT('AppModel');
@ -311,9 +312,7 @@ export class AppModelImpl extends Disposable implements AppModel {
) { ) {
super(); super();
this._applyTheme(); this._setTheme();
this.autoDispose(this.currentTheme.addListener(() => this._applyTheme()));
this._recordSignUpIfIsNewUser(); this._recordSignUpIfIsNewUser();
const state = urlState().state.get(); const state = urlState().state.get();
@ -488,14 +487,16 @@ export class AppModelImpl extends Disposable implements AppModel {
); );
} }
/** private _setTheme() {
* Applies a theme based on the user's current theme preferences.
*/
private _applyTheme() {
// Custom CSS is incompatible with custom themes. // Custom CSS is incompatible with custom themes.
if (getGristConfig().enableCustomCss) { return; } if (getGristConfig().enableCustomCss) { return; }
attachCssThemeVars(this.currentTheme.get()); attachCssThemeVars(this.currentTheme.get());
this.autoDispose(this.currentTheme.addListener((newTheme, oldTheme) => {
if (isEqual(newTheme, oldTheme)) { return; }
attachCssThemeVars(newTheme);
}));
} }
} }

@ -18,7 +18,8 @@ import {getGristConfig} from 'app/common/urlUtils';
import {FullUser} from 'app/common/UserAPI'; import {FullUser} from 'app/common/UserAPI';
import {detectCurrentLang, makeT} from 'app/client/lib/localization'; import {detectCurrentLang, makeT} from 'app/client/lib/localization';
import {translateLocale} from 'app/client/ui/LanguageMenu'; import {translateLocale} from 'app/client/ui/LanguageMenu';
import {Computed, Disposable, dom, domComputed, makeTestId, Observable, styled} from 'grainjs'; import {getPageTitleSuffix} from 'app/common/gristUrls';
import {Computed, Disposable, dom, domComputed, makeTestId, Observable, styled, subscribe} from 'grainjs';
const testId = makeTestId('test-account-page-'); const testId = makeTestId('test-account-page-');
const t = makeT('AccountPage'); const t = makeT('AccountPage');
@ -27,6 +28,7 @@ const t = makeT('AccountPage');
* Creates the account page where a user can manage their profile settings. * Creates the account page where a user can manage their profile settings.
*/ */
export class AccountPage extends Disposable { export class AccountPage extends Disposable {
private readonly _currentPage = Computed.create(this, urlState().state, (_use, s) => s.account);
private _apiKey = Observable.create<string>(this, ''); private _apiKey = Observable.create<string>(this, '');
private _userObs = Observable.create<FullUser|null>(this, null); private _userObs = Observable.create<FullUser|null>(this, null);
private _isEditingName = Observable.create(this, false); private _isEditingName = Observable.create(this, false);
@ -37,6 +39,7 @@ export class AccountPage extends Disposable {
constructor(private _appModel: AppModel) { constructor(private _appModel: AppModel) {
super(); super();
this._setPageTitle();
this._fetchAll().catch(reportError); this._fetchAll().catch(reportError);
} }
@ -228,6 +231,18 @@ designed to ensure that you're the only person who can access your account, even
testId('username-warning'), testId('username-warning'),
); );
} }
private _setPageTitle() {
this.autoDispose(subscribe(this._currentPage, (_use, page): string => {
const suffix = getPageTitleSuffix(getGristConfig());
switch (page) {
case undefined:
case 'account': {
return document.title = `Account${suffix}`;
}
}
}));
}
} }
/** /**

@ -100,10 +100,3 @@ export const dataRow = styled('div', `
align-items: baseline; align-items: baseline;
gap: 2px; gap: 2px;
`); `);
export const betaTag = styled('span', `
text-transform: uppercase;
vertical-align: super;
font-size: ${vars.xsmallFontSize};
color: ${theme.accentText};
`);

@ -354,11 +354,6 @@ export function columnFilterMenu(owner: IDisposableOwner, opts: IFilterMenuOptio
gristDoc.behavioralPromptsManager.attachTip('filterButtons', { gristDoc.behavioralPromptsManager.attachTip('filterButtons', {
popupOptions: { popupOptions: {
attach: null, attach: null,
modifiers: {
flip: {
behavior: ['right', 'top'],
},
},
placement: 'right', placement: 'right',
}, },
}), }),

@ -55,6 +55,7 @@ const cssTextArea = styled(textarea, `
border-radius: 3px; border-radius: 3px;
padding: 3px 7px; padding: 3px 7px;
min-height: calc(3em * 1.5); min-height: calc(3em * 1.5);
resize: none;
&::placeholder { &::placeholder {
color: ${theme.inputPlaceholderFg}; color: ${theme.inputPlaceholderFg};

@ -470,18 +470,17 @@ const cssToggleButton = styled(cssIconButton, `
margin-left: 8px; margin-left: 8px;
background-color: ${theme.rightPanelToggleButtonDisabledBg}; background-color: ${theme.rightPanelToggleButtonDisabledBg};
box-shadow: inset 0 0 0 1px ${theme.inputBorder}; box-shadow: inset 0 0 0 1px ${theme.inputBorder};
cursor: pointer;
&-selected, &-selected:hover { &-selected, &-selected:hover {
box-shadow: none; box-shadow: none;
background-color: ${theme.rightPanelToggleButtonEnabledBg}; background-color: ${theme.rightPanelToggleButtonEnabledBg};
--icon-color: ${theme.rightPanelToggleButtonEnabledFg}; --icon-color: ${theme.rightPanelToggleButtonEnabledFg};
} }
&-selected:hover {
--icon-color: ${theme.rightPanelToggleButtonEnabledHoverFg};
}
&-disabled, &-disabled:hover { &-disabled, &-disabled:hover {
--icon-color: ${theme.rightPanelToggleButtonDisabledFg}; cursor: not-allowed;
background-color: ${theme.rightPanelToggleButtonDisabledBg}; background-color: ${theme.rightPanelToggleButtonDisabledBg};
--icon-color: ${theme.iconDisabled};
} }
`); `);

@ -293,7 +293,7 @@ export class FloatingPopup extends Disposable {
const body = cssPopup( const body = cssPopup(
{tabIndex: '-1'}, {tabIndex: '-1'},
cssPopup.cls('-auto', this._options.autoHeight ?? false), cssPopup.cls('-auto', this._options.autoHeight ?? false),
dom.style('min-height', `${this._minHeight}px`), dom.style('min-height', use => use(this._isMinimized) ? 'unset' : `${this._minHeight}px`),
cssPopupHeader( cssPopupHeader(
cssBottomHandle(testId('move-handle')), cssBottomHandle(testId('move-handle')),
dom.maybe(use => !use(this._isMinimized), () => { dom.maybe(use => !use(this._isMinimized), () => {

@ -1,7 +1,7 @@
import {bigPrimaryButton as gristBigPrimaryButton, import {bigPrimaryButton as gristBigPrimaryButton,
bigPrimaryButtonLink as gristBigPrimaryButtonLink, bigPrimaryButtonLink as gristBigPrimaryButtonLink,
textButton as gristTextButton} from 'app/client/ui2018/buttons'; textButton as gristTextButton} from 'app/client/ui2018/buttons';
import {colors, mediaXSmall, theme} from 'app/client/ui2018/cssVars'; import {mediaXSmall, theme} from 'app/client/ui2018/cssVars';
import {textInput} from 'app/client/ui/inputs'; import {textInput} from 'app/client/ui/inputs';
import {styled} from 'grainjs'; import {styled} from 'grainjs';
@ -61,15 +61,15 @@ export const googleButton = styled('button', `
font-weight: 500; font-weight: 500;
line-height: 16px; line-height: 16px;
padding: 16px; padding: 16px;
color: ${colors.dark}; color: ${theme.loginPageGoogleButtonFg};
background-color: ${colors.lightGrey}; background-color: ${theme.loginPageGoogleButtonBg};
border: 1px solid ${colors.darkGrey}; border: 1px solid ${theme.loginPageGoogleButtonBorder};
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
width: 100%; width: 100%;
&:hover { &:hover {
background-color: ${colors.mediumGrey}; background-color: ${theme.loginPageGoogleButtonBgHover};
} }
`); `);

@ -9,6 +9,7 @@ import {find as findInTree, fromTableData, TreeItemRecord, TreeRecord,
TreeTableData} from 'app/client/models/TreeModel'; TreeTableData} from 'app/client/models/TreeModel';
import {TreeViewComponent} from 'app/client/ui/TreeViewComponent'; import {TreeViewComponent} from 'app/client/ui/TreeViewComponent';
import {cssRadioCheckboxOptions, radioCheckboxOption} from 'app/client/ui2018/checkbox'; import {cssRadioCheckboxOptions, radioCheckboxOption} from 'app/client/ui2018/checkbox';
import {theme} from 'app/client/ui2018/cssVars';
import {cssLink} from 'app/client/ui2018/links'; import {cssLink} from 'app/client/ui2018/links';
import {ISaveModalOptions, saveModal} from 'app/client/ui2018/modals'; import {ISaveModalOptions, saveModal} from 'app/client/ui2018/modals';
import {buildCensoredPage, buildPageDom, PageActions} from 'app/client/ui2018/pages'; import {buildCensoredPage, buildPageDom, PageActions} from 'app/client/ui2018/pages';
@ -175,8 +176,8 @@ const cssWarning = styled('div', `
`); `);
const cssTableName = styled('div', ` const cssTableName = styled('div', `
color: black; color: ${theme.choiceTokenFg};
background-color: #eee; background-color: ${theme.choiceTokenBg};
padding: 3px 6px; padding: 3px 6px;
border-radius: 4px; border-radius: 4px;
`); `);

@ -263,7 +263,7 @@ const cssPinnedDocDesc = styled(cssPinnedDocTimestamp, `
const cssImage = styled('img', ` const cssImage = styled('img', `
position: relative; position: relative;
background-color: ${colors.light}; background-color: ${colors.dark};
height: 100%; height: 100%;
width: 100%; width: 100%;
object-fit: scale-down; object-fit: scale-down;

@ -311,7 +311,6 @@ export class RightPanel extends Disposable {
]), ]),
cssLabel(t("TRANSFORM")), cssLabel(t("TRANSFORM")),
dom.maybe<FieldBuilder|null>(fieldBuilder, builder => builder.buildTransformDom()), dom.maybe<FieldBuilder|null>(fieldBuilder, builder => builder.buildTransformDom()),
dom.maybe(isMultiSelect, () => disabledSection()),
testId('panel-transform'), testId('panel-transform'),
), ),
this._disableIfReadonly(), this._disableIfReadonly(),

@ -15,6 +15,7 @@ export const cssLabel = styled('div', `
`); `);
export const cssHelp = styled('div', ` export const cssHelp = styled('div', `
color: ${theme.lightText};
margin: -8px 16px 12px 16px; margin: -8px 16px 12px 16px;
font-style: italic; font-style: italic;
font-size: ${vars.xsmallFontSize}; font-size: ${vars.xsmallFontSize};

@ -376,12 +376,11 @@ const cssMenuIconLink = styled('a', `
display: block; display: block;
flex: none; flex: none;
padding: 8px 24px; padding: 8px 24px;
--icon-color: ${theme.controlFg};
background-color: ${theme.menuBg};
--icon-color: ${theme.menuItemLinkFg};
&:hover { &:hover {
background-color: ${theme.menuItemLinkselectedBg}; background-color: ${theme.hover};
--icon-color: ${theme.menuItemLinkSelectedFg}; --icon-color: ${theme.controlHoverFg};
} }
`); `);

@ -263,7 +263,8 @@ const cssContributeButtonCloseButton = styled(tokenFieldStyles.cssDeleteButton,
const cssCard = styled('div', ` const cssCard = styled('div', `
width: 297px; width: 297px;
padding: 24px; padding: 24px;
background: #DCF4EB; color: ${theme.announcementPopupFg};
background: ${theme.announcementPopupBg};
border-radius: 4px; border-radius: 4px;
align-self: flex-start; align-self: flex-start;
position: sticky; position: sticky;
@ -310,10 +311,10 @@ const cssCloseButton = styled('div', `
padding: 4px; padding: 4px;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
--icon-color: ${colors.slate}; --icon-color: ${theme.popupCloseButtonFg};
&:hover { &:hover {
background-color: ${colors.mediumGreyOpaque}; background-color: ${theme.hover};
} }
`); `);

@ -13,16 +13,17 @@ import {mediaSmall, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons'; import {icon} from 'app/client/ui2018/icons';
import {cssLink} from 'app/client/ui2018/links'; import {cssLink} from 'app/client/ui2018/links';
import {loadingSpinner} from 'app/client/ui2018/loaders'; import {loadingSpinner} from 'app/client/ui2018/loaders';
import {commonUrls} from 'app/common/gristUrls'; import {commonUrls, getPageTitleSuffix} from 'app/common/gristUrls';
import {TelemetryPrefsWithSources} from 'app/common/InstallAPI'; import {TelemetryPrefsWithSources} from 'app/common/InstallAPI';
import {getGristConfig} from 'app/common/urlUtils'; import {getGristConfig} from 'app/common/urlUtils';
import {Computed, Disposable, dom, makeTestId, Observable, styled} from 'grainjs'; import {Computed, Disposable, dom, makeTestId, Observable, styled, subscribe} from 'grainjs';
const testId = makeTestId('test-support-grist-page-'); const testId = makeTestId('test-support-grist-page-');
const t = makeT('SupportGristPage'); const t = makeT('SupportGristPage');
export class SupportGristPage extends Disposable { export class SupportGristPage extends Disposable {
private readonly _currentPage = Computed.create(this, urlState().state, (_use, s) => s.supportGrist);
private readonly _model: TelemetryModel = new TelemetryModelImpl(this._appModel); private readonly _model: TelemetryModel = new TelemetryModelImpl(this._appModel);
private readonly _optInToTelemetry = Computed.create(this, this._model.prefs, private readonly _optInToTelemetry = Computed.create(this, this._model.prefs,
(_use, prefs) => { (_use, prefs) => {
@ -37,6 +38,7 @@ export class SupportGristPage extends Disposable {
constructor(private _appModel: AppModel) { constructor(private _appModel: AppModel) {
super(); super();
this._setPageTitle();
this._model.fetchTelemetryPrefs().catch(reportError); this._model.fetchTelemetryPrefs().catch(reportError);
} }
@ -186,6 +188,18 @@ export class SupportGristPage extends Disposable {
testId('sponsorship-section'), testId('sponsorship-section'),
); );
} }
private _setPageTitle() {
this.autoDispose(subscribe(this._currentPage, (_use, page): string => {
const suffix = getPageTitleSuffix(getGristConfig());
switch (page) {
case undefined:
case 'support-grist': {
return document.title = `Support Grist${suffix}`;
}
}
}));
}
} }
function telemetryHelpCenterLink() { function telemetryHelpCenterLink() {

@ -1,5 +1,5 @@
import {docUrl, urlState} from 'app/client/models/gristUrlState'; import {docUrl, urlState} from 'app/client/models/gristUrlState';
import {colors} from 'app/client/ui2018/cssVars'; import {theme} from 'app/client/ui2018/cssVars';
import {Document, Workspace} from 'app/common/UserAPI'; import {Document, Workspace} from 'app/common/UserAPI';
import {dom, makeTestId, styled} from 'grainjs'; import {dom, makeTestId, styled} from 'grainjs';
import {HomeModel, ViewSettings} from 'app/client/models/HomeModel'; import {HomeModel, ViewSettings} from 'app/client/models/HomeModel';
@ -63,7 +63,7 @@ const cssDocName = styled(css.docName, `
const cssDocRowDetails = styled('div', ` const cssDocRowDetails = styled('div', `
margin: 0 16px; margin: 0 16px;
line-height: 1.6; line-height: 1.6;
color: ${colors.slate}; color: ${theme.lightText};
`); `);
const cssTemplateDocs = styled('div', ` const cssTemplateDocs = styled('div', `

@ -2,6 +2,7 @@ import {makeT} from 'app/client/lib/localization';
import {AppModel} from 'app/client/models/AppModel'; import {AppModel} from 'app/client/models/AppModel';
import * as css from 'app/client/ui/AccountPageCss'; import * as css from 'app/client/ui/AccountPageCss';
import {labeledSquareCheckbox} from 'app/client/ui2018/checkbox'; import {labeledSquareCheckbox} from 'app/client/ui2018/checkbox';
import {prefersDarkModeObs} from 'app/client/ui2018/cssVars';
import {select} from 'app/client/ui2018/menus'; import {select} from 'app/client/ui2018/menus';
import {ThemeAppearance} from 'app/common/ThemePrefs'; import {ThemeAppearance} from 'app/common/ThemePrefs';
import {Computed, Disposable, dom, makeTestId, styled} from 'grainjs'; import {Computed, Disposable, dom, makeTestId, styled} from 'grainjs';
@ -12,21 +13,30 @@ const t = makeT('ThemeConfig');
export class ThemeConfig extends Disposable { export class ThemeConfig extends Disposable {
private _themePrefs = this._appModel.themePrefs; private _themePrefs = this._appModel.themePrefs;
private _appearance = Computed.create(this, this._themePrefs, (_use, prefs) => {
return prefs.appearance;
}).onWrite((value) => this._updateAppearance(value));
private _syncWithOS = Computed.create(this, this._themePrefs, (_use, prefs) => { private _syncWithOS = Computed.create(this, this._themePrefs, (_use, prefs) => {
return prefs.syncWithOS; return prefs.syncWithOS;
}).onWrite((value) => this._updateSyncWithOS(value)); }).onWrite((value) => this._updateSyncWithOS(value));
private _appearance = Computed.create(this,
this._themePrefs,
this._syncWithOS,
prefersDarkModeObs(),
(_use, prefs, syncWithOS, prefersDarkMode) => {
if (syncWithOS) {
return prefersDarkMode ? 'dark' : 'light';
} else {
return prefs.appearance;
}
})
.onWrite((value) => this._updateAppearance(value));
constructor(private _appModel: AppModel) { constructor(private _appModel: AppModel) {
super(); super();
} }
public buildDom() { public buildDom() {
return dom('div', return dom('div',
css.subHeader(t("Appearance "), css.betaTag('Beta')), css.subHeader(t("Appearance ")),
css.dataRow( css.dataRow(
cssAppearanceSelect( cssAppearanceSelect(
select( select(
@ -35,6 +45,9 @@ export class ThemeConfig extends Disposable {
{value: 'light', label: 'Light'}, {value: 'light', label: 'Light'},
{value: 'dark', label: 'Dark'}, {value: 'dark', label: 'Dark'},
], ],
{
disabled: this._syncWithOS,
},
), ),
testId('appearance'), testId('appearance'),
), ),

@ -263,7 +263,7 @@ const cssFilterMenuWrapper = styled('div', `
border-radius: 3px; border-radius: 3px;
align-items: center; align-items: center;
&-unsaved { &-unsaved {
border: 1px solid ${theme.accentBorder}; border: ${theme.controlBorder};
} }
& .${cssMenu.className} { & .${cssMenu.className} {
border: none; border: none;
@ -364,11 +364,8 @@ const cssSaveTextButton = styled('div', `
cursor: pointer; cursor: pointer;
font-size: ${vars.mediumFontSize}; font-size: ${vars.mediumFontSize};
padding: 0px 5px; padding: 0px 5px;
border-right: 1px solid ${theme.accentBorder}; color: ${theme.controlFg};
border-right: ${theme.controlBorder};
&-accent {
color: ${theme.accentText};
}
`); `);
const cssRevertIconButton = styled('div', ` const cssRevertIconButton = styled('div', `

@ -1,8 +1,8 @@
import {dom, IDomArgs, Observable, styled} from 'grainjs'; import {dom, IDomArgs, Observable, styled} from 'grainjs';
// Shadow css settings for member scroll top and bottom. // Shadow css settings for member scroll top and bottom.
const SHADOW_TOP = 'inset 0 4px 6px 0 rgba(217,217,217,0.4)'; const SHADOW_TOP = 'inset 0 4px 6px 0 var(--grist-theme-scroll-shadow, rgba(217,217,217,0.4))';
const SHADOW_BTM = 'inset 0 -4px 6px 0 rgba(217,217,217,0.4)'; const SHADOW_BTM = 'inset 0 -4px 6px 0 var(--grist-theme-scroll-shadow, rgba(217,217,217,0.4))';
/** /**
* Creates a scroll div used in the UserManager and moveDoc menus to display * Creates a scroll div used in the UserManager and moveDoc menus to display

@ -274,9 +274,11 @@ interface PickerComponentOptions {
} }
class PickerComponent extends Disposable { class PickerComponent extends Disposable {
private _color = Computed.create(this, private _colorHex = Computed.create(this, this._model.obs, (_use, val) =>
this._model.obs, val?.toUpperCase().slice(0, 7));
(use, val) => (val || this._options.defaultColor).toUpperCase().slice(0, 7));
private _colorCss = Computed.create(this, this._colorHex, (_use, color) =>
color || this._options.defaultColor);
constructor( constructor(
private _model: PickerModel<string|undefined>, private _model: PickerModel<string|undefined>,
@ -286,7 +288,7 @@ class PickerComponent extends Disposable {
public buildDom() { public buildDom() {
const title = this._options.title; const title = this._options.title;
const colorText = Computed.create(null, use => use(this._color) || this._options.noneText); const colorText = Computed.create(null, use => use(this._colorHex) || this._options.noneText);
return [ return [
cssHeaderRow(title), cssHeaderRow(title),
cssControlRow( cssControlRow(
@ -294,14 +296,15 @@ class PickerComponent extends Disposable {
dom.update( dom.update(
cssColorSquare( cssColorSquare(
cssLightBorder.cls(''), cssLightBorder.cls(''),
dom.style('background-color', this._color), dom.style('background-color', this._colorCss),
cssNoneIcon('Empty', cssNoneIcon('Empty',
dom.hide(use => Boolean(use(this._color)) === true) dom.hide(use => Boolean(use(this._colorCss)))
), ),
testId(`${title}-color-square`),
), ),
cssColorInput( cssColorInput(
{type: 'color'}, {type: 'color'},
dom.attr('value', this._color), dom.attr('value', use => use(this._model.obs) ?? ''),
dom.on('input', (ev, elem) => this._setValue(elem.value || undefined)), dom.on('input', (ev, elem) => this._setValue(elem.value || undefined)),
testId(`${title}-input`), testId(`${title}-input`),
), ),
@ -321,7 +324,7 @@ class PickerComponent extends Disposable {
) )
), ),
cssEmptyBox( cssEmptyBox(
cssEmptyBox.cls('-selected', (use) => !use(this._color)), cssEmptyBox.cls('-selected', (use) => !use(this._colorCss)),
dom.on('click', () => this._setValue(undefined)), dom.on('click', () => this._setValue(undefined)),
dom.hide(!this._options.allowsNone), dom.hide(!this._options.allowsNone),
cssNoneIcon('Empty'), cssNoneIcon('Empty'),
@ -333,7 +336,7 @@ class PickerComponent extends Disposable {
cssColorSquare( cssColorSquare(
dom.style('background-color', color), dom.style('background-color', color),
cssLightBorder.cls('', isLight(index)), cssLightBorder.cls('', isLight(index)),
cssColorSquare.cls('-selected', (use) => use(this._color) === color), cssColorSquare.cls('-selected', (use) => use(this._colorHex) === color),
dom.style('outline-color', isLight(index) ? '' : color), dom.style('outline-color', isLight(index) ? '' : color),
dom.on('click', () => this._setValue(color)), dom.on('click', () => this._setValue(color)),
testId(`color-${color}`), testId(`color-${color}`),
@ -381,8 +384,6 @@ class FontComponent extends Disposable {
const cssFontOptions = styled('div', ` const cssFontOptions = styled('div', `
display: flex; display: flex;
gap: 1px;
background: ${theme.colorSelectFontOptionsBorder};
border: 1px solid ${theme.colorSelectFontOptionsBorder}; border: 1px solid ${theme.colorSelectFontOptionsBorder};
`); `);
@ -390,10 +391,13 @@ const cssFontOption = styled('div', `
display: grid; display: grid;
place-items: center; place-items: center;
flex-grow: 1; flex-grow: 1;
background: ${theme.colorSelectFontOptionBg};
--icon-color: ${theme.colorSelectFontOptionFg}; --icon-color: ${theme.colorSelectFontOptionFg};
height: 24px; height: 24px;
cursor: pointer; cursor: pointer;
&:not(:last-child) {
border-right: 1px solid ${theme.colorSelectFontOptionsBorder};
}
&:hover:not(&-selected) { &:hover:not(&-selected) {
background: ${theme.colorSelectFontOptionBgHover}; background: ${theme.colorSelectFontOptionBgHover};
} }

@ -146,6 +146,11 @@ export const cssButtonSelect = styled('div', `
/* Vars */ /* Vars */
color: ${theme.text}; color: ${theme.text};
flex: 1 1 0; flex: 1 1 0;
&-disabled {
opacity: 0.4;
pointer-events: none;
}
`); `);
const cssSelectorBtn = styled('div', ` const cssSelectorBtn = styled('div', `
@ -187,6 +192,7 @@ const cssSelectorBtn = styled('div', `
} }
&:hover:not(&-selected) { &:hover:not(&-selected) {
background-color: ${theme.buttonGroupBgHover};
border: 1px solid ${theme.buttonGroupBorderHover}; border: 1px solid ${theme.buttonGroupBorderHover};
z-index: 5; /* Update z-index so selected borders take precedent */ z-index: 5; /* Update z-index so selected borders take precedent */
} }
@ -218,14 +224,6 @@ const cssSelectorBtn = styled('div', `
border: none; border: none;
background-color: ${theme.hover}; background-color: ${theme.hover};
} }
.${cssButtonSelect.className}-disabled > &,
.${cssButtonSelect.className}-disabled > &:hover {
--icon-color: ${theme.rightPanelToggleButtonDisabledFg};
color: ${theme.rightPanelToggleButtonDisabledFg};
background-color: ${theme.rightPanelToggleButtonDisabledBg};
border-color: ${theme.buttonGroupBorder};
pointer-events: none;
}
`); `);
const cssSelectorLabel = styled('span', ` const cssSelectorLabel = styled('span', `

@ -109,7 +109,8 @@ export const textButton = styled(cssButton, `
text-align: left; text-align: left;
background-color: inherit !important; background-color: inherit !important;
&:disabled { &:disabled {
color: ${theme.controlPrimaryDisabled}; color: ${theme.controlPrimaryBg};
opacity: 0.4;
} }
`); `);

@ -199,7 +199,7 @@ export const cssRadioCheckboxOptions = styled('div', `
const cssBlockCheckbox = styled('div', ` const cssBlockCheckbox = styled('div', `
display: flex; display: flex;
padding: 10px 8px; padding: 10px 8px;
border: 1px solid ${theme.modalBorder}; border: 1px solid ${theme.controlSecondaryDisabledFg};
border-radius: 3px; border-radius: 3px;
cursor: pointer; cursor: pointer;
& input::before, & input::after { & input::before, & input::after {
@ -207,7 +207,7 @@ const cssBlockCheckbox = styled('div', `
left: unset; left: unset;
} }
&:hover { &:hover {
border-color: ${theme.accentBorder}; border-color: ${theme.controlFg};
} }
&-block { &-block {
pointer-events: none; pointer-events: none;

@ -245,8 +245,6 @@ export const theme = {
'black'), 'black'),
tooltipCloseButtonHoverBg: new CustomProp('theme-tooltip-close-button-hover-bg', undefined, tooltipCloseButtonHoverBg: new CustomProp('theme-tooltip-close-button-hover-bg', undefined,
'white'), 'white'),
tooltipPopupHeaderFg: new CustomProp('theme-tooltip-popup-header-fg', undefined, colors.light),
tooltipPopupHeaderBg: new CustomProp('theme-tooltip-popup-header-bg', undefined, colors.lightGreen),
/* Modals */ /* Modals */
modalBg: new CustomProp('theme-modal-bg', undefined, 'white'), modalBg: new CustomProp('theme-modal-bg', undefined, 'white'),
@ -290,6 +288,7 @@ export const theme = {
/* Cell Editor */ /* Cell Editor */
cellEditorFg: new CustomProp('theme-cell-editor-fg', undefined, colors.dark), cellEditorFg: new CustomProp('theme-cell-editor-fg', undefined, colors.dark),
cellEditorPlaceholderFg: new CustomProp('theme-cell-editor-placeholder-fg', undefined, colors.slate),
cellEditorBg: new CustomProp('theme-cell-editor-bg', undefined, colors.light), cellEditorBg: new CustomProp('theme-cell-editor-bg', undefined, colors.light),
/* Cursor */ /* Cursor */
@ -298,14 +297,12 @@ export const theme = {
cursorReadonly: new CustomProp('theme-cursor-readonly', undefined, colors.slate), cursorReadonly: new CustomProp('theme-cursor-readonly', undefined, colors.slate),
/* Tables */ /* Tables */
tableHeaderFg: new CustomProp('theme-table-header-fg', undefined, 'unset'), tableHeaderFg: new CustomProp('theme-table-header-fg', undefined, '#000'),
tableHeaderSelectedFg: new CustomProp('theme-table-header-selected-fg', undefined, 'unset'), tableHeaderSelectedFg: new CustomProp('theme-table-header-selected-fg', undefined, '#000'),
tableHeaderBg: new CustomProp('theme-table-header-bg', undefined, colors.lightGrey), tableHeaderBg: new CustomProp('theme-table-header-bg', undefined, colors.lightGrey),
tableHeaderSelectedBg: new CustomProp('theme-table-header-selected-bg', undefined, tableHeaderSelectedBg: new CustomProp('theme-table-header-selected-bg', undefined,
colors.mediumGreyOpaque), colors.mediumGreyOpaque),
tableHeaderBorder: new CustomProp('theme-table-header-border', undefined, 'lightgray'), tableHeaderBorder: new CustomProp('theme-table-header-border', undefined, 'lightgray'),
tableHeaderBorderDark: new CustomProp('theme-table-header-border-dark', undefined,
colors.darkGrey),
tableBodyBg: new CustomProp('theme-table-body-bg', undefined, 'white'), tableBodyBg: new CustomProp('theme-table-body-bg', undefined, 'white'),
tableBodyBorder: new CustomProp('theme-table-body-border', undefined, colors.darkGrey), tableBodyBorder: new CustomProp('theme-table-body-border', undefined, colors.darkGrey),
tableAddNewBg: new CustomProp('theme-table-add-new-bg', undefined, 'inherit'), tableAddNewBg: new CustomProp('theme-table-add-new-bg', undefined, 'inherit'),
@ -314,6 +311,7 @@ export const theme = {
'#999999'), '#999999'),
tableDragDropIndicator: new CustomProp('theme-table-drag-drop-indicator', undefined, 'gray'), tableDragDropIndicator: new CustomProp('theme-table-drag-drop-indicator', undefined, 'gray'),
tableDragDropShadow: new CustomProp('theme-table-drag-drop-shadow', undefined, '#F0F0F0'), tableDragDropShadow: new CustomProp('theme-table-drag-drop-shadow', undefined, '#F0F0F0'),
tableCellSummaryBg: new CustomProp('theme-table-cell-summary-bg', undefined, colors.mediumGrey),
/* Cards */ /* Cards */
cardCompactWidgetBg: new CustomProp('theme-card-compact-widget-bg', undefined, cardCompactWidgetBg: new CustomProp('theme-card-compact-widget-bg', undefined,
@ -339,7 +337,7 @@ export const theme = {
selection: new CustomProp('theme-selection', undefined, colors.selection), selection: new CustomProp('theme-selection', undefined, colors.selection),
selectionDarker: new CustomProp('theme-selection-darker', undefined, 'rgba(22,179,120,0.25)'), selectionDarker: new CustomProp('theme-selection-darker', undefined, 'rgba(22,179,120,0.25)'),
selectionDarkest: new CustomProp('theme-selection-darkest', undefined, 'rgba(22,179,120,0.35)'), selectionDarkest: new CustomProp('theme-selection-darkest', undefined, 'rgba(22,179,120,0.35)'),
selectionOpaqueFg: new CustomProp('theme-selection-opaque-fg', undefined, 'unset'), selectionOpaqueFg: new CustomProp('theme-selection-opaque-fg', undefined, 'black'),
selectionOpaqueBg: new CustomProp('theme-selection-opaque-bg', undefined, selectionOpaqueBg: new CustomProp('theme-selection-opaque-bg', undefined,
colors.selectionOpaque), colors.selectionOpaque),
selectionOpaqueDarkBg: new CustomProp('theme-selection-opaque-dark-bg', undefined, selectionOpaqueDarkBg: new CustomProp('theme-selection-opaque-dark-bg', undefined,
@ -371,6 +369,8 @@ export const theme = {
controlPrimaryFg: new CustomProp('theme-control-primary-fg', undefined, vars.primaryFg), controlPrimaryFg: new CustomProp('theme-control-primary-fg', undefined, vars.primaryFg),
controlPrimaryBg: new CustomProp('theme-control-primary-bg', undefined, vars.primaryBg), controlPrimaryBg: new CustomProp('theme-control-primary-bg', undefined, vars.primaryBg),
controlSecondaryFg: new CustomProp('theme-control-secondary-fg', undefined, colors.slate), controlSecondaryFg: new CustomProp('theme-control-secondary-fg', undefined, colors.slate),
controlSecondaryDisabledFg: new CustomProp('theme-control-secondary-disabled-fg',
undefined, colors.darkGrey),
controlHoverFg: new CustomProp('theme-control-hover-fg', undefined, vars.controlFgHover), controlHoverFg: new CustomProp('theme-control-hover-fg', undefined, vars.controlFgHover),
controlPrimaryHoverBg: new CustomProp('theme-control-primary-hover-bg', undefined, controlPrimaryHoverBg: new CustomProp('theme-control-primary-hover-bg', undefined,
vars.primaryBgHover), vars.primaryBgHover),
@ -380,8 +380,6 @@ export const theme = {
colors.darkGrey), colors.darkGrey),
controlDisabledFg: new CustomProp('theme-control-disabled-fg', undefined, colors.light), controlDisabledFg: new CustomProp('theme-control-disabled-fg', undefined, colors.light),
controlDisabledBg: new CustomProp('theme-control-disabled-bg', undefined, colors.slate), controlDisabledBg: new CustomProp('theme-control-disabled-bg', undefined, colors.slate),
controlPrimaryDisabled: new CustomProp('theme-control-primary-disabled', undefined,
colors.inactiveCursor),
controlBorder: new CustomProp('theme-control-border', undefined, vars.controlBorder), controlBorder: new CustomProp('theme-control-border', undefined, vars.controlBorder),
/* Checkboxes */ /* Checkboxes */
@ -464,8 +462,6 @@ export const theme = {
undefined, colors.light), undefined, colors.light),
rightPanelToggleButtonEnabledBg: new CustomProp('theme-right-panel-toggle-button-enabled-bg', rightPanelToggleButtonEnabledBg: new CustomProp('theme-right-panel-toggle-button-enabled-bg',
undefined, colors.dark), undefined, colors.dark),
rightPanelToggleButtonEnabledHoverFg: new CustomProp(
'theme-right-panel-toggle-button-enabled-hover-fg', undefined, colors.darkGrey),
rightPanelToggleButtonDisabledFg: new CustomProp('theme-right-panel-toggle-button-disabled-fg', rightPanelToggleButtonDisabledFg: new CustomProp('theme-right-panel-toggle-button-disabled-fg',
undefined, colors.light), undefined, colors.light),
rightPanelToggleButtonDisabledBg: new CustomProp('theme-right-panel-toggle-button-disabled-bg', rightPanelToggleButtonDisabledBg: new CustomProp('theme-right-panel-toggle-button-disabled-bg',
@ -487,9 +483,15 @@ export const theme = {
documentHistorySnapshotBorder: new CustomProp('theme-document-history-snapshot-border', documentHistorySnapshotBorder: new CustomProp('theme-document-history-snapshot-border',
undefined, colors.mediumGrey), undefined, colors.mediumGrey),
documentHistoryActivityText: new CustomProp('theme-document-history-activity-text', undefined, documentHistoryActivityText: new CustomProp('theme-document-history-activity-text', undefined,
'unset'), colors.dark),
documentHistoryActivityLightText: new CustomProp('theme-document-history-activity-text-light', documentHistoryActivityLightText: new CustomProp('theme-document-history-activity-text-light',
undefined, '#333333'), undefined, '#333333'),
documentHistoryTableHeaderFg: new CustomProp('theme-document-history-table-header-fg',
undefined, '#000'),
documentHistoryTableBorder: new CustomProp('theme-document-history-table-border',
undefined, 'lightgray'),
documentHistoryTableBorderLight: new CustomProp('theme-document-history-table-border-light',
undefined, '#D9D9D9'),
/* Accents */ /* Accents */
accentIcon: new CustomProp('theme-accent-icon', undefined, colors.lightGreen), accentIcon: new CustomProp('theme-accent-icon', undefined, colors.lightGreen),
@ -509,6 +511,16 @@ export const theme = {
inputReadonlyBg: new CustomProp('theme-input-readonly-bg', undefined, colors.lightGrey), inputReadonlyBg: new CustomProp('theme-input-readonly-bg', undefined, colors.lightGrey),
inputReadonlyBorder: new CustomProp('theme-input-readonly-border', undefined, colors.mediumGreyOpaque), inputReadonlyBorder: new CustomProp('theme-input-readonly-border', undefined, colors.mediumGreyOpaque),
/* Choice Tokens */
choiceTokenFg: new CustomProp('theme-choice-token-fg', undefined, '#000000'),
choiceTokenBlankFg: new CustomProp('theme-choice-token-blank-fg', undefined, colors.slate),
choiceTokenBg: new CustomProp('theme-choice-token-bg', undefined, colors.mediumGreyOpaque),
choiceTokenSelectedBg: new CustomProp('theme-choice-token-selected-bg', undefined, colors.darkGrey),
choiceTokenSelectedBorder: new CustomProp('theme-choice-token-selected-border', undefined, colors.lightGreen),
choiceTokenInvalidFg: new CustomProp('theme-choice-token-invalid-fg', undefined, '#000000'),
choiceTokenInvalidBg: new CustomProp('theme-choice-token-invalid-bg', undefined, 'white'),
choiceTokenInvalidBorder: new CustomProp('theme-choice-token-invalid-border', undefined, colors.error),
/* Choice Entry */ /* Choice Entry */
choiceEntryBg: new CustomProp('theme-choice-entry-bg', undefined, 'white'), choiceEntryBg: new CustomProp('theme-choice-entry-bg', undefined, 'white'),
choiceEntryBorder: new CustomProp('theme-choice-entry-border', undefined, colors.darkGrey), choiceEntryBorder: new CustomProp('theme-choice-entry-border', undefined, colors.darkGrey),
@ -519,7 +531,6 @@ export const theme = {
selectButtonFg: new CustomProp('theme-select-button-fg', undefined, colors.dark), selectButtonFg: new CustomProp('theme-select-button-fg', undefined, colors.dark),
selectButtonPlaceholderFg: new CustomProp('theme-select-button-placeholder-fg', undefined, selectButtonPlaceholderFg: new CustomProp('theme-select-button-placeholder-fg', undefined,
colors.slate), colors.slate),
selectButtonDisabledFg: new CustomProp('theme-select-button-disabled-fg', undefined, 'grey'),
selectButtonBg: new CustomProp('theme-select-button-bg', undefined, 'white'), selectButtonBg: new CustomProp('theme-select-button-bg', undefined, 'white'),
selectButtonBorder: new CustomProp('theme-select-button-border', undefined, colors.darkGrey), selectButtonBorder: new CustomProp('theme-select-button-border', undefined, colors.darkGrey),
selectButtonBorderInvalid: new CustomProp('theme-select-button-border-invalid', undefined, selectButtonBorderInvalid: new CustomProp('theme-select-button-border-invalid', undefined,
@ -529,7 +540,7 @@ export const theme = {
menuText: new CustomProp('theme-menu-text', undefined, colors.slate), menuText: new CustomProp('theme-menu-text', undefined, colors.slate),
menuLightText: new CustomProp('theme-menu-light-text', undefined, colors.slate), menuLightText: new CustomProp('theme-menu-light-text', undefined, colors.slate),
menuBg: new CustomProp('theme-menu-bg', undefined, 'white'), menuBg: new CustomProp('theme-menu-bg', undefined, 'white'),
menuSubheaderFg: new CustomProp('theme-menu-subheader-fg', undefined, 'unset'), menuSubheaderFg: new CustomProp('theme-menu-subheader-fg', undefined, colors.dark),
menuBorder: new CustomProp('theme-menu-border', undefined, colors.mediumGreyOpaque), menuBorder: new CustomProp('theme-menu-border', undefined, colors.mediumGreyOpaque),
menuShadow: new CustomProp('theme-menu-shadow', undefined, 'rgba(38, 38, 51, 0.6)'), menuShadow: new CustomProp('theme-menu-shadow', undefined, 'rgba(38, 38, 51, 0.6)'),
@ -540,19 +551,20 @@ export const theme = {
menuItemDisabledFg: new CustomProp('theme-menu-item-disabled-fg', undefined, '#D9D9D9'), menuItemDisabledFg: new CustomProp('theme-menu-item-disabled-fg', undefined, '#D9D9D9'),
menuItemIconFg: new CustomProp('theme-menu-item-icon-fg', undefined, colors.slate), menuItemIconFg: new CustomProp('theme-menu-item-icon-fg', undefined, colors.slate),
menuItemIconSelectedFg: new CustomProp('theme-menu-item-icon-selected-fg', undefined, 'white'), menuItemIconSelectedFg: new CustomProp('theme-menu-item-icon-selected-fg', undefined, 'white'),
menuItemLinkFg: new CustomProp('theme-menu-item-link-fg', undefined, colors.lightGreen),
menuItemLinkSelectedFg: new CustomProp('theme-menu-item-link-selected-fg', undefined,
colors.darkGreen),
menuItemLinkselectedBg: new CustomProp('theme-menu-item-link-selected-bg', undefined,
colors.mediumGreyOpaque),
/* Autocomplete */ /* Autocomplete */
autocompleteMatchText: new CustomProp('theme-autocomplete-match-text', undefined, autocompleteMatchText: new CustomProp('theme-autocomplete-match-text', undefined,
colors.lightGreen), colors.lightGreen),
autocompleteSelectedMatchText: new CustomProp('theme-autocomplete-selected-match-text', autocompleteSelectedMatchText: new CustomProp('theme-autocomplete-selected-match-text',
undefined, colors.lighterGreen), undefined, colors.lighterGreen),
autocompleteChoiceSelectedBg: new CustomProp('theme-autocomplete-item-selected-bg', undefined, autocompleteItemSelectedBg: new CustomProp('theme-autocomplete-item-selected-bg', undefined,
colors.mediumGreyOpaque), colors.mediumGreyOpaque),
autocompleteAddNewCircleFg: new CustomProp('theme-autocomplete-add-new-circle-fg', undefined,
colors.light),
autocompleteAddNewCircleBg: new CustomProp('theme-autocomplete-add-new-circle-bg', undefined,
colors.lightGreen),
autocompleteAddNewCircleSelectedBg: new CustomProp(
'theme-autocomplete-add-new-circle-selected-bg', undefined, colors.darkGreen),
/* Search */ /* Search */
searchBorder: new CustomProp('theme-search-border', undefined, 'grey'), searchBorder: new CustomProp('theme-search-border', undefined, 'grey'),
@ -594,7 +606,7 @@ export const theme = {
widgetPickerPrimaryBg: new CustomProp('theme-widget-picker-primary-bg', undefined, 'white'), widgetPickerPrimaryBg: new CustomProp('theme-widget-picker-primary-bg', undefined, 'white'),
widgetPickerSecondaryBg: new CustomProp('theme-widget-picker-secondary-bg', undefined, widgetPickerSecondaryBg: new CustomProp('theme-widget-picker-secondary-bg', undefined,
colors.lightGrey), colors.lightGrey),
widgetPickerItemFg: new CustomProp('theme-widget-picker-item-fg', undefined, 'unset'), widgetPickerItemFg: new CustomProp('theme-widget-picker-item-fg', undefined, colors.dark),
widgetPickerItemSelectedBg: new CustomProp('theme-widget-picker-item-selected-bg', undefined, widgetPickerItemSelectedBg: new CustomProp('theme-widget-picker-item-selected-bg', undefined,
colors.mediumGrey), colors.mediumGrey),
widgetPickerItemDisabledBg: new CustomProp('theme-widget-picker-item-disabled-bg', undefined, widgetPickerItemDisabledBg: new CustomProp('theme-widget-picker-item-disabled-bg', undefined,
@ -651,7 +663,9 @@ export const theme = {
/* Button Groups */ /* Button Groups */
buttonGroupFg: new CustomProp('theme-button-group-fg', undefined, colors.dark), buttonGroupFg: new CustomProp('theme-button-group-fg', undefined, colors.dark),
buttonGroupLightFg: new CustomProp('theme-button-group-light-fg', undefined, colors.slate), buttonGroupLightFg: new CustomProp('theme-button-group-light-fg', undefined, colors.slate),
buttonGroupBg: new CustomProp('theme-button-group-bg', undefined, 'unset'), buttonGroupBg: new CustomProp('theme-button-group-bg', undefined, 'transparent'),
buttonGroupBgHover: new CustomProp('theme-button-group-bg-hover', undefined,
colors.hover),
buttonGroupIcon: new CustomProp('theme-button-group-icon', undefined, colors.slate), buttonGroupIcon: new CustomProp('theme-button-group-icon', undefined, colors.slate),
buttonGroupBorder: new CustomProp('theme-button-group-border', undefined, colors.darkGrey), buttonGroupBorder: new CustomProp('theme-button-group-border', undefined, colors.darkGrey),
buttonGroupBorderHover: new CustomProp('theme-button-group-border-hover', undefined, buttonGroupBorderHover: new CustomProp('theme-button-group-border-hover', undefined,
@ -670,6 +684,8 @@ export const theme = {
colors.mediumGrey), colors.mediumGrey),
accessRulesTableBodyFg: new CustomProp('theme-access-rules-table-body-fg', undefined, accessRulesTableBodyFg: new CustomProp('theme-access-rules-table-body-fg', undefined,
colors.dark), colors.dark),
accessRulesTableBodyLightFg: new CustomProp('theme-access-rules-table-body-light-fg', undefined,
colors.darkGrey),
accessRulesTableBorder: new CustomProp('theme-access-rules-table-border', undefined, accessRulesTableBorder: new CustomProp('theme-access-rules-table-border', undefined,
colors.slate), colors.slate),
accessRulesColumnListBorder: new CustomProp('theme-access-rules-column-list-border', undefined, accessRulesColumnListBorder: new CustomProp('theme-access-rules-column-list-border', undefined,
@ -694,7 +710,7 @@ export const theme = {
undefined, colors.cursor), undefined, colors.cursor),
/* Cells */ /* Cells */
cellFg: new CustomProp('theme-cell-fg', undefined, 'unset'), cellFg: new CustomProp('theme-cell-fg', undefined, 'black'),
cellBg: new CustomProp('theme-cell-bg', undefined, '#FFFFFF00'), cellBg: new CustomProp('theme-cell-bg', undefined, '#FFFFFF00'),
cellZebraBg: new CustomProp('theme-cell-zebra-bg', undefined, '#F8F8F8'), cellZebraBg: new CustomProp('theme-cell-zebra-bg', undefined, '#F8F8F8'),
@ -772,13 +788,11 @@ export const theme = {
undefined, colors.darkGrey), undefined, colors.darkGrey),
colorSelectFontOptionFg: new CustomProp('theme-color-select-font-option-fg', colorSelectFontOptionFg: new CustomProp('theme-color-select-font-option-fg',
undefined, colors.dark), undefined, colors.dark),
colorSelectFontOptionBg: new CustomProp('theme-color-select-font-option-bg',
undefined, colors.light),
colorSelectFontOptionBgHover: new CustomProp('theme-color-select-font-option-bg-hover', colorSelectFontOptionBgHover: new CustomProp('theme-color-select-font-option-bg-hover',
undefined, colors.lightGrey), undefined, colors.lightGrey),
colorSelectFontOptionFgSelected: new CustomProp('theme-color-select-font-option-selected-fg', colorSelectFontOptionFgSelected: new CustomProp('theme-color-select-font-option-fg-selected',
undefined, colors.light), undefined, colors.light),
colorSelectFontOptionBgSelected: new CustomProp('theme-color-select-font-option-selected-bg', colorSelectFontOptionBgSelected: new CustomProp('theme-color-select-font-option-bg-selected',
undefined, colors.dark), undefined, colors.dark),
colorSelectColorSquareBorder: new CustomProp('theme-color-select-color-square-border', colorSelectColorSquareBorder: new CustomProp('theme-color-select-color-square-border',
undefined, '#D9D9D9'), undefined, '#D9D9D9'),
@ -807,6 +821,14 @@ export const theme = {
loginPageBg: new CustomProp('theme-login-page-bg', undefined, 'white'), loginPageBg: new CustomProp('theme-login-page-bg', undefined, 'white'),
loginPageBackdrop: new CustomProp('theme-login-page-backdrop', undefined, '#F5F8FA'), loginPageBackdrop: new CustomProp('theme-login-page-backdrop', undefined, '#F5F8FA'),
loginPageLine: new CustomProp('theme-login-page-line', undefined, colors.lightGrey), loginPageLine: new CustomProp('theme-login-page-line', undefined, colors.lightGrey),
loginPageGoogleButtonFg: new CustomProp('theme-login-page-google-button-fg', undefined,
colors.dark),
loginPageGoogleButtonBg: new CustomProp('theme-login-page-google-button-bg', undefined,
colors.lightGrey),
loginPageGoogleButtonBgHover: new CustomProp('theme-login-page-google-button-bg-hover',
undefined, colors.mediumGrey),
loginPageGoogleButtonBorder: new CustomProp('theme-login-page-google-button-border', undefined,
colors.darkGrey),
/* Formula Assistant */ /* Formula Assistant */
formulaAssistantHeaderBg: new CustomProp( formulaAssistantHeaderBg: new CustomProp(
@ -815,6 +837,42 @@ export const theme = {
'theme-formula-assistant-border', undefined, colors.darkGrey), 'theme-formula-assistant-border', undefined, colors.darkGrey),
formulaAssistantPreformattedTextBg: new CustomProp( formulaAssistantPreformattedTextBg: new CustomProp(
'theme-formula-assistant-preformatted-text-bg', undefined, colors.lightGrey), 'theme-formula-assistant-preformatted-text-bg', undefined, colors.lightGrey),
/* Attachments */
attachmentsEditorButtonFg: new CustomProp(
'theme-attachments-editor-button-fg', undefined, colors.darkGreen),
attachmentsEditorButtonHoverFg: new CustomProp(
'theme-attachments-editor-button-hover-fg', undefined, colors.lightGreen),
attachmentsEditorButtonBg: new CustomProp(
'theme-attachments-editor-button-bg', undefined, colors.light),
attachmentsEditorButtonHoverBg: new CustomProp(
'theme-attachments-editor-button-hover-bg', undefined, colors.mediumGreyOpaque),
attachmentsEditorButtonBorder: new CustomProp(
'theme-attachments-editor-button-border', undefined, colors.darkGrey),
attachmentsEditorButtonIcon: new CustomProp(
'theme-attachments-editor-button-icon', undefined, colors.slate),
attachmentsEditorBorder: new CustomProp(
'theme-attachments-editor-border', undefined, colors.mediumGreyOpaque),
attachmentsCellIconFg: new CustomProp(
'theme-attachments-cell-icon-fg', undefined, 'white'),
attachmentsCellIconBg: new CustomProp(
'theme-attachments-cell-icon-bg', undefined, '#D9D9D9'),
attachmentsCellIconHoverBg: new CustomProp(
'theme-attachments-cell-icon-hover-bg', undefined, '#929299'),
/* Announcement Popups */
announcementPopupFg: new CustomProp('theme-announcement-popup-fg', undefined, '#000000'),
announcementPopupBg: new CustomProp('theme-announcement-popup-bg', undefined, '#DCF4EB'),
/* Switches */
switchSliderFg: new CustomProp('theme-switch-slider-fg', undefined, '#ccc'),
switchCircleFg: new CustomProp('theme-switch-circle-fg', undefined, 'white'),
/* Toggle Checkboxes */
toggleCheckboxFg: new CustomProp('theme-toggle-checkbox-fg', undefined, '#606060'),
/* Numeric Spinners */
numericSpinnerFg: new CustomProp('theme-numeric-spinner-fg', undefined, '#606060'),
}; };
const cssColors = values(colors).map(v => v.decl()).join('\n'); const cssColors = values(colors).map(v => v.decl()).join('\n');
@ -1038,7 +1096,7 @@ function getCssThemeBackgroundProperties(appearance: ThemeAppearance) {
* pollute the document with in-line styles. * pollute the document with in-line styles.
*/ */
function getOrCreateStyleElement(id: string) { function getOrCreateStyleElement(id: string) {
let style = document.head.querySelector(id); let style = document.head.querySelector(`#${id}`);
if (style) { return style; } if (style) { return style; }
style = document.createElement('style'); style = document.createElement('style');
style.setAttribute('id', id); style.setAttribute('id', id);

@ -1,6 +1,6 @@
import {findLinks} from 'app/client/lib/textUtils'; import {findLinks} from 'app/client/lib/textUtils';
import { sameDocumentUrlState, urlState } from 'app/client/models/gristUrlState'; import { sameDocumentUrlState, urlState } from 'app/client/models/gristUrlState';
import { colors, hideInPrintView, testId, theme } from 'app/client/ui2018/cssVars'; import { hideInPrintView, testId, theme } from 'app/client/ui2018/cssVars';
import {cssIconBackground, icon} from 'app/client/ui2018/icons'; import {cssIconBackground, icon} from 'app/client/ui2018/icons';
import { CellValue } from 'app/plugin/GristData'; import { CellValue } from 'app/plugin/GristData';
import { dom, DomArg, IDomArgs, Observable, styled } from 'grainjs'; import { dom, DomArg, IDomArgs, Observable, styled } from 'grainjs';
@ -95,7 +95,7 @@ const cssMaybeWrap = styled('span', `
// A gentle transition effect on hover in, and the same effect on hover out with a little delay. // A gentle transition effect on hover in, and the same effect on hover out with a little delay.
export const cssHoverIn = (parentClass: string) => styled('span', ` export const cssHoverIn = (parentClass: string) => styled('span', `
--icon-color: var(--grist-actual-cell-color, ${colors.lightGreen}); --icon-color: var(--grist-actual-cell-color, ${theme.link});
margin: -1px 2px 2px 0; margin: -1px 2px 2px 0;
border-radius: 3px; border-radius: 3px;
transition-property: background-color; transition-property: background-color;
@ -103,7 +103,7 @@ export const cssHoverIn = (parentClass: string) => styled('span', `
transition-duration: 150ms; transition-duration: 150ms;
transition-delay: 90ms; transition-delay: 90ms;
.${parentClass}:hover & { .${parentClass}:hover & {
--icon-background: ${colors.lightGreen}; --icon-background: ${theme.link};
--icon-color: white; --icon-color: white;
transition-duration: 80ms; transition-duration: 80ms;
transition-delay: 0ms; transition-delay: 0ms;
@ -113,5 +113,5 @@ export const cssHoverIn = (parentClass: string) => styled('span', `
const cssHoverInText = cssHoverIn(cssMaybeWrap.className); const cssHoverInText = cssHoverIn(cssMaybeWrap.className);
const linkColor = styled('span', ` const linkColor = styled('span', `
color: var(--grist-actual-cell-color, ${colors.lightGreen});; color: var(--grist-actual-cell-color, ${theme.link});
`); `);

@ -178,7 +178,7 @@ const cssPageInitial = styled('div', `
&-emoji { &-emoji {
background-color: ${theme.pageInitialsEmojiBg}; background-color: ${theme.pageInitialsEmojiBg};
box-shadow: 0 0 0 1px var(--grist-theme-left-panel-page-emoji-outline, var(--grist-color-dark-grey)); box-shadow: 0 0 0 1px ${theme.pageInitialsEmojiOutline};
font-size: 15px; font-size: 15px;
overflow: hidden; overflow: hidden;
color: ${theme.text}; color: ${theme.text};

@ -42,8 +42,8 @@ export const cssSelectBtn = styled('div', `
} }
&.disabled, &-disabled { &.disabled, &-disabled {
--icon-color: ${theme.selectButtonDisabledFg}; opacity: 0.4;
color: ${theme.selectButtonDisabledFg}; pointer-events: none;
cursor: pointer; cursor: default;
} }
`); `);

@ -1,20 +1,20 @@
var dispose = require('../lib/dispose'); var dispose = require('../lib/dispose');
const {theme} = require('app/client/ui2018/cssVars');
const {CellStyle} = require('app/client/widgets/CellStyle'); const {CellStyle} = require('app/client/widgets/CellStyle');
const {dom} = require('grainjs'); const {dom} = require('grainjs');
/** /**
* AbstractWidget - The base of the inheritance tree for widgets. * AbstractWidget - The base of the inheritance tree for widgets.
* @param {Function} field - The RowModel for this view field. * @param {Function} field - The RowModel for this view field.
* @param {string|undefined} options.defaultTextColor - A hex value to set the default text color * @param {string|undefined} options.defaultTextColor - CSS value of the default
* for the widget. Omit defaults to '#000000'. * text color for the widget. Defaults to the current theme's cell fg color.
*
*/ */
function AbstractWidget(field, opts = {}) { function AbstractWidget(field, opts = {}) {
this.field = field; this.field = field;
this.options = field.widgetOptionsJson; this.options = field.widgetOptionsJson;
const {defaultTextColor = '#000000'} = opts;
this.defaultTextColor = defaultTextColor;
this.valueFormatter = this.field.visibleColFormatter; this.valueFormatter = this.field.visibleColFormatter;
this.defaultTextColor = opts.defaultTextColor || '#000000'; this.defaultTextColor = opts.defaultTextColor ?? theme.cellFg.toString();
} }
dispose.makeDisposable(AbstractWidget); dispose.makeDisposable(AbstractWidget);

@ -9,7 +9,7 @@ import {selectFiles, uploadFiles} from 'app/client/lib/uploads';
import {DocData} from 'app/client/models/DocData'; import {DocData} from 'app/client/models/DocData';
import {MetaTableData} from 'app/client/models/TableData'; import {MetaTableData} from 'app/client/models/TableData';
import {basicButton, basicButtonLink, cssButtonGroup} from 'app/client/ui2018/buttons'; 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 {editableLabel} from 'app/client/ui2018/editableLabel';
import {icon} from 'app/client/ui2018/icons'; import {icon} from 'app/client/ui2018/icons';
import {IModalControl, modal} from 'app/client/ui2018/modals'; import {IModalControl, modal} from 'app/client/ui2018/modals';
@ -315,12 +315,12 @@ const cssCloseButton = styled('div', `
padding: 6px; padding: 6px;
border-radius: 32px; border-radius: 32px;
cursor: pointer; cursor: pointer;
background-color: ${colors.light}; background-color: ${theme.attachmentsEditorButtonBg};
--icon-color: ${colors.lightGreen}; --icon-color: ${theme.attachmentsEditorButtonFg};
&:hover { &:hover {
background-color: ${colors.mediumGreyOpaque}; background-color: ${theme.attachmentsEditorButtonHoverBg};
--icon-color: ${colors.darkGreen}; --icon-color: ${theme.attachmentsEditorButtonHoverFg};
} }
`); `);
@ -336,10 +336,10 @@ const cssTitle = styled('div', `
overflow: hidden; overflow: hidden;
&:hover { &:hover {
outline: 1px solid ${colors.slate}; outline: 1px solid ${theme.lightText};
} }
&:focus-within { &:focus-within {
outline: 1px solid ${colors.darkGreen}; outline: 1px solid ${theme.controlFg};
} }
`); `);
@ -362,13 +362,14 @@ const cssFileButtons = styled(cssButtonGroup, `
`); `);
const cssButton = styled(basicButton, ` const cssButton = styled(basicButton, `
background-color: ${colors.light}; color: ${theme.attachmentsEditorButtonFg};
background-color: ${theme.attachmentsEditorButtonBg};
font-weight: normal; font-weight: normal;
padding: 0 16px; padding: 0 16px;
border-top: none; border-top: none;
border-right: none; border-right: none;
border-bottom: none; border-bottom: none;
border-left: 1px solid ${colors.darkGrey}; border-left: 1px solid ${theme.attachmentsEditorButtonBorder};
display: flex; display: flex;
align-items: center; align-items: center;
@ -376,13 +377,14 @@ const cssButton = styled(basicButton, `
border: none; border: none;
} }
&:hover { &:hover {
background-color: ${colors.mediumGreyOpaque}; color: ${theme.attachmentsEditorButtonHoverFg};
border-color: ${colors.darkGrey}; background-color: ${theme.attachmentsEditorButtonHoverBg};
border-color: ${theme.attachmentsEditorButtonBorder};
} }
`); `);
const cssButtonIcon = styled(icon, ` const cssButtonIcon = styled(icon, `
--icon-color: ${colors.slate}; --icon-color: ${theme.attachmentsEditorButtonIcon};
margin-right: 4px; margin-right: 4px;
`); `);
@ -397,11 +399,11 @@ const cssNextArrow = styled('div', `
padding: 6px; padding: 6px;
border-radius: 32px; border-radius: 32px;
cursor: pointer; cursor: pointer;
background-color: ${colors.lightGreen}; background-color: ${theme.controlPrimaryBg};
--icon-color: ${colors.light}; --icon-color: ${theme.controlPrimaryFg};
&:hover { &:hover {
background-color: ${colors.darkGreen}; background-color: ${theme.controlPrimaryHoverBg};
} }
&-left { &-left {
transform: rotateY(180deg); transform: rotateY(180deg);
@ -453,7 +455,7 @@ const cssDetails = styled('div', `
`); `);
const cssDragArea = styled(cssContent, ` const cssDragArea = styled(cssContent, `
border: 2px dashed ${colors.mediumGreyOpaque}; border: 2px dashed ${theme.attachmentsEditorBorder};
height: calc(100% - 96px); height: calc(100% - 96px);
margin-top: 64px; margin-top: 64px;
padding: 0px; padding: 0px;

@ -3,7 +3,7 @@ import * as commands from 'app/client/components/commands';
import {dragOverClass} from 'app/client/lib/dom'; import {dragOverClass} from 'app/client/lib/dom';
import {selectFiles, uploadFiles} from 'app/client/lib/uploads'; import {selectFiles, uploadFiles} from 'app/client/lib/uploads';
import {cssRow} from 'app/client/ui/RightPanelStyles'; 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 {NewAbstractWidget} from 'app/client/widgets/NewAbstractWidget';
import {encodeQueryParams} from 'app/common/gutil'; import {encodeQueryParams} from 'app/common/gutil';
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec'; import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
@ -191,16 +191,16 @@ const cssAttachmentIcon = styled('div.glyphicon.glyphicon-paperclip', `
top: 2px; top: 2px;
left: 2px; left: 2px;
padding: 2px; padding: 2px;
background-color: #D0D0D0; background-color: ${theme.attachmentsCellIconBg};
color: white; color: ${theme.attachmentsCellIconFg};
border-radius: 2px; border-radius: 2px;
border: none; border: none;
cursor: pointer; cursor: pointer;
box-shadow: 0 0 0 1px white; box-shadow: 0 0 0 1px ${theme.cellEditorBg};
z-index: 1; z-index: 1;
&:hover { &:hover {
background-color: #3290BF; background-color: ${theme.attachmentsCellIconHoverBg};
} }
&-hover { &-hover {
@ -222,12 +222,12 @@ const cssAttachmentPreview = styled('div', `
justify-content: center; justify-content: center;
z-index: 0; z-index: 0;
&:hover { &:hover {
border-color: ${colors.lightGreen}; border-color: ${theme.cursor};
} }
`); `);
const cssSizeLabel = styled('div', ` const cssSizeLabel = styled('div', `
color: ${colors.slate}; color: ${theme.lightText};
margin-right: 9px; margin-right: 9px;
`); `);

@ -15,7 +15,7 @@ export class CellStyle extends Disposable {
constructor( constructor(
private _field: ViewFieldRec, private _field: ViewFieldRec,
private _gristDoc: GristDoc, private _gristDoc: GristDoc,
private _defaultTextColor: string private _defaultTextColor: string|undefined
) { ) {
super(); super();
} }
@ -51,21 +51,26 @@ export class CellStyle extends Disposable {
}); });
return colorSelect( return colorSelect(
{ {
textColor: new ColorOption( textColor: new ColorOption({
{ color: headerTextColor, defaultColor: this._defaultTextColor, noneText: 'default' } color: headerTextColor,
), defaultColor: theme.tableHeaderFg.toString(),
fillColor: new ColorOption( noneText: 'default',
{ color: headerFillColor, allowsNone: true, noneText: 'none' } }),
), fillColor: new ColorOption({
color: headerFillColor,
allowsNone: true,
noneText: 'none',
}),
fontBold: headerFontBold, fontBold: headerFontBold,
fontItalic: headerFontItalic, fontItalic: headerFontItalic,
fontUnderline: headerFontUnderline, fontUnderline: headerFontUnderline,
fontStrikethrough: headerFontStrikethrough fontStrikethrough: headerFontStrikethrough
}, { },
onSave: () => options.save(), {
onRevert: () => options.revert(), onSave: () => options.save(),
placeholder: use => use(hasMixedStyle) ? t('Mixed style') : t('Default header style') 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( return colorSelect(
{ {
textColor: new ColorOption( textColor: new ColorOption({
{ color: textColor, defaultColor: this._defaultTextColor, noneText: 'default'} color: textColor,
), defaultColor: this._defaultTextColor,
fillColor: new ColorOption( noneText: 'default',
{ color: fillColor, allowsNone: true, noneText: 'none'} }),
), fillColor: new ColorOption({
color: fillColor,
allowsNone: true,
noneText: 'none',
}),
fontBold: fontBold, fontBold: fontBold,
fontItalic: fontItalic, fontItalic: fontItalic,
fontUnderline: fontUnderline, fontUnderline: fontUnderline,

@ -42,8 +42,8 @@
position: relative; position: relative;
width: 3px; width: 3px;
height: 12px; height: 12px;
background-color: 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, #606060); border: 1px solid var(--grist-actual-cell-color, var(--grist-theme-toggle-checkbox-fg, #606060));
left: 3px; left: 3px;
top: -5px; top: -5px;
} }
@ -52,7 +52,7 @@
position: relative; position: relative;
width: 3px; width: 3px;
height: 3px; height: 3px;
background-color: 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, #606060); border: 1px solid var(--grist-actual-cell-color, var(--grist-theme-toggle-checkbox-fg, #606060));
top: 7px; top: 7px;
} }

@ -7,7 +7,7 @@ const {ACIndexImpl, buildHighlightedDom} = require('app/client/lib/ACIndex');
const {ChoiceItem, cssChoiceList, cssMatchText, cssPlusButton, const {ChoiceItem, cssChoiceList, cssMatchText, cssPlusButton,
cssPlusIcon} = require('app/client/widgets/ChoiceListEditor'); cssPlusIcon} = require('app/client/widgets/ChoiceListEditor');
const {menuCssClass} = require('app/client/ui2018/menus'); 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 {choiceToken, cssChoiceACItem} = require('app/client/widgets/ChoiceToken');
const {dom, styled} = require('grainjs'); const {dom, styled} = require('grainjs');
const {icon} = require('../ui2018/icons'); const {icon} = require('../ui2018/icons');
@ -34,7 +34,13 @@ _.extend(ChoiceEditor.prototype, TextEditor.prototype);
ChoiceEditor.prototype.getCellValue = function() { ChoiceEditor.prototype.getCellValue = function() {
const selectedItem = this.autocomplete && this.autocomplete.getSelectedItem(); 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) { ChoiceEditor.prototype.renderACItem = function(item, highlightFunc) {
@ -60,7 +66,7 @@ ChoiceEditor.prototype.attach = function(cellElem) {
// Don't create autocomplete if readonly. // Don't create autocomplete if readonly.
if (this.options.readonly) { return; } 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 acIndex = new ACIndexImpl(acItems);
const acOptions = { const acOptions = {
popperOptions: { popperOptions: {
@ -100,7 +106,7 @@ ChoiceEditor.prototype.maybeShowAddNew = function(result, text) {
const trimmedText = text.trim(); const trimmedText = text.trim();
if (!this.enableAddNew || !trimmedText) { return result; } 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)) { if (result.items.find((item) => item.cleanText === addNewItem.cleanText)) {
return result; return result;
} }
@ -112,7 +118,7 @@ ChoiceEditor.prototype.maybeShowAddNew = function(result, text) {
} }
const cssChoiceEditIcon = styled(icon, ` const cssChoiceEditIcon = styled(icon, `
background-color: ${colors.slate}; background-color: ${theme.lightText};
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;

@ -33,17 +33,19 @@ export class ChoiceListCell extends ChoiceTextBox {
if (!val) { return null; } if (!val) { return null; }
// Handle any unexpected values we might get (non-array, or array with non-strings). // Handle any unexpected values we might get (non-array, or array with non-strings).
const tokens: unknown[] = Array.isArray(val) ? val : [val]; const tokens: unknown[] = Array.isArray(val) ? val : [val];
return tokens.map(token => return tokens.map(token => {
choiceToken( const isBlank = String(token).trim() === '';
String(token), return choiceToken(
isBlank ? '[Blank]' : String(token),
{ {
...(choiceOptionsByName.get(String(token)) || {}), ...(choiceOptionsByName.get(String(token)) || {}),
invalid: !choiceSet.has(String(token)), invalid: !choiceSet.has(String(token)),
blank: String(token).trim() === '',
}, },
dom.cls(cssToken.className), dom.cls(cssToken.className),
testId('choice-list-cell-token') testId('choice-list-cell-token')
) );
); });
}), }),
); );
} }

@ -21,6 +21,7 @@ export class ChoiceItem implements ACItem, IToken {
constructor( constructor(
public label: string, public label: string,
public isInvalid: boolean, // If set, this token is not one of the valid choices. 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. 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 || []; const choices: string[] = options.field.widgetOptionsJson.peek().choices || [];
this._choiceOptionsByName = options.field.widgetOptionsJson this._choiceOptionsByName = options.field.widgetOptionsJson
.peek().choiceOptions || {}; .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 choiceSet = new Set(choices);
const acIndex = new ACIndexImpl<ChoiceItem>(acItems); 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. // If starting to edit by typing in a string, ignore previous tokens.
const cellValue = decodeObject(options.cellValue); const cellValue = decodeObject(options.cellValue);
const startLabels: unknown[] = options.editValue !== undefined || !Array.isArray(cellValue) ? [] : 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, { this._tokenField = TokenField.ctor<ChoiceItem>().create(this, {
initialValue: startTokens, initialValue: startTokens,
renderToken: item => [ renderToken: item => [
item.label, item.isBlank ? '[Blank]' : item.label,
dom.style('background-color', getRenderFillColor(this._choiceOptionsByName[item.label])), dom.style('background-color', getRenderFillColor(this._choiceOptionsByName[item.label])),
dom.style('color', getRenderTextColor(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-bold', this._choiceOptionsByName[item.label]?.fontBold ?? false),
dom.cls('font-underline', this._choiceOptionsByName[item.label]?.fontUnderline ?? false), dom.cls('font-underline', this._choiceOptionsByName[item.label]?.fontUnderline ?? false),
dom.cls('font-italic', this._choiceOptionsByName[item.label]?.fontItalic ?? false), dom.cls('font-italic', this._choiceOptionsByName[item.label]?.fontItalic ?? false),
dom.cls('font-strikethrough', this._choiceOptionsByName[item.label]?.fontStrikethrough ?? 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, acOptions,
openAutocompleteOnFocus: true, openAutocompleteOnFocus: true,
readonly : options.readonly, readonly : options.readonly,
@ -222,7 +228,7 @@ export class ChoiceListEditor extends NewBaseEditor {
const trimmedText = text.trim(); const trimmedText = text.trim();
if (!this._enableAddNew || !trimmedText) { return result; } 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)) { if (result.items.find((item) => item.cleanText === addNewItem.cleanText)) {
return result; return result;
} }
@ -277,7 +283,7 @@ export const cssToken = styled(tokenFieldStyles.cssToken, `
white-space: pre; white-space: pre;
&.selected { &.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', ` const cssReadonlyStyle = styled('div', `
padding-left: 16px; padding-left: 16px;
background: white; background: ${theme.cellEditorBg};
`); `);
export const cssMatchText = styled('span', ` export const cssMatchText = styled('span', `
@ -349,20 +355,21 @@ export const cssMatchText = styled('span', `
`); `);
export const cssPlusButton = styled('div', ` export const cssPlusButton = styled('div', `
display: inline-block; display: flex;
width: 20px; width: 20px;
height: 20px; height: 20px;
border-radius: 20px; border-radius: 20px;
margin-right: 8px; margin-right: 8px;
text-align: center; align-items: center;
background-color: ${colors.lightGreen}; justify-content: center;
color: ${colors.light}; background-color: ${theme.autocompleteAddNewCircleBg};
color: ${theme.autocompleteAddNewCircleFg};
.selected > & { .selected > & {
background-color: ${colors.darkGreen}; background-color: ${theme.autocompleteAddNewCircleSelectedBg};
} }
`); `);
export const cssPlusIcon = styled(icon, ` 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 {cssBlockedCursor} from 'app/client/ui/RightPanelStyles';
import {basicButton, primaryButton} from 'app/client/ui2018/buttons'; import {basicButton, primaryButton} from 'app/client/ui2018/buttons';
import {colorButton, ColorOption} from 'app/client/ui2018/ColorSelect'; 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 {editableLabel} from 'app/client/ui2018/editableLabel';
import {icon} from 'app/client/ui2018/icons'; import {icon} from 'app/client/ui2018/icons';
import {ChoiceOptionsByName, IChoiceOptions} from 'app/client/widgets/ChoiceTextBox'; import {ChoiceOptionsByName, IChoiceOptions} from 'app/client/widgets/ChoiceTextBox';
@ -492,7 +492,7 @@ const cssListBoxInactive = styled(cssListBox, `
border: 1px solid ${theme.choiceEntryBorderHover}; border: 1px solid ${theme.choiceEntryBorderHover};
} }
&-disabled { &-disabled {
opacity: 0.6; opacity: 0.4;
} }
`); `);
@ -501,8 +501,8 @@ const cssListRow = styled('div', `
margin-top: 4px; margin-top: 4px;
margin-bottom: 4px; margin-bottom: 4px;
padding: 4px 8px; padding: 4px 8px;
color: ${colors.dark}; color: ${theme.choiceTokenFg};
background-color: ${colors.mediumGreyOpaque}; background-color: ${theme.choiceTokenBg};
border-radius: 3px; border-radius: 3px;
text-overflow: ellipsis; text-overflow: ellipsis;
`); `);
@ -521,7 +521,7 @@ const cssToken = styled(cssListRow, `
cursor: grab; cursor: grab;
&.selected { &.selected {
background-color: ${colors.darkGrey}; background-color: ${theme.choiceTokenSelectedBg};
} }
&.token-dragging { &.token-dragging {
pointer-events: none; pointer-events: none;
@ -619,8 +619,9 @@ const cssDeleteButton = styled('div', `
`); `);
const cssDeleteIcon = styled(icon, ` const cssDeleteIcon = styled(icon, `
--icon-color: ${colors.slate}; --icon-color: ${theme.text};
opacity: 0.6;
&:hover { &: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 {KoSaveableObservable} from 'app/client/models/modelUtil';
import {Style} from 'app/client/models/Styles'; import {Style} from 'app/client/models/Styles';
import {cssLabel, cssRow} from 'app/client/ui/RightPanelStyles'; 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 {icon} from 'app/client/ui2018/icons';
import {ChoiceListEntry} from 'app/client/widgets/ChoiceListEntry'; 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 {NTextBox} from 'app/client/widgets/NTextBox';
import {Computed, dom, styled} from 'grainjs'; import {Computed, dom, styled} from 'grainjs';
@ -18,11 +18,11 @@ export type ChoiceOptionsByName = Map<string, IChoiceOptions | undefined>;
const t = makeT('ChoiceTextBox'); const t = makeT('ChoiceTextBox');
export function getRenderFillColor(choiceOptions?: IChoiceOptions) { export function getRenderFillColor(choiceOptions?: IChoiceOptions) {
return choiceOptions?.fillColor ?? DEFAULT_FILL_COLOR; return choiceOptions?.fillColor ?? DEFAULT_BACKGROUND_COLOR;
} }
export function getRenderTextColor(choiceOptions?: IChoiceOptions) { 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, ` const cssChoiceEditIcon = styled(icon, `
background-color: ${colors.slate}; background-color: ${theme.lightText};
display: block; display: block;
height: inherit; height: inherit;
`); `);

@ -1,12 +1,13 @@
import {Style} from 'app/client/models/Styles'; 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'; import {dom, DomContents, DomElementArg, styled} from 'grainjs';
export const DEFAULT_FILL_COLOR = colors.mediumGreyOpaque.value!; export const DEFAULT_BACKGROUND_COLOR = theme.choiceTokenBg.toString();
export const DEFAULT_TEXT_COLOR = '#000000'; export const DEFAULT_COLOR = theme.choiceTokenFg.toString();
export interface IChoiceTokenOptions extends Style { export interface IChoiceTokenOptions extends Style {
invalid?: boolean; invalid?: boolean;
blank?: boolean;
} }
/** /**
@ -29,16 +30,17 @@ export function choiceToken(
...args: DomElementArg[] ...args: DomElementArg[]
): DomContents { ): DomContents {
const {fillColor, textColor, fontBold, fontItalic, fontUnderline, const {fillColor, textColor, fontBold, fontItalic, fontUnderline,
fontStrikethrough, invalid} = options; fontStrikethrough, invalid, blank} = options;
return cssChoiceToken( return cssChoiceToken(
label, label,
dom.style('background-color', fillColor ?? DEFAULT_FILL_COLOR), dom.style('background-color', fillColor ?? DEFAULT_BACKGROUND_COLOR),
dom.style('color', textColor ?? DEFAULT_TEXT_COLOR), dom.style('color', textColor ?? DEFAULT_COLOR),
dom.cls('font-bold', fontBold ?? false), dom.cls('font-bold', fontBold ?? false),
dom.cls('font-underline', fontUnderline ?? false), dom.cls('font-underline', fontUnderline ?? false),
dom.cls('font-italic', fontItalic ?? false), dom.cls('font-italic', fontItalic ?? false),
dom.cls('font-strikethrough', fontStrikethrough ?? false), dom.cls('font-strikethrough', fontStrikethrough ?? false),
invalid ? cssChoiceToken.cls('-invalid') : null, invalid ? cssChoiceToken.cls('-invalid') : null,
blank ? cssChoiceToken.cls('-blank') : null,
...args ...args
); );
} }
@ -52,8 +54,12 @@ export const cssChoiceToken = styled('div', `
white-space: pre; white-space: pre;
&-invalid { &-invalid {
background-color: white !important; color: ${theme.choiceTokenInvalidFg} !important;
box-shadow: inset 0 0 0 1px ${colors.error}; 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; cursor: pointer;
&.selected { &.selected {
background-color: ${theme.autocompleteChoiceSelectedBg}; background-color: ${theme.autocompleteItemSelectedBg};
} }
&-with-new { &-with-new {
scroll-margin-bottom: ${ADD_NEW_HEIGHT}; 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)); 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 .prev:hover,
.datepicker .next:hover, .datepicker .next:hover,
.datepicker .datepicker-switch:hover, .datepicker .datepicker-switch:hover,

@ -1,5 +1,5 @@
import {isDesktop} from 'app/client/lib/browserInfo'; 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 {icon} from 'app/client/ui2018/icons';
import {IEditorCommandGroup} from 'app/client/widgets/NewBaseEditor'; import {IEditorCommandGroup} from 'app/client/widgets/NewBaseEditor';
import {dom, styled} from 'grainjs'; import {dom, styled} from 'grainjs';
@ -25,7 +25,7 @@ const cssFinishBtn = styled('div', `
padding: 8px; padding: 8px;
position: absolute; position: absolute;
top: -8px; top: -8px;
--icon-color: white; --icon-color: ${theme.controlPrimaryFg};
`); `);
const cssCancelBtn = styled(cssFinishBtn, ` const cssCancelBtn = styled(cssFinishBtn, `
@ -34,7 +34,7 @@ const cssCancelBtn = styled(cssFinishBtn, `
`); `);
const cssSaveBtn = styled(cssFinishBtn, ` const cssSaveBtn = styled(cssFinishBtn, `
--icon-background-color: ${colors.lightGreen}; --icon-background-color: ${theme.controlPrimaryBg};
right: -40px; right: -40px;
`); `);

@ -1,6 +1,6 @@
import {makeT} from 'app/client/lib/localization'; import {makeT} from 'app/client/lib/localization';
import {ITooltipControl, showTooltip, tooltipCloseButton} from 'app/client/ui/tooltips'; 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 {icon} from 'app/client/ui2018/icons';
import {cssLink} from 'app/client/ui2018/links'; import {cssLink} from 'app/client/ui2018/links';
import {dom, styled} from 'grainjs'; import {dom, styled} from 'grainjs';
@ -29,7 +29,7 @@ export function showTooltipToCreateFormula(editorDom: HTMLElement, convert: () =
const cssConvertTooltip = styled('div', ` const cssConvertTooltip = styled('div', `
display: flex; display: flex;
align-items: center; align-items: center;
--icon-color: ${colors.lightGreen}; --icon-color: ${theme.controlFg};
& > .${cssLink.className} { & > .${cssLink.className} {
margin-left: 8px; margin-left: 8px;

@ -1,14 +1,14 @@
.transform_editor { .transform_editor {
width: 90%; min-height: 28px;
margin: 5px auto; margin: 8px 16px;
border: 1px solid #DDDDDD; 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 { .transform_menu {
padding: 5px 0; padding-bottom: 8px;
margin: 5px;
border-top: 1px solid rgba(200, 200, 200, .3);
border-bottom: 1px solid rgba(200, 200, 200, .3);
} }
.fieldbuilder_settings { .fieldbuilder_settings {

@ -20,6 +20,7 @@ import { CombinedStyle, Style } from 'app/client/models/Styles';
import { COMMENTS } from 'app/client/models/features'; import { COMMENTS } from 'app/client/models/features';
import { FieldSettingsMenu } from 'app/client/ui/FieldMenus'; import { FieldSettingsMenu } from 'app/client/ui/FieldMenus';
import { cssBlockedCursor, cssLabel, cssRow } from 'app/client/ui/RightPanelStyles'; 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 { buttonSelect, cssButtonSelect } from 'app/client/ui2018/buttonSelect';
import { theme } from 'app/client/ui2018/cssVars'; import { theme } from 'app/client/ui2018/cssVars';
import { IOptionFull, menu, select } from 'app/client/ui2018/menus'; 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('tour-type-selector'),
grainjsDom.cls(cssBlockedCursor.className, use => grainjsDom.cls(cssBlockedCursor.className, use =>
use(this.origColumn.disableModifyBase) || use(this.origColumn.disableModifyBase) ||
use(this._isTransformingFormula) ||
(use(this.field.config.multiselect) && !use(allFormulas)) (use(this.field.config.multiselect) && !use(allFormulas))
), ),
), ),
@ -415,18 +417,18 @@ export class FieldBuilder extends Disposable {
this.columnTransform.finalize().catch(reportError); this.columnTransform.finalize().catch(reportError);
} }
}), }),
kf.row( cssRow(
15, kf.label(t('Apply Formula to Data')), textButton(t('Apply Formula to Data'),
3, kf.buttonGroup( dom.on('click', () => transformButton(true)),
kf.checkButton(transformButton, kd.hide(this._isTransformingFormula),
dom('span.glyphicon.glyphicon-flash'), kd.boolAttr('disabled', () =>
dom.testId("FieldBuilder_editTransform"), this._isTransformingType() ||
testId('edit-transform'), this.origColumn.isFormula() ||
kd.toggleClass('disabled', () => this._isTransformingType() || this.origColumn.isFormula() || this.origColumn.disableModifyBase() ||
this.origColumn.disableModifyBase()) this.field.config.multiselect()),
) dom.testId("FieldBuilder_editTransform"),
) testId('edit-transform'),
), )),
kd.maybe(this._isTransformingFormula, () => { kd.maybe(this._isTransformingFormula, () => {
return this.columnTransform!.buildDom(); return this.columnTransform!.buildDom();
}) })

@ -1,7 +1,7 @@
import { DataRowModel } from 'app/client/models/DataRowModel'; import { DataRowModel } from 'app/client/models/DataRowModel';
import { ViewFieldRec } from 'app/client/models/entities/ViewFieldRec'; import { ViewFieldRec } from 'app/client/models/entities/ViewFieldRec';
import { constructUrl } from 'app/client/models/gristUrlState'; 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 { cssIconBackground, icon } from 'app/client/ui2018/icons';
import { cssHoverIn, gristLink } from 'app/client/ui2018/links'; import { cssHoverIn, gristLink } from 'app/client/ui2018/links';
import { NTextBox } from 'app/client/widgets/NTextBox'; import { NTextBox } from 'app/client/widgets/NTextBox';
@ -15,7 +15,7 @@ import { Computed, dom, styled } from 'grainjs';
*/ */
export class HyperLinkTextBox extends NTextBox { export class HyperLinkTextBox extends NTextBox {
constructor(field: ViewFieldRec) { constructor(field: ViewFieldRec) {
super(field, {defaultTextColor: colors.lightGreen.value}); super(field, {defaultTextColor: theme.link.toString()});
} }
public buildDom(row: DataRowModel) { public buildDom(row: DataRowModel) {
@ -49,7 +49,7 @@ function _formatValue(value: CellValue): string {
} }
const cssFieldClip = styled('div.field_clip', ` 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); const cssHoverOnField = cssHoverIn(cssFieldClip.className);

@ -7,6 +7,7 @@ import {GristDoc} from 'app/client/components/GristDoc';
import {DocData} from 'app/client/models/DocData'; import {DocData} from 'app/client/models/DocData';
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec'; import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
import {SaveableObjObservable} from 'app/client/models/modelUtil'; import {SaveableObjObservable} from 'app/client/models/modelUtil';
import {theme} from 'app/client/ui2018/cssVars';
import {CellStyle} from 'app/client/widgets/CellStyle'; import {CellStyle} from 'app/client/widgets/CellStyle';
import {BaseFormatter} from 'app/common/ValueFormatter'; import {BaseFormatter} from 'app/common/ValueFormatter';
import { import {
@ -19,7 +20,10 @@ import {
} from 'grainjs'; } from 'grainjs';
export interface Options { 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; defaultTextColor?: string;
} }
@ -44,13 +48,13 @@ export abstract class NewAbstractWidget extends Disposable {
protected valueFormatter: Observable<BaseFormatter>; protected valueFormatter: Observable<BaseFormatter>;
protected textColor: Observable<string>; protected textColor: Observable<string>;
protected fillColor: 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(); super();
this.options = field.widgetOptionsJson; this.options = field.widgetOptionsJson;
this.valueFormatter = fromKo(field.formatter); this.valueFormatter = fromKo(field.formatter);
this.defaultTextColor = opts?.defaultTextColor || '#000000';
} }
/** /**

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

@ -2,7 +2,7 @@ import {makeT} from 'app/client/lib/localization';
import {DataRowModel} from 'app/client/models/DataRowModel'; import {DataRowModel} from 'app/client/models/DataRowModel';
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec'; import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
import {cssLabel, cssRow} from 'app/client/ui/RightPanelStyles'; 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 {icon} from 'app/client/ui2018/icons';
import {IOptionFull, select} from 'app/client/ui2018/menus'; import {IOptionFull, select} from 'app/client/ui2018/menus';
import {NTextBox} from 'app/client/widgets/NTextBox'; import {NTextBox} from 'app/client/widgets/NTextBox';
@ -119,12 +119,12 @@ export class Reference extends NTextBox {
const cssRefIcon = styled(icon, ` const cssRefIcon = styled(icon, `
float: left; float: left;
background-color: ${colors.slate}; --icon-color: ${theme.lightText};
margin: -1px 2px 2px 0; margin: -1px 2px 2px 0;
`); `);
const cssRef = styled('div.field_clip', ` const cssRef = styled('div.field_clip', `
&-blank { &-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 { Autocomplete } from 'app/client/lib/autocomplete';
import { ICellItem } from 'app/client/models/ColumnACIndexes'; import { ICellItem } from 'app/client/models/ColumnACIndexes';
import { reportError } from 'app/client/models/errors'; 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 { icon } from 'app/client/ui2018/icons';
import { menuCssClass } from 'app/client/ui2018/menus'; import { menuCssClass } from 'app/client/ui2018/menus';
import { FieldOptions } from 'app/client/widgets/NewBaseEditor'; import { FieldOptions } from 'app/client/widgets/NewBaseEditor';
@ -181,6 +181,8 @@ const cssRefItem = styled('li', `
scroll-margin-bottom: ${addNewHeight}; scroll-margin-bottom: ${addNewHeight};
} }
&-new { &-new {
display: flex;
align-items: center;
color: ${theme.lightText}; color: ${theme.lightText};
position: sticky; position: sticky;
bottom: 0px; bottom: 0px;
@ -195,26 +197,27 @@ const cssRefItem = styled('li', `
`); `);
export const cssPlusButton = styled('div', ` export const cssPlusButton = styled('div', `
display: inline-block; display: flex;
width: 20px; width: 20px;
height: 20px; height: 20px;
border-radius: 20px; border-radius: 20px;
margin-right: 8px; margin-right: 8px;
text-align: center; align-items: center;
background-color: ${colors.lightGreen}; justify-content: center;
color: ${colors.light}; background-color: ${theme.autocompleteAddNewCircleBg};
color: ${theme.autocompleteAddNewCircleFg};
.selected > & { .selected > & {
background-color: ${colors.darkGreen}; background-color: ${theme.autocompleteAddNewCircleSelectedBg};
} }
`); `);
export const cssPlusIcon = styled(icon, ` export const cssPlusIcon = styled(icon, `
background-color: ${colors.light}; background-color: ${theme.autocompleteAddNewCircleFg};
`); `);
const cssRefEditIcon = styled(icon, ` const cssRefEditIcon = styled(icon, `
background-color: ${colors.slate}; background-color: ${theme.lightText};
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;

@ -1,5 +1,5 @@
import {DataRowModel} from 'app/client/models/DataRowModel'; 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 {isList} from 'app/common/gristTypes';
import {dom} from 'grainjs'; import {dom} from 'grainjs';
import {cssChoiceList, cssToken} from "app/client/widgets/ChoiceListCell"; import {cssChoiceList, cssToken} from "app/client/widgets/ChoiceListCell";
@ -51,7 +51,7 @@ export class ReferenceList extends Reference {
return choiceToken( return choiceToken(
isBlankReference ? '[Blank]' : token, isBlankReference ? '[Blank]' : token,
{ {
textColor: isBlankReference ? colors.slate.value : undefined blank: isBlankReference,
}, },
dom.cls(cssToken.className), dom.cls(cssToken.className),
testId('ref-list-cell-token') testId('ref-list-cell-token')

@ -298,7 +298,6 @@ const cssTokenField = styled(tokenFieldStyles.cssTokenField, `
padding: 0 3px; padding: 0 3px;
height: min-content; height: min-content;
min-height: 22px; min-height: 22px;
color: black;
flex-wrap: wrap; flex-wrap: wrap;
`); `);
@ -307,13 +306,14 @@ const cssToken = styled(tokenFieldStyles.cssToken, `
margin: 2px; margin: 2px;
line-height: 16px; line-height: 16px;
white-space: pre; white-space: pre;
color: ${theme.choiceTokenFg};
&.selected { &.selected {
box-shadow: inset 0 0 0 1px ${colors.lightGreen}; box-shadow: inset 0 0 0 1px ${theme.choiceTokenSelectedBorder};
} }
&-blank { &-blank {
color: ${colors.slate}; color: ${theme.lightText};
} }
`); `);

@ -12,7 +12,7 @@
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background-color: #ccc; background-color: var(--grist-theme-switch-slider-fg, #ccc);
border-radius: 17px; border-radius: 17px;
} }
@ -28,7 +28,7 @@
width: 13px; width: 13px;
left: 2px; left: 2px;
bottom: 2px; bottom: 2px;
background-color: white; background-color: var(--grist-theme-switch-circle-fg, white);
border-radius: 17px; border-radius: 17px;
} }

@ -91,6 +91,10 @@
line-height: inherit; line-height: inherit;
} }
.celleditor_text_editor::placeholder {
color: var(--grist-theme-cell-editor-placeholder-fg, unset);
}
.celleditor_content_measure { .celleditor_content_measure {
position: absolute; position: absolute;
left: 0; left: 0;

@ -3,6 +3,7 @@ import { DataRowModel } from 'app/client/models/DataRowModel';
import { ViewFieldRec } from 'app/client/models/entities/ViewFieldRec'; import { ViewFieldRec } from 'app/client/models/entities/ViewFieldRec';
import { KoSaveableObservable } from 'app/client/models/modelUtil'; import { KoSaveableObservable } from 'app/client/models/modelUtil';
import { NewAbstractWidget, Options } from 'app/client/widgets/NewAbstractWidget'; import { NewAbstractWidget, Options } from 'app/client/widgets/NewAbstractWidget';
import { theme } from 'app/client/ui2018/cssVars';
import { dom } from 'grainjs'; import { dom } from 'grainjs';
/** /**
@ -28,7 +29,7 @@ abstract class ToggleBase extends NewAbstractWidget {
export class ToggleCheckBox extends ToggleBase { export class ToggleCheckBox extends ToggleBase {
constructor(field: ViewFieldRec, _options: Options = {}) { constructor(field: ViewFieldRec, _options: Options = {}) {
super(field, {defaultTextColor: '#606060'}); super(field, {defaultTextColor: theme.toggleCheckboxFg.toString()});
} }
public buildDom(row: DataRowModel) { public buildDom(row: DataRowModel) {

@ -77,8 +77,6 @@ export const ThemeColors = t.iface([], {
"tooltip-close-button-fg": "string", "tooltip-close-button-fg": "string",
"tooltip-close-button-hover-fg": "string", "tooltip-close-button-hover-fg": "string",
"tooltip-close-button-hover-bg": "string", "tooltip-close-button-hover-bg": "string",
"tooltip-popup-header-fg": "string",
"tooltip-popup-header-bg": "string",
"modal-bg": "string", "modal-bg": "string",
"modal-backdrop": "string", "modal-backdrop": "string",
"modal-border": "string", "modal-border": "string",
@ -102,6 +100,7 @@ export const ThemeColors = t.iface([], {
"hover": "string", "hover": "string",
"hover-light": "string", "hover-light": "string",
"cell-editor-fg": "string", "cell-editor-fg": "string",
"cell-editor-placeholder-fg": "string",
"cell-editor-bg": "string", "cell-editor-bg": "string",
"cursor": "string", "cursor": "string",
"cursor-inactive": "string", "cursor-inactive": "string",
@ -111,7 +110,6 @@ export const ThemeColors = t.iface([], {
"table-header-bg": "string", "table-header-bg": "string",
"table-header-selected-bg": "string", "table-header-selected-bg": "string",
"table-header-border": "string", "table-header-border": "string",
"table-header-border-dark": "string",
"table-body-bg": "string", "table-body-bg": "string",
"table-body-border": "string", "table-body-border": "string",
"table-add-new-bg": "string", "table-add-new-bg": "string",
@ -119,6 +117,7 @@ export const ThemeColors = t.iface([], {
"table-frozen-columns-border": "string", "table-frozen-columns-border": "string",
"table-drag-drop-indicator": "string", "table-drag-drop-indicator": "string",
"table-drag-drop-shadow": "string", "table-drag-drop-shadow": "string",
"table-cell-summary-bg": "string",
"card-compact-widget-bg": "string", "card-compact-widget-bg": "string",
"card-compact-record-bg": "string", "card-compact-record-bg": "string",
"card-blocks-bg": "string", "card-blocks-bg": "string",
@ -153,13 +152,13 @@ export const ThemeColors = t.iface([], {
"control-primary-fg": "string", "control-primary-fg": "string",
"control-primary-bg": "string", "control-primary-bg": "string",
"control-secondary-fg": "string", "control-secondary-fg": "string",
"control-secondary-disabled-fg": "string",
"control-hover-fg": "string", "control-hover-fg": "string",
"control-primary-hover-bg": "string", "control-primary-hover-bg": "string",
"control-secondary-hover-fg": "string", "control-secondary-hover-fg": "string",
"control-secondary-hover-bg": "string", "control-secondary-hover-bg": "string",
"control-disabled-fg": "string", "control-disabled-fg": "string",
"control-disabled-bg": "string", "control-disabled-bg": "string",
"control-primary-disabled": "string",
"control-border": "string", "control-border": "string",
"checkbox-bg": "string", "checkbox-bg": "string",
"checkbox-disabled-bg": "string", "checkbox-disabled-bg": "string",
@ -206,7 +205,6 @@ export const ThemeColors = t.iface([], {
"right-panel-disabled-overlay": "string", "right-panel-disabled-overlay": "string",
"right-panel-toggle-button-enabled-fg": "string", "right-panel-toggle-button-enabled-fg": "string",
"right-panel-toggle-button-enabled-bg": "string", "right-panel-toggle-button-enabled-bg": "string",
"right-panel-toggle-button-enabled-hover-fg": "string",
"right-panel-toggle-button-disabled-fg": "string", "right-panel-toggle-button-disabled-fg": "string",
"right-panel-toggle-button-disabled-bg": "string", "right-panel-toggle-button-disabled-bg": "string",
"right-panel-field-settings-bg": "string", "right-panel-field-settings-bg": "string",
@ -218,6 +216,9 @@ export const ThemeColors = t.iface([], {
"document-history-snapshot-border": "string", "document-history-snapshot-border": "string",
"document-history-activity-text": "string", "document-history-activity-text": "string",
"document-history-activity-text-light": "string", "document-history-activity-text-light": "string",
"document-history-table-header-fg": "string",
"document-history-table-border": "string",
"document-history-table-border-light": "string",
"accent-icon": "string", "accent-icon": "string",
"accent-border": "string", "accent-border": "string",
"accent-text": "string", "accent-text": "string",
@ -232,12 +233,19 @@ export const ThemeColors = t.iface([], {
"input-focus": "string", "input-focus": "string",
"input-readonly-bg": "string", "input-readonly-bg": "string",
"input-readonly-border": "string", "input-readonly-border": "string",
"choice-token-fg": "string",
"choice-token-blank-fg": "string",
"choice-token-bg": "string",
"choice-token-selected-bg": "string",
"choice-token-selected-border": "string",
"choice-token-invalid-fg": "string",
"choice-token-invalid-bg": "string",
"choice-token-invalid-border": "string",
"choice-entry-bg": "string", "choice-entry-bg": "string",
"choice-entry-border": "string", "choice-entry-border": "string",
"choice-entry-border-hover": "string", "choice-entry-border-hover": "string",
"select-button-fg": "string", "select-button-fg": "string",
"select-button-placeholder-fg": "string", "select-button-placeholder-fg": "string",
"select-button-disabled-fg": "string",
"select-button-bg": "string", "select-button-bg": "string",
"select-button-border": "string", "select-button-border": "string",
"select-button-border-invalid": "string", "select-button-border-invalid": "string",
@ -253,12 +261,12 @@ export const ThemeColors = t.iface([], {
"menu-item-disabled-fg": "string", "menu-item-disabled-fg": "string",
"menu-item-icon-fg": "string", "menu-item-icon-fg": "string",
"menu-item-icon-selected-fg": "string", "menu-item-icon-selected-fg": "string",
"menu-item-link-fg": "string",
"menu-item-link-selected-fg": "string",
"menu-item-link-selected-bg": "string",
"autocomplete-match-text": "string", "autocomplete-match-text": "string",
"autocomplete-selected-match-text": "string", "autocomplete-selected-match-text": "string",
"autocomplete-item-selected-bg": "string", "autocomplete-item-selected-bg": "string",
"autocomplete-add-new-circle-fg": "string",
"autocomplete-add-new-circle-bg": "string",
"autocomplete-add-new-circle-selected-bg": "string",
"search-border": "string", "search-border": "string",
"search-prev-next-button-fg": "string", "search-prev-next-button-fg": "string",
"search-prev-next-button-bg": "string", "search-prev-next-button-bg": "string",
@ -318,6 +326,7 @@ export const ThemeColors = t.iface([], {
"button-group-fg": "string", "button-group-fg": "string",
"button-group-light-fg": "string", "button-group-light-fg": "string",
"button-group-bg": "string", "button-group-bg": "string",
"button-group-bg-hover": "string",
"button-group-icon": "string", "button-group-icon": "string",
"button-group-border": "string", "button-group-border": "string",
"button-group-border-hover": "string", "button-group-border-hover": "string",
@ -328,6 +337,7 @@ export const ThemeColors = t.iface([], {
"access-rules-table-header-fg": "string", "access-rules-table-header-fg": "string",
"access-rules-table-header-bg": "string", "access-rules-table-header-bg": "string",
"access-rules-table-body-fg": "string", "access-rules-table-body-fg": "string",
"access-rules-table-body-light-fg": "string",
"access-rules-table-border": "string", "access-rules-table-border": "string",
"access-rules-column-list-border": "string", "access-rules-column-list-border": "string",
"access-rules-column-item-fg": "string", "access-rules-column-item-fg": "string",
@ -383,7 +393,6 @@ export const ThemeColors = t.iface([], {
"color-select-shadow": "string", "color-select-shadow": "string",
"color-select-font-options-border": "string", "color-select-font-options-border": "string",
"color-select-font-option-fg": "string", "color-select-font-option-fg": "string",
"color-select-font-option-bg": "string",
"color-select-font-option-bg-hover": "string", "color-select-font-option-bg-hover": "string",
"color-select-font-option-fg-selected": "string", "color-select-font-option-fg-selected": "string",
"color-select-font-option-bg-selected": "string", "color-select-font-option-bg-selected": "string",
@ -400,9 +409,30 @@ export const ThemeColors = t.iface([], {
"login-page-bg": "string", "login-page-bg": "string",
"login-page-backdrop": "string", "login-page-backdrop": "string",
"login-page-line": "string", "login-page-line": "string",
"login-page-google-button-fg": "string",
"login-page-google-button-bg": "string",
"login-page-google-button-bg-hover": "string",
"login-page-google-button-border": "string",
"formula-assistant-header-bg": "string", "formula-assistant-header-bg": "string",
"formula-assistant-border": "string", "formula-assistant-border": "string",
"formula-assistant-preformatted-text-bg": "string", "formula-assistant-preformatted-text-bg": "string",
"attachments-editor-button-fg": "string",
"attachments-editor-button-hover-fg": "string",
"attachments-editor-button-bg": "string",
"attachments-editor-button-hover-bg": "string",
"attachments-editor-button-border": "string",
"attachments-editor-button-icon": "string",
"attachments-editor-border": "string",
"attachments-cell-icon-fg": "string",
"attachments-cell-icon-bg": "string",
"attachments-cell-icon-hover-bg": "string",
"switch-slider-fg": "string",
"switch-circle-fg": "string",
"announcement-popup-fg": "string",
"announcement-popup-bg": "string",
"scroll-shadow": "string",
"toggle-checkbox-fg": "string",
"numeric-spinner-fg": "string",
}); });
const exportedTypeSuite: t.ITypeSuite = { const exportedTypeSuite: t.ITypeSuite = {

@ -89,8 +89,6 @@ export interface ThemeColors {
'tooltip-close-button-fg': string; 'tooltip-close-button-fg': string;
'tooltip-close-button-hover-fg': string; 'tooltip-close-button-hover-fg': string;
'tooltip-close-button-hover-bg': string; 'tooltip-close-button-hover-bg': string;
'tooltip-popup-header-fg': string;
'tooltip-popup-header-bg': string;
/* Modals */ /* Modals */
'modal-bg': string; 'modal-bg': string;
@ -128,6 +126,7 @@ export interface ThemeColors {
/* Cell Editor */ /* Cell Editor */
'cell-editor-fg': string; 'cell-editor-fg': string;
'cell-editor-placeholder-fg': string;
'cell-editor-bg': string; 'cell-editor-bg': string;
/* Cursor */ /* Cursor */
@ -141,7 +140,6 @@ export interface ThemeColors {
'table-header-bg': string; 'table-header-bg': string;
'table-header-selected-bg': string; 'table-header-selected-bg': string;
'table-header-border': string; 'table-header-border': string;
'table-header-border-dark': string;
'table-body-bg': string; 'table-body-bg': string;
'table-body-border': string; 'table-body-border': string;
'table-add-new-bg': string; 'table-add-new-bg': string;
@ -149,6 +147,7 @@ export interface ThemeColors {
'table-frozen-columns-border': string; 'table-frozen-columns-border': string;
'table-drag-drop-indicator': string; 'table-drag-drop-indicator': string;
'table-drag-drop-shadow': string; 'table-drag-drop-shadow': string;
'table-cell-summary-bg': string;
/* Cards */ /* Cards */
'card-compact-widget-bg': string; 'card-compact-widget-bg': string;
@ -197,13 +196,13 @@ export interface ThemeColors {
'control-primary-fg': string; 'control-primary-fg': string;
'control-primary-bg': string; 'control-primary-bg': string;
'control-secondary-fg': string; 'control-secondary-fg': string;
'control-secondary-disabled-fg': string;
'control-hover-fg': string; 'control-hover-fg': string;
'control-primary-hover-bg': string; 'control-primary-hover-bg': string;
'control-secondary-hover-fg': string; 'control-secondary-hover-fg': string;
'control-secondary-hover-bg': string; 'control-secondary-hover-bg': string;
'control-disabled-fg': string; 'control-disabled-fg': string;
'control-disabled-bg': string; 'control-disabled-bg': string;
'control-primary-disabled': string;
'control-border': string; 'control-border': string;
/* Checkboxes */ /* Checkboxes */
@ -264,7 +263,6 @@ export interface ThemeColors {
'right-panel-disabled-overlay': string; 'right-panel-disabled-overlay': string;
'right-panel-toggle-button-enabled-fg': string; 'right-panel-toggle-button-enabled-fg': string;
'right-panel-toggle-button-enabled-bg': string; 'right-panel-toggle-button-enabled-bg': string;
'right-panel-toggle-button-enabled-hover-fg': string;
'right-panel-toggle-button-disabled-fg': string; 'right-panel-toggle-button-disabled-fg': string;
'right-panel-toggle-button-disabled-bg': string; 'right-panel-toggle-button-disabled-bg': string;
'right-panel-field-settings-bg': string; 'right-panel-field-settings-bg': string;
@ -278,6 +276,9 @@ export interface ThemeColors {
'document-history-snapshot-border': string; 'document-history-snapshot-border': string;
'document-history-activity-text': string; 'document-history-activity-text': string;
'document-history-activity-text-light': string; 'document-history-activity-text-light': string;
'document-history-table-header-fg': string;
'document-history-table-border': string;
'document-history-table-border-light': string;
/* Accents */ /* Accents */
'accent-icon': string; 'accent-icon': string;
@ -297,6 +298,16 @@ export interface ThemeColors {
'input-readonly-bg': string; 'input-readonly-bg': string;
'input-readonly-border': string; 'input-readonly-border': string;
/* Choice Tokens */
'choice-token-fg': string;
'choice-token-blank-fg': string;
'choice-token-bg': string;
'choice-token-selected-bg': string;
'choice-token-selected-border': string;
'choice-token-invalid-fg': string;
'choice-token-invalid-bg': string;
'choice-token-invalid-border': string;
/* Choice Entry */ /* Choice Entry */
'choice-entry-bg': string; 'choice-entry-bg': string;
'choice-entry-border': string; 'choice-entry-border': string;
@ -305,7 +316,6 @@ export interface ThemeColors {
/* Select Buttons */ /* Select Buttons */
'select-button-fg': string; 'select-button-fg': string;
'select-button-placeholder-fg': string; 'select-button-placeholder-fg': string;
'select-button-disabled-fg': string;
'select-button-bg': string; 'select-button-bg': string;
'select-button-border': string; 'select-button-border': string;
'select-button-border-invalid': string; 'select-button-border-invalid': string;
@ -325,14 +335,14 @@ export interface ThemeColors {
'menu-item-disabled-fg': string; 'menu-item-disabled-fg': string;
'menu-item-icon-fg': string; 'menu-item-icon-fg': string;
'menu-item-icon-selected-fg': string; 'menu-item-icon-selected-fg': string;
'menu-item-link-fg': string;
'menu-item-link-selected-fg': string;
'menu-item-link-selected-bg': string;
/* Autocomplete */ /* Autocomplete */
'autocomplete-match-text': string; 'autocomplete-match-text': string;
'autocomplete-selected-match-text': string; 'autocomplete-selected-match-text': string;
'autocomplete-item-selected-bg': string; 'autocomplete-item-selected-bg': string;
'autocomplete-add-new-circle-fg': string;
'autocomplete-add-new-circle-bg': string;
'autocomplete-add-new-circle-selected-bg': string;
/* Search */ /* Search */
'search-border': string; 'search-border': string;
@ -416,6 +426,7 @@ export interface ThemeColors {
'button-group-fg': string; 'button-group-fg': string;
'button-group-light-fg': string; 'button-group-light-fg': string;
'button-group-bg': string; 'button-group-bg': string;
'button-group-bg-hover': string;
'button-group-icon': string; 'button-group-icon': string;
'button-group-border': string; 'button-group-border': string;
'button-group-border-hover': string; 'button-group-border-hover': string;
@ -428,6 +439,7 @@ export interface ThemeColors {
'access-rules-table-header-fg': string; 'access-rules-table-header-fg': string;
'access-rules-table-header-bg': string; 'access-rules-table-header-bg': string;
'access-rules-table-body-fg': string; 'access-rules-table-body-fg': string;
'access-rules-table-body-light-fg': string;
'access-rules-table-border': string; 'access-rules-table-border': string;
'access-rules-column-list-border': string; 'access-rules-column-list-border': string;
'access-rules-column-item-fg': string; 'access-rules-column-item-fg': string;
@ -497,7 +509,6 @@ export interface ThemeColors {
'color-select-shadow': string; 'color-select-shadow': string;
'color-select-font-options-border': string; 'color-select-font-options-border': string;
'color-select-font-option-fg': string; 'color-select-font-option-fg': string;
'color-select-font-option-bg': string;
'color-select-font-option-bg-hover': string; 'color-select-font-option-bg-hover': string;
'color-select-font-option-fg-selected': string; 'color-select-font-option-fg-selected': string;
'color-select-font-option-bg-selected': string; 'color-select-font-option-bg-selected': string;
@ -518,11 +529,44 @@ export interface ThemeColors {
'login-page-bg': string; 'login-page-bg': string;
'login-page-backdrop': string; 'login-page-backdrop': string;
'login-page-line': string; 'login-page-line': string;
'login-page-google-button-fg': string;
'login-page-google-button-bg': string;
'login-page-google-button-bg-hover': string;
'login-page-google-button-border': string;
/* Formula Assistant */ /* Formula Assistant */
'formula-assistant-header-bg': string; 'formula-assistant-header-bg': string;
'formula-assistant-border': string; 'formula-assistant-border': string;
'formula-assistant-preformatted-text-bg': string; 'formula-assistant-preformatted-text-bg': string;
/* Attachments */
'attachments-editor-button-fg': string;
'attachments-editor-button-hover-fg': string;
'attachments-editor-button-bg': string;
'attachments-editor-button-hover-bg': string;
'attachments-editor-button-border': string;
'attachments-editor-button-icon': string;
'attachments-editor-border': string;
'attachments-cell-icon-fg': string;
'attachments-cell-icon-bg': string;
'attachments-cell-icon-hover-bg': string;
/* Switches */
'switch-slider-fg': string;
'switch-circle-fg': string;
/* Announcement Popups */
'announcement-popup-fg': string;
'announcement-popup-bg': string;
/* Scroll Shadow */
'scroll-shadow': string;
/* Toggle Checkboxes */
'toggle-checkbox-fg': string;
/* Numeric Spinners */
'numeric-spinner-fg': string;
} }
export const ThemePrefsChecker = createCheckers(ThemePrefsTI).ThemePrefs as CheckerT<ThemePrefs>; export const ThemePrefsChecker = createCheckers(ThemePrefsTI).ThemePrefs as CheckerT<ThemePrefs>;
@ -532,7 +576,7 @@ export const ThemeNameChecker = createCheckers(ThemePrefsTI).ThemeName as Checke
export function getDefaultThemePrefs(): ThemePrefs { export function getDefaultThemePrefs(): ThemePrefs {
return { return {
appearance: 'light', appearance: 'light',
syncWithOS: false, syncWithOS: true,
colors: { colors: {
light: 'GristLight', light: 'GristLight',
dark: 'GristDark', dark: 'GristDark',

@ -3,11 +3,11 @@ import {ThemeColors} from 'app/common/ThemePrefs';
export const GristDark: ThemeColors = { export const GristDark: ThemeColors = {
/* Text */ /* Text */
'text': '#EFEFEF', 'text': '#EFEFEF',
'text-light': '#A4A4A4', 'text-light': '#A4A4B1',
'text-dark': '#FFFFFF', 'text-dark': '#FFFFFF',
'text-error': '#FF6666', 'text-error': '#FF6666',
'text-danger': '#FFA500', 'text-danger': '#FFA500',
'text-disabled': '#A4A4A4', 'text-disabled': '#A4A4B1',
/* Page */ /* Page */
'page-bg': '#262633', 'page-bg': '#262633',
@ -19,30 +19,30 @@ export const GristDark: ThemeColors = {
'page-panels-right-panel-bg': '#262633', 'page-panels-right-panel-bg': '#262633',
'page-panels-top-header-bg': '#32323F', 'page-panels-top-header-bg': '#32323F',
'page-panels-bottom-footer-bg': '#32323F', 'page-panels-bottom-footer-bg': '#32323F',
'page-panels-border': '#57575F', 'page-panels-border': '#60606D',
'page-panels-border-resizing': '#1DA270', 'page-panels-border-resizing': '#17B378',
'page-panels-side-panel-opener-fg': '#A4A4A4', 'page-panels-side-panel-opener-fg': '#A4A4B1',
'page-panels-side-panel-opener-active-fg': '#FFFFFF', 'page-panels-side-panel-opener-active-fg': '#FFFFFF',
'page-panels-side-panel-opener-active-bg': '#1DA270', 'page-panels-side-panel-opener-active-bg': '#17B378',
/* Add New */ /* Add New */
'add-new-circle-fg': '#FFFFFF', 'add-new-circle-fg': '#FFFFFF',
'add-new-circle-bg': '#157A54', 'add-new-circle-bg': '#0A5438',
'add-new-circle-hover-bg': '#0A5438', 'add-new-circle-hover-bg': '#157A54',
'add-new-circle-small-fg': '#FFFFFF', 'add-new-circle-small-fg': '#FFFFFF',
'add-new-circle-small-bg': '#1DA270', 'add-new-circle-small-bg': '#157A54',
'add-new-circle-small-hover-bg': '#157A54', 'add-new-circle-small-hover-bg': '#1DA270',
/* Top Bar */ /* Top Bar */
'top-bar-button-primary-fg': '#1DA270', 'top-bar-button-primary-fg': '#17B378',
'top-bar-button-secondary-fg': '#A4A4A4', 'top-bar-button-secondary-fg': '#A4A4B1',
'top-bar-button-disabled-fg': '#69697D', 'top-bar-button-disabled-fg': '#70707D',
'top-bar-button-error-fg': 'FF6666', 'top-bar-button-error-fg': 'FF6666',
/* Notifications */ /* Notifications */
'notifications-panel-header-bg': '#262633', 'notifications-panel-header-bg': '#262633',
'notifications-panel-body-bg': '#32323F', 'notifications-panel-body-bg': '#32323F',
'notifications-panel-border': '#69697D', 'notifications-panel-border': '#70707D',
/* Toasts */ /* Toasts */
'toast-text': '#FFFFFF', 'toast-text': '#FFFFFF',
@ -64,86 +64,85 @@ export const GristDark: ThemeColors = {
/* Tooltips */ /* Tooltips */
'tooltip-fg': 'white', 'tooltip-fg': 'white',
'tooltip-bg': 'rgba(0, 0, 0, 0.75)', 'tooltip-bg': 'rgba(0, 0, 0, 0.75)',
'tooltip-icon': '#A4A4A4', 'tooltip-icon': '#A4A4B1',
'tooltip-close-button-fg': 'white', 'tooltip-close-button-fg': 'white',
'tooltip-close-button-hover-fg': 'black', 'tooltip-close-button-hover-fg': 'black',
'tooltip-close-button-hover-bg': 'white', 'tooltip-close-button-hover-bg': 'white',
'tooltip-popup-header-fg': '#EFEFEF',
'tooltip-popup-header-bg': '#1DA270',
/* Modals */ /* Modals */
'modal-bg': '#32323F', 'modal-bg': '#32323F',
'modal-backdrop': 'rgba(0,0,0,0.6)', 'modal-backdrop': 'rgba(0,0,0,0.6)',
'modal-border': '#57575F', 'modal-border': '#60606D',
'modal-border-dark': '#69697D', 'modal-border-dark': '#70707D',
'modal-border-hover': '#A4A4A4', 'modal-border-hover': '#A4A4B1',
'modal-shadow-inner': '#000000', 'modal-shadow-inner': '#000000',
'modal-shadow-outer': '#000000', 'modal-shadow-outer': '#000000',
'modal-close-button-fg': '#A4A4A4', 'modal-close-button-fg': '#A4A4B1',
'modal-backdrop-close-button-fg': '#1DA270', 'modal-backdrop-close-button-fg': '#17B378',
'modal-backdrop-close-button-hover-fg': '#157A54', 'modal-backdrop-close-button-hover-fg': '#13D78D',
/* Popups */ /* Popups */
'popup-bg': '#32323F', 'popup-bg': '#32323F',
'popup-shadow-inner': '#000000', 'popup-shadow-inner': '#000000',
'popup-shadow-outer': '#000000', 'popup-shadow-outer': '#000000',
'popup-close-button-fg': '#A4A4A4', 'popup-close-button-fg': '#A4A4B1',
/* Prompts */ /* Prompts */
'prompt-fg': '#A4A4A4', 'prompt-fg': '#A4A4B1',
/* Progress Bars */ /* Progress Bars */
'progress-bar-fg': '#1DA270', 'progress-bar-fg': '#17B378',
'progress-bar-error-fg': '#FF6666', 'progress-bar-error-fg': '#FF6666',
'progress-bar-bg': '#69697D', 'progress-bar-bg': '#70707D',
/* Links */ /* Links */
'link': '#1DA270', 'link': '#17B378',
'link-hover': '#1DA270', 'link-hover': '#17B378',
/* Hover */ /* Hover */
'hover': 'rgba(111,111,117,0.6)', 'hover': 'rgba(111,111,125,0.6)',
'hover-light': 'rgba(111,111,117,0.4)', 'hover-light': 'rgba(111,111,125,0.4)',
/* Cell Editor */ /* Cell Editor */
'cell-editor-fg': '#FFFFFF', 'cell-editor-fg': '#FFFFFF',
'cell-editor-placeholder-fg': '#A4A4B1',
'cell-editor-bg': '#32323F', 'cell-editor-bg': '#32323F',
/* Cursor */ /* Cursor */
'cursor': '#1DA270', 'cursor': '#1DA270',
'cursor-inactive': 'rgba(29,162,112,0.5)', 'cursor-inactive': 'rgba(29,162,112,0.5)',
'cursor-readonly': '#A4A4A4', 'cursor-readonly': '#A4A4B1',
/* Tables */ /* Tables */
'table-header-fg': '#EFEFEF', 'table-header-fg': '#EFEFEF',
'table-header-selected-fg': '#EFEFEF', 'table-header-selected-fg': '#EFEFEF',
'table-header-bg': '#262633', 'table-header-bg': '#262633',
'table-header-selected-bg': '#414358', 'table-header-selected-bg': '#414358',
'table-header-border': '#57575F', 'table-header-border': '#70707D',
'table-header-border-dark': '#69697D',
'table-body-bg': '#32323F', 'table-body-bg': '#32323F',
'table-body-border': '#69697D', 'table-body-border': '#60606D',
'table-add-new-bg': '#4A4A5D', 'table-add-new-bg': '#4A4A5D',
'table-scroll-shadow': '#000000', 'table-scroll-shadow': '#000000',
'table-frozen-columns-border': '#A4A4A4', 'table-frozen-columns-border': '#A4A4B1',
'table-drag-drop-indicator': '#A4A4A4', 'table-drag-drop-indicator': '#A4A4B1',
'table-drag-drop-shadow': 'rgba(111,111,117,0.6)', 'table-drag-drop-shadow': 'rgba(111,111,125,0.6)',
'table-cell-summary-bg': 'rgba(111,111,125,0.6)',
/* Cards */ /* Cards */
'card-compact-widget-bg': '#262633', 'card-compact-widget-bg': '#262633',
'card-compact-record-bg': '#32323F', 'card-compact-record-bg': '#32323F',
'card-blocks-bg': '#404150', 'card-blocks-bg': '#404150',
'card-form-label': '#A4A4A4', 'card-form-label': '#A4A4B1',
'card-compact-label': '#A4A4A4', 'card-compact-label': '#A4A4B1',
'card-blocks-label': '#A4A4A4', 'card-blocks-label': '#A4A4B1',
'card-form-border': '#69697D', 'card-form-border': '#70707D',
'card-compact-border': '#69697D', 'card-compact-border': '#70707D',
'card-editing-layout-bg': 'rgba(85, 85, 99, 0.2)', 'card-editing-layout-bg': 'rgba(85, 85, 99, 0.2)',
'card-editing-layout-border': '#69697D', 'card-editing-layout-border': '#70707D',
/* Card Lists */ /* Card Lists */
'card-list-form-border': '#57575F', 'card-list-form-border': '#60606D',
'card-list-blocks-border': '#57575F', 'card-list-blocks-border': '#60606D',
/* Selection */ /* Selection */
'selection': 'rgba(22,179,120,0.15)', 'selection': 'rgba(22,179,120,0.15)',
@ -156,203 +155,214 @@ export const GristDark: ThemeColors = {
/* Widgets */ /* Widgets */
'widget-bg': '#32323F', 'widget-bg': '#32323F',
'widget-border': '#57575F', 'widget-border': '#70707D',
'widget-active-border': '#1DA270', 'widget-active-border': '#157A54',
'widget-inactive-stripes-light': '#262633', 'widget-inactive-stripes-light': '#262633',
'widget-inactive-stripes-dark': '#32323F', 'widget-inactive-stripes-dark': '#32323F',
/* Pinned Docs */ /* Pinned Docs */
'pinned-doc-footer-bg': '#32323F', 'pinned-doc-footer-bg': '#32323F',
'pinned-doc-border': '#57575F', 'pinned-doc-border': '#60606D',
'pinned-doc-border-hover': '#A4A4A4', 'pinned-doc-border-hover': '#A4A4B1',
'pinned-doc-editor-bg': '#57575F', 'pinned-doc-editor-bg': '#60606D',
/* Raw Data */ /* Raw Data */
'raw-data-table-border': '#57575F', 'raw-data-table-border': '#60606D',
'raw-data-table-border-hover': '#A4A4A4', 'raw-data-table-border-hover': '#A4A4B1',
/* Controls */ /* Controls */
'control-fg': '#1DA270', 'control-fg': '#17B378',
'control-primary-fg': '#FFFFFF', 'control-primary-fg': '#FFFFFF',
'control-primary-bg': '#1DA270', 'control-primary-bg': '#157A54',
'control-secondary-fg': '#A4A4A4', 'control-secondary-fg': '#A4A4B1',
'control-hover-fg': '#157A54', 'control-secondary-disabled-fg': '#60606D',
'control-primary-hover-bg': '#157A54', 'control-hover-fg': '#13D78D',
'control-primary-hover-bg': '#1DA270',
'control-secondary-hover-fg': '#EFEFEF', 'control-secondary-hover-fg': '#EFEFEF',
'control-secondary-hover-bg': '#57575F', 'control-secondary-hover-bg': '#60606D',
'control-disabled-fg': '#A4A4A4', 'control-disabled-fg': '#A4A4B1',
'control-disabled-bg': '#69697D', 'control-disabled-bg': '#70707D',
'control-primary-disabled': '#5F8C7B', 'control-border': '1px solid #17B378',
'control-border': '1px solid #1DA270',
/* Checkboxes */ /* Checkboxes */
'checkbox-bg': '#32323F', 'checkbox-bg': '#32323F',
'checkbox-disabled-bg': '#69697D', 'checkbox-disabled-bg': '#70707D',
'checkbox-border': '#69697D', 'checkbox-border': '#70707D',
'checkbox-border-hover': '#57575F', 'checkbox-border-hover': '#A4A4B1',
/* Move Docs */ /* Move Docs */
'move-docs-selected-fg': '#FFFFFF', 'move-docs-selected-fg': '#FFFFFF',
'move-docs-selected-bg': '#1DA270', 'move-docs-selected-bg': '#157A54',
'move-docs-disabled-bg': '#69697D', 'move-docs-disabled-bg': '#70707D',
/* Filter Bar */ /* Filter Bar */
'filter-bar-button-saved-fg': '#FFFFFF', 'filter-bar-button-saved-fg': '#FFFFFF',
'filter-bar-button-saved-bg': '#555563', 'filter-bar-button-saved-bg': '#555563',
'filter-bar-button-saved-hover-bg': '#69697D', 'filter-bar-button-saved-hover-bg': '#70707D',
/* Icons */ /* Icons */
'icon-disabled': '#A4A4A4', 'icon-disabled': '#A4A4B1',
'icon-error': '#FFA500', 'icon-error': '#FFA500',
/* Icon Buttons */ /* Icon Buttons */
'icon-button-fg': '#FFFFFF', 'icon-button-fg': '#FFFFFF',
'icon-button-primary-bg': '#1DA270', 'icon-button-primary-bg': '#17B378',
'icon-button-primary-hover-bg': '#157A54', 'icon-button-primary-hover-bg': '#13D78D',
'icon-button-secondary-bg': '#69697D', 'icon-button-secondary-bg': '#70707D',
'icon-button-secondary-hover-bg': '#A4A4A4', 'icon-button-secondary-hover-bg': '#A4A4B1',
/* Left Panel */ /* Left Panel */
'left-panel-page-hover-bg': 'rgba(111,111,117,0.25)', 'left-panel-page-hover-bg': 'rgba(111,111,117,0.25)',
'left-panel-active-page-fg': '#EFEFEF', 'left-panel-active-page-fg': '#EFEFEF',
'left-panel-active-page-bg': '#555563', 'left-panel-active-page-bg': '#646473',
'left-panel-disabled-page-fg': '#69697D', 'left-panel-disabled-page-fg': '#70707D',
'left-panel-page-options-fg': '#A4A4A4', 'left-panel-page-options-fg': '#A4A4B1',
'left-panel-page-options-hover-fg': '#FFFFFF', 'left-panel-page-options-hover-fg': '#FFFFFF',
'left-panel-page-options-hover-bg': '#69697D', 'left-panel-page-options-hover-bg': '#70707D',
'left-panel-page-options-selected-hover-bg': '#A4A4A4', 'left-panel-page-options-selected-hover-bg': '#A4A4B1',
'left-panel-page-initials-fg': 'white', 'left-panel-page-initials-fg': 'white',
'left-panel-page-initials-bg': '#929299', 'left-panel-page-initials-bg': '#8E8EA0',
'left-panel-page-emoji-fg': 'black', 'left-panel-page-emoji-fg': 'black',
'left-panel-page-emoji-outline': '#69697D', 'left-panel-page-emoji-outline': '#70707D',
/* Right Panel */ /* Right Panel */
'right-panel-tab-fg': '#EFEFEF', 'right-panel-tab-fg': '#EFEFEF',
'right-panel-tab-bg': '#262633', 'right-panel-tab-bg': '#262633',
'right-panel-tab-icon': '#A4A4A4', 'right-panel-tab-icon': '#A4A4B1',
'right-panel-tab-icon-hover': '#1DA270', 'right-panel-tab-icon-hover': '#13D78D',
'right-panel-tab-hover-bg': 'rgba(111,111,117,0.6)', 'right-panel-tab-hover-bg': 'rgba(111,111,117,0.6)',
'right-panel-tab-selected-fg': '#FFFFFF', 'right-panel-tab-selected-fg': '#FFFFFF',
'right-panel-tab-selected-bg': '#1DA270', 'right-panel-tab-selected-bg': '#157A54',
'right-panel-tab-button-hover-bg': '#157A54', 'right-panel-tab-button-hover-bg': '#0A5438',
'right-panel-subtab-fg': '#1DA270', 'right-panel-subtab-fg': '#17B378',
'right-panel-subtab-selected-fg': '#EFEFEF', 'right-panel-subtab-selected-fg': '#EFEFEF',
'right-panel-subtab-selected-underline': '#1DA270', 'right-panel-subtab-selected-underline': '#1DA270',
'right-panel-subtab-hover-fg': '#157A54', 'right-panel-subtab-hover-fg': '#13D78D',
'right-panel-subtab-hover-underline': '#1DA270', 'right-panel-subtab-hover-underline': '#13D78D',
'right-panel-disabled-overlay': '#262633', 'right-panel-disabled-overlay': '#262633',
'right-panel-toggle-button-enabled-fg': '#FFFFFF', 'right-panel-toggle-button-enabled-fg': '#FFFFFF',
'right-panel-toggle-button-enabled-bg': '#555563', 'right-panel-toggle-button-enabled-bg': '#646473',
'right-panel-toggle-button-enabled-hover-fg': '#D9D9D9', 'right-panel-toggle-button-disabled-fg': '#646473',
'right-panel-toggle-button-disabled-fg': '#FFFFFF', 'right-panel-toggle-button-disabled-bg': '#32323F',
'right-panel-toggle-button-disabled-bg': '#333333', 'right-panel-field-settings-bg': '#404150',
'right-panel-field-settings-bg': '#414358', 'right-panel-field-settings-button-bg': '#646473',
'right-panel-field-settings-button-bg': '#57575F',
/* Document History */ /* Document History */
'document-history-snapshot-fg': '#EFEFEF', 'document-history-snapshot-fg': '#EFEFEF',
'document-history-snapshot-selected-fg': '#EFEFEF', 'document-history-snapshot-selected-fg': '#EFEFEF',
'document-history-snapshot-bg': '#32323F', 'document-history-snapshot-bg': '#32323F',
'document-history-snapshot-selected-bg': '#555563', 'document-history-snapshot-selected-bg': '#646473',
'document-history-snapshot-border': '#69697D', 'document-history-snapshot-border': '#70707D',
'document-history-activity-text': '#EFEFEF', 'document-history-activity-text': '#EFEFEF',
'document-history-activity-text-light': '#A4A4A4', 'document-history-activity-text-light': '#A4A4B1',
'document-history-table-header-fg': '#EFEFEF',
'document-history-table-border': '#70707D',
'document-history-table-border-light': '#60606D',
/* Accents */ /* Accents */
'accent-icon': '#1DA270', 'accent-icon': '#17B378',
'accent-border': '#1DA270', 'accent-border': '#157A54',
'accent-text': '#1DA270', 'accent-text': '#17B378',
/* Inputs */ /* Inputs */
'input-fg': '#EFEFEF', 'input-fg': '#EFEFEF',
'input-bg': '#32323F', 'input-bg': '#32323F',
'input-disabled-fg': '#A4A4A4', 'input-disabled-fg': '#A4A4B1',
'input-disabled-bg': '#262633', 'input-disabled-bg': '#262633',
'input-placeholder-fg': '#A4A4A4', 'input-placeholder-fg': '#A4A4B1',
'input-border': '#69697D', 'input-border': '#70707D',
'input-valid': '#1DA270', 'input-valid': '#17B378',
'input-invalid': '#FF6666', 'input-invalid': '#FF6666',
'input-focus': '#5E9ED6', 'input-focus': '#5E9ED6',
'input-readonly-bg': '#262633', 'input-readonly-bg': '#262633',
'input-readonly-border': '#69697D', 'input-readonly-border': '#70707D',
/* Choice Tokens */
'choice-token-fg': '#FFFFFF',
'choice-token-blank-fg': '#A4A4B1',
'choice-token-bg': '#70707D',
'choice-token-selected-bg': '#555563',
'choice-token-selected-border': '#17B378',
'choice-token-invalid-fg': '#FFFFFF',
'choice-token-invalid-bg': '#323240',
'choice-token-invalid-border': '#D0021B',
/* Choice Entry */ /* Choice Entry */
'choice-entry-bg': '#32323F', 'choice-entry-bg': '#32323F',
'choice-entry-border': '#69697D', 'choice-entry-border': '#70707D',
'choice-entry-border-hover': '#A4A4A4', 'choice-entry-border-hover': '#A4A4B1',
/* Select Buttons */ /* Select Buttons */
'select-button-fg': '#EFEFEF', 'select-button-fg': '#EFEFEF',
'select-button-placeholder-fg': '#A4A4A4', 'select-button-placeholder-fg': '#A4A4B1',
'select-button-disabled-fg': '#A4A4A4',
'select-button-bg': '#32323F', 'select-button-bg': '#32323F',
'select-button-border': '#69697D', 'select-button-border': '#70707D',
'select-button-border-invalid': '#FF6666', 'select-button-border-invalid': '#FF6666',
/* Menus */ /* Menus */
'menu-text': '#A4A4A4', 'menu-text': '#A4A4B1',
'menu-light-text': '#A4A4A4', 'menu-light-text': '#A4A4B1',
'menu-bg': '#32323F', 'menu-bg': '#32323F',
'menu-subheader-fg': '#EFEFEF', 'menu-subheader-fg': '#EFEFEF',
'menu-border': '#69697D', 'menu-border': '#70707D',
'menu-shadow': '#000000', 'menu-shadow': '#000000',
/* Menu Items */ /* Menu Items */
'menu-item-fg': '#FFFFFF', 'menu-item-fg': '#FFFFFF',
'menu-item-selected-fg': '#FFFFFF', 'menu-item-selected-fg': '#FFFFFF',
'menu-item-selected-bg': '#1DA270', 'menu-item-selected-bg': '#157A54',
'menu-item-disabled-fg': '#69697D', 'menu-item-disabled-fg': '#70707D',
'menu-item-icon-fg': '#A4A4A4', 'menu-item-icon-fg': '#A4A4B1',
'menu-item-icon-selected-fg': '#FFFFFF', 'menu-item-icon-selected-fg': '#FFFFFF',
'menu-item-link-fg': '#1DA270',
'menu-item-link-selected-fg': '#157A54',
'menu-item-link-selected-bg': '#484859',
/* Autocomplete */ /* Autocomplete */
'autocomplete-match-text': '#1DA270', 'autocomplete-match-text': '#17B378',
'autocomplete-selected-match-text': '#0A5438', 'autocomplete-selected-match-text': '#13D78D',
'autocomplete-item-selected-bg': '#69697D', 'autocomplete-item-selected-bg': '#70707D',
'autocomplete-add-new-circle-fg': '#FFFFFF',
'autocomplete-add-new-circle-bg': '#157A54',
'autocomplete-add-new-circle-selected-bg': '#1DA270',
/* Search */ /* Search */
'search-border': '#69697D', 'search-border': '#70707D',
'search-prev-next-button-fg': '#A4A4A4', 'search-prev-next-button-fg': '#A4A4B1',
'search-prev-next-button-bg': '#24242F', 'search-prev-next-button-bg': '#24242F',
/* Loading Spinners */ /* Loading Spinners */
'loader-fg': '#1DA270', 'loader-fg': '#17B378',
'loader-bg': '#69697D', 'loader-bg': '#70707D',
/* Site Switcher */ /* Site Switcher */
'site-switcher-active-fg': '#FFFFFF', 'site-switcher-active-fg': '#FFFFFF',
'site-switcher-active-bg': '#000000', 'site-switcher-active-bg': '#000000',
/* Doc Menu */ /* Doc Menu */
'doc-menu-doc-options-fg': '#69697D', 'doc-menu-doc-options-fg': '#70707D',
'doc-menu-doc-options-hover-fg': '#A4A4A4', 'doc-menu-doc-options-hover-fg': '#A4A4B1',
'doc-menu-doc-options-hover-bg': '#69697D', 'doc-menu-doc-options-hover-bg': '#70707D',
/* Shortcut Keys */ /* Shortcut Keys */
'shortcut-key-fg': '#FFFFFF', 'shortcut-key-fg': '#FFFFFF',
'shortcut-key-primary-fg': '#17B378', 'shortcut-key-primary-fg': '#17B378',
'shortcut-key-secondary-fg': '#A4A4A4', 'shortcut-key-secondary-fg': '#A4A4B1',
'shortcut-key-bg': '#32323F', 'shortcut-key-bg': '#32323F',
'shortcut-key-border': '#A4A4A4', 'shortcut-key-border': '#A4A4B1',
/* Breadcrumbs */ /* Breadcrumbs */
'breadcrumbs-tag-fg': 'white', 'breadcrumbs-tag-fg': '#FFFFFF',
'breadcrumbs-tag-bg': '#929299', 'breadcrumbs-tag-bg': '#70707D',
'breadcrumbs-tag-alert-bg': '#D0021B', 'breadcrumbs-tag-alert-bg': '#D0021B',
/* Page Widget Picker */ /* Page Widget Picker */
'widget-picker-primary-bg': '#32323F', 'widget-picker-primary-bg': '#32323F',
'widget-picker-secondary-bg': '#262633', 'widget-picker-secondary-bg': '#262633',
'widget-picker-item-fg': '#FFFFFF', 'widget-picker-item-fg': '#FFFFFF',
'widget-picker-item-selected-bg': 'rgba(111,111,117,0.6)', 'widget-picker-item-selected-bg': 'rgba(111,111,125,0.6)',
'widget-picker-item-disabled-bg': 'rgba(111,111,117,0.6)', 'widget-picker-item-disabled-bg': 'rgba(111,111,125,0.6)',
'widget-picker-icon': '#A4A4A4', 'widget-picker-icon': '#A4A4B1',
'widget-picker-primary-icon': '#1DA270', 'widget-picker-primary-icon': '#17B378',
'widget-picker-summary-icon': '#1DA270', 'widget-picker-summary-icon': '#17B378',
'widget-picker-border': 'rgba(111,111,117,0.6)', 'widget-picker-border': 'rgba(111,111,125,0.6)',
'widget-picker-shadow': '#000000', 'widget-picker-shadow': '#000000',
/* Code View */ /* Code View */
@ -368,10 +378,10 @@ export const GristDark: ThemeColors = {
'code-view-literal': '#9ED682', 'code-view-literal': '#9ED682',
/* Importer */ /* Importer */
'importer-table-info-border': '#69697D', 'importer-table-info-border': '#70707D',
'importer-preview-border': '#69697D', 'importer-preview-border': '#70707D',
'importer-skipped-table-overlay': 'rgba(111,111,117,0.6)', 'importer-skipped-table-overlay': 'rgba(111,111,125,0.6)',
'importer-match-icon': '#69697D', 'importer-match-icon': '#70707D',
'importer-outside-bg': '#32323F', 'importer-outside-bg': '#32323F',
'importer-main-content-bg': '#262633', 'importer-main-content-bg': '#262633',
'importer-active-file-bg': '#16B378', 'importer-active-file-bg': '#16B378',
@ -380,11 +390,11 @@ export const GristDark: ThemeColors = {
'importer-inactive-file-fg': '#FFFFFF', 'importer-inactive-file-fg': '#FFFFFF',
/* Menu Toggles */ /* Menu Toggles */
'menu-toggle-fg': '#A4A4A4', 'menu-toggle-fg': '#A4A4B1',
'menu-toggle-hover-fg': '#1DA270', 'menu-toggle-hover-fg': '#17B378',
'menu-toggle-active-fg': '#157A54', 'menu-toggle-active-fg': '#13D78D',
'menu-toggle-bg': '#32323F', 'menu-toggle-bg': '#32323F',
'menu-toggle-border': '#A4A4A4', 'menu-toggle-border': '#A4A4B1',
/* Info Button */ /* Info Button */
'info-button-fg': '#8F8F8F', 'info-button-fg': '#8F8F8F',
@ -393,31 +403,33 @@ export const GristDark: ThemeColors = {
/* Button Groups */ /* Button Groups */
'button-group-fg': '#EFEFEF', 'button-group-fg': '#EFEFEF',
'button-group-light-fg': '#A4A4A4', 'button-group-light-fg': '#A4A4B1',
'button-group-bg': 'unset', 'button-group-bg': 'transparent',
'button-group-icon': '#A4A4A4', 'button-group-bg-hover': 'rgba(111,111,125,0.25)',
'button-group-border': '#69697D', 'button-group-icon': '#A4A4B1',
'button-group-border-hover': '#555563', 'button-group-border': '#70707D',
'button-group-border-hover': '#646473',
'button-group-selected-fg': '#EFEFEF', 'button-group-selected-fg': '#EFEFEF',
'button-group-light-selected-fg': '#1DA270', 'button-group-light-selected-fg': '#17B378',
'button-group-selected-bg': '#555563', 'button-group-selected-bg': '#646473',
'button-group-selected-border': '#555563', 'button-group-selected-border': '#646473',
/* Access Rules */ /* Access Rules */
'access-rules-table-header-fg': '#EFEFEF', 'access-rules-table-header-fg': '#EFEFEF',
'access-rules-table-header-bg': '#57575F', 'access-rules-table-header-bg': '#60606D',
'access-rules-table-body-fg': '#A4A4A4', 'access-rules-table-body-fg': '#A4A4B1',
'access-rules-table-border': '#A4A4A4', 'access-rules-table-body-light-fg': '#70707D',
'access-rules-column-list-border': '#69697D', 'access-rules-table-border': '#A4A4B1',
'access-rules-column-list-border': '#70707D',
'access-rules-column-item-fg': '#EFEFEF', 'access-rules-column-item-fg': '#EFEFEF',
'access-rules-column-item-bg': '#57575F', 'access-rules-column-item-bg': '#60606D',
'access-rules-column-item-icon-fg': '#A4A4A4', 'access-rules-column-item-icon-fg': '#A4A4B1',
'access-rules-column-item-icon-hover-fg': '#EFEFEF', 'access-rules-column-item-icon-hover-fg': '#EFEFEF',
'access-rules-column-item-icon-hover-bg': '#A4A4A4', 'access-rules-column-item-icon-hover-bg': '#A4A4B1',
'access-rules-formula-editor-bg': '#32323F', 'access-rules-formula-editor-bg': '#32323F',
'access-rules-formula-editor-border-hover': '#69697D', 'access-rules-formula-editor-border-hover': '#70707D',
'access-rules-formula-editor-bg-disabled': '#57575F', 'access-rules-formula-editor-bg-disabled': '#60606D',
'access-rules-formula-editor-focus': '#1DA270', 'access-rules-formula-editor-focus': '#17B378',
/* Cells */ /* Cells */
'cell-fg': '#FFFFFF', 'cell-fg': '#FFFFFF',
@ -425,81 +437,113 @@ export const GristDark: ThemeColors = {
'cell-zebra-bg': '#262633', 'cell-zebra-bg': '#262633',
/* Charts */ /* Charts */
'chart-fg': '#A4A4A4', 'chart-fg': '#A4A4B1',
'chart-bg': '#32323F', 'chart-bg': '#32323F',
'chart-legend-bg': '#32323F80', 'chart-legend-bg': 'rgba(50,50,63,0.5)',
'chart-x-axis': '#A4A4A4', 'chart-x-axis': '#A4A4B1',
'chart-y-axis': '#A4A4A4', 'chart-y-axis': '#A4A4B1',
/* Comments */ /* Comments */
'comments-popup-header-bg': '#262633', 'comments-popup-header-bg': '#262633',
'comments-popup-body-bg': '#32323F', 'comments-popup-body-bg': '#32323F',
'comments-popup-border': '#69697D', 'comments-popup-border': '#70707D',
'comments-user-name-fg': '#DFDFDF', 'comments-user-name-fg': '#EFEFEF',
'comments-panel-topic-bg': '#32323F', 'comments-panel-topic-bg': '#32323F',
'comments-panel-topic-border': '#555563', 'comments-panel-topic-border': '#555563',
'comments-panel-resolved-topic-bg': '#262634', 'comments-panel-resolved-topic-bg': '#262633',
/* Date Picker */ /* Date Picker */
'date-picker-selected-fg': '#FFFFFF', 'date-picker-selected-fg': '#FFFFFF',
'date-picker-selected-bg': '#7F7F7F', 'date-picker-selected-bg': '#7A7A8D',
'date-picker-selected-bg-hover': '#8F8F8F', 'date-picker-selected-bg-hover': '#8D8D9C',
'date-picker-today-fg': '#FFFFFF', 'date-picker-today-fg': '#FFFFFF',
'date-picker-today-bg': '#1DA270', 'date-picker-today-bg': '#157A54',
'date-picker-today-bg-hover': '#157A54', 'date-picker-today-bg-hover': '#1DA270',
'date-picker-range-start-end-bg': '#7F7F7F', 'date-picker-range-start-end-bg': '#7A7A8D',
'date-picker-range-start-end-bg-hover': '#8F8F8F', 'date-picker-range-start-end-bg-hover': '#8D8D9C',
'date-picker-range-bg': '#57575F', 'date-picker-range-bg': '#60606D',
'date-picker-range-bg-hover': '#7F7F7F', 'date-picker-range-bg-hover': '#7A7A8D',
/* Tutorials */ /* Tutorials */
'tutorials-popup-border': '#69697D', 'tutorials-popup-border': '#70707D',
'tutorials-popup-header-fg': '#FFFFFF', 'tutorials-popup-header-fg': '#FFFFFF',
'tutorials-popup-box-bg': '#57575F', 'tutorials-popup-box-bg': '#60606D',
/* Ace */ /* Ace */
'ace-editor-bg': '#32323F', 'ace-editor-bg': '#32323F',
'ace-autocomplete-primary-fg': '#EFEFEF', 'ace-autocomplete-primary-fg': '#EFEFEF',
'ace-autocomplete-secondary-fg': '#A4A4A4', 'ace-autocomplete-secondary-fg': '#A4A4B1',
'ace-autocomplete-highlighted-fg': '#FFFFFF', 'ace-autocomplete-highlighted-fg': '#FFFFFF',
'ace-autocomplete-bg': '#32323F', 'ace-autocomplete-bg': '#32323F',
'ace-autocomplete-border': '#69697D', 'ace-autocomplete-border': '#70707D',
'ace-autocomplete-link': '#28BE86', 'ace-autocomplete-link': '#28BE86',
'ace-autocomplete-link-highlighted': '#45D48B', 'ace-autocomplete-link-highlighted': '#45D48B',
'ace-autocomplete-active-line-bg': '#555563', 'ace-autocomplete-active-line-bg': '#555563',
'ace-autocomplete-line-border-hover': 'rgba(111,111,117,0.3)', 'ace-autocomplete-line-border-hover': 'rgba(111,111,125,0.3)',
'ace-autocomplete-line-bg-hover': 'rgba(111,111,117,0.3)', 'ace-autocomplete-line-bg-hover': 'rgba(111,111,125,0.3)',
/* Color Select */ /* Color Select */
'color-select-fg': '#EFEFEF', 'color-select-fg': '#A4A4B1',
'color-select-bg': '#32323F', 'color-select-bg': '#32323F',
'color-select-shadow': '#000000', 'color-select-shadow': '#000000',
'color-select-font-options-border': '#69697D', 'color-select-font-options-border': '#555563',
'color-select-font-option-fg': '#EFEFEF', 'color-select-font-option-fg': '#EFEFEF',
'color-select-font-option-bg': '#32323F', 'color-select-font-option-bg-hover': 'rgba(111,111,125,0.25)',
'color-select-font-option-bg-hover': '#262633',
'color-select-font-option-fg-selected': '#EFEFEF', 'color-select-font-option-fg-selected': '#EFEFEF',
'color-select-font-option-bg-selected': '#555563', 'color-select-font-option-bg-selected': '#646473',
'color-select-color-square-border': '#A4A4A4', 'color-select-color-square-border': '#A4A4B1',
'color-select-color-square-border-empty': '#EFEFEF', 'color-select-color-square-border-empty': '#EFEFEF',
'color-select-input-fg': '#EFEFEF', 'color-select-input-fg': '#A4A4B1',
'color-select-input-bg': '#32323F', 'color-select-input-bg': '#32323F',
'color-select-input-border': '#69697D', 'color-select-input-border': '#70707D',
/* Highlighted Code */ /* Highlighted Code */
'highlighted-code-block-bg': '#262633', 'highlighted-code-block-bg': '#262633',
'highlighted-code-block-bg-disabled': '#555563', 'highlighted-code-block-bg-disabled': '#555563',
'highlighted-code-fg': '#A4A4A4', 'highlighted-code-fg': '#A4A4B1',
'highlighted-code-border': '#69697D', 'highlighted-code-border': '#70707D',
'highlighted-code-bg-disabled': '#555563', 'highlighted-code-bg-disabled': '#32323F',
/* Login Page */ /* Login Page */
'login-page-bg': '#32323F', 'login-page-bg': '#32323F',
'login-page-backdrop': '#404150', 'login-page-backdrop': '#404150',
'login-page-line': '#57575F', 'login-page-line': '#60606D',
'login-page-google-button-fg': '#FFFFFF',
'login-page-google-button-bg': '#404150',
'login-page-google-button-bg-hover': '#555563',
'login-page-google-button-border': '#70707D',
/* Formula Assistant */ /* Formula Assistant */
'formula-assistant-header-bg': '#262633', 'formula-assistant-header-bg': '#262633',
'formula-assistant-border': '#69697D', 'formula-assistant-border': '#70707D',
'formula-assistant-preformatted-text-bg': '#262633', 'formula-assistant-preformatted-text-bg': '#262633',
/* Attachments */
'attachments-editor-button-fg': '#17B378',
'attachments-editor-button-hover-fg': '#13D78D',
'attachments-editor-button-bg': '#404150',
'attachments-editor-button-hover-bg': '#555563',
'attachments-editor-button-border': '#70707D',
'attachments-editor-button-icon': '#A4A4B1',
'attachments-editor-border': '#A4A4B1',
'attachments-cell-icon-fg': '#A4A4B1',
'attachments-cell-icon-bg': '#555563',
'attachments-cell-icon-hover-bg': '#70707D',
/* Switches */
'switch-slider-fg': '#70707D',
'switch-circle-fg': '#EFEFEF',
/* Announcement Popups */
'announcement-popup-fg': '#FFFFFF',
'announcement-popup-bg': '#404150',
/* Scroll Shadow */
'scroll-shadow': 'rgba(0,0,0,0.25)',
/* Toggle Checkboxes */
'toggle-checkbox-fg': '#A4A4B1',
/* Numeric Spinners */
'numeric-spinner-fg': '#A4A4B1',
}; };

@ -68,8 +68,6 @@ export const GristLight: ThemeColors = {
'tooltip-close-button-fg': 'white', 'tooltip-close-button-fg': 'white',
'tooltip-close-button-hover-fg': 'black', 'tooltip-close-button-hover-fg': 'black',
'tooltip-close-button-hover-bg': 'white', 'tooltip-close-button-hover-bg': 'white',
'tooltip-popup-header-fg': 'white',
'tooltip-popup-header-bg': '#16B378',
/* Modals */ /* Modals */
'modal-bg': 'white', 'modal-bg': 'white',
@ -107,6 +105,7 @@ export const GristLight: ThemeColors = {
/* Cell Editor */ /* Cell Editor */
'cell-editor-fg': '#262633', 'cell-editor-fg': '#262633',
'cell-editor-placeholder-fg': '#929299',
'cell-editor-bg': '#FFFFFF', 'cell-editor-bg': '#FFFFFF',
/* Cursor */ /* Cursor */
@ -115,12 +114,11 @@ export const GristLight: ThemeColors = {
'cursor-readonly': '#929299', 'cursor-readonly': '#929299',
/* Tables */ /* Tables */
'table-header-fg': 'unset', 'table-header-fg': '#000',
'table-header-selected-fg': 'unset', 'table-header-selected-fg': '#000',
'table-header-bg': '#F7F7F7', 'table-header-bg': '#F7F7F7',
'table-header-selected-bg': '#E8E8E8', 'table-header-selected-bg': '#E8E8E8',
'table-header-border': 'lightgray', 'table-header-border': 'lightgray',
'table-header-border-dark': '#D9D9D9',
'table-body-bg': 'white', 'table-body-bg': 'white',
'table-body-border': '#D9D9D9', 'table-body-border': '#D9D9D9',
'table-add-new-bg': 'inherit', 'table-add-new-bg': 'inherit',
@ -128,6 +126,7 @@ export const GristLight: ThemeColors = {
'table-frozen-columns-border': '#999999', 'table-frozen-columns-border': '#999999',
'table-drag-drop-indicator': 'gray', 'table-drag-drop-indicator': 'gray',
'table-drag-drop-shadow': '#F0F0F0', 'table-drag-drop-shadow': '#F0F0F0',
'table-cell-summary-bg': 'rgba(217,217,217,0.6)',
/* Cards */ /* Cards */
'card-compact-widget-bg': 'rgba(217,217,217,0.6)', 'card-compact-widget-bg': 'rgba(217,217,217,0.6)',
@ -176,13 +175,13 @@ export const GristLight: ThemeColors = {
'control-primary-fg': '#FFFFFF', 'control-primary-fg': '#FFFFFF',
'control-primary-bg': '#16B378', 'control-primary-bg': '#16B378',
'control-secondary-fg': '#929299', 'control-secondary-fg': '#929299',
'control-secondary-disabled-fg': '#D9D9D9',
'control-hover-fg': '#009058', 'control-hover-fg': '#009058',
'control-primary-hover-bg': '#009058', 'control-primary-hover-bg': '#009058',
'control-secondary-hover-fg': '#262633', 'control-secondary-hover-fg': '#262633',
'control-secondary-hover-bg': '#D9D9D9', 'control-secondary-hover-bg': '#D9D9D9',
'control-disabled-fg': '#FFFFFF', 'control-disabled-fg': '#FFFFFF',
'control-disabled-bg': '#929299', 'control-disabled-bg': '#929299',
'control-primary-disabled': '#A2E1C9',
'control-border': '1px solid #11B683', 'control-border': '1px solid #11B683',
/* Checkboxes */ /* Checkboxes */
@ -243,7 +242,6 @@ export const GristLight: ThemeColors = {
'right-panel-disabled-overlay': '#F7F7F7', 'right-panel-disabled-overlay': '#F7F7F7',
'right-panel-toggle-button-enabled-fg': '#FFFFFF', 'right-panel-toggle-button-enabled-fg': '#FFFFFF',
'right-panel-toggle-button-enabled-bg': '#262633', 'right-panel-toggle-button-enabled-bg': '#262633',
'right-panel-toggle-button-enabled-hover-fg': '#D9D9D9',
'right-panel-toggle-button-disabled-fg': '#FFFFFF', 'right-panel-toggle-button-disabled-fg': '#FFFFFF',
'right-panel-toggle-button-disabled-bg': '#E8E8E8', 'right-panel-toggle-button-disabled-bg': '#E8E8E8',
'right-panel-field-settings-bg': '#E8E8E8', 'right-panel-field-settings-bg': '#E8E8E8',
@ -255,8 +253,11 @@ export const GristLight: ThemeColors = {
'document-history-snapshot-bg': 'white', 'document-history-snapshot-bg': 'white',
'document-history-snapshot-selected-bg': '#262633', 'document-history-snapshot-selected-bg': '#262633',
'document-history-snapshot-border': 'rgba(217,217,217,0.6)', 'document-history-snapshot-border': 'rgba(217,217,217,0.6)',
'document-history-activity-text': '#000000', 'document-history-activity-text': '#262633',
'document-history-activity-text-light': '#333333', 'document-history-activity-text-light': '#929299',
'document-history-table-header-fg': '#000',
'document-history-table-border': 'lightgray',
'document-history-table-border-light': '#D9D9D9',
/* Accents */ /* Accents */
'accent-icon': '#16B378', 'accent-icon': '#16B378',
@ -276,6 +277,16 @@ export const GristLight: ThemeColors = {
'input-readonly-bg': '#F7F7F7', 'input-readonly-bg': '#F7F7F7',
'input-readonly-border': '#E8E8E8', 'input-readonly-border': '#E8E8E8',
/* Choice Tokens */
'choice-token-fg': '#000000',
'choice-token-blank-fg': '#929299',
'choice-token-bg': '#E8E8E8',
'choice-token-selected-bg': '#D9D9D9',
'choice-token-selected-border': '#16B378',
'choice-token-invalid-fg': '#000000',
'choice-token-invalid-bg': 'white',
'choice-token-invalid-border': '#D0021B',
/* Choice Entry */ /* Choice Entry */
'choice-entry-bg': 'white', 'choice-entry-bg': 'white',
'choice-entry-border': '#D9D9D9', 'choice-entry-border': '#D9D9D9',
@ -284,7 +295,6 @@ export const GristLight: ThemeColors = {
/* Select Buttons */ /* Select Buttons */
'select-button-fg': '#262633', 'select-button-fg': '#262633',
'select-button-placeholder-fg': '#929299', 'select-button-placeholder-fg': '#929299',
'select-button-disabled-fg': 'grey',
'select-button-bg': 'white', 'select-button-bg': 'white',
'select-button-border': '#D9D9D9', 'select-button-border': '#D9D9D9',
'select-button-border-invalid': '#D0021B', 'select-button-border-invalid': '#D0021B',
@ -293,7 +303,7 @@ export const GristLight: ThemeColors = {
'menu-text': '#929299', 'menu-text': '#929299',
'menu-light-text': '#929299', 'menu-light-text': '#929299',
'menu-bg': 'white', 'menu-bg': 'white',
'menu-subheader-fg': 'unset', 'menu-subheader-fg': '#262633',
'menu-border': '#E8E8E8', 'menu-border': '#E8E8E8',
'menu-shadow': 'rgba(38, 38, 51, 0.6)', 'menu-shadow': 'rgba(38, 38, 51, 0.6)',
@ -304,14 +314,14 @@ export const GristLight: ThemeColors = {
'menu-item-disabled-fg': '#D9D9D9', 'menu-item-disabled-fg': '#D9D9D9',
'menu-item-icon-fg': '#929299', 'menu-item-icon-fg': '#929299',
'menu-item-icon-selected-fg': 'white', 'menu-item-icon-selected-fg': 'white',
'menu-item-link-fg': '#16B378',
'menu-item-link-selected-fg': '#009058',
'menu-item-link-selected-bg': '#E8E8E8',
/* Autocomplete */ /* Autocomplete */
'autocomplete-match-text': '#16B378', 'autocomplete-match-text': '#16B378',
'autocomplete-selected-match-text': '#B1FFE2', 'autocomplete-selected-match-text': '#B1FFE2',
'autocomplete-item-selected-bg': '#E8E8E8', 'autocomplete-item-selected-bg': '#E8E8E8',
'autocomplete-add-new-circle-fg': '#FFFFFF',
'autocomplete-add-new-circle-bg': '#16B378',
'autocomplete-add-new-circle-selected-bg': '#009058',
/* Search */ /* Search */
'search-border': 'grey', 'search-border': 'grey',
@ -346,7 +356,7 @@ export const GristLight: ThemeColors = {
/* Page Widget Picker */ /* Page Widget Picker */
'widget-picker-primary-bg': 'white', 'widget-picker-primary-bg': 'white',
'widget-picker-secondary-bg': '#F7F7F7', 'widget-picker-secondary-bg': '#F7F7F7',
'widget-picker-item-fg': 'unset', 'widget-picker-item-fg': '#262633',
'widget-picker-item-selected-bg': 'rgba(217,217,217,0.6)', 'widget-picker-item-selected-bg': 'rgba(217,217,217,0.6)',
'widget-picker-item-disabled-bg': 'rgba(217,217,217,0.6)', 'widget-picker-item-disabled-bg': 'rgba(217,217,217,0.6)',
'widget-picker-icon': '#929299', 'widget-picker-icon': '#929299',
@ -394,7 +404,8 @@ export const GristLight: ThemeColors = {
/* Button Groups */ /* Button Groups */
'button-group-fg': '#262633', 'button-group-fg': '#262633',
'button-group-light-fg': '#929299', 'button-group-light-fg': '#929299',
'button-group-bg': 'unset', 'button-group-bg': 'transparent',
'button-group-bg-hover': '#D9D9D9',
'button-group-icon': '#929299', 'button-group-icon': '#929299',
'button-group-border': '#D9D9D9', 'button-group-border': '#D9D9D9',
'button-group-border-hover': '#BFBFBF', 'button-group-border-hover': '#BFBFBF',
@ -407,6 +418,7 @@ export const GristLight: ThemeColors = {
'access-rules-table-header-fg': '#262633', 'access-rules-table-header-fg': '#262633',
'access-rules-table-header-bg': 'rgba(217,217,217,0.6)', 'access-rules-table-header-bg': 'rgba(217,217,217,0.6)',
'access-rules-table-body-fg': '#929299', 'access-rules-table-body-fg': '#929299',
'access-rules-table-body-light-fg': '#D9D9D9',
'access-rules-table-border': '#929299', 'access-rules-table-border': '#929299',
'access-rules-column-list-border': '#D9D9D9', 'access-rules-column-list-border': '#D9D9D9',
'access-rules-column-item-fg': '#262633', 'access-rules-column-item-fg': '#262633',
@ -476,8 +488,7 @@ export const GristLight: ThemeColors = {
'color-select-shadow': 'rgba(38,38,51,0.6)', 'color-select-shadow': 'rgba(38,38,51,0.6)',
'color-select-font-options-border': '#D9D9D9', 'color-select-font-options-border': '#D9D9D9',
'color-select-font-option-fg': '#262633', 'color-select-font-option-fg': '#262633',
'color-select-font-option-bg': '#FFFFFF', 'color-select-font-option-bg-hover': '#D9D9D9',
'color-select-font-option-bg-hover': '#F7F7F7',
'color-select-font-option-fg-selected': '#FFFFFF', 'color-select-font-option-fg-selected': '#FFFFFF',
'color-select-font-option-bg-selected': '#262633', 'color-select-font-option-bg-selected': '#262633',
'color-select-color-square-border': '#D9D9D9', 'color-select-color-square-border': '#D9D9D9',
@ -497,9 +508,42 @@ export const GristLight: ThemeColors = {
'login-page-bg': 'white', 'login-page-bg': 'white',
'login-page-backdrop': '#F5F8FA', 'login-page-backdrop': '#F5F8FA',
'login-page-line': '#F7F7F7', 'login-page-line': '#F7F7F7',
'login-page-google-button-fg': '#262633',
'login-page-google-button-bg': '#F7F7F7',
'login-page-google-button-bg-hover': '#E8E8E8',
'login-page-google-button-border': '#D9D9D9',
/* Formula Assistant */ /* Formula Assistant */
'formula-assistant-header-bg': '#F7F7F7', 'formula-assistant-header-bg': '#F7F7F7',
'formula-assistant-border': '#D9D9D9', 'formula-assistant-border': '#D9D9D9',
'formula-assistant-preformatted-text-bg': '#F7F7F7', 'formula-assistant-preformatted-text-bg': '#F7F7F7',
/* Attachments */
'attachments-editor-button-fg': '#009058',
'attachments-editor-button-hover-fg': '#16B378',
'attachments-editor-button-bg': '#FFFFFF',
'attachments-editor-button-hover-bg': '#E8E8E8',
'attachments-editor-button-border': '#D9D9D9',
'attachments-editor-button-icon': '#929299',
'attachments-editor-border': '#E8E8E8',
'attachments-cell-icon-fg': 'white',
'attachments-cell-icon-bg': '#D9D9D9',
'attachments-cell-icon-hover-bg': '#929299',
/* Switch */
'switch-slider-fg': '#ccc',
'switch-circle-fg': 'white',
/* Announcement Popups */
'announcement-popup-fg': '#000000',
'announcement-popup-bg': '#DCF4EB',
/* Scroll Shadow */
'scroll-shadow': 'rgba(217,217,217,0.6)',
/* Toggle Checkboxes */
'toggle-checkbox-fg': '#606060',
/* Numeric Spinners */
'numeric-spinner-fg': '#606060',
}; };

@ -468,7 +468,9 @@ describe('CellColor', function() {
await gu.openCellColorPicker(); await gu.openCellColorPicker();
// check color preview is correct // check color preview is correct
assert.equal(await driver.find('.test-text-hex').value(), '#606060'); assert.equal(await driver.find('.test-text-hex').value(), 'default');
assert.equal(await driver.find('.test-text-color-square').getCssValue('background-color'),
'rgba(96, 96, 96, 1)');
// close color picker // close color picker
await driver.sendKeys(Key.ENTER); await driver.sendKeys(Key.ENTER);
@ -482,7 +484,9 @@ describe('CellColor', function() {
await gu.openCellColorPicker(); await gu.openCellColorPicker();
// check color preview is correct // check color preview is correct
assert.equal(await driver.find('.test-text-hex').value(), '#2CB0AF'); assert.equal(await driver.find('.test-text-hex').value(), 'default');
assert.equal(await driver.find('.test-text-color-square').getCssValue('background-color'),
'rgba(44, 176, 175, 1)');
// close picker // close picker
await driver.sendKeys(Key.ESCAPE); await driver.sendKeys(Key.ESCAPE);

@ -441,7 +441,7 @@ describe('ChoiceList', function() {
const convertColumn = stackWrapFunc(async function(typeRe: RegExp) { const convertColumn = stackWrapFunc(async function(typeRe: RegExp) {
await gu.setType(typeRe); await gu.setType(typeRe);
await gu.waitForServer(); await gu.waitForServer();
await driver.findContent('.type_transform_prompt button', /Apply/).click(); await driver.findContent('.test-type-transform-apply', /Apply/).click();
await gu.waitForServer(); await gu.waitForServer();
}); });

@ -278,7 +278,7 @@ describe('CustomWidgets', function () {
assert.equal(await getWidgetColor(), 'rgba(38, 38, 51, 1)'); assert.equal(await getWidgetColor(), 'rgba(38, 38, 51, 1)');
// Switch the theme to GristDark. // Switch the theme to GristDark.
await gu.setGristTheme({appearance: 'dark'}); await gu.setGristTheme({appearance: 'dark', syncWithOS: false});
await driver.navigate().back(); await driver.navigate().back();
await gu.waitForDocToLoad(); await gu.waitForDocToLoad();
@ -286,7 +286,7 @@ describe('CustomWidgets', function () {
assert.equal(await getWidgetColor(), 'rgba(239, 239, 239, 1)'); assert.equal(await getWidgetColor(), 'rgba(239, 239, 239, 1)');
// Switch back to GristLight. // Switch back to GristLight.
await gu.setGristTheme({appearance: 'light'}); await gu.setGristTheme({appearance: 'light', syncWithOS: true});
await driver.navigate().back(); await driver.navigate().back();
await gu.waitForDocToLoad(); await gu.waitForDocToLoad();

@ -260,13 +260,14 @@ describe('MultiColumn', function() {
assert.isFalse(await deriveDisabled()); assert.isFalse(await deriveDisabled());
assert.isFalse(await labelDisabled()); assert.isFalse(await labelDisabled());
assert.isFalse(await setTriggerDisabled()); assert.isFalse(await setTriggerDisabled());
assert.isFalse(await transformSectionDisabled()); assert.isTrue(await transformSectionDisabled());
assert.isFalse(await addConditionDisabled()); assert.isFalse(await addConditionDisabled());
assert.isFalse(await columnTypeDisabled()); assert.isFalse(await columnTypeDisabled());
// Make one column a data column, to disable type selector. // Make one column a data column, to disable type selector.
await selectColumns('Test1'); await selectColumns('Test1');
await gu.changeBehavior('Convert column to data'); await gu.changeBehavior('Convert column to data');
assert.isFalse(await transformSectionDisabled());
await selectColumns('Test1', 'Test3'); await selectColumns('Test1', 'Test3');
assert.isTrue(await columnTypeDisabled()); assert.isTrue(await columnTypeDisabled());
@ -1287,8 +1288,7 @@ async function setDataDisabled() {
} }
async function transformSectionDisabled() { async function transformSectionDisabled() {
const elements = await driver.findAll(".test-panel-transform .test-panel-disabled-section"); return (await driver.find(".test-fbuilder-edit-transform").getAttribute('disabled')) === 'true';
return elements.length === 1;
} }
async function addConditionDisabled() { async function addConditionDisabled() {

@ -154,12 +154,12 @@ describe("SelectBy", function() {
assert.equal(await gu.getDetailCell({section, rowNum: 1, col: 'A'}).getText(), '1'); assert.equal(await gu.getDetailCell({section, rowNum: 1, col: 'A'}).getText(), '1');
// Check there are nav buttons in the card view. // Check there are nav buttons in the card view.
assert.equal(await section.find('.btn.detail-left').isPresent(), true); assert.equal(await section.find('.detail-button.detail-left').isPresent(), true);
assert.equal(await section.find('.btn.detail-right').isPresent(), true); assert.equal(await section.find('.detail-button.detail-right').isPresent(), true);
assert.equal(await section.find('.grist-single-record__menu__count').getText(), '1 OF 1'); assert.equal(await section.find('.grist-single-record__menu__count').getText(), '1 OF 1');
// Now add a record to the source table using the card view. // Now add a record to the source table using the card view.
await section.find('.btn.detail-add-btn').click(); await section.find('.detail-button.detail-add-btn').click();
assert.equal(await gu.getDetailCell({section, rowNum: 1, col: 'A'}).getText(), ''); assert.equal(await gu.getDetailCell({section, rowNum: 1, col: 'A'}).getText(), '');
await gu.getDetailCell({section, rowNum: 1, col: 'A'}).click(); await gu.getDetailCell({section, rowNum: 1, col: 'A'}).click();
await gu.sendKeys('1', Key.ENTER); await gu.sendKeys('1', Key.ENTER);

@ -3133,16 +3133,27 @@ export async function downloadSectionCsvGridCells(
export async function setGristTheme(options: { export async function setGristTheme(options: {
appearance: 'light' | 'dark', appearance: 'light' | 'dark',
syncWithOS: boolean,
skipOpenSettingsPage?: boolean, skipOpenSettingsPage?: boolean,
}) { }) {
const {appearance, skipOpenSettingsPage} = options; const {appearance, syncWithOS, skipOpenSettingsPage} = options;
if (!skipOpenSettingsPage) { if (!skipOpenSettingsPage) {
await openProfileSettingsPage(); await openProfileSettingsPage();
} }
await driver.find('.test-theme-config-appearance .test-select-open').click();
await driver.findContent('.test-select-menu li', appearance === 'light' ? 'Light' : 'Dark') const syncWithOSCheckbox = await driver.find('.test-theme-config-sync-with-os');
.click(); const isSyncWithOSChecked = await syncWithOSCheckbox.getAttribute('checked') === 'true';
await waitForServer(); if (syncWithOS !== isSyncWithOSChecked) {
await syncWithOSCheckbox.click();
await waitForServer();
}
if (!syncWithOS) {
await driver.find('.test-theme-config-appearance .test-select-open').click();
await driver.findContent('.test-select-menu li', appearance === 'light' ? 'Light' : 'Dark')
.click();
await waitForServer();
}
} }
} // end of namespace gristUtils } // end of namespace gristUtils

Loading…
Cancel
Save