@quintype/native-components 2.20.6 → 2.20.7

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 CHANGED
@@ -2,6 +2,13 @@
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.7](https://github.com/quintype/native-components/compare/v2.20.6...v2.20.7) (2023-06-16)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * **images:** Fixes crop issues and adds rich-text support for attribution ([#201](https://github.com/quintype/native-components/issues/201)) ([c0a5ca0](https://github.com/quintype/native-components/commit/c0a5ca0f593f1ce3459ae0fcc2aba3f06f21e053))
11
+
5
12
  ### [2.20.6](https://github.com/quintype/native-components/compare/v2.20.5...v2.20.6) (2023-06-15)
6
13
 
7
14
  ### [2.20.5](https://github.com/quintype/native-components/compare/v2.20.4...v2.20.5) (2023-03-21)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quintype/native-components",
3
- "version": "2.20.6",
3
+ "version": "2.20.7",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -18,26 +18,29 @@ const replaceDefaultProtocol = (content) => {
18
18
  };
19
19
 
20
20
  const removeWidthnHeight = (htmlContent) => {
21
- let temp = htmlContent.split(' ');
21
+ const temp = htmlContent.split(' ');
22
22
  let finalHtml = '';
23
- if(temp[0]==='<iframe'){
24
- for(let i=0; i<temp.length; i++){
25
- if((temp[i].includes('width') || temp[i].includes('height')) && !temp[i].includes('/')){
23
+ if (temp[0] === '<iframe') {
24
+ for (let i = 0; i < temp.length; i++) {
25
+ if (
26
+ (temp[i].includes('width') || temp[i].includes('height'))
27
+ && !temp[i].includes('/')
28
+ ) {
26
29
  continue;
27
30
  }
28
- finalHtml = finalHtml + temp[i] + " ";
31
+ finalHtml = `${finalHtml + temp[i]} `;
29
32
  }
30
33
 
31
34
  return finalHtml;
32
35
  }
33
36
  return htmlContent;
34
- }
37
+ };
35
38
 
36
39
  const getHTMLContent = (embedJs) => {
37
- const width = Dimensions.get('window').width;
40
+ const { width } = Dimensions.get('window');
38
41
  const decodedContent = getDecodedContent(embedJs);
39
- let htmlContent = replaceDefaultProtocol(decodedContent)
40
- htmlContent = removeWidthnHeight(htmlContent)
42
+ let htmlContent = replaceDefaultProtocol(decodedContent);
43
+ htmlContent = removeWidthnHeight(htmlContent);
41
44
  const webViewScript = `
42
45
  <script type="application/javascript">
43
46
  var interValId;
@@ -60,8 +63,8 @@ const getHTMLContent = (embedJs) => {
60
63
  <meta name="viewport" content="width=device-width, initial-scale=1">
61
64
  <style>
62
65
  iframe{
63
- width:${width-20}px;
64
- height:${width-20}px;
66
+ width:${width - 20}px;
67
+ height:${width - 20}px;
65
68
  }
66
69
  </style>
67
70
  </head>
@@ -75,7 +78,11 @@ const getHTMLContent = (embedJs) => {
75
78
  export const JSEmbedElement = (props) => {
76
79
  const [height, setHeight] = useState(300);
77
80
  const webViewRef = useRef(null);
78
- const width = get(props, ['currentLayout', 'width'], Dimensions.get('window').width);
81
+ const width = get(
82
+ props,
83
+ ['currentLayout', 'width'],
84
+ Dimensions.get('window').width,
85
+ );
79
86
 
80
87
  useEffect(() => {
81
88
  webViewRef?.current?.reload();
@@ -94,10 +101,10 @@ export const JSEmbedElement = (props) => {
94
101
 
95
102
  const baseUrl = urlMapper[props.element.subtype] || 'https://twitter.com';
96
103
 
97
- return ({
104
+ return {
98
105
  html: getHTMLContent(props.element['embed-js']),
99
106
  baseUrl,
100
- });
107
+ };
101
108
  };
102
109
 
103
110
  return (
@@ -105,7 +112,10 @@ export const JSEmbedElement = (props) => {
105
112
  <WebView
106
113
  ref={webViewRef}
107
114
  style={{
108
- width, height, flex: 0, opacity: 0.99,
115
+ width,
116
+ height,
117
+ flex: 0,
118
+ opacity: 0.99,
109
119
  }}
110
120
  automaticallyAdjustContentInsets={false}
111
121
  scrollEnabled={false}
@@ -6,20 +6,23 @@ import { LightBox } from '../LightBox';
6
6
  import { getImageHeight } from '../../utils';
7
7
 
8
8
  export const LightBoxImage = ({
9
- data, hero, currentLayout, additionalStyles, elementType, onClickHandler = ()=>{}, index
9
+ data, hero, currentLayout, additionalStyles, elementType, onClickHandler = () => {}, index,
10
10
  }) => {
11
- const { cdn, slug, metaData } = data;
11
+ const {
12
+ cdn, slug, metaData, imageWidth: previewWidth,
13
+ } = data;
12
14
  const { width, height } = metaData || {};
13
15
  const imageHeight = getImageHeight(width, height);
14
16
  const imageUri = `${data?.cdn}/${data?.slug}`;
15
17
  const [showModal, setShowModal] = useState(false);
16
18
 
17
19
  const toggleModal = () => {
18
- if(elementType === 'gallery'){
20
+ if (elementType === 'gallery') {
19
21
  onClickHandler(index);
20
- } else{
21
- setShowModal(!showModal)
22
- }};
22
+ } else {
23
+ setShowModal(!showModal);
24
+ }
25
+ };
23
26
 
24
27
  const styles = {
25
28
  image: {
@@ -39,7 +42,8 @@ export const LightBoxImage = ({
39
42
  metaData={metaData}
40
43
  hero={hero || false}
41
44
  styles={cumulativeStyles}
42
- elementType={elementType ? elementType : null}
45
+ imageWidth={previewWidth}
46
+ elementType={elementType || null}
43
47
  />
44
48
  </TouchableOpacity>
45
49
  </>
@@ -47,9 +51,11 @@ export const LightBoxImage = ({
47
51
  };
48
52
 
49
53
  LightBoxImage.propTypes = {
50
- children: PropTypes.element,
51
54
  data: PropTypes.object,
52
55
  hero: PropTypes.bool,
53
56
  currentLayout: PropTypes.object,
54
57
  additionalStyles: PropTypes.object,
58
+ elementType: PropTypes.string,
59
+ onClickHandler: PropTypes.func,
60
+ index: PropTypes.number,
55
61
  };
@@ -5,18 +5,18 @@ import React, {
5
5
  import { StyleSheet, View } from 'react-native';
6
6
  import FastImage from 'react-native-fast-image';
7
7
  import Icon from 'react-native-vector-icons/FontAwesome';
8
- import { isTablet } from 'react-native-device-info';
9
8
  import { FallbackIcon } from '../../Icons/FallBackIcon';
10
9
  import { AppTheme } from '../../utils';
11
- import { getImageURL, getCustomResolutionImageURL } from '../../utils/imageUtils';
10
+ import {
11
+ getImageURL,
12
+ getCustomResolutionImageURL,
13
+ } from '../../utils/imageUtils';
12
14
 
13
15
  const ResponsiveImageBase = (props) => {
14
16
  const [placeholder, setPlaceholder] = useState(true);
15
17
  const { theme } = useContext(AppTheme);
16
18
  const { COLORS, CustomFallBackIcon, CustomFallBackBackground } = theme;
17
19
 
18
- const HERO_IMAGE_HEIGHT = isTablet() ? 300 : 232;
19
-
20
20
  const flattenedImageStyle = StyleSheet.flatten([
21
21
  styles.defaultImage,
22
22
  props.styles,
@@ -24,15 +24,9 @@ const ResponsiveImageBase = (props) => {
24
24
  width: props.imageWidth,
25
25
  height: (props.imageWidth * 9) / 16,
26
26
  },
27
- (props.hero && props?.elementType !== 'gallery' ) && {
28
- width: '100%',
29
- height: HERO_IMAGE_HEIGHT,
30
- alignSelf: 'stretch',
31
- },
32
27
  props?.elementType === 'gallery' && {
33
- backgroundColor: COLORS.BRAND_BLACK
34
- }
35
-
28
+ backgroundColor: COLORS.BRAND_BLACK,
29
+ },
36
30
  ]);
37
31
 
38
32
  const placeholderStyle = {
@@ -48,9 +42,9 @@ const ResponsiveImageBase = (props) => {
48
42
  <FallbackIcon />
49
43
  );
50
44
 
51
- let imageUrl = ''
45
+ let imageUrl = '';
52
46
 
53
- if(props?.elementType === 'gallery'){
47
+ if (props?.elementType === 'gallery') {
54
48
  imageUrl = getCustomResolutionImageURL(props, [1, 1]);
55
49
  } else {
56
50
  imageUrl = getImageURL(props);
@@ -82,7 +76,7 @@ const ResponsiveImageBase = (props) => {
82
76
  style={flattenedImageStyle}
83
77
  source={sourceURI}
84
78
  onLoad={onLoadHandler}
85
- resizeMode={props.hero ? FastImage.resizeMode.cover : FastImage.resizeMode.contain}
79
+ resizeMode={props?.elementType === 'gallery' && !(props.hero) ? FastImage.resizeMode.contain : FastImage.resizeMode.cover}
86
80
  {...props}
87
81
  />
88
82
  {placeholder && (
@@ -105,6 +99,7 @@ ResponsiveImageBase.propTypes = {
105
99
  testID: PropTypes.string,
106
100
  containerTestID: PropTypes.string,
107
101
  imageWidth: PropTypes.number,
102
+ elementType: PropTypes.string,
108
103
  };
109
104
 
110
105
  ResponsiveImageBase.defaultProps = {
@@ -1,6 +1,7 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React, { useContext } from 'react';
3
- import { Text, View } from 'react-native';
3
+ import { View, Linking } from 'react-native';
4
+ import HTML from 'react-native-render-html';
4
5
  import { AppTheme, getScreenPercentageWidth } from '../../utils/index';
5
6
  import { LightBoxImage } from '../LightBoxImage';
6
7
  import { slideshowStoryCardStyles } from './styles';
@@ -9,26 +10,37 @@ export const SlideshowStoryCard = ({ card, cdn }) => {
9
10
  const attribution = card['image-attribution'];
10
11
  const { title } = card;
11
12
  const { theme } = useContext(AppTheme);
12
- const displayDivider = attribution && title ? ' | ' : '';
13
- const styles = slideshowStoryCardStyles(theme)
13
+ const { CAN_COPY_TEXT } = theme;
14
+ const styles = slideshowStoryCardStyles(theme);
14
15
  const imgData = {
15
16
  cdn,
16
17
  slug: card['image-s3-key'],
17
- imageWidth: getScreenPercentageWidth(60),
18
+ imageWidth: getScreenPercentageWidth(100),
18
19
  metaData: card['image-metadata'],
19
20
  };
20
21
 
21
22
  return (
22
23
  <View style={styles.container}>
23
- <View style={styles.image}>
24
- <LightBoxImage data={imgData} hero />
25
- </View>
26
-
24
+ <LightBoxImage data={imgData} />
27
25
  <View style={styles.textContainer}>
28
- <Text style={styles.attributionText} lato>
29
- {`${attribution}${displayDivider}`}
30
- <Text style={styles.cardTitleText}>{`${title}`}</Text>
31
- </Text>
26
+ <HTML
27
+ html={title}
28
+ textSelectable={CAN_COPY_TEXT}
29
+ key={Math.random()}
30
+ baseFontStyle={styles.cardTitleText}
31
+ onLinkPress={(e, href) => {
32
+ Linking.openURL(href);
33
+ }}
34
+ />
35
+ <HTML
36
+ html={attribution}
37
+ textSelectable={CAN_COPY_TEXT}
38
+ key={Math.random()}
39
+ baseFontStyle={styles.attributionText}
40
+ onLinkPress={(e, href) => {
41
+ Linking.openURL(href);
42
+ }}
43
+ />
32
44
  </View>
33
45
  </View>
34
46
  );
@@ -37,5 +49,4 @@ export const SlideshowStoryCard = ({ card, cdn }) => {
37
49
  SlideshowStoryCard.propTypes = {
38
50
  cdn: PropTypes.string.isRequired,
39
51
  card: PropTypes.object,
40
- imageSize: PropTypes.object,
41
52
  };
@@ -1,28 +1,26 @@
1
1
  import { StyleSheet, Dimensions } from 'react-native';
2
- import { COMP_GENERAL_CONSTANTS } from '../../constants/component-constants/general-constants/constants'
2
+
3
3
  const { width } = Dimensions.get('window');
4
4
 
5
- export const slideshowStoryCardStyles = ({ COLORS }) => {
6
- return StyleSheet.create({
7
- image: {
8
- marginRight: 10,
9
- width,
10
- },
11
- textContainer: {
12
- marginTop: 10,
13
- opacity: 0.8,
14
- width,
15
- },
16
- cardTitleText: {
17
- opacity: 0.7,
18
- color: COLORS.BRAND_BLACK
19
- },
20
- container: {
21
- flexDirection: 'column',
22
- },
23
- attributionText: {
24
- color: COLORS.BRAND_BLACK,
25
- textAlign : COMP_GENERAL_CONSTANTS.textAlignment
26
- }
27
- })
28
- }
5
+ export const slideshowStoryCardStyles = ({ COLORS, FONT_FAMILY }) => StyleSheet.create({
6
+ textContainer: {
7
+ paddingHorizontal: 10,
8
+ flexDirection: 'column',
9
+ flexWrap: 'wrap',
10
+ marginTop: 10,
11
+ },
12
+ cardTitleText: {
13
+ opacity: 0.7,
14
+ color: COLORS.BRAND_BLACK,
15
+ fontFamily: FONT_FAMILY.secondary,
16
+ },
17
+ container: {
18
+ flexDirection: 'column',
19
+ width,
20
+ },
21
+ attributionText: {
22
+ color: COLORS.BRAND_BLACK,
23
+ fontFamily: FONT_FAMILY.secondary,
24
+ opacity: 0.8,
25
+ },
26
+ });
@@ -1,17 +1,24 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React, { useContext, useState, useRef } from 'react';
3
- import { View, Modal, SafeAreaView, Dimensions, Image, FlatList, TouchableOpacity } from 'react-native';
3
+ import {
4
+ View,
5
+ Modal,
6
+ Linking,
7
+ SafeAreaView,
8
+ FlatList,
9
+ TouchableOpacity,
10
+ } from 'react-native';
11
+ import Icon from 'react-native-vector-icons/FontAwesome';
12
+ import FastImage from 'react-native-fast-image';
13
+ import HTML from 'react-native-render-html';
4
14
  import { styles } from './styles';
5
15
  import { Text } from '../index';
6
- import { getScreenPercentageWidth, AppTheme } from '../../utils/index';
16
+ import { AppTheme } from '../../utils/index';
7
17
  import { LightBoxImage } from '../LightBoxImage';
8
- import Icon from 'react-native-vector-icons/FontAwesome';
9
- import FastImage from 'react-native-fast-image';
10
- import { resolve } from 'path-browserify';
11
18
 
12
19
  export const StoryGallery = ({ cdn, card }) => {
13
20
  const { theme } = useContext(AppTheme);
14
- const { COLORS, DARK_MODE } = theme;
21
+ const { COLORS, DARK_MODE, CAN_COPY_TEXT } = theme;
15
22
  const galleryStyles = styles(theme);
16
23
  const storyElements = card['story-elements'];
17
24
  const [showModal, setShowModal] = useState(false);
@@ -20,34 +27,38 @@ export const StoryGallery = ({ cdn, card }) => {
20
27
 
21
28
  const flatlistRef = useRef();
22
29
  const [index, setIndex] = useState(0);
23
- const totalSlides = card["story-elements"]?.length;
30
+ const totalSlides = card['story-elements']?.length;
24
31
  const lastSlide = currentIndex + 1 === totalSlides;
25
32
  const firstSlide = currentIndex === 0;
26
33
  const [galleryLastImgUrl, setGalleryLastImageUrl] = useState('');
27
34
 
28
35
  const onPressHandler = (index = 5) => {
29
- setIndex(index)
36
+ setIndex(index);
30
37
  setShowModal(true);
31
- }
38
+ };
32
39
 
33
40
  const moveNext = () => {
34
41
  if (!lastSlide) {
35
- flatlistRef.current.scrollToIndex({ index: Math.floor(Math.min(currentIndex + 1, totalSlides - 1))});
42
+ flatlistRef.current.scrollToIndex({
43
+ index: Math.floor(Math.min(currentIndex + 1, totalSlides - 1)),
44
+ });
36
45
  setCurrentTabIndex(currentIndex + 1);
37
46
  }
38
47
  };
39
48
 
40
49
  const movePrev = () => {
41
50
  if (!firstSlide) {
42
- flatlistRef.current.scrollToIndex({ index: Math.ceil(Math.max(currentIndex - 1, 0)) });
51
+ flatlistRef.current.scrollToIndex({
52
+ index: Math.ceil(Math.max(currentIndex - 1, 0)),
53
+ });
43
54
  setCurrentTabIndex(Math.max(currentIndex - 1, 0));
44
55
  }
45
56
  };
46
57
 
47
58
  const showArrow = (direction) => {
48
- const arrowStyles = direction === "left" ? galleryStyles.leftArrow : galleryStyles.rightArrow;
49
- const onPressHandler = direction === "left" ? movePrev : moveNext;
50
- const iconName = direction === "left" ? 'chevron-left' : 'chevron-right'
59
+ const arrowStyles = direction === 'left' ? galleryStyles.leftArrow : galleryStyles.rightArrow;
60
+ const onPressHandler = direction === 'left' ? movePrev : moveNext;
61
+ const iconName = direction === 'left' ? 'chevron-left' : 'chevron-right';
51
62
  return (
52
63
  <View style={arrowStyles}>
53
64
  <TouchableOpacity onPress={onPressHandler}>
@@ -61,23 +72,26 @@ export const StoryGallery = ({ cdn, card }) => {
61
72
  const xOffset = event.nativeEvent?.contentOffset?.x;
62
73
  const contentWidth = event.nativeEvent?.contentSize?.width;
63
74
  const layoutWidth = event.nativeEvent?.layoutMeasurement?.width;
64
- const value = (xOffset / contentWidth);
65
- const leftThreshold = contentWidth / ( 2 * totalSlides );
66
- const rightThreshold = contentWidth - ( 1.5 ) * layoutWidth;
67
-
68
- if((leftThreshold <= xOffset && (layoutWidth > xOffset || rightThreshold > xOffset ))){
75
+ const value = xOffset / contentWidth;
76
+ const leftThreshold = contentWidth / (2 * totalSlides);
77
+ const rightThreshold = contentWidth - 1.5 * layoutWidth;
78
+
79
+ if (
80
+ leftThreshold <= xOffset
81
+ && (layoutWidth > xOffset || rightThreshold > xOffset)
82
+ ) {
69
83
  setCurrentTabIndex(value * totalSlides);
70
- } else if(xOffset < leftThreshold){
84
+ } else if (xOffset < leftThreshold) {
71
85
  setCurrentTabIndex(0);
72
- } else if(xOffset >= rightThreshold){
73
- setCurrentTabIndex(totalSlides-1);
86
+ } else if (xOffset >= rightThreshold) {
87
+ setCurrentTabIndex(totalSlides - 1);
74
88
  }
75
- }
89
+ };
76
90
 
77
91
  const closeModalHandler = () => {
78
92
  setShowModal(false);
79
93
  setCurrentTabIndex(0);
80
- }
94
+ };
81
95
 
82
96
  const renderItem = (item) => {
83
97
  const data = {
@@ -85,20 +99,38 @@ export const StoryGallery = ({ cdn, card }) => {
85
99
  slug: item.item['image-s3-key'],
86
100
  metaData: item.item['image-metadata'],
87
101
  };
88
-
102
+ const { title } = item.item;
103
+ const attribution = item.item['image-attribution'];
89
104
  const imageUri = `${data?.cdn}/${data?.slug}`;
90
105
 
91
- return <View style={galleryStyles.carouselContainer}>
92
- <FastImage
93
- source={{uri:imageUri}}
94
- resizeMode={FastImage.resizeMode.contain}
95
- style={galleryStyles.carouselImage}
96
- />
97
- <Text primary style={galleryStyles.titleText}>
98
- {item.item?.title}
99
- </Text>
100
- </View>
101
- }
106
+ return (
107
+ <View style={galleryStyles.carouselContainer}>
108
+ <FastImage
109
+ source={{ uri: imageUri }}
110
+ resizeMode={FastImage.resizeMode.contain}
111
+ style={galleryStyles.carouselImage}
112
+ />
113
+ <HTML
114
+ html={title}
115
+ textSelectable={CAN_COPY_TEXT}
116
+ key={Math.random()}
117
+ baseFontStyle={galleryStyles.titleText}
118
+ onLinkPress={(e, href) => {
119
+ Linking.openURL(href);
120
+ }}
121
+ />
122
+ <HTML
123
+ html={attribution}
124
+ textSelectable={CAN_COPY_TEXT}
125
+ key={Math.random()}
126
+ baseFontStyle={galleryStyles.attributionText}
127
+ onLinkPress={(e, href) => {
128
+ Linking.openURL(href);
129
+ }}
130
+ />
131
+ </View>
132
+ );
133
+ };
102
134
 
103
135
  return (
104
136
  <>
@@ -107,35 +139,54 @@ export const StoryGallery = ({ cdn, card }) => {
107
139
 
108
140
  <View style={galleryStyles.imgContainer}>
109
141
  {storyElements.map((element, index) => {
110
-
111
142
  const data = {
112
143
  cdn,
113
144
  slug: element['image-s3-key'],
114
145
  metaData: element['image-metadata'],
115
- imageWidth: getScreenPercentageWidth(100),
116
146
  };
117
147
 
118
- if(storyElements.length >6 && index >= 5){
148
+ if (storyElements.length > 6 && index >= 5) {
119
149
  const imageUri = `${data?.cdn}/${data?.slug}`;
120
- if(galleryLastImgUrl === ''){
150
+ if (galleryLastImgUrl === '') {
121
151
  setGalleryLastImageUrl(imageUri);
122
152
  }
123
153
  return null;
124
154
  }
125
155
 
126
156
  const style = galleryStyles.fullWidth;
127
- return <TouchableOpacity>
128
- <LightBoxImage onClickHandler={onPressHandler} hero={data.metaData['focus-point'] ? true : false} key={index} data={data} additionalStyles={style} elementType={card?.metadata?.type} index={index} />
129
- </TouchableOpacity>
157
+ return (
158
+ <TouchableOpacity>
159
+ <LightBoxImage
160
+ onClickHandler={onPressHandler}
161
+ hero={!!data.metaData['focus-point']}
162
+ key={Math.random()}
163
+ data={data}
164
+ additionalStyles={style}
165
+ elementType={card?.metadata?.type}
166
+ index={index}
167
+ />
168
+ </TouchableOpacity>
169
+ );
130
170
  })}
131
- {storyElements && storyElements.length > 6 && <TouchableOpacity onPress={()=>onPressHandler(5)} style={[galleryStyles.fullWidth, galleryStyles.showMoreImageContainer]}>
132
- <FastImage
133
- source={{uri: galleryLastImgUrl}}
134
- resizeMode={FastImage.resizeMode.cover}
135
- style={galleryStyles.showMoreImage}
136
- />
137
- <Text style={galleryStyles.showMoreText}>+{storyElements.length-5}</Text>
138
- </TouchableOpacity>}
171
+ {storyElements && storyElements.length > 6 && (
172
+ <TouchableOpacity
173
+ onPress={() => onPressHandler(5)}
174
+ style={[
175
+ galleryStyles.fullWidth,
176
+ galleryStyles.showMoreImageContainer,
177
+ ]}
178
+ >
179
+ <FastImage
180
+ source={{ uri: galleryLastImgUrl }}
181
+ resizeMode={FastImage.resizeMode.cover}
182
+ style={galleryStyles.showMoreImage}
183
+ />
184
+ <Text style={galleryStyles.showMoreText}>
185
+ +
186
+ {storyElements.length - 5}
187
+ </Text>
188
+ </TouchableOpacity>
189
+ )}
139
190
  </View>
140
191
  <Text style={galleryStyles.descText} lato>
141
192
  {card.description}
@@ -151,34 +202,40 @@ export const StoryGallery = ({ cdn, card }) => {
151
202
  >
152
203
  <SafeAreaView style={galleryStyles.safeAreaView}>
153
204
  <View style={galleryStyles.modalContainer}>
154
- <TouchableOpacity onPress={closeModalHandler}>
205
+ <TouchableOpacity onPress={closeModalHandler}>
155
206
  <View style={galleryStyles.close}>
156
- <Icon name="times" size={20} color={DARK_MODE ? COLORS.BRAND_BLACK : COLORS.BRAND_WHITE} />
207
+ <Icon
208
+ name="times"
209
+ size={20}
210
+ color={DARK_MODE ? COLORS.BRAND_BLACK : COLORS.BRAND_WHITE}
211
+ />
157
212
  </View>
158
213
  </TouchableOpacity>
159
- <View style={galleryStyles.wrapper}>
160
-
161
- <FlatList
162
- ref={flatlistRef}
163
- data={card["story-elements"]}
164
- renderItem={renderItem}
165
- keyExtractor={(item) => item.id}
166
- horizontal
167
- extraData={currentIndex}
168
- onScroll={handleScroll}
169
- initialScrollIndex={index}
170
- onScrollToIndexFailed = { info => {
171
- const wait = new Promise(resolve=>setTimeout(resolve, 500));
172
- wait.then(()=>{
173
- flatlistRef.current?.scrollToIndex({index: info.index, animated: true});
174
- });
175
- }}
176
- />
177
-
178
- {!firstSlide && showArrow("left")}
179
-
180
- {!lastSlide && showArrow("right")}
181
- </View>
214
+ <View style={galleryStyles.wrapper}>
215
+ <FlatList
216
+ ref={flatlistRef}
217
+ data={card['story-elements']}
218
+ renderItem={renderItem}
219
+ keyExtractor={(item) => item.id}
220
+ horizontal
221
+ extraData={currentIndex}
222
+ onScroll={handleScroll}
223
+ initialScrollIndex={index}
224
+ onScrollToIndexFailed={(info) => {
225
+ const wait = new Promise((resolve) => setTimeout(resolve, 500));
226
+ wait.then(() => {
227
+ flatlistRef.current?.scrollToIndex({
228
+ index: info.index,
229
+ animated: true,
230
+ });
231
+ });
232
+ }}
233
+ />
234
+
235
+ {!firstSlide && showArrow('left')}
236
+
237
+ {!lastSlide && showArrow('right')}
238
+ </View>
182
239
  </View>
183
240
  </SafeAreaView>
184
241
  </Modal>
@@ -1,131 +1,134 @@
1
1
  import { StyleSheet, Dimensions } from 'react-native';
2
2
  import { useContext } from 'react';
3
- import { isTablet } from 'react-native-device-info';
4
3
  import { AppTheme } from '../../utils';
5
4
 
6
-
7
5
  export const styles = ({ FONT_SIZE }) => {
8
6
  const { width: deviceWidth } = Dimensions.get('window');
9
7
  const { theme } = useContext(AppTheme);
10
- const { COLORS, DARK_MODE } = theme;
8
+ const { COLORS, DARK_MODE, FONT_FAMILY } = theme;
11
9
 
12
10
  return StyleSheet.create({
13
- container: {
14
- width: '100%',
15
- paddingHorizontal: 10,
16
- },
17
- titleText: {
18
- fontSize: FONT_SIZE.h1,
19
- marginBottom: 10,
20
- opacity: 0.8,
21
- },
22
- imgContainer: {
23
- width: '100%',
24
- flexDirection: 'row',
25
- flexWrap: 'wrap',
26
- justifyContent: 'space-between',
27
- },
28
- halfWidth: {
29
- width: (deviceWidth - 30) / 2,
30
- height: 124,
31
- },
32
- fullWidth: {
33
- width: (deviceWidth - 30) / 3,
34
- height: (deviceWidth - 30) / 3,
35
- marginVertical: 2.5,
36
- },
37
- descText: {
38
- fontSize: FONT_SIZE.h2,
39
- opacity: 0.8,
40
- paddingTop: 10,
41
- },
42
- modalContainer: {
43
- backgroundColor: DARK_MODE ? COLORS.MONO6 : COLORS.BRAND_BLACK,
44
- flex: 1,
45
- justifyContent: 'center',
46
- },
47
- safeAreaView: {
48
- flex: 1,
49
- backgroundColor: 'transparent',
50
- },
51
- close: {
52
- justifyContent: 'flex-start',
53
- padding: 10,
54
- height: 40,
55
- zIndex: 1,
56
- marginTop: 25,
57
- },
58
- imageContainer: {
59
- justifyContent: 'center',
60
- alignItems: 'center',
61
- width: '100%',
62
- height: '100%',
63
- },
64
- portrait: {
65
- width: '100%',
66
- height: '80%',
67
- },
68
- wrapper: {
69
- paddingHorizontal: 10,
70
- flex:1,
71
- backgroundColor:'black',
72
- width:'100%'
73
- },
74
- titleText: {
75
- fontWeight: "normal",
76
- marginBottom: 10,
77
- fontSize: FONT_SIZE.h3,
78
- opacity: 0.8,
79
- color:'white',
80
- marginTop:10,
81
- marginHorizontal:10
82
- },
83
- leftArrow: {
84
- position: "absolute",
85
- top: "46%",
86
- right: "95%",
87
- left: 20,
88
- zIndex: 999,
89
- width: 30,
90
- height: 40,
91
- backgroundColor: COLORS.TRANSPARENT_BLACK,
92
- display: "flex",
93
- alignItems: "center",
94
- justifyContent: "center",
95
- },
96
- rightArrow: {
97
- position: "absolute",
98
- top: "46%",
99
- left: "93%",
100
- right: 20,
101
- zIndex: 999,
102
- width: 30,
103
- height: 40,
104
- backgroundColor: COLORS.TRANSPARENT_BLACK,
105
- display: "flex",
106
- alignItems: "center",
107
- justifyContent: "center",
108
- },
109
- carouselImage: {
110
- width: '100%',
111
- height: '80%'
112
- },
113
- carouselContainer:{
114
- width: deviceWidth - 10,
115
- margin: 10
116
- },
117
- showMoreImageContainer:{
118
- justifyContent: 'center',
119
- alignItems: 'center'
120
- },
121
- showMoreImage:{
122
- width: '100%',
123
- height: '100%',
124
- opacity: 0.5
125
- },
126
- showMoreText:{
127
- fontSize: 30,
128
- position: 'absolute',
129
- color: COLORS.BRAND_WHITE
130
- }
131
- })};
11
+ container: {
12
+ width: '100%',
13
+ paddingHorizontal: 10,
14
+ },
15
+ imgContainer: {
16
+ width: '100%',
17
+ flexDirection: 'row',
18
+ flexWrap: 'wrap',
19
+ justifyContent: 'space-between',
20
+ },
21
+ halfWidth: {
22
+ width: (deviceWidth - 30) / 2,
23
+ height: 124,
24
+ },
25
+ fullWidth: {
26
+ width: (deviceWidth - 30) / 3,
27
+ height: (deviceWidth - 30) / 3,
28
+ marginVertical: 2.5,
29
+ },
30
+ descText: {
31
+ fontSize: FONT_SIZE.h2,
32
+ opacity: 0.8,
33
+ paddingTop: 10,
34
+ },
35
+ modalContainer: {
36
+ backgroundColor: DARK_MODE ? COLORS.MONO6 : COLORS.BRAND_BLACK,
37
+ flex: 1,
38
+ justifyContent: 'center',
39
+ },
40
+ safeAreaView: {
41
+ flex: 1,
42
+ backgroundColor: 'transparent',
43
+ },
44
+ close: {
45
+ justifyContent: 'flex-start',
46
+ padding: 10,
47
+ height: 40,
48
+ zIndex: 1,
49
+ marginTop: 25,
50
+ },
51
+ imageContainer: {
52
+ justifyContent: 'center',
53
+ alignItems: 'center',
54
+ width: '100%',
55
+ height: '100%',
56
+ },
57
+ portrait: {
58
+ width: '100%',
59
+ height: '80%',
60
+ },
61
+ wrapper: {
62
+ paddingHorizontal: 10,
63
+ flex: 1,
64
+ backgroundColor: 'black',
65
+ width: '100%',
66
+ },
67
+ titleText: {
68
+ fontWeight: 'normal',
69
+ fontSize: FONT_SIZE.h3,
70
+ opacity: 0.8,
71
+ color: 'white',
72
+ marginTop: 10,
73
+ marginHorizontal: 10,
74
+ fontFamily: FONT_FAMILY.secondary,
75
+ },
76
+ attributionText: {
77
+ fontWeight: 'normal',
78
+ marginBottom: 10,
79
+ fontSize: FONT_SIZE.h3,
80
+ opacity: 0.8,
81
+ color: 'white',
82
+ marginHorizontal: 10,
83
+ fontFamily: FONT_FAMILY.secondary,
84
+ },
85
+ leftArrow: {
86
+ position: 'absolute',
87
+ top: '46%',
88
+ right: '95%',
89
+ left: 20,
90
+ zIndex: 999,
91
+ width: 30,
92
+ height: 40,
93
+ backgroundColor: COLORS.TRANSPARENT_BLACK,
94
+ display: 'flex',
95
+ alignItems: 'center',
96
+ justifyContent: 'center',
97
+ },
98
+ rightArrow: {
99
+ position: 'absolute',
100
+ top: '46%',
101
+ left: '93%',
102
+ right: 20,
103
+ zIndex: 999,
104
+ width: 30,
105
+ height: 40,
106
+ backgroundColor: COLORS.TRANSPARENT_BLACK,
107
+ display: 'flex',
108
+ alignItems: 'center',
109
+ justifyContent: 'center',
110
+ },
111
+ carouselImage: {
112
+ width: '100%',
113
+ height: '80%',
114
+ },
115
+ carouselContainer: {
116
+ width: deviceWidth - 10,
117
+ margin: 10,
118
+ },
119
+ showMoreImageContainer: {
120
+ justifyContent: 'center',
121
+ alignItems: 'center',
122
+ },
123
+ showMoreImage: {
124
+ width: '100%',
125
+ height: '100%',
126
+ opacity: 0.5,
127
+ },
128
+ showMoreText: {
129
+ fontSize: 30,
130
+ position: 'absolute',
131
+ color: COLORS.BRAND_WHITE,
132
+ },
133
+ });
134
+ };
@@ -33,7 +33,6 @@ const getHeroImage = (cdn, story) => {
33
33
  metaData={getImageMetadata(story)}
34
34
  slug={imageSlug}
35
35
  imageWidth={getScreenPercentageWidth(100)}
36
- hero
37
36
  />
38
37
  );
39
38
  };
@@ -1,12 +1,12 @@
1
- import PropTypes from "prop-types";
2
- import React, { useContext, useRef, useState } from "react";
3
- import { TouchableOpacity, View } from "react-native";
4
- import { FlatList } from "react-native-gesture-handler";
5
- import Icon from "react-native-vector-icons/AntDesign";
6
- import { AppTheme } from "../../utils";
7
- import { Text } from "../index";
8
- import { SlideshowStoryCard } from "../SlideshowStoryCard";
9
- import { storySlideshowStyles } from "./styles";
1
+ import PropTypes from 'prop-types';
2
+ import React, { useContext, useRef, useState } from 'react';
3
+ import { TouchableOpacity, View } from 'react-native';
4
+ import { FlatList } from 'react-native-gesture-handler';
5
+ import Icon from 'react-native-vector-icons/AntDesign';
6
+ import { AppTheme } from '../../utils';
7
+ import { Text } from '../index';
8
+ import { SlideshowStoryCard } from '../SlideshowStoryCard';
9
+ import { storySlideshowStyles } from './styles';
10
10
 
11
11
  export const StorySlideshow = ({ card, cdn }) => {
12
12
  const { theme } = useContext(AppTheme);
@@ -16,13 +16,13 @@ export const StorySlideshow = ({ card, cdn }) => {
16
16
 
17
17
  const flatlistRef = useRef();
18
18
 
19
- const totalSlides = card["story-elements"]?.length;
19
+ const totalSlides = card['story-elements']?.length;
20
20
  const lastSlide = currentIndex + 1 === totalSlides;
21
21
  const firstSlide = currentIndex === 0;
22
22
 
23
23
  const moveNext = () => {
24
24
  if (!lastSlide) {
25
- flatlistRef.current.scrollToIndex({ index: Math.floor(Math.min(currentIndex + 1, totalSlides - 1))});
25
+ flatlistRef.current.scrollToIndex({ index: Math.floor(Math.min(currentIndex + 1, totalSlides - 1)) });
26
26
  setCurrentTabIndex(currentIndex + 1);
27
27
  }
28
28
  };
@@ -35,9 +35,8 @@ export const StorySlideshow = ({ card, cdn }) => {
35
35
  };
36
36
 
37
37
  const showArrow = (direction) => {
38
- const arrowStyles =
39
- direction === "left" ? styles.leftArrow : styles.rightArrow;
40
- const onPressHandler = direction === "left" ? movePrev : moveNext;
38
+ const arrowStyles = direction === 'left' ? styles.leftArrow : styles.rightArrow;
39
+ const onPressHandler = direction === 'left' ? movePrev : moveNext;
41
40
 
42
41
  return (
43
42
  <View style={arrowStyles}>
@@ -53,27 +52,27 @@ export const StorySlideshow = ({ card, cdn }) => {
53
52
  const contentWidth = event.nativeEvent?.contentSize?.width;
54
53
  const layoutWidth = event.nativeEvent?.layoutMeasurement?.width;
55
54
  const value = (xOffset / contentWidth);
56
- const leftThreshold = contentWidth / ( 2 * totalSlides );
57
- const rightThreshold = contentWidth - ( 1.5 ) * layoutWidth;
55
+ const leftThreshold = contentWidth / (2 * totalSlides);
56
+ const rightThreshold = contentWidth - (1.5) * layoutWidth;
58
57
 
59
- if((leftThreshold <= xOffset && (layoutWidth > xOffset || rightThreshold > xOffset ))){
58
+ if ((leftThreshold <= xOffset && (layoutWidth > xOffset || rightThreshold > xOffset))) {
60
59
  setCurrentTabIndex(value * totalSlides);
61
- } else if(xOffset < leftThreshold){
60
+ } else if (xOffset < leftThreshold) {
62
61
  setCurrentTabIndex(0);
63
- } else if(xOffset >= rightThreshold){
64
- setCurrentTabIndex(totalSlides-1);
62
+ } else if (xOffset >= rightThreshold) {
63
+ setCurrentTabIndex(totalSlides - 1);
65
64
  }
66
- }
65
+ };
67
66
 
68
67
  return (
69
- <View style={styles.wrapper}>
68
+ <View>
70
69
  <Text primary style={styles.titleText}>
71
70
  {card.title}
72
71
  </Text>
73
72
 
74
73
  <FlatList
75
74
  ref={flatlistRef}
76
- data={card["story-elements"]}
75
+ data={card['story-elements']}
77
76
  renderItem={({ item }) => <SlideshowStoryCard card={item} cdn={cdn} />}
78
77
  keyExtractor={(item) => item.id}
79
78
  horizontal
@@ -81,9 +80,14 @@ export const StorySlideshow = ({ card, cdn }) => {
81
80
  onScroll={handleScroll}
82
81
  />
83
82
 
84
- {!firstSlide && showArrow("left")}
83
+ {!firstSlide && showArrow('left')}
85
84
 
86
- {!lastSlide && showArrow("right")}
85
+ {!lastSlide && showArrow('right')}
87
86
  </View>
88
87
  );
89
88
  };
89
+
90
+ StorySlideshow.propTypes = {
91
+ cdn: PropTypes.string,
92
+ card: PropTypes.object,
93
+ };
@@ -1,40 +1,36 @@
1
- import { StyleSheet } from "react-native";
1
+ import { StyleSheet } from 'react-native';
2
2
 
3
- export const storySlideshowStyles = ({ FONT_SIZE, COLORS }) =>
4
- StyleSheet.create({
5
- wrapper: {
6
- paddingHorizontal: 10,
7
- },
8
- titleText: {
9
- fontWeight: "normal",
10
- marginBottom: 10,
11
- fontSize: FONT_SIZE.h1,
12
- opacity: 0.8,
13
- },
14
- leftArrow: {
15
- position: "absolute",
16
- top: "46%",
17
- right: "95%",
18
- left: 20,
19
- zIndex: 999,
20
- width: 30,
21
- height: 40,
22
- backgroundColor: COLORS.TRANSPARENT_BLACK,
23
- display: "flex",
24
- alignItems: "center",
25
- justifyContent: "center",
26
- },
27
- rightArrow: {
28
- position: "absolute",
29
- top: "46%",
30
- left: "93%",
31
- right: 20,
32
- zIndex: 999,
33
- width: 30,
34
- height: 40,
35
- backgroundColor: COLORS.TRANSPARENT_BLACK,
36
- display: "flex",
37
- alignItems: "center",
38
- justifyContent: "center",
39
- },
40
- });
3
+ export const storySlideshowStyles = ({ FONT_SIZE, COLORS }) => StyleSheet.create({
4
+ titleText: {
5
+ fontWeight: 'normal',
6
+ marginBottom: 10,
7
+ fontSize: FONT_SIZE.h1,
8
+ opacity: 0.8,
9
+ },
10
+ leftArrow: {
11
+ position: 'absolute',
12
+ top: '46%',
13
+ right: '95%',
14
+ left: 20,
15
+ zIndex: 999,
16
+ width: 30,
17
+ height: 40,
18
+ backgroundColor: COLORS.TRANSPARENT_BLACK,
19
+ display: 'flex',
20
+ alignItems: 'center',
21
+ justifyContent: 'center',
22
+ },
23
+ rightArrow: {
24
+ position: 'absolute',
25
+ top: '46%',
26
+ left: '93%',
27
+ right: 20,
28
+ zIndex: 999,
29
+ width: 30,
30
+ height: 40,
31
+ backgroundColor: COLORS.TRANSPARENT_BLACK,
32
+ display: 'flex',
33
+ alignItems: 'center',
34
+ justifyContent: 'center',
35
+ },
36
+ });
@@ -29,9 +29,11 @@ export function getImageQuality() {
29
29
  if (NETWORK_TYPE) {
30
30
  if (NETWORK_TYPE === 'wifi') {
31
31
  return 100;
32
- } if (NETWORK_TYPE === '4g') {
32
+ }
33
+ if (NETWORK_TYPE === '4g') {
33
34
  return 85;
34
- } if (NETWORK_TYPE === '3g') {
35
+ }
36
+ if (NETWORK_TYPE === '3g') {
35
37
  return 50;
36
38
  }
37
39
  }
@@ -124,13 +126,13 @@ export const getCustomResolutionImageURL = (props, customAspectRatio) => {
124
126
  const { IMAGE_QUALITY } = theme;
125
127
 
126
128
  const {
127
- metaData, slug, imageWidth, cdn,
129
+ metaData, slug, imageWidth, cdn,
128
130
  } = props;
129
131
  const image = new FocusedImage(slug, metaData);
130
132
 
131
133
  const imageCdn = cdn || 'https://www.quintype.com';
132
- return `${imageCdn}/${image.path(customAspectRatio , {
134
+ return `${imageCdn}/${image.path(customAspectRatio, {
133
135
  w: getPixelRatioForDevice(imageWidth) || Math.round(deviceWidth),
134
136
  q: IMAGE_QUALITY,
135
137
  })}`;
136
- }
138
+ };