Significantly improve the media player UX

This commit is contained in:
Michael Fabian 'Xaymar' Dirks
2022-11-27 00:53:36 +01:00
parent 445d5f45f5
commit 60aaaf7132
4 changed files with 224 additions and 184 deletions
+73 -77
View File
@@ -1,85 +1,81 @@
{% assign file_info = site.static_files | where: "path", include.url %}
{% capture content %}
{% if include.player %}
<div class="top">
<select class="variant"></select>
</div>
<div class="bottom">
<span class="play"></span>
<div class="playback">
{% if include.player %}
<div class="top">
<select class="variant"></select>
</div>
<div class="bottom">
<span class="play"></span>
<span class="time">0:00 / 0:00</span>
<input type="range" class="progress">
</div>
<div class="audio">
<span class="mute"></span>
<input type="range" class="volume">
<span class="fullscreen"></span>
</div>
<span class="fullscreen"></span>
</div>
{% endif %}
{% if include.link %}<a href="{% if include.link == true %}{{ include.url }}{% else %}{{ include.link }}{% endif %}" {% if include.caption %}alt="{{ include.caption }}"{% endif %} target="_blank">{% endif %}
{% assign file_info = site.static_files | where: "path", include.url %}
{% if include.type == "image" %}
<picture
class="content"
{% if include.lazyload %}data-lazyload=""{% endif %}
{% comment %}
src="{{ include.url | absolute_url }}"
{% endcomment %}
{% if include.width %}width="{{ include.width }}"{% endif %}
{% if include.height %}height="{{ include.height }}"{% endif %}>
{% if include.lazyload %}<noscript>{% endif %}
<img src="{{ include.url | absolute_url }}"
{% if include.alt %}alt="{{ include.alt }}"{% endif %}
{% if include.width %}width="{{ include.width }}"{% endif %}
{% if include.height %}height="{{ include.height }}"{% endif %}>
{% if include.lazyload %}</noscript>{% endif %}
</picture>
{% elsif include.type == "video" %}
<video {% if include.player %}{% else %}controls{% endif %}
class="content"
{% if include.lazyload %}data-lazyload=""{% endif %}
{% if include.poster %}poster="{{ include.poster | absolute_url }}"{% endif %}
{% if include.preload %}preload="{{ include.preload }}"{% endif %}
{% comment %}
src="{{ include.url | absolute_url }}"
{% endcomment %}
{% if include.width %}width="{{ include.width }}"{% endif %}
{% if include.height %}height="{{ include.height }}"{% endif %}
{% if include.autoplay %}autoplay="true"{% endif %}
{% if include.muted %}muted="true"{% endif %}
{% if include.loop %}loop="true"{% endif %}>
{% if include.lazyload %}<noscript>{% endif %}
<source src="{{ include.url | absolute_url }}">
{% if include.lazyload %}</noscript>{% endif %}
</video>
{% elsif include.type == "audio" %}
<audio controls
class="content"
{% if include.lazyload %}data-lazyload=""{% endif %}
{% if include.preload %}preload="{{ include.preload }}"{% endif %}
{% comment %}
src="{{ include.url | absolute_url }}"
{% endcomment %}
{% if include.width %}width="{{ include.width }}"{% endif %}
{% if include.height %}height="{{ include.height }}"{% endif %}
{% if include.autoplay %}autoplay="true"{% endif %}
{% if include.muted %}muted="true"{% endif %}
{% if include.loop %}loop="true"{% endif %}>
{% if include.lazyload %}<noscript>{% endif %}
<source src="{{ include.url | absolute_url }}">
{% if include.lazyload %}</noscript>{% endif %}
</audio>
{% endif %}
{% if include.link %}
</a>
{% endif %}
{% if include.caption %}
<figcaption>{{ include.caption }}</figcaption>
{% endif %}
{% endif %}
{% if include.link %}<a href="{% if include.link == true %}{{ include.url }}{% else %}{{ include.link }}{% endif %}" {% if include.caption %}alt="{{ include.caption }}"{% endif %} target="_blank">{% endif %}
{% if include.type == "image" %}
<picture
class="content"
{% if include.width %}width="{{ include.width }}"{% endif %}
{% if include.height %}height="{{ include.height }}"{% endif %}
{% if include.lazyload %}data-lazyload=""{% endif %}
>
{% if include.lazyload %}<noscript>{% endif %}
<img src="{{ include.url | absolute_url }}"
{% if include.alt %}alt="{{ include.alt }}"{% endif %}
{% if include.width %}width="{{ include.width }}"{% endif %}
{% if include.height %}height="{{ include.height }}"{% endif %}>
{% if include.lazyload %}</noscript>{% endif %}
{% if include.content %}{{include.content}}{% endif %}
</picture>
{% elsif include.type == "video" %}
<video
{% if include.player %}{% else %}controls{% endif %}
class="content"
{% if include.width %}width="{{ include.width }}"{% endif %}
{% if include.height %}height="{{ include.height }}"{% endif %}
{% if include.autoplay %}autoplay="true"{% endif %}
{% if include.muted %}muted="true"{% endif %}
{% if include.loop %}loop="true"{% endif %}
{% if include.poster %}poster="{{ include.poster | absolute_url }}"{% endif %}
{% if include.preload %}preload="{{ include.preload }}"{% endif %}
{% if include.lazyload %}data-lazyload=""{% endif %}
>
{% if include.lazyload %}<noscript>{% endif %}
{% if include.url %}<source src="{{ include.url | absolute_url }}">{% endif %}
{% if include.lazyload %}</noscript>{% endif %}
{% if include.content %}{{include.content}}{% endif %}
</video>
{% elsif include.type == "audio" %}
<audio
{% if include.player %}{% else %}controls{% endif %}
class="content"
{% if include.width %}width="{{ include.width }}"{% endif %}
{% if include.height %}height="{{ include.height }}"{% endif %}
{% if include.autoplay %}autoplay="true"{% endif %}
{% if include.muted %}muted="true"{% endif %}
{% if include.loop %}loop="true"{% endif %}
{% if include.preload %}preload="{{ include.preload }}"{% endif %}
{% if include.lazyload %}data-lazyload=""{% endif %}
>
{% if include.lazyload %}<noscript>{% endif %}
{% if include.url %}<source src="{{ include.url | absolute_url }}">{% endif %}
{% if include.lazyload %}</noscript>{% endif %}
{% if include.content %}{{include.content}}{% endif %}
</audio>
{% endif %}
{% if include.link %}</a>{% endif %}
{% if include.caption %}<figcaption>{{ include.caption }}</figcaption>{% endif %}
{% endcapture %}
{% if include.player %}
{% assign class = include.type | append: " player" %}
{% else %}
{% assign class = include.type %}
{% endif %}
{% if include.player %}{% assign class = include.type | append: " player" %}{% else %}{% assign class = include.type %}{% endif %}
{% include blocks/_base.liquid type="media" class=class content=content float=include.float align=include.align id=include.id %}
@@ -68,16 +68,17 @@ videos:
{% for video in page.videos.videos %}
{% capture capture_video %}
{% include blocks/media.liquid type="video" caption=caption poster=video.poster muted=true preload="none" id=video.id player=true %}
<script>
document.getElementById("{{ video.id }}").variants = {
{% for bitrate in page.videos.bitrates %}"{{ bitrate }}kbit/s" : {
{% for resolution in page.videos.resolutions %}"{{ resolution }}" : {
{% for encoder in page.videos.encoders %}
{% assign real_url = encoder.url | replace: ":video", video.id | replace: ":res", resolution | replace: ":rate", bitrate | absolute_url%}"{{ encoder.name }}" : "{{ real_url }}",{% endfor %}
},{% endfor %}
},{% endfor %}
};
{% capture video_sources %}
{% for bitrate in page.videos.bitrates %}
{% for resolution in page.videos.resolutions %}
{% for encoder in page.videos.encoders %}
{% assign real_url = encoder.url | replace: ":video", video.id | replace: ":res", resolution | replace: ":rate", bitrate | absolute_url%}
<source src="{{ real_url }}" title="{{ bitrate }} kbit/s, {{ resolution }}, {{ encoder.name }}">
{% endfor %}
{% endfor %}
{% endfor %}
{% endcapture %}
{% include blocks/media.liquid type="video" caption=caption poster=video.poster muted=true preload="none" player=true content=video_sources %}
</script>
{% endcapture %}
{% include blocks/details.liquid title=video.name content=capture_video level=1 open=true %}
+99 -59
View File
@@ -8,6 +8,8 @@
.block-media > a > .content,
.block-media > .content {
object-fit: contain;
object-position: center center;
}
.block-media > figcaption {
@@ -22,6 +24,7 @@
// --------------------------------------------------------------------------------
// Block: Media Player
// --------------------------------------------------------------------------------
$media-player-button-size: 1.5rem;
.block-media.hide {
cursor: none;
@@ -29,144 +32,181 @@
.block-media > .top,
.block-media > .bottom {
display: block;
margin: 0;
padding: 0.5rem .5rem;
padding: 0.2rem 0.5rem;
}
.block-media > .top {
background: linear-gradient(to top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 80%);
position: absolute;
top: 0;
left: 0;
right: 0;
display: grid;
grid-template-columns: 1;
grid-template-rows: 1;
justify-content: stretch;
padding-bottom: 1rem;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: stretch;
gap: 0;
transition: top ease-in-out 333ms, opacity ease-in-out 333ms;
align-content: stretch;
gap: 0.5rem;
background: linear-gradient(to top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 80%);
transition: top ease-in-out 100ms, opacity ease-in-out 100s;
opacity: 1.0;
overflow: hidden;
user-select: none;
}
.block-media.hide > .top {
top: -100%;
opacity: 0.0;
transition: top ease-in-out 500ms, opacity ease-in-out 500s;
}
.block-media > .top > .variant {
// ToDo: Style this
flex-grow: 1;
}
.block-media > .bottom {
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 80%);
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: grid;
grid-template-columns: max-content 1fr max-content max-content;
justify-content: stretch;
padding-top: 1rem;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: stretch;
align-content: stretch;
gap: 0.5rem;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 80%);
transition: top ease-in-out 100ms, opacity ease-in-out 100s;
opacity: 1.0;
overflow: hidden;
user-select: none;
transition: bottom ease-in-out 333ms, opacity ease-in-out 333ms;
opacity: 1.0;
}
.block-media.hide > .bottom {
bottom: -100%;
opacity: 0.0;
transition: top ease-in-out 500ms, opacity ease-in-out 500s;
}
.block-media > .bottom > .play {
width: 2rem;
height: 2rem;
flex-grow: 0;
display: block;
margin: 0;
padding: 0;
font-size: 2rem;
line-height: 2rem;
width: $media-player-button-size;
height: $media-player-button-size;
font-size: $media-player-button-size;
line-height: $media-player-button-size;
text-align: center;
user-select: none;
}
.block-media > .bottom > .play.playing {
}
.block-media > .bottom > .playback {
.block-media > .bottom > .time {
margin: 0;
padding: 0;
display: grid;
grid-template-columns: max-content 1fr max-content;
justify-content: stretch;
align-items: stretch;
gap: 0.5rem;
user-select: none;
}
width: auto;
height: $media-player-button-size;
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
.block-media > .bottom > .playback > .time {
display: block;
height: 2rem;
margin: 0;
padding: 0;
text-align: right;
line-height: 2rem;
line-height: $media-player-button-size;
user-select: auto;
}
.block-media > .bottom > .playback > .progress {
display: block;
.block-media > .bottom > .progress {
margin: 0;
padding: 0;
width: auto;
min-width: 5rem;
height: 100%;
user-select: none;
}
flex-grow: 5;
flex-shrink: 1;
.block-media > .bottom > .audio {
margin: 0;
padding: 0;
display: grid;
grid-template-columns: max-content 1fr;
justify-content: stretch;
align-items: stretch;
gap: 0.5rem;
user-select: none;
}
.block-media > .bottom > .audio > .mute {
display: block;
user-select: none;
}
.block-media > .bottom > .mute {
margin: 0;
padding: 0;
width: 2rem;
height: 2rem;
font-size: 2rem;
line-height: 2rem;
width: $media-player-button-size;
height: $media-player-button-size;
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
display: block;
font-size: $media-player-button-size;
line-height: $media-player-button-size;
text-align: center;
user-select: none;
}
.block-media > .bottom > .audio > .mute.muted {
.block-media > .bottom > .mute.muted {
}
.block-media > .bottom > .audio > .volume {
display: block;
.block-media > .bottom > .volume {
margin: 0;
padding: 0;
width: auto;
min-width: 3rem;
max-width: 6rem;
height: 100%;
flex-grow: 1;
flex-shrink: 5;
flex-basis: auto;
display: block;
user-select: none;
}
.block-media > .bottom > .fullscreen {
width: 2rem;
height: 2rem;
margin: 0;
padding: 0;
font-size: 2rem;
line-height: 2rem;
width: $media-player-button-size;
height: $media-player-button-size;
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
display: block;
font-size: $media-player-button-size;
line-height: $media-player-button-size;
text-align: center;
user-select: none;
}
@media (max-width: 500px) {
.block-media > .bottom > .time {
display: none;
}
}
@media (max-width: 350px) {
.block-media > .bottom > .volume {
display: none;
}
}
@media (max-width: 250px) {
.block-media > .bottom > .play,
.block-media > .bottom > .mute,
.block-media > .bottom > .fullscreen {
display: none;
}
}
// --------------------------------------------------------------------------------
// Block: Media > Audio
+41 -38
View File
@@ -23,7 +23,7 @@ async function xmr_initialize_player(el) {
el.querySelector("audio");
// Play/Pause
let play_pause = el.querySelector(".bottom > .play");
let play_pause = el.querySelector(".play");
play_pause.update = function() {
if (media.paused) {
play_pause.classList.remove("playing");
@@ -50,7 +50,7 @@ async function xmr_initialize_player(el) {
play_pause.update();
// Mute
let audio_mute = el.querySelector(".bottom > .audio > .mute");
let audio_mute = el.querySelector(".mute");
audio_mute.update = function() {
if (media.muted) {
audio_mute.classList.add("muted");
@@ -75,7 +75,7 @@ async function xmr_initialize_player(el) {
audio_mute.update();
// Volume
let audio_volume = el.querySelector(".bottom > .audio > .volume");
let audio_volume = el.querySelector(".volume");
audio_volume.min = 0;
audio_volume.max = 2147483647;
audio_volume.update = function() {
@@ -102,7 +102,7 @@ async function xmr_initialize_player(el) {
audio_volume.update();
// Time
let playback_time = el.querySelector(".bottom > .playback > .time");
let playback_time = el.querySelector(".time");
playback_time.update = function() {
let duration_text = "";
let need_hour = false;
@@ -153,7 +153,7 @@ async function xmr_initialize_player(el) {
playback_time.update();
// Progress
let playback_progress = el.querySelector(".bottom > .playback > .progress");
let playback_progress = el.querySelector(".progress");
playback_progress.update = function() {
playback_progress.disabled = !media.seekable;
playback_progress.min = 0;
@@ -188,39 +188,6 @@ async function xmr_initialize_player(el) {
});
fullscreen.update();
// Variants
let variants = el.querySelector(".variant");
variants.addEventListener("input", () => {
media.pause();
play_pause.update();
media.src = variants.value;
});
variants.addEventListener("value", () => {
media.pause();
play_pause.update();
media.src = variants.value;
});
function createVariants(el, key, value) {
if (typeof(value) === "object") {
for (let k in value) {
let v = value[k];
createVariants(el, `${key} / ${k}`, v);
}
} else if (typeof(value) === "string") {
let option = document.createElement("option");
option.value = value;
option.textContent = key;
el.appendChild(option);
} else {
el.appendChild(document.createElement(typeof(value)));
}
}
for (let k in el.variants) {
let v = el.variants[k];
createVariants(variants, k, v);
}
variants.value = media.src = variants.querySelectorAll("option")[0].value;
// Media Play/Pause by click
media.addEventListener("click", () => {
play_pause.click();
@@ -257,6 +224,42 @@ async function xmr_initialize_player(el) {
}
});
el.hideOverlay();
// Variants
let variant = el.querySelector(".variant");
variant.update = function() {
let paused = media.paused;
let muted = media.muted;
let volume = media.volume;
let time = media.currentTime;
media.pause();
media.currentSrc = variant.value;
media.play();
media.currentTime = time;
media.volume = volume;
media.muted = muted;
if (paused) {
media.pause();
} else {
media.play();
}
play_pause.update();
}
variant.addEventListener("input", () => { variant.update(); });
variant.addEventListener("value", () => { variant.update(); });
// Add options from available sources.
let sources = el.querySelectorAll("source");
for (let k of sources) {
let option = document.createElement("option");
option.value = k.src;
option.textContent = k.title;
variant.appendChild(option);
}
variant.value = media.currentSrc;
}
async function xmr_initialize_players() {