mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 21:04:37 +03:00
Update gallery view layout and switch libraries (#793)
* Update gallery view layout and switch libraries * Tweak gallery grid layout
This commit is contained in:
@@ -36,7 +36,9 @@
|
|||||||
"bootstrap": "^4.5.2",
|
"bootstrap": "^4.5.2",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"flag-icon-css": "^3.5.0",
|
"flag-icon-css": "^3.5.0",
|
||||||
|
"flexbin": "^0.2.0",
|
||||||
"formik": "^2.1.5",
|
"formik": "^2.1.5",
|
||||||
|
"fslightbox-react": "^1.5.0",
|
||||||
"graphql": "^15.3.0",
|
"graphql": "^15.3.0",
|
||||||
"graphql-tag": "^2.11.0",
|
"graphql-tag": "^2.11.0",
|
||||||
"i18n-iso-countries": "^6.0.0",
|
"i18n-iso-countries": "^6.0.0",
|
||||||
@@ -67,6 +69,7 @@
|
|||||||
"@graphql-codegen/typescript-operations": "^1.17.8",
|
"@graphql-codegen/typescript-operations": "^1.17.8",
|
||||||
"@graphql-codegen/typescript-react-apollo": "^2.0.6",
|
"@graphql-codegen/typescript-react-apollo": "^2.0.6",
|
||||||
"@types/classnames": "^2.2.10",
|
"@types/classnames": "^2.2.10",
|
||||||
|
"@types/fslightbox-react": "^1.4.0",
|
||||||
"@types/lodash": "^4.14.161",
|
"@types/lodash": "^4.14.161",
|
||||||
"@types/node": "14.6.4",
|
"@types/node": "14.6.4",
|
||||||
"@types/react": "16.9.43",
|
"@types/react": "16.9.43",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const Gallery: React.FC = () => {
|
|||||||
if (error) return <div>{error.message}</div>;
|
if (error) return <div>{error.message}</div>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="col-9 m-auto">
|
<div className="col col-lg-9 m-auto">
|
||||||
<GalleryViewer gallery={gallery} />
|
<GalleryViewer gallery={gallery} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,58 +1,46 @@
|
|||||||
import React, { FunctionComponent, useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Lightbox from "react-images";
|
|
||||||
import Gallery from "react-photo-gallery";
|
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
|
import FsLightbox from "fslightbox-react";
|
||||||
|
import "flexbin/flexbin.css";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
gallery: GQL.GalleryDataFragment;
|
gallery: GQL.GalleryDataFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GalleryViewer: FunctionComponent<IProps> = ({ gallery }) => {
|
export const GalleryViewer: React.FC<IProps> = ({ gallery }) => {
|
||||||
const [currentImage, setCurrentImage] = useState<number>(0);
|
const [lightboxToggle, setLightboxToggle] = useState(false);
|
||||||
const [lightboxIsOpen, setLightboxIsOpen] = useState<boolean>(false);
|
const [currentIndex, setCurrentIndex] = useState(0);
|
||||||
|
|
||||||
function openLightbox(
|
const openImage = (index: number) => {
|
||||||
_event: React.MouseEvent<Element>,
|
setCurrentIndex(index);
|
||||||
obj: { index: number }
|
setLightboxToggle(!lightboxToggle);
|
||||||
) {
|
};
|
||||||
setCurrentImage(obj.index);
|
|
||||||
setLightboxIsOpen(true);
|
|
||||||
}
|
|
||||||
function closeLightbox() {
|
|
||||||
setCurrentImage(0);
|
|
||||||
setLightboxIsOpen(false);
|
|
||||||
}
|
|
||||||
function gotoPrevious() {
|
|
||||||
setCurrentImage(currentImage - 1);
|
|
||||||
}
|
|
||||||
function gotoNext() {
|
|
||||||
setCurrentImage(currentImage + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const photos = gallery.files.map((file) => ({
|
const photos = gallery.files.map((file) => file.path ?? "");
|
||||||
src: file.path ?? "",
|
const thumbs = gallery.files.map((file, index) => (
|
||||||
caption: file.name ?? "",
|
<div
|
||||||
}));
|
role="link"
|
||||||
const thumbs = gallery.files.map((file) => ({
|
tabIndex={index}
|
||||||
src: `${file.path}?thumb=true` || "",
|
key={file.index}
|
||||||
width: 1,
|
onClick={() => openImage(index)}
|
||||||
height: 1,
|
onKeyPress={() => openImage(index)}
|
||||||
}));
|
>
|
||||||
|
<img
|
||||||
|
src={`${file.path}?thumb=600` || ""}
|
||||||
|
loading="lazy"
|
||||||
|
className="gallery-image"
|
||||||
|
alt={file.name ?? index.toString()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="gallery">
|
||||||
<Gallery photos={thumbs} columns={15} onClick={openLightbox} />
|
<div className="flexbin">{thumbs}</div>
|
||||||
<Lightbox
|
<FsLightbox
|
||||||
images={photos}
|
sourceIndex={currentIndex}
|
||||||
onClose={closeLightbox}
|
toggler={lightboxToggle}
|
||||||
onClickPrev={gotoPrevious}
|
sources={photos}
|
||||||
onClickNext={gotoNext}
|
|
||||||
currentImage={currentImage}
|
|
||||||
onClickImage={() =>
|
|
||||||
window.open(photos[currentImage].src ?? "", "_blank")
|
|
||||||
}
|
|
||||||
isOpen={lightboxIsOpen}
|
|
||||||
width={9999}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
/* stylelint-disable selector-class-pattern */
|
|
||||||
.react-photo-gallery--gallery {
|
|
||||||
img {
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* stylelint-enable selector-class-pattern */
|
|
||||||
|
|
||||||
.gallery-card {
|
.gallery-card {
|
||||||
padding: 0.5rem;
|
&.card {
|
||||||
|
padding: 0;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-section {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
&-image {
|
&-image {
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
vertical-align: middle;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-image {
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
import { CountryFlag, Icon, LoadingIndicator } from "src/components/Shared";
|
import { CountryFlag, Icon, LoadingIndicator } from "src/components/Shared";
|
||||||
import { useToast } from "src/hooks";
|
import { useToast } from "src/hooks";
|
||||||
import { TextUtils } from "src/utils";
|
import { TextUtils } from "src/utils";
|
||||||
import Lightbox from "react-images";
|
import FsLightbox from "fslightbox-react";
|
||||||
import { PerformerDetailsPanel } from "./PerformerDetailsPanel";
|
import { PerformerDetailsPanel } from "./PerformerDetailsPanel";
|
||||||
import { PerformerOperationsPanel } from "./PerformerOperationsPanel";
|
import { PerformerOperationsPanel } from "./PerformerOperationsPanel";
|
||||||
import { PerformerScenesPanel } from "./PerformerScenesPanel";
|
import { PerformerScenesPanel } from "./PerformerScenesPanel";
|
||||||
@@ -34,7 +34,7 @@ export const Performer: React.FC = () => {
|
|||||||
>({});
|
>({});
|
||||||
const [imagePreview, setImagePreview] = useState<string | null>();
|
const [imagePreview, setImagePreview] = useState<string | null>();
|
||||||
const [imageEncoding, setImageEncoding] = useState<boolean>(false);
|
const [imageEncoding, setImageEncoding] = useState<boolean>(false);
|
||||||
const [lightboxIsOpen, setLightboxIsOpen] = useState(false);
|
const [lightboxToggle, setLightboxToggle] = useState(false);
|
||||||
|
|
||||||
// if undefined then get the existing image
|
// if undefined then get the existing image
|
||||||
// if null then get the default (no) image
|
// if null then get the default (no) image
|
||||||
@@ -288,8 +288,6 @@ export const Performer: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const photos = [{ src: activeImage, caption: "Image" }];
|
|
||||||
|
|
||||||
if (!performer.id) {
|
if (!performer.id) {
|
||||||
return <LoadingIndicator />;
|
return <LoadingIndicator />;
|
||||||
}
|
}
|
||||||
@@ -300,7 +298,10 @@ export const Performer: React.FC = () => {
|
|||||||
{imageEncoding ? (
|
{imageEncoding ? (
|
||||||
<LoadingIndicator message="Encoding image..." />
|
<LoadingIndicator message="Encoding image..." />
|
||||||
) : (
|
) : (
|
||||||
<Button variant="link" onClick={() => setLightboxIsOpen(true)}>
|
<Button
|
||||||
|
variant="link"
|
||||||
|
onClick={() => setLightboxToggle(!lightboxToggle)}
|
||||||
|
>
|
||||||
<img className="performer" src={activeImage} alt="Performer" />
|
<img className="performer" src={activeImage} alt="Performer" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
@@ -321,14 +322,7 @@ export const Performer: React.FC = () => {
|
|||||||
<div className="performer-tabs">{renderTabs()}</div>
|
<div className="performer-tabs">{renderTabs()}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Lightbox
|
<FsLightbox toggler={lightboxToggle} sources={[activeImage]} />
|
||||||
images={photos}
|
|
||||||
onClose={() => setLightboxIsOpen(false)}
|
|
||||||
currentImage={0}
|
|
||||||
isOpen={lightboxIsOpen}
|
|
||||||
onClickImage={() => window.open(activeImage, "_blank")}
|
|
||||||
width={9999}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2919,6 +2919,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/fslightbox-react@^1.4.0":
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/fslightbox-react/-/fslightbox-react-1.4.0.tgz#d2b20486830745ae80318c1c478c9beae5f2cd8a"
|
||||||
|
integrity sha512-ocIiZqFQ3BWBZB8Bp0fuNma7Eb0aOjkgk/nEUfW0omdRw4ciaVivabfsWldNuR69KwRJrvs6MZQuvVV6JEqlFg==
|
||||||
|
dependencies:
|
||||||
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/glob@^7.1.1":
|
"@types/glob@^7.1.1":
|
||||||
version "7.1.1"
|
version "7.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
|
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
|
||||||
@@ -7143,6 +7150,11 @@ flatten@^1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b"
|
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b"
|
||||||
integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==
|
integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==
|
||||||
|
|
||||||
|
flexbin@^0.2.0:
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/flexbin/-/flexbin-0.2.0.tgz#0126306d3d595fcb7dfcb87149b9c9599ff8f4e9"
|
||||||
|
integrity sha1-ASYwbT1ZX8t9/LhxSbnJWZ/49Ok=
|
||||||
|
|
||||||
flush-write-stream@^1.0.0:
|
flush-write-stream@^1.0.0:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
|
resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
|
||||||
@@ -7338,6 +7350,11 @@ fsevents@^1.2.7:
|
|||||||
bindings "^1.5.0"
|
bindings "^1.5.0"
|
||||||
nan "^2.12.1"
|
nan "^2.12.1"
|
||||||
|
|
||||||
|
fslightbox-react@^1.5.0:
|
||||||
|
version "1.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fslightbox-react/-/fslightbox-react-1.5.0.tgz#07cf41d7ff8b02a79a0886d13519550b79dc50e5"
|
||||||
|
integrity sha512-xBe1K06pa3opWar/xBtArsHMnxMJWsmg5EmNdDtheDL9nMCqk2AXYlNnstfYVqtJJjqNReqeL21wc52Yy4rwWg==
|
||||||
|
|
||||||
fstream@^1.0.0, fstream@^1.0.12:
|
fstream@^1.0.0, fstream@^1.0.12:
|
||||||
version "1.0.12"
|
version "1.0.12"
|
||||||
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
|
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
|
||||||
|
|||||||
Reference in New Issue
Block a user