mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 12:54:38 +03:00
Fix lightbox issues (#2457)
* Don't convert localforage to json * Show correct delay value * Fix lightbox delay * Fix delay input losing focus on change * Fix delay input inconsistencies * Fix clicking link preventing scroll bars appearing * Fix slideshow stopping when paging
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
##### 💥 Note: Image Slideshow Delay (in Interface Settings) is now in seconds rather than milliseconds and has not been converted. Please adjust your settings as needed.
|
||||
|
||||
### ✨ New Features
|
||||
* Add python location in System Settings for script scrapers and plugins. ([#2409](https://github.com/stashapp/stash/pull/2409))
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ interface IImageListImages {
|
||||
onChangePage: (page: number) => void;
|
||||
pageCount: number;
|
||||
onSelectChange: (id: string, selected: boolean, shiftKey: boolean) => void;
|
||||
slideshowRunning: boolean;
|
||||
setSlideshowRunning: (running: boolean) => void;
|
||||
}
|
||||
|
||||
const ImageListImages: React.FC<IImageListImages> = ({
|
||||
@@ -74,8 +76,9 @@ const ImageListImages: React.FC<IImageListImages> = ({
|
||||
onChangePage,
|
||||
pageCount,
|
||||
onSelectChange,
|
||||
slideshowRunning,
|
||||
setSlideshowRunning,
|
||||
}) => {
|
||||
const [slideshowRunning, setSlideshowRunning] = useState<boolean>(false);
|
||||
const handleLightBoxPage = useCallback(
|
||||
(direction: number) => {
|
||||
if (direction === -1) {
|
||||
@@ -125,7 +128,7 @@ const ImageListImages: React.FC<IImageListImages> = ({
|
||||
setSlideshowRunning(true);
|
||||
showLightbox(index, true);
|
||||
},
|
||||
[showLightbox]
|
||||
[showLightbox, setSlideshowRunning]
|
||||
);
|
||||
|
||||
function onPreview(index: number, ev: MouseEvent) {
|
||||
@@ -197,6 +200,7 @@ export const ImageList: React.FC<IImageList> = ({
|
||||
const history = useHistory();
|
||||
const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);
|
||||
const [isExportAll, setIsExportAll] = useState(false);
|
||||
const [slideshowRunning, setSlideshowRunning] = useState<boolean>(false);
|
||||
|
||||
const otherOperations = (extraOperations ?? []).concat([
|
||||
{
|
||||
@@ -336,6 +340,8 @@ export const ImageList: React.FC<IImageList> = ({
|
||||
onSelectChange={selectChange}
|
||||
pageCount={pageCount}
|
||||
selectedIds={selectedIds}
|
||||
slideshowRunning={slideshowRunning}
|
||||
setSlideshowRunning={setSlideshowRunning}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -147,10 +147,16 @@ export const LightboxComponent: React.FC<IProps> = ({
|
||||
setLightboxSettings({ scrollMode: v });
|
||||
}
|
||||
|
||||
const configuredDelay = config?.interface.imageLightbox.slideshowDelay
|
||||
? config.interface.imageLightbox.slideshowDelay * SECONDS_TO_MS
|
||||
: undefined;
|
||||
|
||||
const savedDelay = lightboxSettings?.slideshowDelay
|
||||
? lightboxSettings.slideshowDelay * SECONDS_TO_MS
|
||||
: undefined;
|
||||
|
||||
const slideshowDelay =
|
||||
lightboxSettings?.slideshowDelay ??
|
||||
config?.interface.imageLightbox.slideshowDelay ??
|
||||
DEFAULT_SLIDESHOW_DELAY;
|
||||
savedDelay ?? configuredDelay ?? DEFAULT_SLIDESHOW_DELAY;
|
||||
|
||||
function setSlideshowDelay(v: number) {
|
||||
setLightboxSettings({ slideshowDelay: v });
|
||||
@@ -175,7 +181,7 @@ export const LightboxComponent: React.FC<IProps> = ({
|
||||
const [
|
||||
displayedSlideshowInterval,
|
||||
setDisplayedSlideshowInterval,
|
||||
] = useState<string>(slideshowDelay.toString());
|
||||
] = useState<string>((slideshowDelay / SECONDS_TO_MS).toString());
|
||||
|
||||
useEffect(() => {
|
||||
if (images !== oldImages.current && isSwitchingPage) {
|
||||
@@ -264,7 +270,7 @@ export const LightboxComponent: React.FC<IProps> = ({
|
||||
if (slideshowInterval) {
|
||||
setSlideshowInterval(null);
|
||||
} else {
|
||||
setSlideshowInterval(slideshowDelay * SECONDS_TO_MS);
|
||||
setSlideshowInterval(slideshowDelay);
|
||||
}
|
||||
}, [slideshowInterval, slideshowDelay]);
|
||||
|
||||
@@ -409,7 +415,7 @@ export const LightboxComponent: React.FC<IProps> = ({
|
||||
? numberValue
|
||||
: MIN_VALID_INTERVAL_SECONDS;
|
||||
|
||||
setSlideshowDelay(numberValue * SECONDS_TO_MS);
|
||||
setSlideshowDelay(numberValue);
|
||||
|
||||
if (slideshowInterval !== null) {
|
||||
setSlideshowInterval(numberValue * SECONDS_TO_MS);
|
||||
@@ -418,7 +424,11 @@ export const LightboxComponent: React.FC<IProps> = ({
|
||||
|
||||
const currentIndex = index === null ? initialIndex : index;
|
||||
|
||||
const OptionsForm: React.FC<{}> = () => (
|
||||
// #2451: making OptionsForm an inline component means it
|
||||
// get re-rendered each time. This makes the text
|
||||
// field lose focus on input. Use function instead.
|
||||
function renderOptionsForm() {
|
||||
return (
|
||||
<>
|
||||
{slideshowEnabled ? (
|
||||
<Form.Group controlId="delay" as={Row} className="form-container">
|
||||
@@ -455,13 +465,15 @@ export const LightboxComponent: React.FC<IProps> = ({
|
||||
value={displayMode}
|
||||
className="btn-secondary mx-1 mb-1"
|
||||
>
|
||||
{Array.from(imageLightboxDisplayModeIntlMap.entries()).map((v) => (
|
||||
{Array.from(imageLightboxDisplayModeIntlMap.entries()).map(
|
||||
(v) => (
|
||||
<option key={v[0]} value={v[0]}>
|
||||
{intl.formatMessage({
|
||||
id: v[1],
|
||||
})}
|
||||
</option>
|
||||
))}
|
||||
)
|
||||
)}
|
||||
</Form.Control>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
@@ -513,7 +525,8 @@ export const LightboxComponent: React.FC<IProps> = ({
|
||||
setScrollMode(e.target.value as GQL.ImageLightboxScrollMode)
|
||||
}
|
||||
value={
|
||||
lightboxSettings?.scrollMode ?? GQL.ImageLightboxScrollMode.Zoom
|
||||
lightboxSettings?.scrollMode ??
|
||||
GQL.ImageLightboxScrollMode.Zoom
|
||||
}
|
||||
className="btn-secondary mx-1 mb-1"
|
||||
>
|
||||
@@ -544,19 +557,7 @@ export const LightboxComponent: React.FC<IProps> = ({
|
||||
</Form.Group>
|
||||
</>
|
||||
);
|
||||
|
||||
const optionsPopover = (
|
||||
<>
|
||||
<Popover.Title>
|
||||
{intl.formatMessage({
|
||||
id: "dialogs.lightbox.options",
|
||||
})}
|
||||
</Popover.Title>
|
||||
<Popover.Content>
|
||||
<OptionsForm />
|
||||
</Popover.Content>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (!isVisible) {
|
||||
return <></>;
|
||||
@@ -650,13 +651,18 @@ export const LightboxComponent: React.FC<IProps> = ({
|
||||
{...props}
|
||||
style={{ ...props.style }}
|
||||
>
|
||||
{optionsPopover}
|
||||
<Popover.Title>
|
||||
{intl.formatMessage({
|
||||
id: "dialogs.lightbox.options",
|
||||
})}
|
||||
</Popover.Title>
|
||||
<Popover.Content>{renderOptionsForm()}</Popover.Content>
|
||||
</div>
|
||||
)}
|
||||
</Overlay>
|
||||
</div>
|
||||
<InputGroup className={CLASSNAME_OPTIONS_INLINE}>
|
||||
<OptionsForm />
|
||||
{renderOptionsForm()}
|
||||
</InputGroup>
|
||||
</div>
|
||||
{slideshowEnabled && (
|
||||
@@ -787,7 +793,7 @@ export const LightboxComponent: React.FC<IProps> = ({
|
||||
</div>
|
||||
<div>
|
||||
{currentImage?.title && (
|
||||
<Link to={`/images/${currentImage.id}`} onClick={() => hide()}>
|
||||
<Link to={`/images/${currentImage.id}`} onClick={() => close()}>
|
||||
{currentImage.title ?? ""}
|
||||
</Link>
|
||||
)}
|
||||
|
||||
@@ -40,9 +40,11 @@ export function useLocalForage<T>(
|
||||
useEffect(() => {
|
||||
async function runAsync() {
|
||||
try {
|
||||
const serialized = await localForage.getItem<string>(key);
|
||||
const parsed = JSON.parse(serialized ?? "null");
|
||||
if (!Object.is(parsed, null)) {
|
||||
let parsed = await localForage.getItem<T>(key);
|
||||
if (typeof parsed === "string") {
|
||||
parsed = JSON.parse(parsed ?? "null");
|
||||
}
|
||||
if (parsed !== null) {
|
||||
setData(parsed);
|
||||
Cache[key] = parsed;
|
||||
} else {
|
||||
@@ -72,7 +74,7 @@ export function useLocalForage<T>(
|
||||
...Cache[key],
|
||||
...data,
|
||||
};
|
||||
localForage.setItem(key, JSON.stringify(Cache[key]));
|
||||
localForage.setItem(key, Cache[key]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -524,7 +524,7 @@
|
||||
},
|
||||
"slideshow_delay": {
|
||||
"description": "Slideshow is available in galleries when in wall view mode",
|
||||
"heading": "Slideshow Delay"
|
||||
"heading": "Slideshow Delay (seconds)"
|
||||
},
|
||||
"title": "User Interface"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user