├── .gitignore ├── .npmignore ├── README.md ├── city └── index.css ├── fantasy ├── icons │ └── nyan-cat.svg └── index.css ├── forest ├── icons │ ├── play-btn.svg │ └── play-small.svg └── index.css ├── index.html ├── now.json ├── package-lock.json ├── package.json ├── postcss.config.js └── sea └── index.css /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | dist 3 | node_modules 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .cache 3 | node_modules 4 | index.html 5 | 6 | !dist 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Videojs Themes 2 | 3 | Monorepo for Video.js themes :nail_care:. 4 | 5 | ## Usage 6 | 7 | You can pull in the CSS via link tags 8 | 9 | ```html 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ``` 25 | 26 | Or, if you're using CSS modules in JavaScript, you can install the NPM module: 27 | 28 | ```sh 29 | npm install --save video.js @videojs/themes 30 | ``` 31 | 32 | Then just import the files as you would other CSS. 33 | 34 | ```javascript 35 | import 'video.js/dist/video-js.css'; 36 | 37 | // City 38 | import '@videojs/themes/dist/city/index.css'; 39 | 40 | // Fantasy 41 | import '@videojs/themes/dist/fantasy/index.css'; 42 | 43 | // Forest 44 | import '@videojs/themes/dist/forest/index.css'; 45 | 46 | // Sea 47 | import '@videojs/themes/dist/sea/index.css'; 48 | ``` 49 | 50 | Once you've got the theme pulled in, you can then add the relevant class to your player! The class names are structured as `vjs-theme-${THEME_NAME}`, so `vjs-theme-city` for the city theme or `vjs-theme-sea` for the sea theme. 51 | 52 | 53 | ```html 54 | 55 | ``` 56 | 57 | # Building these locally 58 | 59 | If you want to use the CSS in this repo directly instead of using one of the CDNs or the NPM-hosted version, or just do some development, you'll need to clone the repo and `build` them. 60 | 61 | ``` 62 | $ git clone https://github.com/videojs/themes videojs-themes 63 | $ cd videojs-themes 64 | $ npm install 65 | $ npm run build 66 | ``` 67 | 68 | This will create a `dist` folder with the post-processed CSS in them, which you can upload right to your site. If you want to develop against these locally, you can run `npm run dev` to get a local server running a demo of all the themes on it. 69 | -------------------------------------------------------------------------------- /city/index.css: -------------------------------------------------------------------------------- 1 | .vjs-theme-city { 2 | --vjs-theme-city--primary: #bf3b4d; 3 | --vjs-theme-city--secondary: #fff; 4 | } 5 | 6 | .vjs-theme-city .vjs-control-bar { 7 | height: 70px; 8 | padding-top: 20px; 9 | background: none; 10 | background-image: linear-gradient(to top, #000, rgba(0, 0, 0, 0)); 11 | } 12 | 13 | .vjs-theme-city .vjs-button > .vjs-icon-placeholder::before { 14 | line-height: 50px; 15 | } 16 | 17 | .vjs-theme-city .vjs-play-progress::before { 18 | display: none; 19 | } 20 | 21 | .vjs-theme-city .vjs-progress-control { 22 | position: absolute; 23 | top: 0; 24 | right: 0; 25 | left: 0; 26 | width: 100%; 27 | height: 20px; 28 | } 29 | 30 | .vjs-theme-city .vjs-progress-control .vjs-progress-holder { 31 | position: absolute; 32 | top: 20px; 33 | right: 0; 34 | left: 0; 35 | width: 100%; 36 | margin: 0; 37 | } 38 | 39 | .vjs-theme-city .vjs-play-progress { 40 | background-color: var(--vjs-theme-city--primary); 41 | } 42 | 43 | .vjs-theme-city .vjs-remaining-time { 44 | order: 1; 45 | line-height: 50px; 46 | flex: 3; 47 | text-align: left; 48 | } 49 | 50 | .vjs-theme-city .vjs-play-control { 51 | order: 2; 52 | flex: 8; 53 | font-size: 1.75em; 54 | } 55 | 56 | .vjs-theme-city .vjs-volume-panel, 57 | .vjs-theme-city .vjs-picture-in-picture-control, 58 | .vjs-theme-city .vjs-fullscreen-control { 59 | order: 3; 60 | flex: 1; 61 | } 62 | 63 | /* Volume stuff */ 64 | .vjs-theme-city .vjs-volume-panel:hover .vjs-volume-control.vjs-volume-horizontal { 65 | height: 100%; 66 | } 67 | 68 | .vjs-theme-city .vjs-mute-control { 69 | display: none; 70 | } 71 | 72 | .vjs-theme-city .vjs-volume-panel { 73 | margin-left: 0.5em; 74 | margin-right: 0.5em; 75 | padding-top: 1.5em; 76 | } 77 | 78 | .vjs-theme-city .vjs-volume-panel, 79 | .vjs-theme-city .vjs-volume-panel:hover, 80 | .vjs-theme-city .vjs-volume-panel.vjs-volume-panel-horizontal:hover, 81 | .vjs-theme-city .vjs-volume-panel:focus .vjs-volume-control.vjs-volume-horizontal, 82 | .vjs-theme-city .vjs-volume-panel:hover .vjs-volume-control.vjs-volume-horizontal, 83 | .vjs-theme-city .vjs-volume-panel:active .vjs-volume-control.vjs-volume-horizontal, 84 | .vjs-theme-city .vjs-volume-panel.vjs-volume-panel-horizontal:hover, 85 | .vjs-theme-city .vjs-volume-bar.vjs-slider-horizontal { 86 | width: 3em; 87 | } 88 | 89 | .vjs-theme-city .vjs-volume-level::before { 90 | font-size: 1em; 91 | } 92 | 93 | .vjs-theme-city .vjs-volume-panel .vjs-volume-control { 94 | opacity: 1; 95 | width: 100%; 96 | height: 100%; 97 | } 98 | 99 | .vjs-theme-city .vjs-volume-bar { 100 | background-color: transparent; 101 | margin: 0; 102 | } 103 | 104 | .vjs-theme-city .vjs-slider-horizontal .vjs-volume-level { 105 | height: 100%; 106 | } 107 | 108 | .vjs-theme-city .vjs-volume-bar.vjs-slider-horizontal { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | height: 100%; 112 | } 113 | 114 | .vjs-theme-city .vjs-volume-bar::before { 115 | content: ''; 116 | z-index: 0; 117 | width: 0; 118 | height: 0; 119 | position: absolute; 120 | top: 0px; 121 | left: 0; 122 | 123 | border-style: solid; 124 | border-width: 0 0 1.75em 3em; 125 | border-color: transparent transparent rgba(255, 255, 255, 0.25) transparent; 126 | } 127 | 128 | .vjs-theme-city .vjs-volume-level { 129 | overflow: hidden; 130 | background-color: transparent; 131 | } 132 | 133 | .vjs-theme-city .vjs-volume-level::before { 134 | content: ''; 135 | z-index: 1; 136 | width: 0; 137 | height: 0; 138 | position: absolute; 139 | top: 0; 140 | left: 0; 141 | 142 | border-style: solid; 143 | border-width: 0 0 1.75em 3em; 144 | border-color: transparent transparent var(--vjs-theme-city--secondary) transparent; 145 | } 146 | -------------------------------------------------------------------------------- /fantasy/icons/nyan-cat.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /fantasy/index.css: -------------------------------------------------------------------------------- 1 | .vjs-theme-fantasy { 2 | --vjs-theme-fantasy--primary: #9f44b4; 3 | --vjs-theme-fantasy--secondary: #fff; 4 | } 5 | 6 | .vjs-theme-fantasy .vjs-big-play-button { 7 | width: 70px; 8 | height: 70px; 9 | background: none; 10 | line-height: 70px; 11 | font-size: 80px; 12 | border: none; 13 | top: 50%; 14 | left: 50%; 15 | margin-top: -35px; 16 | margin-left: -35px; 17 | color: var(--vjs-theme-fantasy--primary); 18 | } 19 | 20 | .vjs-theme-fantasy:hover .vjs-big-play-button, 21 | .vjs-theme-fantasy.vjs-big-play-button:focus { 22 | background-color: transparent; 23 | color: #fff; 24 | } 25 | 26 | .vjs-theme-fantasy .vjs-control-bar { 27 | height: 54px; 28 | } 29 | 30 | .vjs-theme-fantasy .vjs-button > .vjs-icon-placeholder::before { 31 | line-height: 54px; 32 | } 33 | 34 | .vjs-theme-fantasy .vjs-time-control { 35 | line-height: 54px; 36 | } 37 | 38 | /* Play Button */ 39 | .vjs-theme-fantasy .vjs-play-control { 40 | font-size: 1.5em; 41 | position: relative; 42 | } 43 | 44 | .vjs-theme-fantasy .vjs-volume-panel { 45 | order: 4; 46 | } 47 | 48 | .vjs-theme-fantasy .vjs-volume-bar { 49 | margin-top: 2.5em; 50 | } 51 | 52 | .vjs-theme-city .vjs-volume-panel:hover .vjs-volume-control.vjs-volume-horizontal { 53 | height: 100%; 54 | } 55 | 56 | .vjs-theme-fantasy .vjs-progress-control .vjs-progress-holder { 57 | font-size: 1.5em; 58 | } 59 | 60 | .vjs-theme-fantasy .vjs-progress-control:hover .vjs-progress-holder { 61 | font-size: 1.5em; 62 | } 63 | 64 | .vjs-theme-fantasy .vjs-play-control .vjs-icon-placeholder::before { 65 | height: 1.3em; 66 | width: 1.3em; 67 | margin-top: 0.2em; 68 | border-radius: 1em; 69 | border: 3px solid var(--vjs-theme-fantasy--secondary); 70 | top: 2px; 71 | left: 9px; 72 | line-height: 1.1; 73 | } 74 | 75 | .vjs-theme-fantasy .vjs-play-control:hover .vjs-icon-placeholder::before { 76 | border: 3px solid var(--vjs-theme-fantasy--secondary); 77 | } 78 | 79 | .vjs-theme-fantasy .vjs-play-progress { 80 | background-color: var(--vjs-theme-fantasy--primary); 81 | } 82 | 83 | .vjs-theme-fantasy .vjs-play-progress::before { 84 | height: 0.8em; 85 | width: 0.8em; 86 | content: ''; 87 | background-color: var(--vjs-theme-fantasy--primary); 88 | border: 4px solid var(--vjs-theme-fantasy--secondary); 89 | border-radius: 0.8em; 90 | top: -0.25em; 91 | } 92 | 93 | .vjs-theme-fantasy .vjs-progress-control { 94 | font-size: 14px; 95 | } 96 | 97 | .vjs-theme-fantasy .vjs-fullscreen-control { 98 | order: 6; 99 | } 100 | 101 | .vjs-theme-fantasy .vjs-remaining-time { 102 | display: none; 103 | } 104 | 105 | /* Nyan version */ 106 | .vjs-theme-fantasy.nyan .vjs-play-progress { 107 | background: linear-gradient(to bottom, #fe0000 0%, #fe9a01 16.666666667%, #fe9a01 16.666666667%, #ffff00 33.332666667%, #ffff00 33.332666667%, #32ff00 49.999326667%, #32ff00 49.999326667%, #0099fe 66.6659926%, #0099fe 66.6659926%, #6633ff 83.33266%, #6633ff 83.33266%); 108 | } 109 | 110 | .vjs-theme-fantasy.nyan .vjs-play-progress::before { 111 | height: 1.3em; 112 | width: 1.3em; 113 | background: svg-load('icons/nyan-cat.svg', fill=#fff) no-repeat; 114 | border: none; 115 | top: -0.35em; 116 | } 117 | -------------------------------------------------------------------------------- /forest/icons/play-btn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /forest/icons/play-small.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /forest/index.css: -------------------------------------------------------------------------------- 1 | /* Because of the SVG inliner, these don't work for icons */ 2 | .vjs-theme-forest { 3 | --vjs-theme-forest--primary: #6fb04e; 4 | --vjs-theme-forest--secondary: #fff; 5 | } 6 | 7 | /* Big play Button */ 8 | .vjs-theme-forest:hover .vjs-big-play-button, 9 | .vjs-theme-forest.vjs-big-play-button:focus { 10 | background-color: transparent; 11 | background: svg-load('icons/play-btn.svg', fill=#6fb04e); 12 | } 13 | 14 | .vjs-theme-forest .vjs-big-play-button { 15 | width: 88px; 16 | height: 88px; 17 | background: none; 18 | background-repeat: no-repeat; 19 | background-position: center; 20 | background: svg-load('icons/play-btn.svg', fill=#fff); 21 | border: none; 22 | top: 50%; 23 | left: 50%; 24 | margin-top: -44px; 25 | margin-left: -44px; 26 | color: purple; 27 | } 28 | 29 | .vjs-theme-forest .vjs-big-play-button .vjs-icon-placeholder { 30 | display: none; 31 | } 32 | 33 | /* Control Bar */ 34 | .vjs-theme-forest .vjs-button > .vjs-icon-placeholder::before { 35 | line-height: 1.55; 36 | } 37 | 38 | .vjs-theme-forest .vjs-control:not(.vjs-disabled, .vjs-time-control):hover { 39 | color: var(--vjs-theme-forest--primary); 40 | text-shadow: var(--vjs-theme-forest--secondary) 1px 0 10px; 41 | } 42 | 43 | .vjs-theme-forest .vjs-control-bar { 44 | background: none; 45 | margin-bottom: 1em; 46 | padding-left: 1em; 47 | padding-right: 1em; 48 | } 49 | 50 | /* Play Button */ 51 | .vjs-theme-forest .vjs-play-control { 52 | font-size: 0.8em; 53 | } 54 | 55 | .vjs-theme-forest .vjs-play-control .vjs-icon-placeholder:before { 56 | background-color: var(--vjs-theme-forest--secondary); 57 | height: 1.5em; 58 | width: 1.5em; 59 | margin-top: 0.2em; 60 | border-radius: 1em; 61 | color: var(--vjs-theme-forest--primary); 62 | } 63 | 64 | .vjs-theme-forest .vjs-play-control:hover .vjs-icon-placeholder:before { 65 | background-color: var(--vjs-theme-forest--primary); 66 | color: var(--vjs-theme-forest--secondary); 67 | } 68 | 69 | /* Volume stuff */ 70 | .vjs-theme-forest .vjs-mute-control { 71 | display: none; 72 | } 73 | 74 | .vjs-theme-forest .vjs-volume-panel { 75 | margin-left: 0.5em; 76 | margin-right: 0.5em; 77 | padding-top: 0.3em; 78 | } 79 | 80 | .vjs-theme-forest .vjs-volume-panel, 81 | .vjs-theme-forest .vjs-volume-panel:hover, 82 | .vjs-theme-forest .vjs-volume-panel:hover .vjs-volume-control.vjs-volume-horizontal, 83 | .vjs-theme-forest .vjs-volume-panel:active .vjs-volume-control.vjs-volume-horizontal, 84 | .vjs-theme-forest .vjs-volume-panel.vjs-volume-panel-horizontal:hover, 85 | .vjs-theme-forest .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active, 86 | .vjs-theme-forest .vjs-volume-bar.vjs-slider-horizontal { 87 | width: 3em; 88 | } 89 | 90 | .vjs-theme-forest .vjs-volume-level::before { 91 | font-size: 1em; 92 | } 93 | 94 | .vjs-theme-forest .vjs-volume-panel .vjs-volume-control { 95 | opacity: 1; 96 | width: 100%; 97 | height: 100%; 98 | } 99 | 100 | .vjs-theme-forest .vjs-volume-bar { 101 | background-color: transparent; 102 | margin: 0; 103 | } 104 | 105 | .vjs-theme-forest .vjs-slider-horizontal .vjs-volume-level { 106 | height: 100%; 107 | } 108 | 109 | .vjs-theme-forest .vjs-volume-bar.vjs-slider-horizontal { 110 | margin-top: 0; 111 | margin-bottom: 0; 112 | height: 100%; 113 | } 114 | 115 | .vjs-theme-forest .vjs-volume-bar::before { 116 | content: ''; 117 | z-index: 0; 118 | width: 0; 119 | height: 0; 120 | position: absolute; 121 | top: 0px; 122 | left: 0; 123 | 124 | border-style: solid; 125 | border-width: 0 0 2em 3em; 126 | border-color: transparent transparent var(--vjs-theme-forest--primary) transparent; 127 | } 128 | 129 | .vjs-theme-forest .vjs-volume-level { 130 | overflow: hidden; 131 | background-color: transparent; 132 | } 133 | 134 | .vjs-theme-forest .vjs-volume-level::before { 135 | content: ''; 136 | z-index: 1; 137 | width: 0; 138 | height: 0; 139 | position: absolute; 140 | top: 0; 141 | left: 0; 142 | 143 | border-style: solid; 144 | border-width: 0 0 2em 3em; 145 | border-color: transparent transparent var(--vjs-theme-forest--secondary) transparent; 146 | } 147 | 148 | /* Progress Bar */ 149 | .vjs-theme-forest .vjs-progress-control:hover .vjs-progress-holder { 150 | font-size: 1em; 151 | } 152 | 153 | .vjs-theme-forest .vjs-play-progress::before { 154 | display: none; 155 | } 156 | 157 | .vjs-theme-forest .vjs-progress-holder { 158 | border-radius: 0.2em; 159 | height: 0.5em; 160 | margin: 0; 161 | } 162 | 163 | .vjs-theme-forest .vjs-play-progress, 164 | .vjs-theme-forest .vjs-load-progress, 165 | .vjs-theme-forest .vjs-load-progress div { 166 | border-radius: 0.2em; 167 | } 168 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 17 | 18 | 19 | Sea 20 | 28 | 32 | 33 | 34 | 35 | 36 | Forest 37 | 45 | 49 | 50 | 51 | 52 | 53 | Fantasy 54 | 62 | 66 | 67 | 68 | 69 | 70 | Fantasy (Nyan) 71 | 79 | 83 | 84 | 85 | 86 | 87 | City 88 | 96 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [ 4 | { 5 | "src": "package.json", 6 | "use": "@now/static-build", 7 | "config": { "distDir": "dist" } 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@videojs/themes", 3 | "version": "1.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "parcel build **/*.css index.html --no-source-maps --no-content-hash", 8 | "clean": "rm -rf ./dist", 9 | "dev": "parcel index.html", 10 | "prepublish": "npm run clean && npm run build" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "autoprefixer": "^9.6.1", 17 | "parcel-bundler": "^1.12.3", 18 | "postcss-modules": "^1.4.1", 19 | "postcss-preset-env": "^6.7.0", 20 | "sass": "^1.22.9" 21 | }, 22 | "dependencies": { 23 | "postcss-inline-svg": "^4.1.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [require('autoprefixer'), require('postcss-preset-env'), require('postcss-inline-svg')] 3 | }; 4 | -------------------------------------------------------------------------------- /sea/index.css: -------------------------------------------------------------------------------- 1 | .vjs-theme-sea .vjs-big-play-button { 2 | width: 103px; 3 | height: 79px; 4 | object-fit: contain; 5 | background-color: rgba(255, 255, 255, 0.25); 6 | border: none; 7 | margin: 0 auto; 8 | line-height: 79px; 9 | top: 50%; 10 | left: 50%; 11 | border-radius: 30px; 12 | margin-top: -51.5px; 13 | margin-left: -39.5px; 14 | } 15 | 16 | .vjs-theme-sea .vjs-control-bar { 17 | height: 4em; 18 | background-color: rgba(255, 255, 255, 0.4); 19 | } 20 | 21 | .vjs-theme-sea .vjs-button:hover { 22 | color: #4176bc; 23 | background: linear-gradient(to top, #d0ddee, #fff); 24 | } 25 | 26 | .vjs-theme-sea .vjs-button > .vjs-icon-placeholder::before { 27 | line-height: 2.2; 28 | } 29 | 30 | .vjs-theme-sea .vjs-time-control { 31 | line-height: 4em; 32 | } 33 | 34 | .vjs-theme-sea .vjs-volume-panel { 35 | display: none; 36 | } 37 | 38 | .vjs-theme-sea .vjs-picture-in-picture-control { 39 | display: none; 40 | } 41 | 42 | .vjs-theme-sea .vjs-progress-control .vjs-play-progress { 43 | background-color: rgba(65, 118, 188, 0.9); 44 | } 45 | 46 | .vjs-theme-sea .vjs-progress-control .vjs-play-progress:before { 47 | display: none; 48 | } 49 | 50 | .vjs-theme-sea .vjs-progress-control .vjs-slider { 51 | background-color: rgba(65, 118, 188, 0.1); 52 | } 53 | 54 | .vjs-theme-sea .vjs-progress-control .vjs-load-progress div { 55 | background: rgba(255, 255, 255, 0.5); 56 | } 57 | 58 | .vjs-theme-sea .vjs-progress-control .vjs-progress-holder { 59 | margin: 0; 60 | height: 100%; 61 | } 62 | 63 | .vjs-theme-sea .vjs-progress-control .vjs-time-tooltip { 64 | background-color: rgba(65, 118, 188, 0.5); 65 | color: #fff; 66 | } 67 | 68 | .vjs-theme-sea .vjs-progress-control .vjs-mouse-display .vjs-time-tooltip { 69 | background-color: rgba(255, 255, 255, 0.7); 70 | color: #4176bc; 71 | } 72 | 73 | --------------------------------------------------------------------------------