@quintype/native-components 2.20.1-temp-fast-image-constraint.1 → 2.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +85 -0
- package/package.json +9 -10
- package/src/components/AuthorRow/index.js +18 -16
- package/src/components/CollectionCard/index.js +6 -1
- package/src/components/CollectionCardNew/index.js +5 -1
- package/src/components/CollectionTitleNew/styles.js +0 -1
- package/src/components/JSEmbedElement/index.js +3 -1
- package/src/components/PDFReader/styles.js +1 -0
- package/src/components/PrimaryStoryCard/index.js +21 -10
- package/src/components/PrimaryStoryCardNew/index.js +41 -30
- package/src/components/SecondaryStoryCard/index.js +20 -12
- package/src/components/SecondaryStoryCardNew/index.js +41 -32
- package/src/components/ShareButton/index.js +22 -17
- package/src/components/SlideshowStoryCard/styles.js +3 -2
- package/src/components/Story/index.js +14 -10
- package/src/components/StoryHeader/index.js +4 -2
- package/src/components/StoryHeader/styles.js +3 -1
- package/src/components/StoryImage/styles.js +2 -2
- package/src/components/StoryText/styles.js +2 -0
- package/src/components/TextBigFact/index.js +1 -2
- package/src/components/TextBigFact/styles.js +3 -0
- package/src/components/TextBlockQuote/index.js +5 -4
- package/src/components/TextBlockQuote/styles.js +8 -0
- package/src/components/TextBlurb/styles.js +2 -0
- package/src/components/TextQuote/styles.js +5 -2
- package/src/components/TextSummary/styles.js +2 -0
- package/src/components/YouTubePlayer/index.js +3 -7
- package/src/constants/component-constants/general-constants/constants.js +3 -0
- package/src/utils/parseUtils.js +0 -9
- package/src/utils/story.js +7 -3
- package/src/utils/timeUtils.js +13 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,91 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [2.20.2](https://github.com/quintype/native-components/compare/v2.20.1...v2.20.2) (2023-01-23)
|
|
6
|
+
|
|
7
|
+
### [2.20.1](https://github.com/quintype/native-components/compare/v2.20.0...v2.20.1) (2023-01-12)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
* **share:** Fixes share on Android v12 and above ([#194](https://github.com/quintype/native-components/issues/194)) ([bab63bf](https://github.com/quintype/native-components/commit/bab63bfccefe7648b0e16f01bb120772843e00e2))
|
|
13
|
+
|
|
14
|
+
## [2.20.0](https://github.com/quintype/native-components/compare/v2.19.28...v2.20.0) (2023-01-09)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* **enhancement:** Adds toggles for hideCollectionTitle, readTime, shareButton 🔧 ([#193](https://github.com/quintype/native-components/issues/193)) ([53fcafc](https://github.com/quintype/native-components/commit/53fcafc2d8546abb5eea1e36820dc37c22436644))
|
|
20
|
+
|
|
21
|
+
### [2.19.28](https://github.com/quintype/native-components/compare/v2.19.27...v2.19.28) (2022-12-28)
|
|
22
|
+
|
|
23
|
+
### [2.19.27](https://github.com/quintype/native-components/compare/v2.19.26...v2.19.27) (2022-12-16)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Bug Fixes
|
|
27
|
+
|
|
28
|
+
* **time-util:** Fix spacing for time-distance from now :hammer: ([67d9f37](https://github.com/quintype/native-components/commit/67d9f37459ee220f3c1ef1dd38b12ca7b65cf50e))
|
|
29
|
+
|
|
30
|
+
### [2.19.26](https://github.com/quintype/native-components/compare/v2.19.25...v2.19.26) (2022-12-16)
|
|
31
|
+
|
|
32
|
+
### [2.19.25](https://github.com/quintype/native-components/compare/v2.19.24...v2.19.25) (2022-12-07)
|
|
33
|
+
|
|
34
|
+
### [2.19.24](https://github.com/quintype/native-components/compare/v2.19.23...v2.19.24) (2022-12-06)
|
|
35
|
+
|
|
36
|
+
### [2.19.23](https://github.com/quintype/native-components/compare/v2.19.22...v2.19.23) (2022-12-06)
|
|
37
|
+
|
|
38
|
+
### [2.19.22](https://github.com/quintype/native-components/compare/v2.19.21...v2.19.22) (2022-12-06)
|
|
39
|
+
|
|
40
|
+
### [2.19.21](https://github.com/quintype/native-components/compare/v2.19.20...v2.19.21) (2022-11-18)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### Bug Fixes
|
|
44
|
+
|
|
45
|
+
* **fonts:** Fixes fonts for CollectionTitle and Caption/Attribution HTML 🔨 ([#188](https://github.com/quintype/native-components/issues/188)) ([94c61ff](https://github.com/quintype/native-components/commit/94c61ff385df2225f6a3d1b14c1f5d2ce3a1ed89))
|
|
46
|
+
|
|
47
|
+
### [2.19.20](https://github.com/quintype/native-components/compare/v2.19.19...v2.19.20) (2022-11-07)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
### Bug Fixes
|
|
51
|
+
|
|
52
|
+
* **android:** Fixes Nov 4 critical issue that breaks Android :hammer: ([e6d6c27](https://github.com/quintype/native-components/commit/e6d6c27e55ddbe9542ef3c7733273e4bbe9a1aa2))
|
|
53
|
+
|
|
54
|
+
### [2.19.19](https://github.com/quintype/native-components/compare/v2.19.18...v2.19.19) (2022-08-24)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
### Bug Fixes
|
|
58
|
+
|
|
59
|
+
* **Ads:** Change midcontentAd logic for video-story :hammer: ([#186](https://github.com/quintype/native-components/issues/186)) ([b04a16c](https://github.com/quintype/native-components/commit/b04a16cb74f06c3a3f5639df31b39b2ecd4b6704))
|
|
60
|
+
* **deps:** Fixes dependency-conflict due to incorrect react-native version :hammer: ([b43e8ae](https://github.com/quintype/native-components/commit/b43e8ae0e4cf92d3fce21336c3cdd6c2d73db582))
|
|
61
|
+
|
|
62
|
+
### [2.19.18](https://github.com/quintype/native-components/compare/v2.19.17...v2.19.18) (2022-07-04)
|
|
63
|
+
|
|
64
|
+
### [2.19.17](https://github.com/quintype/native-components/compare/v2.19.14...v2.19.17) (2022-06-29)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
### Bug Fixes
|
|
68
|
+
|
|
69
|
+
* **story-page:** Fixes crash if image-metadata is null 🔨 ([#184](https://github.com/quintype/native-components/issues/184)) ([8f703d1](https://github.com/quintype/native-components/commit/8f703d19c90c4a5c7844e2251c6691263f9b3d4b))
|
|
70
|
+
* **story-template:** Fixed story-template-icon color :hammer: ([#182](https://github.com/quintype/native-components/issues/182)) ([95f750d](https://github.com/quintype/native-components/commit/95f750d7df5f7cc400095317be26900c0cffd3e1))
|
|
71
|
+
|
|
72
|
+
### [2.19.16](https://github.com/quintype/native-components/compare/v2.19.15...v2.19.16) (2022-05-09)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
### Bug Fixes
|
|
76
|
+
|
|
77
|
+
* **story-template:** Fixed story-template-icon color :hammer: ([#182](https://github.com/quintype/native-components/issues/182)) ([95f750d](https://github.com/quintype/native-components/commit/95f750d7df5f7cc400095317be26900c0cffd3e1))
|
|
78
|
+
|
|
79
|
+
### [2.19.15](https://github.com/quintype/native-components/compare/v2.19.14...v2.19.15) (2022-04-12)
|
|
80
|
+
|
|
81
|
+
### [2.19.14](https://github.com/quintype/native-components/compare/v2.19.7...v2.19.14) (2022-04-04)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
### Bug Fixes
|
|
85
|
+
|
|
86
|
+
* **story-cards:** Adds missing translations, fixes text overflow issue by adding multiline ([#179](https://github.com/quintype/native-components/issues/179)) ([93ab137](https://github.com/quintype/native-components/commit/93ab1372fad312b653e5d6d6992d625d217c9455))
|
|
87
|
+
|
|
88
|
+
### [2.19.12](https://github.com/quintype/native-components/compare/v2.19.11...v2.19.12) (2022-02-08)
|
|
89
|
+
|
|
5
90
|
### [2.19.11](https://github.com/quintype/native-components/compare/v2.19.9...v2.19.11) (2022-01-24)
|
|
6
91
|
|
|
7
92
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quintype/native-components",
|
|
3
|
-
"version": "2.20.
|
|
3
|
+
"version": "2.20.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -17,24 +17,23 @@
|
|
|
17
17
|
"prop-types": "15.7.2",
|
|
18
18
|
"quintype-js": "1.2.1",
|
|
19
19
|
"react-htmltext": "^0.40.2",
|
|
20
|
-
"react-native-fast-image": "
|
|
20
|
+
"react-native-fast-image": "8.3.2",
|
|
21
21
|
"react-native-image-pan-zoom": "^2.1.12",
|
|
22
22
|
"react-native-lightbox": "0.8.1",
|
|
23
23
|
"react-native-pdf": "^5.1.4",
|
|
24
|
-
"react-native-share": "^3.7.0",
|
|
25
24
|
"react-native-render-html": "^4.2.3",
|
|
25
|
+
"react-native-share": "^8.1.0",
|
|
26
26
|
"react-native-vector-icons": "^7.0.0",
|
|
27
|
-
"react-native-webview": "^10.6.0",
|
|
28
27
|
"rn-fetch-blob": "^0.10.16"
|
|
29
28
|
},
|
|
30
29
|
"peerDependencies": {
|
|
31
30
|
"@react-navigation/native": ">=5.7.3",
|
|
32
31
|
"lodash": ">=4.17.20",
|
|
33
|
-
"react": ">=
|
|
34
|
-
"react-native": ">=0.
|
|
32
|
+
"react": ">=17.0.2",
|
|
33
|
+
"react-native": ">=0.67.5",
|
|
35
34
|
"react-native-fast-image": ">=8.3.2",
|
|
36
35
|
"react-native-pdf": ">=6.2.0",
|
|
37
|
-
"react-native-webview": ">=
|
|
36
|
+
"react-native-webview": ">=11.0.0",
|
|
38
37
|
"rn-fetch-blob": ">=0.12.0"
|
|
39
38
|
},
|
|
40
39
|
"devDependencies": {
|
|
@@ -54,11 +53,11 @@
|
|
|
54
53
|
"husky": "^4.2.5",
|
|
55
54
|
"jest": "^26.4.0",
|
|
56
55
|
"metro-react-native-babel-preset": "^0.62.0",
|
|
57
|
-
"react": "
|
|
58
|
-
"react-native": "
|
|
56
|
+
"react": "17.0.2",
|
|
57
|
+
"react-native": "0.67.4",
|
|
59
58
|
"react-native-device-info": "^5.6.5",
|
|
60
59
|
"react-native-gesture-handler": "^1.9.0",
|
|
61
|
-
"react-native-svg": "^12.
|
|
60
|
+
"react-native-svg": "^12.3.0",
|
|
62
61
|
"react-navigation-hooks": "^1.1.0",
|
|
63
62
|
"react-test-renderer": "16.13.1"
|
|
64
63
|
},
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import PropTypes from
|
|
2
|
-
import React, { useContext } from
|
|
3
|
-
import { View } from
|
|
4
|
-
import Icon from
|
|
5
|
-
import { ResponsiveImage, Text } from
|
|
6
|
-
import { ActionText } from
|
|
1
|
+
import PropTypes from 'prop-types';
|
|
2
|
+
import React, { useContext } from 'react';
|
|
3
|
+
import { View } from 'react-native';
|
|
4
|
+
import Icon from 'react-native-vector-icons/FontAwesome';
|
|
5
|
+
import { ResponsiveImage, Text } from '../index';
|
|
6
|
+
import { ActionText } from '../ActionText/ActionText';
|
|
7
7
|
|
|
8
|
-
import { authorRowStyleSheet } from
|
|
9
|
-
import { AppTheme } from
|
|
10
|
-
import { COMP_CONTENT_CONSTANTS } from
|
|
8
|
+
import { authorRowStyleSheet } from './styles';
|
|
9
|
+
import { AppTheme } from '../../utils';
|
|
10
|
+
import { COMP_CONTENT_CONSTANTS } from '../../constants/component-constants/content-constants/constants';
|
|
11
11
|
|
|
12
12
|
export const AuthorRow = ({
|
|
13
13
|
authors,
|
|
@@ -18,7 +18,7 @@ export const AuthorRow = ({
|
|
|
18
18
|
disablePress,
|
|
19
19
|
}) => {
|
|
20
20
|
const { theme } = useContext(AppTheme);
|
|
21
|
-
const { COLORS, translate } = theme;
|
|
21
|
+
const { COLORS, translate, enableReadTimeOnStoryScreen } = theme;
|
|
22
22
|
const styles = authorRowStyleSheet(theme);
|
|
23
23
|
|
|
24
24
|
return (
|
|
@@ -33,10 +33,10 @@ export const AuthorRow = ({
|
|
|
33
33
|
style={styles.imageBlock}
|
|
34
34
|
testID={COMP_CONTENT_CONSTANTS.authorImage}
|
|
35
35
|
>
|
|
36
|
-
{author?.[
|
|
36
|
+
{author?.['avatar-s3-key'] ? (
|
|
37
37
|
<ResponsiveImage
|
|
38
38
|
source={{
|
|
39
|
-
uri: `${cdn}/${author?.[
|
|
39
|
+
uri: `${cdn}/${author?.['avatar-s3-key']}`,
|
|
40
40
|
}}
|
|
41
41
|
style={styles.avatarImage}
|
|
42
42
|
imageWidth={50}
|
|
@@ -70,11 +70,13 @@ export const AuthorRow = ({
|
|
|
70
70
|
</View>
|
|
71
71
|
);
|
|
72
72
|
})}
|
|
73
|
-
{readtime ? (
|
|
73
|
+
{enableReadTimeOnStoryScreen && readtime ? (
|
|
74
74
|
<View style={styles.readtimeComponent}>
|
|
75
|
-
<Text style={styles.readtime}>
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
<Text style={styles.readtime}>
|
|
76
|
+
{`| ${readtime} ${translate(
|
|
77
|
+
'min read',
|
|
78
|
+
)}`}
|
|
79
|
+
</Text>
|
|
78
80
|
</View>
|
|
79
81
|
) : null}
|
|
80
82
|
</View>
|
|
@@ -17,17 +17,21 @@ export const CollectionCard = ({
|
|
|
17
17
|
onStoryPress,
|
|
18
18
|
offset,
|
|
19
19
|
horizontalPadding,
|
|
20
|
-
initialOffset /* Number of items to load on first load
|
|
20
|
+
initialOffset, /* Number of items to load on first load */
|
|
21
|
+
hideCollectionTitle,
|
|
21
22
|
}) => {
|
|
22
23
|
const sliceLimit = offset || initialOffset || 5;
|
|
23
24
|
const primaryStory = !isEmpty(stories) && get(stories, [0, 'story'], stories[0]);
|
|
24
25
|
return (
|
|
25
26
|
<>
|
|
27
|
+
{!hideCollectionTitle
|
|
28
|
+
&& (
|
|
26
29
|
<CollectionTitle
|
|
27
30
|
title={collectionName}
|
|
28
31
|
onPress={onCollectionPress}
|
|
29
32
|
horizontalPadding={horizontalPadding}
|
|
30
33
|
/>
|
|
34
|
+
)}
|
|
31
35
|
<PrimaryStoryCard
|
|
32
36
|
onPress={() => {
|
|
33
37
|
!isEmpty(stories) && onStoryPress(primaryStory);
|
|
@@ -62,6 +66,7 @@ CollectionCard.propTypes = {
|
|
|
62
66
|
onStoryPress: PropTypes.func,
|
|
63
67
|
offset: PropTypes.number,
|
|
64
68
|
horizontalPadding: PropTypes.number,
|
|
69
|
+
hideCollectionTitle: PropTypes.bool,
|
|
65
70
|
};
|
|
66
71
|
|
|
67
72
|
CollectionCard.defaultProps = {
|
|
@@ -19,18 +19,21 @@ const CollectionCardNewBase = ({
|
|
|
19
19
|
collectionTestID,
|
|
20
20
|
offset,
|
|
21
21
|
horizontalPadding,
|
|
22
|
-
initialOffset /* Number of items to load on first load
|
|
22
|
+
initialOffset, /* Number of items to load on first load */
|
|
23
|
+
hideCollectionTitle,
|
|
23
24
|
}) => {
|
|
24
25
|
const sliceLimit = offset || initialOffset || 5;
|
|
25
26
|
const primaryStory = !isEmpty(stories) && get(stories, [0, 'story'], stories[0]);
|
|
26
27
|
|
|
27
28
|
return (
|
|
28
29
|
<>
|
|
30
|
+
{!hideCollectionTitle && (
|
|
29
31
|
<CollectionTitleNew
|
|
30
32
|
title={collectionName}
|
|
31
33
|
onPress={onCollectionPress}
|
|
32
34
|
horizontalPadding={horizontalPadding}
|
|
33
35
|
/>
|
|
36
|
+
)}
|
|
34
37
|
<PrimaryStoryCardNew
|
|
35
38
|
collectionTestID={collectionTestID}
|
|
36
39
|
onPress={() => {
|
|
@@ -71,6 +74,7 @@ CollectionCardNewBase.propTypes = {
|
|
|
71
74
|
onStoryPress: PropTypes.func,
|
|
72
75
|
collectionTestID: PropTypes.string,
|
|
73
76
|
horizontalPadding: PropTypes.number,
|
|
77
|
+
hideCollectionTitle: PropTypes.bool,
|
|
74
78
|
};
|
|
75
79
|
|
|
76
80
|
CollectionCardNewBase.defaultProps = {
|
|
@@ -81,7 +81,9 @@ export const JSEmbedElement = (props) => {
|
|
|
81
81
|
<View testID="embed-js">
|
|
82
82
|
<WebView
|
|
83
83
|
ref={webViewRef}
|
|
84
|
-
style={{
|
|
84
|
+
style={{
|
|
85
|
+
width, height, flex: 0, opacity: 0.99,
|
|
86
|
+
}}
|
|
85
87
|
automaticallyAdjustContentInsets={false}
|
|
86
88
|
scrollEnabled={false}
|
|
87
89
|
onMessage={handleOnMessage}
|
|
@@ -2,9 +2,7 @@ import { throttle } from 'lodash';
|
|
|
2
2
|
import get from 'lodash/get';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import React, { useContext } from 'react';
|
|
5
|
-
import {
|
|
6
|
-
StyleSheet, TouchableOpacity, View,
|
|
7
|
-
} from 'react-native';
|
|
5
|
+
import { StyleSheet, TouchableOpacity, View } from 'react-native';
|
|
8
6
|
import Icon from 'react-native-vector-icons/FontAwesome';
|
|
9
7
|
import {
|
|
10
8
|
AppTheme,
|
|
@@ -15,7 +13,10 @@ import {
|
|
|
15
13
|
import { getStoryHeadline } from '../../utils/story';
|
|
16
14
|
import { ResponsiveImage, Text } from '../index';
|
|
17
15
|
import { storyStyles } from './styles';
|
|
18
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
COMP_GENERAL_CONSTANTS,
|
|
18
|
+
COMP_CONTENT_CONSTANTS,
|
|
19
|
+
} from '../../constants/component-constants';
|
|
19
20
|
|
|
20
21
|
export const PrimaryStoryCard = (props) => {
|
|
21
22
|
const { story = {} } = props;
|
|
@@ -23,7 +24,13 @@ export const PrimaryStoryCard = (props) => {
|
|
|
23
24
|
|
|
24
25
|
const translate = get(theme, ['translate'], (word) => word);
|
|
25
26
|
|
|
26
|
-
const {
|
|
27
|
+
const {
|
|
28
|
+
COLORS,
|
|
29
|
+
FONT_SIZE,
|
|
30
|
+
locale,
|
|
31
|
+
reverseTimeAdverbPosition,
|
|
32
|
+
enableReadTimeOnStoryCards,
|
|
33
|
+
} = theme || {};
|
|
27
34
|
|
|
28
35
|
const DATE_FORMAT = 'd MMM, yyyy';
|
|
29
36
|
|
|
@@ -43,7 +50,9 @@ export const PrimaryStoryCard = (props) => {
|
|
|
43
50
|
|
|
44
51
|
const name = get(story.authors, [0, 'name']);
|
|
45
52
|
const authorName = name ? `${translate('By')} ${name} | ` : '';
|
|
46
|
-
const readTime =
|
|
53
|
+
const readTime = enableReadTimeOnStoryCards && story['read-time']
|
|
54
|
+
? `${story['read-time']} ${translate('min read')}`
|
|
55
|
+
: '';
|
|
47
56
|
|
|
48
57
|
const throttledOnpress = throttle(props.onPress, 1000);
|
|
49
58
|
|
|
@@ -100,13 +109,15 @@ export const PrimaryStoryCard = (props) => {
|
|
|
100
109
|
style={autorStyle}
|
|
101
110
|
numberOfLines={2}
|
|
102
111
|
// TODO: Add corrected testID here
|
|
112
|
+
testID={COMP_CONTENT_CONSTANTS.authorName}
|
|
103
113
|
>
|
|
104
|
-
{authorName
|
|
105
|
-
getTimeForStoryCards(
|
|
106
|
-
story[
|
|
114
|
+
{authorName
|
|
115
|
+
+ getTimeForStoryCards(
|
|
116
|
+
story['published-at'],
|
|
107
117
|
DATE_FORMAT,
|
|
108
118
|
locale,
|
|
109
|
-
translate
|
|
119
|
+
translate,
|
|
120
|
+
reverseTimeAdverbPosition,
|
|
110
121
|
)}
|
|
111
122
|
</Text>
|
|
112
123
|
<Text
|
|
@@ -1,25 +1,35 @@
|
|
|
1
|
-
import { get, throttle } from
|
|
2
|
-
import PropTypes from
|
|
3
|
-
import React, { useContext, memo } from
|
|
4
|
-
import { StyleSheet, TouchableOpacity, View } from
|
|
5
|
-
import Icon from
|
|
1
|
+
import { get, throttle } from 'lodash';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import React, { useContext, memo } from 'react';
|
|
4
|
+
import { StyleSheet, TouchableOpacity, View } from 'react-native';
|
|
5
|
+
import Icon from 'react-native-vector-icons/FontAwesome';
|
|
6
6
|
import {
|
|
7
7
|
AppTheme,
|
|
8
8
|
getImageMetadata,
|
|
9
9
|
getImageSlug,
|
|
10
10
|
getTimeForStoryCards,
|
|
11
|
-
} from
|
|
12
|
-
import { getStoryHeadline } from
|
|
13
|
-
import { ResponsiveImage, Text } from
|
|
14
|
-
import { storyStyles } from
|
|
15
|
-
import {
|
|
11
|
+
} from '../../utils';
|
|
12
|
+
import { getStoryHeadline } from '../../utils/story';
|
|
13
|
+
import { ResponsiveImage, Text } from '../index';
|
|
14
|
+
import { storyStyles } from './styles';
|
|
15
|
+
import {
|
|
16
|
+
COMP_GENERAL_CONSTANTS,
|
|
17
|
+
COMP_CONTENT_CONSTANTS,
|
|
18
|
+
} from '../../constants/component-constants';
|
|
16
19
|
|
|
17
20
|
const PrimaryStoryCardNewBase = (props) => {
|
|
18
21
|
const { story = {} } = props;
|
|
19
22
|
const { theme } = useContext(AppTheme);
|
|
20
|
-
const {
|
|
23
|
+
const {
|
|
24
|
+
COLORS,
|
|
25
|
+
FONT_SIZE,
|
|
26
|
+
locale,
|
|
27
|
+
DARK_MODE,
|
|
28
|
+
reverseTimeAdverbPosition,
|
|
29
|
+
enableReadTimeOnStoryCards,
|
|
30
|
+
} = theme || {};
|
|
21
31
|
|
|
22
|
-
const translate = get(theme, [
|
|
32
|
+
const translate = get(theme, ['translate'], (word) => word);
|
|
23
33
|
|
|
24
34
|
const styles = storyStyles(COLORS, FONT_SIZE, DARK_MODE);
|
|
25
35
|
const containerStyle = StyleSheet.flatten([
|
|
@@ -35,16 +45,16 @@ const PrimaryStoryCardNewBase = (props) => {
|
|
|
35
45
|
props.timestampStyle,
|
|
36
46
|
]);
|
|
37
47
|
|
|
38
|
-
const DATE_FORMAT =
|
|
39
|
-
const readTime = story[
|
|
40
|
-
? `${story[
|
|
41
|
-
:
|
|
48
|
+
const DATE_FORMAT = 'd MMM, yyyy';
|
|
49
|
+
const readTime = enableReadTimeOnStoryCards && story['read-time']
|
|
50
|
+
? `${story['read-time']} ${translate('min read')} · `
|
|
51
|
+
: '';
|
|
42
52
|
|
|
43
53
|
const throttledOnpress = throttle(props.onPress, 1000);
|
|
44
54
|
|
|
45
55
|
const showIcon = (name) => (
|
|
46
56
|
<View style={styles.storyType}>
|
|
47
|
-
<Icon name={name} size={22} color={COLORS.
|
|
57
|
+
<Icon name={name} size={22} color={COLORS.MONO7} />
|
|
48
58
|
</View>
|
|
49
59
|
);
|
|
50
60
|
|
|
@@ -55,14 +65,14 @@ const PrimaryStoryCardNewBase = (props) => {
|
|
|
55
65
|
</View>
|
|
56
66
|
);
|
|
57
67
|
const showStoryType = () => {
|
|
58
|
-
switch (story[
|
|
59
|
-
case
|
|
68
|
+
switch (story['story-template']) {
|
|
69
|
+
case 'text':
|
|
60
70
|
return null;
|
|
61
|
-
case
|
|
62
|
-
return showIcon(
|
|
63
|
-
case
|
|
64
|
-
return showIcon(
|
|
65
|
-
case
|
|
71
|
+
case 'photo':
|
|
72
|
+
return showIcon('photo');
|
|
73
|
+
case 'video':
|
|
74
|
+
return showIcon('play');
|
|
75
|
+
case 'live-blog':
|
|
66
76
|
return showLiveBlogIcon();
|
|
67
77
|
default:
|
|
68
78
|
null;
|
|
@@ -98,14 +108,15 @@ const PrimaryStoryCardNewBase = (props) => {
|
|
|
98
108
|
<Text
|
|
99
109
|
style={timestampStyle}
|
|
100
110
|
numberOfLines={2}
|
|
101
|
-
|
|
111
|
+
testID={COMP_CONTENT_CONSTANTS.publishedDate}
|
|
102
112
|
>
|
|
103
|
-
{readTime
|
|
104
|
-
getTimeForStoryCards(
|
|
105
|
-
story[
|
|
113
|
+
{readTime
|
|
114
|
+
+ getTimeForStoryCards(
|
|
115
|
+
story['published-at'],
|
|
106
116
|
DATE_FORMAT,
|
|
107
117
|
locale,
|
|
108
|
-
translate
|
|
118
|
+
translate,
|
|
119
|
+
reverseTimeAdverbPosition,
|
|
109
120
|
)}
|
|
110
121
|
</Text>
|
|
111
122
|
</View>
|
|
@@ -127,7 +138,7 @@ PrimaryStoryCardNewBase.propTypes = {
|
|
|
127
138
|
};
|
|
128
139
|
|
|
129
140
|
PrimaryStoryCardNewBase.defaultProps = {
|
|
130
|
-
cdn:
|
|
141
|
+
cdn: '',
|
|
131
142
|
horizontalPadding: 12,
|
|
132
143
|
};
|
|
133
144
|
|
|
@@ -20,13 +20,21 @@ import {
|
|
|
20
20
|
import { getStoryHeadline } from '../../utils/story';
|
|
21
21
|
import { ResponsiveImage, Text } from '../index';
|
|
22
22
|
import { secStoryCardStyles } from './styles';
|
|
23
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
COMP_GENERAL_CONSTANTS,
|
|
25
|
+
COMP_CONTENT_CONSTANTS,
|
|
26
|
+
} from '../../constants/component-constants';
|
|
24
27
|
|
|
25
28
|
export const SecondaryStoryCard = (props) => {
|
|
26
29
|
const { theme } = useContext(AppTheme);
|
|
27
30
|
const translate = get(theme, ['translate'], (word) => word);
|
|
28
31
|
|
|
29
|
-
const {
|
|
32
|
+
const {
|
|
33
|
+
locale,
|
|
34
|
+
COLORS,
|
|
35
|
+
reverseTimeAdverbPosition,
|
|
36
|
+
enableReadTimeOnStoryCards,
|
|
37
|
+
} = theme;
|
|
30
38
|
const styles = secStoryCardStyles(theme);
|
|
31
39
|
const { story = {} } = props;
|
|
32
40
|
|
|
@@ -45,13 +53,12 @@ export const SecondaryStoryCard = (props) => {
|
|
|
45
53
|
props.dateTextStyle,
|
|
46
54
|
]);
|
|
47
55
|
const iconStyles = StyleSheet.flatten([styles.iconStyles, props.iconStyle]);
|
|
48
|
-
|
|
49
|
-
styles.authorTextContainer,
|
|
50
|
-
props.authorTextContainer,
|
|
51
|
-
]);
|
|
56
|
+
|
|
52
57
|
const name = get(story.authors, [0, 'name']);
|
|
53
58
|
const authorName = name ? `${translate('By')} ${name} | ` : '';
|
|
54
|
-
const readTime =
|
|
59
|
+
const readTime = enableReadTimeOnStoryCards && story['read-time']
|
|
60
|
+
? `${story['read-time']} ${translate('min read')}`
|
|
61
|
+
: '';
|
|
55
62
|
|
|
56
63
|
const throttledOnpress = throttle(props.onPress, 1000);
|
|
57
64
|
|
|
@@ -119,14 +126,15 @@ export const SecondaryStoryCard = (props) => {
|
|
|
119
126
|
<Text
|
|
120
127
|
style={authorTextStyle}
|
|
121
128
|
numberOfLines={2}
|
|
122
|
-
|
|
129
|
+
testID={COMP_CONTENT_CONSTANTS.authorName}
|
|
123
130
|
>
|
|
124
|
-
{authorName
|
|
125
|
-
getTimeForStoryCards(
|
|
126
|
-
story[
|
|
131
|
+
{authorName
|
|
132
|
+
+ getTimeForStoryCards(
|
|
133
|
+
story['published-at'],
|
|
127
134
|
DATE_FORMAT,
|
|
128
135
|
locale,
|
|
129
|
-
translate
|
|
136
|
+
translate,
|
|
137
|
+
reverseTimeAdverbPosition,
|
|
130
138
|
)}
|
|
131
139
|
</Text>
|
|
132
140
|
<View style={iconStyles}>{props.iconComponent}</View>
|
|
@@ -1,32 +1,40 @@
|
|
|
1
|
-
import { get, throttle } from
|
|
2
|
-
import PropTypes from
|
|
3
|
-
import React, { useContext, memo } from
|
|
1
|
+
import { get, throttle } from 'lodash';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import React, { useContext, memo } from 'react';
|
|
4
4
|
import {
|
|
5
|
-
I18nManager,
|
|
6
5
|
StyleSheet,
|
|
7
6
|
TouchableOpacity,
|
|
8
7
|
View,
|
|
9
8
|
TextStyle,
|
|
10
9
|
TouchableOpacityProps,
|
|
11
|
-
} from
|
|
12
|
-
import Icon from
|
|
10
|
+
} from 'react-native';
|
|
11
|
+
import Icon from 'react-native-vector-icons/FontAwesome';
|
|
13
12
|
import {
|
|
14
13
|
AppTheme,
|
|
15
14
|
getImageMetadata,
|
|
16
15
|
getImageSlug,
|
|
17
16
|
getTimeForStoryCards,
|
|
18
|
-
} from
|
|
19
|
-
import { getStoryHeadline } from
|
|
20
|
-
import { ResponsiveImage, Text } from
|
|
21
|
-
import { storyStyles } from
|
|
22
|
-
import {
|
|
17
|
+
} from '../../utils';
|
|
18
|
+
import { getStoryHeadline } from '../../utils/story';
|
|
19
|
+
import { ResponsiveImage, Text } from '../index';
|
|
20
|
+
import { storyStyles } from './styles';
|
|
21
|
+
import {
|
|
22
|
+
COMP_GENERAL_CONSTANTS,
|
|
23
|
+
COMP_CONTENT_CONSTANTS,
|
|
24
|
+
} from '../../constants/component-constants';
|
|
23
25
|
|
|
24
26
|
const SecondaryStoryCardNewBase = (props) => {
|
|
25
27
|
const { story = {} } = props;
|
|
26
28
|
const { theme } = useContext(AppTheme);
|
|
27
|
-
const {
|
|
29
|
+
const {
|
|
30
|
+
locale,
|
|
31
|
+
DARK_MODE,
|
|
32
|
+
COLORS,
|
|
33
|
+
reverseTimeAdverbPosition,
|
|
34
|
+
enableReadTimeOnStoryCards,
|
|
35
|
+
} = theme;
|
|
28
36
|
|
|
29
|
-
const translate = get(theme, [
|
|
37
|
+
const translate = get(theme, ['translate'], (word) => word);
|
|
30
38
|
|
|
31
39
|
const styles = storyStyles(theme, DARK_MODE);
|
|
32
40
|
const containerStyle = StyleSheet.flatten([
|
|
@@ -42,10 +50,10 @@ const SecondaryStoryCardNewBase = (props) => {
|
|
|
42
50
|
props.timestampStyle,
|
|
43
51
|
]);
|
|
44
52
|
|
|
45
|
-
const DATE_FORMAT =
|
|
46
|
-
const readTime = story[
|
|
47
|
-
? `${story[
|
|
48
|
-
:
|
|
53
|
+
const DATE_FORMAT = 'd MMM, yyyy';
|
|
54
|
+
const readTime = enableReadTimeOnStoryCards && story['read-time']
|
|
55
|
+
? `${story['read-time']} ${translate('min read')} · `
|
|
56
|
+
: '';
|
|
49
57
|
|
|
50
58
|
const throttledOnpress = throttle(props.onPress, 1000);
|
|
51
59
|
|
|
@@ -63,14 +71,14 @@ const SecondaryStoryCardNewBase = (props) => {
|
|
|
63
71
|
);
|
|
64
72
|
|
|
65
73
|
const showStoryType = () => {
|
|
66
|
-
switch (story[
|
|
67
|
-
case
|
|
74
|
+
switch (story['story-template']) {
|
|
75
|
+
case 'text':
|
|
68
76
|
return null;
|
|
69
|
-
case
|
|
70
|
-
return showIcon(
|
|
71
|
-
case
|
|
72
|
-
return showIcon(
|
|
73
|
-
case
|
|
77
|
+
case 'photo':
|
|
78
|
+
return showIcon('photo');
|
|
79
|
+
case 'video':
|
|
80
|
+
return showIcon('play');
|
|
81
|
+
case 'live-blog':
|
|
74
82
|
return showLiveBlogIcon();
|
|
75
83
|
default:
|
|
76
84
|
null;
|
|
@@ -86,8 +94,8 @@ const SecondaryStoryCardNewBase = (props) => {
|
|
|
86
94
|
>
|
|
87
95
|
<ResponsiveImage
|
|
88
96
|
metaData={getImageMetadata(story)}
|
|
89
|
-
slug={getImageSlug(story) ||
|
|
90
|
-
cdn={props.cdn ||
|
|
97
|
+
slug={getImageSlug(story) || ''}
|
|
98
|
+
cdn={props.cdn || ''}
|
|
91
99
|
imageWidth={props.imageWidth}
|
|
92
100
|
>
|
|
93
101
|
<View style={styles.storyTypeContainer}>{showStoryType()}</View>
|
|
@@ -106,13 +114,15 @@ const SecondaryStoryCardNewBase = (props) => {
|
|
|
106
114
|
style={timestampStyle}
|
|
107
115
|
numberOfLines={2}
|
|
108
116
|
// TODO: Add corrected testID here
|
|
117
|
+
testID={COMP_CONTENT_CONSTANTS.publishedDate}
|
|
109
118
|
>
|
|
110
|
-
{readTime
|
|
111
|
-
getTimeForStoryCards(
|
|
112
|
-
story[
|
|
119
|
+
{readTime
|
|
120
|
+
+ getTimeForStoryCards(
|
|
121
|
+
story['published-at'],
|
|
113
122
|
DATE_FORMAT,
|
|
114
123
|
locale,
|
|
115
|
-
translate
|
|
124
|
+
translate,
|
|
125
|
+
reverseTimeAdverbPosition,
|
|
116
126
|
)}
|
|
117
127
|
</Text>
|
|
118
128
|
</View>
|
|
@@ -127,13 +137,12 @@ SecondaryStoryCardNewBase.propTypes = TouchableOpacityProps && {
|
|
|
127
137
|
headlineStyle: TextStyle,
|
|
128
138
|
timestampStyle: TextStyle,
|
|
129
139
|
story: PropTypes.any.isRequired,
|
|
130
|
-
collectionTestID: PropTypes.string,
|
|
131
140
|
iconComponent: PropTypes.element,
|
|
132
141
|
horizontalPadding: PropTypes.number,
|
|
133
142
|
};
|
|
134
143
|
|
|
135
144
|
SecondaryStoryCardNewBase.defaultProps = {
|
|
136
|
-
cdn:
|
|
145
|
+
cdn: '',
|
|
137
146
|
horizontalPadding: 12,
|
|
138
147
|
};
|
|
139
148
|
|
|
@@ -1,28 +1,29 @@
|
|
|
1
|
-
import React, { useContext, memo } from
|
|
2
|
-
import { TouchableOpacity } from
|
|
3
|
-
import PropTypes from
|
|
4
|
-
import Icon from
|
|
5
|
-
import Share from
|
|
6
|
-
import { AppTheme } from
|
|
7
|
-
import { shareButtonStyles } from
|
|
8
|
-
import { getStoryHeadline } from
|
|
9
|
-
import { COMP_GENERAL_CONSTANTS } from
|
|
1
|
+
import React, { useContext, memo } from 'react';
|
|
2
|
+
import { TouchableOpacity } from 'react-native';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import Icon from 'react-native-vector-icons/Ionicons';
|
|
5
|
+
import Share from 'react-native-share';
|
|
6
|
+
import { AppTheme } from '../../utils';
|
|
7
|
+
import { shareButtonStyles } from './styles';
|
|
8
|
+
import { getStoryHeadline } from '../../utils/story';
|
|
9
|
+
import { COMP_GENERAL_CONSTANTS } from '../../constants/component-constants';
|
|
10
10
|
|
|
11
11
|
const ShareButtonBase = (props) => {
|
|
12
12
|
const { theme } = useContext(AppTheme);
|
|
13
13
|
const styles = shareButtonStyles(theme);
|
|
14
|
-
const {
|
|
14
|
+
const { enableShareOnStoryCards } = theme;
|
|
15
|
+
const { story, type = 'story', slug } = props;
|
|
15
16
|
|
|
16
17
|
const getShareURL = () => {
|
|
17
18
|
const { url } = story || {};
|
|
18
19
|
switch (type) {
|
|
19
|
-
case
|
|
20
|
+
case 'story':
|
|
20
21
|
return url;
|
|
21
|
-
case
|
|
22
|
+
case 'card':
|
|
22
23
|
return `${url}${slug}`;
|
|
23
|
-
case
|
|
24
|
+
case 'image':
|
|
24
25
|
return `${url}${slug}`;
|
|
25
|
-
case
|
|
26
|
+
case 'attachment':
|
|
26
27
|
return slug;
|
|
27
28
|
default:
|
|
28
29
|
return url || slug;
|
|
@@ -35,7 +36,11 @@ const ShareButtonBase = (props) => {
|
|
|
35
36
|
Share.open({
|
|
36
37
|
message: `${getStoryHeadline(story)} | ${shareURL}`,
|
|
37
38
|
title: getStoryHeadline(story),
|
|
38
|
-
})
|
|
39
|
+
})
|
|
40
|
+
.then(() => {})
|
|
41
|
+
.catch((err) => {
|
|
42
|
+
err && console.log(err);
|
|
43
|
+
});
|
|
39
44
|
}
|
|
40
45
|
};
|
|
41
46
|
|
|
@@ -43,14 +48,14 @@ const ShareButtonBase = (props) => {
|
|
|
43
48
|
return null;
|
|
44
49
|
}
|
|
45
50
|
|
|
46
|
-
return (
|
|
51
|
+
return enableShareOnStoryCards ? (
|
|
47
52
|
<TouchableOpacity
|
|
48
53
|
onPress={share}
|
|
49
54
|
testID={COMP_GENERAL_CONSTANTS.shareButtonTouch}
|
|
50
55
|
>
|
|
51
56
|
<Icon style={styles.iconStyle} name="share-social-outline" size={20} />
|
|
52
57
|
</TouchableOpacity>
|
|
53
|
-
);
|
|
58
|
+
) : null;
|
|
54
59
|
};
|
|
55
60
|
|
|
56
61
|
ShareButtonBase.propTypes = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StyleSheet, Dimensions } from 'react-native';
|
|
2
|
-
|
|
2
|
+
import { COMP_GENERAL_CONSTANTS } from '../../constants/component-constants/general-constants/constants'
|
|
3
3
|
const { width } = Dimensions.get('window');
|
|
4
4
|
|
|
5
5
|
export const slideshowStoryCardStyles = ({ COLORS }) => {
|
|
@@ -21,7 +21,8 @@ export const slideshowStoryCardStyles = ({ COLORS }) => {
|
|
|
21
21
|
flexDirection: 'column',
|
|
22
22
|
},
|
|
23
23
|
attributionText: {
|
|
24
|
-
color: COLORS.BRAND_BLACK
|
|
24
|
+
color: COLORS.BRAND_BLACK,
|
|
25
|
+
textAlign : COMP_GENERAL_CONSTANTS.textAlignment
|
|
25
26
|
}
|
|
26
27
|
})
|
|
27
28
|
}
|
|
@@ -47,7 +47,7 @@ const getLiveBlogTimeStamp = (card, DATE_FORMAT, share, styles, locale) => {
|
|
|
47
47
|
|
|
48
48
|
/* Mutate the data during access check to limit the content shown */
|
|
49
49
|
const mutateDataBeforeAccess = (item, storyHasAccess) => {
|
|
50
|
-
if (isStoryFree(item)) {
|
|
50
|
+
if (isStoryFree(item) === 0 || storyHasAccess === 'granted') {
|
|
51
51
|
return item;
|
|
52
52
|
}
|
|
53
53
|
if (storyHasAccess !== 'loading' && storyHasAccess === 'granted') {
|
|
@@ -55,7 +55,7 @@ const mutateDataBeforeAccess = (item, storyHasAccess) => {
|
|
|
55
55
|
}
|
|
56
56
|
/* The following steps are necessary to keep argument mutation at bay */
|
|
57
57
|
const firstCardObject = get(item, ['cards', 0], {});
|
|
58
|
-
const firstCardElement = get(firstCardObject, ['story-elements', 0], {});
|
|
58
|
+
const firstCardElement = get(firstCardObject, !STORY_TYPES.VIDEO_STORY && ['story-elements', 0], {});
|
|
59
59
|
|
|
60
60
|
return {
|
|
61
61
|
...item,
|
|
@@ -119,8 +119,11 @@ const getStoryCards = (
|
|
|
119
119
|
)}
|
|
120
120
|
{/* Skip first card if it's a listicle */}
|
|
121
121
|
|
|
122
|
-
{source.length >
|
|
123
|
-
|
|
122
|
+
{source.length > (storyType === STORY_TYPES.VIDEO_STORY ? 2 : 1)
|
|
123
|
+
&& isMiddleIndexOfArray(index, source)
|
|
124
|
+
&& getAd(true)}
|
|
125
|
+
{/* ^ Requesting mid-content-ad if there are > 1 card
|
|
126
|
+
(> 2 cards in case of video story since the 1st card gets rendered in header). */}
|
|
124
127
|
|
|
125
128
|
{(card['story-elements'] || []).map((storyElement, index, source) => {
|
|
126
129
|
/* Skip the first video element for video story */
|
|
@@ -129,10 +132,12 @@ const getStoryCards = (
|
|
|
129
132
|
return (
|
|
130
133
|
<>
|
|
131
134
|
{cards.length === 1
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
{/* ^
|
|
135
|
+
&& source.length > (storyType === STORY_TYPES.VIDEO_STORY ? 2 : 1)
|
|
136
|
+
&& isMiddleIndexOfArray(index, source)
|
|
137
|
+
&& getAd(true)}
|
|
138
|
+
{/* ^ In the case of a story having just 1 card,
|
|
139
|
+
requesting mid-content-Ad if there are > 1 story-elements in that card
|
|
140
|
+
(> 2 story-elements in case of video story since the 1st story-element gets rendered in header). */}
|
|
136
141
|
|
|
137
142
|
<StoryContent
|
|
138
143
|
testID={contentTestID}
|
|
@@ -194,9 +199,8 @@ export const Story = ({
|
|
|
194
199
|
|
|
195
200
|
const shouldShowComments = () => {
|
|
196
201
|
if (!enableFbComments) return null;
|
|
197
|
-
|
|
198
202
|
if (
|
|
199
|
-
isStoryFree(story)
|
|
203
|
+
isStoryFree(story) === 0
|
|
200
204
|
|| (storyHasAccess !== 'loading' && storyHasAccess === 'granted')
|
|
201
205
|
) {
|
|
202
206
|
return (
|
|
@@ -69,8 +69,10 @@ export const StoryHeader = (props) => {
|
|
|
69
69
|
const { story } = props;
|
|
70
70
|
const sectionData = get(story, ['sections', 0], {});
|
|
71
71
|
const { theme } = useContext(AppTheme);
|
|
72
|
-
const {
|
|
73
|
-
|
|
72
|
+
const {
|
|
73
|
+
COLORS, CAN_COPY_TEXT, locale, FONT_FAMILY,
|
|
74
|
+
} = theme;
|
|
75
|
+
const styles = storyHeaderStyles(COLORS, FONT_FAMILY);
|
|
74
76
|
const imgCaption = story['hero-image-caption'];
|
|
75
77
|
const attri = story['hero-image-attribution'];
|
|
76
78
|
const imgAttribution = imgCaption && attri ? ` | ${attri}` : attri;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
2
|
|
|
3
|
-
export const storyHeaderStyles = (COLORS) => StyleSheet.create({
|
|
3
|
+
export const storyHeaderStyles = (COLORS, FONT_FAMILY) => StyleSheet.create({
|
|
4
4
|
tagStyle: {
|
|
5
5
|
padding: 10,
|
|
6
6
|
backgroundColor: COLORS.BRAND_7,
|
|
@@ -29,10 +29,12 @@ export const storyHeaderStyles = (COLORS) => StyleSheet.create({
|
|
|
29
29
|
padding: 10,
|
|
30
30
|
paddingBottom: 0,
|
|
31
31
|
color: COLORS.BRAND_BLACK,
|
|
32
|
+
fontFamily: FONT_FAMILY.secondary,
|
|
32
33
|
opacity: 0.8,
|
|
33
34
|
},
|
|
34
35
|
attributionStyle: {
|
|
35
36
|
color: COLORS.BRAND_BLACK,
|
|
37
|
+
fontFamily: FONT_FAMILY.secondary,
|
|
36
38
|
opacity: 0.8,
|
|
37
39
|
},
|
|
38
40
|
captionContainerStyle: {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
2
|
import { getImageHeight } from '../../utils';
|
|
3
3
|
|
|
4
|
-
export const storyImageStyles = ({ COLORS, FONT_SIZE }, metadata) => {
|
|
5
|
-
const { width, height } = metadata;
|
|
4
|
+
export const storyImageStyles = ({ COLORS, FONT_SIZE }, metadata = {}) => {
|
|
5
|
+
const { width, height } = metadata || {};
|
|
6
6
|
const imageHeight = getImageHeight(width, height);
|
|
7
7
|
|
|
8
8
|
return StyleSheet.create({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { COMP_GENERAL_CONSTANTS } from '../../constants/component-constants/general-constants/constants';
|
|
2
3
|
|
|
3
4
|
export const storyTextStyles = (COLORS, FONT_SIZE) => StyleSheet.create({
|
|
4
5
|
container: {
|
|
@@ -8,5 +9,6 @@ export const storyTextStyles = (COLORS, FONT_SIZE) => StyleSheet.create({
|
|
|
8
9
|
fontSize: FONT_SIZE.h2,
|
|
9
10
|
lineHeight: FONT_SIZE.h2 * 1.5,
|
|
10
11
|
color: COLORS.BRAND_8,
|
|
12
|
+
textAlign: COMP_GENERAL_CONSTANTS.textAlignment,
|
|
11
13
|
},
|
|
12
14
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { COMP_GENERAL_CONSTANTS } from '../../constants/component-constants/general-constants/constants';
|
|
2
3
|
|
|
3
4
|
export const bigTextStyles = (COLORS, FONT_SIZE, DARK_MODE) => StyleSheet.create({
|
|
4
5
|
container: {
|
|
@@ -11,10 +12,12 @@ export const bigTextStyles = (COLORS, FONT_SIZE, DARK_MODE) => StyleSheet.create
|
|
|
11
12
|
color: DARK_MODE ? COLORS.BRAND_BLACK : COLORS.BRAND_WHITE,
|
|
12
13
|
lineHeight: FONT_SIZE.h1 * 1.3,
|
|
13
14
|
marginVertical: 10,
|
|
15
|
+
textAlign: COMP_GENERAL_CONSTANTS.textAlignment,
|
|
14
16
|
},
|
|
15
17
|
authorText: {
|
|
16
18
|
fontSize: FONT_SIZE.h5,
|
|
17
19
|
color: DARK_MODE ? COLORS.BRAND_BLACK : COLORS.BRAND_WHITE,
|
|
18
20
|
lineHeight: FONT_SIZE.h5 * 1.3,
|
|
21
|
+
textAlign: COMP_GENERAL_CONSTANTS.textAlignment,
|
|
19
22
|
},
|
|
20
23
|
});
|
|
@@ -26,8 +26,10 @@ export const TextBlockQuote = ({ text, attribution }) => {
|
|
|
26
26
|
|
|
27
27
|
return (
|
|
28
28
|
<View testID="text-block-quote" style={styles.container}>
|
|
29
|
-
<
|
|
30
|
-
|
|
29
|
+
<View style={styles.topBorderContainer}>
|
|
30
|
+
<Icon name="quote-left" size={46} color={DARK_MODE ? COLORS.BRAND_BLACK : COLORS.BRAND_WHITE} />
|
|
31
|
+
</View>
|
|
32
|
+
<HTML
|
|
31
33
|
alterData={alterQuoteData}
|
|
32
34
|
html={text}
|
|
33
35
|
textSelectable={CAN_COPY_TEXT}
|
|
@@ -44,8 +46,7 @@ export const TextBlockQuote = ({ text, attribution }) => {
|
|
|
44
46
|
/>
|
|
45
47
|
{!!attribution && (
|
|
46
48
|
<Text style={styles.authorText}>
|
|
47
|
-
|
|
48
|
-
{attribution}
|
|
49
|
+
{`- ${attribution}`}
|
|
49
50
|
</Text>
|
|
50
51
|
)}
|
|
51
52
|
</View>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { COMP_GENERAL_CONSTANTS } from '../../constants/component-constants/general-constants/constants';
|
|
2
3
|
|
|
3
4
|
export const blockQuoteTextStyles = (FONT_SIZE, COLORS, DARK_MODE) => StyleSheet.create({
|
|
4
5
|
container: {
|
|
@@ -11,10 +12,17 @@ export const blockQuoteTextStyles = (FONT_SIZE, COLORS, DARK_MODE) => StyleSheet
|
|
|
11
12
|
color: DARK_MODE ? COLORS.BRAND_BLACK : COLORS.BRAND_WHITE,
|
|
12
13
|
lineHeight: FONT_SIZE.h1 * 1.3,
|
|
13
14
|
marginVertical: 10,
|
|
15
|
+
textAlign: COMP_GENERAL_CONSTANTS.textAlignment,
|
|
14
16
|
},
|
|
15
17
|
authorText: {
|
|
16
18
|
fontSize: FONT_SIZE.h5,
|
|
17
19
|
color: DARK_MODE ? COLORS.BRAND_BLACK : COLORS.BRAND_WHITE,
|
|
18
20
|
lineHeight: FONT_SIZE.h5 * 1.3,
|
|
21
|
+
textAlign: COMP_GENERAL_CONSTANTS.textAlignment,
|
|
22
|
+
},
|
|
23
|
+
topBorderContainer: {
|
|
24
|
+
alignItems: 'center',
|
|
25
|
+
flexDirection: 'row',
|
|
26
|
+
marginBottom: 8,
|
|
19
27
|
},
|
|
20
28
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { COMP_GENERAL_CONSTANTS } from '../../constants/component-constants/general-constants/constants'
|
|
2
3
|
|
|
3
4
|
export const textBlurbStyles = (FONT_SIZE) => StyleSheet.create({
|
|
4
5
|
container: {
|
|
@@ -9,5 +10,6 @@ export const textBlurbStyles = (FONT_SIZE) => StyleSheet.create({
|
|
|
9
10
|
blurbText: {
|
|
10
11
|
fontSize: FONT_SIZE.h3,
|
|
11
12
|
lineHeight: FONT_SIZE.h3 * 1.3,
|
|
13
|
+
textAlign : COMP_GENERAL_CONSTANTS.textAlignment
|
|
12
14
|
},
|
|
13
15
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { COMP_GENERAL_CONSTANTS } from '../../constants/component-constants/general-constants/constants';
|
|
2
3
|
|
|
3
4
|
export const textQuoteStyles = (COLORS, FONT_SIZE) => StyleSheet.create({
|
|
4
5
|
container: {
|
|
@@ -19,14 +20,15 @@ export const textQuoteStyles = (COLORS, FONT_SIZE) => StyleSheet.create({
|
|
|
19
20
|
fontSize: FONT_SIZE.h1,
|
|
20
21
|
lineHeight: FONT_SIZE.h1 * 1.3,
|
|
21
22
|
color: COLORS.BRAND_BLACK,
|
|
22
|
-
opacity: 0.9
|
|
23
|
+
opacity: 0.9,
|
|
24
|
+
textAlign: COMP_GENERAL_CONSTANTS.textAlignment,
|
|
23
25
|
},
|
|
24
26
|
attributionText: {
|
|
25
27
|
fontSize: FONT_SIZE.h3,
|
|
26
28
|
lineHeight: FONT_SIZE.h3 * 1.3,
|
|
27
29
|
color: COLORS.BRAND_BLACK,
|
|
28
30
|
alignItems: 'flex-end',
|
|
29
|
-
textAlign:
|
|
31
|
+
textAlign: COMP_GENERAL_CONSTANTS.textAlignment,
|
|
30
32
|
},
|
|
31
33
|
quoteTopBorder: {
|
|
32
34
|
backgroundColor: COLORS.BRAND_1,
|
|
@@ -43,5 +45,6 @@ export const textQuoteStyles = (COLORS, FONT_SIZE) => StyleSheet.create({
|
|
|
43
45
|
marginVertical: 10,
|
|
44
46
|
alignSelf: 'flex-end',
|
|
45
47
|
flexDirection: 'row',
|
|
48
|
+
width: '100%',
|
|
46
49
|
},
|
|
47
50
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { COMP_GENERAL_CONSTANTS } from '../../constants/component-constants/general-constants/constants'
|
|
2
3
|
|
|
3
4
|
export const textSummaryStyles = (FONT_SIZE, COLORS) => StyleSheet.create({
|
|
4
5
|
container: {
|
|
@@ -14,6 +15,7 @@ export const textSummaryStyles = (FONT_SIZE, COLORS) => StyleSheet.create({
|
|
|
14
15
|
color: COLORS.BRAND_6,
|
|
15
16
|
fontSize: FONT_SIZE.h2,
|
|
16
17
|
lineHeight: FONT_SIZE.h2 * 1.3,
|
|
18
|
+
textAlign: COMP_GENERAL_CONSTANTS.textAlignment
|
|
17
19
|
},
|
|
18
20
|
summaryText: {
|
|
19
21
|
color: COLORS.BRAND_1,
|
|
@@ -2,17 +2,12 @@ import PropTypes from "prop-types";
|
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { View, Dimensions } from "react-native";
|
|
4
4
|
import { WebView } from "react-native-webview";
|
|
5
|
-
import { getYoutubeVideoID } from "../../utils";
|
|
6
5
|
|
|
7
6
|
export const YouTubePlayer = ({ card = {} }) => {
|
|
8
|
-
const
|
|
9
|
-
if (!
|
|
7
|
+
const ytEmbedURL = card['embed-url'];
|
|
8
|
+
if (!ytEmbedURL) return null;
|
|
10
9
|
|
|
11
10
|
const windowWidth = Dimensions.get("window").width;
|
|
12
|
-
|
|
13
|
-
const ytVideoID = getYoutubeVideoID(ytURL);
|
|
14
|
-
const ytEmbedURL = `https://www.youtube.com/embed/${ytVideoID}`;
|
|
15
|
-
|
|
16
11
|
const styles = webviewStyles(windowWidth);
|
|
17
12
|
|
|
18
13
|
return (
|
|
@@ -36,6 +31,7 @@ const webviewStyles = (windowWidth) => {
|
|
|
36
31
|
},
|
|
37
32
|
container: {
|
|
38
33
|
flex: 1,
|
|
34
|
+
marginVertical: 10,
|
|
39
35
|
},
|
|
40
36
|
};
|
|
41
37
|
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { I18nManager } from 'react-native';
|
|
2
|
+
|
|
1
3
|
export const COMP_GENERAL_CONSTANTS = {
|
|
2
4
|
secondaryStoryCard: "COMP_GENERAL_SECONDARY_STORY",
|
|
3
5
|
primaryStoryCard: "COMP_GENERAL_PRIMARY_STORY",
|
|
@@ -21,4 +23,5 @@ export const COMP_GENERAL_CONSTANTS = {
|
|
|
21
23
|
headerLogoTouch: "COMP_GENERAL_HEADER_LOGO_TOUCH",
|
|
22
24
|
radioButtonTouch: "COMP_GENERAL_RADIO",
|
|
23
25
|
shareButtonTouch: "COMP_GENERAL_SHARE",
|
|
26
|
+
textAlignment: I18nManager.isRTL ? "left" : "auto",
|
|
24
27
|
};
|
package/src/utils/parseUtils.js
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
1
|
export function stripHTML(text) {
|
|
2
2
|
return text?.replace(/<[^>]*>?/gm, '');
|
|
3
3
|
}
|
|
4
|
-
|
|
5
|
-
export function getYoutubeVideoID(url) {
|
|
6
|
-
const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
|
|
7
|
-
const match = url.match(regExp);
|
|
8
|
-
|
|
9
|
-
return (match && match[2].length === 11)
|
|
10
|
-
? match[2]
|
|
11
|
-
: null;
|
|
12
|
-
}
|
package/src/utils/story.js
CHANGED
|
@@ -7,10 +7,14 @@ import get from 'lodash/get';
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
export const isStoryFree = (story = {}) => {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
switch (story.access) {
|
|
11
|
+
case 'login':
|
|
12
|
+
return 1;
|
|
13
|
+
case 'subscription':
|
|
14
|
+
return 2;
|
|
15
|
+
default:
|
|
16
|
+
return 0;
|
|
12
17
|
}
|
|
13
|
-
return story.access === 'public' || Object.is(story.access, null);
|
|
14
18
|
};
|
|
15
19
|
|
|
16
20
|
/**
|
package/src/utils/timeUtils.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { formatDistanceToNowStrict, differenceInMinutes, format as dateFormat } from 'date-fns';
|
|
2
2
|
import * as dateFNSlocale from 'date-fns/locale';
|
|
3
3
|
|
|
4
4
|
export function getTimeAgo(date) {
|
|
5
5
|
if (date) {
|
|
6
|
-
return
|
|
6
|
+
return formatDistanceToNowStrict(new Date(date));
|
|
7
7
|
}
|
|
8
8
|
return '';
|
|
9
9
|
}
|
|
@@ -15,14 +15,23 @@ export function getTimeInFormat(date, format, localTime) {
|
|
|
15
15
|
return '';
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export const getTimeForStoryCards = (
|
|
18
|
+
export const getTimeForStoryCards = (
|
|
19
|
+
date,
|
|
20
|
+
format,
|
|
21
|
+
localTime,
|
|
22
|
+
translate,
|
|
23
|
+
reverseTimeAdverbPosition = false,
|
|
24
|
+
) => {
|
|
19
25
|
if (date) {
|
|
20
26
|
const currentDate = new Date();
|
|
21
27
|
const dateToFormat = new Date(date);
|
|
22
28
|
const locale = dateFNSlocale[localTime];
|
|
23
29
|
const distanceInMinutes = differenceInMinutes(currentDate, dateToFormat);
|
|
24
30
|
if (distanceInMinutes <= 1440) {
|
|
25
|
-
|
|
31
|
+
const timeDistance = formatDistanceToNowStrict(dateToFormat, { locale });
|
|
32
|
+
return reverseTimeAdverbPosition
|
|
33
|
+
? `${translate('ago')} ${timeDistance}`
|
|
34
|
+
: `${timeDistance} ${translate('ago')}`;
|
|
26
35
|
}
|
|
27
36
|
return dateFormat(dateToFormat, format, { locale });
|
|
28
37
|
}
|