@nyris/nyris-webapp 0.3.53 → 0.3.55

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 (110) hide show
  1. package/build/asset-manifest.json +8 -7
  2. package/build/images/fav2/android-chrome-192x192.png +0 -0
  3. package/build/images/fav2/android-chrome-512x512.png +0 -0
  4. package/build/images/fav2/apple-touch-icon.png +0 -0
  5. package/build/images/fav2/browserconfig.xml +9 -0
  6. package/build/images/fav2/favicon-16x16.png +0 -0
  7. package/build/images/fav2/favicon-32x32.png +0 -0
  8. package/build/images/fav2/favicon.ico +0 -0
  9. package/build/images/fav2/mstile-144x144.png +0 -0
  10. package/build/images/fav2/mstile-150x150.png +0 -0
  11. package/build/images/fav2/mstile-310x150.png +0 -0
  12. package/build/images/fav2/mstile-310x310.png +0 -0
  13. package/build/images/fav2/mstile-70x70.png +0 -0
  14. package/build/images/fav2/safari-pinned-tab.svg +67 -0
  15. package/build/images/fav2/site.webmanifest +19 -0
  16. package/build/index.html +1 -1
  17. package/build/js/settings.example.js +1 -2
  18. package/build/manifest.json +13 -18
  19. package/build/static/css/main.d7425370.css +2 -0
  20. package/build/static/css/main.d7425370.css.map +1 -0
  21. package/build/static/js/main.7b9e6c68.js +3 -0
  22. package/build/static/js/{main.ebb92e93.js.LICENSE.txt → main.7b9e6c68.js.LICENSE.txt} +1 -1
  23. package/build/static/js/main.7b9e6c68.js.map +1 -0
  24. package/build/static/media/path.b99a15de38340a04f80828bceeab9884.svg +3 -0
  25. package/package.json +3 -3
  26. package/public/images/fav2/android-chrome-192x192.png +0 -0
  27. package/public/images/fav2/android-chrome-512x512.png +0 -0
  28. package/public/images/fav2/apple-touch-icon.png +0 -0
  29. package/public/images/fav2/browserconfig.xml +9 -0
  30. package/public/images/fav2/favicon-16x16.png +0 -0
  31. package/public/images/fav2/favicon-32x32.png +0 -0
  32. package/public/images/fav2/favicon.ico +0 -0
  33. package/public/images/fav2/mstile-144x144.png +0 -0
  34. package/public/images/fav2/mstile-150x150.png +0 -0
  35. package/public/images/fav2/mstile-310x150.png +0 -0
  36. package/public/images/fav2/mstile-310x310.png +0 -0
  37. package/public/images/fav2/mstile-70x70.png +0 -0
  38. package/public/images/fav2/safari-pinned-tab.svg +67 -0
  39. package/public/images/fav2/site.webmanifest +19 -0
  40. package/public/index.html +8 -90
  41. package/public/js/settings.example.js +1 -2
  42. package/public/manifest.json +13 -18
  43. package/src/Store/Store.ts +0 -1
  44. package/src/Store/search/Search.ts +33 -74
  45. package/src/Store/search/search.initialState.ts +5 -4
  46. package/src/Store/search/types.ts +5 -4
  47. package/src/common/assets/icons/path.svg +3 -0
  48. package/src/components/AppMobile.tsx +0 -1
  49. package/src/components/DragDropFile.tsx +36 -28
  50. package/src/components/Experience-visual-search/ExperienceVisualSearch.scss +3 -4
  51. package/src/components/Experience-visual-search/ExperienceVisualSearch.tsx +14 -7
  52. package/src/components/Feedback.tsx +5 -5
  53. package/src/components/FooterMobile.tsx +4 -5
  54. package/src/components/GoBackButton.tsx +54 -0
  55. package/src/components/Header.tsx +27 -3
  56. package/src/components/HeaderMobile.tsx +29 -12
  57. package/src/components/ImagePreviewMobile.tsx +6 -3
  58. package/src/components/Inquiry/InquiryBanner.tsx +1 -1
  59. package/src/components/Layout.tsx +5 -14
  60. package/src/components/PanelResult/PostFilterAlgolia.tsx +3 -2
  61. package/src/components/ProductDetailView.tsx +338 -330
  62. package/src/components/ProductList/index.tsx +1 -1
  63. package/src/components/appMobile.scss +7 -0
  64. package/src/components/clear-refinements/clear-refinements.tsx +1 -1
  65. package/src/components/common.scss +18 -7
  66. package/src/components/current-refinements/current-refinements.tsx +10 -22
  67. package/src/components/drawer/cameraCustom.tsx +12 -1
  68. package/src/components/input/inputSearch.tsx +79 -21
  69. package/src/components/pre-filter/index.tsx +23 -7
  70. package/src/components/results/ItemResult.tsx +296 -281
  71. package/src/index.tsx +12 -14
  72. package/src/page/landingPage/AppMobile.tsx +3 -9
  73. package/src/page/landingPage/common.scss +164 -48
  74. package/src/page/result/index.tsx +116 -87
  75. package/src/translations.ts +3 -0
  76. package/src/types.ts +1 -0
  77. package/build/images/fav/android-icon-192x192.png +0 -0
  78. package/build/images/fav/apple-icon-114x114.png +0 -0
  79. package/build/images/fav/apple-icon-120x120.png +0 -0
  80. package/build/images/fav/apple-icon-144x144.png +0 -0
  81. package/build/images/fav/apple-icon-152x152.png +0 -0
  82. package/build/images/fav/apple-icon-180x180.png +0 -0
  83. package/build/images/fav/apple-icon-57x57.png +0 -0
  84. package/build/images/fav/apple-icon-60x60.png +0 -0
  85. package/build/images/fav/apple-icon-72x72.png +0 -0
  86. package/build/images/fav/apple-icon-76x76.png +0 -0
  87. package/build/images/fav/browserconfig.xml +0 -2
  88. package/build/images/fav/favicon-16x16.png +0 -0
  89. package/build/images/fav/favicon-32x32.png +0 -0
  90. package/build/images/fav/favicon-96x96.png +0 -0
  91. package/build/images/fav/manifest.json +0 -35
  92. package/build/static/css/main.8c0eb6c0.css +0 -2
  93. package/build/static/css/main.8c0eb6c0.css.map +0 -1
  94. package/build/static/js/main.ebb92e93.js +0 -3
  95. package/build/static/js/main.ebb92e93.js.map +0 -1
  96. package/public/images/fav/android-icon-192x192.png +0 -0
  97. package/public/images/fav/apple-icon-114x114.png +0 -0
  98. package/public/images/fav/apple-icon-120x120.png +0 -0
  99. package/public/images/fav/apple-icon-144x144.png +0 -0
  100. package/public/images/fav/apple-icon-152x152.png +0 -0
  101. package/public/images/fav/apple-icon-180x180.png +0 -0
  102. package/public/images/fav/apple-icon-57x57.png +0 -0
  103. package/public/images/fav/apple-icon-60x60.png +0 -0
  104. package/public/images/fav/apple-icon-72x72.png +0 -0
  105. package/public/images/fav/apple-icon-76x76.png +0 -0
  106. package/public/images/fav/browserconfig.xml +0 -2
  107. package/public/images/fav/favicon-16x16.png +0 -0
  108. package/public/images/fav/favicon-32x32.png +0 -0
  109. package/public/images/fav/favicon-96x96.png +0 -0
  110. package/public/images/fav/manifest.json +0 -35
@@ -6,6 +6,7 @@ import React, {
6
6
  useRef,
7
7
  useState,
8
8
  } from 'react';
9
+ import { useHistory } from 'react-router-dom';
9
10
  import ArrowLeftIcon from '@material-ui/icons/ArrowLeft';
10
11
  import ArrowRightIcon from '@material-ui/icons/ArrowRight';
11
12
 
@@ -33,8 +34,13 @@ import {
33
34
  setRequestImage,
34
35
  setSearchResults,
35
36
  setSelectedRegion,
37
+ setShowFeedback,
36
38
  updateResultChangePosition,
37
39
  updateStatusLoading,
40
+ setFirstSearchResults,
41
+ setFirstSearchImage,
42
+ setFirstSearchPrefilters,
43
+ setFirstSearchThumbSearchInput,
38
44
  } from 'Store/search/Search';
39
45
  import { useAppDispatch, useAppSelector } from 'Store/Store';
40
46
  import { showHits } from '../../constants';
@@ -50,6 +56,7 @@ import { useQuery } from 'hooks/useQuery';
50
56
  import { ReactComponent as PoweredByNyrisImage } from 'common/assets/images/powered_by_nyris.svg';
51
57
  import Feedback from 'components/Feedback';
52
58
  import { SelectedPostFilter } from 'components/SelectedPostFilter';
59
+ import { GoBack } from '../../components/GoBackButton';
53
60
 
54
61
  interface Props {
55
62
  allSearchResults: any;
@@ -70,6 +77,10 @@ function ResultComponent(props: Props) {
70
77
  loadingSearchAlgolia,
71
78
  imageThumbSearchInput,
72
79
  results,
80
+ showFeedback,
81
+ firstSearchResults,
82
+ firstSearchImage,
83
+ fetchingResults,
73
84
  } = search;
74
85
 
75
86
  const isMobile = useMediaQuery({ query: '(max-width: 776px)' });
@@ -86,19 +97,17 @@ function ResultComponent(props: Props) {
86
97
  const [isRfqModalOpen, setIsRfqModalOpen] = useState(false);
87
98
  const imageUploadRef = useRef(null);
88
99
  const rfqRef = useRef<any>(null);
89
- const [isScrolled, setIsScrolled] = useState<
90
- 'not-scrolled' | 'scrolled' | 'user-scrolled'
91
- >('not-scrolled');
92
-
93
- const [showFeedback, setShowFeedback] = useState<
94
- 'not-scrolled' | 'scrolled' | 'user-scrolled'
95
- >('not-scrolled');
96
100
 
101
+ const [feedbackStatus, setFeedbackStatus] = useState<
102
+ 'hidden' | 'submitted' | 'visible'
103
+ >();
97
104
  const [showFeedbackSuccess, setShowFeedbackSuccess] = useState(false);
105
+ const [showSearchBar, setShowSearchBar] = useState(false);
98
106
  const query = useQuery();
99
107
  const searchQuery = query.get('query') || search.valueTextSearch.query;
100
108
  const isAlgoliaEnabled = settings.algolia?.enabled;
101
109
  const isPostFilterEnabled = settings.postFilterOption;
110
+ const history = useHistory();
102
111
 
103
112
  useEffect(() => {
104
113
  if (
@@ -119,19 +128,24 @@ function ResultComponent(props: Props) {
119
128
  }
120
129
  }, [imageThumbSearchInput, loadingSearchAlgolia]);
121
130
 
131
+ useEffect(() => {
132
+ if (loadingSearchAlgolia) {
133
+ setFeedbackStatus('hidden');
134
+ setShowFeedbackSuccess(false);
135
+ }
136
+ }, [loadingSearchAlgolia]);
137
+
122
138
  useEffect(() => {
123
139
  if (selectedRegion) {
124
140
  setImageSelection(selectedRegion);
125
141
  setRfqStatus('inactive');
126
- setIsScrolled('not-scrolled');
127
- setShowFeedback('not-scrolled');
142
+ setFeedbackStatus('hidden');
128
143
  }
129
144
  }, [selectedRegion]);
130
145
 
131
146
  useEffect(() => {
132
147
  if (requestImage) {
133
- setIsScrolled('not-scrolled');
134
- setShowFeedback('not-scrolled');
148
+ setFeedbackStatus('hidden');
135
149
  executeScroll();
136
150
  setImageSelection(DEFAULT_REGION);
137
151
  }
@@ -142,7 +156,7 @@ function ResultComponent(props: Props) {
142
156
  const preFilterValues = [
143
157
  {
144
158
  key: settings.visualSearchFilterKey,
145
- values: Object.keys(preFilter) as string[],
159
+ values: Object.keys(preFilter)
146
160
  },
147
161
  ];
148
162
  dispatch(loadingActionResults());
@@ -225,7 +239,7 @@ function ResultComponent(props: Props) {
225
239
  const preFilterValues = [
226
240
  {
227
241
  key: settings.visualSearchFilterKey,
228
- values: Object.keys(preFilter) as string[],
242
+ values: Object.keys(preFilter),
229
243
  },
230
244
  ];
231
245
  find({
@@ -234,6 +248,14 @@ function ResultComponent(props: Props) {
234
248
  region: searchRegion,
235
249
  filters: !isEmpty(preFilter) ? preFilterValues : undefined,
236
250
  }).then((res: any) => {
251
+ if (!firstSearchResults) {
252
+ dispatch(setFirstSearchResults(res));
253
+ dispatch(setFirstSearchImage(image));
254
+ dispatch(setFirstSearchPrefilters(preFilter));
255
+ if (!isMobile) {
256
+ dispatch(setFirstSearchThumbSearchInput(url))
257
+ }
258
+ }
237
259
  dispatch(setSearchResults(res));
238
260
  dispatch(updateStatusLoading(false));
239
261
  return;
@@ -253,6 +275,7 @@ function ResultComponent(props: Props) {
253
275
 
254
276
  useEffect(() => {
255
277
  document.title = 'Search results';
278
+ setFeedbackStatus('hidden');
256
279
 
257
280
  if (requestImage || isEmpty(searchQuery)) return;
258
281
  const preFilterValues = Object.keys(preFilter) as string[];
@@ -302,6 +325,15 @@ function ResultComponent(props: Props) {
302
325
  // eslint-disable-next-line react-hooks/exhaustive-deps
303
326
  }, [filterSkusString, settings.alogoliaFilterField]);
304
327
 
328
+ useEffect(() => {
329
+ if (history.location?.pathname === '/') {
330
+ setShowSearchBar(true);
331
+ } else {
332
+ setShowSearchBar(false);
333
+ }
334
+ // eslint-disable-next-line react-hooks/exhaustive-deps
335
+ }, [history.location]);
336
+
305
337
  // eslint-disable-next-line react-hooks/exhaustive-deps
306
338
  const debouncedOnImageSelectionChange = useCallback(
307
339
  debounce((r: RectCoords) => {
@@ -328,48 +360,41 @@ function ResultComponent(props: Props) {
328
360
  }, [showPostFilter, isPostFilterEnabled, requestImage]);
329
361
 
330
362
  useEffect(() => {
331
- const handleScroll = () => {
332
- setTimeout(() => {
333
- setIsScrolled(s => (s === 'not-scrolled' ? 'scrolled' : s));
334
- setTimeout(() => {
335
- setIsScrolled(s => (s === 'scrolled' ? 'user-scrolled' : s));
336
- }, 5000);
337
- }, 1000);
338
- };
339
- if (requestImage)
340
- window.addEventListener('scroll', handleScroll, { capture: true });
341
-
342
- return () => {
343
- window.removeEventListener('scroll', handleScroll);
344
- };
345
- }, [requestImage]);
346
-
347
- useEffect(() => {
348
- if (!requestImage || !settings.showFeedback) return;
349
-
350
- setTimeout(() => {
351
- setShowFeedback(s => (s === 'not-scrolled' ? 'scrolled' : s));
352
- }, 5000);
363
+ if (!settings.showFeedback || results?.length === 0 || !showFeedback)
364
+ return;
353
365
 
354
366
  const handleScroll = () => {
355
367
  setTimeout(() => {
356
- setShowFeedback(s => (s === 'not-scrolled' ? 'scrolled' : s));
368
+ setFeedbackStatus(s => (s === 'submitted' ? 'submitted' : 'visible'));
369
+ dispatch(setShowFeedback(false));
357
370
  }, 100);
358
371
  };
359
372
 
360
- window.addEventListener('scroll', handleScroll, { capture: true });
373
+ setTimeout(() => {
374
+ window.removeEventListener('scroll', handleScroll, { capture: true });
375
+ setFeedbackStatus(s => (s === 'submitted' ? 'submitted' : 'visible'));
376
+ dispatch(setShowFeedback(false));
377
+ }, 4000);
378
+
379
+ window.addEventListener('scroll', handleScroll, {
380
+ capture: true,
381
+ once: true,
382
+ });
361
383
 
362
384
  return () => {
363
385
  window.removeEventListener('scroll', handleScroll);
364
386
  };
365
- }, [requestImage, selectedRegion, settings.showFeedback]);
387
+ // eslint-disable-next-line react-hooks/exhaustive-deps
388
+ }, [showFeedback, settings.showFeedback]);
366
389
 
367
390
  const submitFeedback = async (data: boolean) => {
368
391
  setShowFeedbackSuccess(true);
369
392
  setTimeout(() => {
370
393
  setShowFeedbackSuccess(false);
371
394
  }, 3000);
372
- setShowFeedback('user-scrolled');
395
+
396
+ setFeedbackStatus('submitted');
397
+ dispatch(setShowFeedback(false));
373
398
  feedbackSuccessEpic(stateGlobal, data);
374
399
  };
375
400
 
@@ -395,7 +420,7 @@ function ResultComponent(props: Props) {
395
420
  <Configure query={searchQuery} filters={filterString}></Configure>
396
421
  )}
397
422
  <div className="box-wrap-result-component">
398
- {!isMobile && (
423
+ {!isMobile && showSearchBar && (
399
424
  <div className="box-search">
400
425
  <CustomSearchBox />
401
426
  </div>
@@ -404,7 +429,7 @@ function ResultComponent(props: Props) {
404
429
  className="box-result"
405
430
  style={{
406
431
  height: settings.showPoweredByNyris
407
- ? 'calc(100vh - 177px)'
432
+ ? 'calc(100vh - 87px)'
408
433
  : 'calc(100vh - 148px)',
409
434
  }}
410
435
  >
@@ -431,12 +456,18 @@ function ResultComponent(props: Props) {
431
456
  settings.preview && 'ml-auto mr-auto'
432
457
  } ${isMobile && 'col-right-result-mobile'}`}
433
458
  style={{
434
- paddingTop: isMobile ? '8px' : '40px',
459
+ paddingTop: isMobile ? '8px' : '',
435
460
  overflow: !isMobile ? 'auto' : '',
436
461
  display: 'flex',
437
462
  flexDirection: 'column',
438
463
  }}
439
464
  >
465
+ {!isMobile && firstSearchResults && requestImage?.canvas !== firstSearchImage && !fetchingResults ? (
466
+ <GoBack />
467
+ ) : (
468
+ ''
469
+ )}
470
+
440
471
  {!isMobile && settings.algolia.enabled && (
441
472
  <div className="wrap-box-refinements">
442
473
  <CurrentRefinements statusSwitchButton={true} />
@@ -466,27 +497,23 @@ function ResultComponent(props: Props) {
466
497
  backgroundColor: '#FAFAFA',
467
498
  }}
468
499
  >
500
+ {isMobile && firstSearchResults && requestImage?.canvas !== firstSearchImage && !fetchingResults ? (
501
+ <div className="go-back-mobile-container">
502
+ <GoBack />
503
+ </div>
504
+ ) : (
505
+ ''
506
+ )}
507
+
469
508
  <div
470
509
  className={'box-item-result ml-auto mr-auto'}
471
- style={{ paddingLeft: isMobile ? 0 : 16 }}
510
+ style={{
511
+ paddingLeft: isMobile ? 0 : 16,
512
+ paddingTop: isMobile ? 0 : 16,
513
+ height: '100%',
514
+ position: 'relative',
515
+ }}
472
516
  >
473
- {showFeedbackSuccess && (
474
- <div className={'box-item-result feedback-floating'}>
475
- <div className="feedback-success">
476
- Thanks for your feedback!
477
- </div>
478
- </div>
479
- )}
480
- {showFeedback === 'scrolled' && !showFeedbackSuccess && (
481
- <div className={'box-item-result feedback-floating'}>
482
- <Feedback
483
- submitFeedback={submitFeedback}
484
- onFeedbackClose={() => {
485
- setShowFeedback('user-scrolled');
486
- }}
487
- />
488
- </div>
489
- )}
490
517
  <div
491
518
  className="box-item-result ml-auto mr-auto"
492
519
  style={{ height: 'fit-content' }}
@@ -501,6 +528,34 @@ function ResultComponent(props: Props) {
501
528
  requestImage={requestImage}
502
529
  searchQuery={searchQuery}
503
530
  />
531
+ <div
532
+ className="box-item-result ml-auto mr-auto"
533
+ style={{ position: 'absolute' }}
534
+ >
535
+ {showFeedbackSuccess && (
536
+ <div className={'feedback-floating'}>
537
+ <div className="feedback-section">
538
+ <div className="feedback-success">
539
+ Thanks for your feedback!
540
+ </div>
541
+ </div>
542
+ </div>
543
+ )}
544
+ {feedbackStatus === 'visible' &&
545
+ !showFeedbackSuccess && (
546
+ <div className={'feedback-floating'}>
547
+ <div className="feedback-section">
548
+ <Feedback
549
+ submitFeedback={submitFeedback}
550
+ onFeedbackClose={() => {
551
+ setFeedbackStatus('submitted');
552
+ dispatch(setShowFeedback(false));
553
+ }}
554
+ />
555
+ </div>
556
+ </div>
557
+ )}
558
+ </div>
504
559
  </div>
505
560
  </div>
506
561
  <div
@@ -539,6 +594,7 @@ function ResultComponent(props: Props) {
539
594
  style={{
540
595
  display: 'flex',
541
596
  flexGrow: 1,
597
+ marginTop: !isAlgoliaEnabled ? '24px' : '',
542
598
  }}
543
599
  >
544
600
  {requestImage &&
@@ -614,33 +670,6 @@ function ResultComponent(props: Props) {
614
670
  </div>
615
671
  </>
616
672
  </div>
617
- {isScrolled === 'scrolled' &&
618
- requestImage &&
619
- isMobile &&
620
- props.allSearchResults.hits.length > 0 &&
621
- settings.rfq &&
622
- settings.rfq.enabled && (
623
- <div
624
- style={{
625
- fontSize: '14px',
626
- fontWeight: 'bold',
627
- letterSpacing: '1.16px',
628
- color: 'white',
629
- borderRadius: '16px',
630
- backgroundColor: '#4B4B4A',
631
- boxShadow: '0px 0px 16px 0px rgba(85, 86, 107, 0.70)',
632
- padding: '8px 16px',
633
- zIndex: 100,
634
- position: 'absolute',
635
- left: '50%',
636
- transform: 'translate(-50%, -50%)',
637
- width: '356px',
638
- bottom: '86px',
639
- }}
640
- >
641
- Scroll down for personalized support
642
- </div>
643
- )}
644
673
  </>
645
674
  );
646
675
  }
@@ -31,6 +31,7 @@ export const translations = {
31
31
  'Clear all': 'Clear all',
32
32
  Cancel: 'Cancel',
33
33
  Apply: 'Apply',
34
+ 'Back to request image': 'Back to request image',
34
35
  },
35
36
  },
36
37
  de: {
@@ -66,6 +67,7 @@ export const translations = {
66
67
  'Clear all': 'Alles löschen',
67
68
  Cancel: 'Abbrechen',
68
69
  Apply: 'Anwenden',
70
+ 'Back to request image': 'Zurück zur Bildanfrage',
69
71
  },
70
72
  },
71
73
  pt: {
@@ -100,6 +102,7 @@ export const translations = {
100
102
  'Clear all': 'Clear all',
101
103
  Cancel: 'Cancel',
102
104
  Apply: 'Apply',
105
+ 'Back to request image': 'Retroceder para imagem inicial',
103
106
  },
104
107
  },
105
108
  };
package/src/types.ts CHANGED
@@ -76,6 +76,7 @@ export interface AppSettings extends NyrisAPISettings {
76
76
  showGroup?: boolean;
77
77
  showPoweredByNyris?: boolean;
78
78
  support?: Support;
79
+ simpleCardView?: boolean;
79
80
  theme: SearchSuiteSettings;
80
81
  visualSearchFilterKey?: string;
81
82
  warehouseVariant?: boolean;
@@ -1,2 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>
Binary file
Binary file
Binary file
@@ -1,35 +0,0 @@
1
- {
2
- "name": "App",
3
- "icons": [
4
- {
5
- "src": "apple-icon-32x32.png",
6
- "sizes": "32x32",
7
- "type": "image\/png",
8
- "density": "0.75"
9
- },
10
- {
11
- "src": "apple-icon-72x72.png",
12
- "sizes": "72x72",
13
- "type": "image\/png",
14
- "density": "1.5"
15
- },
16
- {
17
- "src": "apple-icon-96x96.png",
18
- "sizes": "96x96",
19
- "type": "image\/png",
20
- "density": "2.0"
21
- },
22
- {
23
- "src": "apple-icon-144x144.png",
24
- "sizes": "144x144",
25
- "type": "image\/png",
26
- "density": "3.0"
27
- },
28
- {
29
- "src": "android-icon-192x192.png",
30
- "sizes": "192x192",
31
- "type": "image\/png",
32
- "density": "4.0"
33
- }
34
- ]
35
- }