Skip to content

Commit

Permalink
fix modal height calc and missing ref types
Browse files Browse the repository at this point in the history
  • Loading branch information
markdavella committed Mar 21, 2024
1 parent a6197e0 commit c44347a
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 60 deletions.
3 changes: 2 additions & 1 deletion web/src/components/InlineModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ function InlineModal(props: InlineModalProps) {
return (
<Collapse
in={open}
timeout={{ appear: 1250, enter: 1250, exit: 350 }}
// timeout={{ appear: 1250, enter: 1250, exit: 350 }}
timeout="auto"
easing={{
enter: 'easeInSine',
exit: 'linear',
Expand Down
74 changes: 38 additions & 36 deletions web/src/components/TabPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,51 @@
import { Grid } from '@mui/material';
import { forwardRef } from 'react';
import { ForwardedRef, forwardRef } from 'react';
import useStore from '../store';

type TabPanelProps = {
children?: React.ReactNode;
index: number;
value: number;
ref?: any; // to do
ref?: React.RefObject<HTMLDivElement>;
};

const CustomTabPanel = forwardRef((props: TabPanelProps, ref: any) => {
const { children, value, index, ...other } = props;
const CustomTabPanel = forwardRef(
(props: TabPanelProps, ref: ForwardedRef<HTMLDivElement>) => {
const { children, value, index, ...other } = props;

const viewType = useStore((state) => state.theme.programmingSelectorView);
const viewType = useStore((state) => state.theme.programmingSelectorView);

return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
key={value}
{...other}
>
{value === index && children && (
<Grid
container
component={'div'}
spacing={2}
sx={{
display: viewType === 'grid' ? 'grid' : 'flex',
gridTemplateColumns:
viewType === 'grid'
? 'repeat(auto-fill, minmax(160px, 1fr))'
: 'none',
justifyContent: viewType === 'grid' ? 'space-around' : 'normal',
mt: 2,
}}
ref={ref}
>
{children}
</Grid>
)}
</div>
);
});
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
key={value}
{...other}
>
{value === index && children && (
<Grid
container
component={'div'}
spacing={2}
sx={{
display: viewType === 'grid' ? 'grid' : 'flex',
gridTemplateColumns:
viewType === 'grid'
? 'repeat(auto-fill, minmax(160px, 1fr))'
: 'none',
justifyContent: viewType === 'grid' ? 'space-around' : 'normal',
mt: 2,
}}
ref={ref}
>
{children}
</Grid>
)}
</div>
);
},
);

export default CustomTabPanel;
27 changes: 16 additions & 11 deletions web/src/components/channel_config/PlexGridItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from '@tunarr/types/plex';
import _, { filter, isNaN } from 'lodash-es';
import React, {
ForwardedRef,
MouseEvent,
forwardRef,
useCallback,
Expand Down Expand Up @@ -42,15 +43,18 @@ export interface PlexGridItemProps<T extends PlexMedia> {
modalIsPending?: CallableFunction;
modalIndex?: number;
onClick?: any;
ref?: any;
ref?: React.RefObject<HTMLDivElement>;
}

const PlexGridItem = forwardRef(
<T extends PlexMedia>(props: PlexGridItemProps<T>, ref: any) => {
<T extends PlexMedia>(
props: PlexGridItemProps<T>,
ref: ForwardedRef<HTMLDivElement>,
) => {
const server = useStore((s) => s.currentServer!); // We have to have a server at this point
const darkMode = useStore((state) => state.theme.darkMode);
const [open, setOpen] = useState(false);
const { item } = props;
const { item, style, moveModal, modalChildren } = props;
const hasChildren = !isTerminalItem(item);
const childPath = isPlexCollection(item) ? 'collections' : 'metadata';
const { isPending, data: children } = usePlexTyped<
Expand All @@ -69,11 +73,11 @@ const PlexGridItem = forwardRef(
const handleClick = () => {
setOpen(!open);

if (props.moveModal) {
props.moveModal();
if (moveModal) {
moveModal();

if (children && props.modalChildren) {
props.modalChildren(children.Metadata);
if (children && modalChildren) {
modalChildren(children.Metadata);
}
}
};
Expand All @@ -88,8 +92,8 @@ const PlexGridItem = forwardRef(
if (children) {
addKnownMediaForServer(server.name, children.Metadata, item.guid);

if (children.Metadata.length > 0 && !!props.modalChildren) {
props.modalChildren(children.Metadata);
if (children.Metadata.length > 0 && !!modalChildren) {
modalChildren(children.Metadata);
}
}
}, [item.guid, server.name, children]);
Expand All @@ -107,7 +111,7 @@ const PlexGridItem = forwardRef(
[item, selectedServer, selectedMediaIds],
);

const { isIntersecting: isInViewport, ref: imageRef } =
const { isIntersecting: isInViewport, ref: imageContainerRef } =
useIntersectionObserver({
threshold: 0,
rootMargin: '0px',
Expand All @@ -125,7 +129,7 @@ const PlexGridItem = forwardRef(
<Fade
in={isInViewport && !_.isUndefined(item)} // to do: eventually we will want to add in: && imageLoaded so it only fades in after image has loaded
timeout={500}
ref={imageRef}
ref={imageContainerRef}
>
<ImageListItem
component={Grid}
Expand All @@ -150,6 +154,7 @@ const PlexGridItem = forwardRef(
: theme.palette.grey[400]
: 'transparent',
transition: 'background-color 10s ease',
...style,
}}
onClick={
hasChildren
Expand Down
30 changes: 26 additions & 4 deletions web/src/components/channel_config/PlexProgrammingSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
PlexTvShow,
} from '@tunarr/types/plex';
import { chain, first, isEmpty, isNil, isUndefined, map } from 'lodash-es';
import { useCallback, useEffect, useRef, useState } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useIntersectionObserver } from 'usehooks-ts';
import {
firstItemInNextRow,
Expand Down Expand Up @@ -111,6 +111,7 @@ export default function PlexProgrammingSelector() {

useEffect(() => {
setModalIndex(-1);
handleModalChildren([]);
}, [tabValue]);

const handleChange = (_: React.SyntheticEvent, newValue: number) => {
Expand All @@ -119,15 +120,31 @@ export default function PlexProgrammingSelector() {

const handleMoveModal = useCallback(
(index: number) => {
console.log('TEST');
if (index === modalIndex) {
handleModalChildren([]);
setModalIndex(-1);
} else {
handleModalChildren([]);
setModalIndex(index);
}
},
[modalIndex],
);

const handleHeightCalc = (childCount: string) => {
console.log(childCount);

// const containerWidth = containerRef?.current?.offsetWidth || 0;
// const itemWidth = imageRef?.current?.offsetWidth || 0;

// return getEstimatedModalHeight(
// containerWidth,
// itemWidth,
// parseInt(childCount),
// );
};

const handleModalChildren = useCallback(
(children: PlexMedia[]) => {
setModalChildren(children);
Expand Down Expand Up @@ -279,7 +296,7 @@ export default function PlexProgrammingSelector() {
viewType === 'list' ? (
<PlexListItem key={item.guid} item={item} />
) : (
<>
<React.Fragment key={item.guid}>
<InlineModal
modalIndex={modalIndex}
modalChildren={modalChildren}
Expand All @@ -293,7 +310,6 @@ export default function PlexProgrammingSelector() {
}
/>
<PlexGridItem
key={item.guid}
item={item}
index={index}
modalIndex={modalIndex}
Expand All @@ -304,9 +320,15 @@ export default function PlexProgrammingSelector() {
modalIsPending={(isPending: boolean) =>
handleModalIsPending(isPending)
}
// style={{
// opacity:
// index === modalIndex && modalIndex === -1
// ? '0.75 !important'
// : '0.55 !important',
// }}
ref={imageRef}
/>
</>
</React.Fragment>
),
)}
</CustomTabPanel>,
Expand Down
27 changes: 19 additions & 8 deletions web/src/helpers/inlineModalUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,33 @@ export function getImagesPerRow(
// Estimate the modal height to prevent div collapse while new modal images load
export function getEstimatedModalHeight(
containerWidth: number,
imageWidth: number,
imageContainerWidth: number,
listSize: number,
): number {
// Exit with defaults if container & image width are not provided
if (containerWidth === 0 || imageWidth === 0) {
if (containerWidth === 0 || imageContainerWidth === 0) {
return 294; //default modal height for 1 row
}

const columns = getImagesPerRow(containerWidth, imageWidth);
const widthPerItem = containerWidth / columns;
const heightPerItem = widthPerItem * 1.72 + 8; //8 magic number for margin-top of each item
const columns = getImagesPerRow(containerWidth, imageContainerWidth);

// Magic Numbers
// to do: eventually grab this data via refs just in case it changes in the future
const inlineModalTopPadding = 16;
const imageContainerXPadding = 8;
const listItemBarContainerHeight = 54;

const imagewidth = imageContainerWidth - imageContainerXPadding * 2; // 16px padding on each item
const heightPerImage = (3 * imagewidth) / 2; // Movie Posters are 2:3
const heightPerItem =
heightPerImage + listItemBarContainerHeight + imageContainerXPadding; // 54px

const rows = listSize < columns ? 1 : Math.ceil(listSize / columns);
//This is min-height so we only need to adjust it for visible rows since we
//use interesectionObserver to load them in
const maxRows = rows >= 3 ? 3 : rows;

return Math.ceil(maxRows * heightPerItem);
return Math.ceil(maxRows * heightPerItem + inlineModalTopPadding); // 16px padding added to top
}

export function firstItemInNextRow(
Expand All @@ -37,7 +47,8 @@ export function firstItemInNextRow(
// Calculate the row number of the current item
const rowNumber = Math.floor(modalIndex / itemsPerRow);

if (modalIndex === -1) {
// Modal is closed or collection has no data, exit
if (modalIndex === -1 || numberOfItems === 0) {
return -1;
}

Expand Down Expand Up @@ -73,6 +84,6 @@ export function extractLastIndexes(arr: PlexMedia[], x: number): number[] {
// Extract the last x elements
const lastElements = arr.slice(-x);

// Use map to create a new array with corresponding indexes
// Return last X indexes in new array
return lastElements.map((_) => arr.indexOf(_));
}

0 comments on commit c44347a

Please sign in to comment.