diff --git a/package.json b/package.json
index f118802c26..23a3cfe52e 100644
--- a/package.json
+++ b/package.json
@@ -64,6 +64,7 @@
"lemmy-js-client": "0.18.0",
"lodash": "^4.17.21",
"mdast-util-gfm-autolink-literal-lemmy": "^1.0.3",
+ "photoswipe": "^5.3.8",
"mdast-util-gfm-strikethrough": "^1.0.3",
"mdast-util-gfm-table": "^1.0.7",
"micromark": "^3.0.0",
@@ -77,7 +78,6 @@
"react-animate-height": "^3.1.1",
"react-dom": "^18.2.0",
"react-markdown": "^8.0.7",
- "react-photoswipe-gallery": "^2.2.7",
"react-redux": "^8.1.1",
"react-router": "^5.3.4",
"react-router-dom": "^5.3.4",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1a3c14ccb6..a7f9afa78d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -181,9 +181,6 @@ devDependencies:
react-markdown:
specifier: ^8.0.7
version: 8.0.7(@types/react@18.2.14)(react@18.2.0)
- react-photoswipe-gallery:
- specifier: ^2.2.7
- version: 2.2.7(photoswipe@5.3.7)(prop-types@15.8.1)(react@18.2.0)
react-redux:
specifier: ^8.1.1
version: 8.1.1(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1)
@@ -6242,18 +6239,6 @@ packages:
- supports-color
dev: true
- /react-photoswipe-gallery@2.2.7(photoswipe@5.3.7)(prop-types@15.8.1)(react@18.2.0):
- resolution: {integrity: sha512-AEYNoL4/IIRosIUonn4haaFQNn1ui4vdVgAY9LHd/imVamNCkqUcyWeT6317UILp/yJI2gohsd3lWmcJEbjCag==}
- peerDependencies:
- photoswipe: '>= 5.2.2'
- prop-types: '>= 15.7.0'
- react: '>= 16.8.0'
- dependencies:
- photoswipe: 5.3.7
- prop-types: 15.8.1
- react: 18.2.0
- dev: true
-
/react-redux@8.1.1(@types/react-dom@18.2.6)(@types/react@18.2.14)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1):
resolution: {integrity: sha512-5W0QaKtEhj+3bC0Nj0NkqkhIv8gLADH/2kYFMTHxCVqQILiWzLv6MaLuV5wJU3BQEdHKzTfcvPN0WMS6SC1oyA==}
peerDependencies:
diff --git a/src/App.tsx b/src/App.tsx
index 3a24afdea0..9028ba08bf 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -26,6 +26,7 @@ import Router from "./Router";
import BeforeInstallPromptProvider from "./BeforeInstallPromptProvider";
import { UpdateContextProvider } from "./pages/settings/update/UpdateContext";
import GlobalStyles from "./GlobalStyles";
+import GalleryProvider from "./features/gallery/GalleryProvider";
setupIonicReact({
rippleEffect: false,
@@ -44,7 +45,9 @@ export default function App() {
-
+
+
+
diff --git a/src/features/auth/Login.tsx b/src/features/auth/Login.tsx
index e5c911e2c7..af9f1cb1a8 100644
--- a/src/features/auth/Login.tsx
+++ b/src/features/auth/Login.tsx
@@ -25,7 +25,7 @@ import { getClient } from "../../services/lemmy";
import { IonInputCustomEvent } from "@ionic/core";
import TermsSheet from "../settings/terms/TermsSheet";
import { LEMMY_SERVERS } from "../../helpers/lemmy";
-import { preventPhotoswipeGalleryFocusTrap } from "../gallery/Gallery";
+import { preventPhotoswipeGalleryFocusTrap } from "../gallery/GalleryImg";
export const Spinner = styled(IonSpinner)`
width: 1.5rem;
diff --git a/src/features/comment/reply/CommentReply.tsx b/src/features/comment/reply/CommentReply.tsx
index 2e6e69772d..5e54f9ff0b 100644
--- a/src/features/comment/reply/CommentReply.tsx
+++ b/src/features/comment/reply/CommentReply.tsx
@@ -22,7 +22,7 @@ import { useAppSelector } from "../../../store";
import { Centered, Spinner } from "../../auth/Login";
import { handleSelector, jwtSelector } from "../../auth/authSlice";
import { css } from "@emotion/react";
-import { preventPhotoswipeGalleryFocusTrap } from "../../gallery/Gallery";
+import { preventPhotoswipeGalleryFocusTrap } from "../../gallery/GalleryImg";
export const Container = styled.div`
position: absolute;
diff --git a/src/features/feed/Feed.tsx b/src/features/feed/Feed.tsx
index 2ee622fcac..674e8f1fa6 100644
--- a/src/features/feed/Feed.tsx
+++ b/src/features/feed/Feed.tsx
@@ -173,7 +173,7 @@ export default function Feed({
fetchMore();
}}
components={{ Header: header, Footer: footer }}
- increaseViewportBy={800}
+ increaseViewportBy={5000}
/>
>
);
diff --git a/src/features/gallery/Gallery.tsx b/src/features/gallery/Gallery.tsx
deleted file mode 100644
index c9947e2d43..0000000000
--- a/src/features/gallery/Gallery.tsx
+++ /dev/null
@@ -1,124 +0,0 @@
-import React, {
- FocusEvent,
- KeyboardEvent,
- forwardRef,
- useImperativeHandle,
- useRef,
- useState,
-} from "react";
-import { Gallery as PhotoswipeGallery, Item } from "react-photoswipe-gallery";
-
-import "photoswipe/dist/photoswipe.css";
-import { createPortal } from "react-dom";
-import styled from "@emotion/styled";
-import PhotoSwipe, { PreparedPhotoSwipeOptions } from "photoswipe";
-import { getSafeArea, isAndroid } from "../../helpers/device";
-import { v4 as uuidv4 } from "uuid";
-
-const Container = styled.div`
- position: absolute;
- bottom: 0;
- right: 0;
- left: 0;
- padding: 1rem;
- padding-top: 4rem;
- padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0));
-
- color: white;
- background: linear-gradient(0deg, rgba(0, 0, 0, 1), transparent);
-`;
-interface ImgProps {
- src?: string;
- alt?: string;
- className?: string;
- onClick?: React.MouseEventHandler;
- footer?: React.ReactElement;
- animationType?: PreparedPhotoSwipeOptions["showHideAnimationType"];
-}
-
-export type GalleryHandle = {
- close: () => void;
-};
-
-/**
- * TODO: photoswipe traps focus, so onFocusCapture and onKeyDown is a hack to prevent it
- * from detecting that we're changing focus. It's not great.. but it's what we got
- * https://github.com/dimsemenov/PhotoSwipe/issues/1968
- */
-export const preventPhotoswipeGalleryFocusTrap = {
- onFocusCapture: (e: FocusEvent) => e.stopPropagation(),
- onKeyDown: (e: KeyboardEvent) => e.stopPropagation(),
-};
-
-export const Gallery = forwardRef(function Gallery(
- { src, alt, footer, className, onClick, animationType },
- ref
-) {
- const [dim, setDim] = useState<{ w: number; h: number } | undefined>();
- const [actionContainer, setActionContainer] = useState(
- null
- );
- const photoswipeRef = useRef();
-
- // Adding a ID to photoswipe creates hash URL, which allows back button
- // to close the dialog
- const [id] = useState(isAndroid() ? uuidv4() : undefined);
-
- useImperativeHandle(ref, () => ({
- close: () => {
- photoswipeRef.current?.destroy();
- },
- }));
-
- return (
- <>
- {actionContainer !== null &&
- footer &&
- createPortal({footer}, actionContainer)}
- getSafeArea(),
- }}
- onOpen={(instance) => {
- photoswipeRef.current = instance;
- }}
- uiElements={[
- {
- appendTo: "root",
- onInit: (el) => {
- setActionContainer(el);
- },
- },
- ]}
- >
- -
- {({ ref, open }) => (
- }
- alt={alt}
- onClick={(e) => {
- onClick?.(e);
- open(e);
- }}
- src={src}
- className={className}
- onLoad={(e) => {
- if (!(e.target instanceof HTMLImageElement)) return;
-
- setDim({ w: e.target.naturalWidth, h: e.target.naturalHeight });
- }}
- />
- )}
-
-
- >
- );
-});
diff --git a/src/features/gallery/GalleryImg.tsx b/src/features/gallery/GalleryImg.tsx
new file mode 100644
index 0000000000..bf7f2fcdf8
--- /dev/null
+++ b/src/features/gallery/GalleryImg.tsx
@@ -0,0 +1,69 @@
+import React, { FocusEvent, KeyboardEvent, useContext, useRef } from "react";
+import "photoswipe/dist/photoswipe.css";
+import { useAppDispatch } from "../../store";
+import { imageLoaded } from "./gallerySlice";
+import { PostView } from "lemmy-js-client";
+import { GalleryContext } from "./GalleryProvider";
+import { PreparedPhotoSwipeOptions } from "photoswipe";
+
+export interface GalleryImgProps {
+ src?: string;
+ alt?: string;
+ className?: string;
+ post?: PostView;
+ animationType?: PreparedPhotoSwipeOptions["showHideAnimationType"];
+}
+
+/**
+ * TODO: photoswipe traps focus, so onFocusCapture and onKeyDown is a hack to prevent it
+ * from detecting that we're changing focus. It's not great.. but it's what we got
+ * https://github.com/dimsemenov/PhotoSwipe/issues/1968
+ */
+export const preventPhotoswipeGalleryFocusTrap = {
+ onFocusCapture: (e: FocusEvent) => e.stopPropagation(),
+ onKeyDown: (e: KeyboardEvent) => e.stopPropagation(),
+};
+
+export function GalleryImg({
+ src,
+ alt,
+ className,
+ post,
+ animationType,
+}: GalleryImgProps) {
+ const dispatch = useAppDispatch();
+ const loaded = useRef(false);
+ const imgRef = useRef(null);
+ const { open } = useContext(GalleryContext);
+
+ return (
+ {
+ if (!loaded.current) return;
+
+ e.stopPropagation();
+
+ open(e.currentTarget, post, animationType);
+ }}
+ src={src}
+ className={className}
+ onLoad={(e) => {
+ if (!(e.target instanceof HTMLImageElement)) return;
+ if (!src) return;
+
+ loaded.current = true;
+
+ dispatch(
+ imageLoaded({
+ src,
+ width: e.target.naturalWidth,
+ height: e.target.naturalHeight,
+ })
+ );
+ }}
+ />
+ );
+}
diff --git a/src/features/gallery/GalleryPostActions.tsx b/src/features/gallery/GalleryPostActions.tsx
index 20553c2da7..2190872dd1 100644
--- a/src/features/gallery/GalleryPostActions.tsx
+++ b/src/features/gallery/GalleryPostActions.tsx
@@ -9,6 +9,8 @@ import { getHandle } from "../../helpers/lemmy";
import MoreActions from "../post/shared/MoreActions";
import { calculateCurrentVotesCount } from "../../helpers/vote";
import { useLocation } from "react-router";
+import { useContext } from "react";
+import { GalleryContext } from "./GalleryProvider";
const Container = styled.div`
display: flex;
@@ -32,13 +34,9 @@ const Amount = styled.div`
interface GalleryPostActionsProps {
post: PostView;
- close: () => void;
}
-export default function GalleryPostActions({
- post,
- close,
-}: GalleryPostActionsProps) {
+export default function GalleryPostActions({ post }: GalleryPostActionsProps) {
const postVotesById = useAppSelector((state) => state.post.postVotesById);
const buildGeneralBrowseLink = useBuildGeneralBrowseLink();
const link = buildGeneralBrowseLink(
@@ -47,6 +45,7 @@ export default function GalleryPostActions({
const router = useIonRouter();
const score = calculateCurrentVotesCount(post, postVotesById);
const location = useLocation();
+ const { close } = useContext(GalleryContext);
function share() {
navigator.share({ url: post.post.ap_id });
diff --git a/src/features/gallery/GalleryProvider.tsx b/src/features/gallery/GalleryProvider.tsx
new file mode 100644
index 0000000000..22f8d3afd4
--- /dev/null
+++ b/src/features/gallery/GalleryProvider.tsx
@@ -0,0 +1,257 @@
+import styled from "@emotion/styled";
+import React, {
+ createContext,
+ useCallback,
+ useEffect,
+ useRef,
+ useState,
+} from "react";
+import GalleryPostActions from "./GalleryPostActions";
+import { createPortal } from "react-dom";
+import { PostView } from "lemmy-js-client";
+import PhotoSwipeLightbox, { PreparedPhotoSwipeOptions } from "photoswipe";
+import { useAppSelector } from "../../store";
+import { getSafeArea, isAndroid } from "../../helpers/device";
+
+import "photoswipe/style.css";
+import { useLocation } from "react-router";
+
+const Container = styled.div`
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ left: 0;
+ padding: 1rem;
+ padding-top: 4rem;
+ padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0));
+
+ color: white;
+ background: linear-gradient(0deg, rgba(0, 0, 0, 1), transparent);
+`;
+
+interface IGalleryContext {
+ // used for determining whether page needs to be scrolled up first
+ open: (
+ img: HTMLImageElement,
+ post?: PostView,
+ animationType?: PreparedPhotoSwipeOptions["showHideAnimationType"]
+ ) => void;
+ close: () => void;
+}
+
+export const GalleryContext = createContext({
+ open: () => {},
+ close: () => {},
+});
+
+const galleryHashEnabled = isAndroid();
+const OPEN_HASH = "galleryOpen";
+
+interface GalleryProviderProps {
+ children: React.ReactNode;
+}
+
+export default function GalleryProvider({ children }: GalleryProviderProps) {
+ const imageDimensionsBySrc = useAppSelector(
+ (state) => state.gallery.imageDimensionsBySrc
+ );
+ const [actionContainer, setActionContainer] = useState(
+ null
+ );
+ const [post, setPost] = useState();
+ const lightboxRef = useRef(null);
+ const location = useLocation();
+
+ useEffect(() => {
+ return () => {
+ lightboxRef.current?.destroy();
+ lightboxRef.current = null;
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ useEffect(() => {
+ if (!lightboxRef.current) return;
+
+ lightboxRef.current.destroy();
+ lightboxRef.current = null;
+ }, [location.pathname]);
+
+ const close = useCallback(() => {
+ if (!lightboxRef.current) return;
+
+ lightboxRef.current.close();
+ }, []);
+
+ const open = useCallback(
+ (
+ img: HTMLImageElement,
+ post?: PostView,
+ animationType?: PreparedPhotoSwipeOptions["showHideAnimationType"]
+ ) => {
+ if (lightboxRef.current) return;
+ if (!imageDimensionsBySrc[img.src]) return;
+
+ setPost(post);
+
+ const instance = new PhotoSwipeLightbox({
+ dataSource: [
+ {
+ src: img.src,
+ ...imageDimensionsBySrc[img.src],
+ },
+ ],
+ showHideAnimationType: animationType ?? "fade",
+ zoom: false,
+ bgOpacity: 1,
+ // Put in ion-app element so share IonActionSheet is on top
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ appendToEl: document.querySelector("ion-app")!,
+ paddingFn: () => getSafeArea(),
+ pswpModule: () => import("photoswipe"),
+ });
+
+ instance.addFilter("thumbEl", () => {
+ return img;
+ });
+
+ instance.addFilter("placeholderSrc", () => {
+ return img.src;
+ });
+
+ instance.on("closingAnimationEnd", () => setPost(undefined));
+
+ instance.on("uiRegister", function () {
+ instance.ui?.registerElement({
+ appendTo: "root",
+ onInit: (el) => {
+ setActionContainer(el);
+ },
+ });
+ });
+
+ // -----------------------------
+ // Android back button logic start
+ const getHistoryState = () => {
+ return {
+ gallery: {
+ open: true,
+ },
+ };
+ };
+
+ instance.on("beforeOpen", () => {
+ if (!galleryHashEnabled) {
+ return;
+ }
+
+ const hasHash = !!getHashValue();
+
+ // was opened by open() method call (click on thumbnail, for example)
+ // we need to create new history record to store hash navigation state
+ if (!hasHash) {
+ window.history.pushState(getHistoryState(), document.title);
+ return;
+ }
+
+ const hasGalleryStateInHistory = Boolean(window.history.state?.gallery);
+
+ // was openned by history.forward()
+ // we do not need to create new history record for hash navigation
+ // because we already have one
+ if (hasGalleryStateInHistory) {
+ return;
+ }
+
+ // was openned by link with gid and pid
+ const baseUrl = getBaseUrl();
+ const currentHash = getHashValue();
+ const urlWithoutOpenedSlide = `${baseUrl}`;
+ const urlWithOpenedSlide = `${baseUrl}#${currentHash}`;
+
+ // firstly, we need to modify current history record - set url without gid and pid
+ // we will return to this state after photoswipe closing
+ window.history.replaceState(
+ window.history.state,
+ document.title,
+ urlWithoutOpenedSlide
+ );
+ // then we need to create new history record to store hash navigation state
+ window.history.pushState(
+ getHistoryState(),
+ document.title,
+ urlWithOpenedSlide
+ );
+ });
+
+ instance.on("change", () => {
+ if (!galleryHashEnabled) {
+ return;
+ }
+
+ const baseUrl = getBaseUrl();
+ const urlWithOpenedSlide = `${baseUrl}#${OPEN_HASH}`;
+ // updates in current history record hash value with actual pid
+ window.history.replaceState(
+ getHistoryState(),
+ document.title,
+ urlWithOpenedSlide
+ );
+ });
+
+ const closeGalleryOnHistoryPopState = () => {
+ if (!galleryHashEnabled) {
+ return;
+ }
+
+ if (instance !== null) {
+ instance.close();
+ }
+ };
+
+ window.addEventListener("popstate", closeGalleryOnHistoryPopState);
+
+ instance.on("destroy", () => {
+ if (galleryHashEnabled) {
+ window.removeEventListener("popstate", closeGalleryOnHistoryPopState);
+
+ // if hash in URL => this destroy was called with ordinary instance.close() call
+ // if not => destroy was called by history.back (browser's back button) => history has been already returned to previous state
+ if (getHashValue()) {
+ window.history.back();
+ }
+ }
+ lightboxRef.current = null;
+ });
+ // Android back button logic end
+ // -----------------------------
+
+ instance.init();
+ lightboxRef.current = instance;
+ },
+ [imageDimensionsBySrc]
+ );
+
+ return (
+
+ {actionContainer !== null &&
+ post &&
+ createPortal(
+
+
+ ,
+ actionContainer
+ )}
+
+ {children}
+
+ );
+}
+
+function getBaseUrl(): string {
+ return `${window.location.pathname}${window.location.search}`;
+}
+
+function getHashValue(): string {
+ return window.location.hash.substring(1);
+}
diff --git a/src/features/gallery/PostGallery.tsx b/src/features/gallery/PostGallery.tsx
deleted file mode 100644
index d4ec9df009..0000000000
--- a/src/features/gallery/PostGallery.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import { useMemo, useRef } from "react";
-import GalleryPostActions from "./GalleryPostActions";
-import { Gallery, GalleryHandle } from "./Gallery";
-import { PostView } from "lemmy-js-client";
-import { findLoneImage } from "../../helpers/markdown";
-import { isUrlImage } from "../../helpers/lemmy";
-import { PreparedPhotoSwipeOptions } from "photoswipe";
-
-interface PostGalleryProps {
- post: PostView;
-
- className?: string;
- animationType?: PreparedPhotoSwipeOptions["showHideAnimationType"];
-}
-
-export default function PostGallery({
- post,
- className,
- animationType,
-}: PostGalleryProps) {
- const galleryRef = useRef(null);
-
- const images = useMemo(() => getImages(post), [post]);
-
- if (!images) return null;
-
- return (
- e.stopPropagation()}
- ref={galleryRef}
- src={images[0]}
- footer={
- galleryRef.current?.close()}
- />
- }
- animationType={animationType}
- className={className}
- />
- );
-}
-
-function getImages(post: PostView): string[] | undefined {
- if (post.post.url && isUrlImage(post.post.url)) return [post.post.url];
-
- const loneImage = post.post.body && findLoneImage(post.post.body);
- if (loneImage) return [loneImage.url];
-}
diff --git a/src/features/gallery/PostGalleryImg.tsx b/src/features/gallery/PostGalleryImg.tsx
new file mode 100644
index 0000000000..e05737d23d
--- /dev/null
+++ b/src/features/gallery/PostGalleryImg.tsx
@@ -0,0 +1,22 @@
+import { PostView } from "lemmy-js-client";
+import { isUrlImage } from "../../helpers/lemmy";
+import { findLoneImage } from "../../helpers/markdown";
+import { GalleryImg, GalleryImgProps } from "./GalleryImg";
+
+export interface PostGalleryImgProps extends Omit {
+ post: PostView;
+}
+
+export default function PostGalleryImg({
+ post,
+ ...props
+}: PostGalleryImgProps) {
+ return ;
+}
+
+function getPostImage(post: PostView): string | undefined {
+ if (post.post.url && isUrlImage(post.post.url)) return post.post.url;
+
+ const loneImage = post.post.body && findLoneImage(post.post.body);
+ if (loneImage) return loneImage.url;
+}
diff --git a/src/features/gallery/gallerySlice.tsx b/src/features/gallery/gallerySlice.tsx
new file mode 100644
index 0000000000..8734e7f1b7
--- /dev/null
+++ b/src/features/gallery/gallerySlice.tsx
@@ -0,0 +1,34 @@
+import { Dictionary, PayloadAction, createSlice } from "@reduxjs/toolkit";
+
+interface ImageDimension {
+ width: number;
+ height: number;
+}
+
+interface Image extends ImageDimension {
+ src: string;
+}
+
+interface CommentState {
+ imageDimensionsBySrc: Dictionary;
+}
+
+const initialState: CommentState = {
+ imageDimensionsBySrc: {},
+};
+
+export const gallerySlice = createSlice({
+ name: "gallery",
+ initialState,
+ reducers: {
+ imageLoaded: (state, action: PayloadAction) => {
+ state.imageDimensionsBySrc[action.payload.src] = action.payload;
+ },
+ resetGallery: () => initialState,
+ },
+});
+
+// Action creators are generated for each case reducer function
+export const { imageLoaded } = gallerySlice.actions;
+
+export default gallerySlice.reducer;
diff --git a/src/features/post/detail/PostDetail.tsx b/src/features/post/detail/PostDetail.tsx
index 59f7cdf351..a6c1ef2a2b 100644
--- a/src/features/post/detail/PostDetail.tsx
+++ b/src/features/post/detail/PostDetail.tsx
@@ -37,7 +37,7 @@ import CommentSort from "../../comment/CommentSort";
import Nsfw, { isNsfw } from "../../labels/Nsfw";
import { PageContext } from "../../auth/PageContext";
import MoreActions from "../shared/MoreActions";
-import PostGallery from "../../gallery/PostGallery";
+import PostGalleryImg from "../../gallery/PostGalleryImg";
const BorderlessIonItem = styled(IonItem)`
--padding-start: 0;
@@ -65,7 +65,7 @@ const lightboxCss = css`
background: var(--lightroom-bg);
`;
-const LightboxImg = styled(PostGallery)`
+const LightboxImg = styled(PostGalleryImg)`
${lightboxCss}
`;
diff --git a/src/features/post/inFeed/compact/Thumbnail.tsx b/src/features/post/inFeed/compact/Thumbnail.tsx
index 07a7d0532f..15b111afa1 100644
--- a/src/features/post/inFeed/compact/Thumbnail.tsx
+++ b/src/features/post/inFeed/compact/Thumbnail.tsx
@@ -6,7 +6,7 @@ import { useMemo } from "react";
import { findLoneImage } from "../../../../helpers/markdown";
import { css } from "@emotion/react";
import { isNsfw } from "../../../labels/Nsfw";
-import PostGallery from "../../../gallery/PostGallery";
+import PostGalleryImg from "../../../gallery/PostGalleryImg";
const Container = styled.div`
display: flex;
@@ -28,7 +28,7 @@ const Container = styled.div`
}
`;
-const StyledImg = styled(PostGallery)<{ blur: boolean }>`
+const StyledImg = styled(PostGalleryImg)<{ blur: boolean }>`
width: 100%;
height: 100%;
object-fit: cover;
@@ -63,7 +63,11 @@ export default function Thumbnail({ post }: ImgProps) {
return (
src && e.stopPropagation()}>
- {src ? : }
+ {src ? (
+
+ ) : (
+
+ )}
);
}
diff --git a/src/features/post/inFeed/large/Image.tsx b/src/features/post/inFeed/large/Image.tsx
index 9192dcfcfa..5f8c49895e 100644
--- a/src/features/post/inFeed/large/Image.tsx
+++ b/src/features/post/inFeed/large/Image.tsx
@@ -1,10 +1,12 @@
import styled from "@emotion/styled";
-import PostGallery from "../../../gallery/PostGallery";
import { css } from "@emotion/react";
+import PostGalleryImg from "../../../gallery/PostGalleryImg";
-export const Image = styled(PostGallery)<{ blur: boolean }>`
+export const Image = styled(PostGalleryImg)<{ blur: boolean }>`
width: 100%;
max-width: none;
+ max-height: max(200vh, 2000px);
+ object-fit: contain;
${({ blur }) =>
blur &&
diff --git a/src/features/shared/Markdown.tsx b/src/features/shared/Markdown.tsx
index af0a7bb574..2ef08b3c81 100644
--- a/src/features/shared/Markdown.tsx
+++ b/src/features/shared/Markdown.tsx
@@ -8,7 +8,7 @@ import LinkInterceptor from "./markdown/LinkInterceptor";
import buildCommunityPlugin from "./markdown/buildCommunityPlugin";
import customRemarkGfm from "./markdown/customRemarkGfm";
import { useMemo } from "react";
-import { Gallery } from "../gallery/Gallery";
+import { GalleryImg } from "../gallery/GalleryImg";
const Blockquote = styled.blockquote`
padding-left: 0.5rem;
@@ -64,13 +64,7 @@ export default function Markdown(props: ReactMarkdownOptions) {
linkTarget="_blank"
{...props}
components={{
- img: (props) => (
- e.stopPropagation()}
- animationType="zoom"
- />
- ),
+ img: (props) => ,
blockquote: (props) => ,
code: (props) =>
,
table: (props) => (
diff --git a/src/index.css b/src/index.css
index c4f2e128e2..27cba5cbe7 100644
--- a/src/index.css
+++ b/src/index.css
@@ -94,7 +94,7 @@ ion-action-sheet ion-icon {
margin-inline-end: 16px !important;
}
-/* react-photoswipe */
+/* photoswipe */
.pswp__top-bar {
top: env(safe-area-inset-top, 0);
diff --git a/src/store.ts b/src/store.ts
index e72e8e7c8b..884d39b7fd 100644
--- a/src/store.ts
+++ b/src/store.ts
@@ -6,6 +6,7 @@ import commentSlice from "./features/comment/commentSlice";
import communitySlice from "./features/community/communitySlice";
import userSlice from "./features/user/userSlice";
import inboxSlice from "./features/inbox/inboxSlice";
+import gallerySlice from "./features/gallery/gallerySlice";
import appearanceSlice, {
fetchSettingsFromDatabase,
} from "./features/settings/appearance/appearanceSlice";
@@ -19,6 +20,7 @@ const store = configureStore({
user: userSlice,
inbox: inboxSlice,
appearance: appearanceSlice,
+ gallery: gallerySlice,
},
});
export type RootState = ReturnType;
diff --git a/yarn.lock b/yarn.lock
index 966e16ac2c..7104934ea4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5378,10 +5378,10 @@ pend@~1.2.0:
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==
-photoswipe@^5.3.7:
- version "5.3.7"
- resolved "https://registry.yarnpkg.com/photoswipe/-/photoswipe-5.3.7.tgz#c67df67aaddb5705bcf8ff265bd2086f57805756"
- integrity sha512-zsyLsTTLFrj0XR1m4/hO7qNooboFKUrDy+Zt5i2d6qjFPAtBjzaj/Xtydso4uxzcXpcqbTmyxDibb3BcSISseg==
+photoswipe@^5.3.8:
+ version "5.3.8"
+ resolved "https://registry.yarnpkg.com/photoswipe/-/photoswipe-5.3.8.tgz#bea7db18e79383833f85c005b833da2029f0daee"
+ integrity sha512-4vTzOQt8GP4Chsm0s+8j2xDtVHAEN252PxrU12A1zXauNn0zD5HRHgjALKO2GKTyBnTnOrJUOxbV8LTrFIMrYw==
picocolors@^1.0.0:
version "1.0.0"
@@ -5661,11 +5661,6 @@ react-markdown@^8.0.7:
unist-util-visit "^4.0.0"
vfile "^5.0.0"
-react-photoswipe-gallery@^2.2.7:
- version "2.2.7"
- resolved "https://registry.yarnpkg.com/react-photoswipe-gallery/-/react-photoswipe-gallery-2.2.7.tgz#27fd45e84a3b7f15846761830c600b2c719053e3"
- integrity sha512-AEYNoL4/IIRosIUonn4haaFQNn1ui4vdVgAY9LHd/imVamNCkqUcyWeT6317UILp/yJI2gohsd3lWmcJEbjCag==
-
react-redux@^8.1.1:
version "8.1.1"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.1.tgz#8e740f3fd864a4cd0de5ba9cdc8ad39cc9e7c81a"