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:
WithoutPants
2022-04-04 06:27:18 +10:00
committed by GitHub
parent 6ebf3ddc9e
commit 92320b3418
5 changed files with 156 additions and 140 deletions

View File

@@ -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>
)}