Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

Feature/timeline #136

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions block-languages/benenson-blocks.pot
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,14 @@ msgstr ""

#: src/scripts/blocks/call-to-action/DisplayComponent.js:74
#: src/scripts/blocks/slider/DisplayComponent.js:313
#: src/scripts/blocks/timeline/DisplayComponent.js:180
msgid "(Heading)"
msgstr ""

#: src/scripts/blocks/call-to-action/DisplayComponent.js:83
#: src/scripts/blocks/image/BlockEdit.js:286
#: src/scripts/blocks/slider/DisplayComponent.js:335
#: src/scripts/blocks/timeline/DisplayComponent.js:202
msgid "(Content)"
msgstr ""

Expand Down Expand Up @@ -615,6 +617,7 @@ msgid "Only has an effect on images smaller than their container"
msgstr ""

#: src/scripts/blocks/image/BlockEdit.js:280
#: src/scripts/blocks/timeline/DisplayComponent.js:192
msgid "(Title)"
msgstr ""

Expand Down Expand Up @@ -1118,6 +1121,7 @@ msgid "(Sub-Heading)"
msgstr ""

#: src/scripts/blocks/slider/DisplayComponent.js:379
#: src/scripts/blocks/timeline/DisplayComponent.js:234
msgid "(No Title)"
msgstr ""

Expand Down Expand Up @@ -1157,6 +1161,34 @@ msgstr ""
msgid "Scroller"
msgstr ""

#: src/scripts/blocks/timeline/DisplayComponent.js:146
msgid "Timeline Milestone Options"
msgstr ""

#: src/scripts/blocks/timeline/DisplayComponent.js:170
msgid "Add a milestone below."
msgstr ""

#: src/scripts/blocks/timeline/DisplayComponent.js:171
msgid "Add milestone"
msgstr ""

#: src/scripts/blocks/timeline/DisplayComponent.js:217
msgid "Remove Milestone"
msgstr ""

#: src/scripts/blocks/timeline/DisplayComponent.js:218
msgid "Add Milestone"
msgstr ""

#: src/scripts/blocks/timeline/DisplayComponent.js:91
msgid "Are you sure you want to delete this milestone from the timeline?"
msgstr ""

#: src/scripts/blocks/timeline/index.js:14
msgid "Timeline"
msgstr ""

#: src/scripts/blocks/tweet/index.js:109
msgid "(Action Title)"
msgstr ""
Expand Down
2 changes: 2 additions & 0 deletions src/scripts/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import subcatDrops from './modules/subcategory-dropdown';
import categoryExpander from './modules/category-expander';
import fluidText from './modules/fluid-text';
import scrollTo from './modules/scrollTo';
import timeline from './modules/timeline';

import './polyfills';

Expand All @@ -34,6 +35,7 @@ const App = () => {
subcatDrops();
categoryExpander();
scrollTo();
timeline();

fluidText(document.getElementsByClassName('article-shareTitle'), 0.9);

Expand Down
1 change: 1 addition & 0 deletions src/scripts/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import './blocks/category-list';
import './blocks/logo-list';
import './blocks/link';
import './blocks/media-aside';
import './blocks/timeline';

wp.blocks.registerBlockStyle('core/table', {
name: 'responsive',
Expand Down
245 changes: 245 additions & 0 deletions src/scripts/blocks/timeline/DisplayComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
const randId = () => Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10);

const { __ } = wp.i18n;
const { Component, Fragment } = wp.element;
const {
PanelBody, Button, DateTimePicker,
} = wp.components;

const {
InspectorControls, RichText,
} = wp.editor;

const { PostMediaSelector } = benenson.components;

class DisplayComponent extends Component {
static emptyMilestone = {
id: '',
heading: '',
title: '',
content: '',
};

constructor(...props) {
super(...props);

this.state = {
selectedMilestone: 0,
};
}

/**
* Higher order component that takes the attribute key,
* this then returns a function which takes a value,
* when called it updates the attribute with the key.
* @param key
* @returns {function(*): *}
*/
createUpdateAttribute = key => value => this.props.setAttributes({ [key]: value });

createUpdateMilestoneAttribute =
index =>
key =>
value =>
this.props.setAttributes({
milestones: [
...this.props.attributes.milestones
.slice(0, Math.max(0, index)),
{
...this.props.attributes.milestones[index],
[key]: value,
},
...this.props.attributes
.milestones.slice(index + 1, this.props.attributes.milestones.length),
],
});

addMilestone = () => {
this.setState({
selectedMilestone: this.props.attributes.milestones.length,
});

this.props.setAttributes({
milestones: [
...this.props.attributes.milestones,
{
...DisplayComponent.emptyMilestone,
id: randId(),
},
],
});
};

deleteMilestone = (index) => {
if (index === this.props.attributes.Milestones.length - 1) {
this.setState({
selectedMilestone: index - 1,
});
}

this.props.setAttributes({
milestones: [
...this.props.attributes
.milestones.slice(0, Math.max(0, index)),
...this.props.attributes
.milestones.slice(index + 1, this.props.attributes.milestones.length),
],
});
};

initiateDelete = () => {
if (confirm(__('Are you sure you want to delete this milestone from the timeline?', 'benenson'))) { // eslint-disable-line no-restricted-globals, no-alert
this.deleteMilestone(this.state.selectedMilestone);
}
};

selectMilestone = index => this.setState({
selectedMilestone: index,
});

createSelectMilestone = index => () => this.selectMilestone(index);

movePrev = () => {
const { selectedMilestone } = this.state;

const blockOrder = [...this.props.attributes.milestones];
const temp = blockOrder[selectedMilestone];
blockOrder[selectedMilestone] = blockOrder[selectedMilestone - 1];
blockOrder[selectedMilestone - 1] = temp;

this.props.setAttributes({
milestones: blockOrder,
});

this.setState({
selectedMilestone: selectedMilestone - 1,
});
};

moveNext = () => {
const { selectedMilestone } = this.state;

const blockOrder = [...this.props.attributes.milestones];
const temp = blockOrder[selectedMilestone];
blockOrder[selectedMilestone] = blockOrder[selectedMilestone + 1];
blockOrder[selectedMilestone + 1] = temp;

this.props.setAttributes({
milestones: blockOrder,
});

this.setState({
selectedMilestone: selectedMilestone + 1,
});
};

render() {
const { attributes } = this.props;
const { selectedMilestone } = this.state;

const currentMilestone = attributes.milestones[selectedMilestone];
const updateMilestone = this.createUpdateMilestoneAttribute(selectedMilestone);

const controls = (
<InspectorControls>
{ currentMilestone && (
<PanelBody title={ __('Timeline Milestone Options', 'benenson') }>
{ attributes.milestones.length >= 2 && (
<p>Change milestone position:</p>
)}
{ selectedMilestone !== 0 && (
<Button onClick={ this.movePrev } className="is-button is-default is-large" style={ { marginRight: '10px' } }>Move back</Button>
)}
{ selectedMilestone < attributes.milestones.length - 1 && (
<Button onClick={ this.moveNext } className="is-button is-default is-large">Move forward</Button>
)}
</PanelBody>
) }
</InspectorControls>
);

return (
<Fragment>
{ controls }
<div className="timmeline">
<div class="timeline-container">
<div className="timelineMilestones">
{ attributes.milestones.length === 0 && (
<div className="timmelineMilestone">
<div className="timmelineMilestone-contentContainer">
<h1 className="timmelineMilestone-title">{ __('Add a milestone below.', 'benenson') }</h1>
<button className="btn btn--white" onClick={ this.addMilestone }>{ __('Add milestone', 'benenson') }</button>
</div>
</div>
) }
{ currentMilestone && (
<div className="timelineMilestone">
<p className="timelineMilestone-heading">
<RichText
tagname="span"
placeholder={ __('(Heading)', 'benenson') }
value={ currentMilestone.heading }
onChange={ updateMilestone('heading') }
formattingControls={ [] }
keepPlaceholderOnFocus={ true }
format="string"
/>
</p>
<div className="timelineMilestone-content">
<RichText
tagname="p"
className="timelineMilestone-title"
placeholder={ __('(Title)', 'benenson') }
value={ currentMilestone.title }
onChange={ updateMilestone('title') }
formattingControls={ [] }
keepPlaceholderOnFocus={ true }
format="string"
/>
<RichText
tagname="p"
className="timelineMilestone-text"
placeholder={ __('(Content)', 'benenson') }
value={ currentMilestone.content }
onChange={ updateMilestone('content') }
formattingControls={ [] }
keepPlaceholderOnFocus={ true }
format="string"
/>
</div>
</div>
) }
</div>
</div>
<nav className="timeline-nav">
{ currentMilestone && (
<div className="timeline-navActions">
<button className="timeline-navButton btn" onClick={ this.initiateDelete }>{ __('Remove Milestone', 'benenson') }</button>
<button className="timeline-navButton btn" onClick={ this.addMilestone }>{ __('Add Milestone', 'benenson') }</button>
</div>
) }
{ attributes.milestones.length > 0 && attributes.milestones.map((milestone, index) => {
const milestoneTitle = milestone.title && milestone.title !== '';

if (selectedMilestone === index) {
return (
<div className="timeline-navButton is-active btn">
<span>{milestoneTitle ? milestone.title : __('(No Title)', 'benenson')}</span>
</div>
);
}

return (
<button className="timeline-navButton btn" onClick={ this.createSelectMilestone(index) }>
{ milestoneTitle ? milestone.title : __('(No Title)', 'benenson') }
</button>
);
}) }
</nav>
</div>
</Fragment>
);
}
}

export default DisplayComponent;
59 changes: 59 additions & 0 deletions src/scripts/blocks/timeline/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import assign from 'lodash-es/assign';
import DisplayComponent from './DisplayComponent';

const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;

const { dateI18n, format, __experimentalGetSettings } = wp.date;

registerBlockType('benenson/timeline', {
title: __('Timeline', 'benenson'),
icon: 'admin-post',
category: 'benenson',
keywords: [
__('Timeline', 'benenson'),
],
supports: {
multiple: true,
},
attributes: {
timelineId: {
type: 'string',
},
milestones: {
type: 'array',
default: [],
},
},

edit: DisplayComponent,

save({ attributes }) {
const dateFormat = __experimentalGetSettings().formats.date;

return (
<div className="timeline">
<div className="timeline-container">
<div class="timeline-line"></div>
<div className="timelineMilestones">
{ attributes.milestones.length > 0 && attributes.milestones.map((milestone, index) => {
const milestoneDate = milestone.date !== '' ? <p className="timelineMilestone-heading">{ dateI18n(dateFormat, milestone.date) }</p> : null;
const milestoneTitle = milestone.title !== '' ? <p className="timelineMilestone-title">{ milestone.title }</p> : null;
const milestoneContent = milestone.content !== '' ? <p className="timelineMilestone-text">{ milestone.content }</p> : null;

return (
<div className="timelineMilestone">
{ milestoneDate }
<div className="timelineMilestone-content">
{ milestoneTitle }
{ milestoneContent }
</div>
</div>
);
}) }
</div>
</div>
</div>
);
},
});
Loading