Skip to content

Commit

Permalink
✨ (admin) allow timelineMin/MaxTime to be overwritten
Browse files Browse the repository at this point in the history
  • Loading branch information
sophiamersmann committed Sep 19, 2024
1 parent cea9233 commit 3dc6b58
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 150 deletions.
188 changes: 113 additions & 75 deletions adminSiteClient/EditorCustomizeTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ColorSchemeName,
FacetAxisDomain,
FacetStrategy,
GrapherInterface,
} from "@ourworldindata/types"
import { Grapher } from "@ourworldindata/grapher"
import {
Expand All @@ -17,6 +18,7 @@ import {
TextField,
Button,
RadioGroup,
BindAutoFloatExt,
} from "./Forms.js"
import {
debounce,
Expand All @@ -39,6 +41,91 @@ import Select from "react-select"
import { AbstractChartEditor } from "./AbstractChartEditor.js"
import { ErrorMessages } from "./ChartEditorTypes.js"

@observer
class TimeField<
T extends { [field: string]: any },
K extends Extract<keyof T, string>,
> extends React.Component<{
editor: AbstractChartEditor
field: K
store: T
label: string
defaultValue: number
defaultTextValue: TimeBoundValue
}> {
private setValue(value: number) {
this.props.store[this.props.field] = value as any
}

@computed get currentValue(): number | undefined {
return this.props.store[this.props.field]
}

@action.bound onChange(value: number | undefined) {
this.setValue(value ?? this.props.defaultValue)
}

@action.bound onBlur() {
if (this.currentValue === undefined) {
this.setValue(this.props.defaultValue)
}
}

render() {
const { editor, label, defaultTextValue, defaultValue } = this.props

const field = this.props.field as keyof GrapherInterface

const inheritedValue = editor.activeParentConfig?.[field] as number
const autoValue =
inheritedValue === defaultTextValue
? defaultValue
: inheritedValue ?? defaultValue

const input = editor.couldPropertyBeInherited(field) ? (
<BindAutoFloatExt
label={label}
readFn={(store) => store[field]}
writeFn={(store, newVal) =>
(store[this.props.field] = newVal as any)
}
auto={autoValue}
isAuto={editor.isPropertyInherited(field)}
store={this.props.store}
onBlur={this.onBlur}
tooltipText={{
auto: "Linked to parent value. Unlink by editing",
manual: "Parent value overridden. Click to reset",
}}
/>
) : (
<NumberField
label={label}
value={this.props.store[field]}
onValue={debounce(this.onChange)}
allowNegative
/>
)

const isButtonDisabled = this.currentValue === defaultValue

return (
<div className="InputWithActionButton">
{input}
<button
className="btn btn-link ActionButton"
onClick={action(() => this.setValue(defaultValue))}
disabled={isButtonDisabled}
>
{isButtonDisabled
? "Bound to data. Edit to unbind"
: "Bind to data"}
</button>
</div>
)
}
}

@observer
export class ColorSchemeSelector extends React.Component<{
grapher: Grapher
Expand Down Expand Up @@ -307,54 +394,6 @@ class TimelineSection<
return this.props.editor.grapher
}

@computed get activeParentConfig() {
return this.props.editor.activeParentConfig
}

@computed get minTime() {
return this.grapher.minTime
}
@computed get maxTime() {
return this.grapher.maxTime
}

@computed get timelineMinTime() {
return this.grapher.timelineMinTime
}
@computed get timelineMaxTime() {
return this.grapher.timelineMaxTime
}

@action.bound onMinTime(value: number | undefined) {
this.grapher.minTime = value ?? TimeBoundValue.negativeInfinity
}

@action.bound onMaxTime(value: number | undefined) {
this.grapher.maxTime = value ?? TimeBoundValue.positiveInfinity
}

@action.bound onTimelineMinTime(value: number | undefined) {
this.grapher.timelineMinTime = value
}

@action.bound onBlurTimelineMinTime() {
if (this.grapher.timelineMinTime === undefined) {
this.grapher.timelineMinTime =
this.activeParentConfig?.timelineMinTime
}
}

@action.bound onTimelineMaxTime(value: number | undefined) {
this.grapher.timelineMaxTime = value
}

@action.bound onBlurTimelineMaxTime() {
if (this.grapher.timelineMaxTime === undefined) {
this.grapher.timelineMaxTime =
this.activeParentConfig?.timelineMaxTime
}
}

@action.bound onToggleHideTimeline(value: boolean) {
this.grapher.hideTimeline = value || undefined
}
Expand All @@ -364,54 +403,53 @@ class TimelineSection<
}

render() {
const { features } = this.props.editor
const { editor } = this.props
const { features } = editor
const { grapher } = this

return (
<Section name="Timeline selection">
<FieldsRow>
{features.timeDomain && (
<NumberField
<TimeField
editor={editor}
store={grapher}
field="minTime"
label="Selection start"
value={this.minTime}
onValue={debounce(this.onMinTime)}
allowNegative
defaultTextValue={TimeBoundValue.negativeInfinity}
defaultValue={-Infinity}
/>
)}
<NumberField
<TimeField
editor={editor}
store={grapher}
field="maxTime"
label={
features.timeDomain
? "Selection end"
: "Selected year"
}
value={this.maxTime}
onValue={debounce(this.onMaxTime)}
allowNegative
defaultValue={Infinity}
defaultTextValue={TimeBoundValue.positiveInfinity}
/>
</FieldsRow>
{features.timelineRange && (
<FieldsRow>
<NumberField
<TimeField
editor={editor}
store={this.props.editor.grapher}
field="timelineMinTime"
label="Timeline min"
value={this.timelineMinTime}
// invoke on the leading edge to avoid interference with onBlur
onValue={debounce(this.onTimelineMinTime, 0, {
leading: true,
trailing: false,
})}
onBlur={this.onBlurTimelineMinTime}
allowNegative
defaultValue={-Infinity}
defaultTextValue={TimeBoundValue.negativeInfinity}
/>
<NumberField
<TimeField
editor={editor}
store={grapher}
field="timelineMaxTime"
label="Timeline max"
value={this.timelineMaxTime}
// invoke on the leading edge to avoid interference with onBlur
onValue={debounce(this.onTimelineMaxTime, 0, {
leading: true,
trailing: false,
})}
onBlur={this.onBlurTimelineMaxTime}
allowNegative
defaultValue={Infinity}
defaultTextValue={TimeBoundValue.positiveInfinity}
/>
</FieldsRow>
)}
Expand Down
26 changes: 12 additions & 14 deletions adminSiteClient/EditorTextTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,9 @@ export class EditorTextTab<
<Section name="Header">
<BindAutoStringExt
label="Title"
readFn={({ grapher }) => grapher.displayTitle}
writeFn={({ grapher }, newVal) =>
(grapher.title = newVal)
}
readAutoFn={({ editor }) =>
readFn={(grapher) => grapher.displayTitle}
writeFn={(grapher, newVal) => (grapher.title = newVal)}
auto={
editor.couldPropertyBeInherited("title")
? editor.activeParentConfig!.title
: undefined
Expand All @@ -106,7 +104,7 @@ export class EditorTextTab<
editor.isPropertyInherited("title") ||
grapher.title === undefined
}
store={{ grapher, editor }}
store={grapher}
softCharacterLimit={100}
/>
{features.showEntityAnnotationInTitleToggle && (
Expand Down Expand Up @@ -156,11 +154,11 @@ export class EditorTextTab<
/>
<BindAutoStringExt
label="Subtitle"
readFn={({ grapher }) => grapher.currentSubtitle}
writeFn={({ grapher }, newVal) =>
readFn={(grapher) => grapher.currentSubtitle}
writeFn={(grapher, newVal) =>
(grapher.subtitle = newVal)
}
readAutoFn={({ editor }) =>
auto={
editor.couldPropertyBeInherited("subtitle")
? editor.activeParentConfig!.subtitle
: undefined
Expand All @@ -169,7 +167,7 @@ export class EditorTextTab<
editor.isPropertyInherited("subtitle") ||
grapher.subtitle === undefined
}
store={{ grapher, editor }}
store={grapher}
placeholder="Briefly describe the context of the data. It's best to avoid duplicating any information which can be easily inferred from other visual elements of the chart."
textarea
softCharacterLimit={280}
Expand All @@ -192,11 +190,11 @@ export class EditorTextTab<
<Section name="Footer">
<BindAutoStringExt
label="Source"
readFn={({ grapher }) => grapher.sourcesLine}
writeFn={({ grapher }, newVal) =>
readFn={(grapher) => grapher.sourcesLine}
writeFn={(grapher, newVal) =>
(grapher.sourceDesc = newVal)
}
readAutoFn={({ editor }) =>
auto={
editor.couldPropertyBeInherited("sourceDesc")
? editor.activeParentConfig!.sourceDesc
: undefined
Expand All @@ -205,7 +203,7 @@ export class EditorTextTab<
editor.isPropertyInherited("sourceDesc") ||
grapher.sourceDesc === undefined
}
store={{ grapher, editor }}
store={grapher}
helpText="Short comma-separated list of source names"
softCharacterLimit={60}
/>
Expand Down
Loading

0 comments on commit 3dc6b58

Please sign in to comment.