mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
Header colored (#581)
This commit is contained in:
@@ -7,6 +7,15 @@ export interface Style {
|
||||
fontStrikethrough?: boolean|undefined;
|
||||
}
|
||||
|
||||
export interface HeaderStyle {
|
||||
headerTextColor?: string | undefined; // this can be string, undefined or an absent key.
|
||||
headerFillColor?: string | undefined;
|
||||
headerFontBold?: boolean | undefined;
|
||||
headerFontUnderline?: boolean | undefined;
|
||||
headerFontItalic?: boolean | undefined;
|
||||
headerFontStrikethrough?: boolean | undefined;
|
||||
}
|
||||
|
||||
export class CombinedStyle implements Style {
|
||||
public readonly textColor?: string;
|
||||
public readonly fillColor?: string;
|
||||
|
||||
@@ -17,6 +17,8 @@ export class ViewFieldConfig {
|
||||
public options: CommonOptions;
|
||||
/** Style options for a field or multiple fields */
|
||||
public style: ko.Computed<StyleOptions>;
|
||||
/** Header style options for a field or multiple fields */
|
||||
public headerStyle: ko.Computed<StyleOptions>;
|
||||
|
||||
// Rest of the options mimic the same options from ViewFieldRec.
|
||||
public wrap: modelUtil.KoSaveableObservable<boolean|undefined>;
|
||||
@@ -255,6 +257,68 @@ export class ViewFieldConfig {
|
||||
result.revert = () => { zip(fields, state).forEach(([f, s]) => f!.style(s!)); };
|
||||
return result;
|
||||
});
|
||||
|
||||
this.headerStyle = ko.pureComputed(() => {
|
||||
const fields = this.fields();
|
||||
const multiSelect = fields.length > 1;
|
||||
const savableOptions = modelUtil.savingComputed({
|
||||
read: () => {
|
||||
// For one column, just proxy this to the field.
|
||||
if (!multiSelect) {
|
||||
return this._field.widgetOptionsJson();
|
||||
}
|
||||
// Assemble final json object.
|
||||
const result: any = {};
|
||||
// First get all widgetOption jsons from all columns/fields.
|
||||
const optionList = fields.map(f => f.widgetOptionsJson());
|
||||
// And fill only those that are common
|
||||
for(const key of ['headerTextColor', 'headerFillColor', 'headerFontBold',
|
||||
'headerFontItalic', 'headerFontUnderline', 'headerFontStrikethrough']) {
|
||||
// Setting null means that this options is there, but has no value.
|
||||
result[key] = null;
|
||||
// If all columns have the same value, use it.
|
||||
if (allSame(optionList.map(v => v[key]))) {
|
||||
result[key] = optionList[0][key] ?? null;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
write: (setter, value) => {
|
||||
if (!multiSelect) {
|
||||
return setter(this._field.widgetOptionsJson, value);
|
||||
}
|
||||
// When the creator panel is saving widgetOptions, it will pass
|
||||
// our virtual widgetObject, which has nulls for mixed values.
|
||||
// If this option wasn't changed (set), we don't want to save it.
|
||||
value = {...value};
|
||||
for(const key of Object.keys(value)) {
|
||||
if (value[key] === null) {
|
||||
delete value[key];
|
||||
}
|
||||
}
|
||||
// Now update all options, for all fields, by amending the options
|
||||
// object from the field/column.
|
||||
for(const item of fields) {
|
||||
const previous = item.widgetOptionsJson.peek();
|
||||
setter(item.widgetOptionsJson, {
|
||||
...previous,
|
||||
...value,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// Style picker needs to be able revert to previous value, if user cancels.
|
||||
const state = fields.map(f => f.headerStyle.peek());
|
||||
// We need some additional information about each property.
|
||||
const result: StyleOptions = extendObservable(modelUtil.objObservable(savableOptions), {
|
||||
// Property has mixed value, if not all options are the same.
|
||||
mixed: prop => ko.pureComputed(() => !allSame(fields.map(f => f.widgetOptionsJson.prop(prop)()))),
|
||||
// Property has empty value, if all options are empty (are null, undefined, empty Array or empty Object).
|
||||
empty: prop => ko.pureComputed(() => allEmpty(fields.map(f => f.widgetOptionsJson.prop(prop)()))),
|
||||
});
|
||||
result.revert = () => { zip(fields, state).forEach(([f, s]) => f!.headerStyle(s!)); };
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
// Helper for Choice/ChoiceList columns, that saves widget options and renames values in a document
|
||||
|
||||
@@ -2,7 +2,7 @@ import {ColumnRec, DocModel, IRowModel, refListRecords, refRecord, ViewSectionRe
|
||||
import {formatterForRec} from 'app/client/models/entities/ColumnRec';
|
||||
import * as modelUtil from 'app/client/models/modelUtil';
|
||||
import {removeRule, RuleOwner} from 'app/client/models/RuleOwner';
|
||||
import {Style} from 'app/client/models/Styles';
|
||||
import { HeaderStyle, Style } from 'app/client/models/Styles';
|
||||
import {ViewFieldConfig} from 'app/client/models/ViewFieldConfig';
|
||||
import * as UserType from 'app/client/widgets/UserType';
|
||||
import {DocumentSettings} from 'app/common/DocumentSettings';
|
||||
@@ -76,8 +76,15 @@ export interface ViewFieldRec extends IRowModel<"_grist_Views_section_field">, R
|
||||
fontUnderline: modelUtil.KoSaveableObservable<boolean|undefined>;
|
||||
fontItalic: modelUtil.KoSaveableObservable<boolean|undefined>;
|
||||
fontStrikethrough: modelUtil.KoSaveableObservable<boolean|undefined>;
|
||||
// Helper computed to change style of a cell without saving it.
|
||||
headerTextColor: modelUtil.KoSaveableObservable<string|undefined>;
|
||||
headerFillColor: modelUtil.KoSaveableObservable<string|undefined>;
|
||||
headerFontBold: modelUtil.KoSaveableObservable<boolean|undefined>;
|
||||
headerFontUnderline: modelUtil.KoSaveableObservable<boolean|undefined>;
|
||||
headerFontItalic: modelUtil.KoSaveableObservable<boolean|undefined>;
|
||||
headerFontStrikethrough: modelUtil.KoSaveableObservable<boolean|undefined>;
|
||||
// Helper computed to change style of a cell and headerStyle without saving it.
|
||||
style: ko.PureComputed<Style>;
|
||||
headerStyle: ko.PureComputed<HeaderStyle>;
|
||||
|
||||
config: ViewFieldConfig;
|
||||
|
||||
@@ -236,6 +243,12 @@ export function createViewFieldRec(this: ViewFieldRec, docModel: DocModel): void
|
||||
this.fontUnderline = this.widgetOptionsJson.prop('fontUnderline');
|
||||
this.fontItalic = this.widgetOptionsJson.prop('fontItalic');
|
||||
this.fontStrikethrough = this.widgetOptionsJson.prop('fontStrikethrough');
|
||||
this.headerTextColor = this.widgetOptionsJson.prop('headerTextColor');
|
||||
this.headerFillColor = this.widgetOptionsJson.prop('headerFillColor');
|
||||
this.headerFontBold = this.widgetOptionsJson.prop('headerFontBold');
|
||||
this.headerFontUnderline = this.widgetOptionsJson.prop('headerFontUnderline');
|
||||
this.headerFontItalic = this.widgetOptionsJson.prop('headerFontItalic');
|
||||
this.headerFontStrikethrough = this.widgetOptionsJson.prop('headerFontStrikethrough');
|
||||
|
||||
this.documentSettings = ko.pureComputed(() => docModel.docInfoRow.documentSettingsJson());
|
||||
this.style = ko.pureComputed({
|
||||
@@ -251,6 +264,19 @@ export function createViewFieldRec(this: ViewFieldRec, docModel: DocModel): void
|
||||
this.widgetOptionsJson.update(style);
|
||||
},
|
||||
});
|
||||
this.headerStyle = ko.pureComputed({
|
||||
read: () => ({
|
||||
headerTextColor: this.headerTextColor(),
|
||||
headerFillColor: this.headerFillColor(),
|
||||
headerFontBold: this.headerFontBold(),
|
||||
headerFontUnderline: this.headerFontUnderline(),
|
||||
headerFontItalic: this.headerFontItalic(),
|
||||
headerFontStrikethrough: this.headerFontStrikethrough(),
|
||||
}) as HeaderStyle,
|
||||
write: (headerStyle: HeaderStyle) => {
|
||||
this.widgetOptionsJson.update(headerStyle);
|
||||
},
|
||||
});
|
||||
|
||||
this.tableId = ko.pureComputed(() => this.column().table().tableId());
|
||||
this.rulesList = ko.pureComputed(() => this._fieldOrColumn().rules());
|
||||
|
||||
Reference in New Issue
Block a user