mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Movie card visual consistency (#1758)
* Support getting scenes on movies in the API * Make movie card visually consistent with scene etc * Add date * Add synopsis * Show scene count with hover listing the scenes * Move scene index to button * Move scene number to own section Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
parent
5fdab995f5
commit
1d04b550b9
7 changed files with 82 additions and 16 deletions
|
|
@ -17,4 +17,10 @@ fragment MovieData on Movie {
|
|||
front_image_path
|
||||
back_image_path
|
||||
scene_count
|
||||
|
||||
scenes {
|
||||
id
|
||||
title
|
||||
path
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ type Movie {
|
|||
front_image_path: String # Resolver
|
||||
back_image_path: String # Resolver
|
||||
scene_count: Int # Resolver
|
||||
scenes: [Scene!]!
|
||||
}
|
||||
|
||||
input MovieCreateInput {
|
||||
|
|
|
|||
|
|
@ -125,6 +125,18 @@ func (r *movieResolver) SceneCount(ctx context.Context, obj *models.Movie) (ret
|
|||
return &res, err
|
||||
}
|
||||
|
||||
func (r *movieResolver) Scenes(ctx context.Context, obj *models.Movie) (ret []*models.Scene, err error) {
|
||||
if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
|
||||
var err error
|
||||
ret, err = repo.Scene().FindByMovieID(obj.ID)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (r *movieResolver) CreatedAt(ctx context.Context, obj *models.Movie) (*time.Time, error) {
|
||||
return &obj.CreatedAt.Timestamp, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
* Support filtering Movies by Performers. ([#1675](https://github.com/stashapp/stash/pull/1675))
|
||||
|
||||
### 🎨 Improvements
|
||||
* Added date and details to Movie card, and move scene count to icon. ([#1758](https://github.com/stashapp/stash/pull/1758))
|
||||
* Added date and details to Gallery card, and move image count to icon. ([#1763](https://github.com/stashapp/stash/pull/1763))
|
||||
* Optimised image thumbnail generation (optionally using `libvips`) and made optional. ([#1655](https://github.com/stashapp/stash/pull/1655))
|
||||
* Added missing image table indexes, resulting in a significant performance improvement. ([#1740](https://github.com/stashapp/stash/pull/1740))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
import React, { FunctionComponent } from "react";
|
||||
import { FormattedPlural } from "react-intl";
|
||||
import { Button, ButtonGroup } from "react-bootstrap";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import { GridCard } from "src/components/Shared";
|
||||
import {
|
||||
GridCard,
|
||||
HoverPopover,
|
||||
Icon,
|
||||
TagLink,
|
||||
TruncatedText,
|
||||
} from "src/components/Shared";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { RatingBanner } from "../Shared/RatingBanner";
|
||||
|
||||
interface IProps {
|
||||
|
|
@ -14,20 +21,47 @@ interface IProps {
|
|||
|
||||
export const MovieCard: FunctionComponent<IProps> = (props: IProps) => {
|
||||
function maybeRenderSceneNumber() {
|
||||
if (!props.sceneIndex) {
|
||||
if (!props.sceneIndex) return;
|
||||
|
||||
return (
|
||||
<span>
|
||||
{props.movie.scene_count}
|
||||
<FormattedPlural
|
||||
value={props.movie.scene_count ?? 0}
|
||||
one="scene"
|
||||
other="scenes"
|
||||
/>
|
||||
<>
|
||||
<hr />
|
||||
<span className="movie-scene-number">
|
||||
<FormattedMessage id="scene" /> #{props.sceneIndex}
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return <span>Scene number: {props.sceneIndex}</span>;
|
||||
function maybeRenderScenesPopoverButton() {
|
||||
if (props.movie.scenes.length === 0) return;
|
||||
|
||||
const popoverContent = props.movie.scenes.map((scene) => (
|
||||
<TagLink key={scene.id} scene={scene} />
|
||||
));
|
||||
|
||||
return (
|
||||
<HoverPopover placement="bottom" content={popoverContent}>
|
||||
<Button className="minimal">
|
||||
<Icon icon="play-circle" />
|
||||
<span>{props.movie.scenes.length}</span>
|
||||
</Button>
|
||||
</HoverPopover>
|
||||
);
|
||||
}
|
||||
|
||||
function maybeRenderPopoverButtonGroup() {
|
||||
if (props.sceneIndex || props.movie.scenes.length > 0) {
|
||||
return (
|
||||
<>
|
||||
{maybeRenderSceneNumber()}
|
||||
<hr />
|
||||
<ButtonGroup className="card-popovers">
|
||||
{maybeRenderScenesPopoverButton()}
|
||||
</ButtonGroup>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -46,10 +80,18 @@ export const MovieCard: FunctionComponent<IProps> = (props: IProps) => {
|
|||
<RatingBanner rating={props.movie.rating} />
|
||||
</>
|
||||
}
|
||||
details={maybeRenderSceneNumber()}
|
||||
details={
|
||||
<>
|
||||
<span>{props.movie.date}</span>
|
||||
<p>
|
||||
<TruncatedText text={props.movie.synopsis} lineCount={3} />
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
selected={props.selected}
|
||||
selecting={props.selecting}
|
||||
onSelectedChanged={props.onSelectedChanged}
|
||||
popovers={maybeRenderPopoverButtonGroup()}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@
|
|||
object-fit: contain;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.movie-scene-number {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.movie-images {
|
||||
|
|
|
|||
Loading…
Reference in a new issue