├── .babelrc
├── .gitignore
├── .prettierrc
├── License.md
├── README.md
├── package.json
├── src
├── Components
│ ├── Play.js
│ ├── Player.js
│ └── Player.md
└── index.js
├── styleguide.config.js
├── webpack.config.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env", "react"],
3 | "plugins": ["transform-class-properties", "transform-object-rest-spread"]
4 | }
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /build
6 | /dist
7 | /styleguide
8 |
9 | # testing
10 | /coverage
11 |
12 | # production
13 | /build
14 |
15 | # misc
16 | .DS_Store
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "overrides": [
4 | {
5 | "files": "*.md",
6 | "options": {
7 | "printWidth": 70,
8 | "useTabs": false,
9 | "trailingComma": "none",
10 | "proseWrap": "never"
11 | }
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/License.md:
--------------------------------------------------------------------------------
1 | # The MIT License
2 |
3 | Copyright 2018 Sara Vieira, contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-lazy-youtube
2 |
3 | React Component to lazy load t+youtube videos by showing only the thumbnail of the video untill the person clicks on it as seen on https://awesometalks.party
4 |
5 | Demo: https://react-lazy-youtube.now.sh/
6 |
7 | Props:
8 |
9 | | Name | Type | Default | Description |
10 | | ----------------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------- |
11 | | id | String | Required | |
12 | | imageSize | enum | default | Size of the thumbnail we get from youtube (default, hqdefault, mqdefault, sddefault, maxresdefault ) |
13 | | noCookies | bool | false | if set to true will change the host to "https://www.youtube-nocookie.com" |
14 | | onEnd | func | noop | Functinn that runs on the end of the video |
15 | | onError | func | noop | Function that runs when the video encounters an error |
16 | | onPause | func | noop | Function that runs when the video is paused |
17 | | onPlay | func | noop | function to run when the video starts Playing |
18 | | onPlaybackQualityChange | func | noop | Function that runs when the video changes quality |
19 | | onPlaybackRateChange | func | noop | Function that runs when the video encounters changes playback rate |
20 | | onStateChange | func | noop | Function that runs when the video changes state like from playing to paused |
21 | | playerVars | object | {} | https://developers.google.com/youtube/player_parameters |
22 | | styles | object | {} | Styles to apply over the wrapper |
23 |
24 |
25 | ## Contributing
26 |
27 | Everyone is welcome to contribute.
28 |
29 | ## Authors and license
30 |
31 | [Sara Vieira](https://iamsaravieira.com) and [contributors](https://github.com/https://github.com/SaraVieira/react-lazy-youtube/graphs/contributors).
32 |
33 | MIT License, see the included [License.md](License.md) file.
34 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-lazy-youtube",
3 | "version": "1.0.1",
4 | "author": "Sara Vieira",
5 | "main": "dist/index.js",
6 | "dependencies": {
7 | "react": "^16.4.0",
8 | "react-dom": "^16.4.0",
9 | "react-youtube": "^7.6.0",
10 | "remcalc": "^1.0.10",
11 | "styled-is": "^1.1.3"
12 | },
13 | "files": [
14 | "dist/index.js",
15 | "dist/index.js.map"
16 | ],
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "webpack",
20 | "test": "react-scripts test --env=jsdom",
21 | "posttest": "npm run format",
22 | "eject": "react-scripts eject",
23 | "styleguide": "styleguidist server",
24 | "styleguide:build": "styleguidist build",
25 | "format": "prettier --write '**/*.{js,css,md}'",
26 | "prepublish": "npm run build"
27 | },
28 | "peerDependencies": {
29 | "prop-types": "^15.6.1",
30 | "react": "^16.4.0",
31 | "react-dom": "^16.4.0",
32 | "react-scripts": "1.1.1",
33 | "styled-components": "^3.3.2"
34 | },
35 | "devDependencies": {
36 | "babel-cli": "^6.26.0",
37 | "babel-core": "",
38 | "babel-loader": "^7.1.4",
39 | "babel-plugin-transform-class-properties": "^6.24.1",
40 | "babel-plugin-transform-object-rest-spread": "^6.26.0",
41 | "babel-preset-env": "",
42 | "babel-preset-react": "",
43 | "prettier": "^1.13.4",
44 | "react-styleguidist": "^7.0.17",
45 | "styled-components": "^3.3.2",
46 | "webpack": "^4.11.1",
47 | "webpack-cli": "^3.0.2"
48 | },
49 | "license": "MIT",
50 | "homepage": "https://github.com/yldio/react-lazy-youtube",
51 | "issues": "https://github.com/yldio/react-lazy-youtube/issues"
52 | }
53 |
--------------------------------------------------------------------------------
/src/Components/Play.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components"
2 |
3 | export default styled.button`
4 | background: #282828;
5 | border-radius: 50% / 10%;
6 | color: ${props => props.theme.white};
7 | font-size: 1em;
8 | height: 3em;
9 | padding: 0;
10 | text-align: center;
11 | text-indent: 0.1em;
12 | transition: all 150ms ease-out;
13 | width: 4em;
14 | position: absolute !important;
15 | top: 50%;
16 | left: 50%;
17 | transform: translateX(-50%) translateY(-50%);
18 | border: none;
19 | opacity: 0.8;
20 | cursor: pointer;
21 | z-index: 9;
22 |
23 | &:hover {
24 | background: #ff0000;
25 | }
26 |
27 | &:before {
28 | background: inherit;
29 | border-radius: 5% / 50%;
30 | bottom: 9%;
31 | content: "";
32 | left: -5%;
33 | position: absolute;
34 | right: -5%;
35 | top: 9%;
36 | }
37 |
38 | &:after {
39 | border-style: solid;
40 | border-width: 1em 0 1em 1.732em;
41 | border-color: transparent transparent transparent rgba(255, 255, 255, 0.75);
42 | content: " ";
43 | font-size: 0.75em;
44 | height: 0;
45 | margin: -1em 0 0 -0.75em;
46 | top: 50%;
47 | position: absolute;
48 | width: 0;
49 | }
50 | `
51 |
--------------------------------------------------------------------------------
/src/Components/Player.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react"
2 | import styled from "styled-components"
3 | import YouTube from "react-youtube"
4 | import is, { isNot } from "styled-is"
5 | import remcalc from "remcalc"
6 | import PropTypes from "prop-types"
7 |
8 | import Play from "./Play"
9 |
10 | const Video = styled.div``
11 |
12 | const VideoWrapper = styled.section`
13 | position: relative;
14 | width: 640px;
15 | height: 360px;
16 | margin: auto;
17 | ${isNot("cinemaMode")`
18 | &:before {
19 | display: block;
20 | content: '';
21 | width: 100%;
22 | padding-top: 56.25%;
23 | }
24 | ${Video} {
25 | position: absolute;
26 | top: 0;
27 | left: 0;
28 | right: 0;
29 | bottom: 0;
30 | }
31 | `};
32 | `
33 |
34 | const Iframe = styled(YouTube)`
35 | position: relative;
36 | z-index: 3;
37 | border: none;
38 | transition: all 200ms ease;
39 | height: 100%;
40 | ${is("cinemaMode")`
41 | height: ${remcalc(600)};
42 | @media (max-width: ${remcalc(768)}) {
43 | height: auto;
44 | }
45 | `};
46 | `
47 |
48 | const Thumbnail = styled.img`
49 | display: block;
50 | width: 100%;
51 | height: 100%;
52 | `
53 |
54 | const Image = styled.div`
55 | position: relative;
56 | margin: auto;
57 | height: 100%;
58 | overflow: hidden;
59 | box-shadow: ${props => props.theme.shadow};
60 | ${is("cinemaMode")`
61 | height: auto;
62 | `};
63 | `
64 |
65 | class Player extends Component {
66 | state = { showVideo: false }
67 |
68 | showVideo = () => this.setState(({ showVideo }) => ({ showVideo: true }))
69 |
70 | render = () => {
71 | const {
72 | id,
73 | onPlay,
74 | onPause,
75 | onEnd,
76 | onError,
77 | onStateChange,
78 | onPlaybackRateChange,
79 | onPlaybackQualityChange,
80 | imageSize,
81 | playerVars,
82 | noCookies,
83 | styles,
84 | ...props
85 | } = this.props
86 |
87 | const { showVideo } = this.state
88 |
89 | const validImageSizes = [
90 | "default",
91 | "hqdefault",
92 | "mqdefault",
93 | "sddefault",
94 | "maxresdefault"
95 | ]
96 |
97 | const image = () =>
98 | validImageSizes.includes(imageSize) ? imageSize : "default"
99 |
100 | return (
101 |
102 |
134 |
135 | )
136 | }
137 | }
138 |
139 | export default Player
140 |
141 | Player.defaultProps = {
142 | onPlay: () => {},
143 | onPause: () => {},
144 | onEnd: () => {},
145 | onError: () => {},
146 | onStateChange: () => {},
147 | onPlaybackRateChange: () => {},
148 | onPlaybackQualityChange: () => {},
149 | imageSize: "default",
150 | playerVars: {},
151 | noCookies: false,
152 | styles: {}
153 | }
154 |
155 | Player.propTypes = {
156 | /** ID of the youtube video to play . */
157 | id: PropTypes.string.isRequired,
158 | /** .function to run when the video starts Playing */
159 | onPlay: PropTypes.func,
160 | /** .Function that runs when the video is paused */
161 | onPause: PropTypes.func,
162 | /** . Functinn that runs on the end of the video */
163 | onEnd: PropTypes.func,
164 | /** .Function that runs when the video encounters an error */
165 | onError: PropTypes.func,
166 | /** .Function that runs when the video changes state like from playing to paused */
167 | onStateChange: PropTypes.func,
168 | /** .Function that runs when the video encounters changes playback rater */
169 | onPlaybackRateChange: PropTypes.func,
170 | /** .Function that runs when the video changes quality */
171 | onPlaybackQualityChange: PropTypes.func,
172 | /** https://developers.google.com/youtube/player_parameters */
173 | playerVars: PropTypes.object,
174 | /** .Styles to apply over the wrappr */
175 | styles: PropTypes.object,
176 | /** .if set to true will change the host to "https://www.youtube-nocookie.com" */
177 | noCookies: PropTypes.bool,
178 | /** .Size of the thumbnail we get from youtube */
179 | imageSize: PropTypes.oneOf([
180 | "default",
181 | "hqdefault",
182 | "mqdefault",
183 | "sddefault",
184 | "maxresdefault"
185 | ])
186 | }
187 |
--------------------------------------------------------------------------------
/src/Components/Player.md:
--------------------------------------------------------------------------------
1 | Default player:
2 |
3 | ```jsx
4 |
5 | ```
6 |
7 | Better Image:
8 |
9 | ```jsx
10 |
11 | ```
12 |
13 | Addtional Styles:
14 |
15 | ```jsx
16 |
24 | ```
25 |
26 | Event handlers:
27 |
28 | ```jsx
29 | console.log("onStateChange")}
33 | onPause={() => console.log("Paused")}
34 | />
35 | ```
36 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import Player from "./Components/Player"
2 |
3 | export default Player
4 |
--------------------------------------------------------------------------------
/styleguide.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | components: "src/Components/**/[A-Z]*.js",
3 | defaultExample: false,
4 | webpackConfig: {
5 | module: {
6 | rules: [
7 | {
8 | test: /\.jsx?$/,
9 | exclude: /node_modules/,
10 | loader: "babel-loader"
11 | }
12 | ]
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require("webpack")
2 | const pkg = require("./package.json")
3 | const path = require("path")
4 | const libraryName = pkg.name
5 | module.exports = {
6 | entry: path.join(__dirname, "./src/index.js"),
7 | mode: "production",
8 | output: {
9 | path: path.join(__dirname, "./dist"),
10 | filename: "index.js",
11 | library: libraryName,
12 | libraryTarget: "umd",
13 | publicPath: "/dist/",
14 | umdNamedDefine: true
15 | },
16 | node: {
17 | net: "empty",
18 | tls: "empty",
19 | dns: "empty"
20 | },
21 | module: {
22 | rules: [
23 | {
24 | test: /\.(js|jsx)$/,
25 | use: ["babel-loader"],
26 | include: path.resolve(__dirname, "src"),
27 | exclude: /node_modules/
28 | }
29 | ]
30 | },
31 | resolve: {
32 | alias: {
33 | react: path.resolve(__dirname, "./node_modules/react"),
34 | "react-dom": path.resolve(__dirname, "./node_modules/react-dom"),
35 | "styled-components": path.resolve(
36 | __dirname,
37 | "./node_modules/styled-components"
38 | )
39 | }
40 | },
41 | externals: {
42 | react: {
43 | commonjs: "react",
44 | commonjs2: "react",
45 | amd: "React",
46 | root: "React"
47 | },
48 | "react-dom": {
49 | commonjs: "react-dom",
50 | commonjs2: "react-dom",
51 | amd: "ReactDOM",
52 | root: "ReactDOM"
53 | },
54 | "styled-components": {
55 | commonjs: "styled-components",
56 | commonjs2: "styled-components",
57 | amd: "styledComponents",
58 | root: "styledComponents"
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------