You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
senzapaura_es/src/lib/components/VideoYoutube.svelte

158 lines
3.5 KiB

<script lang="ts">
/**
* Vídeo de YouTube con carga diferida.
*
* Hasta que alguien pulsa, aquí no se carga NADA de YouTube: se ve la
* portada del propio tema con un botón encima. Solo al pulsar se inserta el
* reproductor incrustado.
*
* Es deliberado por tres motivos: un `<iframe>` de YouTube pesa más que el
* resto de la página junta, deja cookies de terceros antes de que nadie haya
* pedido ver nada —lo que en la UE exige consentimiento— y la miniatura
* oficial se sirve desde los servidores de Google, así que usar la portada
* propia evita también esa petición.
*
* Se usa `youtube-nocookie.com`, que es el mismo reproductor sin las cookies
* de seguimiento salvo que se llegue a reproducir.
*/
import Icono from './Icono.svelte';
import { reproductor } from '$lib/player/player.svelte';
interface Props {
/** Id de YouTube, once caracteres. */
youtube: string;
titulo: string;
/** Imagen propia que hace de portada mientras no se carga el vídeo. */
poster: string;
}
let { youtube, titulo, poster }: Props = $props();
let cargado = $state(false);
function abrir() {
// Dos cosas sonando a la vez, no: manda lo que se acaba de pedir.
reproductor.pausar();
cargado = true;
}
</script>
<div class="marco">
{#if cargado}
<iframe
src="https://www.youtube-nocookie.com/embed/{youtube}?autoplay=1&rel=0"
title={titulo}
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen
></iframe>
{:else}
<button type="button" class="portada" onclick={abrir}>
<img src={poster} alt="" />
<span class="velo"></span>
<span class="play"><Icono nombre="play" tamano={28} /></span>
<span class="etiqueta">
<span class="titulo">{titulo}</span>
<span class="aviso">Ver en YouTube</span>
</span>
</button>
{/if}
</div>
<style>
.marco {
position: relative;
aspect-ratio: 16 / 9;
overflow: hidden;
border: 1px solid var(--c-border);
border-radius: var(--radius-tarjeta);
background: var(--c-bg-sunken);
}
.marco iframe {
width: 100%;
height: 100%;
border: 0;
display: block;
}
.portada {
position: relative;
display: block;
width: 100%;
height: 100%;
padding: 0;
border: none;
background: none;
cursor: pointer;
text-align: left;
}
.portada img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.4s ease;
}
.portada:hover img,
.portada:focus-visible img {
transform: scale(1.03);
}
/* El velo mantiene legible el texto sobre cualquier portada. */
.velo {
position: absolute;
inset: 0;
background: linear-gradient(to top, rgb(0 0 0 / 0.6), rgb(0 0 0 / 0.05) 55%);
}
.play {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}
.portada:hover .play,
.portada:focus-visible .play {
transform: scale(1.12);
}
.etiqueta {
position: absolute;
left: var(--sp-4);
right: var(--sp-4);
bottom: var(--sp-3);
display: flex;
flex-direction: column;
color: #fff;
}
.titulo {
font-weight: 600;
}
.aviso {
font-size: var(--fs-xs);
opacity: 0.85;
}
@media (prefers-reduced-motion: reduce) {
.portada img,
.play {
transition: none;
}
.portada:hover img,
.portada:focus-visible img,
.portada:hover .play,
.portada:focus-visible .play {
transform: none;
}
}
</style>

Powered by TurnKey Linux.