feat: add studio/network sliders to discover

includes some adjustments to titlecard design
pull/1051/head
sct 3 years ago
parent 57bc340840
commit 1c6914f5ce

@ -0,0 +1,46 @@
import Link from 'next/link';
import React, { useState } from 'react';
interface CompanyCardProps {
name: string;
image: string;
url: string;
}
const CompanyCard: React.FC<CompanyCardProps> = ({ image, url, name }) => {
const [isHovered, setHovered] = useState(false);
return (
<Link href={url}>
<a
className={`relative flex items-center justify-center h-32 w-64 sm:h-36 sm:w-72 p-8 shadow transition ease-in-out duration-150 cursor-pointer transform-gpu ${
isHovered ? 'bg-gray-700 scale-105' : 'bg-gray-800 scale-100'
} ring-1 ring-gray-700 rounded-xl`}
onMouseEnter={() => {
setHovered(true);
}}
onMouseLeave={() => setHovered(false)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
setHovered(true);
}
}}
role="link"
tabIndex={0}
>
<img
src={image}
alt={name}
className="relative z-40 max-w-full max-h-full"
/>
<div
className={`absolute bottom-0 left-0 right-0 h-12 rounded-b-xl bg-gradient-to-t z-0 ${
isHovered ? 'from-gray-800' : 'from-gray-900'
}`}
/>
</a>
</Link>
);
};
export default CompanyCard;

@ -49,7 +49,7 @@ const DiscoverTvNetwork: React.FC = () => {
{firstResultData?.network.logoPath ? (
<div className="flex justify-center mb-6">
<img
src={`//image.tmdb.org/t/p/w780_filter(negate,000,666)/${firstResultData.network.logoPath}`}
src={`//image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)${firstResultData.network.logoPath}`}
alt={firstResultData.network.name}
className="max-h-24 sm:max-h-32"
/>

@ -49,7 +49,7 @@ const DiscoverMovieStudio: React.FC = () => {
{firstResultData?.studio.logoPath ? (
<div className="flex justify-center mb-6">
<img
src={`//image.tmdb.org/t/p/w780_filter(negate,000,666)/${firstResultData.studio.logoPath}`}
src={`//image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)${firstResultData.studio.logoPath}`}
alt={firstResultData.studio.name}
className="max-h-24 sm:max-h-32"
/>

@ -0,0 +1,151 @@
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import CompanyCard from '../../CompanyCard';
import Slider from '../../Slider';
const messages = defineMessages({
networks: 'Networks',
});
interface Network {
name: string;
image: string;
url: string;
}
const networks: Network[] = [
{
name: 'Netflix',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/wwemzKWzjKYJFfCeiB57q3r4Bcm.png',
url: '/discover/tv/network/213',
},
{
name: 'Disney+',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/gJ8VX6JSu3ciXHuC2dDGAo2lvwM.png',
url: '/discover/tv/network/2739',
},
{
name: 'Prime Video',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/ifhbNuuVnlwYy5oXA5VIb2YR8AZ.png',
url: '/discover/tv/network/1024',
},
{
name: 'HBO',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/tuomPhY2UtuPTqqFnKMVHvSb724.png',
url: '/discover/tv/network/49',
},
{
name: 'ABC',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/ndAvF4JLsliGreX87jAc9GdjmJY.png',
url: '/discover/tv/network/2',
},
{
name: 'FOX',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/1DSpHrWyOORkL9N2QHX7Adt31mQ.png',
url: '/discover/tv/network/19',
},
{
name: 'Cinemax',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/6mSHSquNpfLgDdv6VnOOvC5Uz2h.png',
url: '/discover/tv/network/359',
},
{
name: 'AMC',
image:
'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/pmvRmATOCaDykE6JrVoeYxlFHw3.png',
url: '/discover/tv/network/174',
},
{
name: 'Showtime',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/Allse9kbjiP6ExaQrnSpIhkurEi.png',
url: '/discover/tv/network/67',
},
{
name: 'Starz',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/8GJjw3HHsAJYwIWKIPBPfqMxlEa.png',
url: '/discover/tv/network/318',
},
{
name: 'The CW',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/ge9hzeaU7nMtQ4PjkFlc68dGAJ9.png',
url: '/discover/tv/network/71',
},
{
name: 'NBC',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/o3OedEP0f9mfZr33jz2BfXOUK5.png',
url: '/discover/tv/network/6',
},
{
name: 'CBS',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/nm8d7P7MJNiBLdgIzUK0gkuEA4r.png',
url: '/discover/tv/network/16',
},
{
name: 'BBC One',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/mVn7xESaTNmjBUyUtGNvDQd3CT1.png',
url: '/discover/tv/network/4',
},
{
name: 'Cartoon Network',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/c5OC6oVCg6QP4eqzW6XIq17CQjI.png',
url: '/discover/tv/network/56',
},
{
name: 'Adult Swim',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/9AKyspxVzywuaMuZ1Bvilu8sXly.png',
url: '/discover/tv/network/80',
},
{
name: 'Nickelodeon',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/ikZXxg6GnwpzqiZbRPhJGaZapqB.png',
url: '/discover/tv/network/13',
},
];
const NetworkSlider: React.FC = () => {
const intl = useIntl();
return (
<>
<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-gray-300 cursor-default sm:text-2xl sm:leading-9 sm:truncate">
<span>{intl.formatMessage(messages.networks)}</span>
</div>
</div>
</div>
<Slider
sliderKey="networks"
isLoading={false}
isEmpty={false}
items={networks.map((network, index) => (
<CompanyCard
key={`network-${index}`}
name={network.name}
image={network.image}
url={network.url}
/>
))}
emptyMessage=""
/>
</>
);
};
export default NetworkSlider;

@ -0,0 +1,109 @@
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import CompanyCard from '../../CompanyCard';
import Slider from '../../Slider';
const messages = defineMessages({
studios: 'Studios',
});
interface Studio {
name: string;
image: string;
url: string;
}
const studios: Studio[] = [
{
name: 'Disney',
image:
'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/wdrCwmRnLFJhEoH8GSfymY85KHT.png',
url: '/discover/movies/studio/2',
},
{
name: '20th Century Fox',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/qZCc1lty5FzX30aOCVRBLzaVmcp.png',
url: '/discover/movies/studio/25',
},
{
name: 'Sony Pictures',
image:
'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/GagSvqWlyPdkFHMfQ3pNq6ix9P.png',
url: '/discover/movies/studio/34',
},
{
name: 'Warner Bros. Pictures',
image:
'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/ky0xOc5OrhzkZ1N6KyUxacfQsCk.png',
url: '/discover/movies/studio/174',
},
{
name: 'Universal',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/8lvHyhjr8oUKOOy2dKXoALWKdp0.png',
url: '/discover/movies/studio/33',
},
{
name: 'Paramount',
image:
'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/fycMZt242LVjagMByZOLUGbCvv3.png',
url: '/discover/movies/studio/4',
},
{
name: 'Pixar',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/1TjvGVDMYsj6JBxOAkUHpPEwLf7.png',
url: '/discover/movies/studio/3',
},
{
name: 'Dreamworks',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/kP7t6RwGz2AvvTkvnI1uteEwHet.png',
url: '/discover/movies/studio/521',
},
{
name: 'Marvel Studios',
image:
'http://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/hUzeosd33nzE5MCNsZxCGEKTXaQ.png',
url: '/discover/movies/studio/420',
},
{
name: 'DC',
image:
'https://image.tmdb.org/t/p/w780_filter(duotone,ffffff,bababa)/2Tc1P3Ac8M479naPp1kYT3izLS5.png',
url: '/discover/movies/studio/9993',
},
];
const StudioSlider: React.FC = () => {
const intl = useIntl();
return (
<>
<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-gray-300 cursor-default sm:text-2xl sm:leading-9 sm:truncate">
<span>{intl.formatMessage(messages.studios)}</span>
</div>
</div>
</div>
<Slider
sliderKey="studios"
isLoading={false}
isEmpty={false}
items={studios.map((studio, index) => (
<CompanyCard
key={`studio-${index}`}
name={studio.name}
image={studio.image}
url={studio.url}
/>
))}
emptyMessage=""
/>
</>
);
};
export default StudioSlider;

@ -9,6 +9,8 @@ import type { RequestResultsResponse } from '../../../server/interfaces/api/requ
import RequestCard from '../RequestCard';
import MediaSlider from '../MediaSlider';
import PageTitle from '../Common/PageTitle';
import StudioSlider from './StudioSlider';
import NetworkSlider from './NetworkSlider';
const messages = defineMessages({
discover: 'Discover',
@ -112,6 +114,7 @@ const Discover: React.FC = () => {
linkUrl="/discover/movies/upcoming"
url="/api/v1/discover/movies/upcoming"
/>
<StudioSlider />
<MediaSlider
sliderKey="popular-tv"
title={intl.formatMessage(messages.populartv)}
@ -124,6 +127,7 @@ const Discover: React.FC = () => {
url="/api/v1/discover/tv/upcoming"
linkUrl="/discover/tv/upcoming"
/>
<NetworkSlider />
</>
);
};

@ -32,7 +32,7 @@ const ShowMoreCard: React.FC<ShowMoreCardProps> = ({ url, posters }) => {
>
<div
className={`relative w-36 sm:w-36 md:w-44
rounded-lg text-white shadow-lg overflow-hidden transition ease-in-out duration-150 cursor-pointer transform-gpu ${
rounded-xl text-white shadow-lg overflow-hidden transition ease-in-out duration-150 cursor-pointer transform-gpu ${
isHovered ? 'bg-gray-500 scale-105' : 'bg-gray-600 scale-100'
}`}
>

@ -37,8 +37,8 @@ const PersonCard: React.FC<PersonCardProps> = ({
<div
className={`relative ${
canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'
} rounded-lg text-white shadow-lg transition ease-in-out duration-150 cursor-pointer transform-gpu ${
isHovered ? 'bg-gray-600 scale-105' : 'bg-gray-700 scale-100'
} rounded-xl text-white shadow transition ease-in-out duration-150 cursor-pointer transform-gpu ring-1 ring-gray-700 ${
isHovered ? 'bg-gray-700 scale-105' : 'bg-gray-800 scale-100'
}`}
>
<div style={{ paddingBottom: '150%' }}>
@ -47,7 +47,7 @@ const PersonCard: React.FC<PersonCardProps> = ({
{profilePath ? (
<img
src={`https://image.tmdb.org/t/p/w600_and_h900_bestv2${profilePath}`}
className="object-cover w-3/4 h-full bg-center bg-cover rounded-full"
className="object-cover w-3/4 h-full bg-center bg-cover rounded-full ring-1 ring-gray-700"
alt=""
/>
) : (
@ -79,7 +79,11 @@ const PersonCard: React.FC<PersonCardProps> = ({
{subName}
</div>
)}
<div className="absolute bottom-0 left-0 right-0 h-12 rounded-b-lg bg-gradient-to-t from-gray-700" />
<div
className={`absolute bottom-0 left-0 right-0 h-12 rounded-b-xl bg-gradient-to-t ${
isHovered ? 'from-gray-800' : 'from-gray-900'
}`}
/>
</div>
</div>
</div>

@ -31,7 +31,7 @@ const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {
const RequestCardPlaceholder: React.FC = () => {
return (
<div className="relative p-4 bg-gray-700 rounded-lg w-72 sm:w-96 animate-pulse">
<div className="relative p-4 bg-gray-700 rounded-xl w-72 sm:w-96 animate-pulse">
<div className="w-20 sm:w-28">
<div className="w-full" style={{ paddingBottom: '150%' }} />
</div>
@ -98,7 +98,7 @@ const RequestCard: React.FC<RequestCardProps> = ({ request, onTitleData }) => {
return (
<div
className="relative flex p-4 text-gray-400 bg-gray-800 bg-center bg-cover rounded-md w-72 sm:w-96"
className="relative flex p-4 text-gray-400 bg-gray-800 bg-center bg-cover rounded-xl w-72 sm:w-96"
style={{
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/${title.backdropPath})`,
}}

@ -103,7 +103,7 @@ const RequestItem: React.FC<RequestItemProps> = ({
if (!title && !error) {
return (
<div
className="w-full h-64 bg-gray-800 rounded-md lg:h-32 animate-pulse"
className="w-full h-64 bg-gray-800 rounded-xl lg:h-32 animate-pulse"
ref={ref}
/>
);
@ -112,7 +112,7 @@ const RequestItem: React.FC<RequestItemProps> = ({
if (!title || !requestData) {
return (
<div
className="w-full h-64 bg-gray-800 rounded-md lg:h-32 animate-pulse"
className="w-full h-64 bg-gray-800 rounded-xl lg:h-32 animate-pulse"
ref={ref}
/>
);
@ -132,7 +132,7 @@ const RequestItem: React.FC<RequestItemProps> = ({
setShowEditModal(false);
}}
/>
<div className="relative flex flex-col justify-between w-full py-4 overflow-hidden text-gray-400 bg-gray-800 rounded-md shadow-md lg:h-32 lg:flex-row">
<div className="relative flex flex-col justify-between w-full py-4 overflow-hidden text-gray-400 bg-gray-800 shadow-md ring-1 ring-gray-700 rounded-xl lg:h-32 lg:flex-row">
<div
className="absolute inset-0 z-0 w-full bg-center bg-cover lg:w-2/3"
style={{

@ -7,7 +7,7 @@ interface PlaceholderProps {
const Placeholder: React.FC<PlaceholderProps> = ({ canExpand = false }) => {
return (
<div
className={`relative animate-pulse rounded-lg bg-gray-700 ${
className={`relative animate-pulse rounded-xl bg-gray-700 ${
canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'
}`}
>

@ -81,8 +81,8 @@ const TitleCard: React.FC<TitleCardProps> = ({
onCancel={closeModal}
/>
<div
className={`transition duration-300 transform-gpu scale-100 outline-none cursor-default titleCard ${
showDetail ? 'scale-105' : ''
className={`transition duration-300 transform-gpu scale-100 outline-none cursor-default titleCard ring-1 ring-gray-700 rounded-xl ${
showDetail ? 'scale-105 shadow-lg' : 'shadow'
}`}
style={{
backgroundImage: image
@ -104,7 +104,7 @@ const TitleCard: React.FC<TitleCardProps> = ({
role="link"
tabIndex={0}
>
<div className="absolute top-0 bottom-0 left-0 right-0 w-full h-full overflow-hidden shadow">
<div className="absolute inset-0 w-full h-full overflow-hidden">
<div className="absolute left-0 right-0 flex items-center justify-between p-2">
<div
className={`rounded-full z-40 pointer-events-none shadow ${
@ -180,7 +180,7 @@ const TitleCard: React.FC<TitleCardProps> = ({
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="absolute top-0 bottom-0 left-0 right-0 z-40 flex items-center justify-center text-white bg-gray-800 bg-opacity-75 rounded-lg">
<div className="absolute inset-0 z-40 flex items-center justify-center text-white bg-gray-800 bg-opacity-75 rounded-xl">
<Spinner className="w-10 h-10" />
</div>
</Transition>
@ -194,10 +194,10 @@ const TitleCard: React.FC<TitleCardProps> = ({
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="absolute top-0 bottom-0 left-0 right-0">
<div className="absolute inset-0 overflow-hidden rounded-xl">
<Link href={mediaType === 'movie' ? `/movie/${id}` : `/tv/${id}`}>
<a
className="absolute top-0 bottom-0 left-0 right-0 w-full h-full overflow-hidden text-left rounded-lg cursor-pointer"
className="absolute inset-0 w-full h-full overflow-hidden text-left cursor-pointer"
style={{
background:
'linear-gradient(180deg, rgba(45, 55, 72, 0.4) 0%, rgba(45, 55, 72, 0.9) 100%)',

@ -18,6 +18,8 @@
"components.Discover.DiscoverNetwork.networkSeries": "{network} Series",
"components.Discover.DiscoverStudio.studioMovies": "{studio} Movies",
"components.Discover.DiscoverTvGenre.genreSeries": "{genre} Series",
"components.Discover.NetworkSlider.networks": "Networks",
"components.Discover.StudioSlider.studios": "Studios",
"components.Discover.discover": "Discover",
"components.Discover.discovermovies": "Popular Movies",
"components.Discover.discovertv": "Popular Series",

@ -25,7 +25,7 @@ ul.cardList > li {
}
.titleCard {
@apply relative bg-gray-800 bg-cover rounded-lg;
@apply relative bg-gray-800 bg-cover;
padding-bottom: 150%;
}

Loading…
Cancel
Save