From ba3c4f3d036bc67c3b09180961226735dd8db266 Mon Sep 17 00:00:00 2001 From: CJ Date: Sun, 21 Jan 2024 12:59:40 -0600 Subject: [PATCH] remaining pages support --- .../src/components/Galleries/GalleryCard.tsx | 31 ++++++++++++++++- .../src/components/Galleries/GalleryList.tsx | 9 +++-- ui/v2.5/src/components/Images/ImageCard.tsx | 32 +++++++++++++++++- ui/v2.5/src/components/Images/ImageList.tsx | 8 ++++- ui/v2.5/src/components/Movies/MovieCard.tsx | 19 ++++++++++- ui/v2.5/src/components/Movies/MovieList.tsx | 9 +++-- .../components/Performers/PerformerCard.tsx | 9 ++--- ui/v2.5/src/components/Scenes/styles.scss | 2 +- ui/v2.5/src/components/Shared/GridCard.tsx | 8 +++-- ui/v2.5/src/components/Studios/StudioCard.tsx | 20 ++++++++++- ui/v2.5/src/components/Studios/StudioList.tsx | 9 +++-- ui/v2.5/src/components/Tags/TagCard.tsx | 33 ++++++++++++++++++- ui/v2.5/src/components/Tags/TagList.tsx | 9 +++-- 13 files changed, 175 insertions(+), 23 deletions(-) diff --git a/ui/v2.5/src/components/Galleries/GalleryCard.tsx b/ui/v2.5/src/components/Galleries/GalleryCard.tsx index 8dd49534195..cd55c2279df 100644 --- a/ui/v2.5/src/components/Galleries/GalleryCard.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryCard.tsx @@ -1,5 +1,5 @@ import { Button, ButtonGroup, OverlayTrigger, Tooltip } from "react-bootstrap"; -import React from "react"; +import React, { useEffect, useState } from "react"; import { Link } from "react-router-dom"; import * as GQL from "src/core/generated-graphql"; import { GridCard } from "../Shared/GridCard"; @@ -17,6 +17,7 @@ import { galleryTitle } from "src/core/galleries"; interface IProps { gallery: GQL.SlimGalleryDataFragment; + containerWidth?: number; selecting?: boolean; selected?: boolean | undefined; zoomIndex?: number; @@ -26,6 +27,33 @@ interface IProps { export const GalleryCard: React.FC = (props) => { const { configuration } = React.useContext(ConfigurationContext); const showStudioAsText = configuration?.interface.showStudioAsText ?? false; + const [cardWidth, setCardWidth] = useState(); + + useEffect(() => { + if (!props.containerWidth || props.zoomIndex === undefined) return; + + let containerPadding = 30; + let containerWidth = props.containerWidth - containerPadding; + let zoomValue = props.zoomIndex; + let maxCardWidth: number; + let paddingOffset = 10; + switch (zoomValue) { + case 0: + maxCardWidth = 240; + break; + case 1: + maxCardWidth = 340; + break; + case 2: + maxCardWidth = 480; + break; + case 3: + maxCardWidth = 640; + } + let maxElementsOnRow = Math.ceil(containerWidth / maxCardWidth!); + let fittedCardWidth = containerWidth / maxElementsOnRow - paddingOffset; + setCardWidth(fittedCardWidth); + }, [props, props.containerWidth, props.zoomIndex]); function maybeRenderScenePopoverButton() { if (props.gallery.scenes.length === 0) return; @@ -153,6 +181,7 @@ export const GalleryCard: React.FC = (props) => { = ({ setIsExportDialogOpen(true); } + const componentRef = useRef(null); + const { width } = useContainerDimensions(componentRef); + function renderContent( result: GQL.FindGalleriesQueryResult, filter: ListFilterModel, @@ -133,10 +137,11 @@ export const GalleryList: React.FC = ({ if (filter.displayMode === DisplayMode.Grid) { return ( -
+
{result.data.findGalleries.galleries.map((gallery) => ( 0} diff --git a/ui/v2.5/src/components/Images/ImageCard.tsx b/ui/v2.5/src/components/Images/ImageCard.tsx index 47f7eac7a79..22ffa09ec1d 100644 --- a/ui/v2.5/src/components/Images/ImageCard.tsx +++ b/ui/v2.5/src/components/Images/ImageCard.tsx @@ -1,4 +1,4 @@ -import React, { MouseEvent, useMemo } from "react"; +import React, { MouseEvent, useEffect, useMemo, useState } from "react"; import { Button, ButtonGroup } from "react-bootstrap"; import cx from "classnames"; import * as GQL from "src/core/generated-graphql"; @@ -20,6 +20,7 @@ import { TruncatedText } from "../Shared/TruncatedText"; interface IImageCardProps { image: GQL.SlimImageDataFragment; + containerWidth?: number; selecting?: boolean; selected?: boolean | undefined; zoomIndex: number; @@ -30,6 +31,34 @@ interface IImageCardProps { export const ImageCard: React.FC = ( props: IImageCardProps ) => { + const [cardWidth, setCardWidth] = useState(); + + useEffect(() => { + if (!props.containerWidth || props.zoomIndex === undefined) return; + + let containerPadding = 30; + let containerWidth = props.containerWidth - containerPadding; + let zoomValue = props.zoomIndex; + let maxCardWidth: number; + let paddingOffset = 10; + switch (zoomValue) { + case 0: + maxCardWidth = 240; + break; + case 1: + maxCardWidth = 340; + break; + case 2: + maxCardWidth = 480; + break; + case 3: + maxCardWidth = 640; + } + let maxElementsOnRow = Math.ceil(containerWidth / maxCardWidth!); + let fittedCardWidth = containerWidth / maxElementsOnRow - paddingOffset; + setCardWidth(fittedCardWidth); + }, [props, props.containerWidth, props.zoomIndex]); + const file = useMemo( () => props.image.visual_files.length > 0 @@ -153,6 +182,7 @@ export const ImageCard: React.FC = ( = ({ ev.preventDefault(); } + const componentRef = useRef(null); + const { width } = useContainerDimensions(componentRef); + function renderImageCard( index: number, image: GQL.SlimImageDataFragment, @@ -204,6 +209,7 @@ const ImageListImages: React.FC = ({ return ( 0} @@ -220,7 +226,7 @@ const ImageListImages: React.FC = ({ if (filter.displayMode === DisplayMode.Grid) { return ( -
+
{images.map((image, index) => renderImageCard(index, image, filter.zoomIndex) )} diff --git a/ui/v2.5/src/components/Movies/MovieCard.tsx b/ui/v2.5/src/components/Movies/MovieCard.tsx index e86856f2ec8..bbcc016999b 100644 --- a/ui/v2.5/src/components/Movies/MovieCard.tsx +++ b/ui/v2.5/src/components/Movies/MovieCard.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import { Button, ButtonGroup } from "react-bootstrap"; import * as GQL from "src/core/generated-graphql"; import { GridCard } from "../Shared/GridCard"; @@ -12,6 +12,7 @@ import { faPlayCircle } from "@fortawesome/free-solid-svg-icons"; interface IProps { movie: GQL.MovieDataFragment; + containerWidth?: number; sceneIndex?: number; selecting?: boolean; selected?: boolean; @@ -19,6 +20,21 @@ interface IProps { } export const MovieCard: React.FC = (props: IProps) => { + const [cardWidth, setCardWidth] = useState(); + + useEffect(() => { + if (!props.containerWidth) return; + + let containerPadding = 30; + let maxUsableWidth = props.containerWidth - containerPadding; + let maxCardWidth = 250; + let paddingOffset = 10; + + let maxElementsOnRow = Math.ceil(maxUsableWidth / maxCardWidth!); + let fittedCardWidth = maxUsableWidth / maxElementsOnRow - paddingOffset; + setCardWidth(fittedCardWidth); + }, [props, props.containerWidth]); + function maybeRenderSceneNumber() { if (!props.sceneIndex) return; @@ -71,6 +87,7 @@ export const MovieCard: React.FC = (props: IProps) => { = ({ filterHook, alterQuery }) => { setIsExportDialogOpen(true); } + const componentRef = useRef(null); + const { width } = useContainerDimensions(componentRef); + function renderContent( result: GQL.FindMoviesQueryResult, filter: ListFilterModel, @@ -130,10 +134,11 @@ export const MovieList: React.FC = ({ filterHook, alterQuery }) => { if (filter.displayMode === DisplayMode.Grid) { return ( -
+
{result.data.findMovies.movies.map((p) => ( 0} selected={selectedIds.has(p.id)} diff --git a/ui/v2.5/src/components/Performers/PerformerCard.tsx b/ui/v2.5/src/components/Performers/PerformerCard.tsx index 3bcc6304fd1..3c29309fbbe 100644 --- a/ui/v2.5/src/components/Performers/PerformerCard.tsx +++ b/ui/v2.5/src/components/Performers/PerformerCard.tsx @@ -34,8 +34,6 @@ export interface IPerformerCardExtraCriteria { interface IPerformerCardProps { performer: GQL.PerformerDataFragment; containerWidth?: number; - previewHeight?: number; - setPreviewHeight?: React.Dispatch>; ageFromDate?: string; selecting?: boolean; selected?: boolean; @@ -68,14 +66,13 @@ export const PerformerCard: React.FC = ({ { id: ageL10nId }, { age, years_old: ageL10String } ); - + const [updatePerformer] = usePerformerUpdate(); const [cardWidth, setCardWidth] = useState(); const [imageHeight, setImageHeight] = useState(); useEffect(() => { - if (!containerWidth) - return; + if (!containerWidth) return; let containerPadding = 30; let maxUsableWidth = containerWidth - containerPadding; @@ -83,7 +80,7 @@ export const PerformerCard: React.FC = ({ let paddingOffset = 10; let maxElementsOnRow = Math.ceil(maxUsableWidth / maxCardWidth!); - let fittedCardWidth = (maxUsableWidth / maxElementsOnRow) - paddingOffset; + let fittedCardWidth = maxUsableWidth / maxElementsOnRow - paddingOffset; let fittedimageHeight = (fittedCardWidth / 2) * 3; setCardWidth(fittedCardWidth); setImageHeight(fittedimageHeight); diff --git a/ui/v2.5/src/components/Scenes/styles.scss b/ui/v2.5/src/components/Scenes/styles.scss index 147472f578e..67e335a5808 100644 --- a/ui/v2.5/src/components/Scenes/styles.scss +++ b/ui/v2.5/src/components/Scenes/styles.scss @@ -99,7 +99,7 @@ textarea.scene-description { max-height: 150px; object-fit: contain; vertical-align: middle; - width: 320px; + width: 100%; @media (max-width: 576px) { width: 100%; diff --git a/ui/v2.5/src/components/Shared/GridCard.tsx b/ui/v2.5/src/components/Shared/GridCard.tsx index 99849d76b04..12a6107068a 100644 --- a/ui/v2.5/src/components/Shared/GridCard.tsx +++ b/ui/v2.5/src/components/Shared/GridCard.tsx @@ -27,8 +27,12 @@ interface ICardProps { export const useContainerDimensions = ( myRef: React.RefObject ) => { - // 15 pixel offset accounts for scrollbar - const [dimensions, setDimensions] = useState({ width: window.innerWidth-15, height: 0 }); + const overflow = window?.visualViewport?.height! < window.innerHeight; + const defaultWidth = overflow ? window.innerWidth - 15 : window.innerWidth; + const [dimensions, setDimensions] = useState({ + width: defaultWidth, + height: 0, + }); useEffect(() => { const getDimensions = () => ({ diff --git a/ui/v2.5/src/components/Studios/StudioCard.tsx b/ui/v2.5/src/components/Studios/StudioCard.tsx index 1acae33ea4b..0a217ea42c7 100644 --- a/ui/v2.5/src/components/Studios/StudioCard.tsx +++ b/ui/v2.5/src/components/Studios/StudioCard.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import { Link } from "react-router-dom"; import * as GQL from "src/core/generated-graphql"; import NavUtils from "src/utils/navigation"; @@ -10,6 +10,7 @@ import { RatingBanner } from "../Shared/RatingBanner"; interface IProps { studio: GQL.StudioDataFragment; + containerWidth?: number; hideParent?: boolean; selecting?: boolean; selected?: boolean; @@ -59,11 +60,27 @@ function maybeRenderChildren(studio: GQL.StudioDataFragment) { export const StudioCard: React.FC = ({ studio, + containerWidth, hideParent, selecting, selected, onSelectedChanged, }) => { + const [cardWidth, setCardWidth] = useState(); + + useEffect(() => { + if (!containerWidth) return; + + let containerPadding = 30; + let maxUsableWidth = containerWidth - containerPadding; + let maxCardWidth = 340; + let paddingOffset = 10; + + let maxElementsOnRow = Math.ceil(maxUsableWidth / maxCardWidth!); + let fittedCardWidth = maxUsableWidth / maxElementsOnRow - paddingOffset; + setCardWidth(fittedCardWidth); + }, [containerWidth]); + function maybeRenderScenesPopoverButton() { if (!studio.scene_count) return; @@ -156,6 +173,7 @@ export const StudioCard: React.FC = ({ = ({ setIsExportDialogOpen(true); } + const componentRef = useRef(null); + const { width } = useContainerDimensions(componentRef); + function renderContent( result: GQL.FindStudiosQueryResult, filter: ListFilterModel, @@ -135,10 +139,11 @@ export const StudioList: React.FC = ({ if (filter.displayMode === DisplayMode.Grid) { return ( -
+
{result.data.findStudios.studios.map((studio) => ( 0} diff --git a/ui/v2.5/src/components/Tags/TagCard.tsx b/ui/v2.5/src/components/Tags/TagCard.tsx index 11c3c5223a8..353f18a151f 100644 --- a/ui/v2.5/src/components/Tags/TagCard.tsx +++ b/ui/v2.5/src/components/Tags/TagCard.tsx @@ -1,5 +1,5 @@ import { ButtonGroup } from "react-bootstrap"; -import React from "react"; +import React, { useEffect, useState } from "react"; import { Link } from "react-router-dom"; import * as GQL from "src/core/generated-graphql"; import NavUtils from "src/utils/navigation"; @@ -10,6 +10,7 @@ import { PopoverCountButton } from "../Shared/PopoverCountButton"; interface IProps { tag: GQL.TagDataFragment; + containerWidth?: number; zoomIndex: number; selecting?: boolean; selected?: boolean; @@ -18,11 +19,40 @@ interface IProps { export const TagCard: React.FC = ({ tag, + containerWidth, zoomIndex, selecting, selected, onSelectedChanged, }) => { + const [cardWidth, setCardWidth] = useState(); + + useEffect(() => { + if (!containerWidth || zoomIndex === undefined) return; + + let containerPadding = 30; + let maxUsableWidth = containerWidth - containerPadding; + let zoomValue = zoomIndex; + let maxCardWidth: number; + let paddingOffset = 10; + switch (zoomValue) { + case 0: + maxCardWidth = 240; + break; + case 1: + maxCardWidth = 340; + break; + case 2: + maxCardWidth = 480; + break; + case 3: + maxCardWidth = 640; + } + let maxElementsOnRow = Math.ceil(maxUsableWidth / maxCardWidth!); + let fittedCardWidth = maxUsableWidth / maxElementsOnRow - paddingOffset; + setCardWidth(fittedCardWidth); + }, [containerWidth, zoomIndex]); + function maybeRenderDescription() { if (tag.description) { return ( @@ -181,6 +211,7 @@ export const TagCard: React.FC = ({ ListFilterModel; @@ -161,6 +162,9 @@ export const TagList: React.FC = ({ filterHook, alterQuery }) => { } } + const componentRef = useRef(null); + const { width } = useContainerDimensions(componentRef); + function renderContent( result: GQL.FindTagsQueryResult, filter: ListFilterModel, @@ -188,10 +192,11 @@ export const TagList: React.FC = ({ filterHook, alterQuery }) => { if (filter.displayMode === DisplayMode.Grid) { return ( -
+
{result.data.findTags.tags.map((tag) => ( 0}