mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +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:
@@ -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,145 +424,140 @@ export const LightboxComponent: React.FC<IProps> = ({
|
||||
|
||||
const currentIndex = index === null ? initialIndex : index;
|
||||
|
||||
const OptionsForm: React.FC<{}> = () => (
|
||||
<>
|
||||
{slideshowEnabled ? (
|
||||
<Form.Group controlId="delay" as={Row} className="form-container">
|
||||
<Col xs={4}>
|
||||
<Form.Label className="col-form-label">
|
||||
<FormattedMessage id="dialogs.lightbox.delay" />
|
||||
</Form.Label>
|
||||
</Col>
|
||||
<Col xs={8}>
|
||||
<Form.Control
|
||||
type="number"
|
||||
className="text-input"
|
||||
min={1}
|
||||
value={displayedSlideshowInterval ?? 0}
|
||||
onChange={onDelayChange}
|
||||
size="sm"
|
||||
/>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
) : undefined}
|
||||
// #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">
|
||||
<Col xs={4}>
|
||||
<Form.Label className="col-form-label">
|
||||
<FormattedMessage id="dialogs.lightbox.delay" />
|
||||
</Form.Label>
|
||||
</Col>
|
||||
<Col xs={8}>
|
||||
<Form.Control
|
||||
type="number"
|
||||
className="text-input"
|
||||
min={1}
|
||||
value={displayedSlideshowInterval ?? 0}
|
||||
onChange={onDelayChange}
|
||||
size="sm"
|
||||
/>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
) : undefined}
|
||||
|
||||
<Form.Group controlId="displayMode" as={Row}>
|
||||
<Col xs={4}>
|
||||
<Form.Label className="col-form-label">
|
||||
<FormattedMessage id="dialogs.lightbox.display_mode.label" />
|
||||
</Form.Label>
|
||||
</Col>
|
||||
<Col xs={8}>
|
||||
<Form.Control
|
||||
as="select"
|
||||
onChange={(e) =>
|
||||
setDisplayMode(e.target.value as GQL.ImageLightboxDisplayMode)
|
||||
}
|
||||
value={displayMode}
|
||||
className="btn-secondary mx-1 mb-1"
|
||||
>
|
||||
{Array.from(imageLightboxDisplayModeIntlMap.entries()).map((v) => (
|
||||
<option key={v[0]} value={v[0]}>
|
||||
{intl.formatMessage({
|
||||
id: v[1],
|
||||
})}
|
||||
</option>
|
||||
))}
|
||||
</Form.Control>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<Form.Group controlId="scaleUp" as={Row} className="mb-1">
|
||||
<Col>
|
||||
<Form.Check
|
||||
type="checkbox"
|
||||
label={intl.formatMessage({
|
||||
id: "dialogs.lightbox.scale_up.label",
|
||||
})}
|
||||
checked={lightboxSettings?.scaleUp ?? false}
|
||||
disabled={displayMode === GQL.ImageLightboxDisplayMode.Original}
|
||||
onChange={(v) => setScaleUp(v.currentTarget.checked)}
|
||||
/>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
<Form.Text className="text-muted">
|
||||
{intl.formatMessage({
|
||||
id: "dialogs.lightbox.scale_up.description",
|
||||
})}
|
||||
</Form.Text>
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<Form.Group controlId="resetZoomOnNav" as={Row} className="mb-1">
|
||||
<Col>
|
||||
<Form.Check
|
||||
type="checkbox"
|
||||
label={intl.formatMessage({
|
||||
id: "dialogs.lightbox.reset_zoom_on_nav",
|
||||
})}
|
||||
checked={lightboxSettings?.resetZoomOnNav ?? false}
|
||||
onChange={(v) => setResetZoomOnNav(v.currentTarget.checked)}
|
||||
/>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
</Form.Group>
|
||||
<Form.Group controlId="scrollMode">
|
||||
<Form.Group as={Row} className="mb-1">
|
||||
<Form.Group controlId="displayMode" as={Row}>
|
||||
<Col xs={4}>
|
||||
<Form.Label className="col-form-label">
|
||||
<FormattedMessage id="dialogs.lightbox.scroll_mode.label" />
|
||||
<FormattedMessage id="dialogs.lightbox.display_mode.label" />
|
||||
</Form.Label>
|
||||
</Col>
|
||||
<Col xs={8}>
|
||||
<Form.Control
|
||||
as="select"
|
||||
onChange={(e) =>
|
||||
setScrollMode(e.target.value as GQL.ImageLightboxScrollMode)
|
||||
}
|
||||
value={
|
||||
lightboxSettings?.scrollMode ?? GQL.ImageLightboxScrollMode.Zoom
|
||||
setDisplayMode(e.target.value as GQL.ImageLightboxDisplayMode)
|
||||
}
|
||||
value={displayMode}
|
||||
className="btn-secondary mx-1 mb-1"
|
||||
>
|
||||
<option
|
||||
value={GQL.ImageLightboxScrollMode.Zoom}
|
||||
key={GQL.ImageLightboxScrollMode.Zoom}
|
||||
>
|
||||
{intl.formatMessage({
|
||||
id: "dialogs.lightbox.scroll_mode.zoom",
|
||||
})}
|
||||
</option>
|
||||
<option
|
||||
value={GQL.ImageLightboxScrollMode.PanY}
|
||||
key={GQL.ImageLightboxScrollMode.PanY}
|
||||
>
|
||||
{intl.formatMessage({
|
||||
id: "dialogs.lightbox.scroll_mode.pan_y",
|
||||
})}
|
||||
</option>
|
||||
{Array.from(imageLightboxDisplayModeIntlMap.entries()).map(
|
||||
(v) => (
|
||||
<option key={v[0]} value={v[0]}>
|
||||
{intl.formatMessage({
|
||||
id: v[1],
|
||||
})}
|
||||
</option>
|
||||
)
|
||||
)}
|
||||
</Form.Control>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
<Form.Text className="text-muted">
|
||||
{intl.formatMessage({
|
||||
id: "dialogs.lightbox.scroll_mode.description",
|
||||
})}
|
||||
</Form.Text>
|
||||
</Form.Group>
|
||||
</>
|
||||
);
|
||||
|
||||
const optionsPopover = (
|
||||
<>
|
||||
<Popover.Title>
|
||||
{intl.formatMessage({
|
||||
id: "dialogs.lightbox.options",
|
||||
})}
|
||||
</Popover.Title>
|
||||
<Popover.Content>
|
||||
<OptionsForm />
|
||||
</Popover.Content>
|
||||
</>
|
||||
);
|
||||
<Form.Group>
|
||||
<Form.Group controlId="scaleUp" as={Row} className="mb-1">
|
||||
<Col>
|
||||
<Form.Check
|
||||
type="checkbox"
|
||||
label={intl.formatMessage({
|
||||
id: "dialogs.lightbox.scale_up.label",
|
||||
})}
|
||||
checked={lightboxSettings?.scaleUp ?? false}
|
||||
disabled={displayMode === GQL.ImageLightboxDisplayMode.Original}
|
||||
onChange={(v) => setScaleUp(v.currentTarget.checked)}
|
||||
/>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
<Form.Text className="text-muted">
|
||||
{intl.formatMessage({
|
||||
id: "dialogs.lightbox.scale_up.description",
|
||||
})}
|
||||
</Form.Text>
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<Form.Group controlId="resetZoomOnNav" as={Row} className="mb-1">
|
||||
<Col>
|
||||
<Form.Check
|
||||
type="checkbox"
|
||||
label={intl.formatMessage({
|
||||
id: "dialogs.lightbox.reset_zoom_on_nav",
|
||||
})}
|
||||
checked={lightboxSettings?.resetZoomOnNav ?? false}
|
||||
onChange={(v) => setResetZoomOnNav(v.currentTarget.checked)}
|
||||
/>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
</Form.Group>
|
||||
<Form.Group controlId="scrollMode">
|
||||
<Form.Group as={Row} className="mb-1">
|
||||
<Col xs={4}>
|
||||
<Form.Label className="col-form-label">
|
||||
<FormattedMessage id="dialogs.lightbox.scroll_mode.label" />
|
||||
</Form.Label>
|
||||
</Col>
|
||||
<Col xs={8}>
|
||||
<Form.Control
|
||||
as="select"
|
||||
onChange={(e) =>
|
||||
setScrollMode(e.target.value as GQL.ImageLightboxScrollMode)
|
||||
}
|
||||
value={
|
||||
lightboxSettings?.scrollMode ??
|
||||
GQL.ImageLightboxScrollMode.Zoom
|
||||
}
|
||||
className="btn-secondary mx-1 mb-1"
|
||||
>
|
||||
<option
|
||||
value={GQL.ImageLightboxScrollMode.Zoom}
|
||||
key={GQL.ImageLightboxScrollMode.Zoom}
|
||||
>
|
||||
{intl.formatMessage({
|
||||
id: "dialogs.lightbox.scroll_mode.zoom",
|
||||
})}
|
||||
</option>
|
||||
<option
|
||||
value={GQL.ImageLightboxScrollMode.PanY}
|
||||
key={GQL.ImageLightboxScrollMode.PanY}
|
||||
>
|
||||
{intl.formatMessage({
|
||||
id: "dialogs.lightbox.scroll_mode.pan_y",
|
||||
})}
|
||||
</option>
|
||||
</Form.Control>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
<Form.Text className="text-muted">
|
||||
{intl.formatMessage({
|
||||
id: "dialogs.lightbox.scroll_mode.description",
|
||||
})}
|
||||
</Form.Text>
|
||||
</Form.Group>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
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>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user