From 4db4c2102aeaeced4ee0225c33d06c21d3dfa7d5 Mon Sep 17 00:00:00 2001 From: Keran Braich Date: Wed, 6 May 2020 10:13:06 +0100 Subject: [PATCH 01/36] Create skeleton x-content-body component Component skeleton created using the x-dash `blueprint` script. --- .storybook/config.js | 1 + CODEOWNERS | 1 + components/x-content-block/.npmignore | 3 ++ components/x-content-block/package.json | 34 +++++++++++++++ components/x-content-block/readme.md | 43 +++++++++++++++++++ components/x-content-block/rollup.js | 4 ++ .../x-content-block/src/ContentBlock.jsx | 11 +++++ .../x-content-block/storybook/index.jsx | 36 ++++++++++++++++ 8 files changed, 133 insertions(+) create mode 100644 components/x-content-block/.npmignore create mode 100644 components/x-content-block/package.json create mode 100644 components/x-content-block/readme.md create mode 100644 components/x-content-block/rollup.js create mode 100644 components/x-content-block/src/ContentBlock.jsx create mode 100644 components/x-content-block/storybook/index.jsx diff --git a/.storybook/config.js b/.storybook/config.js index b21eb1dca..a304f58fb 100644 --- a/.storybook/config.js +++ b/.storybook/config.js @@ -14,4 +14,5 @@ configure(() => { // Add regular story definitions (i.e. those using storiesOf() directly below) require('../components/x-increment/storybook/index.jsx'); require('../components/x-follow-button/storybook/index.jsx'); + require('../components/x-content-block/storybook/index.jsx'); }, module); diff --git a/CODEOWNERS b/CODEOWNERS index 269897bcb..aef5a9747 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,3 +6,4 @@ components/x-teaser @Financial-Times/content-discovery components/x-teaser-timeline @Financial-Times/content-discovery +components/x-content-block @Financial-Times/content-innovation diff --git a/components/x-content-block/.npmignore b/components/x-content-block/.npmignore new file mode 100644 index 000000000..a44a9e753 --- /dev/null +++ b/components/x-content-block/.npmignore @@ -0,0 +1,3 @@ +src/ +stories/ +rollup.js diff --git a/components/x-content-block/package.json b/components/x-content-block/package.json new file mode 100644 index 000000000..30bc3b132 --- /dev/null +++ b/components/x-content-block/package.json @@ -0,0 +1,34 @@ +{ + "name": "@financial-times/x-content-block", + "version": "0.0.0", + "description": "", + "main": "dist/ContentBlock.cjs.js", + "module": "dist/ContentBlock.esm.js", + "browser": "dist/ContentBlock.es5.js", + "scripts": { + "build": "node rollup.js", + "start": "node rollup.js --watch" + }, + "keywords": [ + "x-dash" + ], + "author": "", + "license": "ISC", + "dependencies": { + "@financial-times/x-engine": "file:../../packages/x-engine" + }, + "devDependencies": { + "@financial-times/x-rollup": "file:../../packages/x-rollup" + }, + "repository": { + "type": "git", + "url": "https://github.com/Financial-Times/x-dash.git" + }, + "homepage": "https://github.com/Financial-Times/x-dash/tree/master/components/x-content-block", + "engines": { + "node": ">= 6.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/components/x-content-block/readme.md b/components/x-content-block/readme.md new file mode 100644 index 000000000..51d87589c --- /dev/null +++ b/components/x-content-block/readme.md @@ -0,0 +1,43 @@ +# x-content-block + +This module has these features and scope. + + +## Installation + +This module is compatible with Node 6+ and is distributed on npm. + +```bash +npm install --save @financial-times/x-content-block +``` + +The [`x-engine`][engine] module is used to inject your chosen runtime into the component. Please read the `x-engine` documentation first if you are consuming `x-` components for the first time in your application. + +[engine]: https://github.com/Financial-Times/x-dash/tree/master/packages/x-engine + + +## Usage + +The components provided by this module are all functions that expect a map of [properties](#properties). They can be used with vanilla JavaScript or JSX (If you are not familiar check out [WTF is JSX][jsx-wtf] first). For example if you were writing your application using React you could use the component like this: + +```jsx +import React from 'react'; +import { ContentBlock } from '@financial-times/x-content-block'; + +// A == B == C +const a = ContentBlock(props); +const b = ; +const c = React.createElement(ContentBlock, props); +``` + +All `x-` components are designed to be compatible with a variety of runtimes, not just React. Check out the [`x-engine`][engine] documentation for a list of recommended libraries and frameworks. + +[jsx-wtf]: https://jasonformat.com/wtf-is-jsx/ + +### Properties + +Feature | Type | Notes +-----------------|--------|---------------------------- +`propertyName1` | String | +`propertyName2` | String | +`propertyName2` | String | diff --git a/components/x-content-block/rollup.js b/components/x-content-block/rollup.js new file mode 100644 index 000000000..a6ea5aae4 --- /dev/null +++ b/components/x-content-block/rollup.js @@ -0,0 +1,4 @@ +const xRollup = require('@financial-times/x-rollup'); +const pkg = require('./package.json'); + +xRollup({ input: './src/ContentBlock.jsx', pkg }); diff --git a/components/x-content-block/src/ContentBlock.jsx b/components/x-content-block/src/ContentBlock.jsx new file mode 100644 index 000000000..28f2d39ec --- /dev/null +++ b/components/x-content-block/src/ContentBlock.jsx @@ -0,0 +1,11 @@ +import { h } from '@financial-times/x-engine'; + +const ContentBlock = (props) => ( +
+

{props.title}

+ {props.isBreakingNews && Breaking News!!!} +

+

+); + +export { ContentBlock }; diff --git a/components/x-content-block/storybook/index.jsx b/components/x-content-block/storybook/index.jsx new file mode 100644 index 000000000..6106d3a4d --- /dev/null +++ b/components/x-content-block/storybook/index.jsx @@ -0,0 +1,36 @@ +import React from 'react'; + +import { storiesOf } from '@storybook/react'; +import { withKnobs, text, boolean } from '@storybook/addon-knobs'; + +import { ContentBlock } from '../src/ContentBlock'; + +const defaultProps = { + title: 'Turkey’s virus deaths may be 25% higher than official figure', + content: '

Turkey’s death toll from coronavirus could be as much as 25 per cent higher than the government’s official tally, adding the country of 83m people to the raft of nations that have struggled to accurately capture the impact of the pandemic.

\n

Ankara has previously rejected suggestions that municipal data from Istanbul, the epicentre of the country’s Covid-19 outbreak, showed that there were more deaths from the disease than reported.

\n

But an analysis of individual death records by the Financial Times raises questions about the Turkish government’s explanation for a spike in all-cause mortality in the city of almost 16m people.

\n

Read the article here

\n

', + isBreakingNews: false +}; + +const toggleTitle = () => + text('Title', defaultProps.title); +const toggleIsBreakingNews = () => + boolean('Is breaking news', defaultProps.isBreakingNews); +const toggleContent = () => + text('Content', defaultProps.content) + +storiesOf('x-content-block', module) + .addDecorator(withKnobs) + .addParameters({ + knobs: { + escapeHTML: false + } + }) + .add('Content Body', () => { + const knobs = { + title: toggleTitle(), + isBreakingNews: toggleIsBreakingNews(), + content: toggleContent(), + }; + + return ; + }); From c1acef36871189577c1f83f0572273a277d66573 Mon Sep 17 00:00:00 2001 From: Keran Braich Date: Wed, 6 May 2020 10:44:49 +0100 Subject: [PATCH 02/36] Add styling using Origami component This is my attempt at adding styling to our component. See x-dash documentation: https://financial-times.github.io/x-dash/docs/components/styling --- components/x-content-block/.bowerrc | 8 ++++++++ components/x-content-block/bower.json | 9 +++++++++ components/x-content-block/package.json | 1 + components/x-content-block/src/ContentBlock.jsx | 3 ++- components/x-content-block/src/ContentBlock.scss | 5 +++++ 5 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 components/x-content-block/.bowerrc create mode 100644 components/x-content-block/bower.json create mode 100644 components/x-content-block/src/ContentBlock.scss diff --git a/components/x-content-block/.bowerrc b/components/x-content-block/.bowerrc new file mode 100644 index 000000000..59e9a5925 --- /dev/null +++ b/components/x-content-block/.bowerrc @@ -0,0 +1,8 @@ +{ + "registry": { + "search": [ + "https://origami-bower-registry.ft.com", + "https://registry.bower.io" + ] + } +} diff --git a/components/x-content-block/bower.json b/components/x-content-block/bower.json new file mode 100644 index 000000000..aa82b9290 --- /dev/null +++ b/components/x-content-block/bower.json @@ -0,0 +1,9 @@ +{ + "name": "@financial-times/x-content-block", + "description": "", + "main": "dist/ContentBlock.cjs.js", + "private": true, + "dependencies": { + "o-typography": "^6.3.5" + } +} diff --git a/components/x-content-block/package.json b/components/x-content-block/package.json index 30bc3b132..6ee6d0272 100644 --- a/components/x-content-block/package.json +++ b/components/x-content-block/package.json @@ -5,6 +5,7 @@ "main": "dist/ContentBlock.cjs.js", "module": "dist/ContentBlock.esm.js", "browser": "dist/ContentBlock.es5.js", + "style": "dist/ContentBlock.css", "scripts": { "build": "node rollup.js", "start": "node rollup.js --watch" diff --git a/components/x-content-block/src/ContentBlock.jsx b/components/x-content-block/src/ContentBlock.jsx index 28f2d39ec..2254d26b1 100644 --- a/components/x-content-block/src/ContentBlock.jsx +++ b/components/x-content-block/src/ContentBlock.jsx @@ -1,8 +1,9 @@ import { h } from '@financial-times/x-engine'; +import styles from './ContentBlock.scss'; const ContentBlock = (props) => (
-

{props.title}

+

{props.title}

{props.isBreakingNews && Breaking News!!!}

diff --git a/components/x-content-block/src/ContentBlock.scss b/components/x-content-block/src/ContentBlock.scss new file mode 100644 index 000000000..72168e895 --- /dev/null +++ b/components/x-content-block/src/ContentBlock.scss @@ -0,0 +1,5 @@ +@import 'o-typography/main'; + +.heading { + @include oTypographyHeading($level: 1); +} From 40587113f1396f002cc57c64045db6167de597b7 Mon Sep 17 00:00:00 2001 From: Keran Braich Date: Wed, 6 May 2020 11:21:00 +0100 Subject: [PATCH 03/36] Run `bower install` on prepare --- components/x-content-block/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/x-content-block/package.json b/components/x-content-block/package.json index 6ee6d0272..81b62ea61 100644 --- a/components/x-content-block/package.json +++ b/components/x-content-block/package.json @@ -7,6 +7,7 @@ "browser": "dist/ContentBlock.es5.js", "style": "dist/ContentBlock.css", "scripts": { + "prepare": "bower install && npm run build", "build": "node rollup.js", "start": "node rollup.js --watch" }, @@ -19,7 +20,8 @@ "@financial-times/x-engine": "file:../../packages/x-engine" }, "devDependencies": { - "@financial-times/x-rollup": "file:../../packages/x-rollup" + "@financial-times/x-rollup": "file:../../packages/x-rollup", + "bower": "^1.8.8" }, "repository": { "type": "git", From 528e028ff44e551c3e6d192f96490ccff278c1ea Mon Sep 17 00:00:00 2001 From: Tunca Bergmen <5130615+tbergmen@users.noreply.github.com> Date: Tue, 19 May 2020 16:30:20 +0100 Subject: [PATCH 04/36] Display the current data structure of live blogs in x-content-block --- .../x-content-block/src/ContentBlock.jsx | 93 +++++++++++++++++-- .../x-content-block/src/ContentBlock.scss | 2 +- .../x-content-block/storybook/index.jsx | 43 +++++++-- 3 files changed, 120 insertions(+), 18 deletions(-) diff --git a/components/x-content-block/src/ContentBlock.jsx b/components/x-content-block/src/ContentBlock.jsx index 2254d26b1..d0175c26b 100644 --- a/components/x-content-block/src/ContentBlock.jsx +++ b/components/x-content-block/src/ContentBlock.jsx @@ -1,12 +1,91 @@ import { h } from '@financial-times/x-engine'; import styles from './ContentBlock.scss'; -const ContentBlock = (props) => ( -
-

{props.title}

- {props.isBreakingNews && Breaking News!!!} -

-

-); +const ContentBlock = (props) => { + /** + * Notes: + * + * * textrendered, authordisplayname and keytext properties are temporary for testing purposes. + * Eventually, we would like to get rid of them. + * * Currently, we don't use content property. We need to replace textrendered with content. + * * At the moment article page does not pass articleUrl, therefore sharing links don't work. + * * At the moment, title is rendered twice (once in this component and once in the post body). + * This should be resolved when the data is cleaned in next-article. + */ + const { + mid, + title, + content, + time, + isBreakingNews, + articleUrl, + keytext, + textrendered, + authordisplayname + } = props; + + const shareUrl = articleUrl ? new URL(articleUrl) : null; + if (shareUrl) { + shareUrl.hash = `post-${mid}`; + } + + const twitterUrl = `https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(title)}&via=financialtimes`; + const facebookUrl = `http://www.facebook.com/sharer.php?u=${encodeURIComponent(shareUrl)}&t=${encodeURIComponent(title)}`; + const linkedInUrl = `http://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(shareUrl)}&title=${encodeURIComponent(title)}&source=Financial+Times`; + + return ( + + ); +}; export { ContentBlock }; diff --git a/components/x-content-block/src/ContentBlock.scss b/components/x-content-block/src/ContentBlock.scss index 72168e895..78f2afe7c 100644 --- a/components/x-content-block/src/ContentBlock.scss +++ b/components/x-content-block/src/ContentBlock.scss @@ -1,5 +1,5 @@ @import 'o-typography/main'; -.heading { +.live-post__title { @include oTypographyHeading($level: 1); } diff --git a/components/x-content-block/storybook/index.jsx b/components/x-content-block/storybook/index.jsx index 6106d3a4d..ea2cc34f6 100644 --- a/components/x-content-block/storybook/index.jsx +++ b/components/x-content-block/storybook/index.jsx @@ -1,22 +1,39 @@ import React from 'react'; - import { storiesOf } from '@storybook/react'; import { withKnobs, text, boolean } from '@storybook/addon-knobs'; - import { ContentBlock } from '../src/ContentBlock'; const defaultProps = { + mid: 12345, title: 'Turkey’s virus deaths may be 25% higher than official figure', content: '

Turkey’s death toll from coronavirus could be as much as 25 per cent higher than the government’s official tally, adding the country of 83m people to the raft of nations that have struggled to accurately capture the impact of the pandemic.

\n

Ankara has previously rejected suggestions that municipal data from Istanbul, the epicentre of the country’s Covid-19 outbreak, showed that there were more deaths from the disease than reported.

\n

But an analysis of individual death records by the Financial Times raises questions about the Turkish government’s explanation for a spike in all-cause mortality in the city of almost 16m people.

\n

Read the article here

\n

', - isBreakingNews: false + isBreakingNews: false, + time: { + format: 'MMM dd, HH:mm', + iso: '2020-05-13T18:52:28.000Z', + formatted: '5/13/2020, 19:52:28' + }, + articleUrl: 'https://www.ft.com/content/2b665ec7-a88f-3998-8f39-5371f9c791ed', + keytext: '', + authordisplayname: 'Philip Georgiadis', + textrendered: '

Turkey’s death toll from coronavirus could be as much as 25 per cent higher than the government’s official tally, adding the country of 83m people to the raft of nations that have struggled to accurately capture the impact of the pandemic.

\n

Ankara has previously rejected suggestions that municipal data from Istanbul, the epicentre of the country’s Covid-19 outbreak, showed that there were more deaths from the disease than reported.

\n

But an analysis of individual death records by the Financial Times raises questions about the Turkish government’s explanation for a spike in all-cause mortality in the city of almost 16m people.

\n

Read the article here

\n

', }; -const toggleTitle = () => - text('Title', defaultProps.title); -const toggleIsBreakingNews = () => - boolean('Is breaking news', defaultProps.isBreakingNews); -const toggleContent = () => - text('Content', defaultProps.content) +const toggleTitle = () => text('Title', defaultProps.title); +const toggleShowBreakingNews = () => boolean('Show breaking news', defaultProps.isBreakingNews); +const toggleContent = () => text('Content', defaultProps.content); +const toggleMid = () => text('mid', defaultProps.mid); +const toggleTime = () => ({ + format: text('Time format', defaultProps.time.format), + iso: text('Time ISO', defaultProps.time.iso), + formatted: text('Formatted time', defaultProps.time.formatted) +}); +const toggleArticleUrl = () => text('Article URL', defaultProps.articleUrl); +const toggleKeyText = () => text('Key text', defaultProps.keytext); + +// textrendered and authordisplayname properties will be removed +const toggleAuthor = () => text('Author', defaultProps.authordisplayname); +const toggleTextRendered = () => text('Text rendered', defaultProps.textrendered); storiesOf('x-content-block', module) .addDecorator(withKnobs) @@ -28,8 +45,14 @@ storiesOf('x-content-block', module) .add('Content Body', () => { const knobs = { title: toggleTitle(), - isBreakingNews: toggleIsBreakingNews(), + isBreakingNews: toggleShowBreakingNews(), content: toggleContent(), + mid: toggleMid(), + time: toggleTime(), + articleUrl: toggleArticleUrl(), + keyText: toggleKeyText(), + authordisplayname: toggleAuthor(), + textrendered: toggleTextRendered(), }; return ; From 9a774ab1dd5b9588f4e1c7fa000a4a2fe6d22e67 Mon Sep 17 00:00:00 2001 From: Keran Braich Date: Tue, 19 May 2020 16:54:35 +0100 Subject: [PATCH 05/36] Use `content` prop over `textrendered` `next-article` now provides a content property that can be used by our component. --- components/x-content-block/src/ContentBlock.jsx | 14 ++------------ components/x-content-block/storybook/index.jsx | 7 ++----- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/components/x-content-block/src/ContentBlock.jsx b/components/x-content-block/src/ContentBlock.jsx index d0175c26b..4179dd6fd 100644 --- a/components/x-content-block/src/ContentBlock.jsx +++ b/components/x-content-block/src/ContentBlock.jsx @@ -2,16 +2,7 @@ import { h } from '@financial-times/x-engine'; import styles from './ContentBlock.scss'; const ContentBlock = (props) => { - /** - * Notes: - * - * * textrendered, authordisplayname and keytext properties are temporary for testing purposes. - * Eventually, we would like to get rid of them. - * * Currently, we don't use content property. We need to replace textrendered with content. - * * At the moment article page does not pass articleUrl, therefore sharing links don't work. - * * At the moment, title is rendered twice (once in this component and once in the post body). - * This should be resolved when the data is cleaned in next-article. - */ + // The `authordisplayname` and `keytext` properites are temporary and will eventually be replaced const { mid, title, @@ -20,7 +11,6 @@ const ContentBlock = (props) => { isBreakingNews, articleUrl, keytext, - textrendered, authordisplayname } = props; @@ -48,7 +38,7 @@ const ContentBlock = (props) => { {keytext}

{title}

{isBreakingNews && Breaking news!} -
+
({ formatted: text('Formatted time', defaultProps.time.formatted) }); const toggleArticleUrl = () => text('Article URL', defaultProps.articleUrl); +// The `authordisplayname` and `keytext` properites are temporary and will eventually be replaced const toggleKeyText = () => text('Key text', defaultProps.keytext); - -// textrendered and authordisplayname properties will be removed const toggleAuthor = () => text('Author', defaultProps.authordisplayname); -const toggleTextRendered = () => text('Text rendered', defaultProps.textrendered); storiesOf('x-content-block', module) .addDecorator(withKnobs) @@ -51,8 +49,7 @@ storiesOf('x-content-block', module) time: toggleTime(), articleUrl: toggleArticleUrl(), keyText: toggleKeyText(), - authordisplayname: toggleAuthor(), - textrendered: toggleTextRendered(), + authordisplayname: toggleAuthor() }; return ; From c3a21080cd09a441c1272905568b842ff366c692 Mon Sep 17 00:00:00 2001 From: Keran Braich Date: Tue, 19 May 2020 17:33:50 +0100 Subject: [PATCH 06/36] Move share buttons into their own component --- .../x-content-block/src/ContentBlock.jsx | 45 +---------------- .../x-content-block/src/ShareButtons.jsx | 49 +++++++++++++++++++ 2 files changed, 51 insertions(+), 43 deletions(-) create mode 100644 components/x-content-block/src/ShareButtons.jsx diff --git a/components/x-content-block/src/ContentBlock.jsx b/components/x-content-block/src/ContentBlock.jsx index 4179dd6fd..abca34884 100644 --- a/components/x-content-block/src/ContentBlock.jsx +++ b/components/x-content-block/src/ContentBlock.jsx @@ -1,4 +1,5 @@ import { h } from '@financial-times/x-engine'; +import ShareButtons from './ShareButtons'; import styles from './ContentBlock.scss'; const ContentBlock = (props) => { @@ -14,15 +15,6 @@ const ContentBlock = (props) => { authordisplayname } = props; - const shareUrl = articleUrl ? new URL(articleUrl) : null; - if (shareUrl) { - shareUrl.hash = `post-${mid}`; - } - - const twitterUrl = `https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(title)}&via=financialtimes`; - const facebookUrl = `http://www.facebook.com/sharer.php?u=${encodeURIComponent(shareUrl)}&t=${encodeURIComponent(title)}`; - const linkedInUrl = `http://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(shareUrl)}&title=${encodeURIComponent(title)}&source=Financial+Times`; - return ( ); }; diff --git a/components/x-content-block/src/ShareButtons.jsx b/components/x-content-block/src/ShareButtons.jsx new file mode 100644 index 000000000..a1c258fea --- /dev/null +++ b/components/x-content-block/src/ShareButtons.jsx @@ -0,0 +1,49 @@ +import { h } from '@financial-times/x-engine'; + +export default ({ mid, articleUrl, title }) => { + const shareUrl = articleUrl ? new URL(articleUrl) : null; + if (shareUrl) { + shareUrl.hash = `post-${mid}`; + } + + const twitterUrl = `https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(title)}&via=financialtimes`; + const facebookUrl = `http://www.facebook.com/sharer.php?u=${encodeURIComponent(shareUrl)}&t=${encodeURIComponent(title)}`; + const linkedInUrl = `http://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(shareUrl)}&title=${encodeURIComponent(title)}&source=Financial+Times`; + + return ( + + ); +}; From b2c76f42b90217256c7329a379cf79bbb969d420 Mon Sep 17 00:00:00 2001 From: Keran Braich Date: Wed, 20 May 2020 10:09:19 +0100 Subject: [PATCH 07/36] Move time stamp into its own component --- components/x-content-block/src/ContentBlock.jsx | 10 ++-------- components/x-content-block/src/TimeStamp.jsx | 13 +++++++++++++ 2 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 components/x-content-block/src/TimeStamp.jsx diff --git a/components/x-content-block/src/ContentBlock.jsx b/components/x-content-block/src/ContentBlock.jsx index abca34884..1d9420048 100644 --- a/components/x-content-block/src/ContentBlock.jsx +++ b/components/x-content-block/src/ContentBlock.jsx @@ -1,5 +1,6 @@ import { h } from '@financial-times/x-engine'; import ShareButtons from './ShareButtons'; +import TimeStamp from './TimeStamp'; import styles from './ContentBlock.scss'; const ContentBlock = (props) => { @@ -19,19 +20,12 @@ const ContentBlock = (props) => {
{authordisplayname} - +
{keytext}

{title}

{isBreakingNews && Breaking news!}
-
); diff --git a/components/x-content-block/src/TimeStamp.jsx b/components/x-content-block/src/TimeStamp.jsx new file mode 100644 index 000000000..ab2a71262 --- /dev/null +++ b/components/x-content-block/src/TimeStamp.jsx @@ -0,0 +1,13 @@ +import { h } from '@financial-times/x-engine'; + +export default ({ time }) => { + return ( + + ); +}; From 682fd7d66e98314067ffe525cc8ccabd8257ab3a Mon Sep 17 00:00:00 2001 From: Keran Braich Date: Thu, 28 May 2020 10:21:21 +0100 Subject: [PATCH 08/36] Rename props passed into component After talking to the team, we decided it was best to keep WordPress specific naming (e.g. keytext, authordisplayname) out of our component and instead pass in our idea data structure. We can then restructure the data before it's passed in, in either `next-article` and/or `next-live-events-api`. --- .../x-content-block/src/ContentBlock.jsx | 19 ++++++----- .../x-content-block/src/ShareButtons.jsx | 6 ++-- components/x-content-block/src/TimeStamp.jsx | 6 ++-- .../x-content-block/storybook/index.jsx | 32 +++++++++---------- 4 files changed, 30 insertions(+), 33 deletions(-) diff --git a/components/x-content-block/src/ContentBlock.jsx b/components/x-content-block/src/ContentBlock.jsx index 1d9420048..a674899b7 100644 --- a/components/x-content-block/src/ContentBlock.jsx +++ b/components/x-content-block/src/ContentBlock.jsx @@ -4,29 +4,28 @@ import TimeStamp from './TimeStamp'; import styles from './ContentBlock.scss'; const ContentBlock = (props) => { - // The `authordisplayname` and `keytext` properites are temporary and will eventually be replaced const { - mid, + postId, title, content, - time, + publishedTimestamp, isBreakingNews, articleUrl, - keytext, - authordisplayname + isKeyEvent, + author } = props; return ( -
+
- {authordisplayname} - + {author} +
- {keytext} + {isKeyEvent && Key event}

{title}

{isBreakingNews && Breaking news!}
- +
); }; diff --git a/components/x-content-block/src/ShareButtons.jsx b/components/x-content-block/src/ShareButtons.jsx index a1c258fea..5a55465ad 100644 --- a/components/x-content-block/src/ShareButtons.jsx +++ b/components/x-content-block/src/ShareButtons.jsx @@ -1,9 +1,9 @@ import { h } from '@financial-times/x-engine'; -export default ({ mid, articleUrl, title }) => { +export default ({ postId, articleUrl, title }) => { const shareUrl = articleUrl ? new URL(articleUrl) : null; if (shareUrl) { - shareUrl.hash = `post-${mid}`; + shareUrl.hash = `post-${postId}`; } const twitterUrl = `https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(title)}&via=financialtimes`; @@ -13,7 +13,7 @@ export default ({ mid, articleUrl, title }) => { return (
  • diff --git a/components/x-content-block/src/TimeStamp.jsx b/components/x-content-block/src/TimeStamp.jsx index ab2a71262..4655967e1 100644 --- a/components/x-content-block/src/TimeStamp.jsx +++ b/components/x-content-block/src/TimeStamp.jsx @@ -1,13 +1,13 @@ import { h } from '@financial-times/x-engine'; -export default ({ time }) => { +export default ({ publishedTimestamp }) => { return ( ); }; diff --git a/components/x-content-block/storybook/index.jsx b/components/x-content-block/storybook/index.jsx index fbbd00a81..d4984b691 100644 --- a/components/x-content-block/storybook/index.jsx +++ b/components/x-content-block/storybook/index.jsx @@ -4,34 +4,32 @@ import { withKnobs, text, boolean } from '@storybook/addon-knobs'; import { ContentBlock } from '../src/ContentBlock'; const defaultProps = { - mid: 12345, + postId: 12345, title: 'Turkey’s virus deaths may be 25% higher than official figure', content: '

    Turkey’s death toll from coronavirus could be as much as 25 per cent higher than the government’s official tally, adding the country of 83m people to the raft of nations that have struggled to accurately capture the impact of the pandemic.

    \n

    Ankara has previously rejected suggestions that municipal data from Istanbul, the epicentre of the country’s Covid-19 outbreak, showed that there were more deaths from the disease than reported.

    \n

    But an analysis of individual death records by the Financial Times raises questions about the Turkish government’s explanation for a spike in all-cause mortality in the city of almost 16m people.

    \n

    Read the article here

    \n

    ', isBreakingNews: false, - time: { + publishedTimestamp: { format: 'MMM dd, HH:mm', iso: '2020-05-13T18:52:28.000Z', formatted: '5/13/2020, 19:52:28' }, articleUrl: 'https://www.ft.com/content/2b665ec7-a88f-3998-8f39-5371f9c791ed', - keytext: '', - authordisplayname: 'Philip Georgiadis', - textrendered: '

    Turkey’s death toll from coronavirus could be as much as 25 per cent higher than the government’s official tally, adding the country of 83m people to the raft of nations that have struggled to accurately capture the impact of the pandemic.

    \n

    Ankara has previously rejected suggestions that municipal data from Istanbul, the epicentre of the country’s Covid-19 outbreak, showed that there were more deaths from the disease than reported.

    \n

    But an analysis of individual death records by the Financial Times raises questions about the Turkish government’s explanation for a spike in all-cause mortality in the city of almost 16m people.

    \n

    Read the article here

    \n

    ', + isKeyEvent: false, + author: 'Philip Georgiadis', }; const toggleTitle = () => text('Title', defaultProps.title); const toggleShowBreakingNews = () => boolean('Show breaking news', defaultProps.isBreakingNews); const toggleContent = () => text('Content', defaultProps.content); -const toggleMid = () => text('mid', defaultProps.mid); -const toggleTime = () => ({ - format: text('Time format', defaultProps.time.format), - iso: text('Time ISO', defaultProps.time.iso), - formatted: text('Formatted time', defaultProps.time.formatted) +const togglePostId = () => text('Post ID', defaultProps.postId); +const togglePublishedTimestamp = () => ({ + format: text('Time format', defaultProps.publishedTimestamp.format), + iso: text('Time ISO', defaultProps.publishedTimestamp.iso), + formatted: text('Formatted time', defaultProps.publishedTimestamp.formatted) }); const toggleArticleUrl = () => text('Article URL', defaultProps.articleUrl); -// The `authordisplayname` and `keytext` properites are temporary and will eventually be replaced -const toggleKeyText = () => text('Key text', defaultProps.keytext); -const toggleAuthor = () => text('Author', defaultProps.authordisplayname); +const toggleShowKeyEvent = () => boolean('Show key event', defaultProps.isKeyEvent); +const toggleAuthor = () => text('Author', defaultProps.author); storiesOf('x-content-block', module) .addDecorator(withKnobs) @@ -45,11 +43,11 @@ storiesOf('x-content-block', module) title: toggleTitle(), isBreakingNews: toggleShowBreakingNews(), content: toggleContent(), - mid: toggleMid(), - time: toggleTime(), + postId: togglePostId(), + publishedTimestamp: togglePublishedTimestamp(), articleUrl: toggleArticleUrl(), - keyText: toggleKeyText(), - authordisplayname: toggleAuthor() + isKeyEvent: toggleShowKeyEvent(), + author: toggleAuthor() }; return ; From e936654b6b0a52d820eaef627568cad6d1bea034 Mon Sep 17 00:00:00 2001 From: tbergmen <5130615+tbergmen@users.noreply.github.com> Date: Tue, 2 Jun 2020 17:57:44 +0100 Subject: [PATCH 09/36] Update x-content-block styles --- components/x-content-block/bower.json | 4 +- .../x-content-block/src/ContentBlock.jsx | 12 ++-- .../x-content-block/src/ContentBlock.scss | 62 ++++++++++++++++- .../x-content-block/src/ShareButtons.jsx | 69 ++++++++++--------- components/x-content-block/src/TimeStamp.jsx | 3 +- 5 files changed, 106 insertions(+), 44 deletions(-) diff --git a/components/x-content-block/bower.json b/components/x-content-block/bower.json index aa82b9290..324daa5ae 100644 --- a/components/x-content-block/bower.json +++ b/components/x-content-block/bower.json @@ -4,6 +4,8 @@ "main": "dist/ContentBlock.cjs.js", "private": true, "dependencies": { - "o-typography": "^6.3.5" + "o-colors": "^5.2.4", + "o-spacing": "^2.0.4", + "o-typography": "^6.4.0" } } diff --git a/components/x-content-block/src/ContentBlock.jsx b/components/x-content-block/src/ContentBlock.jsx index a674899b7..c5058550c 100644 --- a/components/x-content-block/src/ContentBlock.jsx +++ b/components/x-content-block/src/ContentBlock.jsx @@ -16,15 +16,13 @@ const ContentBlock = (props) => { } = props; return ( -
    -
    - {author} +
    +
    - {isKeyEvent && Key event} -

    {title}

    - {isBreakingNews && Breaking news!} -
    + {isBreakingNews && Breaking news} +

    {title}

    +
    ); diff --git a/components/x-content-block/src/ContentBlock.scss b/components/x-content-block/src/ContentBlock.scss index 78f2afe7c..79b566652 100644 --- a/components/x-content-block/src/ContentBlock.scss +++ b/components/x-content-block/src/ContentBlock.scss @@ -1,5 +1,63 @@ @import 'o-typography/main'; +@import 'o-spacing/main'; +@import 'o-colors/main'; -.live-post__title { - @include oTypographyHeading($level: 1); +.content-block { + border-bottom: 1px solid oColorsMix(black, paper, 20); + margin-top: oSpacingByName('s8'); + color: oColorsMix(black, paper, 90); +} + +.content-block__title { + @include oTypographyDisplay($scale: 5); + margin-top: oSpacingByName('s4'); +} + +.content-block__breaking-news + .content-block__title { + margin-top: oSpacingByName('s1'); +} + +.content-block__body { + @include oTypographySerif($scale: 1, $line-height: 1.55); + margin-top: oSpacingByName('s6'); +} + +.content-block__body ul { + @include oTypographyList('unordered'); +} + +.content-block__timestamp { + @include oTypographySans($scale:0, $weight: 'semibold'); + font-size: 14px; + text-transform: uppercase; +} + +.content-block__timestamp:after { + content: ''; + display: block; + width: oSpacingByName('s4'); + border-bottom: 4px solid oColorsMix(black, paper, 90); +} + +.content-block__share-buttons { + margin-top: oSpacingByName('s6'); + margin-bottom: oSpacingByName('s8') +} + +.content-block__breaking-news { + @include oTypographySans($scale:0); + font-size: 12px; + color: oColorsByName('crimson'); + text-transform: uppercase; + margin-top: oSpacingByName('s4'); +} + +.content-block__breaking-news:before { + content: ''; + display: inline-block; + width: 8px; + height: 8px; + margin-right: 4px; + border-radius: 50%; + background-color: oColorsByName('crimson'); } diff --git a/components/x-content-block/src/ShareButtons.jsx b/components/x-content-block/src/ShareButtons.jsx index 5a55465ad..5a563707e 100644 --- a/components/x-content-block/src/ShareButtons.jsx +++ b/components/x-content-block/src/ShareButtons.jsx @@ -1,4 +1,5 @@ import { h } from '@financial-times/x-engine'; +import styles from './ContentBlock.scss'; export default ({ postId, articleUrl, title }) => { const shareUrl = articleUrl ? new URL(articleUrl) : null; @@ -11,39 +12,41 @@ export default ({ postId, articleUrl, title }) => { const linkedInUrl = `http://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(shareUrl)}&title=${encodeURIComponent(title)}&source=Financial+Times`; return ( -
    - + ); }; diff --git a/components/x-content-block/src/TimeStamp.jsx b/components/x-content-block/src/TimeStamp.jsx index 4655967e1..16c4fb592 100644 --- a/components/x-content-block/src/TimeStamp.jsx +++ b/components/x-content-block/src/TimeStamp.jsx @@ -1,10 +1,11 @@ import { h } from '@financial-times/x-engine'; +import styles from './ContentBlock.scss'; export default ({ publishedTimestamp }) => { return (
    ); }; From 8cb021fef869033ede71e4057c1ebdc12fbb7522 Mon Sep 17 00:00:00 2001 From: tbergmen <5130615+tbergmen@users.noreply.github.com> Date: Fri, 19 Jun 2020 10:46:31 +0100 Subject: [PATCH 26/36] Add descriptive aria-label to social media sharing links --- components/x-content-block/src/ShareButtons.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/x-content-block/src/ShareButtons.jsx b/components/x-content-block/src/ShareButtons.jsx index 5a563707e..750fd5e01 100644 --- a/components/x-content-block/src/ShareButtons.jsx +++ b/components/x-content-block/src/ShareButtons.jsx @@ -24,7 +24,7 @@ export default ({ postId, articleUrl, title }) => { rel="noopener" href={twitterUrl} data-trackable="twitter"> - Share on Twitter (opens new window) + Share on Twitter (opens new window)
  • @@ -33,7 +33,7 @@ export default ({ postId, articleUrl, title }) => { rel="noopener" href={facebookUrl} data-trackable="facebook"> - Share on Facebook (opens new window) + Share on Facebook (opens new window)
  • @@ -42,7 +42,7 @@ export default ({ postId, articleUrl, title }) => { rel="noopener" href={linkedInUrl} data-trackable="linkedin"> - Share on LinkedIn (opens new window) + Share on LinkedIn (opens new window)
From a790973ac1f4f0bd5c563ad7da9bd109aa62dfc3 Mon Sep 17 00:00:00 2001 From: tbergmen <5130615+tbergmen@users.noreply.github.com> Date: Fri, 19 Jun 2020 11:54:36 +0100 Subject: [PATCH 27/36] Fix unit tests --- .../x-content-block/src/__tests__/Timestamp.test.jsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/components/x-content-block/src/__tests__/Timestamp.test.jsx b/components/x-content-block/src/__tests__/Timestamp.test.jsx index 0b51ba052..b49db7a34 100644 --- a/components/x-content-block/src/__tests__/Timestamp.test.jsx +++ b/components/x-content-block/src/__tests__/Timestamp.test.jsx @@ -29,13 +29,6 @@ describe('x-content-block', () => { expect(dateEl.prop('dateTime')).toEqual(date.toISOString()); expect(dateEl.text()).toEqual(date.toLocaleString()); }); - - it('does not render exact time', () => { - const timestamp = mount(); - const exactTimeEl = timestamp.find('time[data-o-component="o-date"] + span').first(); - - expect(exactTimeEl.text()).toEqual(''); - }); }); describe('when timestamp is in the last 24 hours', () => { @@ -51,9 +44,9 @@ describe('x-content-block', () => { it('renders the exact time', () => { const timestamp = mount(); - const exactTimeEl = timestamp.find('time[data-o-component="o-date"] + span').first(); + const exactTimeEl = timestamp.find('time[data-o-component="o-date"] + time').first(); - expect(exactTimeEl.text()).toMatch(/[0-2]?[0-9]:[0-6][0-9]/); + expect(exactTimeEl.prop('data-o-date-format')).toEqual('HH:mm'); }); }); From 05adef526495ef62413b437d04aa6c1e7038474c Mon Sep 17 00:00:00 2001 From: tbergmen <5130615+tbergmen@users.noreply.github.com> Date: Fri, 19 Jun 2020 12:05:48 +0100 Subject: [PATCH 28/36] Refactor exact time display logic Mainly for better testability --- components/x-content-block/src/Timestamp.jsx | 12 ++++++------ .../x-content-block/src/__tests__/Timestamp.test.jsx | 7 +++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/components/x-content-block/src/Timestamp.jsx b/components/x-content-block/src/Timestamp.jsx index 4e7e931f0..41b2d3f2a 100644 --- a/components/x-content-block/src/Timestamp.jsx +++ b/components/x-content-block/src/Timestamp.jsx @@ -8,18 +8,18 @@ export default ({ publishedTimestamp }) => { const formatted = date.toLocaleString(); let format; - let hideExactTime; + let showExactTime; if (now.getTime() - date.getTime() < oneDay) { // display published date in 'xx minutes ago' format // and render exact time next to it format = 'time-ago-no-seconds'; - hideExactTime = false; + showExactTime = true; } else { // don't display time string if the post is older than one day // because it is already included in the formatted timestamp format = 'MMM dd, HH:mm'; - hideExactTime = true; + showExactTime = false; } return ( @@ -31,15 +31,15 @@ export default ({ publishedTimestamp }) => { data-o-date-format={format} dateTime={publishedTimestamp}>{formatted} + {showExactTime && ( + )}
); }; diff --git a/components/x-content-block/src/__tests__/Timestamp.test.jsx b/components/x-content-block/src/__tests__/Timestamp.test.jsx index b49db7a34..a8c959e87 100644 --- a/components/x-content-block/src/__tests__/Timestamp.test.jsx +++ b/components/x-content-block/src/__tests__/Timestamp.test.jsx @@ -29,6 +29,13 @@ describe('x-content-block', () => { expect(dateEl.prop('dateTime')).toEqual(date.toISOString()); expect(dateEl.text()).toEqual(date.toLocaleString()); }); + + it('does not render exact time', () => { + const timestamp = mount(); + const exactTimeElements = timestamp.find('time[data-o-component="o-date"]'); + + expect(exactTimeElements.length).toEqual(1); + }); }); describe('when timestamp is in the last 24 hours', () => { From 2ba20d3a758dafd06c185ae124fe388387992080 Mon Sep 17 00:00:00 2001 From: tbergmen <5130615+tbergmen@users.noreply.github.com> Date: Fri, 19 Jun 2020 15:52:01 +0100 Subject: [PATCH 29/36] Rename x-content-block to x-live-blog-post --- .storybook/config.js | 2 +- CODEOWNERS | 2 +- .../x-content-block/src/ContentBlock.jsx | 29 ------------------- .../.bowerrc | 0 .../.npmignore | 0 .../bower.json | 4 +-- .../package.json | 12 ++++---- .../readme.md | 14 ++++----- .../rollup.js | 2 +- .../x-live-blog-post/src/LiveBlogPost.jsx | 29 +++++++++++++++++++ .../src/LiveBlogPost.scss} | 26 +++++++---------- .../src/ShareButtons.jsx | 4 +-- .../src/Timestamp.jsx | 8 ++--- .../src/__tests__/LiveBlogPost.test.jsx} | 28 +++++++++--------- .../src/__tests__/ShareButtons.test.jsx | 2 +- .../src/__tests__/Timestamp.test.jsx | 2 +- .../storybook/index.jsx | 6 ++-- 17 files changed, 83 insertions(+), 87 deletions(-) delete mode 100644 components/x-content-block/src/ContentBlock.jsx rename components/{x-content-block => x-live-blog-post}/.bowerrc (100%) rename components/{x-content-block => x-live-blog-post}/.npmignore (100%) rename components/{x-content-block => x-live-blog-post}/bower.json (63%) rename components/{x-content-block => x-live-blog-post}/package.json (76%) rename components/{x-content-block => x-live-blog-post}/readme.md (77%) rename components/{x-content-block => x-live-blog-post}/rollup.js (64%) create mode 100644 components/x-live-blog-post/src/LiveBlogPost.jsx rename components/{x-content-block/src/ContentBlock.scss => x-live-blog-post/src/LiveBlogPost.scss} (75%) rename components/{x-content-block => x-live-blog-post}/src/ShareButtons.jsx (95%) rename components/{x-content-block => x-live-blog-post}/src/Timestamp.jsx (80%) rename components/{x-content-block/src/__tests__/ContentBlock.test.jsx => x-live-blog-post/src/__tests__/LiveBlogPost.test.jsx} (51%) rename components/{x-content-block => x-live-blog-post}/src/__tests__/ShareButtons.test.jsx (97%) rename components/{x-content-block => x-live-blog-post}/src/__tests__/Timestamp.test.jsx (98%) rename components/{x-content-block => x-live-blog-post}/storybook/index.jsx (93%) diff --git a/.storybook/config.js b/.storybook/config.js index a304f58fb..6579545a1 100644 --- a/.storybook/config.js +++ b/.storybook/config.js @@ -14,5 +14,5 @@ configure(() => { // Add regular story definitions (i.e. those using storiesOf() directly below) require('../components/x-increment/storybook/index.jsx'); require('../components/x-follow-button/storybook/index.jsx'); - require('../components/x-content-block/storybook/index.jsx'); + require('../components/x-live-blog-post/storybook/index.jsx'); }, module); diff --git a/CODEOWNERS b/CODEOWNERS index aef5a9747..9092d6947 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,4 +6,4 @@ components/x-teaser @Financial-Times/content-discovery components/x-teaser-timeline @Financial-Times/content-discovery -components/x-content-block @Financial-Times/content-innovation +components/x-live-blog-post @Financial-Times/content-innovation diff --git a/components/x-content-block/src/ContentBlock.jsx b/components/x-content-block/src/ContentBlock.jsx deleted file mode 100644 index 83f0baf33..000000000 --- a/components/x-content-block/src/ContentBlock.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import { h } from '@financial-times/x-engine'; -import ShareButtons from './ShareButtons'; -import Timestamp from './Timestamp'; -import styles from './ContentBlock.scss'; - -const ContentBlock = (props) => { - const { - postId, - title, - content, - publishedTimestamp, - isBreakingNews, - articleUrl - } = props; - - return ( -
-
- -
- {isBreakingNews &&
Breaking news
} -

{title}

-
- -
- ); -}; - -export { ContentBlock }; diff --git a/components/x-content-block/.bowerrc b/components/x-live-blog-post/.bowerrc similarity index 100% rename from components/x-content-block/.bowerrc rename to components/x-live-blog-post/.bowerrc diff --git a/components/x-content-block/.npmignore b/components/x-live-blog-post/.npmignore similarity index 100% rename from components/x-content-block/.npmignore rename to components/x-live-blog-post/.npmignore diff --git a/components/x-content-block/bower.json b/components/x-live-blog-post/bower.json similarity index 63% rename from components/x-content-block/bower.json rename to components/x-live-blog-post/bower.json index 324daa5ae..586366606 100644 --- a/components/x-content-block/bower.json +++ b/components/x-live-blog-post/bower.json @@ -1,7 +1,7 @@ { - "name": "@financial-times/x-content-block", + "name": "@financial-times/x-live-blog-post", "description": "", - "main": "dist/ContentBlock.cjs.js", + "main": "dist/LiveBlogPost.cjs.js", "private": true, "dependencies": { "o-colors": "^5.2.4", diff --git a/components/x-content-block/package.json b/components/x-live-blog-post/package.json similarity index 76% rename from components/x-content-block/package.json rename to components/x-live-blog-post/package.json index b2dc8e0dc..cc6453b2d 100644 --- a/components/x-content-block/package.json +++ b/components/x-live-blog-post/package.json @@ -1,11 +1,11 @@ { - "name": "@financial-times/x-content-block", + "name": "@financial-times/x-live-blog-post", "version": "0.0.0", "description": "", - "main": "dist/ContentBlock.cjs.js", - "module": "dist/ContentBlock.esm.js", - "browser": "dist/ContentBlock.es5.js", - "style": "dist/ContentBlock.css", + "main": "dist/LiveBlogPpost.cjs.js", + "module": "dist/LiveBlogPost.esm.js", + "browser": "dist/LiveBlogPost.es5.js", + "style": "dist/LiveBlogPost.css", "scripts": { "prepare": "bower install && npm run build", "build": "node rollup.js", @@ -28,7 +28,7 @@ "type": "git", "url": "https://github.com/Financial-Times/x-dash.git" }, - "homepage": "https://github.com/Financial-Times/x-dash/tree/master/components/x-content-block", + "homepage": "https://github.com/Financial-Times/x-dash/tree/master/components/x-live-blog-post", "engines": { "node": ">= 10.x" }, diff --git a/components/x-content-block/readme.md b/components/x-live-blog-post/readme.md similarity index 77% rename from components/x-content-block/readme.md rename to components/x-live-blog-post/readme.md index 2eeab6c94..ab9453ed4 100644 --- a/components/x-content-block/readme.md +++ b/components/x-live-blog-post/readme.md @@ -1,6 +1,6 @@ -# x-content-block +# x-live-blog-post -This module displays a block of content with an id, title, body and timestamp. Main use case is the new version of live blogs, although we don't want to limit its usage to it. +This module displays a live blog post with an id, title, body and timestamp. ## Installation @@ -8,7 +8,7 @@ This module displays a block of content with an id, title, body and timestamp. M This module is compatible with Node 10.x+ and is distributed on npm. ```bash -npm install --save @financial-times/x-content-block +npm install --save @financial-times/x-live-blog-post ``` The [`x-engine`][engine] module is used to inject your chosen runtime into the component. Please read the `x-engine` documentation first if you are consuming `x-` components for the first time in your application. @@ -22,12 +22,12 @@ The components provided by this module are all functions that expect a map of [p ```jsx import React from 'react'; -import { ContentBlock } from '@financial-times/x-content-block'; +import { LiveBlogPost } from '@financial-times/x-live-blog-post'; // A == B == C -const a = ContentBlock(props); -const b = ; -const c = React.createElement(ContentBlock, props); +const a = LiveBlogPost(props); +const b = ; +const c = React.createElement(LiveBlogPost, props); ``` All `x-` components are designed to be compatible with a variety of runtimes, not just React. Check out the [`x-engine`][engine] documentation for a list of recommended libraries and frameworks. diff --git a/components/x-content-block/rollup.js b/components/x-live-blog-post/rollup.js similarity index 64% rename from components/x-content-block/rollup.js rename to components/x-live-blog-post/rollup.js index a6ea5aae4..0a1e8b89c 100644 --- a/components/x-content-block/rollup.js +++ b/components/x-live-blog-post/rollup.js @@ -1,4 +1,4 @@ const xRollup = require('@financial-times/x-rollup'); const pkg = require('./package.json'); -xRollup({ input: './src/ContentBlock.jsx', pkg }); +xRollup({ input: './src/LiveBlogPost.jsx', pkg }); diff --git a/components/x-live-blog-post/src/LiveBlogPost.jsx b/components/x-live-blog-post/src/LiveBlogPost.jsx new file mode 100644 index 000000000..b19b3f0bb --- /dev/null +++ b/components/x-live-blog-post/src/LiveBlogPost.jsx @@ -0,0 +1,29 @@ +import { h } from '@financial-times/x-engine'; +import ShareButtons from './ShareButtons'; +import Timestamp from './Timestamp'; +import styles from './LiveBlogPost.scss'; + +const LiveBlogPost = (props) => { + const { + postId, + title, + content, + publishedTimestamp, + isBreakingNews, + articleUrl + } = props; + + return ( +
+
+ +
+ {isBreakingNews &&
Breaking news
} +

{title}

+
+ +
+ ); +}; + +export { LiveBlogPost }; diff --git a/components/x-content-block/src/ContentBlock.scss b/components/x-live-blog-post/src/LiveBlogPost.scss similarity index 75% rename from components/x-content-block/src/ContentBlock.scss rename to components/x-live-blog-post/src/LiveBlogPost.scss index 7f90c5abd..49ed73eb5 100644 --- a/components/x-content-block/src/ContentBlock.scss +++ b/components/x-live-blog-post/src/LiveBlogPost.scss @@ -2,60 +2,56 @@ @import 'o-spacing/main'; @import 'o-colors/main'; -.content-block { +.live-blog-post { border-bottom: 1px solid oColorsMix(black, paper, 20); margin-top: oSpacingByName('s8'); color: oColorsMix(black, paper, 90); } -.content-block__title { +.live-blog-post__title { @include oTypographyDisplay($scale: 5); margin-top: oSpacingByName('s4'); } -.content-block__breaking-news + .content-block__title { +.live-blog-post__breaking-news + .live-blog-post__title { margin-top: oSpacingByName('s1'); } -.content-block__body { +.live-blog-post__body { @include oTypographySerif($scale: 1, $line-height: 1.55); margin-top: oSpacingByName('s6'); } -.content-block__body ul { +.live-blog-post__body ul { @include oTypographyList('unordered'); } -.content-block__timestamp { +.live-blog-post__timestamp { @include oTypographySans($scale:0, $weight: 'semibold'); font-size: 14px; text-transform: uppercase; } -.content-block__timestamp-exact-time { +.live-blog-post__timestamp-exact-time { @include oTypographySans($scale:0, $weight: 'light'); font-size: 14px; color: oColorsMix(black, paper, 50); padding-left: oSpacingByName('s2'); } -.content-block__timestamp-exact-time-hidden { - display: none; -} - -.content-block__timestamp-container:after { +.live-blog-post__timestamp-container:after { content: ''; display: block; width: oSpacingByName('s4'); border-bottom: 4px solid oColorsMix(black, paper, 90); } -.content-block__share-buttons { +.live-blog-post__share-buttons { margin-top: oSpacingByName('s6'); margin-bottom: oSpacingByName('s8'); } -.content-block__breaking-news { +.live-blog-post__breaking-news { @include oTypographySans($scale:0); font-size: 12px; color: oColorsByName('crimson'); @@ -63,7 +59,7 @@ margin-top: oSpacingByName('s4'); } -.content-block__breaking-news:before { +.live-blog-post__breaking-news:before { content: ''; display: inline-block; width: oSpacingByName('s2'); diff --git a/components/x-content-block/src/ShareButtons.jsx b/components/x-live-blog-post/src/ShareButtons.jsx similarity index 95% rename from components/x-content-block/src/ShareButtons.jsx rename to components/x-live-blog-post/src/ShareButtons.jsx index 750fd5e01..3d05db6b6 100644 --- a/components/x-content-block/src/ShareButtons.jsx +++ b/components/x-live-blog-post/src/ShareButtons.jsx @@ -1,5 +1,5 @@ import { h } from '@financial-times/x-engine'; -import styles from './ContentBlock.scss'; +import styles from './LiveBlogPost.scss'; export default ({ postId, articleUrl, title }) => { const shareUrl = articleUrl ? new URL(articleUrl) : null; @@ -12,7 +12,7 @@ export default ({ postId, articleUrl, title }) => { const linkedInUrl = `http://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(shareUrl)}&title=${encodeURIComponent(title)}&source=Financial+Times`; return ( -
+
{ const now = new Date(); @@ -23,10 +23,10 @@ export default ({ publishedTimestamp }) => { } return ( -
+
); }; diff --git a/components/x-live-blog-post/storybook/index.jsx b/components/x-live-blog-post/storybook/index.jsx index 57521b0ed..0b59567d1 100644 --- a/components/x-live-blog-post/storybook/index.jsx +++ b/components/x-live-blog-post/storybook/index.jsx @@ -10,6 +10,7 @@ const defaultProps = { isBreakingNews: false, publishedTimestamp: '2020-05-13T18:52:28.000Z', articleUrl: 'https://www.ft.com/content/2b665ec7-a88f-3998-8f39-5371f9c791ed', + showShareButtons: true, }; const toggleTitle = () => text('Title', defaultProps.title); @@ -18,6 +19,7 @@ const toggleContent = () => text('Content', defaultProps.content); const togglePostId = () => text('Post ID', defaultProps.postId); const togglePublishedTimestamp = () => text('Published timestamp', defaultProps.publishedTimestamp); const toggleArticleUrl = () => text('Article URL', defaultProps.articleUrl); +const toggleShowShareButtons = () => boolean('Show share buttons', defaultProps.showShareButtons); storiesOf('x-live-blog-post', module) .addDecorator(withKnobs) @@ -34,6 +36,7 @@ storiesOf('x-live-blog-post', module) postId: togglePostId(), publishedTimestamp: togglePublishedTimestamp(), articleUrl: toggleArticleUrl(), + showShareButtons: toggleShowShareButtons(), }; return ; From f058595f8c22bfc5454f8d6df27d63ca0436bbee Mon Sep 17 00:00:00 2001 From: tbergmen <5130615+tbergmen@users.noreply.github.com> Date: Mon, 22 Jun 2020 14:12:46 +0100 Subject: [PATCH 33/36] Hide share buttons by default Share buttons will only show when `showShareButtons` flag is set explicitly. --- components/x-live-blog-post/src/LiveBlogPost.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/x-live-blog-post/src/LiveBlogPost.jsx b/components/x-live-blog-post/src/LiveBlogPost.jsx index 4e1b815f6..f12469081 100644 --- a/components/x-live-blog-post/src/LiveBlogPost.jsx +++ b/components/x-live-blog-post/src/LiveBlogPost.jsx @@ -11,7 +11,7 @@ const LiveBlogPost = (props) => { publishedTimestamp, isBreakingNews, articleUrl, - showShareButtons = true, + showShareButtons, } = props; return ( From efee2ac40055fda2c1c51e0c2501ced1fb195a5d Mon Sep 17 00:00:00 2001 From: tbergmen <5130615+tbergmen@users.noreply.github.com> Date: Mon, 22 Jun 2020 14:14:09 +0100 Subject: [PATCH 34/36] Add documentation about showShareButtons flag --- components/x-live-blog-post/readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/components/x-live-blog-post/readme.md b/components/x-live-blog-post/readme.md index dd219b1e5..acce4201c 100644 --- a/components/x-live-blog-post/readme.md +++ b/components/x-live-blog-post/readme.md @@ -44,3 +44,4 @@ Feature | Type | Notes `isBreakingNews` | Bool | When `true` displays "breaking news" tag `publishedTimestamp`| String | ISO timestamp of publish date `articleUrl` | String | Url of the main article that includes this post +`showShareButtons` | Bool | default: `false` - Shows social media share buttons when `true` From 7833595b805eacad39750be3a8af749bd3984cf3 Mon Sep 17 00:00:00 2001 From: tbergmen <5130615+tbergmen@users.noreply.github.com> Date: Mon, 22 Jun 2020 14:25:37 +0100 Subject: [PATCH 35/36] fix unit tests --- .../x-live-blog-post/src/__tests__/LiveBlogPost.test.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/x-live-blog-post/src/__tests__/LiveBlogPost.test.jsx b/components/x-live-blog-post/src/__tests__/LiveBlogPost.test.jsx index d69fa38da..bb03528ad 100644 --- a/components/x-live-blog-post/src/__tests__/LiveBlogPost.test.jsx +++ b/components/x-live-blog-post/src/__tests__/LiveBlogPost.test.jsx @@ -9,7 +9,8 @@ const breakingNews = { content: '

Test

', publishedTimestamp: new Date().toISOString(), isBreakingNews: true, - articleUrl: 'Https://www.ft.com' + articleUrl: 'Https://www.ft.com', + showShareButtons: true }; const regularPost = { @@ -18,7 +19,8 @@ const regularPost = { content: '

Test body

', publishedTimestamp: new Date().toISOString(), isBreakingNews: false, - articleUrl: 'Https://www.ft.com' + articleUrl: 'Https://www.ft.com', + showShareButtons: true } describe('x-live-blog-post', () => { From ff4af671daf2ee581e9e96676ea4123f82df3139 Mon Sep 17 00:00:00 2001 From: tbergmen <5130615+tbergmen@users.noreply.github.com> Date: Mon, 22 Jun 2020 14:34:07 +0100 Subject: [PATCH 36/36] Explicitly set the default value of showShareButtons property --- components/x-live-blog-post/src/LiveBlogPost.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/x-live-blog-post/src/LiveBlogPost.jsx b/components/x-live-blog-post/src/LiveBlogPost.jsx index f12469081..51e67f2f2 100644 --- a/components/x-live-blog-post/src/LiveBlogPost.jsx +++ b/components/x-live-blog-post/src/LiveBlogPost.jsx @@ -11,7 +11,7 @@ const LiveBlogPost = (props) => { publishedTimestamp, isBreakingNews, articleUrl, - showShareButtons, + showShareButtons = false, } = props; return (