Header colored (#581)

This commit is contained in:
CamilleLegeron
2023-08-07 20:01:35 +02:00
committed by GitHub
parent 7c114bf600
commit 02841bd15c
16 changed files with 408 additions and 39 deletions

View File

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

View File

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

View File

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