Skip to content

Commit bf9fe43

Browse files
lsteinclaude
andauthored
feat(slideshow): gray out play button on last slide in sequential mode (#296)
When stopped on the final slide in sequential mode (album or search results), the play button now grays out and ignores clicks — there is nothing left to advance to. Shuffle mode (no "end") and wrap-navigation (always resolves to a real index) are unaffected, and the Pause button is never disabled. Reuses slideState.resolveOffset(+1) — the same end-of-list signal the auto-pause path from #293 relies on — and refreshes the button via the existing slideChanged listener so it updates on every navigation path. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8bda412 commit bf9fe43

3 files changed

Lines changed: 28 additions & 2 deletions

File tree

photomap/frontend/static/css/control-and-search-panels.css

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@
5656
}
5757

5858
#controlPanel button.back-nav-disabled,
59-
#controlPanel button.back-nav-disabled:hover {
59+
#controlPanel button.back-nav-disabled:hover,
60+
#controlPanel button.slideshow-disabled,
61+
#controlPanel button.slideshow-disabled:hover {
6062
opacity: 0.25;
6163
cursor: default;
6264
}

photomap/frontend/static/javascript/events.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,9 @@ export function showHidePanelText(hide) {
205205

206206
// Listen for slide changes to update UI
207207
window.addEventListener("slideChanged", () => {
208-
// nothing to do here yet, but could be used to update UI elements
208+
// Refresh the play/pause button so it grays out when we land on the last
209+
// slide in sequential mode (and re-activates when we navigate away).
210+
updateSlideshowButtonIcon();
209211
});
210212

211213
// Toggle grid/swiper views

photomap/frontend/static/javascript/slideshow.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { saveSettingsToLocalStorage, state } from "./state.js";
2+
import { slideState } from "./slide-state.js";
23
import { isUmapFullscreen, toggleUmapWindow } from "./umap.js";
34

45
// SVG icons used for the button/menu
@@ -15,6 +16,14 @@ export function slideShowRunning() {
1516
return !!state.single_swiper?.swiper?.autoplay?.running;
1617
}
1718

19+
// In sequential mode there is a genuine end of the list, so a stopped slideshow
20+
// resting on the final slide has nowhere to advance to. resolveOffset(+1)
21+
// reports null only at that end (wrap mode always resolves to a real index, and
22+
// random mode has no end), so it cleanly captures the "last slide" case.
23+
function atSequentialEnd() {
24+
return state.mode !== "random" && slideState.resolveOffset(+1).globalIndex === null;
25+
}
26+
1827
// public: update the icon displayed on the start/stop button according to state
1928
export function updateSlideshowButtonIcon() {
2029
const container = document.getElementById("slideshowIcon");
@@ -42,6 +51,13 @@ export function updateSlideshowButtonIcon() {
4251
btn.title = `Start Slideshow (${modeLabel})`;
4352
}
4453
}
54+
55+
// Gray out and disable Play when stopped on the final slide in sequential
56+
// mode — there is nothing left to play. Never disable the Pause button.
57+
if (btn) {
58+
const disabled = !isRunning && atSequentialEnd();
59+
btn.classList.toggle("slideshow-disabled", disabled);
60+
}
4561
}
4662

4763
// small fullscreen/play indicator (moved from events.js)
@@ -92,6 +108,12 @@ export async function toggleSlideshowWithIndicator(e) {
92108
e.stopPropagation();
93109
}
94110

111+
// Ignore clicks while parked on the last sequential slide (button is grayed
112+
// out): there is nothing to start.
113+
if (!slideShowRunning() && atSequentialEnd()) {
114+
return;
115+
}
116+
95117
if (slideShowRunning()) {
96118
// pause
97119
try {

0 commit comments

Comments
 (0)