1+ import React , { useState , useEffect } from "react"
2+ import tw , { css } from "twin.macro"
3+ import ReactPlayer from "react-player/lazy"
4+ import "slick-carousel/slick/slick.css"
5+ import "slick-carousel/slick/slick-theme.css"
6+ import Slider from "react-slick"
7+ import {
8+ SliderContentImageStyle ,
9+ SliderStyle ,
10+ SliderContentStyle ,
11+ getSliderSetting
12+ } from "./main-media-util-helper"
13+
14+ /**
15+ *
16+ * **Credits**
17+ * Author : yangshun
18+ * Gist link : https://gist.github.com/yangshun/9892961
19+ */
20+ const parseVideo = url => {
21+ url . match ( / ( h t t p : | h t t p s : | ) \/ \/ ( p l a y e r .| w w w .) ? ( v i m e o \. c o m | y o u t u ( b e \. c o m | \. b e | b e \. g o o g l e a p i s \. c o m ) ) \/ ( v i d e o \/ | e m b e d \/ | w a t c h \? v = | v \/ ) ? ( [ A - Z a - z 0 - 9 . _ % - ] * ) ( & \S + ) ? / ) ;
22+
23+ const type = RegExp . $3 . indexOf ( "youtu" ) > - 1 ? "youtube" :
24+ RegExp . $3 . indexOf ( "vimeo" ) > - 1 ? "vimeo"
25+ : undefined
26+
27+ return {
28+ type : type ,
29+ id : RegExp . $6
30+ }
31+ }
32+
33+ const getVideoThumbnailUrl = async url => {
34+ const video = parseVideo ( url )
35+ if ( video . type === "youtube" )
36+ return video . id ? "https://img.youtube.com/vi/" + video . id + "/maxresdefault.jpg" : "#"
37+ if ( video . type === "vimeo" ) {
38+ const fetched = ( async videoId => {
39+ let result = { }
40+ try {
41+ const response = await fetch ( "https://vimeo.com/api/v2/video/" + videoId + ".json" )
42+ result = await response . json ( )
43+ return result [ 0 ] . thumbnail_large
44+ } catch ( e ) {
45+ console . error ( "Error while fetching Vimeo video data" , e )
46+ }
47+ } )
48+ return fetched ( video . id )
49+ }
50+ }
51+
52+ const renderMainMediaDisplayElement = {
53+ video : video => {
54+ return (
55+ < div tw = "h-full text-center" key = { video . key } id = { video . key } css = { video . css } >
56+ < ReactPlayer url = { video . url } width = "100%" controls = { true } />
57+ </ div >
58+ )
59+ } ,
60+ image : image => (
61+ < a href = { image . url } tw = "w-full text-center" css = { image . css }
62+ key = { image . key } id = { image . key } >
63+ < img
64+ alt = { `Screenshot of ${ image . name } website` }
65+ tw = "border-4 max-w-full inline-block"
66+ src = { image . src }
67+ />
68+ </ a >
69+ ) ,
70+ }
71+
72+ const renderMainMediaSliderElement = {
73+ video : video => sliderThumbnail ( video ) ,
74+ image : image => sliderThumbnail ( image )
75+ }
76+
77+ const sliderThumbnail = props => {
78+ props = props || { }
79+ const src = props . src || props . thumbnailSrc || "#"
80+ const alt = props . name || "Thumbnail"
81+ return (
82+ < div css = { [ SliderContentStyle ] }
83+ id = { props . key }
84+ key = { props . key }
85+ onClick = { props . onClick }
86+ aria-hidden = "true" >
87+ < img
88+ alt = { alt }
89+ id = { props . key + "_img" }
90+ key = { props . key + "_img" }
91+ src = { src }
92+ css = { [
93+ tw `border-4 max-w-full` ,
94+ SliderContentImageStyle
95+ ] }
96+ />
97+ </ div >
98+ )
99+ }
100+
101+ export const MainMediaUtil = ( { data} ) => {
102+ const [ items ] = useState ( data )
103+ const [ index , setIndex ] = useState ( 0 )
104+ const [ isRendered , setIsRendered ] = useState ( false )
105+ const [ hasThumbnails , setHasThumbnails ] = useState ( false )
106+ const sliderSetting = getSliderSetting ( items . length )
107+
108+ const toggleDisplayStatusOfElement = options => {
109+ options = options || { }
110+ const idForElementToDisplay = "#main_media_util_in_display_" + index
111+ const elementToDisplay = document . querySelector ( idForElementToDisplay )
112+ elementToDisplay . setAttribute ( 'style' , options . style || 'display:block' )
113+
114+ if ( isRendered ) return
115+ const idForElementToFocus = "#main_media_util_" + index
116+ const elementToFocus = document . querySelector ( idForElementToFocus )
117+ elementToFocus . focus ( { preventScroll : true } )
118+ setIsRendered ( true )
119+ }
120+
121+ const populateVideoThumbnails = async ( ) => {
122+ items . map ( async item => {
123+ if ( item . type !== "video" ) return
124+ const url = await getVideoThumbnailUrl ( item . source . url )
125+ const target = document . querySelector ( "#" + item . source . key + "_img" )
126+ target . setAttribute ( "src" , url )
127+ } )
128+ setHasThumbnails ( true )
129+ }
130+
131+ useEffect ( ( ) => {
132+ if ( items . length > 1 ) toggleDisplayStatusOfElement ( )
133+ if ( ! hasThumbnails ) populateVideoThumbnails ( )
134+ } )
135+
136+ return items && items . length > 1 ? (
137+ < >
138+ < div tw = "items-center h-full mb-1" >
139+ { items . map ( ( item , itemIndex ) => {
140+ item . source . key = "main_media_util_in_display_" + itemIndex
141+ item . source . css = css `display : none;`
142+ return renderMainMediaDisplayElement [ item . type ] ( item . source )
143+ } ) }
144+ </ div >
145+ < div tw = "items-center h-full ml-2 mr-2" >
146+ < Slider { ...sliderSetting } css = { [ SliderStyle ] } >
147+ { items . map ( ( item , itemIndex ) => {
148+ item . source . key = "main_media_util_" + itemIndex
149+ item . source . onClick = ( ) => {
150+ if ( itemIndex === index ) return
151+ toggleDisplayStatusOfElement ( { style : 'display:none' } )
152+ setIndex ( itemIndex )
153+ }
154+ return renderMainMediaSliderElement [ item . type ] ( item . source )
155+ } ) }
156+ </ Slider >
157+ </ div >
158+ </ >
159+ ) : (
160+ < div tw = "flex justify-center items-center h-full mb-5 pb-4" >
161+ { items && items . map ( item => {
162+ item . source . key = "main_media_util_in_display_0"
163+ return renderMainMediaDisplayElement [ item . type ] ( item . source )
164+ } ) }
165+ </ div >
166+ )
167+ }
0 commit comments