(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

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