(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
This commit is contained in:
George Gevoian
2022-09-05 18:51:57 -07:00
parent d7b3fb972c
commit ec157dc469
122 changed files with 3616 additions and 1075 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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