Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@
</head>
<body>
<div id="screensaver-container" class="screensaver hidden">
<img id="screensaver-image1" alt="Screensaver Image" style="opacity: 0;">
<img id="screensaver-image2" alt="Screensaver Image" style="opacity: 0;">
<div id="screensaver-thumbnails" class="screensaver-thumbnails"></div>
<div class="screensaver-controls">
<img id="screensaver-image1" alt="Screensaver Image" style="opacity: 0;">
<img id="screensaver-image2" alt="Screensaver Image" style="opacity: 0;">
<div class="screensaver-thumbnail-carousel">
<button id="screensaver-thumb-left" class="thumb-nav" aria-label="Previous image">&#9664;</button>
<div id="screensaver-thumbnails" class="screensaver-thumbnails"></div>
<button id="screensaver-thumb-right" class="thumb-nav" aria-label="Next image">&#9654;</button>
</div>
<div class="screensaver-controls">
<div class="screensaver-settings">
<label>Prompt:
<textarea id="screensaver-prompt" rows="3"></textarea>
Expand Down
80 changes: 53 additions & 27 deletions screensaver.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ document.addEventListener("DOMContentLoaded", () => {
const stopButton = document.getElementById("screensaver-exit");
const playPauseButton = document.getElementById("screensaver-playpause");
const saveButton = document.getElementById("screensaver-save");
const copyButton = document.getElementById("screensaver-copy");
const hideButton = document.getElementById("screensaver-hide");
const screensaverImage1 = document.getElementById("screensaver-image1");
const screensaverImage2 = document.getElementById("screensaver-image2");
const copyButton = document.getElementById("screensaver-copy");
const hideButton = document.getElementById("screensaver-hide");
const thumbnailCarousel = document.querySelector('.screensaver-thumbnail-carousel');
const thumbnailContainer = document.getElementById('screensaver-thumbnails');
const thumbLeft = document.getElementById('screensaver-thumb-left');
const thumbRight = document.getElementById('screensaver-thumb-right');
const screensaverImage1 = document.getElementById("screensaver-image1");
const screensaverImage2 = document.getElementById("screensaver-image2");
const promptInput = document.getElementById("screensaver-prompt");
const timerInput = document.getElementById("screensaver-timer");
const aspectSelect = document.getElementById("screensaver-aspect");
Expand Down Expand Up @@ -299,7 +303,7 @@ document.addEventListener("DOMContentLoaded", () => {
console.log("Current promptHistory length:", promptHistory.length, "Prompts:", promptHistory);
}

function updateThumbnailHistory() {
function updateThumbnailHistory(scrollToEnd = true) {
const thumbnailContainer = document.getElementById('screensaver-thumbnails');
if (!thumbnailContainer) {
console.error("Thumbnail container not found in DOM.");
Expand Down Expand Up @@ -333,8 +337,13 @@ document.addEventListener("DOMContentLoaded", () => {
console.log(`Added thumbnail ${index + 1}/${imageHistory.length} to DOM:`, thumb.src);
});

// keep the view scrolled to the latest thumbnail
thumbnailContainer.scrollTo({ left: thumbnailContainer.scrollWidth, behavior: 'smooth' });
if (scrollToEnd) {
// keep the view scrolled to the latest thumbnail
thumbnailContainer.scrollTo({ left: thumbnailContainer.scrollWidth, behavior: 'smooth' });
} else {
const selected = thumbnailContainer.querySelector('img.thumbnail.selected');
if (selected) selected.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' });
}
console.log("Updated thumbnail gallery with", imageHistory.length, "images. DOM count:", thumbnailContainer.children.length);

const offsetWidth = thumbnailContainer.offsetWidth;
Expand All @@ -351,23 +360,23 @@ document.addEventListener("DOMContentLoaded", () => {
const nextImgElement = document.getElementById(`screensaver-${nextImage}`);
currentImgElement.style.opacity = '0';
nextImgElement.onload = () => {
nextImgElement.style.opacity = '1';
currentImage = nextImage;
updateThumbnailHistory();
nextImgElement.style.opacity = '1';
currentImage = nextImage;
updateThumbnailHistory(false);
};
nextImgElement.onerror = () => {
nextImgElement.src = "https://via.placeholder.com/512?text=Image+Failed";
nextImgElement.style.opacity = '1';
currentImage = nextImage;
updateThumbnailHistory();
nextImgElement.src = "https://via.placeholder.com/512?text=Image+Failed";
nextImgElement.style.opacity = '1';
currentImage = nextImage;
updateThumbnailHistory(false);
};
nextImgElement.src = imageUrl;
nextImgElement.alt = "Screensaver Image";
if (nextImgElement.complete && nextImgElement.naturalWidth !== 0) {
nextImgElement.style.opacity = '1';
currentImgElement.style.opacity = '0';
currentImage = nextImage;
updateThumbnailHistory();
updateThumbnailHistory(false);
}
// restart the timer so new generations resume after viewing a historical image
setOrResetImageInterval();
Expand Down Expand Up @@ -496,17 +505,17 @@ document.addEventListener("DOMContentLoaded", () => {

function toggleControls() {
controlsHidden = !controlsHidden;
const controls = document.querySelector('.screensaver-controls');
const thumbnails = document.querySelector('.screensaver-thumbnails');
if (controlsHidden) {
controls.classList.add('hidden-panel');
thumbnails.classList.add('hidden-panel');
hideButton.innerHTML = "🙉";
} else {
controls.classList.remove('hidden-panel');
thumbnails.classList.remove('hidden-panel');
hideButton.innerHTML = "🙈";
}
const controls = document.querySelector('.screensaver-controls');
const thumbnails = thumbnailCarousel;
if (controlsHidden) {
controls.classList.add('hidden-panel');
thumbnails.classList.add('hidden-panel');
hideButton.innerHTML = "🙉";
} else {
controls.classList.remove('hidden-panel');
thumbnails.classList.remove('hidden-panel');
hideButton.innerHTML = "🙈";
}
window.showToast(controlsHidden ? "Controls hidden" : "Controls visible");
}

Expand Down Expand Up @@ -689,12 +698,29 @@ document.addEventListener("DOMContentLoaded", () => {
else window.showToast("Start the screensaver first!");
});

if (thumbLeft && thumbRight && thumbnailContainer) {
thumbLeft.addEventListener('click', (e) => {
e.stopPropagation();
thumbnailContainer.scrollBy({ left: -thumbnailContainer.clientWidth / 2, behavior: 'smooth' });
});
thumbRight.addEventListener('click', (e) => {
e.stopPropagation();
thumbnailContainer.scrollBy({ left: thumbnailContainer.clientWidth / 2, behavior: 'smooth' });
});
thumbnailContainer.addEventListener('wheel', (e) => {
if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) {
e.preventDefault();
thumbnailContainer.scrollBy({ left: e.deltaY, behavior: 'smooth' });
}
}, { passive: false });
}

document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && screensaverActive && controlsHidden) {
e.stopPropagation();
e.preventDefault();
const controls = document.querySelector('.screensaver-controls');
const thumbnails = document.querySelector('.screensaver-thumbnails');
const thumbnails = thumbnailCarousel;
controls.classList.add('hidden-panel');
thumbnails.classList.add('hidden-panel');
}
Expand Down
139 changes: 81 additions & 58 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -790,44 +790,47 @@ body {
transition: opacity var(--transition-duration, 1s) ease;
}

.screensaver-thumbnails {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
gap: 12px;
overflow-x: auto;
width: 100%;
height: 120px;
padding: 10px;
background: rgba(0, 0, 0, 0.7);
border-radius: 0;
z-index: 2;
transition: opacity 0.3s ease;
scrollbar-width: thin;
scrollbar-color: #707070 #333333;
white-space: nowrap;
direction: ltr;
scroll-behavior: smooth;
}

.screensaver-thumbnails::-webkit-scrollbar {
height: 8px;
}

.screensaver-thumbnails::-webkit-scrollbar-track {
background: #333333;
border-radius: 4px;
}

.screensaver-thumbnails::-webkit-scrollbar-thumb {
background: #707070;
border-radius: 4px;
}

.screensaver-thumbnail-carousel {
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
width: 100%;
max-width: 1200px;
z-index: 2;
gap: 8px;
padding: 10px;
background: rgba(0, 0, 0, 0.7);
scrollbar-width: thin;
}

.screensaver-thumbnails {
flex: 1;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
gap: 12px;
overflow-x: auto;
white-space: nowrap;
scroll-behavior: smooth;
}

.screensaver-thumbnails::-webkit-scrollbar {
height: 8px;
}

.screensaver-thumbnails::-webkit-scrollbar-track {
background: #333333;
border-radius: 4px;
}

.screensaver-thumbnails::-webkit-scrollbar-thumb {
background: #707070;
border-radius: 4px;
}

.screensaver-thumbnails img.thumbnail {
width: 160px;
height: 90px;
Expand All @@ -840,16 +843,36 @@ body {
display: inline-block;
opacity: 1;
position: static;
scroll-snap-align: center;
}

.screensaver-thumbnails img.thumbnail:hover {
border: 3px solid #00ffcc;
transform: scale(1.05);
}

.screensaver-thumbnails img.thumbnail.selected {
border: 3px solid #ffcc00;
}

.thumb-nav {
background: rgba(0, 0, 0, 0.6);
color: #fff;
border: none;
cursor: pointer;
padding: 0 12px;
height: 90px;
border-radius: 8px;
font-size: 1.4rem;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s;
}

.thumb-nav:hover {
background: rgba(0, 0, 0, 0.8);
}

.screensaver-thumbnails img.thumbnail:hover {
border: 3px solid #00ffcc;
transform: scale(1.05);
}

.screensaver-thumbnails img.thumbnail.selected {
border: 3px solid #ffcc00;
}

.screensaver-controls {
position: fixed;
Expand All @@ -871,17 +894,17 @@ body {
transform: translateX(-50%) scale(1.02);
}

.screensaver:not(:hover) .screensaver-controls,
.screensaver:not(:hover) .screensaver-thumbnails {
opacity: 0.5;
}
.screensaver-controls.hidden-panel,
.screensaver-thumbnails.hidden-panel {
opacity: 0;
pointer-events: none;
transform: translateX(-50%) translateY(20px);
}
.screensaver:not(:hover) .screensaver-controls,
.screensaver:not(:hover) .screensaver-thumbnail-carousel {
opacity: 0.5;
}

.screensaver-controls.hidden-panel,
.screensaver-thumbnail-carousel.hidden-panel {
opacity: 0;
pointer-events: none;
transform: translateX(-50%) translateY(20px);
}

.screensaver-settings {
display: grid;
Expand Down
39 changes: 33 additions & 6 deletions stylesScreensaver.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,27 @@
display: block;
}

.screensaver-thumbnails {
.screensaver-thumbnail-carousel {
position: fixed;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
width: 90%;
max-width: 1200px;
z-index: 2;
gap: 8px;
}

.screensaver-thumbnails {
flex: 1;
display: flex;
flex-direction: row;
gap: 10px;
overflow-x: auto;
width: 90%;
max-width: 1200px;
padding: 10px;
border-radius: 12px;
z-index: 2;
transition: opacity 0.3s ease;
scrollbar-width: thin;
white-space: nowrap;
Expand Down Expand Up @@ -64,6 +71,26 @@
display: inline-block;
opacity: 1;
position: static;
scroll-snap-align: center;
}

.thumb-nav {
background: rgba(0, 0, 0, 0.6);
color: #fff;
border: none;
cursor: pointer;
padding: 0 12px;
height: 80px;
border-radius: 8px;
font-size: 1.2rem;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s;
}

.thumb-nav:hover {
background: rgba(0, 0, 0, 0.8);
}

.screensaver-controls {
Expand All @@ -85,12 +112,12 @@
}

.screensaver:not(:hover) .screensaver-controls,
.screensaver:not(:hover) .screensaver-thumbnails {
.screensaver:not(:hover) .screensaver-thumbnail-carousel {
opacity: 0.5;
}

.screensaver-controls.hidden-panel,
.screensaver-thumbnails.hidden-panel {
.screensaver-thumbnail-carousel.hidden-panel {
opacity: 0;
pointer-events: none;
transform: translateX(-50%) translateY(20px);
Expand Down