Browse Source
* Experiment with javascript bundling * Experiment with snowpack. Making progress * Success! Uses local js modules and assets and no cdns * Missing local csspull/226/head
25 changed files with 8870 additions and 57 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
{ |
||||
"name": "owncast-dependencies", |
||||
"version": "1.0.0", |
||||
"description": "", |
||||
"main": "index.js", |
||||
"dependencies": { |
||||
"@joeattardi/emoji-button": "^4.2.0", |
||||
"@justinribeiro/lite-youtube": "^0.9.0", |
||||
"@videojs/http-streaming": "^2.2.0", |
||||
"@videojs/themes": "^1.0.0", |
||||
"htm": "^3.0.4", |
||||
"preact": "^10.5.3", |
||||
"showdown": "^1.9.1", |
||||
"tailwindcss": "^1.8.10", |
||||
"video.js": "^7.9.6" |
||||
}, |
||||
"devDependencies": { |
||||
"snowpack": "^2.12.1" |
||||
}, |
||||
"snowpack": { |
||||
"install": [ |
||||
"video.js/dist/video.min.js", |
||||
"@videojs/themes/fantasy/*", |
||||
"@videojs/http-streaming/dist/videojs-http-streaming.min.js", |
||||
"video.js/dist/video-js.min.css", |
||||
"@joeattardi/emoji-button", |
||||
"@justinribeiro/lite-youtube", |
||||
"htm", |
||||
"preact", |
||||
"showdown", |
||||
"tailwindcss/dist/tailwind.min.css" |
||||
] |
||||
}, |
||||
"scripts": { |
||||
"test": "echo \"Error: no test specified\" && exit 1", |
||||
"build": "npm install && npx snowpack install && cp -R web_modules ../../webroot/js" |
||||
}, |
||||
"author": "", |
||||
"license": "ISC" |
||||
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,301 @@
@@ -0,0 +1,301 @@
|
||||
/** |
||||
* |
||||
* The shadowDom / Intersection Observer version of Paul's concept: |
||||
* https://github.com/paulirish/lite-youtube-embed
|
||||
* |
||||
* A lightweight YouTube embed. Still should feel the same to the user, just |
||||
* MUCH faster to initialize and paint. |
||||
* |
||||
* Thx to these as the inspiration |
||||
* https://storage.googleapis.com/amp-vs-non-amp/youtube-lazy.html
|
||||
* https://autoplay-youtube-player.glitch.me/
|
||||
* |
||||
* Once built it, I also found these (👍👍): |
||||
* https://github.com/ampproject/amphtml/blob/master/extensions/amp-youtube
|
||||
* https://github.com/Daugilas/lazyYT https://github.com/vb/lazyframe
|
||||
*/ |
||||
class LiteYTEmbed extends HTMLElement { |
||||
constructor() { |
||||
super(); |
||||
this.iframeLoaded = false; |
||||
this.setupDom(); |
||||
} |
||||
static get observedAttributes() { |
||||
return ['videoid']; |
||||
} |
||||
connectedCallback() { |
||||
this.addEventListener('pointerover', LiteYTEmbed.warmConnections, { |
||||
once: true, |
||||
}); |
||||
this.addEventListener('click', () => this.addIframe()); |
||||
} |
||||
get videoId() { |
||||
return encodeURIComponent(this.getAttribute('videoid') || ''); |
||||
} |
||||
set videoId(id) { |
||||
this.setAttribute('videoid', id); |
||||
} |
||||
get videoTitle() { |
||||
return this.getAttribute('videotitle') || 'Video'; |
||||
} |
||||
set videoTitle(title) { |
||||
this.setAttribute('videotitle', title); |
||||
} |
||||
get videoPlay() { |
||||
return this.getAttribute('videoPlay') || 'Play'; |
||||
} |
||||
set videoPlay(name) { |
||||
this.setAttribute('videoPlay', name); |
||||
} |
||||
get videoStartAt() { |
||||
return Number(this.getAttribute('videoStartAt') || '0'); |
||||
} |
||||
set videoStartAt(time) { |
||||
this.setAttribute('videoStartAt', String(time)); |
||||
} |
||||
get autoLoad() { |
||||
return this.hasAttribute('autoload'); |
||||
} |
||||
set autoLoad(value) { |
||||
if (value) { |
||||
this.setAttribute('autoload', ''); |
||||
} |
||||
else { |
||||
this.removeAttribute('autoload'); |
||||
} |
||||
} |
||||
get params() { |
||||
return `start=${this.videoStartAt}&${this.getAttribute('params')}`; |
||||
} |
||||
/** |
||||
* Define our shadowDOM for the component |
||||
*/ |
||||
setupDom() { |
||||
const shadowDom = this.attachShadow({ mode: 'open' }); |
||||
shadowDom.innerHTML = ` |
||||
<style> |
||||
:host { |
||||
contain: content; |
||||
display: block; |
||||
position: relative; |
||||
width: 100%; |
||||
padding-bottom: calc(100% / (16 / 9)); |
||||
} |
||||
|
||||
#frame, #fallbackPlaceholder, iframe { |
||||
position: absolute; |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
|
||||
#frame { |
||||
cursor: pointer; |
||||
} |
||||
|
||||
#fallbackPlaceholder { |
||||
object-fit: cover; |
||||
} |
||||
|
||||
#frame::before { |
||||
content: ''; |
||||
display: block; |
||||
position: absolute; |
||||
top: 0; |
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAADGCAYAAAAT+OqFAAAAdklEQVQoz42QQQ7AIAgEF/T/D+kbq/RWAlnQyyazA4aoAB4FsBSA/bFjuF1EOL7VbrIrBuusmrt4ZZORfb6ehbWdnRHEIiITaEUKa5EJqUakRSaEYBJSCY2dEstQY7AuxahwXFrvZmWl2rh4JZ07z9dLtesfNj5q0FU3A5ObbwAAAABJRU5ErkJggg==); |
||||
background-position: top; |
||||
background-repeat: repeat-x; |
||||
height: 60px; |
||||
padding-bottom: 50px; |
||||
width: 100%; |
||||
transition: all 0.2s cubic-bezier(0, 0, 0.2, 1); |
||||
z-index: 1; |
||||
} |
||||
/* play button */ |
||||
.lty-playbtn { |
||||
width: 70px; |
||||
height: 46px; |
||||
background-color: #212121; |
||||
z-index: 1; |
||||
opacity: 0.8; |
||||
border-radius: 14%; /* TODO: Consider replacing this with YT's actual svg. Eh. */ |
||||
transition: all 0.2s cubic-bezier(0, 0, 0.2, 1); |
||||
border: 0; |
||||
} |
||||
#frame:hover .lty-playbtn { |
||||
background-color: #f00; |
||||
opacity: 1; |
||||
} |
||||
/* play button triangle */ |
||||
.lty-playbtn:before { |
||||
content: ''; |
||||
border-style: solid; |
||||
border-width: 11px 0 11px 19px; |
||||
border-color: transparent transparent transparent #fff; |
||||
} |
||||
.lty-playbtn, |
||||
.lty-playbtn:before { |
||||
position: absolute; |
||||
top: 50%; |
||||
left: 50%; |
||||
transform: translate3d(-50%, -50%, 0); |
||||
} |
||||
|
||||
/* Post-click styles */ |
||||
.lyt-activated { |
||||
cursor: unset; |
||||
} |
||||
|
||||
#frame.lyt-activated::before, |
||||
.lyt-activated .lty-playbtn { |
||||
display: none; |
||||
} |
||||
</style> |
||||
<div id="frame"> |
||||
<picture> |
||||
<source id="webpPlaceholder" type="image/webp"> |
||||
<source id="jpegPlaceholder" type="image/jpeg"> |
||||
<img id="fallbackPlaceholder" referrerpolicy="origin"> |
||||
</picture> |
||||
<button class="lty-playbtn"></button> |
||||
</div> |
||||
`;
|
||||
this.domRefFrame = this.shadowRoot.querySelector('#frame'); |
||||
this.domRefImg = { |
||||
fallback: this.shadowRoot.querySelector('#fallbackPlaceholder'), |
||||
webp: this.shadowRoot.querySelector('#webpPlaceholder'), |
||||
jpeg: this.shadowRoot.querySelector('#jpegPlaceholder'), |
||||
}; |
||||
this.domRefPlayButton = this.shadowRoot.querySelector('.lty-playbtn'); |
||||
} |
||||
/** |
||||
* Parse our attributes and fire up some placeholders |
||||
*/ |
||||
setupComponent() { |
||||
this.initImagePlaceholder(); |
||||
this.domRefPlayButton.setAttribute('aria-label', `${this.videoPlay}: ${this.videoTitle}`); |
||||
this.setAttribute('title', `${this.videoPlay}: ${this.videoTitle}`); |
||||
if (this.autoLoad) { |
||||
this.initIntersectionObserver(); |
||||
} |
||||
} |
||||
/** |
||||
* Lifecycle method that we use to listen for attribute changes to period |
||||
* @param {*} name |
||||
* @param {*} oldVal |
||||
* @param {*} newVal |
||||
*/ |
||||
attributeChangedCallback(name, oldVal, newVal) { |
||||
switch (name) { |
||||
case 'videoid': { |
||||
if (oldVal !== newVal) { |
||||
this.setupComponent(); |
||||
// if we have a previous iframe, remove it and the activated class
|
||||
if (this.domRefFrame.classList.contains('lyt-activated')) { |
||||
this.domRefFrame.classList.remove('lyt-activated'); |
||||
this.shadowRoot.querySelector('iframe').remove(); |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
/** |
||||
* Inject the iframe into the component body |
||||
*/ |
||||
addIframe() { |
||||
if (!this.iframeLoaded) { |
||||
const iframeHTML = ` |
||||
<iframe frameborder="0" |
||||
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen |
||||
src="https://www.youtube.com/embed/${this.videoId}?autoplay=1&${this.params}" |
||||
></iframe>`; |
||||
this.domRefFrame.insertAdjacentHTML('beforeend', iframeHTML); |
||||
this.domRefFrame.classList.add('lyt-activated'); |
||||
this.iframeLoaded = true; |
||||
} |
||||
} |
||||
/** |
||||
* Setup the placeholder image for the component |
||||
*/ |
||||
initImagePlaceholder() { |
||||
// we don't know which image type to preload, so warm the connection
|
||||
LiteYTEmbed.addPrefetch('preconnect', 'https://i.ytimg.com/'); |
||||
const posterUrlWebp = `https://i.ytimg.com/vi_webp/${this.videoId}/hqdefault.webp`; |
||||
const posterUrlJpeg = `https://i.ytimg.com/vi/${this.videoId}/hqdefault.jpg`; |
||||
this.domRefImg.webp.srcset = posterUrlWebp; |
||||
this.domRefImg.jpeg.srcset = posterUrlJpeg; |
||||
this.domRefImg.fallback.src = posterUrlJpeg; |
||||
this.domRefImg.fallback.setAttribute('aria-label', `${this.videoPlay}: ${this.videoTitle}`); |
||||
this.domRefImg.fallback.setAttribute('alt', `${this.videoPlay}: ${this.videoTitle}`); |
||||
} |
||||
/** |
||||
* Setup the Intersection Observer to load the iframe when scrolled into view |
||||
*/ |
||||
initIntersectionObserver() { |
||||
if ('IntersectionObserver' in window && |
||||
'IntersectionObserverEntry' in window) { |
||||
const options = { |
||||
root: null, |
||||
rootMargin: '0px', |
||||
threshold: 0, |
||||
}; |
||||
const observer = new IntersectionObserver((entries, observer) => { |
||||
entries.forEach(entry => { |
||||
if (entry.isIntersecting && !this.iframeLoaded) { |
||||
LiteYTEmbed.warmConnections(); |
||||
this.addIframe(); |
||||
observer.unobserve(this); |
||||
} |
||||
}); |
||||
}, options); |
||||
observer.observe(this); |
||||
} |
||||
} |
||||
/** |
||||
* Add a <link rel={preload | preconnect} ...> to the head |
||||
* @param {*} kind |
||||
* @param {*} url |
||||
* @param {*} as |
||||
*/ |
||||
static addPrefetch(kind, url, as) { |
||||
const linkElem = document.createElement('link'); |
||||
linkElem.rel = kind; |
||||
linkElem.href = url; |
||||
if (as) { |
||||
linkElem.as = as; |
||||
} |
||||
linkElem.crossOrigin = 'true'; |
||||
document.head.append(linkElem); |
||||
} |
||||
/** |
||||
* Begin preconnecting to warm up the iframe load Since the embed's netwok |
||||
* requests load within its iframe, preload/prefetch'ing them outside the |
||||
* iframe will only cause double-downloads. So, the best we can do is warm up |
||||
* a few connections to origins that are in the critical path. |
||||
* |
||||
* Maybe `<link rel=preload as=document>` would work, but it's unsupported: |
||||
* http://crbug.com/593267 But TBH, I don't think it'll happen soon with Site
|
||||
* Isolation and split caches adding serious complexity. |
||||
*/ |
||||
static warmConnections() { |
||||
if (LiteYTEmbed.preconnected) |
||||
return; |
||||
// Host that YT uses to serve JS needed by player, per amp-youtube
|
||||
LiteYTEmbed.addPrefetch('preconnect', 'https://s.ytimg.com'); |
||||
// The iframe document and most of its subresources come right off
|
||||
// youtube.com
|
||||
LiteYTEmbed.addPrefetch('preconnect', 'https://www.youtube.com'); |
||||
// The botguard script is fetched off from google.com
|
||||
LiteYTEmbed.addPrefetch('preconnect', 'https://www.google.com'); |
||||
// TODO: Not certain if these ad related domains are in the critical path.
|
||||
// Could verify with domain-specific throttling.
|
||||
LiteYTEmbed.addPrefetch('preconnect', 'https://googleads.g.doubleclick.net'); |
||||
LiteYTEmbed.addPrefetch('preconnect', 'https://static.doubleclick.net'); |
||||
LiteYTEmbed.preconnected = true; |
||||
} |
||||
} |
||||
LiteYTEmbed.preconnected = false; |
||||
// Register custom element
|
||||
customElements.define('lite-youtube', LiteYTEmbed); |
||||
|
||||
export { LiteYTEmbed }; |
@ -0,0 +1,116 @@
@@ -0,0 +1,116 @@
|
||||
.vjs-theme-fantasy { |
||||
--vjs-theme-fantasy--primary: #9f44b4; |
||||
--vjs-theme-fantasy--secondary: #fff; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-big-play-button { |
||||
width: 70px; |
||||
height: 70px; |
||||
background: none; |
||||
line-height: 70px; |
||||
font-size: 80px; |
||||
border: none; |
||||
top: 50%; |
||||
left: 50%; |
||||
margin-top: -35px; |
||||
margin-left: -35px; |
||||
color: var(--vjs-theme-fantasy--primary); |
||||
} |
||||
|
||||
.vjs-theme-fantasy:hover .vjs-big-play-button, |
||||
.vjs-theme-fantasy.vjs-big-play-button:focus { |
||||
background-color: transparent; |
||||
color: #fff; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-control-bar { |
||||
height: 54px; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-button > .vjs-icon-placeholder::before { |
||||
line-height: 54px; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-time-control { |
||||
line-height: 54px; |
||||
} |
||||
|
||||
/* Play Button */ |
||||
.vjs-theme-fantasy .vjs-play-control { |
||||
font-size: 1.5em; |
||||
position: relative; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-volume-panel { |
||||
order: 4; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-volume-bar { |
||||
margin-top: 2.5em; |
||||
} |
||||
|
||||
.vjs-theme-city .vjs-volume-panel:hover .vjs-volume-control.vjs-volume-horizontal { |
||||
height: 100%; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-progress-control .vjs-progress-holder { |
||||
font-size: 1.5em; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-progress-control:hover .vjs-progress-holder { |
||||
font-size: 1.5em; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-play-control .vjs-icon-placeholder::before { |
||||
height: 1.3em; |
||||
width: 1.3em; |
||||
margin-top: 0.2em; |
||||
border-radius: 1em; |
||||
border: 3px solid var(--vjs-theme-fantasy--secondary); |
||||
top: 2px; |
||||
left: 9px; |
||||
line-height: 1.1; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-play-control:hover .vjs-icon-placeholder::before { |
||||
border: 3px solid var(--vjs-theme-fantasy--secondary); |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-play-progress { |
||||
background-color: var(--vjs-theme-fantasy--primary); |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-play-progress::before { |
||||
height: 0.8em; |
||||
width: 0.8em; |
||||
content: ''; |
||||
background-color: var(--vjs-theme-fantasy--primary); |
||||
border: 4px solid var(--vjs-theme-fantasy--secondary); |
||||
border-radius: 0.8em; |
||||
top: -0.25em; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-progress-control { |
||||
font-size: 14px; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-fullscreen-control { |
||||
order: 6; |
||||
} |
||||
|
||||
.vjs-theme-fantasy .vjs-remaining-time { |
||||
display: none; |
||||
} |
||||
|
||||
/* Nyan version */ |
||||
.vjs-theme-fantasy.nyan .vjs-play-progress { |
||||
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%); |
||||
} |
||||
|
||||
.vjs-theme-fantasy.nyan .vjs-play-progress::before { |
||||
height: 1.3em; |
||||
width: 1.3em; |
||||
background: svg-load('icons/nyan-cat.svg', fill=#fff) no-repeat; |
||||
border: none; |
||||
top: -0.35em; |
||||
} |
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; |
||||
|
||||
function getDefaultExportFromCjs (x) { |
||||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; |
||||
} |
||||
|
||||
function createCommonjsModule(fn, basedir, module) { |
||||
return module = { |
||||
path: basedir, |
||||
exports: {}, |
||||
require: function (path, base) { |
||||
return commonjsRequire(path, (base === undefined || base === null) ? module.path : base); |
||||
} |
||||
}, fn(module, module.exports), module.exports; |
||||
} |
||||
|
||||
function getDefaultExportFromNamespaceIfNotNamed (n) { |
||||
return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; |
||||
} |
||||
|
||||
function commonjsRequire () { |
||||
throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs'); |
||||
} |
||||
|
||||
export { commonjsGlobal as a, getDefaultExportFromNamespaceIfNotNamed as b, createCommonjsModule as c, getDefaultExportFromCjs as g }; |
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
import { b as getDefaultExportFromNamespaceIfNotNamed, a as commonjsGlobal } from './_commonjsHelpers-37fa8da4.js'; |
||||
|
||||
var _nodeResolve_empty = {}; |
||||
|
||||
var _nodeResolve_empty$1 = /*#__PURE__*/Object.freeze({ |
||||
__proto__: null, |
||||
'default': _nodeResolve_empty |
||||
}); |
||||
|
||||
var minDoc = /*@__PURE__*/getDefaultExportFromNamespaceIfNotNamed(_nodeResolve_empty$1); |
||||
|
||||
var topLevel = typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : |
||||
typeof window !== 'undefined' ? window : {}; |
||||
|
||||
|
||||
var doccy; |
||||
|
||||
if (typeof document !== 'undefined') { |
||||
doccy = document; |
||||
} else { |
||||
doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; |
||||
|
||||
if (!doccy) { |
||||
doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; |
||||
} |
||||
} |
||||
|
||||
var document_1 = doccy; |
||||
|
||||
var win; |
||||
|
||||
if (typeof window !== "undefined") { |
||||
win = window; |
||||
} else if (typeof commonjsGlobal !== "undefined") { |
||||
win = commonjsGlobal; |
||||
} else if (typeof self !== "undefined"){ |
||||
win = self; |
||||
} else { |
||||
win = {}; |
||||
} |
||||
|
||||
var window_1 = win; |
||||
|
||||
export { document_1 as d, window_1 as w }; |
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
var n=function(t,s,r,e){var u;s[0]=0;for(var h=1;h<s.length;h++){var p=s[h++],a=s[h]?(s[0]|=p?1:2,r[s[h++]]):s[++h];3===p?e[0]=a:4===p?e[1]=Object.assign(e[1]||{},a):5===p?(e[1]=e[1]||{})[s[++h]]=a:6===p?e[1][s[++h]]+=a+"":p?(u=t.apply(a,n(t,a,r,["",null])),e.push(u),a[0]?s[0]|=2:(s[h-2]=0,s[h]=u)):e.push(a);}return e},t=new Map;function htm_module(s){var r=t.get(this);return r||(r=new Map,t.set(this,r)),(r=n(this,r.get(s)||(r.set(s,r=function(n){for(var t,s,r=1,e="",u="",h=[0],p=function(n){1===r&&(n||(e=e.replace(/^\s*\n\s*|\s*\n\s*$/g,"")))?h.push(0,n,e):3===r&&(n||e)?(h.push(3,n,e),r=2):2===r&&"..."===e&&n?h.push(4,n,0):2===r&&e&&!n?h.push(5,0,!0,e):r>=5&&((e||!n&&5===r)&&(h.push(r,0,e,s),r=6),n&&(h.push(r,n,0,s),r=6)),e="";},a=0;a<n.length;a++){a&&(1===r&&p(),p(a));for(var l=0;l<n[a].length;l++)t=n[a][l],1===r?"<"===t?(p(),h=[h],r=3):e+=t:4===r?"--"===e&&">"===t?(r=1,e=""):e=t+e[0]:u?t===u?u="":e+=t:'"'===t||"'"===t?u=t:">"===t?(p(),r=1):r&&("="===t?(r=5,s=e,e=""):"/"===t&&(r<5||">"===n[a][l+1])?(p(),3===r&&(h=h[0]),r=h,(h=h[0]).push(2,0,r),r=0):" "===t||"\t"===t||"\n"===t||"\r"===t?(p(),r=2):e+=t),3===r&&"!--"===e&&(r=4,h=h[0]);}return p(),h}(s)),r),arguments,[])).length>1?r:r[0]} |
||||
|
||||
export default htm_module; |
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
{ |
||||
"imports": { |
||||
"@joeattardi/emoji-button": "./@joeattardi/emoji-button.js", |
||||
"@justinribeiro/lite-youtube": "./@justinribeiro/lite-youtube.js", |
||||
"@videojs/http-streaming/dist/videojs-http-streaming.min.js": "./@videojs/http-streaming/dist/videojs-http-streaming.min.js", |
||||
"@videojs/themes/fantasy/index.css": "./@videojs/themes/fantasy/index.css", |
||||
"htm": "./htm.js", |
||||
"preact": "./preact.js", |
||||
"showdown": "./showdown.js", |
||||
"tailwindcss/dist/tailwind.min.css": "./tailwindcss/dist/tailwind.min.css", |
||||
"video.js/dist/video-js.min.css": "./videojs/dist/video-js.min.css", |
||||
"video.js/dist/video.min.js": "./videojs/dist/video.min.js" |
||||
} |
||||
} |
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue