├── .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 |