@times-components/ts-components 1.104.1-alpha.14 → 1.104.1-alpha.34

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.
Files changed (31) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/article-header/ArticleHeader.js +6 -3
  3. package/dist/components/article-header/ArticleHeader.stories.js +2 -5
  4. package/dist/components/article-sidebar/ArticleSidebar.js +6 -3
  5. package/dist/components/article-sidebar/ArticleSidebar.stories.js +20 -10
  6. package/dist/components/article-sidebar/__tests__/index.test.js +49 -7
  7. package/dist/components/article-sidebar/tracking-helpers.d.ts +13 -0
  8. package/dist/components/article-sidebar/tracking-helpers.js +16 -0
  9. package/dist/components/twitter-embed/TwitterEmbed.d.ts +5 -3
  10. package/dist/components/twitter-embed/TwitterEmbed.js +85 -12
  11. package/dist/components/twitter-embed/__tests__/TwitterEmbed.test.js +366 -25
  12. package/dist/components/twitter-embed/styles.d.ts +8 -0
  13. package/dist/components/twitter-embed/styles.js +75 -0
  14. package/dist/components/updated-timestamp/UpdatedTimestamp.js +4 -2
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.js +2 -1
  17. package/package.json +5 -4
  18. package/rnw.js +1 -1
  19. package/src/components/article-header/ArticleHeader.stories.tsx +1 -5
  20. package/src/components/article-header/ArticleHeader.tsx +5 -6
  21. package/src/components/article-sidebar/ArticleSidebar.stories.tsx +24 -10
  22. package/src/components/article-sidebar/ArticleSidebar.tsx +22 -2
  23. package/src/components/article-sidebar/__tests__/__snapshots__/index.test.tsx.snap +8 -8
  24. package/src/components/article-sidebar/__tests__/index.test.tsx +56 -6
  25. package/src/components/article-sidebar/tracking-helpers.ts +21 -0
  26. package/src/components/twitter-embed/TwitterEmbed.tsx +146 -14
  27. package/src/components/twitter-embed/__tests__/TwitterEmbed.test.tsx +523 -22
  28. package/src/components/twitter-embed/styles.ts +82 -0
  29. package/src/components/updated-timestamp/UpdatedTimestamp.tsx +3 -1
  30. package/src/index.ts +2 -0
  31. package/tslint.json +2 -1
@@ -1,54 +1,555 @@
1
1
  import React from 'react';
2
- import { render } from '@testing-library/react';
3
- import { TwitterEmbed } from '../TwitterEmbed'; // Adjust the path as necessary
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import { TwitterEmbed } from '../TwitterEmbed';
4
4
  import '@testing-library/jest-dom';
5
+ import get from 'lodash.get';
6
+
7
+ // Mocking external dependencies
8
+ jest.mock('@times-components/interactive-wrapper', () =>
9
+ jest.fn(() => <div>InteractiveWrapper</div>)
10
+ );
11
+ jest.mock('lodash.get');
5
12
 
6
13
  const mockTcfApi = jest.fn();
7
14
 
8
15
  describe('TwitterEmbed', () => {
9
16
  beforeEach(() => {
17
+ // Reset mocks before each test
10
18
  mockTcfApi.mockReset();
11
19
  window.__tcfapi = mockTcfApi;
12
20
 
13
- // // Mock console.log to avoid using it directly
14
- // tslint:disable-next-line:no-console
15
- jest.spyOn(global.console, 'log').mockImplementation(() => {
16
- // Intentionally left blank for linting rule
17
- });
21
+ /* tslint:disable:no-empty */
22
+ jest.spyOn(global.console, 'log').mockImplementation(() => {});
23
+ /* tslint:disable:no-empty */
24
+ jest.spyOn(global.console, 'warn').mockImplementation(() => {});
18
25
  });
19
26
 
20
27
  afterEach(() => {
28
+ // Restore mocks after each test
21
29
  jest.restoreAllMocks();
22
30
  });
23
31
 
24
- it('logs "TCF API not available" if __tcfapi is not defined', () => {
25
- delete window.__tcfapi;
32
+ it('renders Twitter content if consent is given for Twitter', () => {
33
+ mockTcfApi.mockImplementation((_, __, callback) => {
34
+ callback({ consentedVendors: [{ name: 'Twitter' }] }, true);
35
+ });
36
+
37
+ const mockElement = {
38
+ attributes: {},
39
+ value: 'Twitter content',
40
+ key: 'twitter-embed'
41
+ };
42
+ const url = 'https://twitter.com';
43
+
44
+ render(<TwitterEmbed element={mockElement} url={url} />);
45
+
46
+ // Assert that InteractiveWrapper is rendered
47
+ expect(screen.getByText('InteractiveWrapper')).toBeInTheDocument();
48
+ });
49
+
50
+ it('renders blocked content message if consent for Twitter is not given', () => {
51
+ mockTcfApi.mockImplementation((_, __, callback) => {
52
+ callback({ consentedVendors: [] }, true);
53
+ });
26
54
 
27
- render(<TwitterEmbed sectionColour="blue" />);
55
+ const mockElement = {
56
+ attributes: {},
57
+ value: 'Twitter content',
58
+ key: 'twitter-embed'
59
+ };
60
+ const url = 'https://twitter.com';
28
61
 
29
- // tslint:disable-next-line:no-console
30
- expect(console.log).toHaveBeenCalledWith('TCF API not available');
62
+ render(<TwitterEmbed element={mockElement} url={url} />);
63
+
64
+ // Assert that the blocked content message is rendered
65
+ expect(screen.getByText('X (Twitter) content blocked')).toBeInTheDocument();
66
+ expect(screen.getByText('privacy manager.')).toBeInTheDocument();
67
+ expect(
68
+ screen.getByRole('button', { name: /Enable cookies/i })
69
+ ).toBeInTheDocument();
70
+ expect(
71
+ screen.getByRole('button', { name: /Allow cookies once/i })
72
+ ).toBeInTheDocument();
73
+ });
74
+
75
+ it('calls __tcfapi and logs an error if consent data is unavailable', () => {
76
+ mockTcfApi.mockImplementation((_, __, callback) => {
77
+ callback(null, false);
78
+ });
79
+
80
+ const mockElement = {
81
+ attributes: {},
82
+ value: 'Twitter content',
83
+ key: 'twitter-embed'
84
+ };
85
+ const url = 'https://twitter.com';
86
+
87
+ render(<TwitterEmbed element={mockElement} url={url} />);
88
+
89
+ expect(global.console.log).toHaveBeenCalledWith(
90
+ 'Error fetching consent data or Twitter not allowed'
91
+ );
31
92
  });
32
93
 
33
- it('calls __tcfapi and logs the success response', () => {
34
- // tslint:disable-next-line:no-unused-variable
35
- mockTcfApi.mockImplementation((command, version, callback) => {
36
- callback({ vendorConsents: {} }, true);
37
- // tslint:disable-next-line:no-console
38
- console.log('command', command, version);
94
+ it('enables cookies and unblocks Twitter content', () => {
95
+ mockTcfApi.mockImplementation((_, __, callback) => {
96
+ callback(
97
+ {
98
+ grants: {
99
+ '5fab0c31a22863611c5f8764': { purposeGrants: { '1': true } }
100
+ }
101
+ },
102
+ true
103
+ );
39
104
  });
40
105
 
41
- render(<TwitterEmbed sectionColour="blue" />);
106
+ const mockElement = {
107
+ attributes: {},
108
+ value: 'Twitter content',
109
+ key: 'twitter-embed'
110
+ };
111
+ const url = 'https://twitter.com';
112
+
113
+ render(<TwitterEmbed element={mockElement} url={url} />);
114
+
115
+ fireEvent.click(screen.getByRole('button', { name: /Enable cookies/i }));
42
116
 
117
+ // Ensure that the __tcfapi function is called with the correct arguments
43
118
  expect(mockTcfApi).toHaveBeenCalledWith(
44
119
  'getCustomVendorConsents',
45
120
  2,
46
121
  expect.any(Function)
47
122
  );
48
123
 
49
- // tslint:disable-next-line:no-console
50
- expect(console.log).toHaveBeenCalledWith('TCF API response:', {
51
- vendorConsents: {}
124
+ mockTcfApi.mock.calls[0][2](
125
+ {
126
+ grants: { '5fab0c31a22863611c5f8764': { purposeGrants: { '1': true } } }
127
+ },
128
+ true
129
+ );
130
+
131
+ expect(screen.getByText('InteractiveWrapper')).toBeInTheDocument();
132
+ });
133
+
134
+ it('allows cookies once and unblocks Twitter content temporarily', () => {
135
+ // Mock implementation for __tcfapi
136
+ mockTcfApi.mockImplementation((_, __, callback) => {
137
+ callback(
138
+ {
139
+ grants: {
140
+ '5fab0c31a22863611c5f8764': { purposeGrants: { '1': true } }
141
+ }
142
+ },
143
+ true
144
+ );
52
145
  });
146
+
147
+ const mockElement = {
148
+ attributes: {},
149
+ value: 'Twitter content',
150
+ key: 'twitter-embed'
151
+ };
152
+ const url = 'https://twitter.com';
153
+
154
+ render(<TwitterEmbed element={mockElement} url={url} />);
155
+
156
+ // Click the "Allow cookies once" button
157
+ fireEvent.click(
158
+ screen.getByRole('button', { name: /Allow cookies once/i })
159
+ );
160
+
161
+ // Ensure that Twitter content is unblocked temporarily (InteractiveWrapper is rendered)
162
+ expect(screen.getByText('InteractiveWrapper')).toBeInTheDocument();
163
+
164
+ // Mock that cookies are not permanently set, and content should be blocked again after refresh
165
+ // Here, we just verify that consent was not permanently stored
166
+ mockTcfApi.mockReset(); // Reset the mock to simulate a new page load without consent
167
+
168
+ render(<TwitterEmbed element={mockElement} url={url} />);
169
+
170
+ // Ensure that the blocked content message is rendered again after refresh
171
+ expect(screen.getByText('X (Twitter) content blocked')).toBeInTheDocument();
172
+ });
173
+
174
+ it('handles missing __tcfapi gracefully', () => {
175
+ // Ensure __tcfapi is undefined
176
+ delete window.__tcfapi;
177
+
178
+ const mockElement = {
179
+ attributes: {},
180
+ value: 'Twitter content',
181
+ key: 'twitter-embed'
182
+ };
183
+ const url = 'https://twitter.com';
184
+
185
+ render(<TwitterEmbed element={mockElement} url={url} />);
186
+
187
+ // Ensure that the blocked content message is rendered
188
+ expect(screen.getByText('X (Twitter) content blocked')).toBeInTheDocument();
189
+ expect(global.console.log).toHaveBeenCalledWith('window', window);
190
+ });
191
+
192
+ it('opens privacy modal when available', () => {
193
+ const mockLoadPrivacyManagerModal = jest.fn();
194
+
195
+ // Mock the sourcepoint configuration
196
+ window.__TIMES_CONFIG__ = {
197
+ sourcepoint: {
198
+ gdprMessageId: 'messageIdForGDPR'
199
+ }
200
+ };
201
+
202
+ // Mock get to return loadPrivacyManagerModal function
203
+ (get as jest.Mock).mockReturnValue(mockLoadPrivacyManagerModal);
204
+
205
+ const mockElement = {
206
+ attributes: {},
207
+ value: 'Twitter content',
208
+ key: 'twitter-embed'
209
+ };
210
+ const url = 'https://twitter.com';
211
+
212
+ render(<TwitterEmbed element={mockElement} url={url} />);
213
+
214
+ // Simulate user clicking the privacy manager link
215
+ const privacyManagerLink = screen.getByText('privacy manager.');
216
+ fireEvent.click(privacyManagerLink);
217
+
218
+ // Ensure that the privacy modal load function is called with the correct message ID
219
+ expect(mockLoadPrivacyManagerModal).toHaveBeenCalledWith(
220
+ 'messageIdForGDPR'
221
+ );
222
+ });
223
+
224
+ it('handles missing privacy modal gracefully', () => {
225
+ // Mock get to return undefined (no privacy modal available)
226
+ (get as jest.Mock).mockReturnValue(undefined);
227
+
228
+ const mockElement = {
229
+ attributes: {},
230
+ value: 'Twitter content',
231
+ key: 'twitter-embed'
232
+ };
233
+ const url = 'https://twitter.com';
234
+
235
+ render(<TwitterEmbed element={mockElement} url={url} />);
236
+
237
+ // Simulate user clicking the privacy manager link
238
+ const privacyManagerLink = screen.getByText('privacy manager.');
239
+ fireEvent.click(privacyManagerLink);
240
+
241
+ // Ensure that the console.warn is triggered
242
+ expect(global.console.warn).toHaveBeenCalledWith(
243
+ 'Sourcepoint LoadPrivacyManagerModal is not available'
244
+ );
245
+ });
246
+
247
+ it('allows cookies once for Twitter', () => {
248
+ // Mock implementation for __tcfapi
249
+ mockTcfApi.mockImplementation((_, __, callback) => {
250
+ callback(
251
+ {
252
+ grants: {
253
+ '5fab0c31a22863611c5f8764': { purposeGrants: { '1': true } }
254
+ }
255
+ },
256
+ true
257
+ );
258
+ });
259
+
260
+ const mockElement = {
261
+ attributes: {},
262
+ value: 'Twitter content',
263
+ key: 'twitter-embed'
264
+ };
265
+ const url = 'https://twitter.com';
266
+
267
+ render(<TwitterEmbed element={mockElement} url={url} />);
268
+
269
+ // Click the "Allow cookies once" button
270
+ fireEvent.click(
271
+ screen.getByRole('button', { name: /Allow cookies once/i })
272
+ );
273
+
274
+ // Ensure that the Twitter content is rendered after allowing cookies once
275
+ expect(screen.getByText('InteractiveWrapper')).toBeInTheDocument();
276
+ });
277
+
278
+ it('renders Twitter content when isTwitterAllowed is initially true', () => {
279
+ // Mock implementation to set consent for Twitter from the start
280
+ mockTcfApi.mockImplementation((_, __, callback) => {
281
+ callback({ consentedVendors: [{ name: 'Twitter' }] }, true);
282
+ });
283
+
284
+ const mockElement = {
285
+ attributes: {},
286
+ value: 'Twitter content',
287
+ key: 'twitter-embed'
288
+ };
289
+ const url = 'https://twitter.com';
290
+
291
+ // Initially set isTwitterAllowed to true
292
+ render(<TwitterEmbed element={mockElement} url={url} />);
293
+
294
+ // Ensure Twitter content is immediately displayed
295
+ expect(screen.getByText('InteractiveWrapper')).toBeInTheDocument();
296
+ });
297
+
298
+ it('handles when __tcfapi is not available on window', () => {
299
+ // Ensure __tcfapi is undefined
300
+ delete window.__tcfapi;
301
+
302
+ const mockElement = {
303
+ attributes: {},
304
+ value: 'Twitter content',
305
+ key: 'twitter-embed'
306
+ };
307
+ const url = 'https://twitter.com';
308
+
309
+ render(<TwitterEmbed element={mockElement} url={url} />);
310
+
311
+ // Ensure that blocked content message is rendered when __tcfapi is not available
312
+ expect(screen.getByText('X (Twitter) content blocked')).toBeInTheDocument();
313
+
314
+ // Ensure that console.log is called since __tcfapi is not available
315
+ expect(global.console.log).toHaveBeenCalledWith('window', window);
316
+ });
317
+
318
+ it('handles when __tcfapi is a stub', () => {
319
+ // Define __tcfapi as a stub (noop)
320
+ window.__tcfapi = jest.fn();
321
+
322
+ const mockElement = {
323
+ attributes: {},
324
+ value: 'Twitter content',
325
+ key: 'twitter-embed'
326
+ };
327
+ const url = 'https://twitter.com';
328
+
329
+ render(<TwitterEmbed element={mockElement} url={url} />);
330
+
331
+ // Ensure that blocked content message is rendered since the stub does nothing
332
+ expect(screen.getByText('X (Twitter) content blocked')).toBeInTheDocument();
333
+
334
+ // Ensure __tcfapi was called, even though it is a stub
335
+ expect(window.__tcfapi).toHaveBeenCalledWith(
336
+ 'getCustomVendorConsents',
337
+ 2,
338
+ expect.any(Function)
339
+ );
340
+ });
341
+
342
+ it('allows cookies once when the Allow cookies once button is clicked', () => {
343
+ const mockElement = {
344
+ attributes: {},
345
+ value: 'Twitter content',
346
+ key: 'twitter-embed'
347
+ };
348
+ const url = 'https://twitter.com';
349
+
350
+ render(<TwitterEmbed element={mockElement} url={url} />);
351
+
352
+ // Click the "Allow cookies once" button
353
+ fireEvent.click(
354
+ screen.getByRole('button', { name: /Allow cookies once/i })
355
+ );
356
+
357
+ // Ensure that Twitter content is unblocked temporarily (InteractiveWrapper is rendered)
358
+ expect(screen.getByText('InteractiveWrapper')).toBeInTheDocument();
359
+ });
360
+
361
+ it('calls enableCookies and logs an error when vendor consent data is not found', () => {
362
+ const consoleErrorMock = jest
363
+ .spyOn(global.console, 'error')
364
+ .mockImplementation(() => {});
365
+
366
+ const mockElement = {
367
+ attributes: {},
368
+ value: 'Twitter content',
369
+ key: 'twitter-embed'
370
+ };
371
+ const url = 'https://twitter.com';
372
+
373
+ window.__tcfapi = jest.fn((_, __, callback) => {
374
+ callback(null, true); // Simulate the case where the vendor consent data is missing
375
+ });
376
+
377
+ render(<TwitterEmbed element={mockElement} url={url} />);
378
+
379
+ fireEvent.click(screen.getByRole('button', { name: /Enable cookies/i }));
380
+
381
+ expect(consoleErrorMock).toHaveBeenCalledWith(
382
+ 'Twitter vendor consent not available:',
383
+ null
384
+ );
385
+
386
+ consoleErrorMock.mockRestore();
387
+ });
388
+
389
+ it('calls openPrivacyModal and warns when no modal is available', () => {
390
+ const consoleWarnMock = jest
391
+ .spyOn(global.console, 'warn')
392
+ .mockImplementation(() => {});
393
+
394
+ const mockElement = {
395
+ attributes: {},
396
+ value: 'Twitter content',
397
+ key: 'twitter-embed'
398
+ };
399
+ const url = 'https://twitter.com';
400
+
401
+ render(<TwitterEmbed element={mockElement} url={url} />);
402
+
403
+ // Simulate clicking the privacy manager link
404
+ const privacyManagerLink = screen.getByText('privacy manager.');
405
+ fireEvent.click(privacyManagerLink);
406
+
407
+ // Expect the console warning to be called
408
+ expect(consoleWarnMock).toHaveBeenCalledWith(
409
+ 'Sourcepoint LoadPrivacyManagerModal is not available'
410
+ );
411
+
412
+ consoleWarnMock.mockRestore();
413
+ });
414
+
415
+ it('logs error when consent setting fails', () => {
416
+ const consoleErrorMock = jest
417
+ .spyOn(global.console, 'error')
418
+ .mockImplementation(() => {});
419
+
420
+ const mockElement = {
421
+ attributes: {},
422
+ value: 'Twitter content',
423
+ key: 'twitter-embed'
424
+ };
425
+ const url = 'https://twitter.com';
426
+
427
+ window.__tcfapi = jest.fn((_, __, callback) => {
428
+ callback(
429
+ {
430
+ grants: {
431
+ '5fab0c31a22863611c5f8764': { purposeGrants: { '1': true } }
432
+ }
433
+ },
434
+ false
435
+ ); // Simulate failure
436
+ });
437
+
438
+ render(<TwitterEmbed element={mockElement} url={url} />);
439
+
440
+ fireEvent.click(screen.getByRole('button', { name: /Enable cookies/i }));
441
+
442
+ expect(consoleErrorMock).toHaveBeenCalledWith(
443
+ 'Twitter vendor consent not available:',
444
+ {
445
+ grants: { '5fab0c31a22863611c5f8764': { purposeGrants: { '1': true } } }
446
+ }
447
+ );
448
+
449
+ consoleErrorMock.mockRestore();
450
+ });
451
+
452
+ it('calls enableCookies and logs a console error when TCF API is not available', () => {
453
+ const consoleErrorMock = jest
454
+ .spyOn(global.console, 'error')
455
+ .mockImplementation(() => {});
456
+
457
+ const mockElement = {
458
+ attributes: {},
459
+ value: 'Twitter content',
460
+ key: 'twitter-embed'
461
+ };
462
+ const url = 'https://twitter.com';
463
+
464
+ // Simulate missing __tcfapi
465
+ delete window.__tcfapi;
466
+
467
+ render(<TwitterEmbed element={mockElement} url={url} />);
468
+
469
+ // Simulate clicking the "Enable cookies" button
470
+ fireEvent.click(screen.getByRole('button', { name: /Enable cookies/i }));
471
+
472
+ // Expect a console error
473
+ expect(consoleErrorMock).toHaveBeenCalledWith(
474
+ 'TCF API is not available or Twitter vendor ID is missing.'
475
+ );
476
+
477
+ consoleErrorMock.mockRestore();
478
+ });
479
+
480
+ it('calls enableCookies and logs a console error when TCF API is not available', () => {
481
+ const consoleErrorMock = jest
482
+ .spyOn(global.console, 'error')
483
+ .mockImplementation(() => {});
484
+
485
+ const mockElement = {
486
+ attributes: {},
487
+ value: 'Twitter content',
488
+ key: 'twitter-embed'
489
+ };
490
+ const url = 'https://twitter.com';
491
+
492
+ delete window.__tcfapi;
493
+
494
+ render(<TwitterEmbed element={mockElement} url={url} />);
495
+
496
+ fireEvent.click(screen.getByRole('button', { name: /Enable cookies/i }));
497
+
498
+ expect(consoleErrorMock).toHaveBeenCalledWith(
499
+ 'TCF API is not available or Twitter vendor ID is missing.'
500
+ );
501
+
502
+ consoleErrorMock.mockRestore();
503
+ });
504
+ it('calls enableCookies and logs a console error when TCF API is not available', () => {
505
+ const consoleErrorMock = jest
506
+ .spyOn(global.console, 'error')
507
+ .mockImplementation(() => {});
508
+
509
+ const mockElement = {
510
+ attributes: {},
511
+ value: 'Twitter content',
512
+ key: 'twitter-embed'
513
+ };
514
+ const url = 'https://twitter.com';
515
+
516
+ delete window.__tcfapi;
517
+
518
+ render(<TwitterEmbed element={mockElement} url={url} />);
519
+
520
+ fireEvent.click(screen.getByRole('button', { name: /Enable cookies/i }));
521
+
522
+ expect(consoleErrorMock).toHaveBeenCalledWith(
523
+ 'TCF API is not available or Twitter vendor ID is missing.'
524
+ );
525
+
526
+ consoleErrorMock.mockRestore();
527
+ });
528
+
529
+ it('logs a warning when the privacy modal is unavailable', () => {
530
+ const consoleWarnMock = jest
531
+ .spyOn(global.console, 'warn')
532
+ .mockImplementation(() => {});
533
+
534
+ const mockElement = {
535
+ attributes: {},
536
+ value: 'Twitter content',
537
+ key: 'twitter-embed'
538
+ };
539
+ const url = 'https://twitter.com';
540
+
541
+ (get as jest.Mock).mockReturnValue(undefined);
542
+
543
+ render(<TwitterEmbed element={mockElement} url={url} />);
544
+
545
+ // Simulate clicking the privacy manager link
546
+ fireEvent.click(screen.getByText('privacy manager.'));
547
+
548
+ // Expect the warning to be logged
549
+ expect(consoleWarnMock).toHaveBeenCalledWith(
550
+ 'Sourcepoint LoadPrivacyManagerModal is not available'
551
+ );
552
+
553
+ consoleWarnMock.mockRestore();
53
554
  });
54
555
  });
@@ -0,0 +1,82 @@
1
+ import styled from 'styled-components';
2
+ import { breakpoints } from '@times-components/ts-styleguide';
3
+ import { IconContainer } from '../save-star/styles';
4
+
5
+ export const CardContainer = styled.div`
6
+ padding: 24px;
7
+ height: auto;
8
+ width: auto;
9
+ border: 1px solid #e4e4e4;
10
+ background-color: #f5f5f5;
11
+ margin: 0;
12
+ max-width: 460px;
13
+ `;
14
+
15
+ export const Header = styled.div`
16
+ display: flex;
17
+ `;
18
+
19
+ export const CustomIconContainer = styled(IconContainer)`
20
+ height: auto;
21
+ width: auto;
22
+ margin-right: 8px;
23
+ svg {
24
+ fill: #1573a2;
25
+ width: 20px;
26
+ height: 20px;
27
+ }
28
+ `;
29
+
30
+ export const Title = styled.h1`
31
+ color: #005c8a;
32
+ font-family: Roboto;
33
+ font-size: 20px;
34
+ font-style: normal;
35
+ font-weight: 700;
36
+ line-height: 112.5%;
37
+ margin: 0;
38
+
39
+ @media (max-width: ${breakpoints.medium}px) {
40
+ font-size: 18px;
41
+ }
42
+ `;
43
+
44
+ export const Paragraph = styled.p`
45
+ color: #333;
46
+ font-family: Roboto;
47
+ font-size: 18px;
48
+ font-style: normal;
49
+ font-weight: 400;
50
+ line-height: 150%;
51
+
52
+ @media (max-width: ${breakpoints.medium}px) {
53
+ font-size: 16px;
54
+ }
55
+ `;
56
+
57
+ export const EnableButton = styled.button`
58
+ display: flex;
59
+ align-items: flex-start;
60
+ align-self: stretch;
61
+ background-color: #005c8a;
62
+ padding: 8px 12px;
63
+ width: 100%;
64
+ justify-content: center;
65
+ color: #ffffff;
66
+ border: none;
67
+ `;
68
+
69
+ export const AllowButton = styled.button`
70
+ display: flex;
71
+ align-items: flex-start;
72
+ align-self: stretch;
73
+ color: #333333;
74
+ width: 100%;
75
+ justify-content: center;
76
+ margin-top: 12px;
77
+ padding: 8px 12px;
78
+ `;
79
+
80
+ export const LinkPrivacyManager = styled.a`
81
+ color: #00527a;
82
+ `;
@@ -1,5 +1,7 @@
1
1
  import React from 'react';
2
- import { differenceInSeconds, format, formatDistanceStrict } from 'date-fns';
2
+ import differenceInSeconds from 'date-fns/differenceInSeconds';
3
+ import formatDistanceStrict from 'date-fns/formatDistanceStrict';
4
+ import format from 'date-fns/format';
3
5
 
4
6
  import { Container, TimeSinceUpdate } from './styles';
5
7
 
package/src/index.ts CHANGED
@@ -118,3 +118,5 @@ export { ArticleSidebar } from './components/article-sidebar/ArticleSidebar';
118
118
  export {
119
119
  FeaturesCarousel
120
120
  } from './components/features-carousel/FeaturesCarousel';
121
+
122
+ export { TwitterEmbed } from './components/twitter-embed/TwitterEmbed';
package/tslint.json CHANGED
@@ -11,6 +11,7 @@
11
11
  "object-literal-sort-keys": false,
12
12
  "member-access": false,
13
13
  "ordered-imports": false,
14
- "interface-over-type-literal": false
14
+ "interface-over-type-literal": false,
15
+ "no-submodule-imports": false
15
16
  }
16
17
  }