mirror of
https://github.com/wahyd4/links.git
synced 2026-08-08 21:04:53 +10:00
Add ability to configure image slide interval
This commit is contained in:
Binary file not shown.
@@ -24,14 +24,35 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s ease-in-out;
|
||||
transition: all 0.5s ease-in-out;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: scale(1) rotate(0deg);
|
||||
filter: blur(0px);
|
||||
}
|
||||
.slide.active {
|
||||
opacity: 1;
|
||||
}
|
||||
/* Transition Effects */
|
||||
.slide.fade-out {
|
||||
opacity: 0;
|
||||
}
|
||||
.slide.slide-out {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
.slide.scale-out {
|
||||
transform: scale(0.8);
|
||||
opacity: 0;
|
||||
}
|
||||
.slide.rotate-out {
|
||||
transform: rotate(-15deg);
|
||||
opacity: 0;
|
||||
}
|
||||
.slide.blur-out {
|
||||
filter: blur(10px);
|
||||
opacity: 0;
|
||||
}
|
||||
.slide img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
@@ -78,6 +99,35 @@
|
||||
.control-button:hover {
|
||||
background: rgba(255,255,255,0.2);
|
||||
}
|
||||
.control-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
background: rgba(255,255,255,0.1);
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
.slider {
|
||||
-webkit-appearance: none;
|
||||
width: 100px;
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
background: rgba(255,255,255,0.2);
|
||||
outline: none;
|
||||
}
|
||||
.slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background: #3b82f6;
|
||||
cursor: pointer;
|
||||
}
|
||||
#intervalValue {
|
||||
color: white;
|
||||
min-width: 30px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.progress-circle {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
@@ -117,6 +167,51 @@
|
||||
max-width: 400px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.settings-panel {
|
||||
position: fixed;
|
||||
bottom: 5rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
display: none;
|
||||
width: 90%;
|
||||
max-width: 400px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.settings-content {
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.settings-group {
|
||||
margin: 1rem 0;
|
||||
padding: 0.75rem;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
.settings-group h4 {
|
||||
color: #fff;
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.settings-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
.settings-item .slider {
|
||||
flex: 1;
|
||||
}
|
||||
.settings-item span {
|
||||
color: white;
|
||||
min-width: 40px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.playlist-content {
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
@@ -176,6 +271,34 @@
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
}
|
||||
.transition-options {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.transition-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 0.375rem;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
.transition-option:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.transition-option input[type="radio"] {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0;
|
||||
}
|
||||
.transition-option label {
|
||||
color: white;
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.controls {
|
||||
@@ -269,6 +392,13 @@
|
||||
</svg>
|
||||
<span>{% trans "Playlist" %}</span>
|
||||
</button>
|
||||
<button class="control-button" onclick="toggleSettings()">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
|
||||
</svg>
|
||||
<span>{% trans "Settings" %}</span>
|
||||
</button>
|
||||
<button class="control-button" onclick="exitSlideshow()">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
@@ -278,6 +408,44 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-panel">
|
||||
<div class="settings-content">
|
||||
<h3>{% trans "Slideshow Settings" %}</h3>
|
||||
<div class="settings-group">
|
||||
<h4>{% trans "Transition Interval" %}</h4>
|
||||
<div class="settings-item">
|
||||
<input type="range" class="slider" id="intervalSlider" min="2000" step="1000" max="15000" value="5000" oninput="updateInterval(this.value)">
|
||||
<span id="intervalValue">5s</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-group">
|
||||
<h4>{% trans "Transition Effect" %}</h4>
|
||||
<div class="transition-options">
|
||||
<div class="transition-option">
|
||||
<input type="radio" id="effect-fade" name="transition-effect" value="fade" checked>
|
||||
<label for="effect-fade">Fade</label>
|
||||
</div>
|
||||
<div class="transition-option">
|
||||
<input type="radio" id="effect-slide" name="transition-effect" value="slide">
|
||||
<label for="effect-slide">Slide</label>
|
||||
</div>
|
||||
<div class="transition-option">
|
||||
<input type="radio" id="effect-scale" name="transition-effect" value="scale">
|
||||
<label for="effect-scale">Scale</label>
|
||||
</div>
|
||||
<div class="transition-option">
|
||||
<input type="radio" id="effect-rotate" name="transition-effect" value="rotate">
|
||||
<label for="effect-rotate">Rotate</label>
|
||||
</div>
|
||||
<div class="transition-option">
|
||||
<input type="radio" id="effect-blur" name="transition-effect" value="blur">
|
||||
<label for="effect-blur">Blur</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<audio id="backgroundMusic">
|
||||
<source src="" type="audio/mpeg">
|
||||
Your browser does not support the audio element.
|
||||
@@ -307,11 +475,12 @@ const totalSlides = slides.length;
|
||||
let slideInterval = null;
|
||||
let progressInterval = null;
|
||||
let isPlaying = true;
|
||||
const INTERVAL_TIME = 5000; // 5 seconds
|
||||
let INTERVAL_TIME = 5000; // 5 seconds, configurable through slider
|
||||
const CONTROLS_HIDE_DELAY = 6000; // 6 seconds
|
||||
let startTime = null;
|
||||
let animationFrame = null;
|
||||
let controlsTimeout = null;
|
||||
let currentEffect = 'fade';
|
||||
const backgroundMusic = document.getElementById('backgroundMusic');
|
||||
let isMusicPlaying = true;
|
||||
|
||||
@@ -485,23 +654,62 @@ function togglePlaylist() {
|
||||
const playlistPanel = document.querySelector('.music-playlist');
|
||||
if (playlistPanel.style.display === 'none' || playlistPanel.style.display === '') {
|
||||
playlistPanel.style.display = 'block';
|
||||
document.querySelector('.settings-panel').style.display = 'none';
|
||||
} else {
|
||||
playlistPanel.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSettings() {
|
||||
const settingsPanel = document.querySelector('.settings-panel');
|
||||
if (settingsPanel.style.display === 'none' || settingsPanel.style.display === '') {
|
||||
settingsPanel.style.display = 'block';
|
||||
document.querySelector('.music-playlist').style.display = 'none';
|
||||
} else {
|
||||
settingsPanel.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function selectSong(index) {
|
||||
loadSong(index);
|
||||
togglePlaylist();
|
||||
}
|
||||
|
||||
function showSlide(index) {
|
||||
slides.forEach(slide => slide.classList.remove('active'));
|
||||
const oldSlide = slides[currentSlide];
|
||||
currentSlide = (index + totalSlides) % totalSlides;
|
||||
slides[currentSlide].classList.add('active');
|
||||
const newSlide = slides[currentSlide];
|
||||
|
||||
// Remove any existing transition classes
|
||||
oldSlide.classList.remove('active', 'fade-out', 'slide-out', 'scale-out', 'rotate-out', 'blur-out');
|
||||
newSlide.classList.remove('fade-out', 'slide-out', 'scale-out', 'rotate-out', 'blur-out');
|
||||
|
||||
// Add the appropriate transition class
|
||||
oldSlide.classList.add(`${currentEffect}-out`);
|
||||
newSlide.classList.add('active');
|
||||
|
||||
resetProgress();
|
||||
}
|
||||
|
||||
function updateTransitionEffect(effect) {
|
||||
currentEffect = effect;
|
||||
}
|
||||
|
||||
// Add event listeners for transition effects
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
await fetchPlaylist();
|
||||
startSlideshow();
|
||||
// Initialize interval value display
|
||||
document.getElementById('intervalValue').textContent = `${INTERVAL_TIME/1000}s`;
|
||||
|
||||
// Add transition effect listeners
|
||||
document.querySelectorAll('input[name="transition-effect"]').forEach(radio => {
|
||||
radio.addEventListener('change', (e) => {
|
||||
updateTransitionEffect(e.target.value);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function nextSlide() {
|
||||
showSlide(currentSlide + 1);
|
||||
}
|
||||
@@ -583,6 +791,15 @@ function resetProgress() {
|
||||
}
|
||||
}
|
||||
|
||||
function updateInterval(value) {
|
||||
INTERVAL_TIME = parseInt(value);
|
||||
document.getElementById('intervalValue').textContent = `${value / 1000}s`;
|
||||
if (isPlaying) {
|
||||
stopSlideshow();
|
||||
startSlideshow();
|
||||
}
|
||||
}
|
||||
|
||||
// Keyboard controls
|
||||
document.addEventListener('keydown', (e) => {
|
||||
switch(e.key) {
|
||||
@@ -617,6 +834,8 @@ document.addEventListener('keydown', (e) => {
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
await fetchPlaylist();
|
||||
startSlideshow();
|
||||
// Initialize interval value display
|
||||
document.getElementById('intervalValue').textContent = `${INTERVAL_TIME/1000}s`;
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Vendored
+4
@@ -1811,6 +1811,10 @@ video {
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.outline {
|
||||
outline-style: solid;
|
||||
}
|
||||
|
||||
.blur {
|
||||
--tw-blur: blur(8px);
|
||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||
|
||||
Reference in New Issue
Block a user