new functions and fixes

This commit is contained in:
Mateusz Gruszczyński
2026-08-05 22:13:04 +02:00
parent 9fc32d0d31
commit e842b26978
34 changed files with 2505 additions and 115 deletions
+56
View File
@@ -0,0 +1,56 @@
.rustpad-media {
width: min(100%, 960px);
margin: 18px auto;
overflow: hidden;
border: 1px solid var(--border);
border-radius: 12px;
background: #000;
box-shadow: 0 12px 30px color-mix(in srgb, #000 22%, transparent);
}
.rustpad-media__player,
.rustpad-media__player iframe,
.rustpad-media__player video,
video.rustpad-media__player {
display: block;
width: 100%;
max-width: 100%;
}
.rustpad-media__player[data-player-kind="youtube"] {
position: relative;
aspect-ratio: 16 / 9;
}
.rustpad-media__player[data-player-kind="youtube"] iframe {
position: absolute;
inset: 0;
height: 100%;
border: 0;
}
video.rustpad-media__player,
.rustpad-media__player video {
max-height: min(72vh, 760px);
background: #000;
}
.rustpad-media__fallback {
margin: 0;
padding: 10px 12px;
border-top: 1px solid color-mix(in srgb, white 18%, transparent);
background: var(--surface-deep);
color: var(--muted);
font-size: .78rem;
}
.rustpad-media__fallback a {
color: var(--accent-soft);
}
@media (max-width: 600px) {
.rustpad-media {
margin-block: 14px;
border-radius: 9px;
}
}
+47
View File
@@ -0,0 +1,47 @@
/*
* RustPad media player helpers.
* Project-owned code: keeps native video playback and YouTube embeds responsive.
*/
const initialized = new WeakSet();
function createYouTubeFrame(node) {
const videoId = String(node.dataset.videoId || "").trim();
if (!/^[A-Za-z0-9_-]{6,20}$/.test(videoId)) return;
const iframe = document.createElement("iframe");
iframe.src = `https://www.youtube-nocookie.com/embed/${encodeURIComponent(videoId)}?rel=0&modestbranding=1&playsinline=1`;
iframe.title = node.dataset.playerTitle || "YouTube video";
iframe.loading = "lazy";
iframe.allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share";
iframe.referrerPolicy = "strict-origin-when-cross-origin";
iframe.allowFullscreen = true;
node.replaceChildren(iframe);
}
function initializeNativeVideo(video) {
video.controls = true;
video.playsInline = true;
video.preload = video.preload || "metadata";
const fallback = video.closest(".rustpad-media")?.querySelector(".rustpad-media__fallback");
if (!fallback) return;
const revealFallback = () => { fallback.hidden = false; };
video.addEventListener("error", revealFallback, { once: true });
video.querySelectorAll("source").forEach(source => source.addEventListener("error", revealFallback, { once: true }));
}
export function hydrateMediaPlayers(root = document) {
root.querySelectorAll("[data-rustpad-player]").forEach(node => {
if (initialized.has(node)) return;
initialized.add(node);
if (node.dataset.playerKind === "youtube") createYouTubeFrame(node);
else if (node instanceof HTMLVideoElement) initializeNativeVideo(node);
});
}
export function destroyMediaPlayers(root = document) {
root.querySelectorAll('[data-rustpad-player][data-player-kind="youtube"] iframe').forEach(frame => {
frame.src = "about:blank";
});
}