@treely/strapi-slices 4.0.0 → 4.1.1

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.
@@ -0,0 +1,332 @@
1
+ import React, { useContext } from 'react';
2
+ import {
3
+ Button,
4
+ Box,
5
+ Container,
6
+ DefaultSectionContainer,
7
+ DefaultSectionHeader,
8
+ Flex,
9
+ Heading,
10
+ RichText,
11
+ SimpleGrid,
12
+ Spacer,
13
+ Tag,
14
+ Text,
15
+ Wrapper,
16
+ useMediaQuery,
17
+ } from 'boemly';
18
+ import Image from 'next/image';
19
+ import StrapiImage from '../../models/strapi/StrapiImage';
20
+ import strapiMediaUrl from '../../utils/strapiMediaUrl';
21
+ import StrapiLink from '../../models/strapi/StrapiLink';
22
+ import StrapiLinkButton from '../../components/StrapiLinkButton';
23
+ import { CDN_URI } from '../../constants/api';
24
+ import { IntlContext } from 'react-intl';
25
+ import { BREAKPOINT_MD_QUERY } from '../../constants/breakpoints';
26
+ import { useState } from 'react';
27
+ import { FormattedMessage } from 'react-intl';
28
+ import FullScreenImage from '../../components/FullScreenImage';
29
+
30
+ export interface TimelineProps {
31
+ slice: {
32
+ title: string;
33
+ text?: string;
34
+ tagline?: string;
35
+
36
+ timelineItems: TimelineItem[];
37
+ };
38
+ }
39
+
40
+ export interface TimelineItem {
41
+ id: number;
42
+ tagline?: string;
43
+ title: string;
44
+ text?: string;
45
+ badge?: { text: string; variant: 'orange' | 'green' | 'red' | 'gray' };
46
+ logo?: StrapiImage;
47
+ icon?: StrapiImage;
48
+ image?: StrapiImage;
49
+ button?: StrapiLink;
50
+ backgroundShapes?: boolean;
51
+ }
52
+
53
+ export const Timeline: React.FC<TimelineProps> = ({ slice }: TimelineProps) => {
54
+ const { formatMessage } = useContext(IntlContext);
55
+ const [visibleItems, setVisibleItems] = useState(3);
56
+ const [mobile] = useMediaQuery(BREAKPOINT_MD_QUERY);
57
+ const [isOpen, setIsOpen] = useState(false);
58
+
59
+ const showMoreItems = () => {
60
+ setVisibleItems((prevVisibleItems) => prevVisibleItems + 3);
61
+ };
62
+
63
+ return (
64
+ <DefaultSectionContainer>
65
+ <Wrapper>
66
+ <Flex flexDir={['column', null, null, 'row']}>
67
+ <Box
68
+ width={['full', null, null, '50%']}
69
+ position={[null, null, null, 'sticky']}
70
+ top={['16', null, null, '32']}
71
+ height="full"
72
+ paddingRight={[null, null, null, '28']}
73
+ >
74
+ <DefaultSectionHeader
75
+ tagline={slice.tagline}
76
+ title={slice.title}
77
+ text={slice.text}
78
+ />
79
+ {mobile && (
80
+ <>
81
+ <Spacer h="10" />
82
+ <Flex justifyContent="center">
83
+ <Box
84
+ borderRadius="full"
85
+ width="3"
86
+ height="3"
87
+ margin="1.5"
88
+ backgroundColor="gray"
89
+ />
90
+ </Flex>
91
+ <Box
92
+ overflow="visible"
93
+ borderRight="dashed 1px var(--boemly-colors-gray-200)"
94
+ transform="translateX(-50%)"
95
+ position="relative"
96
+ height="20"
97
+ />
98
+ </>
99
+ )}
100
+ </Box>
101
+ <Box
102
+ overflow="visible"
103
+ maxWidth={['full', null, null, '50%']}
104
+ borderLeft={[
105
+ null,
106
+ null,
107
+ null,
108
+ 'dashed 1px var(--boemly-colors-gray-200)',
109
+ ]}
110
+ position="relative"
111
+ width="full"
112
+ >
113
+ <Flex
114
+ flexDir="column"
115
+ overflow="visible"
116
+ gap={[null, null, null, '8']}
117
+ >
118
+ {slice.timelineItems.slice(0, visibleItems).map((item, index) => (
119
+ <SimpleGrid
120
+ gap={['none', null, null, '4']}
121
+ key={item.id}
122
+ columns={[1, null, null, 2]}
123
+ alignContent="center"
124
+ gridTemplateColumns={[null, null, null, '5% 85%']}
125
+ position="relative"
126
+ >
127
+ <Flex
128
+ alignItems="center"
129
+ justifyContent={['center', null, null, 'flex-start']}
130
+ >
131
+ <Box
132
+ position="absolute"
133
+ transform={[null, null, null, 'translateX(-50%)']}
134
+ backgroundColor="white"
135
+ >
136
+ {item.icon ? (
137
+ <Box padding="2">
138
+ <Image
139
+ src={strapiMediaUrl(item.icon.img, 'xSmall')}
140
+ alt={item.icon.alt}
141
+ width="21"
142
+ height="21"
143
+ />
144
+ </Box>
145
+ ) : (
146
+ <Box padding="2">
147
+ <Box
148
+ borderRadius="full"
149
+ backgroundColor="primary.800"
150
+ width="2"
151
+ height="2"
152
+ />
153
+ </Box>
154
+ )}
155
+ {mobile && (
156
+ <Box
157
+ overflow="visible"
158
+ borderRight="dashed 1px var(--boemly-colors-gray-200)"
159
+ transform="translateX(-50%)"
160
+ position="relative"
161
+ height="10"
162
+ />
163
+ )}
164
+ </Box>
165
+ </Flex>
166
+ <Container
167
+ p={[null, null, null, '3']}
168
+ zIndex="base"
169
+ position="relative"
170
+ elevation="none"
171
+ >
172
+ {item.backgroundShapes ? (
173
+ <Box
174
+ position="absolute"
175
+ left="0"
176
+ top="0"
177
+ width="full"
178
+ height="full"
179
+ zIndex="-1"
180
+ >
181
+ <Image
182
+ src={`${CDN_URI}/assets/v3/strapi-slices/timeline-shapes.svg`}
183
+ alt={formatMessage({
184
+ id: 'sections.timeline.backgroundShapes',
185
+ })}
186
+ fill
187
+ style={{
188
+ objectFit: 'cover',
189
+ borderRadius: 'var(--boemly-radii-xl)',
190
+ }}
191
+ />
192
+ </Box>
193
+ ) : (
194
+ <></>
195
+ )}
196
+
197
+ <Flex flexDir="column">
198
+ <Flex
199
+ alignItems="flex-start"
200
+ justifyContent="space-between"
201
+ >
202
+ <Box>
203
+ {item.tagline && (
204
+ <>
205
+ <Text color="primary.800" size="smMonoUppercase">
206
+ {item.tagline}
207
+ </Text>
208
+ <Spacer h="2" />
209
+ </>
210
+ )}
211
+ </Box>
212
+ <Flex>
213
+ {item.badge && (
214
+ <Tag
215
+ colorScheme={item.badge.variant}
216
+ borderRadius="md"
217
+ >
218
+ {item.badge.text}
219
+ </Tag>
220
+ )}
221
+ {item.logo && (
222
+ <Box position="relative" height="8" width="16">
223
+ <Image
224
+ src={strapiMediaUrl(item.logo.img, 'small')}
225
+ alt={item.logo.alt}
226
+ fill
227
+ style={{
228
+ objectFit: item.logo.objectFit,
229
+ }}
230
+ />
231
+ </Box>
232
+ )}
233
+ </Flex>
234
+ </Flex>
235
+ <Heading
236
+ size="lg"
237
+ mt={['6', null, null, '3']}
238
+ maxWidth="xs"
239
+ >
240
+ {item.title}
241
+ </Heading>
242
+ {item.text && (
243
+ <Box mt="3">
244
+ <RichText content={item.text} />
245
+ </Box>
246
+ )}
247
+ {item.button && (
248
+ <Box textAlign="left">
249
+ <Spacer h="4" />
250
+ <StrapiLinkButton
251
+ link={item.button}
252
+ size="sm"
253
+ variant="outline"
254
+ />
255
+ </Box>
256
+ )}
257
+ {item.image ? (
258
+ <>
259
+ <Box
260
+ position="relative"
261
+ mt="4"
262
+ height={['2xs', null, null, null, '48']}
263
+ minWidth={[null, null, null, null, '50%']}
264
+ >
265
+ <Image
266
+ src={strapiMediaUrl(item.image.img, 'xLarge')}
267
+ alt={item.image.alt}
268
+ fill
269
+ style={{
270
+ cursor: mobile ? 'unset' : 'pointer',
271
+ objectFit: item.image.objectFit || 'cover',
272
+ borderRadius: 'var(--boemly-radii-xl)',
273
+ }}
274
+ onClick={() => !mobile && setIsOpen(true)}
275
+ />
276
+ <FullScreenImage
277
+ images={[item.image]}
278
+ isOpen={isOpen}
279
+ onClose={() => setIsOpen(false)}
280
+ />
281
+ </Box>
282
+ </>
283
+ ) : (
284
+ <></>
285
+ )}
286
+ </Flex>
287
+ </Container>
288
+ {mobile && index + 1 < slice.timelineItems.length && (
289
+ <Box
290
+ overflow="visible"
291
+ borderRight="dashed 1px var(--boemly-colors-gray-200)"
292
+ transform="translateX(-50%)"
293
+ position="relative"
294
+ height="20"
295
+ />
296
+ )}
297
+ </SimpleGrid>
298
+ ))}
299
+ </Flex>
300
+ {visibleItems < slice.timelineItems.length && (
301
+ <>
302
+ <Box
303
+ width="full"
304
+ height={['36', null, null, '64']}
305
+ position="absolute"
306
+ bottom="0"
307
+ zIndex="1"
308
+ background="linear-gradient(180deg, rgba(255, 255, 255, 0.00) 0%, rgba(255, 255, 255, 0.98) 76.54%, #FFF 100%)"
309
+ />
310
+ <Box
311
+ bottom="0"
312
+ textAlign="center"
313
+ zIndex="overlay"
314
+ position="relative"
315
+ >
316
+ <Button
317
+ variant="outline"
318
+ size="sm"
319
+ onClick={showMoreItems}
320
+ m={[null, null, null, '8']}
321
+ >
322
+ <FormattedMessage id="sections.timeline.showMoreButton" />
323
+ </Button>
324
+ </Box>
325
+ </>
326
+ )}
327
+ </Box>
328
+ </Flex>
329
+ </Wrapper>
330
+ </DefaultSectionContainer>
331
+ );
332
+ };
@@ -0,0 +1,3 @@
1
+ import { Timeline } from './Timeline';
2
+
3
+ export default Timeline;
@@ -0,0 +1,5 @@
1
+ const messagesDe = {
2
+ 'sections.timeline.backgroundShapes': 'Hintergrundformen',
3
+ 'sections.timeline.showMoreButton': 'Drei weitere Meilensteine anzeigen',
4
+ };
5
+ export default messagesDe;
@@ -0,0 +1,5 @@
1
+ const messagesEn = {
2
+ 'sections.timeline.backgroundShapes': 'Background shapes',
3
+ 'sections.timeline.showMoreButton': 'Show three more milestones',
4
+ };
5
+ export default messagesEn;