(core) Add dark mode to user preferences

Summary:
Adds initial implementation of dark mode. Preferences for dark mode are
available on the account settings page. Dark mode is currently a beta feature
as there are still some small bugs to squash and a few remaining UI elements
to style.

Test Plan: Browser tests.

Reviewers: jarek

Reviewed By: jarek

Subscribers: paulfitz, jarek

Differential Revision: https://phab.getgrist.com/D3587
pull/223/head
George Gevoian 2 years ago
parent d7b3fb972c
commit ec157dc469

@ -5,7 +5,7 @@ import {createUserImage} from 'app/client/ui/UserImage';
import {cssMemberImage, cssMemberListItem, cssMemberPrimary,
cssMemberSecondary, cssMemberText} from 'app/client/ui/UserItem';
import {basicButton, basicButtonLink} from 'app/client/ui2018/buttons';
import {colors, testId} from 'app/client/ui2018/cssVars';
import {testId, theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {menuCssClass, menuDivider} from 'app/client/ui2018/menus';
import {PermissionDataWithExtraUsers} from 'app/common/ActiveDocAPI';
@ -130,7 +130,7 @@ const cssUserItem = styled(cssMemberListItem, `
padding: 8px 16px;
align-items: center;
&:hover {
background-color: ${colors.lightGrey};
background-color: ${theme.lightHover};
}
`);
@ -146,7 +146,9 @@ const cssUserButton = styled('div', `
white-space: nowrap;
gap: 4px;
&:hover {
background-color: ${colors.darkGrey};
--icon-color: ${theme.controlFg};
color: ${theme.controlFg};
background-color: ${theme.hover};
}
&-disabled {
visibility: hidden;

@ -12,7 +12,7 @@ import {TableData} from 'app/client/models/TableData';
import {shadowScroll} from 'app/client/ui/shadowScroll';
import {bigBasicButton, bigPrimaryButton} from 'app/client/ui2018/buttons';
import {squareCheckbox} from 'app/client/ui2018/checkbox';
import {colors, testId} from 'app/client/ui2018/cssVars';
import {testId, theme} from 'app/client/ui2018/cssVars';
import {textInput} from 'app/client/ui2018/editableLabel';
import {cssIconButton, icon} from 'app/client/ui2018/icons';
import {menu, menuItemAsync} from 'app/client/ui2018/menus';
@ -1445,45 +1445,50 @@ const cssSectionHeading = styled('div', `
align-items: center;
margin-bottom: 8px;
font-weight: bold;
color: ${colors.slate};
color: ${theme.lightText};
`);
const cssTableName = styled('span', `
color: ${colors.dark};
color: ${theme.text};
`);
const cssInput = styled(textInput, `
color: ${theme.inputFg};
background-color: ${theme.inputBg};
width: 100%;
border: 1px solid transparent;
cursor: pointer;
&:hover {
border: 1px solid ${colors.darkGrey};
border: 1px solid ${theme.inputBorder};
}
&:focus {
box-shadow: inset 0 0 0 1px ${colors.cursor};
border-color: ${colors.cursor};
box-shadow: inset 0 0 0 1px ${theme.controlFg};
border-color: ${theme.controlFg};
cursor: unset;
}
&[disabled] {
color: ${colors.dark};
background-color: ${colors.mediumGreyOpaque};
color: ${theme.inputDisabledFg};
background-color: ${theme.inputDisabledBg};
box-shadow: unset;
border-color: transparent;
}
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
`);
const cssConditionError = styled('div', `
margin-top: 4px;
width: 100%;
color: ${colors.error};
color: ${theme.errorText};
`);
/**
* Fairly general table styles.
*/
const cssTableRounded = styled('div', `
border: 1px solid ${colors.slate};
border: 1px solid ${theme.accessRulesTableBorder};
border-radius: 8px;
overflow: hidden;
`);
@ -1491,7 +1496,7 @@ const cssTableRounded = styled('div', `
// Row with a border
const cssTableRow = styled('div', `
display: flex;
border-bottom: 1px solid ${colors.slate};
border-bottom: 1px solid ${theme.accessRulesTableBorder};
&:last-child {
border-bottom: none;
}
@ -1499,8 +1504,8 @@ const cssTableRow = styled('div', `
// Darker table header
const cssTableHeaderRow = styled(cssTableRow, `
background-color: ${colors.mediumGrey};
color: ${colors.dark};
background-color: ${theme.accessRulesTableHeaderBg};
color: ${theme.accessRulesTableHeaderFg};
`);
// Cell for table column header.
@ -1517,7 +1522,7 @@ const cssCell = styled('div', `
overflow: hidden;
&-rborder {
border-right: 1px solid ${colors.slate};
border-right: 1px solid ${theme.accessRulesTableBorder};
}
&-center {
text-align: center;
@ -1551,6 +1556,7 @@ const cssRuleBody = styled('div', `
`);
const cssRuleDescription = styled('div', `
color: ${theme.text};
display: flex;
align-items: center;
margin: 16px 0 8px 0;
@ -1568,6 +1574,6 @@ const cssCenterContent = styled('div', `
`);
const cssDefaultLabel = styled('div', `
color: ${colors.slate};
color: ${theme.accessRulesTableBodyFg};
font-weight: bold;
`);

@ -44,7 +44,6 @@
--color-hint-text: #888;
--scroll-bar-width: 12px;
--scroll-bar-bg: #f0f0f0;
/* fonts */
--font-navbar-title: "Helvetica", "Arial", sans-serif;
@ -96,12 +95,12 @@ body {
.show_scrollbar::-webkit-scrollbar {
width: var(--scroll-bar-width);
height: var(--scroll-bar-width);
background-color: var(--scroll-bar-bg);
background-color: var(--scroll-bar-bg, #f0f0f0);
}
.show_scrollbar::-webkit-scrollbar-thumb {
background-color: rgba(0,0,0,0.3);
background-color: var(--scroll-bar-fg, #a8a8a8);
-webkit-border-radius: 100px;
border: 2px solid var(--scroll-bar-bg);
border: 2px solid var(--scroll-bar-bg, #f0f0f0);
}
.show_scrollbar::-webkit-scrollbar-thumb:vertical {
min-height: 4rem;
@ -110,13 +109,16 @@ body {
min-width: 4rem;
}
.show_scrollbar::-webkit-scrollbar-thumb:hover {
background-color: rgba(0,0,0,0.4); /* Some darker color when you click it */
background-color: var(--scroll-bar-hover-fg, #8f8f8f);
-webkit-border-radius: 100px;
}
.show_scrollbar::-webkit-scrollbar-thumb:active {
background-color: rgba(0,0,0,0.5); /* Some darker color when you click it */
background-color: var(--scroll-bar-active-fg, #7c7c7c);
-webkit-border-radius: 100px;
}
.show_scrollbar::-webkit-scrollbar-corner {
background-color: var(--scroll-bar-bg, #f0f0f0);
}
div.dev_warning {
position: absolute;
z-index: 10;

@ -1,10 +1,12 @@
var ace = require('brace');
var _ = require('underscore');
// Used to load python language settings and 'chrome' ace style
// Used to load python language settings and color themes
require('brace/mode/python');
require('brace/theme/chrome');
require('brace/theme/dracula');
require('brace/ext/language_tools');
var {setupAceEditorCompletions} = require('./AceEditorCompletions');
var {getGristConfig} = require('../../common/urlUtils');
var dom = require('../lib/dom');
var dispose = require('../lib/dispose');
var modelUtil = require('../models/modelUtil');
@ -198,7 +200,14 @@ AceEditor.prototype._setup = function() {
});
this.session = this.editor.getSession();
this.session.setMode('ace/mode/python');
this.editor.setTheme('ace/theme/chrome');
const gristTheme = this.gristDoc?.docPageModel.appModel.currentTheme;
this._setAceTheme(gristTheme?.get());
if (!getGristConfig().enableCustomCss && gristTheme) {
this.autoDispose(gristTheme.addListener((theme) => {
this._setAceTheme(theme);
}));
}
// Default line numbers to hidden
this.editor.renderer.setShowGutter(false);
@ -270,6 +279,12 @@ AceEditor.prototype._getContentHeight = function() {
return Math.max(1, this.session.getScreenLength()) * this.editor.renderer.lineHeight;
};
AceEditor.prototype._setAceTheme = function(gristTheme) {
const {enableCustomCss} = getGristConfig();
const gristAppearance = gristTheme?.appearance;
const aceTheme = gristAppearance === 'dark' && !enableCustomCss ? 'dracula' : 'chrome';
this.editor.setTheme(`ace/theme/${aceTheme}`);
};
let _RangeConstructor = null; //singleton, load it lazily
AceEditor.makeRange = function(a, b, c, d) {

@ -27,7 +27,11 @@
}
.action_info_from_self {
color: #333333;
color: var(--grist-theme-document-history-activity-text-light, #333333);
}
.action_desc {
color: var(--grist-theme-document-history-activity-text-light, unset);
}
.action_log_item.undone > .action_info,
@ -46,10 +50,12 @@
}
.action_log_rename_pre {
color: #333333;
background: #faa;
}
.action_log_rename_post {
color: #333333;
background: #afa;
}
@ -62,7 +68,7 @@
text-align: center;
margin-top: 0;
padding-top: 0;
color: #000;
color: var(--grist-theme-document-history-activity-text, #000);
}
.action_log_table td {
@ -100,6 +106,7 @@
}
.action_log_cell_remove {
color: #333333;
background: #faa;
text-decoration: line-through;
padding-left: 2px;
@ -111,6 +118,7 @@
}
.action_log_cell_add {
color: #333333;
background: #afa;
padding-left: 2px;
padding-right: 2px;

@ -16,7 +16,7 @@ import {cssLabel, cssRow, cssSeparator} from 'app/client/ui/RightPanelStyles';
import {cssFieldEntry, cssFieldLabel, IField, VisibleFieldsConfig } from 'app/client/ui/VisibleFieldsConfig';
import {IconName} from 'app/client/ui2018/IconList';
import {squareCheckbox} from 'app/client/ui2018/checkbox';
import {colors, vars} from 'app/client/ui2018/cssVars';
import {theme, vars} from 'app/client/ui2018/cssVars';
import {cssDragger} from 'app/client/ui2018/draggableList';
import {icon} from 'app/client/ui2018/icons';
import {IOptionFull, linkSelect, menu, menuItem, menuText, select} from 'app/client/ui2018/menus';
@ -33,6 +33,7 @@ import debounce = require('lodash/debounce');
import defaults = require('lodash/defaults');
import defaultsDeep = require('lodash/defaultsDeep');
import isNumber = require('lodash/isNumber');
import merge = require('lodash/merge');
import sum = require('lodash/sum');
import union = require('lodash/union');
import type {Annotations, Config, Datum, ErrorBar, Layout, LayoutAxis, Margin,
@ -221,6 +222,8 @@ export class ChartView extends Disposable {
this.listenTo(this.sortedRows, 'rowNotify', this._update);
this.autoDispose(this.sortedRows.getKoArray().subscribe(this._update));
this.autoDispose(this._formatterComp.subscribe(this._update));
this.autoDispose(this.gristDoc.docPageModel.appModel.currentTheme.addListener(() =>
this._update()));
}
public prepareToPrint(onOff: boolean) {
@ -333,7 +336,7 @@ export class ChartView extends Disposable {
// meantime and cause error later. So let's check again.
if (this.isDisposed()) { return; }
const layout: Partial<Layout> = defaultsDeep(plotData.layout, getPlotlyLayout(options));
const layout: Partial<Layout> = defaultsDeep(plotData.layout, this._getPlotlyLayout(options));
const config: Partial<Config> = {...plotData.config, displayModeBar: false};
// react() can be used in place of newPlot(), and is faster when updating an existing plot.
await Plotly.react(this._chartDom, plotData.data, layout, config);
@ -348,6 +351,50 @@ export class ChartView extends Disposable {
private _isCompatibleSeries(col: ColumnRec) {
return isNumericOnly(this._chartType.peek()) ? isNumericLike(col) : true;
}
private _getPlotlyLayout(options: ChartOptions): Partial<Layout> {
// Note that each call to getPlotlyLayout() creates a new layout object. We are intentionally
// avoiding reuse because Plotly caches too many layout calculations when the object is reused.
const yaxis: Partial<LayoutAxis> = {automargin: true, title: {standoff: 0}};
const xaxis: Partial<LayoutAxis> = {automargin: true, title: {standoff: 0}};
if (options.logYAxis) { yaxis.type = 'log'; }
if (options.invertYAxis) { yaxis.autorange = 'reversed'; }
const layout = {
// Margins include labels, titles, legend, and may get auto-expanded beyond this.
margin: {
l: 50,
r: 50,
b: 40, // Space below chart which includes x-axis labels
t: 30, // Space above the chart (doesn't include any text)
pad: 4
} as Margin,
yaxis,
xaxis,
...(options.stacked ? {barmode: 'relative'} : {}),
};
return merge(layout, this._getPlotlyTheme());
}
private _getPlotlyTheme(): Partial<Layout> {
const appModel = this.gristDoc.docPageModel.appModel;
const {colors} = appModel.currentTheme.get();
return {
paper_bgcolor: colors['chart-bg'],
plot_bgcolor: colors['chart-bg'],
xaxis: {
color: colors['chart-x-axis'],
},
yaxis: {
color: colors['chart-y-axis'],
},
font: {
color: colors['chart-fg'],
},
legend: {
bgcolor: colors['chart-legend-bg'],
},
};
}
}
/**
@ -420,32 +467,6 @@ function extractErrorBars(series: Series[], options: ChartOptions): Map<Series,
defaults(ChartView.prototype, BaseView.prototype);
Object.assign(ChartView.prototype, BackboneEvents);
function getPlotlyLayout(options: ChartOptions): Partial<Layout> {
// Note that each call to getPlotlyLayout() creates a new layout object. We are intentionally
// avoiding reuse because Plotly caches too many layout calculations when the object is reused.
const yaxis: Partial<LayoutAxis> = {automargin: true, title: {standoff: 0}};
const xaxis: Partial<LayoutAxis> = {automargin: true, title: {standoff: 0}};
if (options.logYAxis) { yaxis.type = 'log'; }
if (options.invertYAxis) { yaxis.autorange = 'reversed'; }
return {
// Margins include labels, titles, legend, and may get auto-expanded beyond this.
margin: {
l: 50,
r: 50,
b: 40, // Space below chart which includes x-axis labels
t: 30, // Space above the chart (doesn't include any text)
pad: 4
} as Margin,
legend: {
// Translucent background, so chart data is still visible if legend overlaps it.
bgcolor: "#FFFFFF80",
},
yaxis,
xaxis,
...(options.stacked ? {barmode: 'relative'} : {}),
};
}
/**
* The grainjs component for side-pane configuration options for a Chart section.
*/
@ -1257,7 +1278,7 @@ const cssRowLabel = styled('div', `
margin-right: 8px;
font-weight: initial; /* negate bootstrap */
color: ${colors.dark};
color: ${theme.text};
overflow: hidden;
text-overflow: ellipsis;
user-select: none;
@ -1265,7 +1286,7 @@ const cssRowLabel = styled('div', `
const cssRowHelp = styled(cssRow, `
font-size: ${vars.smallFontSize};
color: ${colors.slate};
color: ${theme.lightText};
`);
const cssAddIcon = styled(icon, `
@ -1275,15 +1296,15 @@ const cssAddIcon = styled(icon, `
const cssAddYAxis = styled('div', `
display: flex;
cursor: pointer;
color: ${colors.lightGreen};
--icon-color: ${colors.lightGreen};
color: ${theme.controlFg};
--icon-color: ${theme.controlFg};
&:not(:first-child) {
margin-top: 8px;
}
&:hover, &:focus, &:active {
color: ${colors.darkGreen};
--icon-color: ${colors.darkGreen};
color: ${theme.controlHoverFg};
--icon-color: ${theme.controlHoverFg};
}
`);
@ -1299,7 +1320,7 @@ const cssRemoveIcon = styled(icon, `
const cssHintRow = styled('div', `
margin: -4px 16px 8px 16px;
color: ${colors.slate};
color: ${theme.lightText};
`);
const cssRangeInput = styled('input', `

@ -15,9 +15,38 @@
}
.g-code-viewer.hljs {
color: var(--grist-theme-code-view-text, #444);
background-color: inherit;
}
.g-code-panel-denied {
text-align: center;
}
.g-code-viewer .hljs-keyword {
color: var(--grist-theme-code-view-keyword, #444);
}
.g-code-viewer .hljs-comment {
color: var(--grist-theme-code-view-comment, #888888);
}
.g-code-viewer .hljs-meta {
color: var(--grist-theme-code-view-meta, #1F7199);
}
.g-code-viewer .hljs-title {
color: var(--grist-theme-code-view-title, #880000);
}
.g-code-viewer .hljs-params {
color: var(--grist-theme-code-view-params, #444);
}
.g-code-viewer .hljs-string {
color: var(--grist-theme-code-view-string, #880000);
}
.g-code-viewer .hljs-number {
color: var(--grist-theme-code-view-number, #880000);
}

@ -47,7 +47,7 @@ export class DataTables extends Disposable {
cssItem(
testId('table'),
cssLeft(
dom.domComputed((use) => cssGreenIcon(
dom.domComputed((use) => cssTableTypeIcon(
use(tableRec.summarySourceTable) !== 0 ? 'PivotLight' : 'TypeTable',
testId(`table-id-${use(tableRec.tableId)}`)
)),
@ -107,7 +107,7 @@ export class DataTables extends Disposable {
const tableName = [
use(table.tableNameDef), isSummaryTable ? use(table.groupDesc) : ''
].filter(p => Boolean(p?.trim())).join(' ');
return dom('span', tableName);
return cssTableName(tableName);
} else {
return dom('div', // to disable flex grow in the widget
dom.domComputed(fromKo(table.rawViewSection), vs =>
@ -178,9 +178,9 @@ const cssItem = styled('div', `
width: 100%;
height: calc(1em * 56/13); /* 56px for 13px font */
max-width: 750px;
border: 1px solid ${css.colors.mediumGrey};
border: 1px solid ${css.theme.rawDataTableBorder};
&:hover {
border-color: ${css.colors.slate};
border-color: ${css.theme.rawDataTableBorderHover};
}
`);
@ -224,8 +224,8 @@ const cssRight = styled('div', `
flex: none;
`);
const cssGreenIcon = styled(icon, `
--icon-color: ${css.colors.lightGreen};
const cssTableTypeIcon = styled(icon, `
--icon-color: ${css.theme.accentIcon};
`);
const cssLine = styled('span', `
@ -246,7 +246,7 @@ const cssTableRowsWrapper = styled('div', `
width: 80px;
overflow: hidden;
align-items: baseline;
color: ${css.colors.slate};
color: ${css.theme.lightText};
line-height: 18px;
padding: 0px 2px;
`);
@ -256,12 +256,12 @@ const cssHoverWrapper = styled('div', `
overflow: hidden;
cursor: default;
align-items: baseline;
color: ${css.colors.slate};
color: ${css.theme.lightText};
transition: background 0.05s;
padding: 0px 2px;
line-height: 18px;
&:hover {
background: ${css.colors.lightGrey};
background: ${css.theme.lightHover};
}
`);
@ -272,6 +272,7 @@ const cssTableId = styled(cssLine, `
const cssTableRows = cssTableId;
const cssTableTitle = styled('div', `
color: ${css.theme.text};
white-space: nowrap;
`);
@ -294,3 +295,7 @@ const cssTableList = styled('div', `
const cssLoadingDots = styled(loadingDots, `
--dot-size: 6px;
`);
const cssTableName = styled('span', `
color: ${css.theme.text};
`);

@ -9,7 +9,7 @@
left: 0;
width: 100%;
background: white;
background: var(--grist-theme-page-panels-main-panel-bg, white);
z-index: 1;
margin-top: -3px;
}
@ -37,15 +37,15 @@
min-height: 16px;
white-space: pre;
word-wrap: break-word;
color: black;
color: var(--grist-theme-cell-fg, black);
}
.g_record_detail_value.record-add {
background-color: #f6f6ff;
background-color: var(--grist-theme-table-add-new-bg, #f6f6ff);
}
.g_record_detail_value.scissors {
outline: 2px dashed var(--grist-color-cursor);
outline: 2px dashed var(--grist-theme-cursor, var(--grist-color-cursor));
}
.g_record_detail_value.draft {
@ -55,7 +55,7 @@
.detail_row_num {
font-size: var(--grist-x-small-font-size);
font-weight: normal;
color: var(--grist-color-slate);
color: var(--grist-theme-text-light, var(--grist-color-slate));
padding: 8px;
display: flex;
align-items: center;
@ -163,7 +163,7 @@
.detail_theme_record_compact {
/* 12px is enough margin on the right to include most of the floating scrollbar on MacOS */
padding: 4px 16px 0px 16px;
background-color: var(--grist-color-medium-grey);
background-color: var(--grist-theme-card-compact-widget-bg, var(--grist-color-medium-grey));
}
.detail_theme_record_compact.detailview_record_single {
@ -175,12 +175,12 @@
}
.detail_theme_record_compact > .g_record_detail_inner {
background-color: white;
background-color: var(--grist-theme-card-compact-record-bg, white);
position: relative;
}
.detail_theme_record_compact > .g_record_detail_inner > .layout_root {
border: 1px solid var(--grist-color-dark-grey);
border: 1px solid var(--grist-theme-card-compact-border, var(--grist-color-dark-grey));
border-right: none;
border-bottom: none;
}
@ -196,8 +196,8 @@
.detail_theme_field_compact {
border-top: none;
border-left: none;
border-right: 1px solid var(--grist-color-dark-grey);
border-bottom: 1px solid var(--grist-color-dark-grey);
border-right: 1px solid var(--grist-theme-card-compact-border, var(--grist-color-dark-grey));
border-bottom: 1px solid var(--grist-theme-card-compact-border, var(--grist-color-dark-grey));
padding: 1px 1px 1px 5px;
margin: 0;
line-height: 1.2;
@ -206,7 +206,7 @@
.detail_theme_field_compact > .g_record_detail_label {
font-weight: normal;
font-size: var(--grist-small-font-size);
color: var(--grist-color-slate);
color: var(--grist-theme-card-compact-label, var(--grist-color-slate));
min-height: 0px;
white-space: nowrap;
@ -227,7 +227,7 @@
.detail_theme_field_form > .g_record_detail_label {
font-size: var(--grist-small-font-size);
color: var(--grist-color-slate);
color: var(--grist-theme-card-form-label, var(--grist-color-slate));
font-weight: bold;
min-height: 0px;
white-space: nowrap;
@ -241,7 +241,7 @@
* needs to learn to match the value box's style. Right now, the cell editor style is hard-coded.
*/
.detail_theme_field_form > .g_record_detail_value {
border: 1px solid lightgrey;
border: 1px solid var(--grist-theme-card-form-border, lightgrey);
}
.detail_theme_record_form {
@ -253,7 +253,7 @@
}
.detail_theme_record_form.detailview_record_detail {
border-bottom: 1px solid var(--grist-color-dark-grey);
border-bottom: 1px solid var(--grist-theme-card-list-form-border, var(--grist-color-dark-grey));
padding-bottom: 12px;
}
@ -272,20 +272,20 @@
}
.detail_theme_record_blocks.detailview_record_detail {
border-bottom: 1px solid var(--grist-color-dark-grey);
border-bottom: 1px solid var(--grist-theme-card-list-blocks-border, var(--grist-color-dark-grey));
padding-bottom: 8px;
}
.detail_theme_field_blocks {
padding: 6px;
margin: 8px;
background-color: var(--grist-color-medium-grey);
background-color: var(--grist-theme-card-blocks-bg, var(--grist-color-medium-grey));
border-radius: 2px;
}
.detail_theme_field_blocks > .g_record_detail_label {
font-size: var(--grist-small-font-size);
color: var(--grist-color-slate);
color: var(--grist-theme-card-blocks-label, var(--grist-color-slate));
font-weight: normal;
white-space: nowrap;
overflow: hidden;

@ -2,7 +2,7 @@ import {DocPageModel} from 'app/client/models/DocPageModel';
import {urlState} from 'app/client/models/gristUrlState';
import {docListHeader} from 'app/client/ui/DocMenuCss';
import {infoTooltip} from 'app/client/ui/tooltips';
import {colors, mediaXSmall} from 'app/client/ui2018/cssVars';
import {mediaXSmall, theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {loadingDots, loadingSpinner} from 'app/client/ui2018/loaders';
import {APPROACHING_LIMIT_RATIO, DataLimitStatus} from 'app/common/DocUsage';
@ -341,12 +341,11 @@ const cssLightlyBoldedText = styled('div', `
font-weight: 500;
`);
const cssIconAndText = styled('div', `
const cssWarningMessage = styled('div', `
color: ${theme.text};
--icon-color: ${theme.text};
display: flex;
gap: 16px;
`);
const cssWarningMessage = styled(cssIconAndText, `
margin-top: 16px;
`);
@ -392,6 +391,7 @@ const cssUsageMetrics = styled('div', `
`);
const cssUsageMetric = styled('div', `
color: ${theme.text};
display: flex;
flex-direction: column;
width: 180px;
@ -408,14 +408,14 @@ const cssProgressBarContainer = styled('div', `
width: 100%;
height: 4px;
border-radius: 5px;
background: ${colors.darkGrey};
background: ${theme.progressBarBg};
`);
const cssProgressBarFill = styled(cssProgressBarContainer, `
background: ${colors.lightGreen};
background: ${theme.progressBarFg};
&-approaching-limit {
background: ${colors.error};
background: ${theme.progressBarErrorFg};
}
`);

@ -6,7 +6,7 @@ import {
import { GristDoc } from "app/client/components/GristDoc";
import { ITooltipControl, showTooltip, tooltipCloseButton } from "app/client/ui/tooltips";
import { FieldEditorStateEvent } from "app/client/widgets/FieldEditor";
import { colors, testId } from "app/client/ui2018/cssVars";
import { testId, theme } from "app/client/ui2018/cssVars";
import { cssLink } from "app/client/ui2018/links";
/**
@ -408,7 +408,7 @@ class EditorAdapter extends Disposable implements Editor {
const styledTooltip = styled('div', `
display: flex;
align-items: center;
--icon-color: ${colors.lightGreen};
--icon-color: ${theme.controlFg};
& > .${cssLink.className} {
margin-left: 8px;
@ -430,7 +430,7 @@ function cellTooltip(clb: () => any) {
// Discard notification dom
const styledNotification = styled('div', `
cursor: pointer;
color: ${colors.lightGreen};
color: ${theme.controlFg};
&:hover {
text-decoration: underline;
}

@ -26,7 +26,10 @@ export class FormulaTransform extends ColumnTransform {
* Build the transform menu for a formula transform
*/
public buildDom() {
this.editor = this.autoDispose(AceEditor.create({ observable: this.transformColumn.formula }));
this.editor = this.autoDispose(AceEditor.create({
gristDoc: this.gristDoc,
observable: this.transformColumn.formula,
}));
return [
dom('div.transform_menu',
dom('div.transform_editor',

@ -1,4 +1,5 @@
.gridview_data_pane {
background-color: var(--grist-theme-table-body-bg, unset);
position: relative;
width: 100%;
overflow: hidden;
@ -22,7 +23,7 @@
overscroll-behavior: none;
z-index: 2; /* scrollbar should be over the overlay background */
border-top: 1px solid lightgrey;
border-top: 1px solid var(--grist-theme-table-header-border, lightgrey);
}
.gridview_data_pane > .gridview_data_scroll {
@ -48,7 +49,7 @@
}
.field.column_name {
border-bottom: 1px solid lightgray;
border-bottom: 1px solid var(--grist-theme-table-header-border, lightgray);
line-height: var(--gridview-header-height);
height: calc(var(--gridview-header-height) + 1px); /* Also should match height for overlay elements */
}
@ -70,8 +71,9 @@
width: 4rem; /* Also should match width for .gridview_header_corner, and the overlay elements */
flex: none;
border-bottom: 1px solid var(--grist-color-dark-grey);
background-color: var(--grist-color-light-grey);
border-bottom: 1px solid var(--grist-theme-table-header-border-dark, var(--grist-color-dark-grey));
color: var(--grist-theme-table-header-fg, unset);
background-color: var(--grist-theme-table-header-bg, var(--grist-color-light-grey));
z-index: 2; /* goes over data cells */
padding-top: 2px;
@ -100,7 +102,7 @@
* do not want !important, as it interferes with row selection.
*/
.gridview_data_row_num {
background-color: var(--grist-color-light-grey) !important;
background-color: var(--grist-theme-table-header-bg , var(--grist-color-light-grey)) !important;
}
.gridview_header_backdrop_top {
display: none;
@ -109,7 +111,7 @@
display: none;
}
.gridview_data_header {
background-color: var(--grist-color-light-grey) !important;
background-color: var(--grist-theme-table-header-bg, var(--grist-color-light-grey)) !important;
}
.print-widget .gridview_header_backdrop_left, .print-widget .gridview_data_corner_overlay {
display: none;
@ -125,15 +127,15 @@
display: table-header-group;
break-inside: avoid;
position: static;
border-top: 1px solid var(--grist-color-dark-grey);
border-left: 1px solid var(--grist-color-dark-grey);
border-top: 1px solid var(--grist-theme-table-header-border-dark, var(--grist-color-dark-grey));
border-left: 1px solid var(--grist-theme-table-header-border-dark, var(--grist-color-dark-grey));
}
.print-widget .gridview_data_header {
padding-left: 4rem !important;
}
.print-widget .gridview_data_pane .print-all-rows {
display: table-row-group;
border-left: 1px solid var(--grist-color-dark-grey);
border-left: 1px solid var(--grist-theme-table-body-border, var(--grist-color-dark-grey));
}
.print-widget .gridview_data_pane .print-row {
display: table-row;
@ -149,14 +151,14 @@
.scroll_shadow_top,
.scroll_shadow_left {
position:absolute;
background-color: var(--grist-color-light-grey) !important;
background-color: var(--grist-theme-table-header-bg, var(--grist-color-light-grey)) !important;
}
.gridview_data_corner_overlay {
width: 4rem;
height: calc(var(--gridview-header-height) + 1px); /* matches gridview_data_header height (+border) */
top: 1px; /* go under 1px border on scrollpane */
border-bottom: 1px solid lightgray;
border-bottom: 1px solid var(--grist-theme-table-header-border, lightgray);
z-index: 3;
cursor: pointer;
}
@ -176,7 +178,7 @@
this value is the position where this movement should stop.
*/
left: calc(4em + (var(--frozen-width, 0) - min(var(--frozen-scroll-offset, 0), var(--frozen-offset, 0))) * 1px);
box-shadow: -6px 0 6px 6px #444;
box-shadow: -6px 0 6px 6px var(--grist-theme-table-scroll-shadow, #444);
/* shadow should only show to the right of it (10px should be enough) */
-webkit-clip-path: polygon(0 0, 10px 0, 10px 100%, 0 100%);
clip-path: polygon(0 0, 10px 0, 10px 100%, 0 100%);
@ -188,7 +190,7 @@
height: 100%;
width: 0px;
left: 4em;
box-shadow: -8px 0 14px 4px #444;
box-shadow: -8px 0 14px 4px var(--grist-theme-table-scroll-shadow, #444);
-webkit-clip-path: polygon(0 0, 10px 0, 10px 100%, 0 100%);
clip-path: polygon(0 0, 28px 0, 24px 100%, 0 100%);
z-index: 3;
@ -204,7 +206,7 @@
as this component will be hidden when the scroll starts
*/
left: calc(4em + var(--frozen-width, 0) * 1px);
background-color: #999999;
background-color: var(--grist-theme-table-frozen-columns-border, #999999);
z-index: 3;
user-select: none;
pointer-events: none
@ -215,7 +217,7 @@
height: 0;
width: 100%; /* needs to be wide enough to flow off the side*/
top: calc(var(--gridview-header-height) + 1px); /* matches gridview_data_header height (+border) */
box-shadow: 0 -6px 6px 6px #444;
box-shadow: 0 -6px 6px 6px var(--grist-theme-table-scroll-shadow, #444);
/* should only show below it (10px should be enough) */
-webkit-clip-path: polygon(0 0, 0 10px, 100% 10px, 100% 0);
@ -228,7 +230,7 @@
height:100%;
top: 1px; /* go under 1px border on scrollpane */
z-index: 1;
border-right: 1px solid lightgray;
border-right: 1px solid var(--grist-theme-table-header-border, lightgray);
}
.gridview_left_border {
@ -236,7 +238,7 @@
width: 0px; /* Matches rowid width (+border) */
height: 100%;
z-index: 3;
border-right: 1px solid var(--grist-color-dark-grey) !important;
border-right: 1px solid var(--grist-theme-table-body-border, var(--grist-color-dark-grey)) !important;
user-select: none;
pointer-events: none
}
@ -245,7 +247,7 @@
width: 100%;
height: calc(var(--gridview-header-height) + 1px); /* matches gridview_data_header height (+border) */
top: 1px; /* go under 1px border on scrollpane */
border-bottom: 1px solid lightgray;
border-bottom: 1px solid var(--grist-theme-table-header-border, lightgray);
z-index: 1;
}
@ -266,7 +268,7 @@
width: 0px;
height: 100%;
position: absolute;
border: 2px solid gray;
border: 2px solid var(--grist-theme-table-drag-drop-indicator, gray);
z-index: 20;
top: 0px;
}
@ -275,10 +277,10 @@
width: 0px;
height: 100%;
position: absolute;
border: 1px solid gray;
border: 1px solid var(--grist-theme-table-drag-drop-indicator, gray);
z-index: 15;
top: 0px;
background-color: #F0F0F0;
background-color: var(--grist-theme-table-drag-drop-shadow, #F0F0F0);
opacity: 0.5;
}
@ -286,7 +288,7 @@
width: 100%;
height: 0px;
position: absolute;
border: 2px solid gray;
border: 2px solid var(--grist-theme-table-drag-drop-indicator, gray);
z-index: 20;
left: 0px;
}
@ -295,10 +297,10 @@
width: 100%;
height: 0px;
position: absolute;
border: 1px solid gray;
border: 1px solid var(--grist-theme-table-drag-drop-indicator, gray);
z-index: 15;
left: 0px;
background-color: #F0F0F0;
background-color: var(--grist-theme-table-drag-drop-shadow, #F0F0F0);
opacity: 0.5;
pointer-events: none; /* prevents row drag shadow from stealing row headers clicks */
}
@ -323,12 +325,12 @@
}
.gridview_row .record.record-hlines .field.frozen {
box-shadow: 0px 1px 0px var(--grist-color-dark-grey);
box-shadow: 0px 1px 0px var(--grist-theme-table-body-border, var(--grist-color-dark-grey));
}
/* selected field has a transparent color - with frozen fields we can't do it */
.gridview_row .field.frozen.selected {
background-color: var(--grist-color-selection-opaque);
background-color: var(--grist-theme-selection-opaque-bg, var(--grist-color-selection-opaque));
}
/* make room for a frozen line by adding margin to first not frozen field - in header and in data */
@ -342,22 +344,25 @@
background: white !important;
}
.column_names .column_name.frozen {
background: var(--grist-color-light-grey) !important;
background: var(--grist-theme-table-header-bg, var(--grist-color-light-grey)) !important;
}
}
/* Column hover effect */
.gridview_row .field.hover-column, /* normal field in a row */
.gridview_row .field.frozen.hover-column, /* frozen field in a row */
.gridview_row .field.hover-column .field_clip,
.column_name.hover-column, /* column name */
.column_name.hover-column.selected /* selected column name */ {
.column_name.hover-column.selected, /* selected column name */
.gridview_row .field.frozen.hover-column /* frozen field in a row */ {
/* for frozen fields can't use alpha channel */
background-color: var(--grist-color-selection-opaque);
background-color: var(--grist-theme-selection-opaque-bg, var(--grist-color-selection-opaque));
color: var(--grist-theme-selection-opaque-fg, unset);
}
/* For zebra stripes, make the selection little darker */
.record-zebra.record-even .field.hover-column {
background-color: var(--grist-color-selection-darker-opaque);
background-color: var(--grist-theme-selection-opaque-dark-bg, var(--grist-color-selection-darker-opaque));
color: var(--grist-theme-selection-opaque-fg, unset);
}
/* When column has a hover, remove menu button. */
.column_name.hover-column .menu_toggle {

@ -16,7 +16,7 @@ import {SortedRowSet} from 'app/client/models/rowset';
import {buildHighlightedCode} from 'app/client/ui/CodeHighlight';
import {openFilePicker} from 'app/client/ui/FileDialog';
import {bigBasicButton, bigPrimaryButton} from 'app/client/ui2018/buttons';
import {colors, testId, vars} from 'app/client/ui2018/cssVars';
import {testId, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {IOptionFull, linkSelect, menu, menuDivider, menuItem, multiSelect} from 'app/client/ui2018/menus';
import {cssModalButtons, cssModalTitle} from 'app/client/ui2018/modals';
@ -663,7 +663,7 @@ export class Importer extends DisposableWithEvents {
fields && fields.length > 0 ?
cssUnmatchedFields(
dom('div',
cssGreenText(
cssAccentText(
`${fields.length} unmatched ${fields.length > 1 ? 'fields' : 'field'}`
),
' in import:'
@ -939,11 +939,11 @@ const cssActionLink = styled('div', `
display: inline-flex;
align-items: center;
cursor: pointer;
color: ${colors.lightGreen};
--icon-color: ${colors.lightGreen};
color: ${theme.controlFg};
--icon-color: ${theme.controlFg};
&:hover {
color: ${colors.darkGreen};
--icon-color: ${colors.darkGreen};
color: ${theme.controlHoverFg};
--icon-color: ${theme.controlHoverFg};
}
`);
@ -972,7 +972,7 @@ const cssPreviewWrapper = styled('div', `
// This partly duplicates cssSectionHeader from HomeLeftPane.ts
const cssSectionHeader = styled('div', `
margin-bottom: 8px;
color: ${colors.slate};
color: ${theme.lightText};
text-transform: uppercase;
font-weight: 500;
font-size: ${vars.xsmallFontSize};
@ -994,9 +994,9 @@ const cssTableInfo = styled('div', `
margin: 4px 0px;
width: 300px;
border-radius: 3px;
border: 1px solid ${colors.darkGrey};
border: 1px solid ${theme.importerTableInfoBorder};
&:hover, &-selected {
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
`);
@ -1009,7 +1009,7 @@ const cssTableLine = styled('div', `
const cssToFrom = styled('span', `
flex: none;
margin-right: 8px;
color: ${colors.slate};
color: ${theme.lightText};
text-transform: uppercase;
font-weight: 500;
font-size: ${vars.xsmallFontSize};
@ -1062,11 +1062,11 @@ const cssOverlay = styled('div', `
height: 100%;
width: 100%;
z-index: 10;
background: ${colors.mediumGrey};
background: ${theme.importerSkippedTableOverlay};
`);
const cssPreviewGrid = styled(cssPreview, `
border: 1px solid ${colors.darkGrey};
border: 1px solid ${theme.importerPreviewBorder};
position: relative;
`);
@ -1079,7 +1079,7 @@ const cssMergeOptionsToggle = styled('div', `
`);
const cssMergeOptionsMessage = styled('div', `
color: ${colors.slate};
color: ${theme.lightText};
margin-bottom: 8px;
`);
@ -1099,14 +1099,14 @@ const cssFieldFormula = styled(buildHighlightedCode, `
cursor: pointer;
margin-top: 1px;
padding-left: 4px;
--icon-color: ${colors.lightGreen};
--icon-color: ${theme.accentIcon};
`);
const cssColumnMatchIcon = styled(icon, `
flex-shrink: 0;
width: 20px;
height: 32px;
background-color: ${colors.darkGrey};
background-color: ${theme.importerMatchIcon};
margin-right: 4px;
`);
@ -1138,10 +1138,10 @@ const cssDestinationFieldSettings = styled('div', `
line-height: 0px;
border-radius: 3px;
cursor: pointer;
--icon-color: ${colors.slate};
--icon-color: ${theme.lightText};
&:hover, &.weasel-popup-open {
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
`);
@ -1154,9 +1154,9 @@ const cssUnmatchedFieldsList = styled('div', `
text-overflow: ellipsis;
overflow: hidden;
padding-right: 16px;
color: ${colors.slate};
color: ${theme.lightText};
`);
const cssGreenText = styled('span', `
color: ${colors.lightGreen};
const cssAccentText = styled('span', `
color: ${theme.accentText};
`);

@ -1,6 +1,6 @@
import {bigBasicButton, bigPrimaryButton} from 'app/client/ui2018/buttons';
import {squareCheckbox} from 'app/client/ui2018/checkbox';
import {colors, testId} from 'app/client/ui2018/cssVars';
import {testId, theme} from 'app/client/ui2018/cssVars';
import {cssModalButtons} from 'app/client/ui2018/modals';
import {ParseOptionSchema} from 'app/plugin/FileParserAPI';
import {Computed, dom, DomContents, IDisposableOwner, input, Observable, styled} from 'grainjs';
@ -107,12 +107,18 @@ const cssParseOptionName = styled('div', `
margin-bottom: 8px;
`);
const cssInputText = styled(input, `
color: ${theme.inputFg};
background-color: ${theme.inputBg};
position: relative;
display: inline-block;
outline: none;
height: 28px;
border: 1px solid ${colors.darkGrey};
border: 1px solid ${theme.inputBorder};
border-radius: 3px;
padding: 0 6px;
width: 100%;
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
`);

@ -33,6 +33,7 @@
}
.preference_desc {
color: var(--grist-theme-document-history-activity-text, unset);
margin-left: 5px;
cursor: pointer;
font-weight: normal;

@ -4,7 +4,7 @@ import {DocumentUsage} from 'app/client/components/DocumentUsage';
import {GristDoc} from 'app/client/components/GristDoc';
import {printViewSection} from 'app/client/components/Printing';
import {buildViewSectionDom, ViewSectionHelper} from 'app/client/components/ViewLayout';
import {colors, mediaSmall, vars} from 'app/client/ui2018/cssVars';
import {mediaSmall, theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {Computed, Disposable, dom, fromKo, makeTestId, Observable, styled} from 'grainjs';
import {reportError} from 'app/client/models/errors';
@ -112,7 +112,7 @@ const cssContainer = styled('div', `
`);
const cssOverlay = styled('div', `
background-color: ${colors.backdrop};
background-color: ${theme.modalBackdrop};
inset: 0px;
height: 100%;
width: 100%;
@ -127,7 +127,7 @@ const cssOverlay = styled('div', `
`);
const cssSectionWrapper = styled('div', `
background: white;
background: ${theme.mainPanelBg};
height: 100%;
display: flex;
flex-direction: column;
@ -154,9 +154,9 @@ const cssCloseButton = styled(icon, `
height: 24px;
width: 24px;
cursor: pointer;
--icon-color: ${vars.primaryBg};
--icon-color: ${theme.modalBackdropCloseButtonFg};
&:hover {
--icon-color: ${colors.lighterGreen};
--icon-color: ${theme.modalBackdropCloseButtonHoverFg};
}
@media ${mediaSmall} {
& {

@ -11,11 +11,11 @@
cursor: move;
z-index: 5;
background-color: rgba(192, 192, 192, 0.2);
border-left: 1px solid white;
border-top: 1px solid white;
border-right: 1px solid var(--grist-color-dark-grey);
border-bottom: 1px solid var(--grist-color-dark-grey);
background-color: var(--grist-theme-card-editing-layout-bg, rgba(192, 192, 192, 0.2));
border-left: 1px solid var(--grist-theme-card-editing-layout-border, white);
border-top: 1px solid var(--grist-theme-card-editing-layout-border, white);
border-right: 1px solid var(--grist-theme-card-editing-layout-border, var(--grist-color-dark-grey));
border-bottom: 1px solid var(--grist-theme-card-editing-layout-border, var(--grist-color-dark-grey));
}
.dropdown-menu .g_record_layout_newfield {

@ -47,7 +47,10 @@ export class TypeTransform extends ColumnTransform {
const disableButtons = Observable.create(null, false);
this._reviseTypeChange.set(false);
this.editor = this.autoDispose(AceEditor.create({ observable: this.transformColumn.formula }));
this.editor = this.autoDispose(AceEditor.create({
gristDoc: this.gristDoc,
observable: this.transformColumn.formula,
}));
return dom('div',
testId('type-transform-top'),
dom.maybe(this._transformWidget, transformWidget => transformWidget.buildTransformConfigDom()),

@ -17,7 +17,7 @@ const {addFilterMenu} = require('app/client/ui/FilterBar');
const {cssIcon, cssRow} = require('app/client/ui/RightPanelStyles');
const {basicButton, primaryButton} = require('app/client/ui2018/buttons');
const {labeledLeftSquareCheckbox} = require("app/client/ui2018/checkbox");
const {colors} = require('app/client/ui2018/cssVars');
const {theme} = require('app/client/ui2018/cssVars');
const {cssDragger} = require('app/client/ui2018/draggableList');
const {menu, menuItem, select} = require('app/client/ui2018/menus');
const {confirmModal} = require('app/client/ui2018/modals');
@ -236,7 +236,7 @@ ViewConfigTab.prototype._buildSortRow = function(colRef, sortSpec, columns) {
),
cssMenu(
cssBigIconWrapper(
cssIcon('Dots', grainjsDom.cls(cssBgLightGreen.className, hasSpecs)),
cssIcon('Dots', grainjsDom.cls(cssBgAccent.className, hasSpecs)),
testId('sort-options-icon'),
),
menu(_ctl => flags.map(({computed, allowedTypes, flag, label}) => {
@ -571,7 +571,7 @@ const cssMenuIcon = styled(cssIcon, `
margin: 0 8px 0 0;
.${cssMenuItem.className}-sel > & {
background-color: ${colors.light};
background-color: ${theme.iconButtonFg};
}
`);
@ -586,37 +586,37 @@ const cssSortIconBtn = styled(cssIcon, `
flex: none;
margin: 0 6px;
cursor: pointer;
background-color: ${colors.slate};
background-color: ${theme.controlSecondaryFg};
&:hover {
background-color: ${colors.dark};
background-color: ${theme.controlSecondaryHoverFg};
}
`);
const cssSortIconPrimaryBtn = styled(cssSortIconBtn, `
background-color: ${colors.lightGreen};
background-color: ${theme.controlFg};
&:hover {
background-color: ${colors.darkGreen};
background-color: ${theme.controlHoverFg};
}
`);
const cssTextBtn = styled('div', `
color: ${colors.lightGreen};
color: ${theme.controlFg};
cursor: pointer;
&:hover {
color: ${colors.darkGreen};
color: ${theme.controlHoverFg};
}
`);
const cssPlusIcon = styled(cssIcon, `
background-color: ${colors.lightGreen};
background-color: ${theme.controlFg};
cursor: pointer;
margin: 0px 4px 3px 0;
.${cssTextBtn.className}:hover > & {
background-color: ${colors.darkGreen};
background-color: ${theme.controlHoverFg};
}
`);
@ -673,24 +673,24 @@ const cssMenu = styled('div', `
border-radius: 3px;
border: 1px solid transparent;
&:hover, &.weasel-popup-open {
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
`);
const cssBgLightGreen = styled(`div`, `
background: ${colors.lightGreen}
const cssBgAccent = styled(`div`, `
background: ${theme.accentIcon}
`)
const cssOptionMenuItem = styled('div', `
&:hover {
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
& label {
flex: 1;
cursor: pointer;
}
&.disabled * {
color: ${colors.darkGrey} important;
color: ${theme.menuItemDisabledFg} important;
cursor: not-allowed;
}
`)

@ -12,14 +12,13 @@
cursor: default;
height: 24px;
margin-left: -16px; /* to include drag handle that shows up on hover */
color: var(--grist-color-slate);
color: var(--grist-theme-text-light, var(--grist-color-slate));
font-size: var(--grist-small-font-size);
font-weight: 500;
white-space: nowrap;
}
.viewsection_content {
background-color: #ffffff;
overflow: visible;
margin: 12px;
}
@ -91,19 +90,19 @@
.view_data_pane_container {
position: relative;
flex: auto;
border: 1px solid var(--grist-color-dark-grey);
border: 1px solid var(--grist-theme-widget-border, var(--grist-color-dark-grey));
}
@media not print {
.active_section > .view_data_pane_container {
box-shadow: -2px 0 0 0px var(--grist-color-light-green);
border-left: 1px solid var(--grist-color-light-green);
box-shadow: -2px 0 0 0px var(--grist-theme-widget-active-border, var(--grist-color-light-green));
border-left: 1px solid var(--grist-theme-widget-active-border, var(--grist-color-light-green));
}
.active_section > .view_data_pane_container.viewsection_type_detail {
/* this color is a translucent version of grist-color-light-green */
box-shadow: -2px 0 0 0px var(--grist-color-inactive-cursor);
border-left: 1px solid var(--grist-color-inactive-cursor);
box-shadow: -2px 0 0 0px var(--grist-theme-cursor-inactive, var(--grist-color-inactive-cursor));
border-left: 1px solid var(--grist-theme-cursor-inactive, var(--grist-color-inactive-cursor));
}
}
@ -111,7 +110,7 @@
.active_section--no-indicator > .view_data_pane_container,
.active_section--no-indicator > .view_data_pane_container.viewsection_type_detail {
box-shadow: none;
border-left: 1px solid var(--grist-color-dark-grey);
border-left: 1px solid var(--grist-theme-widget-border, var(--grist-color-dark-grey));
}
.disable_viewpane {

@ -15,7 +15,7 @@ import {reportError} from 'app/client/models/errors';
import {filterBar} from 'app/client/ui/FilterBar';
import {viewSectionMenu} from 'app/client/ui/ViewSectionMenu';
import {buildWidgetTitle} from 'app/client/ui/WidgetTitle';
import {colors, mediaSmall, testId} from 'app/client/ui2018/cssVars';
import {mediaSmall, testId, theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {DisposableWithEvents} from 'app/common/DisposableWithEvents';
import {mod} from 'app/common/gutil';
@ -335,7 +335,7 @@ const cssTestClick = styled(`div`, `
const cssSigmaIcon = styled(icon, `
bottom: 1px;
margin-right: 5px;
background-color: ${colors.slate}
background-color: ${theme.lightText}
`);
const cssViewLeaf = styled('div', `
@ -352,12 +352,12 @@ const cssViewLeafInactive = styled('div', `
overflow: hidden;
background: repeating-linear-gradient(
-45deg,
${colors.mediumGreyOpaque},
${colors.mediumGreyOpaque} 10px,
${colors.lightGrey} 10px,
${colors.lightGrey} 20px
${theme.widgetInactiveStripesDark},
${theme.widgetInactiveStripesDark} 10px,
${theme.widgetInactiveStripesLight} 10px,
${theme.widgetInactiveStripesLight} 20px
);
border: 1px solid ${colors.darkGrey};
border: 1px solid ${theme.widgetBorder};
border-radius: 4px;
padding: 0 2px;
}

@ -10,7 +10,7 @@
border-width: 0px;
border-style: none;
border-color: 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-bottom-width: 1px; /* style: none, set by record-hlines*/
/* Record background is white by default.
@ -19,8 +19,8 @@
selected fields - this still remains white.
TODO: consider making this color the single source
*/
background: var(--grist-row-background-color, white);
color: var(--grist-row-color, black);
background: var(--grist-row-background-color, var(--grist-theme-cell-bg, white));
color: var(--grist-row-color, var(--grist-theme-cell-fg, black));
}
.record.record-hlines { /* Overwrites style, width set on element */
@ -28,11 +28,11 @@
}
.record.record-zebra.record-even {
background-color: var(--grist-row-background-color-zebra, #f8f8f8);
background-color: var(--grist-row-background-color-zebra, var(--grist-theme-cell-zebra-bg, #f8f8f8));
}
.record.record-add {
background-color: #f6f6ff !important; /* important to win over zebra stripes */
background-color: var(--grist-theme-table-add-new-bg, #f6f6ff) !important; /* important to win over zebra stripes */
}
.field {
@ -47,15 +47,16 @@
}
.record-vlines > .field {
border-right-color: var(--grist-color-dark-grey); /* set border visibility */
/* set border visibility */
border-right-color: var(--grist-theme-table-body-border, var(--grist-color-dark-grey));
}
.field.scissors {
outline: 2px dashed var(--grist-color-cursor);
outline: 2px dashed var(--grist-theme-cursor, var(--grist-color-cursor));
}
.field.selected {
background-color: var(--grist-color-selection);
background-color: var(--grist-theme-selection, var(--grist-color-selection));
}
.field.draft {
@ -136,58 +137,38 @@
width: 100%;
height: 100%;
/* one pixel outline around the cell, and one inside the cell */
outline: 1px solid var(--grist-color-inactive-cursor);
box-shadow: inset 0 0 0 1px var(--grist-color-inactive-cursor);
outline: 1px solid var(--grist-theme-cursor-inactive, var(--grist-color-inactive-cursor));
box-shadow: inset 0 0 0 1px var(--grist-theme-cursor-inactive, var(--grist-color-inactive-cursor));
pointer-events: none;
}
.active_cursor {
outline: 1px solid var(--grist-color-cursor);
box-shadow: inset 0 0 0 1px var(--grist-color-cursor);
outline: 1px solid var(--grist-theme-cursor, var(--grist-color-cursor));
box-shadow: inset 0 0 0 1px var(--grist-theme-cursor, var(--grist-color-cursor));
}
}
/* These classes are used to flash the cursor to indicate that editing in a cell is disabled. */
.cursor_read_only {
outline: 1px solid #ff9a00;
box-shadow: inset 0 0 0 1px #ff9a00;
}
.cursor_read_only_fade {
outline-color: var(--grist-color-cursor);
box-shadow: inset 0 0 0 1px var(--grist-color-cursor);
transition: outline-color 0.5s ease-in, box-shadow 0.5s ease-in;
}
.cursor_read_only_lock {
top: 0px;
height: 100%;
padding: 0 4px;
line-height: inherit;
background-color: #ff9a00;
color: white;
opacity: 1;
}
.cursor_read_only_fade > .cursor_read_only_lock {
opacity: 0;
transition: opacity 0.5s ease-in;
}
.column_name {
background-color: var(--grist-color-light-grey);
color: var(--grist-theme-table-header-fg, unset);
background-color: var(--grist-theme-table-header-bg, var(--grist-color-light-grey));
text-align: center;
cursor: pointer;
/* Column headers always show vertical gridlines, to make it clear how to resize them */
border-right-color: var(--grist-color-dark-grey);
border-right-color: var(--grist-theme-table-header-border-dark, var(--grist-color-dark-grey));
}
.column_names.record {
border-left-color: var(--grist-theme-table-header-border, var(--grist-color-dark-grey));
}
.column_name.selected {
background-color: var(--grist-color-medium-grey-opaque);
color: var(--grist-theme-table-header-selected-fg, unset);
background-color: var(--grist-theme-table-header-selected-bg, var(--grist-color-medium-grey-opaque));
}
.gridview_data_row_num.selected {
background-color: var(--grist-color-medium-grey-opaque);
color: var(--grist-theme-table-header-selected-fg, unset);
background-color: var(--grist-theme-table-header-selected-bg, var(--grist-color-medium-grey-opaque));
}
.gridview_data_row_info.linked_dst::before {

@ -1,6 +1,6 @@
import {ACIndex, ACItem, buildHighlightedDom} from 'app/client/lib/ACIndex';
import {Autocomplete, IAutocompleteOptions} from 'app/client/lib/autocomplete';
import {colors} from "app/client/ui2018/cssVars";
import {theme} from "app/client/ui2018/cssVars";
import {icon} from "app/client/ui2018/icons";
import {menuCssClass} from 'app/client/ui2018/menus';
import {dom, DomElementArg, Holder, IDisposableOwner, Observable, styled} from 'grainjs';
@ -96,11 +96,12 @@ const cssSelectBtn = styled('div', `
position: relative;
width: 100%;
height: 30px;
color: ${colors.dark};
--icon-color: ${colors.dark};
color: ${theme.selectButtonFg};
--icon-color: ${theme.selectButtonFg};
`);
const cssSelectItem = styled('li', `
color: ${theme.menuItemFg};
display: block;
white-space: pre;
overflow: hidden;
@ -110,12 +111,14 @@ const cssSelectItem = styled('li', `
cursor: pointer;
&.selected {
background-color: var(--weaseljs-selected-background-color, #5AC09C);
color: var(--weaseljs-selected-color, white);
background-color: ${theme.menuItemSelectedBg};
color: ${theme.menuItemSelectedFg};
}
`);
const cssInput = styled('input', `
color: ${theme.inputFg};
background-color: ${theme.inputBg};
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
@ -123,20 +126,23 @@ const cssInput = styled('input', `
width: 100%;
padding: 0 6px;
outline: none;
border: 1px solid ${colors.darkGrey};
border: 1px solid ${theme.inputBorder};
border-radius: 3px;
cursor: pointer;
line-height: 16px;
cursor: pointer;
&:disabled {
color: grey;
background-color: initial;
color: ${theme.inputDisabledFg};
background-color: ${theme.inputDisabledBg};
}
&:focus {
cursor: initial;
outline: none;
box-shadow: 0px 0px 2px 2px #5E9ED6;
box-shadow: 0px 0px 2px 2px ${theme.inputFocus};
}
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
`);
@ -147,8 +153,8 @@ const cssIcon = styled(icon, `
`);
const cssMatchText = styled('span', `
color: ${colors.lightGreen};
color: ${theme.autocompleteMatchText};
.selected > & {
color: ${colors.lighterGreen};
color: ${theme.autocompleteSelectedMatchText};
}
`);

@ -18,7 +18,7 @@
import { ACItem } from 'app/client/lib/ACIndex';
import { modKeyProp } from 'app/client/lib/browserInfo';
import { Autocomplete, IAutocompleteOptions } from 'app/client/lib/autocomplete';
import { colors, testId } from 'app/client/ui2018/cssVars';
import { colors, testId, theme } from 'app/client/ui2018/cssVars';
import { icon } from 'app/client/ui2018/icons';
import { csvDecodeRow, csvEncodeRow } from 'app/common/csvFormat';
import { computedArray, IDisposableCtor, IObsArraySplice, ObsArray, obsArray, Observable } from 'grainjs';
@ -679,6 +679,8 @@ const cssInputWrapper = styled('div', `
`);
const cssTokenInput = styled('input', `
color: ${theme.cellEditorFg};
background-color: ${theme.cellEditorBg};
flex: auto;
-webkit-appearance: none;
-moz-appearance: none;

@ -1,5 +1,5 @@
import { theme } from 'app/client/ui2018/cssVars';
import { Disposable, dom, Observable, styled } from 'grainjs';
import { colors } from 'app/client/ui2018/cssVars';
/**
* Simple validation controls. Renders as a red text with a validation message.
@ -117,5 +117,5 @@ export class Validator extends Disposable {
}
const cssError = styled('div.validator', `
color: ${colors.error};
color: ${theme.errorText};
`);

@ -103,7 +103,7 @@ div:hover > .kf_tooltip {
min-width: 16px;
min-height: 16px;
padding: 4px;
background-color: white;
background-color: var(--grist-theme-popup-bg, white);
border-radius: 2px;
box-shadow: 0 1px 1px 1px rgba(0,0,0,0.15);
line-height: 1.1rem;
@ -129,7 +129,7 @@ div:hover > .kf_tooltip {
right: 20px;
width: 10px;
height: 10px;
background-color: white;
background-color: var(--grist-theme-popup-bg, white);
transform: rotate(45deg);
z-index: 11;
}
@ -393,6 +393,7 @@ div:hover > .kf_tooltip {
}
.kf_label {
color: var(--grist-theme-text, unset);
white-space: nowrap;
font-size: 1.1rem;
cursor: default;
@ -436,7 +437,7 @@ div:hover > .kf_tooltip {
top: 0;
left: 0;
padding: 0;
color: #333;
color: var(--grist-theme-input-fg, #333);
}
.elabel_content_measure {

@ -5,6 +5,7 @@ import {urlState} from 'app/client/models/gristUrlState';
import {Notifier} from 'app/client/models/NotifyModel';
import {getFlavor, ProductFlavor} from 'app/client/ui/CustomThemes';
import {buildNewSiteModal, buildUpgradeModal} from 'app/client/ui/ProductUpgrades';
import {attachCssThemeVars, prefersDarkModeObs} from 'app/client/ui2018/cssVars';
import {OrgUsageSummary} from 'app/common/DocUsage';
import {Features, isLegacyPlan, Product} from 'app/common/Features';
import {GristLoadConfig} from 'app/common/gristUrls';
@ -13,6 +14,9 @@ import {LocalPlugin} from 'app/common/plugin';
import {UserPrefs} from 'app/common/Prefs';
import {isOwner} from 'app/common/roles';
import {getTagManagerScript} from 'app/common/tagManager';
import {getDefaultThemePrefs, Theme, ThemeAppearance, ThemeColors, ThemePrefs,
ThemePrefsChecker} from 'app/common/ThemePrefs';
import {getThemeColors} from 'app/common/Themes';
import {getGristConfig} from 'app/common/urlUtils';
import {getOrgName, Organization, OrgError, SUPPORT_EMAIL, UserAPI, UserAPIImpl} from 'app/common/UserAPI';
import {getUserPrefObs, getUserPrefsObs} from 'app/client/models/UserPrefs';
@ -75,7 +79,10 @@ export interface AppModel {
currentProduct: Product|null; // The current org's product.
currentFeatures: Features; // Features of the current org's product.
userPrefsObs: Observable<UserPrefs>;
themePrefs: Observable<ThemePrefs>;
currentTheme: Computed<Theme>;
pageType: Observable<PageType>;
@ -209,6 +216,11 @@ export class AppModelImpl extends Disposable implements AppModel {
public readonly isLegacySite = Boolean(this.currentProduct && isLegacyPlan(this.currentProduct.name));
public readonly userPrefsObs = getUserPrefsObs(this);
public readonly themePrefs = getUserPrefObs(this.userPrefsObs, 'theme', {
defaultValue: getDefaultThemePrefs(),
checker: ThemePrefsChecker,
}) as Observable<ThemePrefs>;
public readonly currentTheme = this._getCurrentThemeObs();
// Get the current PageType from the URL.
public readonly pageType: Observable<PageType> = Computed.create(this, urlState().state,
@ -223,6 +235,10 @@ export class AppModelImpl extends Disposable implements AppModel {
public readonly orgError?: OrgError,
) {
super();
this._applyTheme();
this.autoDispose(this.currentTheme.addListener(() => this._applyTheme()));
this._recordSignUpIfIsNewUser();
const state = urlState().state.get();
@ -311,6 +327,39 @@ export class AppModelImpl extends Disposable implements AppModel {
dataLayer.push({event: 'new-sign-up'});
getUserPrefObs(this.userPrefsObs, 'recordSignUpEvent').set(undefined);
}
private _getCurrentThemeObs() {
return Computed.create(this, this.themePrefs, prefersDarkModeObs(),
(_use, themePrefs, prefersDarkMode) => {
let appearance: ThemeAppearance;
if (!themePrefs.syncWithOS) {
appearance = themePrefs.appearance;
} else {
appearance = prefersDarkMode ? 'dark' : 'light';
}
const nameOrColors = themePrefs.colors[appearance];
let colors: ThemeColors;
if (typeof nameOrColors === 'string') {
colors = getThemeColors(nameOrColors);
} else {
colors = nameOrColors;
}
return {appearance, colors};
},
);
}
/**
* Applies a theme based on the user's current theme preferences.
*/
private _applyTheme() {
// Custom CSS is incompatible with custom themes.
if (getGristConfig().enableCustomCss) { return; }
attachCssThemeVars(this.currentTheme.get());
}
}
export function getHomeUrl(): string {

@ -2,6 +2,7 @@ import {localStorageObs} from 'app/client/lib/localStorageObs';
import {AppModel} from 'app/client/models/AppModel';
import {UserOrgPrefs, UserPrefs} from 'app/common/Prefs';
import {Computed, Observable} from 'grainjs';
import {CheckerT} from 'ts-interface-checker';
interface PrefsTypes {
userOrgPrefs: UserOrgPrefs;
@ -12,15 +13,14 @@ function makePrefFunctions<P extends keyof PrefsTypes>(prefsTypeName: P) {
type PrefsType = PrefsTypes[P];
/**
* Creates an observable that returns UserOrgPrefs, and which stores them when set.
* Creates an observable that returns a PrefsType, and which stores changes when set.
*
* For anon user, the prefs live in localStorage. Note that the observable isn't actually watching
* for changes on the server, it will only change when set.
*/
function getPrefsObs(appModel: AppModel): Observable<PrefsType> {
const savedPrefs = appModel.currentValidUser ? appModel.currentOrg?.[prefsTypeName] : undefined;
if (savedPrefs) {
const prefsObs = Observable.create<PrefsType>(null, savedPrefs!);
if (appModel.currentValidUser) {
const prefsObs = Observable.create<PrefsType>(null, appModel.currentOrg?.[prefsTypeName] ?? {});
return Computed.create(null, (use) => use(prefsObs))
.onWrite(prefs => {
prefsObs.set(prefs);
@ -41,10 +41,30 @@ function makePrefFunctions<P extends keyof PrefsTypes>(prefsTypeName: P) {
* stores it when set.
*/
function getPrefObs<Name extends keyof PrefsType>(
prefsObs: Observable<PrefsType>, prefName: Name
): Observable<PrefsType[Name]> {
return Computed.create(null, (use) => use(prefsObs)[prefName])
.onWrite(value => prefsObs.set({...prefsObs.get(), [prefName]: value}));
prefsObs: Observable<PrefsType>,
prefName: Name,
options: {
defaultValue?: Exclude<PrefsType[Name], undefined>;
checker?: CheckerT<PrefsType[Name]>;
} = {}
): Observable<PrefsType[Name] | undefined> {
const {defaultValue, checker} = options;
return Computed.create(null, (use) => {
const prefs = use(prefsObs);
if (!(prefName in prefs)) { return defaultValue; }
const value = prefs[prefName];
if (checker) {
try {
checker.check(value);
} catch (e) {
console.error(`getPrefObs: preference ${prefName.toString()} has value of invalid type`, e);
return defaultValue;
}
}
return value;
}).onWrite(value => prefsObs.set({...prefsObs.get(), [prefName]: value}));
}
return {getPrefsObs, getPrefObs};

@ -1,17 +1,19 @@
import {AppModel, reportError} from 'app/client/models/AppModel';
import {urlState} from 'app/client/models/gristUrlState';
import * as css from 'app/client/ui/AccountPageCss';
import {ApiKey} from 'app/client/ui/ApiKey';
import {AppHeader} from 'app/client/ui/AppHeader';
import {buildChangePasswordDialog} from 'app/client/ui/ChangePasswordDialog';
import {leftPanelBasic} from 'app/client/ui/LeftPanelCommon';
import {MFAConfig} from 'app/client/ui/MFAConfig';
import {pagePanels} from 'app/client/ui/PagePanels';
import {ThemeConfig} from 'app/client/ui/ThemeConfig';
import {createTopBarHome} from 'app/client/ui/TopBar';
import {transientInput} from 'app/client/ui/transientInput';
import {cssBreadcrumbs, cssBreadcrumbsLink, separator} from 'app/client/ui2018/breadcrumbs';
import {cssBreadcrumbs, separator} from 'app/client/ui2018/breadcrumbs';
import {labeledSquareCheckbox} from 'app/client/ui2018/checkbox';
import {icon} from 'app/client/ui2018/icons';
import {colors, vars} from 'app/client/ui2018/cssVars';
import {cssLink} from 'app/client/ui2018/links';
import {getGristConfig} from 'app/common/urlUtils';
import {FullUser} from 'app/common/UserAPI';
import {Computed, Disposable, dom, domComputed, makeTestId, Observable, styled} from 'grainjs';
@ -46,19 +48,21 @@ export class AccountPage extends Disposable {
},
headerMain: this._buildHeaderMain(),
contentMain: this._buildContentMain(),
testId,
});
}
private _buildContentMain() {
const {enableCustomCss} = getGristConfig();
return domComputed(this._userObs, (user) => user && (
cssContainer(cssAccountPage(
cssHeader('Account settings'),
cssDataRow(
cssSubHeader('Email'),
cssEmail(user.email),
css.container(css.accountPage(
css.header('Account settings'),
css.dataRow(
css.inlineSubHeader('Email'),
css.email(user.email),
),
cssDataRow(
cssSubHeader('Name'),
css.dataRow(
css.inlineSubHeader('Name'),
domComputed(this._isEditingName, (isEditing) => (
isEditing ? [
transientInput(
@ -69,16 +73,16 @@ export class AccountPage extends Disposable {
},
{ size: '5' }, // Lower size so that input can shrink below ~152px.
dom.on('input', (_ev, el) => this._nameEdit.set(el.value)),
cssFlexGrow.cls(''),
css.flexGrow.cls(''),
),
cssTextBtn(
cssIcon('Settings'), 'Save',
css.textBtn(
css.icon('Settings'), 'Save',
// No need to save on 'click'. The transient input already does it on close.
),
] : [
cssName(user.name),
cssTextBtn(
cssIcon('Settings'), 'Edit',
css.name(user.name),
css.textBtn(
css.icon('Settings'), 'Edit',
dom.on('click', () => this._isEditingName.set(true)),
),
]
@ -87,17 +91,17 @@ export class AccountPage extends Disposable {
),
// show warning for invalid name but not for the empty string
dom.maybe(use => use(this._nameEdit) && !use(this._isNameValid), cssWarnings),
cssHeader('Password & Security'),
cssDataRow(
cssSubHeader('Login Method'),
cssLoginMethod(user.loginMethod),
user.loginMethod === 'Email + Password' ? cssTextBtn('Change Password',
css.header('Password & Security'),
css.dataRow(
css.inlineSubHeader('Login Method'),
css.loginMethod(user.loginMethod),
user.loginMethod === 'Email + Password' ? css.textBtn('Change Password',
dom.on('click', () => this._showChangePasswordDialog()),
) : null,
testId('login-method'),
),
user.loginMethod !== 'Email + Password' ? null : dom.frag(
cssDataRow(
css.dataRow(
labeledSquareCheckbox(
this._allowGoogleLogin,
'Allow signing in to this account with Google',
@ -105,16 +109,21 @@ export class AccountPage extends Disposable {
),
testId('allow-google-login'),
),
cssSubHeaderFullWidth('Two-factor authentication'),
cssDescription(
css.subHeader('Two-factor authentication'),
css.description(
"Two-factor authentication is an extra layer of security for your Grist account designed " +
"to ensure that you're the only person who can access your account, even if someone " +
"knows your password."
),
dom.create(MFAConfig, user),
),
cssHeader('API'),
cssDataRow(cssSubHeader('API Key'), cssContent(
// Custom CSS is incompatible with custom themes.
enableCustomCss ? null : [
css.header('Theme'),
dom.create(ThemeConfig, this._appModel),
],
css.header('API'),
css.dataRow(css.inlineSubHeader('API Key'), css.content(
dom.create(ApiKey, {
apiKey: this._apiKey,
onCreate: () => this._createApiKey(),
@ -131,7 +140,7 @@ export class AccountPage extends Disposable {
private _buildHeaderMain() {
return dom.frag(
cssBreadcrumbs({ style: 'margin-left: 16px;' },
cssBreadcrumbsLink(
cssLink(
urlState().setLinkUrl({}),
'Home',
testId('home'),
@ -204,103 +213,12 @@ export function checkName(name: string): boolean {
* Builds dom to show marning messages to the user.
*/
function buildNameWarningsDom() {
return cssWarning(
return css.warning(
"Names only allow letters, numbers and certain special characters",
testId('username-warning'),
);
}
const cssContainer = styled('div', `
display: flex;
justify-content: center;
overflow: auto;
`);
const cssHeader = styled('div', `
height: 32px;
line-height: 32px;
margin: 28px 0 16px 0;
color: ${colors.dark};
font-size: ${vars.xxxlargeFontSize};
font-weight: ${vars.headerControlTextWeight};
`);
const cssAccountPage = styled('div', `
max-width: 600px;
padding: 16px;
`);
const cssDataRow = styled('div', `
margin: 8px 0px;
display: flex;
align-items: baseline;
`);
const cssSubHeaderFullWidth = styled('div', `
padding: 8px 0;
display: inline-block;
vertical-align: top;
font-weight: bold;
`);
const cssSubHeader = styled(cssSubHeaderFullWidth, `
min-width: 110px;
`);
const cssContent = styled('div', `
flex: 1 1 300px;
`);
const cssTextBtn = styled('button', `
font-size: ${vars.mediumFontSize};
color: ${colors.lightGreen};
cursor: pointer;
margin-left: 16px;
background-color: transparent;
border: none;
padding: 0;
text-align: left;
min-width: 110px;
&:hover {
color: ${colors.darkGreen};
}
`);
const cssIcon = styled(icon, `
background-color: ${colors.lightGreen};
margin: 0 4px 2px 0;
.${cssTextBtn.className}:hover > & {
background-color: ${colors.darkGreen};
}
`);
const cssWarnings = styled(buildNameWarningsDom, `
margin: -8px 0 0 110px;
`);
const cssDescription = styled('div', `
color: #8a8a8a;
font-size: 13px;
`);
const cssFlexGrow = styled('div', `
flex-grow: 1;
`);
const cssName = styled(cssFlexGrow, `
word-break: break-word;
`);
const cssEmail = styled('div', `
word-break: break-word;
`);
const cssLoginMethod = styled(cssFlexGrow, `
word-break: break-word;
`);
const cssWarning = styled('div', `
color: red;
`);

@ -0,0 +1,108 @@
import {theme, vars} from 'app/client/ui2018/cssVars';
import {icon as gristIcon} from 'app/client/ui2018/icons';
import {styled} from 'grainjs';
export const container = styled('div', `
display: flex;
justify-content: center;
overflow: auto;
`);
export const accountPage = styled('div', `
max-width: 600px;
margin-top: auto;
margin-bottom: auto;
padding: 16px;
`);
export const content = styled('div', `
flex: 1 1 300px;
`);
export const textBtn = styled('button', `
font-size: ${vars.mediumFontSize};
color: ${theme.controlFg};
cursor: pointer;
margin-left: 16px;
background-color: transparent;
border: none;
padding: 0;
text-align: left;
min-width: 110px;
&:hover {
color: ${theme.controlHoverFg};
}
`);
export const icon = styled(gristIcon, `
background-color: ${theme.controlFg};
margin: 0 4px 2px 0;
.${textBtn.className}:hover > & {
background-color: ${theme.controlHoverFg};
}
`);
export const description = styled('div', `
color: ${theme.lightText};
font-size: 13px;
`);
export const flexGrow = styled('div', `
flex-grow: 1;
`);
export const name = styled(flexGrow, `
color: ${theme.text};
word-break: break-word;
`);
export const email = styled('div', `
color: ${theme.text};
word-break: break-word;
`);
export const loginMethod = styled(flexGrow, `
color: ${theme.text};
word-break: break-word;
`);
export const warning = styled('div', `
color: ${theme.errorText};
`);
export const header = styled('div', `
height: 32px;
line-height: 32px;
margin: 28px 0 16px 0;
color: ${theme.text};
font-size: ${vars.xxxlargeFontSize};
font-weight: ${vars.headerControlTextWeight};
`);
export const subHeader = styled('div', `
color: ${theme.text};
padding: 8px 0;
vertical-align: top;
font-weight: bold;
display: block;
`);
export const inlineSubHeader = styled(subHeader, `
display: inline-block;
min-width: 110px;
`);
export const dataRow = styled('div', `
margin: 8px 0px;
display: flex;
align-items: baseline;
`);
export const betaTag = styled('span', `
text-transform: uppercase;
vertical-align: super;
font-size: ${vars.xsmallFontSize};
color: ${theme.accentText};
`);

@ -7,7 +7,7 @@ import {manageTeamUsers} from 'app/client/ui/OpenUserManager';
import {createUserImage} from 'app/client/ui/UserImage';
import * as viewport from 'app/client/ui/viewport';
import {primaryButton} from 'app/client/ui2018/buttons';
import {colors, mediaDeviceNotSmall, testId, vars} from 'app/client/ui2018/cssVars';
import {mediaDeviceNotSmall, testId, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {menu, menuDivider, menuItem, menuItemLink, menuSubHeader} from 'app/client/ui2018/menus';
import {commonUrls, shouldHideUiElement} from 'app/common/gristUrls';
@ -165,14 +165,14 @@ const cssUserName = styled('div', `
margin-left: 8px;
font-size: ${vars.mediumFontSize};
font-weight: ${vars.headerControlTextWeight};
color: ${colors.dark};
color: ${theme.text};
`);
const cssEmail = styled('div', `
margin-top: 4px;
font-size: ${vars.smallFontSize};
font-weight: initial;
color: ${colors.slate};
color: ${theme.lightText};
`);
const cssSmallIconWrap = styled('div', `
@ -181,16 +181,16 @@ const cssSmallIconWrap = styled('div', `
`);
const cssOtherEmail = styled('div', `
color: ${colors.slate};
color: ${theme.lightText};
.${cssMenuItem.className}-sel & {
color: ${colors.light};
color: ${theme.menuItemSelectedFg};
}
`);
const cssCheckmark = styled(icon, `
flex: none;
margin-left: 16px;
--icon-color: ${colors.lightGreen};
--icon-color: ${theme.accentIcon};
`);
// Note that this css class hides the item when the device width is small (not based on viewport

@ -1,4 +1,4 @@
import {colors, vars} from 'app/client/ui2018/cssVars';
import {theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {dom, DomElementArg, Observable, styled} from "grainjs";
@ -20,7 +20,7 @@ export const cssAddNewButton = styled('div', `
align-items: center;
margin: 22px 0px 22px 0px;
height: 40px;
color: ${colors.light};
color: ${theme.controlPrimaryFg};
border: none;
border-radius: 4px;
@ -30,19 +30,19 @@ export const cssAddNewButton = styled('div', `
font-weight: bold;
overflow: hidden;
--circle-color: ${colors.lightGreen};
--circle-color: ${theme.addNewCircleSmallBg};
&:hover, &.weasel-popup-open {
--circle-color: ${colors.darkGreen};
--circle-color: ${theme.addNewCircleSmallHoverBg};
}
&-open {
margin: 22px 16px 22px 16px;
background-color: ${colors.lightGreen};
--circle-color: ${colors.darkGreen};
background-color: ${theme.controlPrimaryBg};
--circle-color: ${theme.addNewCircleBg};
}
&-open:hover, &-open.weasel-popup-open {
background-color: ${colors.darkGreen};
--circle-color: ${colors.darkerGreen};
background-color: ${theme.controlPrimaryHoverBg};
--circle-color: ${theme.addNewCircleHoverBg};
}
`);
const cssLeftMargin = styled('div', `
@ -53,6 +53,7 @@ const cssLeftMargin = styled('div', `
}
`);
const cssAddText = styled('div', `
color: ${theme.controlPrimaryFg};
flex: 0 0.5 content;
white-space: nowrap;
min-width: 0px;
@ -70,6 +71,6 @@ const cssPlusButton = styled('div', `
text-align: center;
`);
const cssPlusIcon = styled(icon, `
background-color: ${colors.light};
background-color: ${theme.addNewCircleFg};
margin-top: 6px;
`);

@ -1,4 +1,5 @@
import { basicButton, textButton } from 'app/client/ui2018/buttons';
import { theme, vars } from 'app/client/ui2018/cssVars';
import { icon } from 'app/client/ui2018/icons';
import { confirmModal } from 'app/client/ui2018/modals';
import { Disposable, dom, IDomArgs, makeTestId, Observable, observable, styled } from 'grainjs';
@ -119,11 +120,17 @@ export class ApiKey extends Disposable {
}
const description = styled('div', `
color: #8a8a8a;
font-size: 13px;
margin-top: 8px;
color: ${theme.lightText};
font-size: ${vars.mediumFontSize};
`);
const cssInput = styled('input', `
background-color: transparent;
color: ${theme.inputFg};
border: 1px solid ${theme.inputBorder};
padding: 4px;
border-radius: 3px;
outline: none;
flex: 1 0 0;
`);

@ -9,7 +9,8 @@ body {
font-size: 1.2rem;
margin: 0;
padding: 0;
background: url('img/gplaypattern.png');
background: var(--grist-theme-bg, url('img/gplaypattern.png'));
background-color: var(--grist-theme-bg-color, unset);
}
.g-help {

@ -2,9 +2,8 @@ import {urlState} from 'app/client/models/gristUrlState';
import {buildAppMenuBillingItem} from 'app/client/ui/BillingButtons';
import {getTheme} from 'app/client/ui/CustomThemes';
import {cssLeftPane} from 'app/client/ui/PagePanels';
import {colors, testId, vars} from 'app/client/ui2018/cssVars';
import {colors, testId, theme, vars} from 'app/client/ui2018/cssVars';
import * as version from 'app/common/version';
import {BindableValue, Disposable, dom, styled} from "grainjs";
import {menu, menuItem, menuItemLink, menuSubHeader} from 'app/client/ui2018/menus';
import {isTemplatesOrg, Organization} from 'app/common/UserAPI';
import {AppModel} from 'app/client/models/AppModel';
@ -13,7 +12,7 @@ import {DocPageModel} from 'app/client/models/DocPageModel';
import * as roles from 'app/common/roles';
import {manageTeamUsersApp} from 'app/client/ui/OpenUserManager';
import {maybeAddSiteSwitcherSection} from 'app/client/ui/SiteSwitcher';
import {DomContents} from 'grainjs';
import {BindableValue, Disposable, dom, DomContents, styled} from 'grainjs';
// Maps a name of a Product (from app/gen-server/entity/Product.ts) to a tag (pill) to show next
// to the org name.
@ -33,12 +32,12 @@ export class AppHeader extends Disposable {
}
public buildDom() {
const theme = getTheme(this._appModel.topAppModel.productFlavor);
const productFlavor = getTheme(this._appModel.topAppModel.productFlavor);
const currentOrg = this._appModel.currentOrg;
return cssAppHeader(
cssAppHeader.cls('-widelogo', theme.wideLogo || false),
cssAppHeader.cls('-widelogo', productFlavor.wideLogo || false),
// Show version when hovering over the application icon.
cssAppLogo(
{title: `Ver ${version.version} (${version.gitcommit})`},
@ -96,10 +95,11 @@ const cssAppHeader = styled('div', `
width: 100%;
height: 100%;
align-items: center;
background-color: ${theme.leftPanelBg};
&, &:hover, &:focus {
text-decoration: none;
outline: none;
color: ${colors.dark};
color: ${theme.text};
}
`);
@ -124,6 +124,7 @@ const cssAppLogo = styled('a', `
`);
const cssDropdownIcon = styled(icon, `
--icon-color: ${theme.text};
flex-shrink: 0;
margin-right: 8px;
`);
@ -138,7 +139,7 @@ const cssOrg = styled('div', `
font-weight: 500;
&:hover {
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
.${cssLeftPane.className}-open & {

@ -105,6 +105,7 @@ function pagePanelsHome(owner: IDisposableOwner, appModel: AppModel, app: App) {
headerMain: createTopBarHome(appModel),
contentMain: createDocMenu(pageModel),
contentTop: buildHomeBanners(appModel),
testId,
});
}

@ -11,10 +11,11 @@ import {FilterInfo} from 'app/client/models/entities/ViewSectionRec';
import {RowId, RowSource} from 'app/client/models/rowset';
import {ColumnFilterFunc, SectionFilter} from 'app/client/models/SectionFilter';
import {TableData} from 'app/client/models/TableData';
import {cssInput} from 'app/client/ui/cssInput';
import {basicButton, primaryButton} from 'app/client/ui2018/buttons';
import {cssLabel as cssCheckboxLabel, cssCheckboxSquare, cssLabelText, Indeterminate, labeledTriStateSquareCheckbox
} from 'app/client/ui2018/checkbox';
import {colors, vars} from 'app/client/ui2018/cssVars';
import {theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {menuCssClass, menuDivider} from 'app/client/ui2018/menus';
import {CellValue} from 'app/common/DocActions';
@ -593,7 +594,7 @@ const cssMenu = styled('div', `
max-width: 400px;
max-height: 90vh;
outline: none;
background-color: white;
background-color: ${theme.menuBg};
padding-top: 0;
padding-bottom: 12px;
`);
@ -608,15 +609,15 @@ const cssMenuHeader = styled('div', `
`);
const cssSelectAll = styled('div', `
display: flex;
color: ${colors.lightGreen};
color: ${theme.controlFg};
cursor: default;
user-select: none;
&-disabled {
color: ${colors.slate};
color: ${theme.controlSecondaryFg};
}
`);
const cssDotSeparator = styled('span', `
color: ${colors.lightGreen};
color: ${theme.controlFg};
margin: 0 4px;
user-select: none;
`);
@ -637,14 +638,13 @@ const cssMenuItem = styled('div', `
`);
export const cssItemValue = styled(cssLabelText, `
margin-right: 12px;
color: ${colors.dark};
white-space: pre;
`);
const cssItemCount = styled('div', `
flex-grow: 1;
align-self: normal;
text-align: right;
color: ${colors.slate};
color: ${theme.lightText};
`);
const cssMenuFooter = styled('div', `
display: flex;
@ -656,6 +656,8 @@ const cssApplyButton = styled(primaryButton, `
margin-right: 4px;
`);
const cssSearch = styled(input, `
color: ${theme.inputFg};
background-color: ${theme.inputBg};
flex-grow: 1;
min-width: 1px;
-webkit-appearance: none;
@ -668,22 +670,26 @@ const cssSearch = styled(input, `
border: none;
outline: none;
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
`);
const cssSearchIcon = styled(icon, `
--icon-color: ${theme.lightText};
flex-shrink: 0;
margin-left: auto;
margin-right: 4px;
`);
const cssNoResults = styled(cssMenuItem, `
font-style: italic;
color: ${colors.slate};
color: ${theme.lightText};
justify-content: center;
`);
const cssSortIcon = styled(icon, `
--icon-color: ${colors.slate};
--icon-color: ${theme.controlSecondaryFg};
margin-left: auto;
&-active {
--icon-color: ${colors.lightGreen}
--icon-color: ${theme.controlFg}
}
`);
const cssLabel = styled(cssCheckboxLabel, `
@ -695,6 +701,7 @@ const cssToken = styled('div', `
margin-right: 12px;
`);
const cssRangeHeader = styled(cssMenuItem, `
color: ${theme.text};
padding: unset;
border-radius: 0 0 3px 0;
text-transform: uppercase;
@ -704,14 +711,14 @@ const cssRangeHeader = styled(cssMenuItem, `
const cssRangeContainer = styled(cssMenuItem, `
display: flex;
justify-content: left;
align-items: center;
column-gap: 10px;
`);
const cssRangeInputSeparator = styled('span', `
font-weight: 600;
position: relative;
top: 3px;
color: var(--grist-color-slate);
color: ${theme.lightText};
`);
const cssRangeInput = styled('input', `
const cssRangeInput = styled(cssInput, `
height: unset;
width: 120px;
`);

@ -5,7 +5,7 @@ import {urlState} from 'app/client/models/gristUrlState';
import {getTimeFromNow} from 'app/client/models/HomeModel';
import {buildConfigContainer} from 'app/client/ui/RightPanel';
import {buttonSelect} from 'app/client/ui2018/buttonSelect';
import {colors, testId, vars} from 'app/client/ui2018/cssVars';
import {testId, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {menu, menuAnnotate, menuItemLink} from 'app/client/ui2018/menus';
import {buildUrlId, parseUrlId} from 'app/common/gristUrls';
@ -108,7 +108,7 @@ export class DocHistory extends Disposable implements IDomComponent {
const cssSubTabs = styled('div', `
padding: 16px;
border-bottom: 1px solid ${colors.mediumGrey};
border-bottom: 1px solid ${theme.pagePanelsBorder};
`);
const cssSnapshot = styled('div', `
@ -117,24 +117,25 @@ const cssSnapshot = styled('div', `
const cssSnapshotTime = styled('div', `
text-align: right;
color: ${colors.slate};
color: ${theme.lightText};
font-size: ${vars.smallFontSize};
`);
const cssSnapshotCard = styled('div', `
border: 1px solid ${colors.mediumGrey};
border: 1px solid ${theme.documentHistorySnapshotBorder};
padding: 8px;
background: white;
color: ${theme.documentHistorySnapshotFg};
background: ${theme.documentHistorySnapshotBg};
border-radius: 8px;
overflow: hidden;
display: flex;
align-items: center;
--icon-color: ${colors.slate};
--icon-color: ${theme.controlSecondaryFg};
&-current {
background-color: ${colors.dark};
color: ${colors.light};
--icon-color: ${colors.light};
background-color: ${theme.documentHistorySnapshotSelectedBg};
color: ${theme.documentHistorySnapshotSelectedFg};
--icon-color: ${theme.documentHistorySnapshotSelectedFg};
}
`);
@ -152,6 +153,6 @@ const cssMenuDots = styled('div', `
border-radius: 3px;
cursor: default;
&:hover, &.weasel-popup-open {
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
`);

@ -17,7 +17,7 @@ import {transition} from 'app/client/ui/transitions';
import {showWelcomeQuestions} from 'app/client/ui/WelcomeQuestions';
import {createVideoTourTextButton} from 'app/client/ui/OpenVideoTour';
import {buttonSelect, cssButtonSelect} from 'app/client/ui2018/buttonSelect';
import {colors, isNarrowScreenObs} from 'app/client/ui2018/cssVars';
import {isNarrowScreenObs, theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {loadingSpinner} from 'app/client/ui2018/loaders';
import {menu, menuItem, menuText, select} from 'app/client/ui2018/menus';
@ -84,7 +84,7 @@ function createLoadedDocMenu(owner: IDisposableOwner, home: HomeModel) {
// TODO: this is shown on all pages, but there is a hack in currentWSPinnedDocs that
// removes all pinned docs when on trash page.
dom.maybe((use) => use(home.currentWSPinnedDocs).length > 0, () => [
css.docListHeader(css.docHeaderIconDark('PinBig'), 'Pinned Documents'),
css.docListHeader(css.pinnedDocsIcon('PinBig'), 'Pinned Documents'),
createPinnedDocs(home, home.currentWSPinnedDocs),
]),
@ -393,7 +393,7 @@ function buildWorkspaceDocBlock(home: HomeModel, workspace: Workspace, flashDocI
// The flash value may change to true, and then immediately to false. We highlight it
// using a transition, and scroll into view, when it turns back to false.
transition(flash, {
prepare(elem, val) { if (!val) { elem.style.backgroundColor = colors.slate.toString(); } },
prepare(elem, val) { if (!val) { elem.style.backgroundColor = theme.lightText.toString(); } },
run(elem, val) { if (!val) { elem.style.backgroundColor = ''; scrollIntoViewIfNeeded(elem); } },
})
),

@ -1,5 +1,5 @@
import {transientInput} from 'app/client/ui/transientInput';
import {colors, mediaSmall, vars} from 'app/client/ui2018/cssVars';
import {mediaSmall, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {styled} from 'grainjs';
import {bigBasicButton} from 'app/client/ui2018/buttons';
@ -41,7 +41,7 @@ export const docList = styled('div', `
const listHeader = styled('div', `
min-height: 32px;
line-height: 32px;
color: ${colors.dark};
color: ${theme.text};
font-size: ${vars.xxxlargeFontSize};
font-weight: ${vars.headerControlTextWeight};
`);
@ -81,6 +81,7 @@ export const allDocsTemplates = styled('div', `
`);
export const docBlock = styled('div', `
color: ${theme.text};
max-width: 550px;
min-width: 300px;
margin-bottom: 28px;
@ -96,6 +97,7 @@ export const templatesDocBlock = styled(docBlock, `
`);
export const otherSitesBlock = styled('div', `
color: ${theme.text};
margin-bottom: 32px;
`);
@ -112,16 +114,18 @@ export const siteButton = styled(bigBasicButton, `
flex: 0 0 auto;
`);
export const docHeaderIconDark = styled(icon, `
export const docHeaderIcon = styled(icon, `
margin-right: 8px;
margin-top: -3px;
--icon-color: ${theme.lightText};
`);
export const docHeaderIcon = styled(docHeaderIconDark, `
--icon-color: ${colors.slate};
export const pinnedDocsIcon = styled(docHeaderIcon, `
--icon-color: ${theme.text};
`);
export const featuredTemplatesIcon = styled(icon, `
--icon-color: ${theme.text};
margin-right: 8px;
width: 20px;
height: 20px;
@ -141,7 +145,7 @@ const docBlockHeader = `
line-height: 40px;
margin-bottom: 8px;
margin-right: -16px;
color: ${colors.dark};
color: ${theme.text};
font-size: ${vars.mediumFontSize};
font-weight: bold;
&, &:hover, &:focus {
@ -156,6 +160,7 @@ export const docBlockHeaderLink = styled('a', docBlockHeader);
export const templateBlockHeader = styled('div', docBlockHeader);
export const wsLeft = styled('div', `
color: ${theme.text};
flex: 1 0 50%;
min-width: 0px;
margin-right: 24px;
@ -166,11 +171,11 @@ export const docRowWrapper = styled('div', `
margin: 0px -16px 8px -16px;
border-radius: 3px;
font-size: ${vars.mediumFontSize};
color: ${colors.dark};
--icon-color: ${colors.slate};
color: ${theme.text};
--icon-color: ${theme.lightText};
&:hover, &.weasel-popup-open, &-renaming {
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
`);
@ -188,7 +193,7 @@ export const docRowLink = styled('a', `
color: inherit;
}
&-no-access, &-no-access:hover, &-no-access:focus {
color: ${colors.slate};
color: ${theme.disabledText};
cursor: not-allowed;
}
`);
@ -211,13 +216,13 @@ export const docName = styled('div', `
export const docPinIcon = styled(icon, `
flex: none;
margin-left: 4px;
--icon-color: ${colors.lightGreen};
--icon-color: ${theme.accentIcon};
`);
export const docPublicIcon = styled(icon, `
flex: none;
margin-left: auto;
--icon-color: ${colors.lightGreen};
--icon-color: ${theme.accentIcon};
`);
export const docEditorInput = styled(transientInput, `
@ -231,7 +236,7 @@ export const docEditorInput = styled(transientInput, `
export const docRowUpdatedAt = styled('div', `
flex: 1 1 50%;
color: ${colors.slate};
color: ${theme.lightText};
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@ -247,20 +252,20 @@ export const docMenuTrigger = styled('div', `
line-height: 0px;
border-radius: 3px;
cursor: default;
--icon-color: ${colors.darkGrey};
--icon-color: ${theme.docMenuDocOptionsFg};
.${docRowLink.className}:hover > & {
--icon-color: ${colors.slate};
--icon-color: ${theme.docMenuDocOptionsHoverFg};
}
&:hover, &.weasel-popup-open {
background-color: ${colors.darkGrey};
--icon-color: ${colors.slate};
background-color: ${theme.docMenuDocOptionsHoverBg};
--icon-color: ${theme.docMenuDocOptionsHoverFg};
}
`);
export const moveDocModalBody = styled('div', `
display: flex;
flex-direction: column;
border-bottom: 1px solid ${colors.darkGrey};
border-bottom: 1px solid ${theme.modalBorderDark};
margin: 0 -64px;
height: 200px;
`);
@ -275,11 +280,11 @@ export const moveDocListItem = styled('div', `
font-size: ${vars.mediumFontSize};
&-selected {
background-color: ${colors.lightGreen};
color: white;
background-color: ${theme.moveDocsSelectedBg};
color: ${theme.moveDocsSelectedFg};
}
&-disabled {
color: ${colors.darkGrey};
color: ${theme.moveDocsDisabledFg};
cursor: default;
}
`);
@ -319,13 +324,14 @@ export const sortSelector = styled('div', `
line-height: unset;
align-items: center;
border-radius: ${vars.controlBorderRadius};
color: ${colors.lightGreen};
--icon-color: ${colors.lightGreen};
color: ${theme.controlFg};
--icon-color: ${theme.controlFg};
background-color: unset;
&:focus, &:hover {
outline: none;
box-shadow: none;
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
@media ${mediaSmall} {
& {

@ -1,6 +1,6 @@
import {IExampleInfo} from 'app/client/ui/ExampleInfo';
import {prepareForTransition, TransitionWatcher} from 'app/client/ui/transitions';
import {colors, mediaXSmall, testId, vars} from 'app/client/ui2018/cssVars';
import {mediaXSmall, testId, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {cssLink} from 'app/client/ui2018/links';
import {dom, styled} from 'grainjs';
@ -98,8 +98,8 @@ const cssCard = styled('div', `
margin-right: 24px;
max-width: 624px;
padding: 32px 56px 32px 32px;
background-color: white;
box-shadow: 0 2px 18px 0 rgba(31,37,50,0.31), 0 0 1px 0 rgba(76,86,103,0.24);
background-color: ${theme.popupBg};
box-shadow: 0 2px 18px 0 ${theme.popupInnerShadow}, 0 0 1px 0 ${theme.popupOuterShadow};
display: flex;
overflow: hidden;
transition-property: opacity, transform;
@ -129,10 +129,12 @@ const cssImage = styled('img', `
`);
const cssBody = styled('div', `
color: ${theme.text};
min-width: 0px;
`);
const cssTitle = styled('div', `
color: ${theme.text};
font-size: var(--title-font-size);
font-weight: ${vars.headerControlTextWeight};
margin-bottom: 16px;
@ -165,10 +167,10 @@ export const cssCloseButton = styled('div', `
padding: 4px;
border-radius: 4px;
cursor: pointer;
--icon-color: ${colors.slate};
--icon-color: ${theme.popupCloseButtonFg};
&:hover {
background-color: ${colors.mediumGreyOpaque};
background-color: ${theme.hover};
}
`);

@ -5,7 +5,7 @@ import {buildHighlightedCode, cssCodeBlock} from 'app/client/ui/CodeHighlight';
import {cssBlockedCursor, cssLabel, cssRow} from 'app/client/ui/RightPanelStyles';
import {buildFormulaTriggers} from 'app/client/ui/TriggerFormulas';
import {textButton} from 'app/client/ui2018/buttons';
import {colors, testId} from 'app/client/ui2018/cssVars';
import {testId, theme} from 'app/client/ui2018/cssVars';
import {textInput} from 'app/client/ui2018/editableLabel';
import {cssIconButton, icon} from 'app/client/ui2018/icons';
import {IconName} from 'app/client/ui2018/IconList';
@ -42,13 +42,13 @@ export function buildNameConfig(owner: MultiHolder, origColumn: ColumnRec, curso
cssRow(
dom.cls(cssBlockedCursor.className, origColumn.disableModify),
cssColLabelBlock(
editor = textInput(fromKo(origColumn.label),
editor = cssInput(fromKo(origColumn.label),
async val => { await origColumn.label.saveOnly(val); editedLabel.set(''); },
dom.on('input', (ev, elem) => { if (!untieColId.peek()) { editedLabel.set(elem.value); } }),
dom.boolAttr('disabled', origColumn.disableModify),
testId('field-label'),
),
textInput(editableColId,
cssInput(editableColId,
saveColId,
dom.boolAttr('disabled', use => use(origColumn.disableModify) || !use(origColumn.untieColIdFromLabel)),
cssCodeBlock.cls(''),
@ -332,10 +332,10 @@ export const cssFieldFormula = styled(buildHighlightedCode, `
cursor: pointer;
margin-top: 4px;
padding-left: 24px;
--icon-color: ${colors.lightGreen};
--icon-color: ${theme.accentIcon};
&-disabled-icon.formula_field_sidepane::before {
--icon-color: ${colors.slate};
--icon-color: ${theme.lightText};
}
&-disabled {
pointer-events: none;
@ -344,20 +344,20 @@ export const cssFieldFormula = styled(buildHighlightedCode, `
const cssToggleButton = styled(cssIconButton, `
margin-left: 8px;
background-color: var(--grist-color-medium-grey-opaque);
box-shadow: inset 0 0 0 1px ${colors.darkGrey};
background-color: ${theme.rightPanelToggleButtonDisabledBg};
box-shadow: inset 0 0 0 1px ${theme.inputBorder};
&-selected, &-selected:hover {
box-shadow: none;
background-color: ${colors.dark};
--icon-color: ${colors.light};
background-color: ${theme.rightPanelToggleButtonEnabledBg};
--icon-color: ${theme.rightPanelToggleButtonEnabledFg};
}
&-selected:hover {
--icon-color: ${colors.darkGrey};
--icon-color: ${theme.rightPanelToggleButtonEnabledHoverFg};
}
&-disabled, &-disabled:hover {
--icon-color: ${colors.light};
background-color: var(--grist-color-medium-grey-opaque);
--icon-color: ${theme.rightPanelToggleButtonDisabledFg};
background-color: ${theme.rightPanelToggleButtonDisabledBg};
}
`);
@ -374,7 +374,7 @@ const cssColTieBlock = styled('div', `
const cssColTieConnectors = styled('div', `
position: absolute;
border: 2px solid var(--grist-color-dark-grey);
border: 2px solid ${theme.inputBorder};
top: -9px;
bottom: -9px;
right: 11px;
@ -386,3 +386,18 @@ const cssColTieConnectors = styled('div', `
const cssEmptySeparator = styled('div', `
margin-top: 16px;
`);
const cssInput = styled(textInput, `
color: ${theme.inputFg};
background-color: ${theme.mainPanelBg};
border: 1px solid ${theme.inputBorder};
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
&:disabled {
background-color: ${theme.inputDisabledBg};
color: ${theme.inputDisabledFg};
}
`);

@ -3,7 +3,7 @@ import { ColumnRec, ViewFieldRec, ViewSectionRec } from "app/client/models/DocMo
import { FilterInfo } from "app/client/models/entities/ViewSectionRec";
import { attachColumnFilterMenu } from "app/client/ui/ColumnFilterMenu";
import { cssButton, cssButtonGroup } from "app/client/ui2018/buttons";
import { colors, testId } from "app/client/ui2018/cssVars";
import { testId, theme } from "app/client/ui2018/cssVars";
import { icon } from "app/client/ui2018/icons";
import { menu, menuItemAsync } from "app/client/ui2018/menus";
import { dom, IDisposableOwner, IDomArgs, styled } from "grainjs";
@ -117,14 +117,14 @@ const cssBtn = styled('div', `
margin: 0 4px;
}
&-grayed {
color: ${colors.light};
--icon-color: ${colors.light};
background-color: ${colors.slate};
border-color: ${colors.slate};
color: ${theme.filterBarButtonSavedFg};
--icon-color: ${theme.filterBarButtonSavedFg};
background-color: ${theme.filterBarButtonSavedBg};
border-color: ${theme.filterBarButtonSavedBg};
}
&-grayed:hover {
background-color: ${colors.darkGrey};
border-color: ${colors.darkGrey};
background-color: ${theme.filterBarButtonSavedHoverBg};
border-color: ${theme.filterBarButtonSavedHoverBg};
}
`);
const primaryButton = (...args: IDomArgs<HTMLDivElement>) => (

@ -1,6 +1,6 @@
import { allCommands } from 'app/client/components/commands';
import { ViewFieldRec } from 'app/client/models/entities/ViewFieldRec';
import { testId, vars } from 'app/client/ui2018/cssVars';
import { testId, theme } from 'app/client/ui2018/cssVars';
import { icon } from 'app/client/ui2018/icons';
import { menuDivider, menuItem, menuItemCmd } from 'app/client/ui2018/menus';
import { Sort } from 'app/common/SortSpec';
@ -297,9 +297,9 @@ const cssCustomMenuItem = styled('div', `
padding: 8px 8px;
display: flex;
&:not(:hover) {
background-color: white;
color: black;
--icon-color: black;
background-color: ${theme.menuBg};
color: ${theme.menuItemFg};
--icon-color: ${theme.menuItemFg};
}
&:last-of-type {
padding-right: 24px;
@ -310,9 +310,9 @@ const cssCustomMenuItem = styled('div', `
flex: 1 0 auto;
}
&-selected, &-selected:not(:hover) {
background-color: ${vars.primaryBg};
color: white;
--icon-color: white;
background-color: ${theme.menuItemSelectedBg};
color: ${theme.menuItemSelectedFg};
--icon-color: ${theme.menuItemSelectedFg};
}
`);

@ -5,7 +5,7 @@ import * as css from 'app/client/ui/DocMenuCss';
import {createDocAndOpen, importDocAndOpen} from 'app/client/ui/HomeLeftPane';
import {manageTeamUsersApp} from 'app/client/ui/OpenUserManager';
import {bigBasicButton, cssButton} from 'app/client/ui2018/buttons';
import {testId, vars} from 'app/client/ui2018/cssVars';
import {testId, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {cssLink} from 'app/client/ui2018/links';
import {commonUrls, shouldHideUiElement} from 'app/common/gristUrls';
@ -131,6 +131,7 @@ function makeCreateButtons(homeModel: HomeModel) {
}
const cssParagraph = styled(css.docBlock, `
color: ${theme.text};
line-height: 1.6;
`);

@ -9,7 +9,7 @@ import {docImport, importFromPlugin} from 'app/client/ui/HomeImports';
import {cssLinkText, cssPageEntry, cssPageIcon, cssPageLink, cssSpacer} from 'app/client/ui/LeftPanelCommon';
import {createVideoTourToolsButton} from 'app/client/ui/OpenVideoTour';
import {transientInput} from 'app/client/ui/transientInput';
import {colors, testId} from 'app/client/ui2018/cssVars';
import {testId, theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {menu, menuIcon, menuItem, upgradableMenuItem, upgradeText} from 'app/client/ui2018/menus';
import {confirmModal} from 'app/client/ui2018/modals';
@ -248,6 +248,7 @@ export const cssEditorInput = styled(transientInput, `
flex: 1 1 0px;
min-width: 0px;
color: initial;
background-color: ${theme.inputBg};
margin-right: 16px;
font-size: inherit;
`);
@ -265,9 +266,9 @@ const cssMenuTrigger = styled('div', `
display: block;
}
&:hover, &.weasel-popup-open {
background-color: ${colors.darkGrey};
background-color: ${theme.pageOptionsHoverBg};
}
.${cssPageEntry.className}-selected &:hover, .${cssPageEntry.className}-selected &.weasel-popup-open {
background-color: ${colors.slate};
background-color: ${theme.pageOptionsSelectedHoverBg};
}
`);

@ -15,7 +15,7 @@
*/
import {beaconOpenMessage} from 'app/client/lib/helpScout';
import {AppModel} from 'app/client/models/AppModel';
import {colors, testId, vars} from 'app/client/ui2018/cssVars';
import {testId, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {commonUrls, shouldHideUiElement} from 'app/common/gristUrls';
import {dom, DomContents, Observable, styled} from 'grainjs';
@ -83,7 +83,7 @@ export const cssTools = styled('div', `
export const cssSectionHeader = styled('div', `
margin: 24px 0 8px 24px;
color: ${colors.slate};
color: ${theme.lightText};
text-transform: uppercase;
font-weight: 500;
font-size: ${vars.xsmallFontSize};
@ -96,22 +96,22 @@ export const cssSectionHeader = styled('div', `
export const cssPageEntry = styled('div', `
margin: 0px 16px 0px 0px;
border-radius: 0 3px 3px 0;
color: ${colors.dark};
--icon-color: ${colors.slate};
color: ${theme.text};
--icon-color: ${theme.lightText};
cursor: default;
&:hover, &.weasel-popup-open, &-renaming {
background-color: ${colors.mediumGrey};
background-color: ${theme.pageHoverBg};
}
&-selected, &-selected:hover, &-selected.weasel-popup-open {
background-color: ${colors.darkBg};
color: ${colors.light};
--icon-color: ${colors.light};
background-color: ${theme.activePageBg};
color: ${theme.activePageFg};
--icon-color: ${theme.activePageFg};
}
&-disabled, &-disabled:hover, &-disabled.weasel-popup-open {
background-color: initial;
color: ${colors.darkGrey};
--icon-color: ${colors.darkGrey};
color: ${theme.disabledPageFg};
--icon-color: ${theme.disabledPageFg};
}
.${cssTools.className}-collapsed > & {
margin-right: 0;
@ -171,12 +171,12 @@ export const cssPageEntryMain = styled(cssPageEntry, `
export const cssPageEntrySmall = styled(cssPageEntry, `
flex: none;
border-radius: 3px;
--icon-color: ${colors.lightGreen};
--icon-color: ${theme.controlFg};
& > .${cssPageLink.className} {
padding: 0 8px 0 16px;
}
&:hover {
--icon-color: ${colors.darkGreen};
--icon-color: ${theme.controlHoverFg};
}
.${cssTools.className}-collapsed & {
display: none;

@ -9,7 +9,7 @@ import {getWorkspaceInfo, ownerName, workspaceName} from 'app/client/models/Work
import {cssInput} from 'app/client/ui/cssInput';
import {bigBasicButton, bigPrimaryButtonLink} from 'app/client/ui2018/buttons';
import {labeledSquareCheckbox} from 'app/client/ui2018/checkbox';
import {colors, testId, vars} from 'app/client/ui2018/cssVars';
import {testId, theme, vars} from 'app/client/ui2018/cssVars';
import {loadingSpinner} from 'app/client/ui2018/loaders';
import {select} from 'app/client/ui2018/menus';
import {confirmModal, cssModalBody, cssModalButtons, cssModalWidth, modal, saveModal} from 'app/client/ui2018/modals';
@ -284,7 +284,7 @@ export const cssField = styled('div', `
export const cssLabel = styled('label', `
font-weight: normal;
font-size: ${vars.mediumFontSize};
color: ${colors.dark};
color: ${theme.text};
margin: 8px 16px 0 0;
white-space: nowrap;
width: 80px;
@ -292,7 +292,7 @@ export const cssLabel = styled('label', `
`);
const cssWarningText = styled('div', `
color: red;
color: ${theme.errorText};
margin-top: 8px;
`);

@ -1,6 +1,6 @@
import { dom, DomArg, IDisposableOwner, styled } from "grainjs";
import { theme } from "app/client/ui2018/cssVars";
import { icon } from "app/client/ui2018/icons";
import { colors } from "app/client/ui2018/cssVars";
import { dom, DomArg, IDisposableOwner, styled } from "grainjs";
/**
* Creates a toggle button - little square button with a dropdown icon inside, used
@ -15,18 +15,18 @@ export function menuToggle(obs: IDisposableOwner, ...args: DomArg[]) {
}
const cssMenuToggle = styled('div.menu_toggle', `
background: white;
background: ${theme.menuToggleBg};
cursor: pointer;
--icon-color: ${colors.slate};
border: 1px solid ${colors.slate};
--icon-color: ${theme.menuToggleFg};
border: 1px solid ${theme.menuToggleBorder};
border-radius: 4px;
&:hover {
--icon-color: ${colors.darkGreen};
border-color: ${colors.darkGreen};
--icon-color: ${theme.menuToggleHoverFg};
border-color: ${theme.menuToggleHoverFg};
}
&:active {
--icon-color: ${colors.darkerGreen};
border-color: ${colors.darkerGreen};
--icon-color: ${theme.menuToggleActiveFg};
border-color: ${theme.menuToggleActiveFg};
}
& > .menu_toggle_icon {
display: block; /* don't create a line */

@ -4,7 +4,7 @@ import {ConnectState} from 'app/client/models/ConnectState';
import {urlState} from 'app/client/models/gristUrlState';
import {Expirable, IAppError, Notification, Notifier, NotifyAction, Progress} from 'app/client/models/NotifyModel';
import {cssHoverCircle, cssTopBarBtn} from 'app/client/ui/TopBarCss';
import {colors, vars} from 'app/client/ui2018/cssVars';
import {theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {IconName} from "app/client/ui2018/IconList";
import {menuCssClass} from 'app/client/ui2018/menus';
@ -193,8 +193,8 @@ function buildConnectStateButton(state: ConnectState): Element {
const cssDropdownWrapper = styled('div', `
background-color: white;
border: 1px solid ${colors.darkGrey};
background-color: ${theme.notificationsPanelBodyBg};
border: 1px solid ${theme.notificationsPanelBorder};
padding: 0px;
`);
@ -208,17 +208,18 @@ const cssDropdownHeader = styled('div', `
justify-content: space-between;
align-items: center;
padding: 24px;
background-color: ${colors.lightGrey};
outline: 1px solid ${colors.darkGrey};
background-color: ${theme.notificationsPanelHeaderBg};
outline: 1px solid ${theme.notificationsPanelBorder};
`);
const cssDropdownHeaderTitle = styled('span', `
color: ${theme.text};
font-weight: bold;
`);
const cssDropdownFeedbackLink = styled('div', `
display: flex;
color: ${colors.lightGreen};
color: ${theme.controlFg};
cursor: pointer;
user-select: none;
&:hover {
@ -227,21 +228,21 @@ const cssDropdownFeedbackLink = styled('div', `
`);
const cssDropdownFeedbackIcon = styled(icon, `
background-color: ${colors.lightGreen};
background-color: ${theme.controlFg};
margin-right: 4px;
`);
const cssDropdownStatus = styled('div', `
padding: 16px 48px 24px 48px;
text-align: center;
border-top: 1px solid ${colors.darkGrey};
border-top: 1px solid ${theme.notificationsPanelBorder};
`);
const cssDropdownStatusText = styled('div', `
display: inline-block;
margin: 8px 0 0 0;
text-align: left;
color: ${colors.slate};
color: ${theme.lightText};
`);
// z-index below is set above other assorted children of <body> which include z-index such as 999
@ -279,7 +280,7 @@ const cssToastActions = styled('div', `
display: flex;
align-items: flex-end;
margin-top: 16px;
color: ${colors.lightGreen};
color: ${theme.toastControlFg};
`);
const cssToastWrapper = styled('div', `
@ -292,8 +293,8 @@ const cssToastWrapper = styled('div', `
padding: 12px;
border-radius: 3px;
color: ${colors.light};
background-color: ${vars.toastBg};
color: ${theme.toastText};
background-color: ${theme.toastBg};
pointer-events: auto;
@ -301,28 +302,28 @@ const cssToastWrapper = styled('div', `
transition: opacity ${Expirable.fadeDelay}ms;
&-error {
border-left: 6px solid ${colors.error};
border-left: 6px solid ${theme.toastErrorBg};
padding-left: 6px;
--icon-color: ${colors.error};
--icon-color: ${theme.toastErrorIcon};
}
&-success {
border-left: 6px solid ${colors.darkGreen};
border-left: 6px solid ${theme.toastSuccessBg};
padding-left: 6px;
--icon-color: ${colors.darkGreen};
--icon-color: ${theme.toastSuccessIcon};
}
&-warning {
border-left: 6px solid ${colors.warningBg};
border-left: 6px solid ${theme.toastWarningBg};
padding-left: 6px;
--icon-color: ${colors.warning};
--icon-color: ${theme.toastWarningIcon};
}
&-info {
border-left: 6px solid ${colors.lightBlue};
border-left: 6px solid ${theme.toastInfoBg};
padding-left: 6px;
--icon-color: ${colors.lightBlue};
--icon-color: ${theme.toastInfoIcon};
}
&-info .${cssToastActions.className} {
color: ${colors.lighterBlue};
color: ${theme.toastInfoControlFg};
}
&-left-icon {
@ -340,9 +341,9 @@ const cssToastWrapper = styled('div', `
}
.${cssDropdownContent.className} > & {
background-color: unset;
color: unset;
color: ${theme.text};
border-radius: 0px;
border-top: 1px solid ${colors.darkGrey};
border-top: 1px solid ${theme.notificationsPanelBorder};
margin: 0px;
padding: 16px 20px;
}
@ -389,8 +390,8 @@ const cssToastMemos = styled('div', `
const cssToastMemo = styled('div', `
margin: 3px;
color: ${colors.dark};
background: ${colors.light};
color: ${theme.text};
background: ${theme.notificationsPanelBodyBg};
padding: 3px;
`);
@ -399,16 +400,16 @@ const cssProgressBarWrapper = styled('div', `
margin-bottom: 11px;
height: 3px;
border-radius: 3px;
background-color: ${colors.light};
background-color: ${theme.progressBarBg};
`);
const cssProgressBarSize = styled('span', `
color: ${colors.slate};
color: ${theme.toastLightText};
`);
const cssProgressBarStatus = styled('div', `
height: 3px;
min-width: 3px;
border-radius: 3px;
background-color: ${colors.lightGreen};
background-color: ${theme.progressBarFg};
`);

@ -27,7 +27,7 @@ import { createPopper, Placement } from '@popperjs/core';
import { FocusLayer } from 'app/client/lib/FocusLayer';
import * as Mousetrap from 'app/client/lib/Mousetrap';
import { bigBasicButton, bigPrimaryButton } from "app/client/ui2018/buttons";
import { colors, vars } from "app/client/ui2018/cssVars";
import { theme, vars } from "app/client/ui2018/cssVars";
import range = require("lodash/range");
import {IGristUrlState} from "app/common/gristUrls";
import {urlState} from "app/client/models/gristUrlState";
@ -321,13 +321,13 @@ function buildArrow() {
const Container = styled('div', `
align-self: center;
border: 2px solid ${colors.lightGreen};
border: 2px solid ${theme.accentBorder};
border-radius: 3px;
z-index: 1000;
max-width: 490px;
position: relative;
background-color: white;
box-shadow: 0 2px 18px 0 rgba(31,37,50,0.31), 0 0 1px 0 rgba(76,86,103,0.24);
background-color: ${theme.popupBg};
box-shadow: 0 2px 18px 0 ${theme.popupInnerShadow}, 0 0 1px 0 ${theme.popupOuterShadow};
outline: unset;
`);
@ -339,9 +339,9 @@ const ArrowContainer = styled('div', `
position: absolute;
& path {
stroke: ${colors.lightGreen};
stroke: ${theme.accentBorder};
stroke-width: 2px;
fill: white;
fill: ${theme.popupBg};
}
${sideSelectorChunk('top')} > & {
@ -376,7 +376,7 @@ const ArrowContainer = styled('div', `
const ContentWrapper = styled('div', `
position: relative;
padding: 32px;
background-color: white;
background-color: ${theme.popupBg};
`);
const Footer = styled('div', `
@ -402,9 +402,9 @@ const Dot = styled('div', `
border-radius: 3px;
margin-right: 12px;
align-self: center;
background-color: ${colors.lightGreen};
background-color: ${theme.progressBarFg};
&-done {
background-color: ${colors.darkGrey};
background-color: ${theme.progressBarBg};
}
`);
@ -424,10 +424,11 @@ const Overlay = styled('div', `
const cssTitle = styled('div', `
font-size: ${vars.xxxlargeFontSize};
font-weight: ${vars.headerControlTextWeight};
color: ${colors.dark};
color: ${theme.text};
margin: 0 0 16px 0;
line-height: 32px;
`);
const cssBody = styled('div', `
color: ${theme.text};
`);

@ -1,6 +1,6 @@
import * as commands from 'app/client/components/commands';
import {cssLinkText, cssPageEntryMain, cssPageIcon, cssPageLink} from 'app/client/ui/LeftPanelCommon';
import {colors} from 'app/client/ui2018/cssVars';
import {theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {modal} from 'app/client/ui2018/modals';
import {commonUrls, shouldHideUiElement} from 'app/common/gristUrls';
@ -106,21 +106,21 @@ const cssVideo = styled('iframe', `
`);
const cssVideoTourTextButton = styled('div', `
color: ${colors.lightGreen};
color: ${theme.controlFg};
cursor: pointer;
&:hover {
color: ${colors.darkGreen};
color: ${theme.controlHoverFg};
}
`);
const cssVideoIcon = styled(icon, `
background-color: ${colors.lightGreen};
background-color: ${theme.controlFg};
cursor: pointer;
margin: 0px 4px 3px 0;
.${cssVideoTourTextButton.className}:hover > & {
background-color: ${colors.darkGreen};
background-color: ${theme.controlHoverFg};
}
`);
@ -130,10 +130,10 @@ const cssCloseButton = styled('div', `
padding: 4px;
border-radius: 4px;
cursor: pointer;
--icon-color: ${colors.slate};
--icon-color: ${theme.modalCloseButtonFg};
&:hover {
background-color: ${colors.mediumGreyOpaque};
background-color: ${theme.hover};
}
`);

@ -6,7 +6,7 @@ import {watchElementForBlur} from 'app/client/lib/FocusLayer';
import {urlState} from "app/client/models/gristUrlState";
import {resizeFlexVHandle} from 'app/client/ui/resizeHandle';
import {transition, TransitionWatcher} from 'app/client/ui/transitions';
import {colors, cssHideForNarrowScreen, isScreenResizing, mediaNotSmall, mediaSmall} from 'app/client/ui2018/cssVars';
import {cssHideForNarrowScreen, isScreenResizing, mediaNotSmall, mediaSmall, theme} from 'app/client/ui2018/cssVars';
import {isNarrowScreenObs} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {dom, DomArg, MultiHolder, noTestId, Observable, styled, subscribe, TestId} from "grainjs";
@ -102,7 +102,7 @@ export function pagePanels(page: PageContents) {
testId('left-panel'),
cssOverflowContainer(
contentWrapper = cssLeftPanelContainer(
cssTopHeader(left.header),
cssLeftPaneHeader(left.header),
left.content,
),
),
@ -264,7 +264,7 @@ export function pagePanels(page: PageContents) {
cssRightPane(
testId('right-panel'),
cssTopHeader(right.header),
cssRightPaneHeader(right.header),
right.content,
dom.style('width', (use) => use(right.panelOpen) ? use(right.panelWidth) + 'px' : ''),
@ -341,7 +341,7 @@ const cssPageContainer = styled(cssVBox, `
right: 0;
bottom: 0;
min-width: 600px;
background-color: ${colors.lightGrey};
background-color: ${theme.pageBg};
@media ${mediaSmall} {
& {
@ -359,7 +359,7 @@ const cssContentMain = styled(cssHBox, `
`);
export const cssLeftPane = styled(cssVBox, `
position: relative;
background-color: ${colors.lightGrey};
background-color: ${theme.leftPanelBg};
width: 48px;
margin-right: 0px;
transition: width 0.4s;
@ -415,7 +415,7 @@ const cssMainPane = styled(cssVBox, `
position: relative;
flex: 1 1 0px;
min-width: 0px;
background-color: white;
background-color: ${theme.mainPanelBg};
z-index: 1;
&-left-overlap {
margin-left: 48px;
@ -423,7 +423,7 @@ const cssMainPane = styled(cssVBox, `
`);
const cssRightPane = styled(cssVBox, `
position: relative;
background-color: ${colors.lightGrey};
background-color: ${theme.rightPanelBg};
width: 0px;
margin-left: 0px;
overflow: hidden;
@ -461,13 +461,13 @@ const cssRightPane = styled(cssVBox, `
display: none;
}
`);
const cssTopHeader = styled('div', `
height: 48px;
const cssHeader = styled('div', `
height: 49px;
flex: none;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid ${colors.mediumGrey};
border-bottom: 1px solid ${theme.pagePanelsBorder};
@media print {
& {
@ -479,9 +479,18 @@ const cssTopHeader = styled('div', `
display: none;
}
`);
const cssTopHeader = styled(cssHeader, `
background-color: ${theme.topHeaderBg};
`);
const cssLeftPaneHeader = styled(cssHeader, `
background-color: ${theme.leftPanelBg};
`);
const cssRightPaneHeader = styled(cssHeader, `
background-color: ${theme.rightPanelBg};
`);
const cssBottomFooter = styled ('div', `
height: ${bottomFooterHeightPx}px;
background-color: white;
background-color: ${theme.bottomFooterBg};
z-index: 20;
display: flex;
flex-direction: row;
@ -492,7 +501,7 @@ const cssBottomFooter = styled ('div', `
bottom: 0;
left: 0;
right: 0;
border-top: 1px solid ${colors.mediumGrey};
border-top: 1px solid ${theme.pagePanelsBorder};
@media ${mediaNotSmall} {
& {
display: none;
@ -508,8 +517,8 @@ const cssBottomFooter = styled ('div', `
}
`);
const cssResizeFlexVHandle = styled(resizeFlexVHandle, `
--resize-handle-color: ${colors.mediumGrey};
--resize-handle-highlight: ${colors.lightGreen};
--resize-handle-color: ${theme.pagePanelsBorder};
--resize-handle-highlight: ${theme.pagePanelsBorderResizing};
@media print {
& {
@ -521,7 +530,7 @@ const cssResizeDisabledBorder = styled('div', `
flex: none;
width: 1px;
height: 100%;
background-color: ${colors.mediumGrey};
background-color: ${theme.pagePanelsBorder};
position: absolute;
top: 0;
bottom: 0;
@ -535,20 +544,20 @@ const cssPanelOpener = styled(icon, `
padding: 8px 8px;
cursor: pointer;
-webkit-mask-size: 16px 16px;
background-color: ${colors.lightGreen};
background-color: ${theme.controlFg};
transition: transform 0.4s;
&:hover { background-color: ${colors.darkGreen}; }
&:hover { background-color: ${theme.controlHoverFg}; }
&-open { transform: rotateY(180deg); }
`);
const cssPanelOpenerNarrowScreenBtn = styled('div', `
width: 32px;
height: 32px;
--icon-color: ${colors.slate};
--icon-color: ${theme.sidePanelOpenerFg};
cursor: pointer;
border-radius: 4px;
&-open {
background-color: ${colors.lightGreen};
--icon-color: white;
background-color: ${theme.sidePanelOpenerActiveBg};
--icon-color: ${theme.sidePanelOpenerActiveFg};
}
`);
const cssPanelOpenerNarrowScreen = styled(icon, `
@ -562,7 +571,7 @@ const cssContentOverlay = styled('div', `
left: 0;
bottom: 0;
right: 0;
background-color: grey;
background-color: ${theme.pageBackdrop};
opacity: 0.5;
display: none;
z-index: 9;

@ -3,7 +3,7 @@ import { ColumnRec, DocModel, TableRec, ViewSectionRec } from 'app/client/models
import { linkId, NoLink } from 'app/client/ui/selectBy';
import { getWidgetTypes, IWidgetType } from 'app/client/ui/widgetTypes';
import { bigPrimaryButton } from "app/client/ui2018/buttons";
import { colors, vars } from "app/client/ui2018/cssVars";
import { theme, vars } from "app/client/ui2018/cssVars";
import { icon } from "app/client/ui2018/icons";
import { spinnerModal } from 'app/client/ui2018/modals';
import { isLongerThan, nativeCompare } from "app/common/gutil";
@ -421,15 +421,15 @@ function header(label: string) {
}
const cssContainer = styled('div', `
--outline: 1px solid rgba(217,217,217,0.60);
--outline: 1px solid ${theme.widgetPickerBorder};
max-height: 386px;
box-shadow: 0 2px 20px 0 rgba(38,38,51,0.20);
box-shadow: 0 2px 20px 0 ${theme.widgetPickerShadow};
border-radius: 2px;
display: flex;
flex-direction: column;
user-select: none;
background-color: white;
background-color: ${theme.widgetPickerPrimaryBg};
`);
const cssPopupWrapper = styled('div', `
@ -450,17 +450,19 @@ const cssPanel = styled('div', `
overflow: auto;
padding-bottom: 18px;
&:nth-of-type(2n) {
background-color: ${colors.lightGrey};
background-color: ${theme.widgetPickerSecondaryBg};
outline: var(--outline);
}
`);
const cssHeader = styled('div', `
color: ${theme.text};
margin: 24px 0 24px 24px;
font-size: ${vars.mediumFontSize};
`);
const cssEntry = styled('div', `
color: ${theme.widgetPickerItemFg};
padding: 0 0 0 24px;
height: 32px;
display: flex;
@ -471,10 +473,10 @@ const cssEntry = styled('div', `
overflow: hidden;
cursor: pointer;
&-selected {
background-color: ${colors.mediumGrey};
background-color: ${theme.widgetPickerItemSelectedBg};
}
&-disabled {
color: ${colors.mediumGrey};
color: ${theme.widgetPickerItemDisabledBg};
cursor: default;
}
&-disabled&-selected {
@ -485,14 +487,14 @@ const cssEntry = styled('div', `
const cssIcon = styled(icon, `
margin-right: 8px;
flex-shrink: 0;
--icon-color: ${colors.slate};
--icon-color: ${theme.widgetPickerIcon};
.${cssEntry.className}-disabled > & {
opacity: 0.2;
opacity: 0.25;
}
`);
const cssTypeIcon = styled(cssIcon, `
--icon-color: ${colors.lightGreen};
--icon-color: ${theme.widgetPickerPrimaryIcon};
`);
const cssLabel = styled('span', `
@ -518,7 +520,7 @@ const cssPivot = styled(cssEntry, `
const cssBigIcon = styled(icon, `
width: 24px;
height: 24px;
background-color: ${colors.darkGreen};
background-color: ${theme.widgetPickerSummaryIcon};
`);
const cssFooter = styled('div', `
@ -536,11 +538,14 @@ const cssFooterContent = styled('div', `
`);
const cssSmallLabel = styled('span', `
color: ${theme.text};
font-size: ${vars.xsmallFontSize};
margin-right: 8px;
`);
const cssSelect = styled(select, `
color: ${theme.selectButtonFg};
background-color: ${theme.selectButtonBg};
flex: 1 0 160px;
width: 160px;
`);

@ -8,7 +8,7 @@ import {find as findInTree, fromTableData, TreeItemRecord, TreeRecord,
TreeTableData} from 'app/client/models/TreeModel';
import {TreeViewComponent} from 'app/client/ui/TreeViewComponent';
import {labeledCircleCheckbox} from 'app/client/ui2018/checkbox';
import {colors} from 'app/client/ui2018/cssVars';
import {theme} from 'app/client/ui2018/cssVars';
import {cssLink} from 'app/client/ui2018/links';
import {ISaveModalOptions, saveModal} from 'app/client/ui2018/modals';
import {buildPageDom, PageActions} from 'app/client/ui2018/pages';
@ -182,7 +182,7 @@ const cssOptions = styled('div', `
const cssBlockCheckbox = styled('div', `
display: flex;
padding: 10px 8px;
border: 1px solid ${colors.mediumGrey};
border: 1px solid ${theme.modalBorder};
border-radius: 3px;
cursor: pointer;
& input::before, & input::after {
@ -190,7 +190,7 @@ const cssBlockCheckbox = styled('div', `
left: unset;
}
&:hover {
border-color: ${colors.lightGreen};
border-color: ${theme.accentBorder};
}
&-block {
pointer-events: none;
@ -208,7 +208,8 @@ const cssWarning = styled('div', `
`);
const cssTableName = styled('div', `
background: #eee;
color: black;
background-color: #eee;
padding: 3px 6px;
border-radius: 4px;
`);

@ -2,7 +2,7 @@ import {docUrl, urlState} from 'app/client/models/gristUrlState';
import {getTimeFromNow, HomeModel} from 'app/client/models/HomeModel';
import {makeDocOptionsMenu, makeRemovedDocOptionsMenu} from 'app/client/ui/DocMenu';
import {transientInput} from 'app/client/ui/transientInput';
import {colors, vars} from 'app/client/ui2018/cssVars';
import {colors, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {menu} from 'app/client/ui2018/menus';
import * as roles from 'app/common/roles';
@ -115,11 +115,11 @@ const pinnedDocWrapper = styled('div', `
position: relative;
width: 210px;
margin: 16px 24px 16px 0;
border: 1px solid ${colors.mediumGrey};
border: 1px solid ${theme.pinnedDocBorder};
border-radius: 1px;
vertical-align: top;
&:hover {
border: 1px solid ${colors.slate};
border: 1px solid ${theme.pinnedDocBorderHover};
}
/* TODO: Specify a gap on flexbox parents of pinnedDocWrapper instead. */
@ -132,16 +132,16 @@ const pinnedDoc = styled('a', `
display: flex;
flex-direction: column;
width: 100%;
color: black;
color: ${theme.text};
text-decoration: none;
cursor: pointer;
&:hover {
color: black;
color: ${theme.text};
text-decoration: none;
}
&-no-access, &-no-access:hover {
color: ${colors.slate};
color: ${theme.disabledText};
cursor: not-allowed;
}
`);
@ -216,6 +216,7 @@ const pinnedDocOptions = styled('div', `
const pinnedDocFooter = styled('div', `
width: 100%;
font-size: ${vars.mediumFontSize};
background-color: ${theme.pinnedDocFooterBg};
`);
const pinnedDocTitle = styled('div', `
@ -238,17 +239,18 @@ const pinnedDocEditorInput = styled(transientInput, `
padding: 0;
border: none;
outline: none;
background-color: ${colors.mediumGrey};
color: ${theme.text};
background-color: ${theme.pinnedDocEditorBg};
`);
const cssPinnedDocTimestamp = styled('div', `
margin: 8px 16px 16px 16px;
color: ${colors.slate};
color: ${theme.lightText};
`);
const cssPinnedDocDesc = styled(cssPinnedDocTimestamp, `
margin: 8px 16px 16px 16px;
color: ${colors.slate};
color: ${theme.lightText};
height: 48px;
line-height: 16px;
-webkit-box-orient: vertical;
@ -271,5 +273,5 @@ const cssPublicIcon = styled(icon, `
position: absolute;
top: 16px;
left: 16px;
--icon-color: ${colors.lightGreen};
--icon-color: ${theme.accentIcon};
`);

@ -30,7 +30,7 @@ import {CustomSectionConfig} from 'app/client/ui/CustomSectionConfig';
import {VisibleFieldsConfig} from 'app/client/ui/VisibleFieldsConfig';
import {IWidgetType, widgetTypes} from 'app/client/ui/widgetTypes';
import {basicButton, primaryButton} from 'app/client/ui2018/buttons';
import {colors, testId, vars} from 'app/client/ui2018/cssVars';
import {testId, theme, vars} from 'app/client/ui2018/cssVars';
import {textInput} from 'app/client/ui2018/editableLabel';
import {IconName} from 'app/client/ui2018/IconList';
import {icon} from 'app/client/ui2018/icons';
@ -567,7 +567,7 @@ function tabContentToDom(content: Observable<TabContent[]>|TabContent[]|IDomComp
}
const cssOverlay = styled('div', `
background-color: white;
background-color: ${theme.rightPanelDisabledOverlay};
opacity: 0.8;
position: absolute;
top: 0;
@ -578,19 +578,21 @@ const cssOverlay = styled('div', `
`);
const cssBottomText = styled('span', `
color: ${theme.text};
position: absolute;
bottom: -40px;
padding: 4px 16px;
`);
const cssLabel = styled('div', `
color: ${theme.text};
text-transform: uppercase;
margin: 16px 16px 12px 16px;
font-size: ${vars.xsmallFontSize};
`);
const cssRow = styled('div', `
color: ${theme.text};
display: flex;
margin: 8px 16px;
align-items: center;
@ -598,7 +600,7 @@ const cssRow = styled('div', `
margin-top: 24px;
}
&-disabled {
color: ${colors.slate};
color: ${theme.disabledText};
}
`);
@ -613,29 +615,29 @@ const cssButtonRow = styled(cssRow, `
const cssIcon = styled(icon, `
flex: 0 0 auto;
--icon-color: ${colors.slate};
--icon-color: ${theme.lightText};
`);
const cssTopBarItem = styled('div', `
flex: 1 1 0px;
height: 100%;
background-color: ${colors.lightGrey};
background-color: ${theme.rightPanelTabBg};
font-weight: ${vars.headerControlTextWeight};
color: ${colors.dark};
--icon-color: ${colors.slate};
color: ${theme.rightPanelTabFg};
--icon-color: ${theme.rightPanelTabIcon};
display: flex;
align-items: center;
cursor: default;
&-selected {
background-color: ${colors.lightGreen};
background-color: ${theme.rightPanelTabSelectedBg};
font-weight: initial;
color: ${colors.light};
--icon-color: ${colors.light};
color: ${theme.rightPanelTabSelectedFg};
--icon-color: ${theme.rightPanelTabSelectedFg};
}
&:not(&-selected):hover {
background-color: ${colors.mediumGrey};
--icon-color: ${colors.lightGreen};
background-color: ${theme.rightPanelTabHoverBg};
--icon-color: ${theme.rightPanelTabIconHover};
}
`);
@ -659,7 +661,7 @@ const cssHoverCircle = styled('div', `
justify-content: center;
&:hover {
background-color: ${colors.darkGreen};
background-color: ${theme.rightPanelTabCloseButtonHoverBg};
}
`);
@ -678,7 +680,7 @@ const cssSubTabContainer = styled('div', `
`);
const cssSubTab = styled('div', `
color: ${colors.lightGreen};
color: ${theme.rightPanelSubtabFg};
flex: auto;
height: 100%;
display: flex;
@ -686,21 +688,21 @@ const cssSubTab = styled('div', `
justify-content: flex-end;
text-align: center;
padding-bottom: 8px;
border-bottom: 1px solid ${colors.mediumGrey};
border-bottom: 1px solid ${theme.pagePanelsBorder};
cursor: default;
&-selected {
color: ${colors.dark};
border-bottom: 1px solid ${colors.lightGreen};
color: ${theme.rightPanelSubtabSelectedFg};
border-bottom: 1px solid ${theme.rightPanelSubtabSelectedUnderline};
}
&:not(&-selected):hover {
color: ${colors.darkGreen};
color: ${theme.rightPanelSubtabHoverFg};
}
&:hover {
border-bottom: 1px solid ${colors.lightGreen};
border-bottom: 1px solid ${theme.rightPanelSubtabHoverUnderline};
}
.${cssSubTabContainer.className}:hover > &-selected:not(:hover) {
border-bottom: 1px solid ${colors.mediumGrey};
border-bottom: 1px solid ${theme.pagePanelsBorder};
}
`);
@ -710,7 +712,7 @@ const cssTabContents = styled('div', `
`);
const cssSeparator = styled('div', `
border-bottom: 1px solid ${colors.mediumGrey};
border-bottom: 1px solid ${theme.pagePanelsBorder};
margin-top: 16px;
`);
@ -731,7 +733,7 @@ const cssConfigContainer = styled('div', `
const cssDataLabel = styled('div', `
flex: 0 0 81px;
color: ${colors.slate};
color: ${theme.lightText};
font-size: ${vars.xsmallFontSize};
margin-left: 4px;
margin-top: 2px;
@ -751,7 +753,7 @@ const cssList = styled('div', `
const cssListItem = styled('li', `
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
border-radius: 2px;
margin-bottom: 4px;
white-space: nowrap;
@ -763,10 +765,12 @@ const cssListItem = styled('li', `
const cssTextInput = styled(textInput, `
flex: 1 0 auto;
color: ${theme.inputFg};
background-color: ${theme.inputBg};
&:disabled {
color: ${colors.slate};
background-color: ${colors.lightGrey};
color: ${theme.inputDisabledFg};
background-color: ${theme.inputDisabledBg};
pointer-events: none;
}
`);

@ -1,13 +1,14 @@
import {colors, vars} from 'app/client/ui2018/cssVars';
import {theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {styled} from 'grainjs';
export const cssIcon = styled(icon, `
flex: 0 0 auto;
--icon-color: ${colors.slate};
--icon-color: ${theme.lightText};
`);
export const cssLabel = styled('div', `
color: ${theme.text};
text-transform: uppercase;
margin: 16px 16px 12px 16px;
font-size: ${vars.xsmallFontSize};
@ -23,11 +24,12 @@ export const cssRow = styled('div', `
display: flex;
margin: 8px 16px;
align-items: center;
color: ${theme.text};
&-top-space {
margin-top: 24px;
}
&-disabled {
color: ${colors.slate};
color: ${theme.disabledText};
}
`);
@ -46,6 +48,6 @@ export const cssButtonRow = styled(cssRow, `
`);
export const cssSeparator = styled('div', `
border-bottom: 1px solid ${colors.mediumGrey};
border-bottom: 1px solid ${theme.pagePanelsBorder};
margin-top: 16px;
`);

@ -6,7 +6,7 @@ import {makeCopy, replaceTrunkWithFork} from 'app/client/ui/MakeCopyMenu';
import {sendToDrive} from 'app/client/ui/sendToDrive';
import {cssHoverCircle, cssTopBarBtn} from 'app/client/ui/TopBarCss';
import {primaryButton} from 'app/client/ui2018/buttons';
import {colors, mediaXSmall, testId} from 'app/client/ui2018/cssVars';
import {mediaXSmall, testId, theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {menu, menuAnnotate, menuDivider, menuIcon, menuItem, menuItemLink, menuText} from 'app/client/ui2018/menus';
import {buildUrlId, parseUrlId} from 'app/common/gristUrls';
@ -265,9 +265,9 @@ const cssShareButton = styled('div', `
margin: 5px;
white-space: nowrap;
--share-btn-bg: ${colors.lightGreen};
--share-btn-bg: ${theme.controlPrimaryBg};
&-combined:hover, &-combined.weasel-popup-open {
--share-btn-bg: ${colors.darkGreen};
--share-btn-bg: ${theme.controlPrimaryHoverBg};
}
`);
@ -289,14 +289,14 @@ const cssShareAction = styled(primaryButton, `
const cssShareCircle = styled(cssHoverCircle, `
z-index: 1;
background-color: var(--share-btn-bg);
border: 1px solid white;
border: 1px solid ${theme.topHeaderBg};
&:hover, &.weasel-popup-open {
background-color: ${colors.darkGreen};
background-color: ${theme.controlPrimaryHoverBg};
}
`);
const cssShareIcon = styled(cssTopBarBtn, `
background-color: white;
background-color: ${theme.controlPrimaryFg};
height: 30px;
width: 30px;
`);
@ -310,8 +310,8 @@ const cssMenuSplitLinkText = styled('div', `
flex: auto;
padding: var(--weaseljs-menu-item-padding, 8px 24px);
&:not(:hover) {
background-color: white;
color: black;
background-color: ${theme.menuBg};
color: ${theme.menuItemFg};
}
`);
@ -320,11 +320,11 @@ const cssMenuIconLink = styled('a', `
flex: none;
padding: 8px 24px;
background-color: white;
--icon-color: ${colors.lightGreen};
background-color: ${theme.menuBg};
--icon-color: ${theme.menuItemLinkFg};
&:hover {
background-color: ${colors.mediumGreyOpaque};
--icon-color: ${colors.darkGreen};
background-color: ${theme.menuItemLinkselectedBg};
--icon-color: ${theme.menuItemLinkSelectedFg};
}
`);

@ -3,9 +3,9 @@ import {getOrgName} from 'app/common/UserAPI';
import {dom, makeTestId, styled} from 'grainjs';
import {AppModel} from 'app/client/models/AppModel';
import {urlState} from 'app/client/models/gristUrlState';
import {theme} from 'app/client/ui2018/cssVars';
import {menuDivider, menuIcon, menuItem, menuItemLink, menuSubHeader} from 'app/client/ui2018/menus';
import {icon} from 'app/client/ui2018/icons';
import {colors} from 'app/client/ui2018/cssVars';
const testId = makeTestId('test-site-switcher-');
@ -49,14 +49,14 @@ export function buildSiteSwitcher(appModel: AppModel) {
}
const cssOrgSelected = styled('div', `
background-color: ${colors.dark};
color: ${colors.light};
background-color: ${theme.siteSwitcherActiveBg};
color: ${theme.siteSwitcherActiveFg};
`);
const cssOrgCheckmark = styled(icon, `
flex: none;
margin-left: 16px;
--icon-color: ${colors.light};
--icon-color: ${theme.siteSwitcherActiveFg};
display: none;
.${cssOrgSelected.className} > & {
display: block;

@ -0,0 +1,62 @@
import {AppModel} from 'app/client/models/AppModel';
import * as css from 'app/client/ui/AccountPageCss';
import {labeledSquareCheckbox} from 'app/client/ui2018/checkbox';
import {select} from 'app/client/ui2018/menus';
import {ThemeAppearance} from 'app/common/ThemePrefs';
import {Computed, Disposable, dom, makeTestId, styled} from 'grainjs';
const testId = makeTestId('test-theme-config-');
export class ThemeConfig extends Disposable {
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) => {
return prefs.syncWithOS;
}).onWrite((value) => this._updateSyncWithOS(value));
constructor(private _appModel: AppModel) {
super();
}
public buildDom() {
return dom('div',
css.subHeader('Appearance ', css.betaTag('Beta')),
css.dataRow(
cssAppearanceSelect(
select(
this._appearance,
[
{value: 'light', label: 'Light'},
{value: 'dark', label: 'Dark'},
],
),
testId('appearance'),
),
),
css.dataRow(
labeledSquareCheckbox(
this._syncWithOS,
'Switch appearance automatically to match system',
testId('sync-with-os'),
),
),
testId('container'),
);
}
private _updateAppearance(appearance: ThemeAppearance) {
this._themePrefs.set({...this._themePrefs.get(), appearance});
}
private _updateSyncWithOS(syncWithOS: boolean) {
this._themePrefs.set({...this._themePrefs.get(), syncWithOS});
}
}
const cssAppearanceSelect = styled('div', `
width: 120px;
`);

@ -7,7 +7,7 @@ import {createHelpTools, cssLinkText, cssPageEntry, cssPageEntryMain, cssPageEnt
cssPageIcon, cssPageLink, cssSectionHeader, cssSpacer, cssSplitPageEntry,
cssTools} from 'app/client/ui/LeftPanelCommon';
import {hoverTooltip, tooltipCloseButton} from 'app/client/ui/tooltips';
import {colors} from 'app/client/ui2018/cssVars';
import {theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {cssLink} from 'app/client/ui2018/links';
import {menuAnnotate} from 'app/client/ui2018/menus';
@ -206,7 +206,7 @@ function addRevertViewAsUI() {
const cssConvertTooltip = styled('div', `
display: flex;
align-items: center;
--icon-color: ${colors.lightGreen};
--icon-color: ${theme.controlFg};
& > .${cssLink.className} {
margin-left: 8px;
@ -223,10 +223,10 @@ const cssExampleCardOpener = styled('div', `
width: 24px;
padding: 4px;
line-height: 0px;
--icon-color: ${colors.light};
background-color: ${colors.lightGreen};
--icon-color: ${theme.iconButtonFg};
background-color: ${theme.iconButtonPrimaryBg};
&:hover {
background-color: ${colors.darkGreen};
background-color: ${theme.iconButtonPrimaryHoverBg};
}
.${cssTools.className}-collapsed & {
display: none;
@ -234,9 +234,9 @@ const cssExampleCardOpener = styled('div', `
`);
const cssRevertViewAsButton = styled(cssExampleCardOpener, `
background-color: ${colors.darkGrey};
background-color: ${theme.iconButtonSecondaryBg};
&:hover {
background-color: ${colors.slate};
background-color: ${theme.iconButtonSecondaryHoverBg};
}
`);

@ -10,7 +10,7 @@ import {buildShareMenuButton} from 'app/client/ui/ShareMenu';
import {cssHoverCircle, cssTopBarBtn} from 'app/client/ui/TopBarCss';
import {docBreadcrumbs} from 'app/client/ui2018/breadcrumbs';
import {basicButton} from 'app/client/ui2018/buttons';
import {colors, cssHideForNarrowScreen, testId} from 'app/client/ui2018/cssVars';
import {cssHideForNarrowScreen, testId, theme} from 'app/client/ui2018/cssVars';
import {IconName} from 'app/client/ui2018/IconList';
import {waitGrainObs} from 'app/common/gutil';
import * as roles from 'app/common/roles';
@ -129,14 +129,14 @@ function topBarUndoBtn(iconName: IconName, ...domArgs: DomElementArg[]): Element
}
const cssTopBarUndoBtn = styled(cssTopBarBtn, `
background-color: ${colors.slate};
background-color: ${theme.topBarButtonSecondaryFg};
.${cssHoverCircle.className}:hover & {
background-color: ${colors.lightGreen};
background-color: ${theme.topBarButtonPrimaryFg};
}
.${cssHoverCircle.className}-disabled:hover & {
background-color: ${colors.darkGrey};
background-color: ${theme.topBarButtonDisabledFg};
cursor: default;
}
`);

@ -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 {styled} from 'grainjs';
@ -9,7 +9,7 @@ export const cssHoverCircle = styled('div', `
border-radius: 16px;
&:hover, &.weasel-popup-open {
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
&-disabled:hover {
@ -23,12 +23,12 @@ export const cssTopBarBtn = styled(icon, `
padding: 8px 8px;
cursor: pointer;
-webkit-mask-size: 16px 16px;
background-color: ${colors.lightGreen};
background-color: ${theme.topBarButtonPrimaryFg};
.${cssHoverCircle.className}-disabled & {
background-color: ${colors.darkGrey};
background-color: ${theme.topBarButtonDisabledFg};
cursor: default;
}
&-slate { background-color: ${colors.slate}; }
&-error { background-color: ${colors.error}; }
&-slate { background-color: ${theme.topBarButtonSecondaryFg}; }
&-error { background-color: ${theme.topBarButtonErrorFg}; }
`);

@ -1,4 +1,4 @@
import { colors, vars } from "app/client/ui2018/cssVars";
import { theme } from "app/client/ui2018/cssVars";
import { icon } from "app/client/ui2018/icons";
import { styled } from "grainjs";
@ -42,27 +42,28 @@ export const itemHeader = styled('div', `
min-width: 0;
border-radius: 0 2px 2px 0;
border: solid 1px transparent;
color: ${theme.text};
.${itemHeaderWrapper.className}-not-dragging:hover > & {
background-color: ${colors.mediumGrey};
background-color: ${theme.pageHoverBg};
}
.${itemHeaderWrapper.className}-not-dragging > &.selected {
background-color: ${colors.darkBg};
color: white;
background-color: ${theme.activePageBg};
color: ${theme.activePageFg};
}
&.highlight {
border-color: ${vars.controlFg};
border-color: ${theme.controlFg};
}
`);
export const dropdown = styled(icon, `
background-color: ${colors.slate};
background-color: ${theme.controlSecondaryFg};
.${itemHeaderWrapper.className}-not-dragging > .${itemHeader.className}.selected & {
background-color: white;
background-color: ${theme.activePageFg};
}
`);
export const itemLabelRight = styled('div', `
--icon-color: ${colors.slate};
--icon-color: ${theme.controlSecondaryFg};
width: 16px;
.${treeViewContainer.className}-close & {
display: none;
@ -114,6 +115,6 @@ export const offset = styled('div', `
export const target = styled('div', `
position: absolute;
height: 2px;
background: ${vars.controlFg};
background: ${theme.controlFg};
pointer-events: none;
`);

@ -5,7 +5,7 @@ import {cssRow} from 'app/client/ui/RightPanelStyles';
import {shadowScroll} from 'app/client/ui/shadowScroll';
import {basicButton, primaryButton} from "app/client/ui2018/buttons";
import {labeledSquareCheckbox} from "app/client/ui2018/checkbox";
import {colors, testId} from 'app/client/ui2018/cssVars';
import {testId, theme} from 'app/client/ui2018/cssVars';
import {icon} from "app/client/ui2018/icons";
import {menuCssClass, menuDivider} from 'app/client/ui2018/menus';
import {cssSelectBtn} from 'app/client/ui2018/select';
@ -228,7 +228,7 @@ const cssSelectSummary = styled('div', `
&:empty::before {
content: "Select fields";
color: ${colors.slate};
color: ${theme.selectButtonPlaceholderFg};
}
`);
@ -244,8 +244,8 @@ const cssSelectorMenu = styled(cssMenu, `
const cssItemsList = styled(shadowScroll, `
flex: auto;
min-height: 80px;
border-top: 1px solid ${colors.darkGrey};
border-bottom: 1px solid ${colors.darkGrey};
border-top: 1px solid ${theme.menuBorder};
border-bottom: 1px solid ${theme.menuBorder};
margin-top: 8px;
padding: 8px 0;
`);
@ -263,7 +263,7 @@ const cssSelectorItem = styled(cssMenuItem, `
`);
const cssSelectorNote = styled('span', `
color: ${colors.slate};
color: ${theme.lightText};
`);
const cssSelectorFooter = styled(cssSelectorItem, `

@ -1,4 +1,4 @@
import {colors} from 'app/client/ui2018/cssVars';
import {colors, theme} from 'app/client/ui2018/cssVars';
import {FullUser} from 'app/common/LoginSessionAPI';
import {dom, DomElementArg, styled} from 'grainjs';
@ -120,8 +120,7 @@ const cssUserPicture = styled('img', `
width: 100%;
height: 100%;
object-fit: cover;
background-color: white;
background-color: ${theme.menuBg};
border-radius: 100px;
border: 1px solid white; /* make sure edge of circle with initials is not visible */
box-sizing: content-box; /* keep the border outside of the size of the image */
`);

@ -1,4 +1,4 @@
import {colors, vars} from 'app/client/ui2018/cssVars';
import {colors, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {input, styled} from 'grainjs';
import {cssMenuItem} from 'popweasel';
@ -54,16 +54,16 @@ export const cssMemberText = styled('div', `
export const cssMemberPrimary = styled('span', `
font-weight: bold;
color: ${colors.dark};
color: ${theme.text};
padding: 2px 0;
.${cssMenuItem.className}-sel & {
color: white;
color: ${theme.menuItemSelectedFg};
}
`);
export const cssMemberSecondary = styled('span', `
color: ${colors.slate};
color: ${theme.lightText};
/* the following just undo annoying bootstrap styles that apply to all labels */
margin: 0px;
font-weight: normal;
@ -71,12 +71,12 @@ export const cssMemberSecondary = styled('span', `
white-space: nowrap;
.${cssMenuItem.className}-sel & {
color: white;
color: ${theme.menuItemSelectedFg};
}
`);
export const cssMemberType = styled('span', `
color: ${colors.slate};
color: ${theme.lightText};
/* the following just undo annoying bootstrap styles that apply to all labels */
margin: 0px;
font-weight: normal;
@ -84,12 +84,12 @@ export const cssMemberType = styled('span', `
white-space: nowrap;
.${cssMenuItem.className}-sel & {
color: white;
color: ${theme.menuItemSelectedFg};
}
`);
export const cssMemberTypeProblem = styled('span', `
color: ${colors.error};
color: ${theme.errorText};
/* the following just undo annoying bootstrap styles that apply to all labels */
margin: 0px;
font-weight: normal;
@ -97,7 +97,7 @@ export const cssMemberTypeProblem = styled('span', `
white-space: nowrap;
.${cssMenuItem.className}-sel & {
color: white;
color: ${theme.menuItemSelectedFg};
}
`);
@ -113,6 +113,7 @@ export const cssMemberBtn = styled('div', `
`);
export const cssRemoveIcon = styled(icon, `
background-color: ${theme.lightText};
margin: 12px 0;
`);
@ -122,26 +123,32 @@ export const cssEmailInputContainer = styled('div', `
height: 42px;
padding: 0 3px;
margin: 16px 63px;
border: 1px solid ${colors.darkGrey};
border: 1px solid ${theme.inputBorder};
border-radius: 3px;
font-size: ${vars.mediumFontSize};
outline: none;
&-green {
border: 1px solid ${colors.lightGreen};
border: 1px solid ${theme.inputValid};
}
`);
export const cssEmailInput = styled(input, `
color: ${theme.inputFg};
background-color: ${theme.inputBg};
flex: 1 1 0;
line-height: 42px;
font-size: ${vars.mediumFontSize};
font-family: ${vars.fontFamily};
outline: none;
border: none;
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
`);
export const cssMailIcon = styled(icon, `
margin: 12px 8px 12px 13px;
background-color: ${colors.slate};
background-color: ${theme.lightText};
`);

@ -32,7 +32,7 @@ import {cssEmailInput, cssEmailInputContainer, cssMailIcon, cssMemberBtn, cssMem
cssMemberPrimary, cssMemberSecondary, cssMemberText, cssMemberType, cssMemberTypeProblem,
cssRemoveIcon} from 'app/client/ui/UserItem';
import {basicButton, bigBasicButton, bigPrimaryButton} from 'app/client/ui2018/buttons';
import {colors, mediaXSmall, testId, vars} from 'app/client/ui2018/cssVars';
import {colors, mediaXSmall, testId, theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {cssLink} from 'app/client/ui2018/links';
import {loadingSpinner} from 'app/client/ui2018/loaders';
@ -662,7 +662,7 @@ const cssAccessDetailsBody = styled('div', `
const cssUserManagerBody = styled(cssAccessDetailsBody, `
height: 374px;
border-bottom: 1px solid ${colors.darkGrey};
border-bottom: 1px solid ${theme.modalBorderDark};
`);
const cssSpinner = styled('div', `
@ -695,7 +695,7 @@ const cssOptionRow = styled('div', `
const cssOptionBtn = styled('span', `
display: inline-flex;
font-size: ${vars.mediumFontSize};
color: ${colors.lightGreen};
color: ${theme.controlFg};
cursor: pointer;
`);
@ -703,14 +703,15 @@ const cssPublicMemberIcon = styled(icon, `
width: 40px;
height: 40px;
margin: 0 4px;
--icon-color: ${colors.lightGreen};
--icon-color: ${theme.accentIcon};
`);
const cssPublicAccessIcon = styled(icon, `
--icon-color: ${colors.lightGreen};
--icon-color: ${theme.accentIcon};
`);
const cssUndoIcon = styled(icon, `
--icon-color: ${theme.controlSecondaryFg};
margin: 12px 0;
`);
@ -718,7 +719,7 @@ const cssRoleBtn = styled('div', `
display: flex;
justify-content: flex-end;
font-size: ${vars.mediumFontSize};
color: ${colors.lightGreen};
color: ${theme.controlFg};
margin: 12px 24px;
cursor: pointer;
@ -730,7 +731,7 @@ const cssRoleBtn = styled('div', `
const cssCollapseIcon = styled(icon, `
margin-top: 1px;
background-color: var(--grist-color-light-green);
background-color: ${theme.controlFg};
`);
const cssInputMenuItem = styled(menuItem, `
@ -747,8 +748,8 @@ const cssUserImagePlus = styled(cssUserImage, `
}
.${cssMenuItem.className}-sel & {
background-color: white;
color: ${colors.lightGreen};
background-color: ${theme.menuItemIconSelectedFg};
color: ${theme.menuItemSelectedBg};
}
`);
@ -762,7 +763,7 @@ const cssOrgName = styled('div', `
`);
const cssOrgDomain = styled('span', `
color: ${colors.lightGreen};
color: ${theme.accentText};
`);
const cssFadeInFromTop = keyframes(`

@ -7,7 +7,7 @@ import {addFilterMenu} from 'app/client/ui/FilterBar';
import {hoverTooltip} from 'app/client/ui/tooltips';
import {makeViewLayoutMenu} from 'app/client/ui/ViewLayoutMenu';
import {basicButton, primaryButton} from 'app/client/ui2018/buttons';
import {colors, vars} from 'app/client/ui2018/cssVars';
import {theme, vars} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {menu} from 'app/client/ui2018/menus';
import {Sort} from 'app/common/SortSpec';
@ -292,7 +292,7 @@ const cssMenu = styled('div', `
}
&:hover, &.weasel-popup-open {
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
`);
@ -310,13 +310,13 @@ const cssMenuIconWrapper = styled(cssIconWrapper, `
height: 22px;
&:hover, &.weasel-popup-open {
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
&-changed {
background-color: ${colors.lightGreen};
background-color: ${theme.accentIcon};
}
&-changed:hover, &-changed:hover.weasel-popup-open {
background-color: ${colors.darkGreen};
background-color: ${theme.controlHoverFg};
}
`);
@ -326,7 +326,7 @@ const cssFilterMenuWrapper = styled('div', `
border-radius: 3px;
align-items: center;
&-unsaved {
border: 1px solid ${colors.lightGreen};
border: 1px solid ${theme.accentBorder};
}
& .${cssMenu.className} {
border: none;
@ -337,18 +337,18 @@ const cssFilterMenuWrapper = styled('div', `
const cssIcon = styled(icon, `
flex: none;
cursor: pointer;
background-color: ${colors.slate};
background-color: ${theme.lightText};
.${cssMenuIconWrapper.className}-changed & {
background-color: white;
background-color: ${theme.controlPrimaryFg};
}
.${clsOldUI.className} & {
background-color: white;
background-color: ${theme.controlPrimaryFg};
}
&-green {
background-color: ${colors.lightGreen};
background-color: ${theme.accentIcon};
}
`);
@ -363,20 +363,21 @@ const cssDotsIconWrapper = styled(cssIconWrapper, `
const cssFilterIconWrapper = styled(cssIconWrapper, `
border-radius: 2px 0px 0px 2px;
.${cssFilterMenuWrapper.className}-unsaved & {
background-color: ${colors.lightGreen};
background-color: ${theme.accentIcon};
}
`);
const cssFilterIcon = styled(cssIcon, `
.${cssFilterIconWrapper.className}-any & {
background-color: ${colors.lightGreen};
background-color: ${theme.accentIcon};
}
.${cssFilterMenuWrapper.className}-unsaved & {
background-color: white;
background-color: ${theme.controlPrimaryFg};
}
`);
const cssMenuInfoHeader = styled('div', `
color: ${theme.menuSubheaderFg};
font-weight: ${vars.bigControlTextWeight};
padding: 8px 24px 8px 24px;
cursor: default;
@ -389,18 +390,19 @@ const cssMenuText = styled('div', `
cursor: default;
white-space: nowrap;
&-green {
color: ${colors.lightGreen};
color: ${theme.accentText};
}
&-gray {
color: ${colors.slate};
color: ${theme.lightText};
}
`);
const cssGrayedMenuText = styled(cssMenuText, `
color: ${colors.slate};
color: ${theme.lightText};
`);
const cssMenuTextLabel = styled('span', `
color: ${theme.menuItemFg};
flex-grow: 1;
padding: 0 4px;
overflow: hidden;
@ -418,13 +420,13 @@ const cssSmallIconWrapper = styled('div', `
margin: 0 5px 0 5px;
&-green {
background-color: ${colors.lightGreen};
background-color: ${theme.accentIcon};
}
&-gray {
background-color: ${colors.slate};
background-color: ${theme.lightText};
}
& > .${cssIcon.className} {
background-color: white;
background-color: ${theme.controlPrimaryFg};
}
`);

@ -7,7 +7,7 @@ import { getFieldType } from "app/client/ui/RightPanel";
import { IWidgetType } from "app/client/ui/widgetTypes";
import { basicButton, cssButton, primaryButton } from 'app/client/ui2018/buttons';
import * as checkbox from "app/client/ui2018/checkbox";
import { colors, vars } from "app/client/ui2018/cssVars";
import { theme, vars } from "app/client/ui2018/cssVars";
import { cssDragger } from "app/client/ui2018/draggableList";
import { icon } from "app/client/ui2018/icons";
import * as gutil from 'app/common/gutil';
@ -200,7 +200,7 @@ export class VisibleFieldsConfig extends Disposable {
dom.maybe(
(use) => Boolean(use(use(this._section.viewFields).getObservable()).length),
() => (
cssGreenLabel(
cssControlLabel(
icon('Tick'),
'Select All',
dom.on('click', () => this._setVisibleCheckboxes(fieldsDraggable, true)),
@ -236,7 +236,7 @@ export class VisibleFieldsConfig extends Disposable {
dom.maybe(
(use) => Boolean(use(this._hiddenFields.getObservable()).length && !use(this._collapseHiddenFields)),
() => (
cssGreenLabel(
cssControlLabel(
icon('Tick'),
'Select All',
dom.on('click', () => this._setHiddenCheckboxes(hiddenFieldsDraggable, true)),
@ -453,7 +453,7 @@ export const cssDragRow = styled('div', `
export const cssFieldEntry = styled('div', `
display: flex;
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
width: 100%;
border-radius: 2px;
margin: 0 8px 0 0;
@ -463,10 +463,11 @@ export const cssFieldEntry = styled('div', `
overflow: hidden;
text-overflow: ellipsis;
--icon-color: ${colors.slate};
--icon-color: ${theme.lightText};
`);
const cssHideIcon = styled(icon, `
--icon-color: ${theme.lightText};
display: none;
cursor: pointer;
flex: none;
@ -477,12 +478,14 @@ const cssHideIcon = styled(icon, `
`);
export const cssFieldLabel = styled('span', `
color: ${theme.text};
flex: 1 1 auto;
text-overflow: ellipsis;
overflow: hidden;
`);
const cssFieldListHeader = styled('span', `
color: ${theme.text};
flex: 1 1 0px;
font-size: ${vars.xsmallFontSize};
text-transform: uppercase;
@ -492,15 +495,15 @@ const cssRow = styled('div', `
display: flex;
margin: 16px;
overflow: hidden;
--icon-color: ${colors.slate};
--icon-color: ${theme.lightText};
& > .${cssButton.className} {
margin-right: 8px;
}
`);
const cssGreenLabel = styled('div', `
--icon-color: ${colors.lightGreen};
color: ${colors.lightGreen};
const cssControlLabel = styled('div', `
--icon-color: ${theme.controlFg};
color: ${theme.controlFg};
cursor: pointer;
`);
@ -511,6 +514,7 @@ const cssHeader = styled(cssRow, `
`);
const cssHeaderIcon = styled(icon, `
--icon-color: ${theme.lightText};
flex: none;
margin-right: 4px;
`);

@ -1,7 +1,7 @@
import {FocusLayer} from 'app/client/lib/FocusLayer';
import {ViewSectionRec} from 'app/client/models/entities/ViewSectionRec';
import {basicButton, cssButton, primaryButton} from 'app/client/ui2018/buttons';
import {colors, vars} from 'app/client/ui2018/cssVars';
import {theme, vars} from 'app/client/ui2018/cssVars';
import {cssTextInput} from 'app/client/ui2018/editableLabel';
import {menuCssClass} from 'app/client/ui2018/menus';
import {ModalControl} from 'app/client/ui2018/modals';
@ -189,7 +189,7 @@ const cssTitle = styled('div', `
text-overflow: ellipsis;
align-self: start;
&:hover {
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
&-empty {
min-width: 48px;
@ -202,12 +202,13 @@ const cssRenamePopup = styled('div', `
flex-direction: column;
min-width: 280px;
padding: 16px;
background-color: white;
background-color: ${theme.popupBg};
border-radius: 2px;
outline: none;
`);
const cssLabel = styled('label', `
color: ${theme.text};
font-size: ${vars.xsmallFontSize};
font-weight: ${vars.bigControlTextWeight};
margin: 0 0 8px 0;
@ -235,11 +236,16 @@ const cssInput = styled((
opts: IInputOptions,
...args) => input(obs, opts, cssTextInput.cls(''), ...args), `
text-overflow: ellipsis;
color: ${theme.inputFg};
background-color: transparent;
&:disabled {
color: ${colors.slate};
background-color: ${colors.lightGrey};
color: ${theme.inputDisabledFg};
background-color: ${theme.inputDisabledBg};
pointer-events: none;
}
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
.${cssInputWithIcon.className} > &:disabled {
padding-right: 28px;
}

@ -1,12 +1,18 @@
import {colors, vars} from 'app/client/ui2018/cssVars';
import {theme, vars} from 'app/client/ui2018/cssVars';
import {styled} from 'grainjs';
export const cssInput = styled('input', `
color: ${theme.inputFg};
background-color: ${theme.inputBg};
height: 30px;
width: 100%;
font-size: ${vars.mediumFontSize};
border-radius: 3px;
padding: 5px;
border: 1px solid ${colors.darkGrey};
border: 1px solid ${theme.inputBorder};
outline: none;
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
`);

@ -5,7 +5,7 @@ import {leftPanelBasic} from 'app/client/ui/LeftPanelCommon';
import {pagePanels} from 'app/client/ui/PagePanels';
import {createTopBarHome} from 'app/client/ui/TopBar';
import {bigBasicButtonLink, bigPrimaryButtonLink} from 'app/client/ui2018/buttons';
import {colors, vars} from 'app/client/ui2018/cssVars';
import {theme, vars} from 'app/client/ui2018/cssVars';
import {getPageTitleSuffix, GristLoadConfig} from 'app/common/gristUrls';
import {getGristConfig} from 'app/common/urlUtils';
import {dom, DomElementArg, makeTestId, observable, styled} from 'grainjs';
@ -144,12 +144,12 @@ const cssErrorHeader = styled('div', `
font-size: ${vars.xxxlargeFontSize};
margin: 24px;
text-align: center;
color: ${colors.dark};
color: ${theme.text};
`);
const cssErrorText = styled('div', `
font-size: ${vars.mediumFontSize};
color: ${colors.dark};
color: ${theme.text};
margin: 0 auto 24px auto;
max-width: 400px;
text-align: center;

@ -1,4 +1,4 @@
import {colors, vars} from 'app/client/ui2018/cssVars';
import {theme, vars} from 'app/client/ui2018/cssVars';
import {dom, DomElementArg, Observable, styled} from 'grainjs';
export const cssInput = styled('input', `
@ -7,10 +7,16 @@ export const cssInput = styled('input', `
line-height: 20px;
width: 100%;
padding: 14px;
border: 1px solid #D9D9D9;
border: 1px solid ${theme.inputBorder};
border-radius: 4px;
outline: none;
display: block;
color: ${theme.inputFg};
background-color: ${theme.inputBg};
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
&[type=number] {
-moz-appearance: textfield;
@ -22,11 +28,11 @@ export const cssInput = styled('input', `
}
&-invalid {
border: 1px solid ${colors.error};
border: 1px solid ${theme.inputInvalid};
}
&-valid {
border: 1px solid ${colors.lightGreen};
border: 1px solid ${theme.inputValid};
}
`);

@ -1,71 +0,0 @@
import {Disposable} from 'app/client/lib/dispose';
import {dom, styled} from 'grainjs';
const modalBacker = styled('div', `
position: fixed;
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 100;
background-color: rgba(0, 0, 0, 0.5);
`);
const modal = styled('div', `
background-color: white;
color: black;
margin: 0 auto;
border-radius: 4px;
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.2);
border: 1px solid #aaa;
padding: 10px;
`);
export const modalHeader = styled('div', `
font-size: 12pt;
color: #859394;
padding: 5px;
`);
export const modalButtonRow = styled('div', `
width: 70%;
margin: 0 auto;
text-align: center;
& > button {
width: 80px;
}
`);
/**
* A simple modal. Shows up in the middle of the screen with a tinted backdrop.
* Created with the given body content and width.
*
* Closed and disposed via clicking anywhere outside the modal. May also be closed by
* calling the `dispose()` function.
*/
export class Modal1 extends Disposable {
private _dom: Element;
public create(
body: Element,
width: number = 300
) {
this._dom = modalBacker(
modal({style: `width: ${width}px;`, tabindex: "-1"},
dom.cls('clipboard_focus'),
body,
dom.on('click', (e) => e.stopPropagation())
),
dom.on('click', () => this.dispose())
);
document.body.appendChild(this._dom);
this.autoDisposeCallback(() => {
document.body.removeChild(this._dom);
});
}
}

@ -6,7 +6,7 @@
*/
import {prepareForTransition} from 'app/client/ui/transitions';
import {colors, testId} from 'app/client/ui2018/cssVars';
import {testId, theme} from 'app/client/ui2018/cssVars';
import {IconName} from 'app/client/ui2018/IconList';
import {icon} from 'app/client/ui2018/icons';
import {dom, DomContents, DomElementArg, DomElementMethod, styled} from 'grainjs';
@ -225,11 +225,11 @@ export function infoTooltip(tipContent: DomContents, ...domArgs: DomElementArg[]
const cssTooltip = styled('div', `
position: absolute;
z-index: 5000; /* should be higher than a modal */
background-color: rgba(0, 0, 0, 0.75);
background-color: ${theme.tooltipBg};
border-radius: 3px;
box-shadow: 0 0 2px rgba(0,0,0,0.5);
text-align: center;
color: white;
color: ${theme.tooltipFg};
width: auto;
font-family: sans-serif;
font-size: 10pt;
@ -246,19 +246,19 @@ const cssTooltipCloseButton = styled('div', `
line-height: 16px;
text-align: center;
margin: -4px -4px -4px 8px;
--icon-color: white;
--icon-color: ${theme.tooltipCloseButtonFg};
border-radius: 16px;
&:hover {
background-color: white;
--icon-color: black;
background-color: ${theme.tooltipCloseButtonHoverBg};
--icon-color: ${theme.tooltipCloseButtonHoverFg};
}
`);
const cssIconTooltip = styled(icon, `
height: 12px;
width: 12px;
background-color: ${colors.slate};
background-color: ${theme.tooltipIcon};
flex-shrink: 0;
`);

@ -7,7 +7,8 @@
*/
import {reportError} from 'app/client/models/AppModel';
import {dom, DomArg} from 'grainjs';
import {theme} from 'app/client/ui2018/cssVars';
import {dom, DomArg, styled} from 'grainjs';
export interface ITransientInputOptions {
initialValue: string;
@ -36,7 +37,7 @@ export function transientInput({initialValue, save, close}: ITransientInputOptio
setTimeout(() => { input.focus(); input.select(); }, 10);
}
const input = dom('input', {type: 'text', placeholder: 'Enter name'},
const input = cssInput({type: 'text', placeholder: 'Enter name'},
dom.prop('value', initialValue),
dom.on('blur', () => onSave(false)),
dom.onKeyDown({
@ -48,3 +49,12 @@ export function transientInput({initialValue, save, close}: ITransientInputOptio
delayedFocus();
return input;
}
const cssInput = styled('input', `
background-color: transparent;
color: ${theme.inputFg};
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
`);

@ -1,7 +1,7 @@
import * as commands from 'app/client/components/commands';
import { urlState } from 'app/client/models/gristUrlState';
import { IOnBoardingMsg, startOnBoarding } from "app/client/ui/OnBoardingPopups";
import { colors } from 'app/client/ui2018/cssVars';
import { theme } from 'app/client/ui2018/cssVars';
import { icon } from "app/client/ui2018/icons";
import { cssLink } from "app/client/ui2018/links";
import { dom, styled } from "grainjs";
@ -54,7 +54,7 @@ export const welcomeTour: IOnBoardingMsg[] = [
selector: '.tour-share-icon',
title: 'Sharing',
body: () => [
dom('p', 'Use the Share button (', Icon('Share'), ') to share the document or export data.')
dom('p', 'Use the Share button (', TopBarButtonIcon('Share'), ') to share the document or export data.')
],
placement: 'bottom',
cropPadding: true,
@ -90,7 +90,7 @@ export function startWelcomeTour(onFinishCB: () => void) {
const KeyContent = styled('span', `
font-style: normal;
font-family: inherit;
color: ${colors.darkGreen};
color: ${theme.shortcutKeyPrimaryFg};
`);
const KeyStrong = styled(KeyContent, `
@ -102,20 +102,20 @@ const Key = styled('div', `
padding: 2px 5px;
border-radius: 4px;
margin: 0px 2px;
border: 1px solid ${colors.slate};
color: black;
background-color: white;
border: 1px solid ${theme.shortcutKeyBorder};
color: ${theme.shortcutKeyFg};
background-color: ${theme.shortcutKeyBg};
font-family: inherit;
font-style: normal;
white-space: nowrap;
`);
const Icon = styled(icon, `
--icon-color: ${colors.lightGreen};
const TopBarButtonIcon = styled(icon, `
--icon-color: ${theme.topBarButtonPrimaryFg};
`);
const GreyIcon = styled(icon, `
--icon-color: ${colors.slate};
--icon-color: ${theme.shortcutKeySecondaryFg};
margin-right: 8px;
`);

@ -1,6 +1,6 @@
import {basicButton, primaryButton} from 'app/client/ui2018/buttons';
import {isLight, swatches} from 'app/client/ui2018/ColorPalette';
import {colors, testId, vars} from 'app/client/ui2018/cssVars';
import {colors, testId, theme, vars} from 'app/client/ui2018/cssVars';
import {textInput} from 'app/client/ui2018/editableLabel';
import {IconName} from 'app/client/ui2018/IconList';
import {icon} from 'app/client/ui2018/icons';
@ -348,7 +348,8 @@ const cssFontOption = styled('div', `
display: grid;
place-items: center;
flex-grow: 1;
background: white;
background: ${colors.light};
--icon-color: ${colors.dark};
height: 24px;
cursor: pointer;
&:hover:not(&-selected) {
@ -418,12 +419,13 @@ const cssContent = styled('div', `
`);
const cssHexBox = styled(textInput, `
border: 1px solid ${colors.darkGrey};
border: 1px solid ${theme.inputBorder};
border-left: none;
font-size: ${vars.smallFontSize};
display: flex;
align-items: center;
color: ${colors.slate};
color: ${theme.lightText};
background-color: ${theme.inputBg};
width: 56px;
outline: none;
padding: 0 3px;

@ -6,35 +6,27 @@
* Workspace is a clickable link and document and page names are editable labels.
*/
import { urlState } from 'app/client/models/gristUrlState';
import { colors, cssHideForNarrowScreen, mediaNotSmall, testId } from 'app/client/ui2018/cssVars';
import { cssHideForNarrowScreen, mediaNotSmall, testId, theme } from 'app/client/ui2018/cssVars';
import { editableLabel } from 'app/client/ui2018/editableLabel';
import { icon } from 'app/client/ui2018/icons';
import { cssLink } from 'app/client/ui2018/links';
import { UserOverride } from 'app/common/DocListAPI';
import { userOverrideParams } from 'app/common/gristUrls';
import { BindableValue, dom, Observable, styled } from 'grainjs';
import { tooltip } from 'popweasel';
export const cssBreadcrumbs = styled('div', `
color: ${colors.slate};
color: ${theme.lightText};
white-space: nowrap;
cursor: default;
`);
export const cssBreadcrumbsLink = styled('a', `
color: ${colors.lightGreen};
text-decoration: none;
&:hover {
text-decoration: underline;
}
`);
export const separator = styled('span', `
padding: 0 2px;
`);
const cssIcon = styled(icon, `
background-color: ${colors.lightGreen};
background-color: ${theme.accentIcon};
margin-top: -2px;
`);
@ -43,7 +35,7 @@ const cssPublicIcon = styled(cssIcon, `
margin-top: -4px;
`);
const cssWorkspaceName = styled(cssBreadcrumbsLink, `
const cssWorkspaceName = styled(cssLink, `
margin-left: 8px;
`);
@ -54,7 +46,7 @@ const cssWorkspaceNarrowScreen = styled(icon, `
margin-bottom: 4px;
margin-left: -7px;
margin-right: 8px;
background-color: ${colors.slate};
background-color: ${theme.lightText};
cursor: pointer;
@media ${mediaNotSmall} {
& {
@ -65,21 +57,21 @@ const cssWorkspaceNarrowScreen = styled(icon, `
const cssEditableName = styled('input', `
&:hover, &:focus {
color: ${colors.dark};
color: ${theme.text};
}
`);
const cssTag = styled('span', `
background-color: ${colors.slate};
color: white;
background-color: ${theme.breadcrumbsTagBg};
color: ${theme.breadcrumbsTagFg};
border-radius: 3px;
padding: 0 4px;
margin-left: 4px;
`);
const cssAlertTag = styled(cssTag, `
background-color: ${colors.error};
--icon-color: white;
background-color: ${theme.breadcrumbsTagAlertBg};
--icon-color: ${theme.breadcrumbsTagFg};
a {
cursor: pointer;
}

@ -1,4 +1,4 @@
import {colors, testId, vars} from 'app/client/ui2018/cssVars';
import {colors, testId, theme, vars} from 'app/client/ui2018/cssVars';
import {IconName} from 'app/client/ui2018/IconList';
import {icon} from 'app/client/ui2018/icons';
import {isColorDark} from 'app/common/gutil';
@ -142,7 +142,7 @@ export const cssButtonSelect = styled('div', `
display: flex;
/* Vars */
color: ${colors.dark};
color: ${theme.text};
flex: 1 1 0;
`);
@ -165,8 +165,9 @@ const cssSelectorBtn = styled('div', `
white-space: nowrap;
padding: 4px 10px;
border: 1px solid ${colors.darkGrey};
--icon-color: ${colors.slate};
background-color: ${theme.buttonGroupBg};
border: 1px solid ${theme.buttonGroupBorder};
--icon-color: ${theme.buttonGroupIcon};
margin-left: -1px;
@ -184,15 +185,15 @@ const cssSelectorBtn = styled('div', `
}
&:hover:not(&-selected) {
border: 1px solid ${colors.hover};
border: 1px solid ${theme.buttonGroupBorderHover};
z-index: 5; /* Update z-index so selected borders take precedent */
}
&-selected {
color: ${colors.light};
--icon-color: ${colors.light};
border: 1px solid ${colors.dark};
background-color: ${colors.dark};
color: ${theme.buttonGroupSelectedFg};
--icon-color: ${theme.buttonGroupSelectedFg};
border: 1px solid ${theme.buttonGroupSelectedBorder};
background-color: ${theme.buttonGroupSelectedBg};
z-index: 10; /* Update z-index so selected borders take precedent */
}
@ -202,18 +203,18 @@ const cssSelectorBtn = styled('div', `
border-radius: ${vars.controlBorderRadius};
margin-left: 0px;
padding: 8px;
color: ${colors.slate};
--icon-color: ${colors.slate};
color: ${theme.buttonGroupLightFg};
--icon-color: ${theme.buttonGroupLightFg};
}
.${cssButtonSelect.className}-light > &-selected {
border: none;
color: ${colors.lightGreen};
--icon-color: ${colors.lightGreen};
color: ${theme.buttonGroupLightSelectedFg};
--icon-color: ${theme.buttonGroupLightSelectedFg};
background-color: initial;
}
.${cssButtonSelect.className}-light > &:hover {
border: none;
background-color: ${colors.mediumGrey};
background-color: ${theme.hover};
}
`);

@ -12,7 +12,7 @@
* `primaryButton('Primary button', dom.prop('disabled', true))`
*/
import { colors, vars } from 'app/client/ui2018/cssVars';
import { theme, vars } from 'app/client/ui2018/cssVars';
import { tbind } from 'app/common/tbind';
import { dom, DomElementArg, styled } from 'grainjs';
@ -29,11 +29,12 @@ export const cssButton = styled('button', `
padding: 4px 8px;
background-color: transparent;
color: ${vars.controlFg};
--icon-color: ${vars.controlFg};
color: ${theme.controlFg};
--icon-color: ${theme.controlFg};
border: ${vars.controlBorder};
border-radius: ${vars.controlBorderRadius};
border-color: ${theme.controlBorder};
cursor: pointer;
@ -44,29 +45,29 @@ export const cssButton = styled('button', `
}
&-primary {
background-color: ${vars.primaryBg};
color: ${vars.primaryFg};
--icon-color: ${vars.primaryFg};
border-color: ${vars.primaryBg};
background-color: ${theme.controlPrimaryBg};
color: ${theme.controlPrimaryFg};
--icon-color: ${theme.controlPrimaryFg};
border-color: ${theme.controlPrimaryBg};
}
&:hover {
color: ${vars.controlFgHover};
--icon-color: ${vars.controlFgHover};
border-color: ${vars.controlFgHover};
color: ${theme.controlHoverFg};
--icon-color: ${theme.controlHoverFg};
border-color: ${theme.controlHoverFg};
}
&-primary:hover {
color: ${vars.primaryFg};
--icon-color: ${vars.primaryFg};
background-color: ${vars.primaryBgHover};
border-color: ${vars.primaryBgHover};
color: ${theme.controlPrimaryFg};
--icon-color: ${theme.controlPrimaryFg};
background-color: ${theme.controlPrimaryHoverBg};
border-color: ${theme.controlPrimaryHoverBg};
}
&:disabled {
cursor: not-allowed;
color: ${colors.light};
--icon-color: ${colors.light};
background-color: ${colors.slate};
border-color: ${colors.slate};
color: ${theme.controlDisabledFg};
--icon-color: ${theme.controlDisabledFg};
background-color: ${theme.controlDisabledBg};
border-color: ${theme.controlDisabledBg};
}
`);
@ -107,7 +108,7 @@ export const textButton = styled(cssButton, `
padding: 0px;
background-color: inherit !important;
&:disabled {
color: ${colors.inactiveCursor};
color: ${theme.controlPrimaryDisabled};
}
`);

@ -15,7 +15,7 @@
* labeledSquareCheckbox(observable(false), 'Include other values', dom.prop('disabled', true)),
*/
import { colors } from 'app/client/ui2018/cssVars';
import { theme } from 'app/client/ui2018/cssVars';
import { Computed, dom, DomArg, styled } from 'grainjs';
import { Observable } from 'grainjs';
@ -28,9 +28,9 @@ export const cssLabel = styled('label', `
outline: none;
user-select: none;
--color: ${colors.darkGrey};
--color: ${theme.checkboxBorder};
&:hover {
--color: ${colors.hover};
--color: ${theme.checkboxBorderHover};
}
`);
@ -53,20 +53,14 @@ export const cssCheckboxSquare = styled('input', `
--radius: 3px;
&:checked:enabled, &:indeterminate:enabled {
--color: ${colors.lightGreen};
--color: ${theme.controlPrimaryBg};
}
&:disabled {
--color: ${colors.darkGrey};
--color: ${theme.checkboxDisabledBg};
cursor: not-allowed;
}
.${cssLabel.className}:hover > &:checked:enabled,
.${cssLabel.className}:hover > &:indeterminate:enabled, {
--color: ${colors.darkGreen};
}
&::before, &::after {
content: '';
@ -86,6 +80,14 @@ export const cssCheckboxSquare = styled('input', `
background-color: var(--color);
}
&:not(:checked):indeterminate::after {
-webkit-mask-image: var(--icon-Minus);
}
&:not(:disabled)::after {
background-color: ${theme.checkboxBg};
}
&:checked::after, &:indeterminate::after {
content: '';
position: absolute;
@ -95,15 +97,7 @@ export const cssCheckboxSquare = styled('input', `
-webkit-mask-size: contain;
-webkit-mask-position: center;
-webkit-mask-repeat: no-repeat;
background-color: ${colors.light};
}
&:not(:checked):indeterminate::after {
-webkit-mask-image: var(--icon-Minus);
}
&:not(:disabled)::after {
background-color: ${colors.light};
background-color: ${theme.controlPrimaryFg};
}
`);
@ -113,7 +107,7 @@ export const cssCheckboxCircle = styled(cssCheckboxSquare, `
export const cssLabelText = styled('span', `
margin-left: 8px;
color: ${colors.dark};
color: ${theme.text};
font-weight: initial; /* negate bootstrap */
overflow: hidden;
text-overflow: ellipsis;

@ -8,6 +8,7 @@
*/
import {urlState} from 'app/client/models/gristUrlState';
import {getTheme, ProductFlavor} from 'app/client/ui/CustomThemes';
import {Theme, ThemeAppearance} from 'app/common/ThemePrefs';
import {dom, makeTestId, Observable, styled, TestId} from 'grainjs';
import debounce = require('lodash/debounce');
import values = require('lodash/values');
@ -15,17 +16,32 @@ import values = require('lodash/values');
const VAR_PREFIX = 'grist';
class CustomProp {
constructor(public name: string, public value: string) { }
constructor(public name: string, public value?: string, public fallback?: string | CustomProp) {
}
public decl(): string | undefined {
if (this.value === undefined) { return undefined; }
public decl() {
return `--${VAR_PREFIX}-${this.name}: ${this.value};`;
}
public toString() {
return `var(--${VAR_PREFIX}-${this.name})`;
public toString(): string {
let value = `--${VAR_PREFIX}-${this.name}`;
if (this.fallback) {
value += `, ${this.fallback}`;
}
return `var(${value})`;
}
}
/**
* Theme-agnostic color properties.
*
* These are appropriate for UI elements whose color should not change based on the active
* theme. Generally, you should instead use the properties defined in `theme`, which will change
* based on the active theme.
*/
export const colors = {
lightGrey: new CustomProp('color-light-grey', '#F7F7F7'),
mediumGrey: new CustomProp('color-medium-grey', 'rgba(217,217,217,0.6)'),
@ -46,7 +62,7 @@ export const colors = {
lightBlue: new CustomProp('color-light-blue', '#3B82F6'),
orange: new CustomProp('color-orange', '#F9AE41'),
cursor: new CustomProp('color-cursor', '#16B378'), // cursor is lightGreen
cursor: new CustomProp('color-cursor', '#16B378'),
selection: new CustomProp('color-selection', 'rgba(22,179,120,0.15)'),
selectionOpaque: new CustomProp('color-selection-opaque', '#DCF4EB'),
selectionDarkerOpaque: new CustomProp('color-selection-darker-opaque', '#d6eee5'),
@ -117,6 +133,512 @@ export const vars = {
toastBg: new CustomProp('toast-bg', '#040404'),
};
/**
* Theme-related color properties.
*
* Unlike `colors`, these properties don't define any values as they aren't known ahead of time.
* Instead, when the application loads, CSS variables mapped to these properties are attached to
* the document based on the user's theme preferences.
*
* In the case that CSS variables aren't attached to the document, their fallback values will be
* used. This ensures that styles are still applied even when there's trouble fetching preferences,
* and also serves as a method of maintaining backwards compatibility with custom CSS rules that
* use legacy variable names (prefixed with `grist-color-`).
*/
export const theme = {
/* Text */
text: new CustomProp('theme-text', undefined, colors.dark),
lightText: new CustomProp('theme-text-light', undefined, colors.slate),
darkText: new CustomProp('theme-text-dark', undefined, 'black'),
errorText: new CustomProp('theme-text-error', undefined, colors.error),
dangerText: new CustomProp('theme-text-danger', undefined, '#FFA500'),
disabledText: new CustomProp('theme-text-disabled', undefined, colors.slate),
/* Page */
pageBg: new CustomProp('theme-page-bg', undefined, colors.lightGrey),
pageBackdrop: new CustomProp('theme-page-backdrop', undefined, 'grey'),
/* Page Panels */
mainPanelBg: new CustomProp('theme-page-panels-main-panel-bg', undefined, 'white'),
leftPanelBg: new CustomProp('theme-page-panels-left-panel-bg', undefined, colors.lightGrey),
rightPanelBg: new CustomProp('theme-page-panels-right-panel-bg', undefined, colors.lightGrey),
topHeaderBg: new CustomProp('theme-page-panels-top-header-bg', undefined, 'white'),
bottomFooterBg: new CustomProp('theme-page-panels-bottom-footer-bg', undefined, 'white'),
pagePanelsBorder: new CustomProp('theme-page-panels-border', undefined, colors.mediumGrey),
pagePanelsBorderResizing: new CustomProp('theme-page-panels-border-resizing', undefined,
colors.lightGreen),
sidePanelOpenerFg: new CustomProp('theme-page-panels-side-panel-opener-fg', undefined,
colors.slate),
sidePanelOpenerActiveFg: new CustomProp('theme-page-panels-side-panel-opener-active-fg',
undefined, 'white'),
sidePanelOpenerActiveBg: new CustomProp('theme-page-panels-side-panel-opener-active-bg',
undefined, colors.lightGreen),
/* Add New */
addNewCircleFg: new CustomProp('theme-add-new-circle-fg', undefined, colors.light),
addNewCircleBg: new CustomProp('theme-add-new-circle-bg', undefined, colors.darkGreen),
addNewCircleHoverBg: new CustomProp('theme-add-new-circle-hover-bg', undefined,
colors.darkerGreen),
addNewCircleSmallFg: new CustomProp('theme-add-new-circle-small-fg', undefined, colors.light),
addNewCircleSmallBg: new CustomProp('theme-add-new-circle-small-bg', undefined,
colors.lightGreen),
addNewCircleSmallHoverBg: new CustomProp('theme-add-new-circle-small-hover-bg', undefined,
colors.darkGreen),
/* Top Bar */
topBarButtonPrimaryFg: new CustomProp('theme-top-bar-button-primary-fg', undefined,
colors.lightGreen),
topBarButtonSecondaryFg: new CustomProp('theme-top-bar-button-secondary-fg', undefined,
colors.slate),
topBarButtonDisabledFg: new CustomProp('theme-top-bar-button-disabled-fg', undefined,
colors.darkGrey),
topBarButtonErrorFg: new CustomProp('theme-top-bar-button-error-fg', undefined, colors.error),
/* Notifications */
notificationsPanelHeaderBg: new CustomProp('theme-notifications-panel-header-bg', undefined,
colors.lightGrey),
notificationsPanelBodyBg: new CustomProp('theme-notifications-panel-body-bg', undefined,
'white'),
notificationsPanelBorder: new CustomProp('theme-notifications-panel-border', undefined,
colors.darkGrey),
/* Toasts */
toastText: new CustomProp('theme-toast-text', undefined, colors.light),
toastLightText: new CustomProp('theme-toast-text-light', undefined, colors.slate),
toastBg: new CustomProp('theme-toast-bg', undefined, vars.toastBg),
toastErrorIcon: new CustomProp('theme-toast-error-icon', undefined, colors.error),
toastErrorBg: new CustomProp('theme-toast-error-bg', undefined, colors.error),
toastSuccessIcon: new CustomProp('theme-toast-success-icon', undefined, colors.darkGreen),
toastSuccessBg: new CustomProp('theme-toast-success-bg', undefined, colors.darkGreen),
toastWarningIcon: new CustomProp('theme-toast-warning-icon', undefined, colors.warning),
toastWarningBg: new CustomProp('theme-toast-warning-bg', undefined, colors.warningBg),
toastInfoIcon: new CustomProp('theme-toast-info-icon', undefined, colors.lightBlue),
toastInfoBg: new CustomProp('theme-toast-info-bg', undefined, colors.lightBlue),
toastControlFg: new CustomProp('theme-toast-control-fg', undefined, colors.lightGreen),
toastInfoControlFg: new CustomProp('theme-toast-control-info-fg', undefined, colors.lighterBlue),
/* Tooltips */
tooltipFg: new CustomProp('theme-tooltip-fg', undefined, 'white'),
tooltipBg: new CustomProp('theme-tooltip-bg', undefined, 'rgba(0, 0, 0, 0.75)'),
tooltipIcon: new CustomProp('theme-tooltip-icon', undefined, colors.slate),
tooltipCloseButtonFg: new CustomProp('theme-tooltip-close-button-fg', undefined, 'white'),
tooltipCloseButtonHoverFg: new CustomProp('theme-tooltip-close-button-hover-fg', undefined,
'black'),
tooltipCloseButtonHoverBg: new CustomProp('theme-tooltip-close-button-hover-bg', undefined,
'white'),
/* Modals */
modalBg: new CustomProp('theme-modal-bg', undefined, 'white'),
modalBackdrop: new CustomProp('theme-modal-backdrop', undefined, colors.backdrop),
modalBorder: new CustomProp('theme-modal-border', undefined, colors.mediumGreyOpaque),
modalBorderDark: new CustomProp('theme-modal-border-dark', undefined, colors.darkGrey),
modalBorderHover: new CustomProp('theme-modal-border-hover', undefined, colors.slate),
modalInnerShadow: new CustomProp('theme-modal-shadow-inner', undefined,
'rgba(31, 37, 50, 0.31)'),
modalOuterShadow: new CustomProp('theme-modal-shadow-outer', undefined,
'rgba(76, 86, 103, 0.24)'),
modalCloseButtonFg: new CustomProp('theme-modal-close-button-fg', undefined, colors.slate),
modalBackdropCloseButtonFg: new CustomProp('theme-modal-backdrop-close-button-fg', undefined,
vars.primaryBg),
modalBackdropCloseButtonHoverFg: new CustomProp('theme-modal-backdrop-close-button-hover-fg',
undefined, colors.lighterGreen),
/* Popups */
popupBg: new CustomProp('theme-popup-bg', undefined, 'white'),
popupInnerShadow: new CustomProp('theme-popup-shadow-inner', undefined,
'rgba(31, 37, 50, 0.31)'),
popupOuterShadow: new CustomProp('theme-popup-shadow-outer', undefined,
'rgba(76, 86, 103, 0.24)'),
popupCloseButtonFg: new CustomProp('theme-popup-close-button-fg', undefined, colors.slate),
/* Progress Bars */
progressBarFg: new CustomProp('theme-progress-bar-fg', undefined, colors.lightGreen),
progressBarErrorFg: new CustomProp('theme-progress-bar-error-fg', undefined, colors.error),
progressBarBg: new CustomProp('theme-progress-bar-bg', undefined, colors.darkGrey),
/* Links */
link: new CustomProp('theme-link', undefined, colors.lightGreen),
linkHover: new CustomProp('theme-link-hover', undefined, colors.lightGreen),
/* Hover */
hover: new CustomProp('theme-hover', undefined, colors.mediumGrey),
lightHover: new CustomProp('theme-hover-light', undefined, colors.lightGrey),
/* Cell Editor */
cellEditorFg: new CustomProp('theme-cell-editor-fg', undefined, colors.dark),
cellEditorBg: new CustomProp('theme-cell-editor-bg', undefined, colors.light),
/* Cursor */
cursor: new CustomProp('theme-cursor', undefined, colors.cursor),
cursorInactive: new CustomProp('theme-cursor-inactive', undefined, colors.inactiveCursor),
cursorReadonly: new CustomProp('theme-cursor-readonly', undefined, colors.slate),
/* Tables */
tableHeaderFg: new CustomProp('theme-table-header-fg', undefined, 'unset'),
tableHeaderSelectedFg: new CustomProp('theme-table-header-selected-fg', undefined, 'unset'),
tableHeaderBg: new CustomProp('theme-table-header-bg', undefined, colors.lightGrey),
tableHeaderSelectedBg: new CustomProp('theme-table-header-selected-bg', undefined,
colors.mediumGreyOpaque),
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, 'unset'),
tableBodyBorder: new CustomProp('theme-table-body-border', undefined, colors.darkGrey),
tableAddNewBg: new CustomProp('theme-table-add-new-bg', undefined, 'inherit'),
tableScrollShadow: new CustomProp('theme-table-scroll-shadow', undefined, '#444444'),
tableFrozenColumnsBorder: new CustomProp('theme-table-frozen-columns-border', undefined,
'#999999'),
tableDragDropIndicator: new CustomProp('theme-table-drag-drop-indicator', undefined, 'gray'),
tableDragDropShadow: new CustomProp('theme-table-drag-drop-shadow', undefined, '#F0F0F0'),
/* Cards */
cardCompactWidgetBg: new CustomProp('theme-card-compact-widget-bg', undefined,
colors.mediumGrey),
cardCompactRecordBg: new CustomProp('theme-card-compact-record-bg', undefined, 'white'),
cardBlocksBg: new CustomProp('theme-card-blocks-bg', undefined, colors.mediumGrey),
cardFormLabel: new CustomProp('theme-card-form-label', undefined, colors.slate),
cardCompactLabel: new CustomProp('theme-card-compact-label', undefined, colors.slate),
cardBlocksLabel: new CustomProp('theme-card-blocks-label', undefined, colors.slate),
cardFormBorder: new CustomProp('theme-card-form-border', undefined, 'lightgrey'),
cardCompactBorder: new CustomProp('theme-card-compact-border', undefined, colors.darkGrey),
cardEditingLayoutBg: new CustomProp('theme-card-editing-layout-bg', undefined,
'rgba(192, 192, 192, 0.2)'),
cardEditingLayoutBorder: new CustomProp('theme-card-editing-layout-border', undefined,
colors.darkGrey),
/* Card Lists */
cardListFormBorder: new CustomProp('theme-card-list-form-border', undefined, colors.darkGrey),
cardListBlocksBorder: new CustomProp('theme-card-list-blocks-border', undefined,
colors.darkGrey),
/* Selection */
selection: new CustomProp('theme-selection', undefined, colors.selection),
selectionOpaqueFg: new CustomProp('theme-selection-opaque-fg', undefined, 'unset'),
selectionOpaqueBg: new CustomProp('theme-selection-opaque-bg', undefined,
colors.selectionOpaque),
selectionOpaqueDarkBg: new CustomProp('theme-selection-opaque-dark-bg', undefined,
colors.selectionDarkerOpaque),
/* Widgets */
widgetBorder: new CustomProp('theme-widget-border', undefined, colors.darkGrey),
widgetActiveBorder: new CustomProp('theme-widget-active-border', undefined, colors.lightGreen),
widgetInactiveStripesLight: new CustomProp('theme-widget-inactive-stripes-light', undefined,
colors.lightGrey),
widgetInactiveStripesDark: new CustomProp('theme-widget-inactive-stripes-dark', undefined,
colors.mediumGreyOpaque),
/* Pinned Docs */
pinnedDocFooterBg: new CustomProp('theme-pinned-doc-footer-bg', undefined, colors.light),
pinnedDocBorder: new CustomProp('theme-pinned-doc-border', undefined, colors.mediumGrey),
pinnedDocBorderHover: new CustomProp('theme-pinned-doc-border-hover', undefined, colors.slate),
pinnedDocEditorBg: new CustomProp('theme-pinned-doc-editor-bg', undefined, colors.mediumGrey),
/* Raw Data */
rawDataTableBorder: new CustomProp('theme-raw-data-table-border', undefined, colors.mediumGrey),
rawDataTableBorderHover: new CustomProp('theme-raw-data-table-border-hover',
undefined, colors.slate),
/* Controls */
controlFg: new CustomProp('theme-control-fg', undefined, vars.controlFg),
controlPrimaryFg: new CustomProp('theme-control-primary-fg', undefined, vars.primaryFg),
controlPrimaryBg: new CustomProp('theme-control-primary-bg', undefined, vars.primaryBg),
controlSecondaryFg: new CustomProp('theme-control-secondary-fg', undefined, colors.slate),
controlHoverFg: new CustomProp('theme-control-hover-fg', undefined, vars.controlFgHover),
controlPrimaryHoverBg: new CustomProp('theme-control-primary-hover-bg', undefined,
vars.primaryBgHover),
controlSecondaryHoverFg: new CustomProp('theme-control-secondary-hover-fg', undefined,
colors.dark),
controlSecondaryHoverBg: new CustomProp('theme-control-secondary-hover-bg', undefined,
colors.darkGrey),
controlDisabledFg: new CustomProp('theme-control-disabled-fg', undefined, colors.light),
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, '#11B683'),
/* Checkboxes */
checkboxBg: new CustomProp('theme-checkbox-bg', undefined, colors.light),
checkboxDisabledBg: new CustomProp('theme-checkbox-disabled-bg', undefined, colors.darkGrey),
checkboxBorder: new CustomProp('theme-checkbox-border', undefined, colors.darkGrey),
checkboxBorderHover: new CustomProp('theme-checkbox-border-hover', undefined, colors.hover),
/* Move Docs */
moveDocsSelectedFg: new CustomProp('theme-move-docs-selected-fg', undefined, 'white'),
moveDocsSelectedBg: new CustomProp('theme-move-docs-selected-bg', undefined, colors.lightGreen),
moveDocsDisabledFg: new CustomProp('theme-move-docs-disabled-bg', undefined, colors.darkGrey),
/* Filter Bar */
filterBarButtonSavedFg: new CustomProp('theme-filter-bar-button-saved-fg', undefined,
colors.light),
filterBarButtonSavedBg: new CustomProp('theme-filter-bar-button-saved-bg', undefined,
colors.slate),
filterBarButtonSavedHoverBg: new CustomProp('theme-filter-bar-button-saved-hover-bg', undefined,
colors.darkGrey),
/* Icon Buttons */
iconButtonFg: new CustomProp('theme-icon-button-fg', undefined, colors.light),
iconButtonPrimaryBg: new CustomProp('theme-icon-button-primary-bg', undefined,
colors.lightGreen),
iconButtonPrimaryHoverBg: new CustomProp('theme-icon-button-primary-hover-bg',
undefined, colors.darkGreen),
iconButtonSecondaryBg: new CustomProp('theme-icon-button-secondary-bg', undefined,
colors.darkGrey),
iconButtonSecondaryHoverBg: new CustomProp('theme-icon-button-secondary-hover-bg',
undefined, colors.slate),
/* Left Panel */
pageHoverBg: new CustomProp('theme-left-panel-page-hover-bg', undefined, colors.mediumGrey),
activePageFg: new CustomProp('theme-left-panel-active-page-fg', undefined, 'white'),
activePageBg: new CustomProp('theme-left-panel-active-page-bg', undefined, colors.darkBg),
disabledPageFg: new CustomProp('theme-left-panel-disabled-page-fg', undefined, colors.darkGrey),
pageOptionsFg: new CustomProp('theme-left-panel-page-options-bg', undefined, colors.slate),
pageOptionsHoverFg: new CustomProp('theme-left-panel-page-options-hover-fg', undefined, 'white'),
pageOptionsHoverBg: new CustomProp('theme-left-panel-page-options-hover-bg', undefined,
colors.darkGrey),
pageOptionsSelectedHoverBg: new CustomProp('theme-left-panel-page-options-selected-hover-bg',
undefined, colors.slate),
pageInitialsFg: new CustomProp('theme-left-panel-page-initials-fg', undefined, 'white'),
pageInitialsBg: new CustomProp('theme-left-panel-page-initials-bg', undefined, colors.slate),
/* Right Panel */
rightPanelTabFg: new CustomProp('theme-right-panel-tab-fg', undefined, colors.dark),
rightPanelTabBg: new CustomProp('theme-right-panel-tab-bg', undefined, colors.lightGrey),
rightPanelTabIcon: new CustomProp('theme-right-panel-tab-icon', undefined, colors.slate),
rightPanelTabIconHover: new CustomProp('theme-right-panel-tab-icon-hover', undefined,
colors.lightGreen),
rightPanelTabHoverBg: new CustomProp('theme-right-panel-tab-hover-bg', undefined,
colors.mediumGrey),
rightPanelTabSelectedFg: new CustomProp('theme-right-panel-tab-selected-fg', undefined,
colors.light),
rightPanelTabSelectedBg: new CustomProp('theme-right-panel-tab-selected-bg', undefined,
colors.lightGreen),
rightPanelTabCloseButtonHoverBg: new CustomProp('theme-right-panel-tab-close-button-hover-bg',
undefined, colors.darkGreen),
rightPanelSubtabFg: new CustomProp('theme-right-panel-subtab-fg', undefined, colors.lightGreen),
rightPanelSubtabSelectedFg: new CustomProp('theme-right-panel-subtab-selected-fg', undefined,
colors.dark),
rightPanelSubtabSelectedUnderline: new CustomProp('theme-right-panel-subtab-selected-underline',
undefined, colors.lightGreen),
rightPanelSubtabHoverFg: new CustomProp('theme-right-panel-subtab-hover-fg', undefined,
colors.darkGreen),
rightPanelSubtabHoverUnderline: new CustomProp('theme-right-panel-subtab-hover-underline',
undefined, colors.lightGreen),
rightPanelDisabledOverlay: new CustomProp('theme-right-panel-disabled-overlay', undefined,
'white'),
rightPanelToggleButtonEnabledFg: new CustomProp('theme-right-panel-toggle-button-enabled-fg',
undefined, colors.light),
rightPanelToggleButtonEnabledBg: new CustomProp('theme-right-panel-toggle-button-enabled-bg',
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',
undefined, colors.light),
rightPanelToggleButtonDisabledBg: new CustomProp('theme-right-panel-toggle-button-disabled-bg',
undefined, colors.mediumGreyOpaque),
rightPanelFieldSettingsBg: new CustomProp('theme-right-panel-field-settings-bg',
undefined, colors.mediumGreyOpaque),
rightPanelFieldSettingsButtonBg: new CustomProp('theme-right-panel-field-settings-button-bg',
undefined, 'lightgrey'),
/* Document History */
documentHistorySnapshotFg: new CustomProp('theme-document-history-snapshot-fg', undefined,
colors.dark),
documentHistorySnapshotSelectedFg: new CustomProp('theme-document-history-snapshot-selected-fg',
undefined, colors.light),
documentHistorySnapshotBg: new CustomProp('theme-document-history-snapshot-bg', undefined,
'white'),
documentHistorySnapshotSelectedBg: new CustomProp('theme-document-history-snapshot-selected-bg',
undefined, colors.dark),
documentHistorySnapshotBorder: new CustomProp('theme-document-history-snapshot-border',
undefined, colors.mediumGrey),
documentHistoryActivityText: new CustomProp('theme-document-history-activity-text', undefined,
'unset'),
documentHistoryActivityLightText: new CustomProp('theme-document-history-activity-text-light',
undefined, '#333333'),
/* Accents */
accentIcon: new CustomProp('theme-accent-icon', undefined, colors.lightGreen),
accentBorder: new CustomProp('theme-accent-border', undefined, colors.lightGreen),
accentText: new CustomProp('theme-accent-text', undefined, colors.lightGreen),
/* Inputs */
inputFg: new CustomProp('theme-input-fg', undefined, 'black'),
inputBg: new CustomProp('theme-input-bg', undefined, 'white'),
inputDisabledFg: new CustomProp('theme-input-disabled-fg', undefined, colors.slate),
inputDisabledBg: new CustomProp('theme-input-disabled-bg', undefined, colors.lightGrey),
inputPlaceholderFg: new CustomProp('theme-input-placeholder-fg', undefined, '#757575'),
inputBorder: new CustomProp('theme-input-border', undefined, colors.darkGrey),
inputValid: new CustomProp('theme-input-valid', undefined, colors.lightGreen),
inputInvalid: new CustomProp('theme-input-invalid', undefined, colors.error),
inputFocus: new CustomProp('theme-input-focus', undefined, '#5E9ED6'),
inputReadonlyBg: new CustomProp('theme-input-readonly-bg', undefined, colors.lightGrey),
inputReadonlyBorder: new CustomProp('theme-input-readonly-border', undefined, colors.mediumGreyOpaque),
/* Choice Entry */
choiceEntryBg: new CustomProp('theme-choice-entry-bg', undefined, 'white'),
choiceEntryBorder: new CustomProp('theme-choice-entry-border', undefined, colors.darkGrey),
choiceEntryBorderHover: new CustomProp('theme-choice-entry-border-hover', undefined,
colors.hover),
/* Select Buttons */
selectButtonFg: new CustomProp('theme-select-button-fg', undefined, colors.dark),
selectButtonPlaceholderFg: new CustomProp('theme-select-button-placeholder-fg', undefined,
colors.slate),
selectButtonDisabledFg: new CustomProp('theme-select-button-disabled-fg', undefined, 'grey'),
selectButtonBg: new CustomProp('theme-select-button-bg', undefined, 'white'),
selectButtonBorder: new CustomProp('theme-select-button-border', undefined, colors.darkGrey),
selectButtonBorderInvalid: new CustomProp('theme-select-button-border-invalid', undefined,
colors.error),
/* Menus */
menuText: new CustomProp('theme-menu-text', undefined, colors.slate),
menuLightText: new CustomProp('theme-menu-light-text', undefined, colors.slate),
menuBg: new CustomProp('theme-menu-bg', undefined, 'white'),
menuSubheaderFg: new CustomProp('theme-menu-subheader-fg', undefined, 'unset'),
menuBorder: new CustomProp('theme-menu-border', undefined, colors.mediumGreyOpaque),
menuShadow: new CustomProp('theme-menu-shadow', undefined, 'rgba(38, 38, 51, 0.6)'),
/* Menu Items */
menuItemFg: new CustomProp('theme-menu-item-fg', undefined, 'unset'),
menuItemSelectedFg: new CustomProp('theme-menu-item-selected-fg', undefined, colors.light),
menuItemSelectedBg: new CustomProp('theme-menu-item-selected-bg', undefined, vars.primaryBg),
menuItemDisabledFg: new CustomProp('theme-menu-item-disabled-fg', undefined, '#D9D9D9'),
menuItemIconFg: new CustomProp('theme-menu-item-icon-fg', undefined, colors.slate),
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 */
autocompleteMatchText: new CustomProp('theme-autocomplete-match-text', undefined,
colors.lightGreen),
autocompleteSelectedMatchText: new CustomProp('theme-autocomplete-selected-match-text',
undefined, colors.lighterGreen),
autocompleteChoiceSelectedBg: new CustomProp('theme-autocomplete-item-selected-bg', undefined,
colors.mediumGreyOpaque),
/* Search */
searchBorder: new CustomProp('theme-search-border', undefined, 'grey'),
searchPrevNextButtonFg: new CustomProp('theme-search-prev-next-button-fg', undefined,
colors.slate),
searchPrevNextButtonBg: new CustomProp('theme-search-prev-next-button-bg', undefined,
colors.mediumGrey),
/* Loaders */
loaderFg: new CustomProp('theme-loader-fg', undefined, colors.lightGreen),
loaderBg: new CustomProp('theme-loader-bg', undefined, colors.darkGrey),
/* Site Switcher */
siteSwitcherActiveFg: new CustomProp('theme-site-switcher-active-fg', undefined, colors.light),
siteSwitcherActiveBg: new CustomProp('theme-site-switcher-active-bg', undefined, colors.dark),
/* Doc Menu */
docMenuDocOptionsFg: new CustomProp('theme-doc-menu-doc-options-fg', undefined, colors.darkGrey),
docMenuDocOptionsHoverFg: new CustomProp('theme-doc-menu-doc-options-hover-fg', undefined,
colors.slate),
docMenuDocOptionsHoverBg: new CustomProp('theme-doc-menu-doc-options-hover-bg', undefined,
colors.darkGrey),
/* Shortcut Keys */
shortcutKeyFg: new CustomProp('theme-shortcut-key-fg', undefined, 'black'),
shortcutKeyPrimaryFg: new CustomProp('theme-shortcut-key-primary-fg', undefined,
colors.darkGreen),
shortcutKeySecondaryFg: new CustomProp('theme-shortcut-key-secondary-fg', undefined,
colors.slate),
shortcutKeyBg: new CustomProp('theme-shortcut-key-bg', undefined, 'white'),
shortcutKeyBorder: new CustomProp('theme-shortcut-key-border', undefined, colors.slate),
/* Breadcrumbs */
breadcrumbsTagFg: new CustomProp('theme-breadcrumbs-tag-fg', undefined, 'white'),
breadcrumbsTagBg: new CustomProp('theme-breadcrumbs-tag-bg', undefined, colors.slate),
breadcrumbsTagAlertBg: new CustomProp('theme-breadcrumbs-tag-alert-fg', undefined, colors.error),
/* Page Widget Picker */
widgetPickerPrimaryBg: new CustomProp('theme-widget-picker-primary-bg', undefined, 'white'),
widgetPickerSecondaryBg: new CustomProp('theme-widget-picker-secondary-bg', undefined,
colors.lightGrey),
widgetPickerItemFg: new CustomProp('theme-widget-picker-item-fg', undefined, colors.lightGrey),
widgetPickerItemSelectedBg: new CustomProp('theme-widget-picker-item-selected-bg', undefined,
colors.lightGrey),
widgetPickerItemDisabledBg: new CustomProp('theme-widget-picker-item-disabled-bg', undefined,
colors.lightGrey),
widgetPickerIcon: new CustomProp('theme-widget-picker-icon', undefined, colors.slate),
widgetPickerPrimaryIcon: new CustomProp('theme-widget-picker-primary-icon', undefined,
colors.lightGreen),
widgetPickerSummaryIcon: new CustomProp('theme-widget-picker-summary-icon', undefined,
colors.darkGreen),
widgetPickerBorder: new CustomProp('theme-widget-picker-border', undefined, colors.mediumGrey),
widgetPickerShadow: new CustomProp('theme-widget-picker-shadow', undefined,
'rgba(38,38,51,0.20)'),
/* Code View */
codeViewText: new CustomProp('theme-code-view-text', undefined, '#444'),
codeViewKeyword: new CustomProp('theme-code-view-keyword', undefined, '#444'),
codeViewComment: new CustomProp('theme-code-view-comment', undefined, '#888888'),
codeViewMeta: new CustomProp('theme-code-view-meta', undefined, '#1F7199'),
codeViewTitle: new CustomProp('theme-code-view-title', undefined, '#880000'),
codeViewParams: new CustomProp('theme-code-view-params', undefined, '#444'),
codeViewString: new CustomProp('theme-code-view-string', undefined, '#880000'),
codeViewNumber: new CustomProp('theme-code-view-number', undefined, '#880000'),
/* Importer */
importerTableInfoBorder: new CustomProp('theme-importer-table-info-border', undefined, colors.darkGrey),
importerPreviewBorder: new CustomProp('theme-importer-preview-border', undefined,
colors.darkGrey),
importerSkippedTableOverlay: new CustomProp('theme-importer-skipped-table-overlay', undefined,
colors.mediumGrey),
importerMatchIcon: new CustomProp('theme-importer-match-icon', undefined, colors.darkGrey),
/* Menu Toggles */
menuToggleFg: new CustomProp('theme-menu-toggle-fg', undefined, colors.slate),
menuToggleHoverFg: new CustomProp('theme-menu-toggle-hover-fg', undefined, colors.darkGreen),
menuToggleActiveFg: new CustomProp('theme-menu-toggle-active-fg', undefined, colors.darkerGreen),
menuToggleBg: new CustomProp('theme-menu-toggle-bg', undefined, 'white'),
menuToggleBorder: new CustomProp('theme-menu-toggle-border', undefined, colors.slate),
/* Button Groups */
buttonGroupFg: new CustomProp('theme-button-group-fg', undefined, colors.dark),
buttonGroupLightFg: new CustomProp('theme-button-group-light-fg', undefined, colors.slate),
buttonGroupBg: new CustomProp('theme-button-group-bg', undefined, 'unset'),
buttonGroupIcon: new CustomProp('theme-button-group-icon', undefined, colors.slate),
buttonGroupBorder: new CustomProp('theme-button-group-border', undefined, colors.darkGrey),
buttonGroupBorderHover: new CustomProp('theme-button-group-border-hover', undefined,
colors.hover),
buttonGroupSelectedFg: new CustomProp('theme-button-group-selected-fg', undefined, colors.light),
buttonGroupLightSelectedFg: new CustomProp('theme-button-group-light-selected-fg', undefined,
colors.lightGreen),
buttonGroupSelectedBg: new CustomProp('theme-button-group-selected-bg', undefined, colors.dark),
buttonGroupSelectedBorder: new CustomProp('theme-button-group-selected-border', undefined,
colors.dark),
/* Access Rules */
accessRulesTableHeaderFg: new CustomProp('theme-access-rules-table-header-fg', undefined,
colors.dark),
accessRulesTableHeaderBg: new CustomProp('theme-access-rules-table-header-bg', undefined,
colors.mediumGrey),
accessRulesTableBodyFg: new CustomProp('theme-access-rules-table-body-fg', undefined,
colors.dark),
accessRulesTableBorder: new CustomProp('theme-access-rules-table-border', undefined,
colors.slate),
/* Cells */
cellFg: new CustomProp('theme-cell-fg', undefined, 'unset'),
cellBg: new CustomProp('theme-cell-bg', undefined, '#FFFFFF00'),
cellZebraBg: new CustomProp('theme-cell-zebra-bg', undefined, '#F8F8F8'),
/* Formula Editor */
formulaEditorBg: new CustomProp('theme-formula-editor-bg', undefined, 'white'),
/* Charts */
chartFg: new CustomProp('theme-chart-fg', undefined, '#444'),
chartBg: new CustomProp('theme-chart-bg', undefined, '#fff'),
chartLegendBg: new CustomProp('theme-chart-legend-bg', undefined, '#FFFFFF80'),
chartXAxis: new CustomProp('theme-chart-x-axis', undefined, '#444'),
chartYAxis: new CustomProp('theme-chart-y-axis', undefined, '#444'),
};
const cssColors = values(colors).map(v => v.decl()).join('\n');
const cssVars = values(vars).map(v => v.decl()).join('\n');
const cssFontParams = `
@ -237,17 +759,107 @@ export function isScreenResizing(): Observable<boolean> {
return _isScreenResizingObs;
}
let _prefersDarkModeObs: Observable<boolean>|undefined;
/**
* Attaches the global css properties to the document's root to them available in the page.
* Returns a singleton observable for whether the user agent prefers dark mode.
*/
export function prefersDarkModeObs(): Observable<boolean> {
if (!_prefersDarkModeObs) {
const query = window.matchMedia('(prefers-color-scheme: dark)');
const obs = Observable.create<boolean>(null, query.matches);
query.addEventListener('change', event => obs.set(event.matches));
_prefersDarkModeObs = obs;
}
return _prefersDarkModeObs;
}
/**
* Attaches the global css properties to the document's root to make them available in the page.
*/
export function attachCssRootVars(productFlavor: ProductFlavor, varsOnly: boolean = false) {
dom.update(document.documentElement, varsOnly ? dom.cls(cssVarsOnly.className) : dom.cls(cssRootVars));
document.documentElement.classList.add(cssRoot.className);
document.body.classList.add(cssBody.className);
const theme = getTheme(productFlavor);
if (theme.bodyClassName) {
document.body.classList.add(theme.bodyClassName);
const customTheme = getTheme(productFlavor);
if (customTheme.bodyClassName) {
document.body.classList.add(customTheme.bodyClassName);
}
const interfaceStyle = urlState().state.get().params?.style || 'full';
document.body.classList.add(`interface-${interfaceStyle}`);
}
/**
* Attaches theme-related css properties to the theme style element.
*/
export function attachCssThemeVars({appearance, colors: themeColors}: Theme) {
// Prepare the custom properties needed for applying the theme.
const properties = Object.entries(themeColors)
.map(([name, value]) => `--grist-theme-${name}: ${value};`);
// Include properties for styling the scrollbar.
properties.push(...getCssScrollbarProperties(appearance));
// Include properties for picking an appropriate background image.
properties.push(...getCssThemeBackgroundProperties(appearance));
// Apply the properties to the theme style element.
getOrCreateStyleElement('grist-theme').textContent = `:root {
${properties.join('\n')}
}`;
// Make the browser aware of the color scheme.
document.documentElement.style.setProperty(`color-scheme`, appearance);
// Cache the appearance in local storage; this is currently used to apply a suitable
// background image that's shown while the application is loading.
localStorage.setItem('appearance', appearance);
}
/**
* Gets scrollbar-related css properties that are appropriate for the given `appearance`.
*
* Note: Browser support for customizing scrollbars is still a mixed bag; the bulk of customization
* is non-standard and unsupported by Firefox. If support matures, we could expose some of these in
* custom themes, but for now we'll just go with reasonable presets.
*/
function getCssScrollbarProperties(appearance: ThemeAppearance) {
return [
'--scroll-bar-fg: ' +
(appearance === 'dark' ? '#6B6B6B;' : '#A8A8A8;'),
'--scroll-bar-hover-fg: ' +
(appearance === 'dark' ? '#7B7B7B;' : '#8F8F8F;'),
'--scroll-bar-active-fg: ' +
(appearance === 'dark' ? '#8B8B8B;' : '#7C7C7C;'),
'--scroll-bar-bg: ' +
(appearance === 'dark' ? '#2B2B2B;' : '#F0F0F0;'),
];
}
/**
* Gets background-related css properties that are appropriate for the given `appearance`.
*
* Currently, this sets a property for showing a background image that's visible while a page
* is loading.
*/
function getCssThemeBackgroundProperties(appearance: ThemeAppearance) {
const value = appearance === 'dark'
? 'url("img/prismpattern.png")'
: 'url("img/gplaypattern.png")';
return [`--grist-theme-bg: ${value};`];
}
/**
* Gets or creates a style element in the head of the document with the given `id`.
*
* Useful for grouping CSS values such as theme custom properties without needing to
* pollute the document with in-line styles.
*/
function getOrCreateStyleElement(id: string) {
let style = document.head.querySelector(id);
if (style) { return style; }
style = document.createElement('style');
style.setAttribute('id', id);
document.head.append(style);
return style;
}

@ -1,4 +1,4 @@
import {testId} from 'app/client/ui2018/cssVars';
import {testId, theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
import {styled} from 'grainjs';
@ -6,6 +6,7 @@ import {styled} from 'grainjs';
// Drag icon for use in koForm draggableList.
export const cssDragger = styled((...args: any[]) => icon('DragDrop', testId('dragger'), ...args), `
--icon-color: ${theme.controlSecondaryFg};
visibility: hidden;
align-self: center;
flex-shrink: 0;

@ -9,7 +9,7 @@
*
* TODO: Consider merging this into grainjs's input widget.
*/
import { colors } from 'app/client/ui2018/cssVars';
import { theme } from 'app/client/ui2018/cssVars';
import { dom, DomArg, styled } from 'grainjs';
import { Observable } from 'grainjs';
import noop = require('lodash/noop');
@ -45,7 +45,7 @@ export const cssLabelText = styled(rawTextInput, `
export const cssTextInput = styled('input', `
outline: none;
height: 28px;
border: 1px solid ${colors.darkGrey};
border: 1px solid ${theme.inputBorder};
border-radius: 3px;
padding: 0 6px;
`);
@ -97,7 +97,7 @@ export function editableLabel(label: Observable<string>, options: EditableLabelO
/**
* Provides a text input element that pretty much behaves like the editableLabel only it shows as a
* regular input within a rigid static frame. It takes in an observable that is setf on Enter or loss
* regular input within a rigid static frame. It takes in an observable that is set on Enter or loss
* of focus. Escape cancels editing. Validation logic (if any) should happen in the save function,
* to reject a value simply throw an error, this will revert to the the saved one.
*/

@ -49,7 +49,7 @@
* `);
*/
import { colors } from 'app/client/ui2018/cssVars';
import { theme } from 'app/client/ui2018/cssVars';
import { dom, DomElementArg, styled } from 'grainjs';
import { IconName } from './IconList';
@ -65,7 +65,7 @@ const iconDiv = styled('div', `
-webkit-mask-size: contain;
width: 16px;
height: 16px;
background-color: var(--icon-color, black);
background-color: var(--icon-color, var(--grist-theme-text, black));
`);
export const cssIconBackground = styled(iconDiv, `
@ -85,7 +85,7 @@ export function icon(name: IconName, ...domArgs: DomElementArg[]): HTMLElement {
}
/**
* Container box for an slate-colored icon to serve as a button, with a grey background on hover.
* Container box for an icon to serve as a button..
*/
export const cssIconButton = styled('div', `
flex: none;
@ -95,9 +95,9 @@ export const cssIconButton = styled('div', `
border-radius: 3px;
line-height: 0px;
cursor: default;
--icon-color: ${colors.slate};
--icon-color: ${theme.controlSecondaryFg};
&:hover, &.weasel-popup-open {
background-color: ${colors.darkGrey};
--icon-color: ${colors.slate};
background-color: ${theme.controlSecondaryHoverBg};
--icon-color: ${theme.controlSecondaryFg};
}
`);

@ -1,19 +1,19 @@
import { sameDocumentUrlState, urlState } from 'app/client/models/gristUrlState';
import { colors } from 'app/client/ui2018/cssVars';
import { theme } from 'app/client/ui2018/cssVars';
import { CellValue } from 'app/plugin/GristData';
import { dom, IDomArgs, Observable, styled } from 'grainjs';
/**
* Styling for a simple green <A HREF> link.
* Styling for a simple <A HREF> link.
*/
export const cssLink = styled('a', `
color: ${colors.lightGreen};
--icon-color: ${colors.lightGreen};
color: ${theme.link};
--icon-color: ${theme.link};
text-decoration: none;
&:hover, &:focus {
color: ${colors.lightGreen};
--icon-color: ${colors.lightGreen};
color: ${theme.linkHover};
--icon-color: ${theme.linkHover};
text-decoration: underline;
}
`);

@ -1,4 +1,4 @@
import {colors} from 'app/client/ui2018/cssVars';
import {theme} from 'app/client/ui2018/cssVars';
import {DomArg, keyframes, styled} from 'grainjs';
const rotate360 = keyframes(`
@ -9,10 +9,10 @@ const rotate360 = keyframes(`
const flash = keyframes(`
0% {
background-color: ${colors.lightGreen};
background-color: ${theme.loaderFg};
}
50%, 100% {
background-color: ${colors.darkGrey};
background-color: ${theme.loaderBg};
}
`);
@ -25,8 +25,8 @@ export const loadingSpinner = styled('div', `
width: 32px;
height: 32px;
border-radius: 32px;
border: 4px solid ${colors.darkGrey};
border-top-color: ${colors.lightGreen};
border: 4px solid ${theme.loaderBg};
border-top-color: ${theme.loaderFg};
animation: ${rotate360} 1s ease-out infinite;
`);
@ -52,8 +52,8 @@ const cssLoadingDot = styled('div', `
border-radius: 50%;
width: var(--dot-size);
height: var(--dot-size);
background-color: ${colors.lightGreen};
color: ${colors.lightGreen};
background-color: ${theme.loaderFg};
color: ${theme.loaderFg};
animation: ${flash} 1s alternate infinite;
&-left {

@ -2,7 +2,7 @@ import { Command } from 'app/client/components/commands';
import { NeedUpgradeError, reportError } from 'app/client/models/errors';
import { textButton } from 'app/client/ui2018/buttons';
import { cssCheckboxSquare, cssLabel, cssLabelText } from 'app/client/ui2018/checkbox';
import { colors, testId, vars } from 'app/client/ui2018/cssVars';
import { testId, theme, vars } from 'app/client/ui2018/cssVars';
import { IconName } from 'app/client/ui2018/IconList';
import { icon } from 'app/client/ui2018/icons';
import { cssSelectBtn } from 'app/client/ui2018/select';
@ -60,11 +60,12 @@ export const cssMenuElem = styled('div', `
line-height: initial;
max-width: 400px;
padding: 8px 0px 16px 0px;
box-shadow: 0 2px 20px 0 rgba(38,38,51,0.6);
box-shadow: 0 2px 20px 0 ${theme.menuShadow};
min-width: 160px;
z-index: 999;
--weaseljs-selected-background-color: ${vars.primaryBg};
--weaseljs-selected-background-color: ${theme.menuItemSelectedBg};
--weaseljs-menu-item-padding: 8px 24px;
background-color: ${theme.menuBg};
@media print {
& {
@ -76,13 +77,16 @@ export const cssMenuElem = styled('div', `
const menuItemStyle = `
justify-content: flex-start;
align-items: center;
--icon-color: ${colors.lightGreen};
color: ${theme.menuItemFg};
--icon-color: ${theme.accentIcon};
.${weasel.cssMenuItem.className}-sel {
--icon-color: ${colors.light};
color: ${theme.menuItemSelectedFg};
--icon-color: ${theme.menuItemSelectedFg};
}
&.disabled {
cursor: default;
opacity: 0.2;
color: ${theme.menuItemDisabledFg};
--icon-color: ${theme.menuItemDisabledFg};
}
`;
@ -237,7 +241,9 @@ export function multiSelect<T>(selectedOptions: MutableObsArray<T>,
weasel.setPopupToCreateDom(elem, ctl => buildMultiSelectMenu(ctl), weasel.defaultMenuOptions);
},
dom.style('border', use => {
return options.error && use(options.error) ? '1px solid red' : `1px solid ${colors.darkGrey}`;
return options.error && use(options.error)
? `1px solid ${theme.selectButtonBorderInvalid}`
: `1px solid ${theme.selectButtonBorder}`;
}),
...domArgs
);
@ -394,6 +400,7 @@ export function selectOption(
}
export const menuSubHeader = styled('div', `
color: ${theme.menuSubheaderFg};
font-size: ${vars.xsmallFontSize};
text-transform: uppercase;
font-weight: ${vars.bigControlTextWeight};
@ -405,7 +412,7 @@ export const menuText = styled('div', `
display: flex;
align-items: center;
font-size: ${vars.smallFontSize};
color: ${colors.slate};
color: ${theme.menuText};
padding: 8px 24px 4px 24px;
max-width: 250px;
cursor: default;
@ -440,6 +447,7 @@ export function menuAnnotate(text: string, ...args: DomElementArg[]) {
}
export const menuDivider = styled(weasel.cssMenuDivider, `
background-color: ${theme.menuBorder};
margin: 8px 0;
`);
@ -464,8 +472,8 @@ const cssSelectBtnLink = styled('div', `
display: flex;
align-items: center;
font-size: ${vars.mediumFontSize};
color: ${colors.lightGreen};
--icon-color: ${colors.lightGreen};
color: ${theme.controlFg};
--icon-color: ${theme.controlFg};
width: initial;
height: initial;
line-height: inherit;
@ -480,8 +488,8 @@ const cssSelectBtnLink = styled('div', `
-moz-appearance: none;
&:hover, &:focus, &:active {
color: ${colors.darkGreen};
--icon-color: ${colors.darkGreen};
color: ${theme.controlHoverFg};
--icon-color: ${theme.controlHoverFg};
box-shadow: initial;
}
`);
@ -489,7 +497,7 @@ const cssSelectBtnLink = styled('div', `
const cssOptionIcon = styled(icon, `
height: 16px;
width: 16px;
background-color: ${colors.slate};
background-color: ${theme.menuItemIconFg};
margin: -3px 8px 0 2px;
`);
@ -504,7 +512,11 @@ export const cssOptionRowIcon = styled(cssOptionIcon, `
flex: none;
.${weasel.cssMenuItem.className}-sel & {
background-color: white;
background-color: ${theme.menuItemSelectedFg};
}
.${weasel.cssMenuItem.className}.disabled & {
background-color: ${theme.menuItemDisabledFg};
}
`);
@ -512,6 +524,19 @@ const cssOptionLabel = styled('div', `
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.${weasel.cssMenuItem.className} & {
color: ${theme.menuItemFg};
}
.${weasel.cssMenuItem.className}-sel & {
color: ${theme.menuItemSelectedFg};
background-color: ${theme.menuItemSelectedBg};
}
.${weasel.cssMenuItem.className}.disabled & {
color: ${theme.menuItemDisabledFg};
}
`);
const cssInlineCollapseIcon = styled(icon, `
@ -524,7 +549,7 @@ const cssCollapseIcon = styled(icon, `
right: 12px;
top: calc(50% - 8px);
pointer-events: none;
background-color: ${colors.dark};
background-color: ${theme.selectButtonFg};
`);
const cssInputButtonMenuElem = styled(cssMenuElem, `
@ -537,16 +562,20 @@ const cssMenuItemCmd = styled('div', `
const cssCmdKey = styled('span', `
margin-left: 16px;
color: ${colors.slate};
color: ${theme.menuItemIconFg};
margin-right: -12px;
.${weasel.cssMenuItem.className}-sel > & {
color: ${colors.lightGrey};
color: ${theme.menuItemIconSelectedFg};
}
.${weasel.cssMenuItem.className}.disabled > & {
color: ${theme.menuItemDisabledFg};
}
`);
const cssAnnotateMenuItem = styled('span', `
color: ${colors.lightGreen};
color: ${theme.accentText};
text-transform: uppercase;
font-size: 8px;
vertical-align: super;
@ -555,7 +584,7 @@ const cssAnnotateMenuItem = styled('span', `
font-weight: bold;
.${weasel.cssMenuItem.className}-sel > & {
color: white;
color: ${theme.menuItemIconSelectedFg};
}
`);
@ -563,9 +592,10 @@ const cssMultiSelectSummary = styled('div', `
flex: 1 1 0px;
overflow: hidden;
text-overflow: ellipsis;
color: ${theme.selectButtonFg};
&-placeholder {
color: ${colors.slate}
color: ${theme.selectButtonPlaceholderFg};
}
`);
@ -575,6 +605,7 @@ const cssMultiSelectMenu = styled(weasel.cssMenu, `
max-height: calc(max(300px, 95vh - 300px));
max-width: 400px;
padding-bottom: 0px;
background-color: ${theme.menuBg};
`);
const cssCheckboxLabel = styled(cssLabel, `
@ -583,7 +614,7 @@ const cssCheckboxLabel = styled(cssLabel, `
const cssCheckboxText = styled(cssLabelText, `
margin-right: 12px;
color: ${colors.dark};
color: ${theme.text};
white-space: pre;
`);

@ -3,7 +3,7 @@ import {reportError} from 'app/client/models/errors';
import {cssInput} from 'app/client/ui/cssInput';
import {prepareForTransition, TransitionWatcher} from 'app/client/ui/transitions';
import {bigBasicButton, bigPrimaryButton, cssButton} from 'app/client/ui2018/buttons';
import {colors, mediaSmall, testId, vars} from 'app/client/ui2018/cssVars';
import {mediaSmall, testId, theme, vars} from 'app/client/ui2018/cssVars';
import {loadingSpinner} from 'app/client/ui2018/loaders';
import {waitGrainObs} from 'app/common/gutil';
import {Computed, Disposable, dom, DomContents, DomElementArg, input, keyframes,
@ -474,12 +474,12 @@ export function cssModalWidth(style: ModalWidth) {
// the flex container, to ensure the full item can be scrolled in case of overflow.
// See https://stackoverflow.com/a/33455342/328565
const cssModalDialog = styled('div', `
background-color: white;
background-color: ${theme.modalBg};
min-width: 428px;
color: black;
color: ${theme.darkText};
margin: auto;
border-radius: 3px;
box-shadow: 0 2px 18px 0 rgba(31,37,50,0.31), 0 0 1px 0 rgba(76,86,103,0.24);
box-shadow: 0 2px 18px 0 ${theme.modalInnerShadow}, 0 0 1px 0 ${theme.modalOuterShadow};
padding: 40px 64px;
outline: none;
@ -506,13 +506,14 @@ const cssModalDialog = styled('div', `
export const cssModalTitle = styled('div', `
font-size: ${vars.xxxlargeFontSize};
font-weight: ${vars.headerControlTextWeight};
color: ${colors.dark};
color: ${theme.text};
margin: 0 0 16px 0;
line-height: 32px;
overflow-wrap: break-word;
`);
export const cssModalBody = styled('div', `
color: ${theme.text};
margin: 16px 0;
`);
@ -530,7 +531,7 @@ const cssFadeIn = keyframes(`
`);
const cssFadeOut = keyframes(`
from {background-color: ${colors.backdrop}}
from {background-color: ${theme.modalBackdrop}}
`);
const cssModalBacker = styled('div', `
@ -543,7 +544,7 @@ const cssModalBacker = styled('div', `
left: 0;
padding: 16px;
z-index: 999;
background-color: ${colors.backdrop};
background-color: ${theme.modalBackdrop};
overflow-y: auto;
animation-name: ${cssFadeIn};
animation-duration: 0.4s;

@ -1,7 +1,7 @@
import { isDesktop } from 'app/client/lib/browserInfo';
import { cssEditorInput } from "app/client/ui/HomeLeftPane";
import { itemHeader, itemHeaderWrapper, treeViewContainer } from "app/client/ui/TreeViewComponentCss";
import { colors } from "app/client/ui2018/cssVars";
import { theme } from "app/client/ui2018/cssVars";
import { icon } from "app/client/ui2018/icons";
import { menu, menuItem, menuText } from "app/client/ui2018/menus";
import { dom, domComputed, DomElementArg, makeTestId, observable, Observable, styled } from "grainjs";
@ -86,7 +86,7 @@ export function buildPageDom(name: Observable<string>, actions: PageActions, ...
dom.on('click', (ev) => isTargetSelected(ev.target as HTMLElement) && isRenaming.set(true)),
),
cssPageMenuTrigger(
cssPageIcon('Dots'),
cssPageMenuIcon('Dots'),
menu(pageMenu, {placement: 'bottom-start', parentSelectorToMark: '.' + itemHeader.className}),
dom.on('click', (ev) => { ev.stopPropagation(); ev.preventDefault(); }),
@ -104,7 +104,6 @@ export function buildPageDom(name: Observable<string>, actions: PageActions, ...
}
const cssPageItem = styled('a', `
--icon-color: ${colors.slate};
display: flex;
flex-direction: row;
height: 28px;
@ -122,9 +121,9 @@ const cssPageItem = styled('a', `
const cssPageInitial = styled('div', `
flex-shrink: 0;
color: white;
color: ${theme.pageInitialsFg};
border-radius: 3px;
background-color: ${colors.slate};
background-color: ${theme.pageInitialsBg};
width: 16px;
height: 16px;
text-align: center;
@ -187,20 +186,21 @@ const cssPageMenuTrigger = styled('div', `
}
}
.${itemHeaderWrapper.className}-not-dragging &:hover, &.weasel-popup-open {
background-color: ${colors.darkGrey};
background-color: ${theme.pageOptionsHoverBg};
}
.${itemHeaderWrapper.className}-not-dragging > .${itemHeader.className}.selected &:hover,
.${itemHeaderWrapper.className}-not-dragging > .${itemHeader.className}.selected &.weasel-popup-open {
background-color: ${colors.slate};
background-color: ${theme.pageOptionsSelectedHoverBg};
}
.${itemHeader.className}.weasel-popup-open, .${itemHeader.className}-renaming {
background-color: ${colors.mediumGrey};
background-color: ${theme.pageHoverBg};
}
`);
const cssPageIcon = styled(icon, `
const cssPageMenuIcon = styled(icon, `
background-color: ${theme.pageOptionsFg};
.${itemHeader.className}.selected & {
background-color: white;
background-color: ${theme.pageOptionsHoverFg};
}
`);

@ -8,7 +8,7 @@ import { SearchModel } from 'app/client/models/SearchModel';
import { hoverTooltip, IHoverTipOptions } from 'app/client/ui/tooltips';
import { cssHoverCircle, cssTopBarBtn } from 'app/client/ui/TopBarCss';
import { labeledSquareCheckbox } from 'app/client/ui2018/checkbox';
import { colors, mediaSmall, vars } from 'app/client/ui2018/cssVars';
import { mediaSmall, theme, vars } from 'app/client/ui2018/cssVars';
import { icon } from 'app/client/ui2018/icons';
import { dom, input, styled } from 'grainjs';
import { noTestId, TestId } from 'grainjs';
@ -32,7 +32,7 @@ const searchWrapper = styled('div', `
position: relative;
&-expand {
width: 100% !important;
border: 1px solid grey;
border: 1px solid ${theme.searchBorder};
}
@media ${mediaSmall} {
& {
@ -58,6 +58,8 @@ const expandedSearch = styled('div', `
`);
const searchInput = styled(input, `
background-color: ${theme.topHeaderBg};
color: ${theme.inputFg};
outline: none;
border: none;
margin: 0;
@ -70,6 +72,9 @@ const searchInput = styled(input, `
.${searchWrapper.className}-expand & {
width: 100%;
}
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
`);
const cssArrowBtn = styled('div', `
@ -80,8 +85,8 @@ const cssArrowBtn = styled('div', `
visibility: hidden;
width: 24px;
height: 24px;
background-color: ${colors.mediumGrey};
--icon-color: ${colors.slate};
background-color: ${theme.searchPrevNextButtonBg};
--icon-color: ${theme.searchPrevNextButtonFg};
border-radius: 3px;
text-align: center;
display: flex;
@ -94,31 +99,31 @@ const cssArrowBtn = styled('div', `
const cssCloseBtn = styled(icon, `
cursor: pointer;
background-color: ${colors.lightGreen};
background-color: ${theme.controlFg};
margin-left: 4px;
flex-shrink: 0;
`);
const cssLabel = styled('span', `
font-size: ${vars.smallFontSize};
color: ${colors.slate};
color: ${theme.lightText};
white-space: nowrap;
margin-right: 12px;
`);
const cssOptions = styled('div', `
background: ${theme.topHeaderBg};
position: absolute;
right: 0;
top: 46px;
top: 48px;
z-index: 1;
background: white;
padding: 2px 4px;
overflow: hidden;
white-space: nowrap;
`);
const cssShortcut = styled('span', `
color: ${colors.slate};
color: ${theme.lightText};
`);
const searchArrowBtnTooltipOptions: IHoverTipOptions = {

@ -1,4 +1,4 @@
import {colors, vars} from 'app/client/ui2018/cssVars';
import {theme, vars} from 'app/client/ui2018/cssVars';
import {styled} from 'grainjs';
// Import popweasel so that the styles we define here are included later in CSS, and take priority
@ -19,12 +19,12 @@ export const cssSelectBtn = styled('div', `
width: 100%;
height: 30px;
line-height: 16px;
background-color: white;
color: ${colors.dark};
--icon-color: ${colors.dark};
background-color: ${theme.selectButtonBg};
color: ${theme.selectButtonFg};
--icon-color: ${theme.selectButtonFg};
font-size: ${vars.mediumFontSize};
padding: 5px;
border: 1px solid ${colors.darkGrey};
border: 1px solid ${theme.selectButtonBorder};
border-radius: 3px;
cursor: pointer;
overflow: hidden;
@ -42,7 +42,8 @@ export const cssSelectBtn = styled('div', `
}
&.disabled {
color: grey;
--icon-color: ${theme.selectButtonDisabledFg};
color: ${theme.selectButtonDisabledFg};
cursor: pointer;
}
`);

@ -3,7 +3,7 @@ import {GristDoc} from 'app/client/components/GristDoc';
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
import {textButton} from 'app/client/ui2018/buttons';
import {ColorOption, colorSelect} from 'app/client/ui2018/ColorSelect';
import {colors, vars} from 'app/client/ui2018/cssVars';
import {theme, vars} from 'app/client/ui2018/cssVars';
import {ConditionalStyle} from 'app/client/widgets/ConditionalStyle';
import {Disposable, dom, DomContents, fromKo, MultiHolder, Observable, styled} from 'grainjs';
@ -67,6 +67,7 @@ const cssLine = styled('div', `
`);
const cssLabel = styled('div', `
color: ${theme.text};
text-transform: uppercase;
font-size: ${vars.xsmallFontSize};
`);
@ -83,6 +84,6 @@ const cssRow = styled('div', `
margin-top: 24px;
}
&-disabled {
color: ${colors.slate};
color: ${theme.disabledText};
}
`);

@ -2,7 +2,7 @@ import {createGroup} from 'app/client/components/commands';
import {ACIndexImpl, ACItem, ACResults, buildHighlightedDom, normalizeText, HighlightFunc} from 'app/client/lib/ACIndex';
import {IAutocompleteOptions} from 'app/client/lib/autocomplete';
import {IToken, TokenField, tokenFieldStyles} from 'app/client/lib/TokenField';
import {colors, testId} from 'app/client/ui2018/cssVars';
import {colors, testId, theme} from 'app/client/ui2018/cssVars';
import {menuCssClass} from 'app/client/ui2018/menus';
import {createMobileButtons, getButtonMargins} from 'app/client/widgets/EditorButtons';
import {EditorPlacement} from 'app/client/widgets/EditorPlacement';
@ -253,7 +253,7 @@ export class ChoiceListEditor extends NewBaseEditor {
}
const cssCellEditor = styled('div', `
background-color: white;
background-color: ${theme.cellEditorBg};
font-family: var(--grist-font-family-data);
font-size: var(--grist-medium-font-size);
`);
@ -332,7 +332,7 @@ const cssInputSizer = styled('div', `
// Set z-index to be higher than the 1000 set for .cell_editor.
export const cssChoiceList = styled('div', `
z-index: 1001;
box-shadow: 0 0px 8px 0 rgba(38,38,51,0.6);
box-shadow: 0 0px 8px 0 ${theme.menuShadow};
overflow-y: auto;
padding: 8px 0 0 0;
--weaseljs-menu-item-padding: 8px 16px;

@ -2,7 +2,7 @@ import {IToken, TokenField} from 'app/client/lib/TokenField';
import {cssBlockedCursor} from 'app/client/ui/RightPanelStyles';
import {basicButton, primaryButton} from 'app/client/ui2018/buttons';
import {colorButton, ColorOption} from 'app/client/ui2018/ColorSelect';
import {colors, testId} from 'app/client/ui2018/cssVars';
import {colors, testId, theme} from 'app/client/ui2018/cssVars';
import {editableLabel} from 'app/client/ui2018/editableLabel';
import {icon} from 'app/client/ui2018/icons';
import {ChoiceOptionsByName, IChoiceOptions} from 'app/client/widgets/ChoiceTextBox';
@ -422,17 +422,17 @@ const cssListBox = styled('div', `
line-height: 1.5;
padding-left: 4px;
padding-right: 4px;
border: 1px solid ${colors.hover};
border: 1px solid ${theme.choiceEntryBorderHover};
border-radius: 4px;
background-color: white;
background-color: ${theme.choiceEntryBg};
`);
const cssListBoxInactive = styled(cssListBox, `
cursor: pointer;
border: 1px solid ${colors.darkGrey};
border: 1px solid ${theme.choiceEntryBorder};
&:hover:not(&-disabled) {
border: 1px solid ${colors.hover};
border: 1px solid ${theme.choiceEntryBorderHover};
}
&-disabled {
opacity: 0.6;
@ -445,7 +445,7 @@ const cssListRow = styled('div', `
margin-bottom: 4px;
padding: 4px 8px;
color: ${colors.dark};
background-color: ${colors.mediumGrey};
background-color: ${colors.mediumGreyOpaque};
border-radius: 3px;
text-overflow: ellipsis;
`);
@ -510,6 +510,7 @@ const cssEditableLabel = styled('div', `
`);
const cssTokenInput = styled('input', `
background-color: ${theme.choiceEntryBg};
padding-top: 4px;
padding-bottom: 4px;
overflow: hidden;

@ -1,8 +1,8 @@
import {dom, DomContents, DomElementArg, styled} from "grainjs";
import {colors, vars} from "app/client/ui2018/cssVars";
import {Style} from 'app/client/models/Styles';
import {colors, theme, vars} from 'app/client/ui2018/cssVars';
import {dom, DomContents, DomElementArg, styled} from 'grainjs';
export const DEFAULT_FILL_COLOR = colors.mediumGreyOpaque.value;
export const DEFAULT_FILL_COLOR = colors.mediumGreyOpaque.value!;
export const DEFAULT_TEXT_COLOR = '#000000';
export interface IChoiceTokenOptions extends Style {
@ -70,8 +70,7 @@ export const cssChoiceACItem = styled('li', `
cursor: pointer;
&.selected {
background-color: ${colors.mediumGreyOpaque};
color: ${colors.dark};
background-color: ${theme.autocompleteChoiceSelectedBg};
}
&-with-new {
scroll-margin-bottom: ${ADD_NEW_HEIGHT};
@ -79,15 +78,11 @@ export const cssChoiceACItem = styled('li', `
&-new {
display: flex;
align-items: center;
color: ${colors.slate};
position: sticky;
bottom: 0px;
height: ${ADD_NEW_HEIGHT};
background-color: white;
border-top: 1px solid ${colors.mediumGreyOpaque};
background-color: ${theme.menuBg};
border-top: 1px solid ${theme.menuBorder};
scroll-margin-bottom: initial;
}
&-new.selected {
color: ${colors.lightGrey};
}
`);

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save