91e75e620b
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Has been cancelled
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Has been cancelled
CD: Docs MCP Server / build (linux/amd64) (push) Has been cancelled
CD: Docs MCP Server / build (linux/arm64) (push) Has been cancelled
CD: Docs MCP Server / merge (push) Has been cancelled
CI: cua-driver distro-compat matrix / Resolve release version (push) Has been cancelled
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Has been cancelled
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Has been cancelled
CI: cua-driver distro-compat matrix / Distro compat summary (push) Has been cancelled
CI: Rust Linux unit / Rust Linux unit and compile (push) Has been cancelled
CI: Rust Windows unit / Rust Windows unit and compile (push) Has been cancelled
CI: Nix Linux Rust source / Nix / compositor build (push) Has been cancelled
CI: Nix Linux Rust source / Nix / driver package (push) Has been cancelled
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Has been cancelled
318 lines
9.6 KiB
HTML
318 lines
9.6 KiB
HTML
<main
|
|
class="flex flex-col h-full w-full p-6 overflow-auto"
|
|
role="main"
|
|
aria-label="Video player interface"
|
|
>
|
|
<div class="max-w-2xl mx-auto w-full">
|
|
<h1 class="text-xl font-semibold text-gray-900 mb-4">Video Player</h1>
|
|
|
|
<!-- Video Player -->
|
|
<div class="bg-black rounded-lg overflow-hidden shadow-lg">
|
|
<!-- Mock Video Display -->
|
|
<div
|
|
class="relative bg-gradient-to-br from-gray-800 to-gray-900 aspect-video flex items-center justify-center"
|
|
>
|
|
<div id="video-display" class="text-center">
|
|
<iconify-icon
|
|
id="play-icon"
|
|
icon="mdi:play"
|
|
class="text-white hidden"
|
|
style="font-size: 4rem"
|
|
></iconify-icon>
|
|
<iconify-icon
|
|
id="pause-icon"
|
|
icon="mdi:pause"
|
|
class="text-white"
|
|
style="font-size: 4rem"
|
|
></iconify-icon>
|
|
</div>
|
|
<div
|
|
class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-3"
|
|
>
|
|
<div class="text-white text-sm">Sample Video</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Controls -->
|
|
<div class="bg-gray-900 p-3">
|
|
<!-- Progress/Seek Bar -->
|
|
<div class="mb-3">
|
|
<input
|
|
type="range"
|
|
id="seek-bar"
|
|
min="0"
|
|
max="225"
|
|
value="0"
|
|
class="w-full h-1 bg-gray-700 rounded-lg appearance-none cursor-pointer seek-slider"
|
|
aria-label="Video progress"
|
|
aria-valuemin="0"
|
|
aria-valuemax="225"
|
|
aria-valuenow="0"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Control Buttons -->
|
|
<div class="flex items-center gap-3">
|
|
<!-- Play/Pause Button -->
|
|
<button
|
|
id="play-pause-btn"
|
|
class="p-2 hover:bg-gray-800 rounded transition-colors"
|
|
aria-label="Play or pause video"
|
|
>
|
|
<iconify-icon
|
|
id="play-pause-icon"
|
|
icon="mdi:pause"
|
|
class="text-white"
|
|
style="font-size: 1.5rem"
|
|
></iconify-icon>
|
|
</button>
|
|
|
|
<!-- Volume Controls -->
|
|
<div class="relative volume-control-container">
|
|
<button
|
|
id="volume-btn"
|
|
class="p-2 hover:bg-gray-800 rounded transition-colors"
|
|
aria-label="Volume control"
|
|
>
|
|
<iconify-icon
|
|
id="volume-icon"
|
|
icon="mdi:volume-high"
|
|
class="text-white"
|
|
style="font-size: 1.25rem"
|
|
></iconify-icon>
|
|
</button>
|
|
|
|
<!-- Collapsible Volume Slider (hidden by default) -->
|
|
<div
|
|
id="volume-slider-container"
|
|
class="hidden absolute bottom-full left-0 mb-2 bg-gray-800 rounded-lg p-3 shadow-lg"
|
|
>
|
|
<div class="flex flex-col items-center gap-2" style="height: 100px">
|
|
<input
|
|
type="range"
|
|
id="volume-slider"
|
|
min="0"
|
|
max="100"
|
|
value="50"
|
|
orient="vertical"
|
|
class="h-full volume-slider-vertical"
|
|
aria-label="Volume level"
|
|
aria-valuemin="0"
|
|
aria-valuemax="100"
|
|
aria-valuenow="50"
|
|
/>
|
|
<span id="volume-display" class="text-white text-xs">50%</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Time Display -->
|
|
<div class="text-white text-sm ml-auto">
|
|
<span id="current-time">0:00</span> / <span id="duration">3:45</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 p-3 bg-blue-50 border border-blue-200 rounded">
|
|
<p class="text-sm text-blue-800">
|
|
<iconify-icon icon="mdi:information" class="text-blue-600"></iconify-icon>
|
|
Use the video player controls
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
/* Seek bar slider styling */
|
|
.seek-slider::-webkit-slider-thumb {
|
|
appearance: none;
|
|
width: 14px;
|
|
height: 14px;
|
|
background: white;
|
|
cursor: pointer;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.seek-slider::-moz-range-thumb {
|
|
width: 14px;
|
|
height: 14px;
|
|
background: white;
|
|
cursor: pointer;
|
|
border-radius: 50%;
|
|
border: none;
|
|
}
|
|
|
|
/* Vertical volume slider styling */
|
|
.volume-slider-vertical {
|
|
writing-mode: bt-lr;
|
|
-webkit-appearance: slider-vertical;
|
|
width: 8px;
|
|
background: #4b5563;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.volume-slider-vertical::-webkit-slider-thumb {
|
|
appearance: none;
|
|
width: 16px;
|
|
height: 16px;
|
|
background: white;
|
|
cursor: pointer;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.volume-slider-vertical::-moz-range-thumb {
|
|
width: 16px;
|
|
height: 16px;
|
|
background: white;
|
|
cursor: pointer;
|
|
border-radius: 50%;
|
|
border: none;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
// Initialize player state
|
|
const initialState = '{{INITIAL_STATE}}';
|
|
let isPlaying = initialState === 'playing';
|
|
let volume = 50;
|
|
let isMuted = false;
|
|
let currentTime = 0;
|
|
const totalDuration = 225; // 3:45 in seconds
|
|
|
|
// Store state globally for evaluation
|
|
window.__playerState = {
|
|
is_playing: isPlaying,
|
|
volume: volume,
|
|
is_muted: isMuted,
|
|
current_time: currentTime,
|
|
};
|
|
|
|
// Update UI based on state
|
|
function updateUI() {
|
|
const playPauseIcon = document.getElementById('play-pause-icon');
|
|
const playIcon = document.getElementById('play-icon');
|
|
const pauseIcon = document.getElementById('pause-icon');
|
|
const volumeIcon = document.getElementById('volume-icon');
|
|
const volumeDisplay = document.getElementById('volume-display');
|
|
const volumeSlider = document.getElementById('volume-slider');
|
|
const seekBar = document.getElementById('seek-bar');
|
|
|
|
// Update play/pause
|
|
if (isPlaying) {
|
|
playPauseIcon.setAttribute('icon', 'mdi:pause');
|
|
playIcon.classList.add('hidden');
|
|
pauseIcon.classList.remove('hidden');
|
|
} else {
|
|
playPauseIcon.setAttribute('icon', 'mdi:play');
|
|
playIcon.classList.remove('hidden');
|
|
pauseIcon.classList.add('hidden');
|
|
}
|
|
|
|
// Update volume
|
|
if (isMuted) {
|
|
volumeIcon.setAttribute('icon', 'mdi:volume-off');
|
|
volumeDisplay.textContent = '0%';
|
|
} else {
|
|
if (volume === 0) {
|
|
volumeIcon.setAttribute('icon', 'mdi:volume-off');
|
|
} else if (volume < 50) {
|
|
volumeIcon.setAttribute('icon', 'mdi:volume-low');
|
|
} else {
|
|
volumeIcon.setAttribute('icon', 'mdi:volume-high');
|
|
}
|
|
volumeDisplay.textContent = volume + '%';
|
|
}
|
|
|
|
volumeSlider.value = volume;
|
|
volumeSlider.setAttribute('aria-valuenow', volume);
|
|
|
|
// Update seek bar
|
|
seekBar.value = currentTime;
|
|
seekBar.setAttribute('aria-valuenow', currentTime);
|
|
|
|
// Update global state
|
|
window.__playerState = {
|
|
is_playing: isPlaying,
|
|
volume: volume,
|
|
is_muted: isMuted,
|
|
current_time: currentTime,
|
|
};
|
|
}
|
|
|
|
// Play/Pause button
|
|
document.getElementById('play-pause-btn').addEventListener('click', function () {
|
|
isPlaying = !isPlaying;
|
|
updateUI();
|
|
});
|
|
|
|
// Volume button and slider controls
|
|
const volumeBtn = document.getElementById('volume-btn');
|
|
const volumeSliderContainer = document.getElementById('volume-slider-container');
|
|
const volumeControlContainer = document.querySelector('.volume-control-container');
|
|
let volumeSliderVisible = false;
|
|
|
|
// Click volume button to toggle mute
|
|
volumeBtn.addEventListener('click', function (e) {
|
|
e.stopPropagation();
|
|
isMuted = !isMuted;
|
|
updateUI();
|
|
});
|
|
|
|
// Show volume slider on hover
|
|
volumeControlContainer.addEventListener('mouseenter', function () {
|
|
volumeSliderContainer.classList.remove('hidden');
|
|
volumeSliderVisible = true;
|
|
});
|
|
|
|
// Keep slider visible when interacting with it
|
|
volumeSliderContainer.addEventListener('mouseenter', function () {
|
|
volumeSliderVisible = true;
|
|
});
|
|
|
|
// Hide when mouse leaves the entire volume control area
|
|
volumeControlContainer.addEventListener('mouseleave', function (e) {
|
|
// Only hide if we're not over the slider container
|
|
if (!volumeSliderContainer.contains(e.relatedTarget)) {
|
|
volumeSliderContainer.classList.add('hidden');
|
|
volumeSliderVisible = false;
|
|
}
|
|
});
|
|
|
|
// Volume slider
|
|
const volumeSlider = document.getElementById('volume-slider');
|
|
volumeSlider.addEventListener('input', function () {
|
|
volume = parseInt(this.value);
|
|
if (isMuted && volume > 0) {
|
|
isMuted = false;
|
|
}
|
|
updateUI();
|
|
});
|
|
|
|
// Seek bar
|
|
const seekBar = document.getElementById('seek-bar');
|
|
seekBar.addEventListener('input', function () {
|
|
currentTime = parseInt(this.value);
|
|
const minutes = Math.floor(currentTime / 60);
|
|
const seconds = currentTime % 60;
|
|
document.getElementById('current-time').textContent =
|
|
minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
|
|
updateUI();
|
|
});
|
|
|
|
// Simulate video time progression when playing
|
|
setInterval(() => {
|
|
if (isPlaying && currentTime < totalDuration) {
|
|
currentTime += 1;
|
|
const minutes = Math.floor(currentTime / 60);
|
|
const seconds = currentTime % 60;
|
|
document.getElementById('current-time').textContent =
|
|
minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
|
|
updateUI();
|
|
}
|
|
}, 1000);
|
|
|
|
// Initialize UI
|
|
updateUI();
|
|
</script>
|
|
</main>
|