feat(ui): Add custom title functionality (#825)

This commit is contained in:
TheCatLady
2021-02-03 05:44:10 -05:00
committed by GitHub
parent 3ffd5ab0ee
commit 35c6bfc021
35 changed files with 162 additions and 42 deletions

View File

@@ -1,5 +1,4 @@
import axios from 'axios';
import Head from 'next/head';
import { useRouter } from 'next/router';
import React, { useContext, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
@@ -18,6 +17,7 @@ import Modal from '../Common/Modal';
import Slider from '../Slider';
import TitleCard from '../TitleCard';
import Transition from '../Transition';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
overviewunavailable: 'Overview unavailable.',
@@ -108,9 +108,7 @@ const CollectionDetails: React.FC<CollectionDetailsProps> = ({
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})`,
}}
>
<Head>
<title>{data.name} - Overseerr</title>
</Head>
<PageTitle title={data.name} />
<Transition
enter="opacity-0 transition duration-300"
enterFrom="opacity-0"

View File

@@ -0,0 +1,22 @@
import React from 'react';
import useSettings from '../../../hooks/useSettings';
import Head from 'next/head';
interface PageTitleProps {
title: string | (string | undefined)[];
}
const PageTitle: React.FC<PageTitleProps> = ({ title }) => {
const settings = useSettings();
return (
<Head>
<title>
{Array.isArray(title) ? title.filter(Boolean).join(' - ') : title} -{' '}
{settings.currentSettings.applicationTitle}
</title>
</Head>
);
};
export default PageTitle;

View File

@@ -3,10 +3,11 @@ import { useSWRInfinite } from 'swr';
import type { MovieResult } from '../../../server/models/Search';
import ListView from '../Common/ListView';
import { LanguageContext } from '../../context/LanguageContext';
import { defineMessages, FormattedMessage } from 'react-intl';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import Header from '../Common/Header';
import useSettings from '../../hooks/useSettings';
import { MediaStatus } from '../../../server/constants/media';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
discovermovies: 'Popular Movies',
@@ -20,6 +21,7 @@ interface SearchResult {
}
const DiscoverMovies: React.FC = () => {
const intl = useIntl();
const settings = useSettings();
const { locale } = useContext(LanguageContext);
const { data, error, size, setSize } = useSWRInfinite<SearchResult>(
@@ -68,6 +70,7 @@ const DiscoverMovies: React.FC = () => {
return (
<>
<PageTitle title={intl.formatMessage(messages.discovermovies)} />
<div className="mt-1 mb-5">
<Header>
<FormattedMessage {...messages.discovermovies} />

View File

@@ -2,11 +2,12 @@ import React, { useContext } from 'react';
import { useSWRInfinite } from 'swr';
import type { TvResult } from '../../../server/models/Search';
import ListView from '../Common/ListView';
import { defineMessages, FormattedMessage } from 'react-intl';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { LanguageContext } from '../../context/LanguageContext';
import Header from '../Common/Header';
import useSettings from '../../hooks/useSettings';
import { MediaStatus } from '../../../server/constants/media';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
discovertv: 'Popular Series',
@@ -20,6 +21,7 @@ interface SearchResult {
}
const DiscoverTv: React.FC = () => {
const intl = useIntl();
const settings = useSettings();
const { locale } = useContext(LanguageContext);
const { data, error, size, setSize } = useSWRInfinite<SearchResult>(
@@ -67,6 +69,7 @@ const DiscoverTv: React.FC = () => {
return (
<>
<PageTitle title={intl.formatMessage(messages.discovertv)} />
<div className="mt-1 mb-5">
<Header>
<FormattedMessage {...messages.discovertv} />

View File

@@ -7,10 +7,11 @@ import type {
} from '../../../server/models/Search';
import ListView from '../Common/ListView';
import { LanguageContext } from '../../context/LanguageContext';
import { defineMessages, FormattedMessage } from 'react-intl';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import Header from '../Common/Header';
import useSettings from '../../hooks/useSettings';
import { MediaStatus } from '../../../server/constants/media';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
trending: 'Trending',
@@ -24,6 +25,7 @@ interface SearchResult {
}
const Trending: React.FC = () => {
const intl = useIntl();
const settings = useSettings();
const { locale } = useContext(LanguageContext);
const { data, error, size, setSize } = useSWRInfinite<SearchResult>(
@@ -74,6 +76,7 @@ const Trending: React.FC = () => {
return (
<>
<PageTitle title={intl.formatMessage(messages.trending)} />
<div className="mt-1 mb-5">
<Header>
<FormattedMessage {...messages.trending} />

View File

@@ -3,10 +3,11 @@ import { useSWRInfinite } from 'swr';
import type { MovieResult } from '../../../server/models/Search';
import ListView from '../Common/ListView';
import { LanguageContext } from '../../context/LanguageContext';
import { defineMessages, FormattedMessage } from 'react-intl';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import Header from '../Common/Header';
import useSettings from '../../hooks/useSettings';
import { MediaStatus } from '../../../server/constants/media';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
upcomingmovies: 'Upcoming Movies',
@@ -20,6 +21,7 @@ interface SearchResult {
}
const UpcomingMovies: React.FC = () => {
const intl = useIntl();
const settings = useSettings();
const { locale } = useContext(LanguageContext);
const { data, error, size, setSize } = useSWRInfinite<SearchResult>(
@@ -69,6 +71,7 @@ const UpcomingMovies: React.FC = () => {
return (
<>
<PageTitle title={intl.formatMessage(messages.upcomingmovies)} />
<div className="mt-1 mb-5">
<Header>
<FormattedMessage {...messages.upcomingmovies} />

View File

@@ -8,8 +8,10 @@ import type { MediaResultsResponse } from '../../../server/interfaces/api/mediaI
import type { RequestResultsResponse } from '../../../server/interfaces/api/requestInterfaces';
import RequestCard from '../RequestCard';
import MediaSlider from '../MediaSlider';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
discover: 'Discover',
recentrequests: 'Recent Requests',
popularmovies: 'Popular Movies',
populartv: 'Popular Series',
@@ -35,6 +37,7 @@ const Discover: React.FC = () => {
return (
<>
<PageTitle title={intl.formatMessage(messages.discover)} />
<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 hover:text-white sm:text-2xl sm:leading-9 sm:truncate">

View File

@@ -176,7 +176,7 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
<div className="flex-shrink-0 flex items-center px-4">
<span className="text-xl text-gray-50">
<a href="/">
<img src="/logo.png" alt="Overseerr Logo" />
<img src="/logo.png" alt="Logo" />
</a>
</span>
</div>
@@ -238,7 +238,7 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
<div className="flex items-center flex-shrink-0 px-4">
<span className="text-2xl text-gray-50">
<a href="/">
<img src="/logo.png" alt="Overseerr Logo" />
<img src="/logo.png" alt="Logo" />
</a>
</span>
</div>

View File

@@ -10,8 +10,10 @@ import LanguagePicker from '../Layout/LanguagePicker';
import LocalLogin from './LocalLogin';
import Accordion from '../Common/Accordion';
import useSettings from '../../hooks/useSettings';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
signin: 'Sign In',
signinheader: 'Sign in to continue',
signinwithplex: 'Use your Plex account',
signinwithoverseerr: 'Use your Overseerr account',
@@ -59,6 +61,7 @@ const Login: React.FC = () => {
return (
<div className="relative flex flex-col min-h-screen bg-gray-900 py-14">
<PageTitle title={intl.formatMessage(messages.signin)} />
<ImageFader
backgroundImages={[
'/images/rotate1.jpg',
@@ -73,11 +76,7 @@ const Login: React.FC = () => {
<LanguagePicker />
</div>
<div className="relative z-40 px-4 sm:mx-auto sm:w-full sm:max-w-md">
<img
src="/logo.png"
className="w-auto mx-auto max-h-32"
alt="Overseerr Logo"
/>
<img src="/logo.png" className="w-auto mx-auto max-h-32" alt="Logo" />
<h2 className="mt-2 text-3xl font-extrabold leading-9 text-center text-gray-100">
<FormattedMessage {...messages.signinheader} />
</h2>

View File

@@ -9,6 +9,7 @@ import Error from '../../../pages/_error';
import Header from '../../Common/Header';
import LoadingSpinner from '../../Common/LoadingSpinner';
import PersonCard from '../../PersonCard';
import PageTitle from '../../Common/PageTitle';
const messages = defineMessages({
fullcast: 'Full Cast',
@@ -32,6 +33,7 @@ const MovieCast: React.FC = () => {
return (
<>
<PageTitle title={[intl.formatMessage(messages.fullcast), data.title]} />
<div className="mt-1 mb-5">
<Header
subtext={

View File

@@ -9,6 +9,7 @@ import Error from '../../../pages/_error';
import Header from '../../Common/Header';
import LoadingSpinner from '../../Common/LoadingSpinner';
import PersonCard from '../../PersonCard';
import PageTitle from '../../Common/PageTitle';
const messages = defineMessages({
fullcrew: 'Full Crew',
@@ -32,6 +33,7 @@ const MovieCrew: React.FC = () => {
return (
<>
<PageTitle title={[intl.formatMessage(messages.fullcrew), data.title]} />
<div className="mt-1 mb-5">
<Header
subtext={

View File

@@ -9,6 +9,7 @@ import { LanguageContext } from '../../context/LanguageContext';
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
import useSettings from '../../hooks/useSettings';
import { MediaStatus } from '../../../server/constants/media';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
recommendations: 'Recommendations',
@@ -77,6 +78,9 @@ const MovieRecommendations: React.FC = () => {
return (
<>
<PageTitle
title={[intl.formatMessage(messages.recommendations), movieData?.title]}
/>
<div className="mt-1 mb-5">
<Header
subtext={

View File

@@ -9,6 +9,7 @@ import type { MovieDetails } from '../../../server/models/Movie';
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
import { MediaStatus } from '../../../server/constants/media';
import useSettings from '../../hooks/useSettings';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
similar: 'Similar Titles',
@@ -77,6 +78,9 @@ const MovieSimilar: React.FC = () => {
return (
<>
<PageTitle
title={[intl.formatMessage(messages.similar), movieData?.title]}
/>
<div className="mt-1 mb-5">
<Header
subtext={

View File

@@ -27,7 +27,6 @@ import RTAudFresh from '../../assets/rt_aud_fresh.svg';
import RTAudRotten from '../../assets/rt_aud_rotten.svg';
import type { RTRating } from '../../../server/api/rottentomatoes';
import Error from '../../pages/_error';
import Head from 'next/head';
import ExternalLinkBlock from '../ExternalLinkBlock';
import { sortCrewPriority } from '../../utils/creditHelpers';
import StatusBadge from '../StatusBadge';
@@ -36,6 +35,7 @@ import MediaSlider from '../MediaSlider';
import ConfirmButton from '../Common/ConfirmButton';
import DownloadBlock from '../DownloadBlock';
import ButtonWithDropdown from '../Common/ButtonWithDropdown';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
releasedate: 'Release Date',
@@ -137,10 +137,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
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})`,
}}
>
<Head>
<title>{data.title} - Overseerr</title>
</Head>
<PageTitle title={data.title} />
<SlideOver
show={showManager}
title={intl.formatMessage(messages.manageModalTitle)}
@@ -181,7 +178,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
<div className="mb-6">
{data?.mediaInfo &&
data?.mediaInfo.status !== MediaStatus.AVAILABLE && (
<div className="flex flex-col sm:flex-row flex-nowrap mb-2">
<div className="flex flex-col mb-2 sm:flex-row flex-nowrap">
<Button
onClick={() => markAvailable()}
className="w-full sm:mb-0"
@@ -205,7 +202,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
)}
{data?.mediaInfo &&
data?.mediaInfo.status4k !== MediaStatus.AVAILABLE && (
<div className="flex flex-col sm:flex-row flex-nowrap mb-2">
<div className="flex flex-col mb-2 sm:flex-row flex-nowrap">
<Button
onClick={() => markAvailable(true)}
className="w-full sm:mb-0"

View File

@@ -12,6 +12,7 @@ import { LanguageContext } from '../../context/LanguageContext';
import ImageFader from '../Common/ImageFader';
import Ellipsis from '../../assets/ellipsis.svg';
import { groupBy } from 'lodash';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
appearsin: 'Appears in',
@@ -172,6 +173,7 @@ const PersonDetails: React.FC = () => {
return (
<>
<PageTitle title={data.name} />
{(sortedCrew || sortedCast) && (
<div className="absolute top-0 left-0 right-0 z-0 h-96">
<ImageFader

View File

@@ -7,6 +7,7 @@ import Header from '../Common/Header';
import Table from '../Common/Table';
import Button from '../Common/Button';
import { defineMessages, useIntl } from 'react-intl';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
requests: 'Requests',
@@ -54,6 +55,7 @@ const RequestList: React.FC = () => {
return (
<>
<PageTitle title={intl.formatMessage(messages.requests)} />
<div className="flex flex-col justify-between md:items-end md:flex-row">
<Header>{intl.formatMessage(messages.requests)}</Header>
<div className="flex flex-col mt-2 md:flex-row">

View File

@@ -10,8 +10,10 @@ import ListView from '../Common/ListView';
import { LanguageContext } from '../../context/LanguageContext';
import { defineMessages, useIntl } from 'react-intl';
import Header from '../Common/Header';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
search: 'Search',
searchresults: 'Search Results',
});
@@ -65,6 +67,7 @@ const Search: React.FC = () => {
return (
<>
<PageTitle title={intl.formatMessage(messages.search)} />
<div className="mt-1 mb-5">
<Header>{intl.formatMessage(messages.searchresults)}</Header>
</div>

View File

@@ -2,8 +2,10 @@ import React from 'react';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { defineMessages, useIntl } from 'react-intl';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
settings: 'Settings',
menuGeneralSettings: 'General Settings',
menuPlexSettings: 'Plex',
menuServices: 'Services',
@@ -91,6 +93,7 @@ const SettingsLayout: React.FC = ({ children }) => {
};
return (
<>
<PageTitle title={intl.formatMessage(messages.settings)} />
<div className="mt-6">
<div className="sm:hidden">
<select

View File

@@ -12,6 +12,7 @@ import { useToasts } from 'react-toast-notifications';
import Badge from '../Common/Badge';
import globalMessages from '../../i18n/globalMessages';
import PermissionEdit from '../PermissionEdit';
import * as Yup from 'yup';
const messages = defineMessages({
generalsettings: 'General Settings',
@@ -20,6 +21,7 @@ const messages = defineMessages({
save: 'Save Changes',
saving: 'Saving…',
apikey: 'API Key',
applicationTitle: 'Application Title',
applicationurl: 'Application URL',
toastApiKeySuccess: 'New API key generated!',
toastApiKeyFailure: 'Something went wrong while generating a new API key.',
@@ -38,6 +40,7 @@ const messages = defineMessages({
localLogin: 'Enable Local User Sign-In',
localLoginTip:
'Disabling this option only prevents new sign-ins (no user data is deleted)',
validationApplicationTitle: 'You must provide an application title',
});
const SettingsMain: React.FC = () => {
@@ -47,6 +50,11 @@ const SettingsMain: React.FC = () => {
const { data, error, revalidate } = useSWR<MainSettings>(
'/api/v1/settings/main'
);
const MainSettingsSchema = Yup.object().shape({
applicationTitle: Yup.string().required(
intl.formatMessage(messages.validationApplicationTitle)
),
});
const regenerate = async () => {
try {
@@ -82,6 +90,7 @@ const SettingsMain: React.FC = () => {
<div className="section">
<Formik
initialValues={{
applicationTitle: data?.applicationTitle,
applicationUrl: data?.applicationUrl,
csrfProtection: data?.csrfProtection,
defaultPermissions: data?.defaultPermissions ?? 0,
@@ -90,9 +99,11 @@ const SettingsMain: React.FC = () => {
trustProxy: data?.trustProxy,
}}
enableReinitialize
validationSchema={MainSettingsSchema}
onSubmit={async (values) => {
try {
await axios.post('/api/v1/settings/main', {
applicationTitle: values.applicationTitle,
applicationUrl: values.applicationUrl,
csrfProtection: values.csrfProtection,
defaultPermissions: values.defaultPermissions,
@@ -115,7 +126,7 @@ const SettingsMain: React.FC = () => {
}
}}
>
{({ isSubmitting, values, setFieldValue }) => {
{({ errors, touched, isSubmitting, values, setFieldValue }) => {
return (
<Form className="section">
{userHasPermission(Permission.ADMIN) && (
@@ -160,6 +171,24 @@ const SettingsMain: React.FC = () => {
</div>
</div>
)}
<div className="form-row">
<label htmlFor="applicationTitle" className="text-label">
{intl.formatMessage(messages.applicationTitle)}
</label>
<div className="form-input">
<div className="flex max-w-lg rounded-md shadow-sm">
<Field
id="applicationTitle"
name="applicationTitle"
type="text"
placeholder="Overseerr"
/>
</div>
{errors.applicationTitle && touched.applicationTitle && (
<div className="error">{errors.applicationTitle}</div>
)}
</div>
</div>
<div className="form-row">
<label htmlFor="applicationUrl" className="text-label">
{intl.formatMessage(messages.applicationurl)}

View File

@@ -10,8 +10,10 @@ import axios from 'axios';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import Badge from '../Common/Badge';
import LanguagePicker from '../Layout/LanguagePicker';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
setup: 'Setup',
finish: 'Finish Setup',
finishing: 'Finishing…',
continue: 'Continue',
@@ -44,6 +46,7 @@ const Setup: React.FC = () => {
return (
<div className="relative flex flex-col justify-center min-h-screen py-12 bg-gray-900">
<PageTitle title={intl.formatMessage(messages.setup)} />
<ImageFader
backgroundImages={[
'/images/rotate1.jpg',
@@ -61,11 +64,11 @@ const Setup: React.FC = () => {
<img
src="/logo.png"
className="w-auto mx-auto mb-10 max-h-32"
alt="Overseerr Logo"
alt="Logo"
/>
<nav className="relative z-50">
<ul
className="bg-gray-800 bg-opacity-50 border border-gray-600 divide-y divide-gray-600 rounded-md md:flex md:divide-y-0"
className="bg-gray-800 bg-opacity-50 border border-gray-600 divide-y divide-gray-600 rounded-md md:flex md:divide-y-0"
style={{ backdropFilter: 'blur(5px)' }}
>
<SetupSteps

View File

@@ -9,6 +9,7 @@ import Error from '../../../pages/_error';
import Header from '../../Common/Header';
import LoadingSpinner from '../../Common/LoadingSpinner';
import PersonCard from '../../PersonCard';
import PageTitle from '../../Common/PageTitle';
const messages = defineMessages({
fullseriescast: 'Full Series Cast',
@@ -32,6 +33,9 @@ const TvCast: React.FC = () => {
return (
<>
<PageTitle
title={[intl.formatMessage(messages.fullseriescast), data.name]}
/>
<div className="mt-1 mb-5">
<Header
subtext={

View File

@@ -9,6 +9,7 @@ import Error from '../../../pages/_error';
import Header from '../../Common/Header';
import LoadingSpinner from '../../Common/LoadingSpinner';
import PersonCard from '../../PersonCard';
import PageTitle from '../../Common/PageTitle';
const messages = defineMessages({
fullseriescrew: 'Full Series Crew',
@@ -32,6 +33,9 @@ const TvCrew: React.FC = () => {
return (
<>
<PageTitle
title={[intl.formatMessage(messages.fullseriescrew), data.name]}
/>
<div className="mt-1 mb-5">
<Header
subtext={

View File

@@ -9,6 +9,7 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { TvDetails } from '../../../server/models/Tv';
import { MediaStatus } from '../../../server/constants/media';
import useSettings from '../../hooks/useSettings';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
recommendations: 'Recommendations',
@@ -77,6 +78,9 @@ const TvRecommendations: React.FC = () => {
return (
<>
<PageTitle
title={[intl.formatMessage(messages.recommendations), tvData?.name]}
/>
<div className="mt-1 mb-5">
<Header
subtext={

View File

@@ -9,6 +9,7 @@ import type { TvDetails } from '../../../server/models/Tv';
import Header from '../Common/Header';
import { MediaStatus } from '../../../server/constants/media';
import useSettings from '../../hooks/useSettings';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
similar: 'Similar Series',
@@ -77,6 +78,7 @@ const TvSimilar: React.FC = () => {
return (
<>
<PageTitle title={[intl.formatMessage(messages.similar), tvData?.name]} />
<div className="mt-1 mb-5">
<Header
subtext={

View File

@@ -27,7 +27,6 @@ import RTRotten from '../../assets/rt_rotten.svg';
import RTAudFresh from '../../assets/rt_aud_fresh.svg';
import RTAudRotten from '../../assets/rt_aud_rotten.svg';
import type { RTRating } from '../../../server/api/rottentomatoes';
import Head from 'next/head';
import { ANIME_KEYWORD_ID } from '../../../server/api/themoviedb/constants';
import ExternalLinkBlock from '../ExternalLinkBlock';
import { sortCrewPriority } from '../../utils/creditHelpers';
@@ -38,6 +37,7 @@ import MediaSlider from '../MediaSlider';
import ConfirmButton from '../Common/ConfirmButton';
import DownloadBlock from '../DownloadBlock';
import ButtonWithDropdown from '../Common/ButtonWithDropdown';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
firstAirDate: 'First Air Date',
@@ -156,9 +156,7 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
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})`,
}}
>
<Head>
<title>{data.name} - Overseerr</title>
</Head>
<PageTitle title={data.name} />
<RequestModal
tmdbId={data.id}
show={showRequestModal}
@@ -209,7 +207,7 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
<div className="mb-6">
{data?.mediaInfo &&
data?.mediaInfo.status !== MediaStatus.AVAILABLE && (
<div className="flex flex-col sm:flex-row flex-nowrap mb-2">
<div className="flex flex-col mb-2 sm:flex-row flex-nowrap">
<Button
onClick={() => markAvailable()}
className="w-full sm:mb-0"
@@ -233,7 +231,7 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
)}
{data?.mediaInfo &&
data?.mediaInfo.status4k !== MediaStatus.AVAILABLE && (
<div className="flex flex-col sm:flex-row flex-nowrap mb-2">
<div className="flex flex-col mb-2 sm:flex-row flex-nowrap">
<Button
onClick={() => markAvailable(true)}
className="w-full sm:mb-0"

View File

@@ -11,6 +11,7 @@ import PermissionEdit from '../PermissionEdit';
import { Field, Form, Formik } from 'formik';
import * as Yup from 'yup';
import { UserType } from '../../../server/constants/user';
import PageTitle from '../Common/PageTitle';
export const messages = defineMessages({
edituser: 'Edit User',
@@ -85,6 +86,7 @@ const UserEdit: React.FC = () => {
>
{({ isSubmitting, handleSubmit }) => (
<Form>
<PageTitle title={intl.formatMessage(messages.edituser)} />
<div>
<div className="flex flex-col justify-between sm:flex-row">
<Header>

View File

@@ -20,8 +20,10 @@ import * as Yup from 'yup';
import AddUserIcon from '../../assets/useradd.svg';
import Alert from '../Common/Alert';
import BulkEditModal from './BulkEditModal';
import PageTitle from '../Common/PageTitle';
const messages = defineMessages({
users: 'Users',
userlist: 'User List',
importfromplex: 'Import Users from Plex',
importfromplexerror: 'Something went wrong while importing users from Plex.',
@@ -178,6 +180,7 @@ const UserList: React.FC = () => {
return (
<>
<PageTitle title={intl.formatMessage(messages.users)} />
<Transition
enter="opacity-0 transition duration-300"
enterFrom="opacity-0"