Skip to content

Commit 9690be8

Browse files
committed
adding code to show thumbnails below tool media carousel (analysis-tools-dev#20)
1 parent 1280ce3 commit 9690be8

31 files changed

+979
-505
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ This project would not be possible without the generous support of our sponsors.
1717
<td><a href="https://deepcode.ai"><img width="200px" src="static/sponsors/deepcode.svg" /></a></td>
1818
<td><a href="https://deepsource.io/"><img width="200px" src="static/sponsors/deepsource.png" /></a></td>
1919
<td><a href="https://www.viva64.com/free-license"><img height="100px" src="static/sponsors/pvs-studio.svg" /></a></td>
20-
<td><a href="https://codescene.io/"><img width="200px" src="static/sponsors/codescene.png" /></a></td>
20+
<td><a href="https://codescene.io/"><img width="200px" src="static/sponsors/codescene.svg" /></a></td>
2121
</tr>
2222
</table>
2323

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@
4141
"react-multi-carousel": "^2.5.5",
4242
"react-player": "^2.6.2",
4343
"react-select": "^3.1.0",
44+
"react-slick": "0.26",
4445
"react-typography": "^0.16.19",
46+
"slick-carousel": "^1.8.1",
4547
"styled-components": "^5.1.0",
4648
"tailwindcss": "^1.4.6",
4749
"twin.macro": "^1.1.0",

src/components/layout.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export default ({ children }) => {
9898
</p>
9999
<p tw="pb-6">
100100
<a href="https://codescene.io?utm_source=github_analysis_tools.dev&utm_medium=sponsorship&utm_content=banner_logo">
101-
<img alt="CodeScene logo" src="/sponsors/codescene.png" />
101+
<img alt="CodeScene logo" src="/sponsors/codescene.svg" />
102102
</a>
103103
</p>
104104
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { css } from "twin.macro"
2+
export const SliderContentImageStyle = css`
3+
height: inherit;
4+
margin-left: auto;
5+
margin-right: auto;
6+
`
7+
export const SliderStyle = css`
8+
.slick-prev:before,
9+
.slick-next:before {
10+
color: #222425!important;
11+
}
12+
.slick-slide {
13+
padding: 0rem 1rem 0rem 1rem;
14+
}
15+
`
16+
export const SliderContentStyle = css`
17+
margin: 1rem 0rem 1rem 0.1rem;
18+
transition: transform .2s;
19+
height: 8rem;
20+
background: #f7f7f7;
21+
text-align: center;
22+
cursor: pointer;
23+
border-radius: 0.5rem;
24+
25+
&:hover {
26+
-ms-transform: scale(1.005);
27+
-webkit-transform: scale(1.005);
28+
transform: scale(1.005);
29+
}
30+
31+
&:focus {
32+
outline: none;
33+
-webkit-box-shadow: 0px 0px 4px 0px rgba(173,173,173,1);
34+
-moz-box-shadow: 0px 0px 4px 0px rgba(173,173,173,1);
35+
box-shadow: 0px 0px 4px 0px rgba(173,173,173,1);
36+
}
37+
`
38+
export const getSliderSetting = noOfElements => {
39+
const maxSlidesToShow = noOfElements < 3 ? 2 : 3;
40+
return {
41+
focusOnSelect: true,
42+
dots: true,
43+
infinite: false,
44+
speed: 500,
45+
slidesToShow: maxSlidesToShow,
46+
slidesToScroll: 1,
47+
responsive: [{
48+
breakpoint: 1200,
49+
settings: {
50+
slidesToShow: maxSlidesToShow,
51+
slidesToScroll: 1
52+
}
53+
}, {
54+
breakpoint: 600,
55+
settings: {
56+
slidesToShow: 2,
57+
slidesToScroll: 1
58+
}
59+
}, {
60+
breakpoint: 480,
61+
settings: {
62+
slidesToShow: 1,
63+
slidesToScroll: 1
64+
}
65+
}
66+
]
67+
}
68+
}
+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
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(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-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+
}

src/components/tool/main-media.js

+2-42
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React from "react"
22
import "twin.macro"
3-
import ReactPlayer from "react-player/lazy"
4-
import Carousel from "react-multi-carousel"
3+
import { MainMediaUtil } from "./main-media-util"
54

65
const getVideo = resources => {
76
if (!resources) {
@@ -15,22 +14,6 @@ const getVideo = resources => {
1514
}
1615
}
1716

18-
const renders = {
19-
video: video => (
20-
<ReactPlayer tw="max-w-full" url={video.url} width="100%" controls="true" />
21-
),
22-
image: image => (
23-
<a href={image.url} tw="w-full text-center">
24-
<img
25-
alt={`Screenshot of ${image.name} website`}
26-
tw="border-4 max-w-full inline-block"
27-
src={image.src}
28-
height="360"
29-
/>
30-
</a>
31-
),
32-
}
33-
3417
const MainMedia = ({ tool }) => {
3518
const { name, homepage, resources } = tool
3619
let screenshot = { name, url: homepage, src: tool.fields.screenshot }
@@ -45,32 +28,9 @@ const MainMedia = ({ tool }) => {
4528
items.push({ type: "video", source: video })
4629
}
4730

48-
const carouselProps = {
49-
responsive: {
50-
all: {
51-
breakpoint: { max: 3000, min: 0 },
52-
items: 1,
53-
},
54-
},
55-
infinite: true,
56-
showDots: true,
57-
}
58-
5931
return (
6032
<div tw="mb-5">
61-
{items.length > 1 ? (
62-
<Carousel {...carouselProps}>
63-
{items.map(item => (
64-
<div tw="flex justify-center items-center h-full mb-5 pb-4">
65-
{renders[item.type](item.source)}
66-
</div>
67-
))}
68-
</Carousel>
69-
) : (
70-
<div tw="flex justify-center items-center h-full mb-5 pb-4">
71-
{renders[items[0].type](items[0].source)}
72-
</div>
73-
)}
33+
<MainMediaUtil data={items} />
7434
</div>
7535
)
7636
}
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
30.3 KB
Loading
Loading
53.1 KB
Loading
Loading
Loading
29.2 KB
Loading
Loading

static/sponsors/codescene.png

-58.4 KB
Loading

static/sponsors/codescene.svg

+56
Loading

0 commit comments

Comments
 (0)