feat: add tagline, episode runtime, genres list to media details & clean/refactor CSS into globals (#1160)

This commit is contained in:
TheCatLady
2021-03-14 20:16:39 -04:00
committed by GitHub
parent 3d6b343413
commit 2f2e00237d
23 changed files with 683 additions and 584 deletions

View File

@@ -19,12 +19,14 @@ import Transition from '../Transition';
import PageTitle from '../Common/PageTitle';
import { useUser, Permission } from '../../hooks/useUser';
import useSettings from '../../hooks/useSettings';
import Link from 'next/link';
import { uniq } from 'lodash';
const messages = defineMessages({
overviewunavailable: 'Overview unavailable.',
overview: 'Overview',
movies: 'Movies',
numberofmovies: 'Number of Movies: {count}',
numberofmovies: '{count} Movies',
requesting: 'Requesting…',
request: 'Request',
requestcollection: 'Request Collection',
@@ -62,6 +64,10 @@ const CollectionDetails: React.FC<CollectionDetailsProps> = ({
}
);
const { data: genres } = useSWR<{ id: number; name: string }[]>(
`/api/v1/genres/movie?language=${locale}`
);
if (!data && !error) {
return <LoadingSpinner />;
}
@@ -105,6 +111,17 @@ const CollectionDetails: React.FC<CollectionDetailsProps> = ({
collectionStatus4k = MediaStatus.PARTIALLY_AVAILABLE;
}
const hasRequestable =
data.parts.filter(
(part) => !part.mediaInfo || part.mediaInfo.status === MediaStatus.UNKNOWN
).length > 0;
const hasRequestable4k =
data.parts.filter(
(part) =>
!part.mediaInfo || part.mediaInfo.status4k === MediaStatus.UNKNOWN
).length > 0;
const requestableParts = data.parts.filter(
(part) =>
!part.mediaInfo ||
@@ -147,9 +164,43 @@ const CollectionDetails: React.FC<CollectionDetailsProps> = ({
}
};
const collectionAttributes: React.ReactNode[] = [];
collectionAttributes.push(
intl.formatMessage(messages.numberofmovies, {
count: data.parts.length,
})
);
if (genres && data.parts.some((part) => part.genreIds.length)) {
collectionAttributes.push(
uniq(
data.parts.reduce(
(genresList: number[], curr) => genresList.concat(curr.genreIds),
[]
)
)
.map((genreId) => (
<Link
href={`/discover/movies/genre/${genreId}`}
key={`genre-${genreId}`}
>
<a className="hover:underline">
{genres.find((g) => g.id === genreId)?.name}
</a>
</Link>
))
.reduce((prev, curr) => (
<>
{prev}, {curr}
</>
))
);
}
return (
<div
className="px-4 pt-16 -mx-4 -mt-16 bg-center bg-cover"
className="media-page"
style={{
height: 493,
backgroundImage: `linear-gradient(180deg, rgba(17, 24, 39, 0.47) 0%, rgba(17, 24, 39, 1) 100%), url(//image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data.backdropPath})`,
@@ -216,24 +267,20 @@ const CollectionDetails: React.FC<CollectionDetailsProps> = ({
</ul>
</Modal>
</Transition>
<div className="flex flex-col items-center pt-4 lg:flex-row lg:items-end">
<div className="lg:mr-4">
<img
src={`//image.tmdb.org/t/p/w600_and_h900_bestv2${data.posterPath}`}
alt=""
className="w-32 rounded shadow md:rounded-lg md:shadow-2xl md:w-44 lg:w-52"
/>
</div>
<div className="flex flex-col flex-1 mt-4 text-center text-white lg:mr-4 lg:mt-0 lg:text-left">
<div className="mb-2 space-x-2">
<span className="ml-2 lg:ml-0">
<StatusBadge
status={collectionStatus}
inProgress={data.parts.some(
(part) => (part.mediaInfo?.downloadStatus ?? []).length > 0
)}
/>
</span>
<div className="media-header">
<img
src={`//image.tmdb.org/t/p/w600_and_h900_bestv2${data.posterPath}`}
alt=""
className="media-poster"
/>
<div className="media-title">
<div className="media-status">
<StatusBadge
status={collectionStatus}
inProgress={data.parts.some(
(part) => (part.mediaInfo?.downloadStatus ?? []).length > 0
)}
/>
{settings.currentSettings.movie4kEnabled &&
hasPermission(
[Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE],
@@ -241,43 +288,83 @@ const CollectionDetails: React.FC<CollectionDetailsProps> = ({
type: 'or',
}
) && (
<span>
<StatusBadge
status={collectionStatus4k}
is4k
inProgress={data.parts.some(
(part) =>
(part.mediaInfo?.downloadStatus4k ?? []).length > 0
)}
/>
</span>
<StatusBadge
status={collectionStatus4k}
is4k
inProgress={data.parts.some(
(part) =>
(part.mediaInfo?.downloadStatus4k ?? []).length > 0
)}
/>
)}
</div>
<h1 className="text-2xl md:text-4xl">{data.name}</h1>
<span className="mt-1 text-xs lg:text-base lg:mt-0">
{intl.formatMessage(messages.numberofmovies, {
count: data.parts.length,
})}
<h1>{data.name}</h1>
<span className="media-attributes">
{collectionAttributes.length > 0 &&
collectionAttributes
.map((t, k) => <span key={k}>{t}</span>)
.reduce((prev, curr) => (
<>
{prev} | {curr}
</>
))}
</span>
</div>
<div className="relative z-10 flex flex-wrap justify-center flex-shrink-0 mt-4 sm:justify-end sm:flex-nowrap lg:mt-0">
<div className="media-actions">
{hasPermission(Permission.REQUEST) &&
(collectionStatus !== MediaStatus.AVAILABLE ||
(hasRequestable ||
(settings.currentSettings.movie4kEnabled &&
hasPermission(
[Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE],
{ type: 'or' }
) &&
collectionStatus4k !== MediaStatus.AVAILABLE)) && (
<div className="mb-3 sm:mb-0">
<ButtonWithDropdown
buttonType="primary"
onClick={() => {
setRequestModal(true);
setIs4k(collectionStatus === MediaStatus.AVAILABLE);
}}
text={
<>
hasRequestable4k)) && (
<ButtonWithDropdown
buttonType="primary"
onClick={() => {
setRequestModal(true);
setIs4k(!hasRequestable);
}}
text={
<>
<svg
className="w-4 mr-1"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
/>
</svg>
<span>
{intl.formatMessage(
hasRequestable
? messages.requestcollection
: messages.requestcollection4k
)}
</span>
</>
}
>
{settings.currentSettings.movie4kEnabled &&
hasPermission(
[Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE],
{ type: 'or' }
) &&
hasRequestable &&
hasRequestable4k && (
<ButtonWithDropdown.Item
buttonType="primary"
onClick={() => {
setRequestModal(true);
setIs4k(true);
}}
>
<svg
className="w-4 mr-1"
fill="none"
@@ -293,70 +380,27 @@ const CollectionDetails: React.FC<CollectionDetailsProps> = ({
/>
</svg>
<span>
{intl.formatMessage(
collectionStatus === MediaStatus.AVAILABLE
? messages.requestcollection4k
: messages.requestcollection
)}
{intl.formatMessage(messages.requestcollection4k)}
</span>
</>
}
>
{settings.currentSettings.movie4kEnabled &&
hasPermission(
[Permission.REQUEST_4K, Permission.REQUEST_4K_MOVIE],
{ type: 'or' }
) &&
collectionStatus !== MediaStatus.AVAILABLE &&
collectionStatus4k !== MediaStatus.AVAILABLE && (
<ButtonWithDropdown.Item
buttonType="primary"
onClick={() => {
setRequestModal(true);
setIs4k(true);
}}
>
<svg
className="w-4 mr-1"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
/>
</svg>
<span>
{intl.formatMessage(messages.requestcollection4k)}
</span>
</ButtonWithDropdown.Item>
)}
</ButtonWithDropdown>
</div>
</ButtonWithDropdown.Item>
)}
</ButtonWithDropdown>
)}
</div>
</div>
<div className="flex flex-col pt-8 pb-4 text-white md:flex-row">
<div className="flex-1 md:mr-8">
<h2 className="text-xl md:text-2xl">
{intl.formatMessage(messages.overview)}
</h2>
<p className="pt-2 text-sm md:text-base">
<div className="media-overview">
<div className="flex-1">
<h2>{intl.formatMessage(messages.overview)}</h2>
<p>
{data.overview
? data.overview
: intl.formatMessage(messages.overviewunavailable)}
</p>
</div>
</div>
<div className="mt-6 mb-4 md:flex md:items-center md:justify-between">
<div className="flex-1 min-w-0">
<div className="inline-flex items-center text-xl leading-7 text-white sm:text-2xl sm:leading-9 sm:truncate">
<span>{intl.formatMessage(messages.movies)}</span>
</div>
<div className="slider-header">
<div className="slider-title">
<span>{intl.formatMessage(messages.movies)}</span>
</div>
</div>
<Slider