mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Show gallery cover on the edit panel (#5935)
This commit is contained in:
parent
724d438721
commit
c9ca40152f
5 changed files with 60 additions and 11 deletions
|
|
@ -9,12 +9,14 @@ import (
|
||||||
type GalleryURLBuilder struct {
|
type GalleryURLBuilder struct {
|
||||||
BaseURL string
|
BaseURL string
|
||||||
GalleryID string
|
GalleryID string
|
||||||
|
UpdatedAt string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGalleryURLBuilder(baseURL string, gallery *models.Gallery) GalleryURLBuilder {
|
func NewGalleryURLBuilder(baseURL string, gallery *models.Gallery) GalleryURLBuilder {
|
||||||
return GalleryURLBuilder{
|
return GalleryURLBuilder{
|
||||||
BaseURL: baseURL,
|
BaseURL: baseURL,
|
||||||
GalleryID: strconv.Itoa(gallery.ID),
|
GalleryID: strconv.Itoa(gallery.ID),
|
||||||
|
UpdatedAt: strconv.FormatInt(gallery.UpdatedAt.Unix(), 10),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,5 +25,5 @@ func (b GalleryURLBuilder) GetPreviewURL() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b GalleryURLBuilder) GetCoverURL() string {
|
func (b GalleryURLBuilder) GetCoverURL() string {
|
||||||
return b.BaseURL + "/gallery/" + b.GalleryID + "/cover"
|
return b.BaseURL + "/gallery/" + b.GalleryID + "/cover?t=" + b.UpdatedAt
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -162,6 +162,21 @@ export const GalleryEditPanel: React.FC<IProps> = ({
|
||||||
);
|
);
|
||||||
}, [scrapers]);
|
}, [scrapers]);
|
||||||
|
|
||||||
|
const cover = useMemo(() => {
|
||||||
|
if (gallery?.paths?.cover) {
|
||||||
|
return (
|
||||||
|
<div className="gallery-cover">
|
||||||
|
<img
|
||||||
|
src={gallery.paths.cover}
|
||||||
|
alt={intl.formatMessage({ id: "cover_image" })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div></div>;
|
||||||
|
}, [gallery?.paths?.cover, intl]);
|
||||||
|
|
||||||
async function onSave(input: InputValues) {
|
async function onSave(input: InputValues) {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
|
|
@ -463,6 +478,12 @@ export const GalleryEditPanel: React.FC<IProps> = ({
|
||||||
</Col>
|
</Col>
|
||||||
<Col lg={5} xl={12}>
|
<Col lg={5} xl={12}>
|
||||||
{renderDetailsField()}
|
{renderDetailsField()}
|
||||||
|
<Form.Group controlId="cover_image">
|
||||||
|
<Form.Label>
|
||||||
|
<FormattedMessage id="cover_image" />
|
||||||
|
</Form.Label>
|
||||||
|
{cover}
|
||||||
|
</Form.Group>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,21 @@ $galleryTabWidth: 450px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gallery-cover {
|
||||||
|
aspect-ratio: 4 / 3;
|
||||||
|
display: block;
|
||||||
|
height: auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-cover img {
|
||||||
|
height: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
div.GalleryWall {
|
div.GalleryWall {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
|
||||||
|
|
@ -1613,17 +1613,30 @@ export const mutateAddGalleryImages = (input: GQL.GalleryAddInput) =>
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function evictCover(cache: ApolloCache<GQL.Gallery>, gallery_id: string) {
|
||||||
|
const fields: Pick<Modifiers<GQL.Gallery>, "paths" | "cover"> = {};
|
||||||
|
fields.paths = (paths) => {
|
||||||
|
if (!("cover" in paths)) {
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
const coverUrl = new URL(paths.cover);
|
||||||
|
coverUrl.search = "?t=" + Math.floor(Date.now() / 1000);
|
||||||
|
return { ...paths, cover: coverUrl.toString() };
|
||||||
|
};
|
||||||
|
fields.cover = (_value, { DELETE }) => DELETE;
|
||||||
|
cache.modify({
|
||||||
|
id: cache.identify({ __typename: "Gallery", id: gallery_id }),
|
||||||
|
fields,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export const mutateSetGalleryCover = (input: GQL.GallerySetCoverInput) =>
|
export const mutateSetGalleryCover = (input: GQL.GallerySetCoverInput) =>
|
||||||
client.mutate<GQL.SetGalleryCoverMutation>({
|
client.mutate<GQL.SetGalleryCoverMutation>({
|
||||||
mutation: GQL.SetGalleryCoverDocument,
|
mutation: GQL.SetGalleryCoverDocument,
|
||||||
variables: input,
|
variables: input,
|
||||||
update(cache, result) {
|
update(cache, result) {
|
||||||
if (!result.data?.setGalleryCover) return;
|
if (!result.data?.setGalleryCover) return;
|
||||||
|
evictCover(cache, input.gallery_id);
|
||||||
cache.evict({
|
|
||||||
id: cache.identify({ __typename: "Gallery", id: input.gallery_id }),
|
|
||||||
fieldName: "cover",
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1633,11 +1646,7 @@ export const mutateResetGalleryCover = (input: GQL.GalleryResetCoverInput) =>
|
||||||
variables: input,
|
variables: input,
|
||||||
update(cache, result) {
|
update(cache, result) {
|
||||||
if (!result.data?.resetGalleryCover) return;
|
if (!result.data?.resetGalleryCover) return;
|
||||||
|
evictCover(cache, input.gallery_id);
|
||||||
cache.evict({
|
|
||||||
id: cache.identify({ __typename: "Gallery", id: input.gallery_id }),
|
|
||||||
fieldName: "cover",
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ For best results, images in zip file should be stored without compression (copy,
|
||||||
|
|
||||||
If a filename of an image in the gallery zip file ends with `cover.jpg`, it will be treated like a cover and presented first in the gallery view page and as a gallery cover in the gallery list view. If more than one images match the name the first one found in natural sort order is selected.
|
If a filename of an image in the gallery zip file ends with `cover.jpg`, it will be treated like a cover and presented first in the gallery view page and as a gallery cover in the gallery list view. If more than one images match the name the first one found in natural sort order is selected.
|
||||||
|
|
||||||
|
You can also manually select any image from a gallery as its cover. On the gallery details page, select the desired cover image, and then select **Set as Cover** in the ⋯ menu.
|
||||||
|
|
||||||
## Image clips/gifs
|
## Image clips/gifs
|
||||||
|
|
||||||
Images can also be clips/gifs. These are meant to be short video loops. Right now they are not possible in zipfiles. To declare video files to be images, there are two ways:
|
Images can also be clips/gifs. These are meant to be short video loops. Right now they are not possible in zipfiles. To declare video files to be images, there are two ways:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue