Files
maher 703f50a09d
Some checks failed
Build / run (push) Has been cancelled
first commit
2025-10-29 11:42:25 +01:00

139 lines
4.3 KiB
TypeScript
Executable File

import React, {Fragment, ReactNode} from 'react';
import clsx from 'clsx';
import {Channel} from '@common/channels/channel';
import {FilterList} from '@common/datatable/filters/filter-list/filter-list';
import {AnimatePresence, m} from 'framer-motion';
import {opacityAnimation} from '@common/ui/animation/opacity-animation';
import {useBackendFilterUrlParams} from '@common/datatable/filters/backend-filter-url-params';
import {MOVIE_MODEL, SERIES_MODEL, TITLE_MODEL} from '@app/titles/models/title';
import {ChannelSortButton} from '@app/channels/channel-header/channel-sort-button';
import {AddFilterButton} from '@common/datatable/filters/add-filter-button';
import {TuneIcon} from '@common/icons/material/Tune';
import {SiteSectionHeading} from '@app/titles/site-section-heading';
import {Trans} from '@common/i18n/trans';
import {useParams} from 'react-router-dom';
import {ChannelLayoutButton} from '@app/channels/channel-header/channel-layout-button';
import {useTitleIndexFilters} from '@app/titles/use-title-index-filters';
import {FilterListSkeleton} from '@common/datatable/filters/filter-list/filter-list-skeleton';
import {UserListByline} from '@app/user-lists/user-list-byline';
import {UserListDetails} from '@app/user-lists/user-list-details';
const FilterModelTypes = [TITLE_MODEL, MOVIE_MODEL, SERIES_MODEL];
interface Props {
channel: Channel;
margin?: string;
isNested: boolean;
actions?: ReactNode;
}
export function ChannelHeader({
channel,
isNested,
actions,
margin = isNested ? 'mb-16 md:mb-30' : 'mb-20 md:mb-40',
}: Props) {
const shouldShowFilterButton =
!isNested &&
FilterModelTypes.includes(channel.config.contentModel) &&
channel.config.contentType === 'listAll';
const {encodedFilters} = useBackendFilterUrlParams();
const {filters, filtersLoading} = useTitleIndexFilters({
disabled: !shouldShowFilterButton,
});
if (channel.config.hideTitle) {
return null;
}
return (
<section className={clsx(margin)}>
<ChannelTitle
channel={channel}
isNested={isNested}
actions={
<Fragment>
{actions}
{!isNested && <ChannelSortButton channel={channel} />}
{shouldShowFilterButton && (
<AddFilterButton
icon={<TuneIcon />}
color={null}
variant="text"
disabled={filtersLoading}
filters={filters}
/>
)}
{!isNested && <ChannelLayoutButton channel={channel} />}
</Fragment>
}
/>
{shouldShowFilterButton && (
<div className="mt-14">
<AnimatePresence initial={false} mode="wait">
{filtersLoading && encodedFilters ? (
<FilterListSkeleton />
) : (
<m.div key="filter-list" {...opacityAnimation}>
<FilterList filters={filters} />
</m.div>
)}
</AnimatePresence>
</div>
)}
</section>
);
}
interface ChannelTitleProps {
channel: Channel;
isNested: boolean;
actions?: ReactNode;
}
function ChannelTitle({channel, isNested, actions}: ChannelTitleProps) {
const {restriction: urlParam} = useParams();
if (channel.config.hideTitle) {
return null;
}
const link =
channel.config.restriction && urlParam
? `/${channel.slug}/${urlParam}`
: `/${channel.slug}`;
return (
<SiteSectionHeading
className="flex-auto"
margin="m-0"
description={<ChannelDescription channel={channel} />}
actions={actions}
headingType={isNested ? 'h2' : 'h1'}
descriptionFontSize={isNested ? 'text-sm' : undefined}
fontWeight={isNested ? 'font-normal' : undefined}
link={isNested ? link : undefined}
>
<Trans message={channel.name} />
</SiteSectionHeading>
);
}
interface ChannelDescriptionProps {
channel: Channel;
}
function ChannelDescription({channel}: ChannelDescriptionProps) {
if (channel.type === 'channel') {
return <Fragment>{channel.description}</Fragment>;
}
return (
<div className="mt-18 items-center text-sm md:flex">
{channel.user && <UserListByline user={channel.user} />}
<UserListDetails
list={channel}
className="ml-auto max-md:mt-14"
showShareButton
/>
</div>
);
}