mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Improve dark mode
Summary: Enhances dark mode support for the formula editor, and adds support to the color select popup. Also fixes some bugs with dark mode. Test Plan: Tested manually. Reviewers: jarek Reviewed By: jarek Differential Revision: https://phab.getgrist.com/D3847
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
import {setupAceEditorCompletions} from 'app/client/components/AceEditorCompletions';
|
||||
import {colors} from 'app/client/ui2018/cssVars';
|
||||
import {theme} from 'app/client/ui2018/cssVars';
|
||||
import {Theme} from 'app/common/ThemePrefs';
|
||||
import {getGristConfig} from 'app/common/urlUtils';
|
||||
import * as ace from 'brace';
|
||||
import {dom, DomArg, Observable, styled} from 'grainjs';
|
||||
import {Computed, dom, DomArg, Listener, Observable, styled} from 'grainjs';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
export interface ACLFormulaOptions {
|
||||
gristTheme: Computed<Theme>;
|
||||
initialValue: string;
|
||||
readOnly: boolean;
|
||||
placeholder: DomArg;
|
||||
@@ -19,7 +22,19 @@ export function aclFormulaEditor(options: ACLFormulaOptions) {
|
||||
const editor: ace.Editor = ace.edit(editorElem);
|
||||
|
||||
// Set various editor options.
|
||||
editor.setTheme('ace/theme/chrome');
|
||||
function setAceTheme(gristTheme: Theme) {
|
||||
const {enableCustomCss} = getGristConfig();
|
||||
const gristAppearance = gristTheme.appearance;
|
||||
const aceTheme = gristAppearance === 'dark' && !enableCustomCss ? 'dracula' : 'chrome';
|
||||
editor.setTheme(`ace/theme/${aceTheme}`);
|
||||
}
|
||||
setAceTheme(options.gristTheme.get());
|
||||
let themeListener: Listener | undefined;
|
||||
if (!getGristConfig().enableCustomCss) {
|
||||
themeListener = options.gristTheme.addListener((gristTheme) => {
|
||||
setAceTheme(gristTheme);
|
||||
});
|
||||
}
|
||||
// ACE editor resizes automatically when maxLines is set.
|
||||
editor.setOptions({enableLiveAutocompletion: true, maxLines: 10});
|
||||
editor.renderer.setShowGutter(false); // Default line numbers to hidden
|
||||
@@ -80,6 +95,7 @@ export function aclFormulaEditor(options: ACLFormulaOptions) {
|
||||
}
|
||||
|
||||
return cssConditionInputAce(
|
||||
dom.autoDispose(themeListener ?? null),
|
||||
cssConditionInputAce.cls('-disabled', options.readOnly),
|
||||
// ACE editor calls preventDefault on clicks into the scrollbar area, which prevents focus
|
||||
// being set when the click happens to be into there. To ensure we can focus on such clicks
|
||||
@@ -100,22 +116,25 @@ const cssConditionInputAce = styled('div', `
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid ${colors.darkGrey};
|
||||
border: 1px solid ${theme.accessRulesFormulaEditorBorderHover};
|
||||
}
|
||||
&:not(&-disabled):focus-within {
|
||||
box-shadow: inset 0 0 0 1px ${colors.cursor};
|
||||
border-color: ${colors.cursor};
|
||||
box-shadow: inset 0 0 0 1px ${theme.accessRulesFormulaEditorFocus};
|
||||
border-color: ${theme.accessRulesFormulaEditorFocus};
|
||||
}
|
||||
&:not(:focus-within) .ace_scroller, &-disabled .ace_scroller {
|
||||
cursor: unset;
|
||||
}
|
||||
&-disabled, &-disabled:hover {
|
||||
background-color: ${colors.mediumGreyOpaque};
|
||||
background-color: ${theme.accessRulesFormulaEditorBgDisabled};
|
||||
box-shadow: unset;
|
||||
border-color: transparent;
|
||||
}
|
||||
&-disabled .ace-chrome {
|
||||
background-color: ${colors.mediumGreyOpaque};
|
||||
& .ace-chrome, & .ace-dracula {
|
||||
background-color: ${theme.accessRulesFormulaEditorBg};
|
||||
}
|
||||
&-disabled .ace-chrome, &-disabled .ace-dracula {
|
||||
background-color: ${theme.accessRulesFormulaEditorBgDisabled};
|
||||
}
|
||||
& .ace_marker-layer, & .ace_cursor-layer {
|
||||
display: none;
|
||||
|
||||
@@ -123,9 +123,9 @@ export class AccessRules extends Disposable {
|
||||
// Map of tableId to basic metadata for all tables in the document.
|
||||
private _aclResources = new Map<string, AclTableDescription>();
|
||||
|
||||
private _aclUsersPopup = ACLUsersPopup.create(this, this._gristDoc.docPageModel);
|
||||
private _aclUsersPopup = ACLUsersPopup.create(this, this.gristDoc.docPageModel);
|
||||
|
||||
constructor(private _gristDoc: GristDoc) {
|
||||
constructor(public gristDoc: GristDoc) {
|
||||
super();
|
||||
this._ruleStatus = Computed.create(this, (use) => {
|
||||
const defRuleSet = use(this._docDefaultRuleSet);
|
||||
@@ -175,10 +175,10 @@ export class AccessRules extends Disposable {
|
||||
// changes). Instead, react deliberately if rules change. Note that table/column renames would
|
||||
// trigger changes to rules, so we don't need to listen for those separately.
|
||||
for (const tableId of ['_grist_ACLResources', '_grist_ACLRules']) {
|
||||
const tableData = this._gristDoc.docData.getTable(tableId)!;
|
||||
const tableData = this.gristDoc.docData.getTable(tableId)!;
|
||||
this.autoDispose(tableData.tableActionEmitter.addListener(this._onChange, this));
|
||||
}
|
||||
this.autoDispose(this._gristDoc.docPageModel.currentDoc.addListener(this._updateDocAccessData, this));
|
||||
this.autoDispose(this.gristDoc.docPageModel.currentDoc.addListener(this._updateDocAccessData, this));
|
||||
|
||||
this.update().catch((e) => this._errorMessage.set(e.message));
|
||||
}
|
||||
@@ -202,9 +202,9 @@ export class AccessRules extends Disposable {
|
||||
const rules = this._ruleCollection;
|
||||
|
||||
const [ , , aclResources] = await Promise.all([
|
||||
rules.update(this._gristDoc.docData, {log: console, pullOutSchemaEdit: true}),
|
||||
rules.update(this.gristDoc.docData, {log: console, pullOutSchemaEdit: true}),
|
||||
this._updateDocAccessData(),
|
||||
this._gristDoc.docComm.getAclResources(),
|
||||
this.gristDoc.docComm.getAclResources(),
|
||||
]);
|
||||
this._aclResources = new Map(Object.entries(aclResources.tables));
|
||||
this._ruleProblems.set(aclResources.problems);
|
||||
@@ -244,7 +244,7 @@ export class AccessRules extends Disposable {
|
||||
// Note that if anything has changed, we apply changes relative to the current state of the
|
||||
// ACL tables (they may have changed by other users). So our changes will win.
|
||||
|
||||
const docData = this._gristDoc.docData;
|
||||
const docData = this.gristDoc.docData;
|
||||
const resourcesTable = docData.getMetaTable('_grist_ACLResources');
|
||||
const rulesTable = docData.getMetaTable('_grist_ACLRules');
|
||||
|
||||
@@ -346,7 +346,7 @@ export class AccessRules extends Disposable {
|
||||
|
||||
public buildDom() {
|
||||
return cssOuter(
|
||||
dom('div', this._gristDoc.behavioralPromptsManager.attachTip('accessRules', {
|
||||
dom('div', this.gristDoc.behavioralPromptsManager.attachTip('accessRules', {
|
||||
hideArrow: true,
|
||||
})),
|
||||
cssAddTableRow(
|
||||
@@ -485,7 +485,7 @@ export class AccessRules extends Disposable {
|
||||
|
||||
public async checkAclFormula(text: string): Promise<FormulaProperties> {
|
||||
if (text) {
|
||||
return this._gristDoc.docComm.checkAclFormula(text);
|
||||
return this.gristDoc.docComm.checkAclFormula(text);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -1433,6 +1433,7 @@ class ObsUserAttributeRule extends Disposable {
|
||||
cssColumnGroup(
|
||||
cssCell1(
|
||||
aclFormulaEditor({
|
||||
gristTheme: this._accessRules.gristDoc.currentTheme,
|
||||
initialValue: this._charId.get(),
|
||||
readOnly: false,
|
||||
setValue: (text) => this._setUserAttr(text),
|
||||
@@ -1655,6 +1656,7 @@ class ObsRulePart extends Disposable {
|
||||
cssCell2(
|
||||
wide ? cssCell4.cls('') : null,
|
||||
aclFormulaEditor({
|
||||
gristTheme: this._ruleSet.accessRules.gristDoc.currentTheme,
|
||||
initialValue: this._aclFormula.get(),
|
||||
readOnly: this.isBuiltIn(),
|
||||
setValue: (value) => this._setAclFormula(value),
|
||||
|
||||
Reference in New Issue
Block a user