mirror of
https://github.com/fallenbagel/jellyseerr.git
synced 2026-01-01 12:18:35 -05:00
feat: upgrade tailwindcss to 2.0.1
This commit is contained in:
@@ -14,7 +14,7 @@ const Badge: React.FC<BadgeProps> = ({ badgeType = 'default', children }) => {
|
||||
badgeStyle.push('bg-red-600 text-red-100');
|
||||
break;
|
||||
case 'warning':
|
||||
badgeStyle.push('bg-orange-500 text-orange-100');
|
||||
badgeStyle.push('bg-yellow-500 text-yellow-100');
|
||||
break;
|
||||
case 'success':
|
||||
badgeStyle.push('bg-green-400 text-green-100');
|
||||
|
||||
@@ -26,32 +26,32 @@ const Button: React.FC<ButtonProps> = ({
|
||||
switch (buttonType) {
|
||||
case 'primary':
|
||||
buttonStyle.push(
|
||||
'text-white bg-indigo-600 hover:bg-indigo-500 focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 disabled:opacity-50'
|
||||
'text-white bg-indigo-600 hover:bg-indigo-500 focus:border-indigo-700 focus:ring-indigo active:bg-indigo-700 disabled:opacity-50'
|
||||
);
|
||||
break;
|
||||
case 'danger':
|
||||
buttonStyle.push(
|
||||
'text-white bg-red-600 hover:bg-red-500 focus:border-red-700 focus:shadow-outline-red active:bg-red-700 disabled:opacity-50'
|
||||
'text-white bg-red-600 hover:bg-red-500 focus:border-red-700 focus:ring-red active:bg-red-700 disabled:opacity-50'
|
||||
);
|
||||
break;
|
||||
case 'warning':
|
||||
buttonStyle.push(
|
||||
'text-white bg-orange-500 hover:bg-orange-400 focus:border-orange-700 focus:shadow-outline-orange active:bg-orange-700 disabled:opacity-50'
|
||||
'text-white bg-yellow-500 hover:bg-yellow-400 focus:border-yellow-700 focus:ring-yellow active:bg-yellow-700 disabled:opacity-50'
|
||||
);
|
||||
break;
|
||||
case 'success':
|
||||
buttonStyle.push(
|
||||
'text-white bg-green-400 hover:bg-green-300 focus:border-green-700 focus:shadow-outline-green active:bg-green-700 disabled:opacity-50'
|
||||
'text-white bg-green-400 hover:bg-green-300 focus:border-green-700 focus:ring-green active:bg-green-700 disabled:opacity-50'
|
||||
);
|
||||
break;
|
||||
case 'ghost':
|
||||
buttonStyle.push(
|
||||
'text-white bg-transaprent border border-cool-gray-600 hover:border-cool-gray-200 focus:border-cool-gray-100 active:border-cool-gray-100 disabled:opacity-50'
|
||||
'text-white bg-transaprent border border-gray-600 hover:border-gray-200 focus:border-gray-100 active:border-gray-100 disabled:opacity-50'
|
||||
);
|
||||
break;
|
||||
default:
|
||||
buttonStyle.push(
|
||||
'leading-5 font-medium rounded-md text-gray-200 bg-cool-gray-500 hover:bg-cool-gray-400 hover:text-white focus:border-blue-300 focus:shadow-outline-blue active:text-gray-200 active:bg-cool-gray-400 disabled:opacity-50'
|
||||
'leading-5 font-medium rounded-md text-gray-200 bg-gray-500 hover:bg-gray-400 hover:text-white focus:border-blue-300 focus:ring-blue active:text-gray-200 active:bg-gray-400 disabled:opacity-50'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ const ButtonWithDropdown: React.FC<ButtonWithDropdownProps> = ({
|
||||
<span className="relative z-0 inline-flex shadow-sm rounded-md">
|
||||
<button
|
||||
type="button"
|
||||
className={`relative inline-flex items-center px-4 py-2 text-white bg-indigo-600 hover:bg-indigo-500 text-sm leading-5 font-medium hover:text-white focus:shadow-outline-indigo active:bg-indigo-700 focus:z-10 focus:outline-none focus:shadow-outline-blue transition ease-in-out duration-150 ${
|
||||
className={`relative inline-flex items-center px-4 py-2 text-white bg-indigo-600 hover:bg-indigo-500 text-sm leading-5 font-medium hover:text-white focus:ring-indigo active:bg-indigo-700 focus:z-10 focus:outline-none focus:ring-blue transition ease-in-out duration-150 ${
|
||||
children ? 'rounded-l-md' : 'rounded-md'
|
||||
}`}
|
||||
ref={buttonRef}
|
||||
@@ -53,7 +53,7 @@ const ButtonWithDropdown: React.FC<ButtonWithDropdownProps> = ({
|
||||
{children && (
|
||||
<button
|
||||
type="button"
|
||||
className="relative inline-flex items-center px-2 py-2 rounded-r-md bg-indigo-700 hover:bg-indigo-500 text-sm leading-5 font-medium text-white focus:z-10 focus:outline-none active:bg-indigo-700 border border-indigo-600 focus:shadow-outline-blue transition ease-in-out duration-150"
|
||||
className="relative inline-flex items-center px-2 py-2 rounded-r-md bg-indigo-700 hover:bg-indigo-500 text-sm leading-5 font-medium text-white focus:z-10 focus:outline-none active:bg-indigo-700 border border-indigo-600 focus:ring-blue transition ease-in-out duration-150"
|
||||
aria-label="Expand"
|
||||
onClick={() => setIsOpen((state) => !state)}
|
||||
>
|
||||
@@ -85,7 +85,7 @@ const ButtonWithDropdown: React.FC<ButtonWithDropdownProps> = ({
|
||||
leaveTo="transform opacity-0 scale-95"
|
||||
>
|
||||
<div className="origin-top-right absolute right-0 mt-2 -mr-1 w-56 rounded-md shadow-lg">
|
||||
<div className="rounded-md bg-indigo-600 shadow-xs">
|
||||
<div className="rounded-md bg-indigo-600 ring-1 ring-black ring-opacity-5">
|
||||
<div className="py-1">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,12 +13,12 @@ const Header: React.FC<HeaderProps> = ({
|
||||
return (
|
||||
<div className="md:flex md:items-center md:justify-between mt-8 mb-8">
|
||||
<div className={`flex-1 min-w-0 mx-${extraMargin}`}>
|
||||
<h2 className="text-2xl font-bold leading-7 text-cool-gray-100 sm:text-4xl sm:leading-9 truncate sm:overflow-visible">
|
||||
<h2 className="text-2xl font-bold leading-7 text-gray-100 sm:text-4xl sm:leading-9 truncate sm:overflow-visible">
|
||||
<span className="bg-clip-text text-transparent bg-gradient-to-br from-indigo-400 to-purple-400">
|
||||
{children}
|
||||
</span>
|
||||
</h2>
|
||||
{subtext && <div className="text-cool-gray-400 mt-2">{subtext}</div>}
|
||||
{subtext && <div className="text-gray-400 mt-2">{subtext}</div>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -27,7 +27,7 @@ const ListView: React.FC<ListViewProps> = ({
|
||||
return (
|
||||
<>
|
||||
{isEmpty && (
|
||||
<div className="w-full mt-64 text-2xl text-center text-cool-gray-400">
|
||||
<div className="w-full mt-64 text-2xl text-center text-gray-400">
|
||||
No Results
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
|
||||
const LoadingSpinner: React.FC = () => {
|
||||
return (
|
||||
<div className="h-64 inset-0 flex justify-center items-center text-cool-gray-200">
|
||||
<div className="h-64 inset-0 flex justify-center items-center text-gray-200">
|
||||
<svg
|
||||
className="w-16 h-16"
|
||||
viewBox="0 0 38 38"
|
||||
|
||||
@@ -77,7 +77,7 @@ const Modal: React.FC<ModalProps> = ({
|
||||
<>
|
||||
{ReactDOM.createPortal(
|
||||
<animated.div
|
||||
className="fixed top-0 left-0 right-0 bottom-0 bg-cool-gray-800 bg-opacity-50 w-full h-full z-50 flex justify-center items-center"
|
||||
className="fixed top-0 left-0 right-0 bottom-0 bg-gray-800 bg-opacity-50 w-full h-full z-50 flex justify-center items-center"
|
||||
style={props.style}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Escape') {
|
||||
@@ -103,7 +103,7 @@ const Modal: React.FC<ModalProps> = ({
|
||||
item && (
|
||||
<animated.div
|
||||
style={props}
|
||||
className="inline-block align-bottom bg-cool-gray-700 sm:rounded-lg px-4 pt-5 pb-4 text-left overflow-auto shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-3xl w-full sm:p-6 max-h-full"
|
||||
className="inline-block align-bottom bg-gray-700 sm:rounded-lg px-4 pt-5 pb-4 text-left overflow-auto shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-3xl w-full sm:p-6 max-h-full"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline"
|
||||
@@ -112,7 +112,7 @@ const Modal: React.FC<ModalProps> = ({
|
||||
>
|
||||
<div className="sm:flex sm:items-center">
|
||||
{iconSvg && (
|
||||
<div className="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-cool-gray-600 text-white sm:mx-0 sm:h-10 sm:w-10">
|
||||
<div className="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-gray-600 text-white sm:mx-0 sm:h-10 sm:w-10">
|
||||
{iconSvg}
|
||||
</div>
|
||||
)}
|
||||
@@ -132,7 +132,7 @@ const Modal: React.FC<ModalProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
{children && (
|
||||
<div className="mt-4 text-sm leading-5 text-cool-gray-300">
|
||||
<div className="mt-4 text-sm leading-5 text-gray-300">
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -46,7 +46,7 @@ const SlideOver: React.FC<SlideOverProps> = ({
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div
|
||||
className={`z-50 fixed inset-0 overflow-hidden bg-opacity-50 bg-cool-gray-800`}
|
||||
className={`z-50 fixed inset-0 overflow-hidden bg-opacity-50 bg-gray-800`}
|
||||
>
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<section className="absolute inset-y-0 right-0 pl-10 max-w-full flex">
|
||||
@@ -61,7 +61,7 @@ const SlideOver: React.FC<SlideOverProps> = ({
|
||||
leaveTo="translate-x-full"
|
||||
>
|
||||
<div className="w-screen max-w-md" ref={slideoverRef}>
|
||||
<div className="h-full flex flex-col bg-cool-gray-700 shadow-xl overflow-y-scroll">
|
||||
<div className="h-full flex flex-col bg-gray-700 shadow-xl overflow-y-scroll">
|
||||
<header className="space-y-1 py-6 px-4 bg-indigo-600 sm:px-6">
|
||||
<div className="flex items-center justify-between space-x-3">
|
||||
<h2 className="text-lg leading-7 font-medium text-white">
|
||||
|
||||
@@ -77,7 +77,7 @@ const Discover: React.FC = () => {
|
||||
<>
|
||||
<div className="md:flex md:items-center md:justify-between mb-4 mt-6">
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<div className="inline-flex text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<span>
|
||||
<FormattedMessage {...messages.recentlyAdded} />
|
||||
</span>
|
||||
@@ -99,7 +99,7 @@ const Discover: React.FC = () => {
|
||||
<div className="md:flex md:items-center md:justify-between mb-4 mt-6">
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link href="/requests">
|
||||
<a className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<a className="inline-flex text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<span>
|
||||
<FormattedMessage {...messages.recentrequests} />
|
||||
</span>
|
||||
@@ -137,7 +137,7 @@ const Discover: React.FC = () => {
|
||||
<div className="md:flex md:items-center md:justify-between mb-4 mt-6">
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link href="/discover/movies/upcoming">
|
||||
<a className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<a className="inline-flex text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<span>
|
||||
<FormattedMessage {...messages.upcoming} />
|
||||
</span>
|
||||
@@ -180,7 +180,7 @@ const Discover: React.FC = () => {
|
||||
<div className="md:flex md:items-center md:justify-between mb-4 mt-6">
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link href="/discover/trending">
|
||||
<a className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<a className="inline-flex text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<span>
|
||||
<FormattedMessage {...messages.trending} />
|
||||
</span>
|
||||
@@ -244,7 +244,7 @@ const Discover: React.FC = () => {
|
||||
<div className="md:flex md:items-center md:justify-between mb-4 mt-6">
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link href="/discover/movies">
|
||||
<a className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<a className="inline-flex text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<span>
|
||||
<FormattedMessage {...messages.popularmovies} />
|
||||
</span>
|
||||
@@ -287,7 +287,7 @@ const Discover: React.FC = () => {
|
||||
<div className="md:flex md:items-center md:justify-between mb-4 mt-4">
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link href="/discover/tv">
|
||||
<a className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<a className="inline-flex text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<span>
|
||||
<FormattedMessage {...messages.populartv} />
|
||||
</span>
|
||||
|
||||
@@ -37,7 +37,7 @@ const LanguagePicker: React.FC = () => {
|
||||
<div className="ml-3 relative">
|
||||
<div>
|
||||
<button
|
||||
className="p-1 text-gray-400 rounded-full hover:bg-cool-gray-500 hover:text-white focus:outline-none focus:shadow-outline focus:text-white"
|
||||
className="p-1 text-gray-400 rounded-full hover:bg-gray-500 hover:text-white focus:outline-none focus:ring focus:text-white"
|
||||
aria-label="Language Picker"
|
||||
onClick={() => setDropdownOpen(true)}
|
||||
>
|
||||
@@ -68,17 +68,17 @@ const LanguagePicker: React.FC = () => {
|
||||
className="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg"
|
||||
ref={dropdownRef}
|
||||
>
|
||||
<div className="py-2 px-2 rounded-md bg-cool-gray-700 shadow-xs">
|
||||
<div className="py-2 px-2 rounded-md bg-gray-700 ring-1 ring-black ring-opacity-5">
|
||||
<div>
|
||||
<label
|
||||
htmlFor="language"
|
||||
className="block text-sm leading-5 font-medium text-cool-gray-300 pb-2"
|
||||
className="block text-sm leading-5 font-medium text-gray-300 pb-2"
|
||||
>
|
||||
<FormattedMessage {...messages.changelanguage} />
|
||||
</label>
|
||||
<select
|
||||
id="language"
|
||||
className="mt-1 form-select block w-full pl-3 pr-10 py-2 text-base leading-6 text-white bg-cool-gray-700 border-cool-gray-600 focus:outline-none focus:shadow-outline-indigo focus:border-blue-800 sm:text-sm sm:leading-5"
|
||||
className="mt-1 form-select block w-full pl-3 pr-10 py-2 text-base leading-6 text-white bg-gray-700 border-gray-600 focus:outline-none focus:ring-indigo focus:border-blue-800 sm:text-sm sm:leading-5"
|
||||
onChange={(e) =>
|
||||
setLocale && setLocale(e.target.value as AvailableLocales)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from 'react';
|
||||
const Notifications: React.FC = () => {
|
||||
return (
|
||||
<button
|
||||
className="p-1 text-gray-400 rounded-full hover:bg-cool-gray-500 hover:text-white focus:outline-none focus:shadow-outline focus:text-white"
|
||||
className="p-1 text-gray-400 rounded-full hover:bg-gray-500 hover:text-white focus:outline-none focus:ring focus:text-white"
|
||||
aria-label="Notifications"
|
||||
>
|
||||
<svg
|
||||
|
||||
@@ -27,7 +27,7 @@ const SearchInput: React.FC = () => {
|
||||
</div>
|
||||
<input
|
||||
id="search_field"
|
||||
className="block w-full h-full pl-8 pr-3 py-2 rounded-md bg-cool-gray-600 text-white placeholder-gray-300 focus:outline-none focus:placeholder-gray-400 sm:text-base"
|
||||
className="block w-full h-full pl-8 pr-3 py-2 rounded-md border-transparent focus:border-transparent bg-gray-600 text-white placeholder-gray-300 focus:outline-none focus:ring-0 focus:placeholder-gray-400 sm:text-base"
|
||||
placeholder={intl.formatMessage(messages.searchPlaceholder)}
|
||||
type="search"
|
||||
value={searchValue}
|
||||
|
||||
@@ -168,7 +168,7 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
|
||||
</div>
|
||||
<div className="flex-1 h-0 pt-5 pb-4 overflow-y-auto">
|
||||
<div className="flex-shrink-0 flex items-center px-4">
|
||||
<span className="text-xl text-cool-gray-50">
|
||||
<span className="text-xl text-gray-50">
|
||||
<Link href="/">
|
||||
<a>
|
||||
<img src="/logo.png" alt="Overseerr Logo" />
|
||||
@@ -232,7 +232,7 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
|
||||
<div className="flex flex-col h-0 flex-1 bg-gray-800">
|
||||
<div className="flex-1 flex flex-col pt-5 pb-4 overflow-y-auto">
|
||||
<div className="flex items-center flex-shrink-0 px-4">
|
||||
<span className="text-2xl text-cool-gray-50">
|
||||
<span className="text-2xl text-gray-50">
|
||||
<Link href="/">
|
||||
<a>
|
||||
<img src="/logo.png" alt="Overseerr Logo" />
|
||||
|
||||
@@ -22,7 +22,7 @@ const UserDropdown: React.FC = () => {
|
||||
<div className="ml-3 relative">
|
||||
<div>
|
||||
<button
|
||||
className="max-w-xs flex items-center text-sm rounded-full focus:outline-none focus:shadow-outline"
|
||||
className="max-w-xs flex items-center text-sm rounded-full focus:outline-none focus:ring"
|
||||
id="user-menu"
|
||||
aria-label="User menu"
|
||||
aria-haspopup="true"
|
||||
@@ -45,7 +45,7 @@ const UserDropdown: React.FC = () => {
|
||||
ref={dropdownRef}
|
||||
>
|
||||
<div
|
||||
className="py-1 rounded-md bg-cool-gray-700 shadow-xs"
|
||||
className="py-1 rounded-md bg-gray-700 ring-1 ring-black ring-opacity-5"
|
||||
role="menu"
|
||||
aria-orientation="vertical"
|
||||
aria-labelledby="user-menu"
|
||||
|
||||
@@ -11,11 +11,11 @@ const Layout: React.FC = ({ children }) => {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<div className="min-h-full h-full flex bg-cool-gray-900">
|
||||
<div className="min-h-full h-full flex bg-gray-900">
|
||||
<Sidebar open={isSidebarOpen} setClosed={() => setSidebarOpen(false)} />
|
||||
|
||||
<div className="flex flex-col w-0 flex-1 md:ml-64 relative mb-16">
|
||||
<div className="z-10 flex-shrink-0 flex h-16 bg-cool-gray-600 shadow fixed right-0 left-0 md:left-64">
|
||||
<div className="z-10 flex-shrink-0 flex h-16 bg-gray-600 shadow fixed right-0 left-0 md:left-64">
|
||||
<button
|
||||
className="px-4 border-r border-gray-800 text-gray-200 focus:outline-none focus:bg-gray-300 focus:text-gray-600 md:hidden"
|
||||
aria-label="Open sidebar"
|
||||
@@ -77,7 +77,7 @@ const Layout: React.FC = ({ children }) => {
|
||||
<p className="mt-3 text-sm leading-5 md:mt-0 md:ml-6">
|
||||
<a
|
||||
href="http://github.com/sct/overseerr"
|
||||
className="whitespace-no-wrap font-medium text-indigo-100 hover:text-white transition ease-in-out duration-150"
|
||||
className="whitespace-nowrap font-medium text-indigo-100 hover:text-white transition ease-in-out duration-150"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
|
||||
@@ -35,7 +35,7 @@ const Login: React.FC = () => {
|
||||
}, [user, router]);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-cool-gray-900 flex flex-col justify-center py-12 sm:px-6 lg:px-8 relative">
|
||||
<div className="min-h-screen bg-gray-900 flex flex-col justify-center py-12 sm:px-6 lg:px-8 relative">
|
||||
<ImageFader
|
||||
backgroundImages={[
|
||||
'/images/rotate1.jpg',
|
||||
@@ -50,13 +50,13 @@ const Login: React.FC = () => {
|
||||
className="mx-auto max-h-32 w-auto"
|
||||
alt="Overseerr Logo"
|
||||
/>
|
||||
<h2 className="mt-2 text-center text-3xl leading-9 font-extrabold text-cool-gray-100">
|
||||
<h2 className="mt-2 text-center text-3xl leading-9 font-extrabold text-gray-100">
|
||||
Log in to continue
|
||||
</h2>
|
||||
</div>
|
||||
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md relative z-50">
|
||||
<div
|
||||
className="bg-cool-gray-800 bg-opacity-50 py-8 px-4 shadow sm:rounded-lg sm:px-10"
|
||||
className="bg-gray-800 bg-opacity-50 py-8 px-4 shadow sm:rounded-lg sm:px-10"
|
||||
style={{ backdropFilter: 'blur(5px)' }}
|
||||
>
|
||||
<PlexLoginButton
|
||||
|
||||
@@ -125,7 +125,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
className="bg-cover bg-center -mx-4 -mt-2 px-4 sm:px-8 pt-4 "
|
||||
style={{
|
||||
height: 493,
|
||||
backgroundImage: `linear-gradient(180deg, rgba(45, 55, 72, 0.47) 0%, #1A202E 100%), url(//image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data.backdropPath})`,
|
||||
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})`,
|
||||
}}
|
||||
>
|
||||
<RequestModal
|
||||
@@ -145,20 +145,18 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
subText={data.title}
|
||||
>
|
||||
<h3 className="text-xl mb-2">Requests</h3>
|
||||
<div className="bg-cool-gray-600 shadow overflow-hidden rounded-md">
|
||||
<div className="bg-gray-600 shadow overflow-hidden rounded-md">
|
||||
<ul>
|
||||
{data.mediaInfo?.requests?.map((request) => (
|
||||
<li
|
||||
key={`manage-request-${request.id}`}
|
||||
className="border-b last:border-b-0 border-cool-gray-700"
|
||||
className="border-b last:border-b-0 border-gray-700"
|
||||
>
|
||||
<RequestBlock request={request} onUpdate={() => revalidate()} />
|
||||
</li>
|
||||
))}
|
||||
{(data.mediaInfo?.requests ?? []).length === 0 && (
|
||||
<li className="text-center py-4 text-cool-gray-400">
|
||||
No requests
|
||||
</li>
|
||||
<li className="text-center py-4 text-gray-400">No requests</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
@@ -171,7 +169,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
>
|
||||
Clear All Media Data
|
||||
</Button>
|
||||
<div className="text-sm text-cool-gray-400 mt-2">
|
||||
<div className="text-sm text-gray-400 mt-2">
|
||||
This will remove all media data including all requests for this
|
||||
item. This action is irreversible. If this item exists in your
|
||||
Plex library, the media information will be recreated next sync.
|
||||
@@ -373,9 +371,9 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full md:w-80 mt-8 md:mt-0">
|
||||
<div className="bg-cool-gray-900 rounded-lg shadow border border-cool-gray-800">
|
||||
<div className="bg-gray-900 rounded-lg shadow border border-gray-800">
|
||||
{(data.voteCount > 0 || ratingData) && (
|
||||
<div className="flex px-4 py-2 border-b border-cool-gray-800 last:border-b-0 items-center justify-center">
|
||||
<div className="flex px-4 py-2 border-b border-gray-800 last:border-b-0 items-center justify-center">
|
||||
{ratingData?.criticsRating && (
|
||||
<>
|
||||
<span className="text-sm">
|
||||
@@ -385,7 +383,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
<RTFresh className="w-6 mr-1" />
|
||||
)}
|
||||
</span>
|
||||
<span className="text-cool-gray-400 text-sm mr-4 last:mr-0">
|
||||
<span className="text-gray-400 text-sm mr-4 last:mr-0">
|
||||
{ratingData.criticsScore}%
|
||||
</span>
|
||||
</>
|
||||
@@ -399,7 +397,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
<RTAudFresh className="w-6 mr-1" />
|
||||
)}
|
||||
</span>
|
||||
<span className="text-cool-gray-400 text-sm mr-4 last:mr-0">
|
||||
<span className="text-gray-400 text-sm mr-4 last:mr-0">
|
||||
{ratingData.audienceScore}%
|
||||
</span>
|
||||
</>
|
||||
@@ -409,18 +407,18 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
<span className="text-sm">
|
||||
<TmdbLogo className="w-6 mr-2" />
|
||||
</span>
|
||||
<span className="text-cool-gray-400 text-sm">
|
||||
<span className="text-gray-400 text-sm">
|
||||
{data.voteAverage}/10
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex px-4 py-2 border-b border-cool-gray-800 last:border-b-0">
|
||||
<div className="flex px-4 py-2 border-b border-gray-800 last:border-b-0">
|
||||
<span className="text-sm">
|
||||
<FormattedMessage {...messages.releasedate} />
|
||||
</span>
|
||||
<span className="flex-1 text-right text-cool-gray-400 text-sm">
|
||||
<span className="flex-1 text-right text-gray-400 text-sm">
|
||||
<FormattedDate
|
||||
value={new Date(data.releaseDate)}
|
||||
year="numeric"
|
||||
@@ -429,20 +427,20 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex px-4 py-2 border-b border-cool-gray-800 last:border-b-0">
|
||||
<div className="flex px-4 py-2 border-b border-gray-800 last:border-b-0">
|
||||
<span className="text-sm">
|
||||
<FormattedMessage {...messages.status} />
|
||||
</span>
|
||||
<span className="flex-1 text-right text-cool-gray-400 text-sm">
|
||||
<span className="flex-1 text-right text-gray-400 text-sm">
|
||||
{data.status}
|
||||
</span>
|
||||
</div>
|
||||
{data.revenue > 0 && (
|
||||
<div className="flex px-4 py-2 border-b border-cool-gray-800 last:border-b-0">
|
||||
<div className="flex px-4 py-2 border-b border-gray-800 last:border-b-0">
|
||||
<span className="text-sm">
|
||||
<FormattedMessage {...messages.revenue} />
|
||||
</span>
|
||||
<span className="flex-1 text-right text-cool-gray-400 text-sm">
|
||||
<span className="flex-1 text-right text-gray-400 text-sm">
|
||||
<FormattedNumber
|
||||
currency="USD"
|
||||
style="currency"
|
||||
@@ -452,11 +450,11 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
</div>
|
||||
)}
|
||||
{data.budget > 0 && (
|
||||
<div className="flex px-4 py-2 border-b border-cool-gray-800 last:border-b-0">
|
||||
<div className="flex px-4 py-2 border-b border-gray-800 last:border-b-0">
|
||||
<span className="text-sm">
|
||||
<FormattedMessage {...messages.budget} />
|
||||
</span>
|
||||
<span className="flex-1 text-right text-cool-gray-400 text-sm">
|
||||
<span className="flex-1 text-right text-gray-400 text-sm">
|
||||
<FormattedNumber
|
||||
currency="USD"
|
||||
style="currency"
|
||||
@@ -465,11 +463,11 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex px-4 py-2 border-b border-cool-gray-800 last:border-b-0">
|
||||
<div className="flex px-4 py-2 border-b border-gray-800 last:border-b-0">
|
||||
<span className="text-sm">
|
||||
<FormattedMessage {...messages.originallanguage} />
|
||||
</span>
|
||||
<span className="flex-1 text-right text-cool-gray-400 text-sm">
|
||||
<span className="flex-1 text-right text-gray-400 text-sm">
|
||||
{data.originalLanguage}
|
||||
</span>
|
||||
</div>
|
||||
@@ -479,7 +477,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
<div className="md:flex md:items-center md:justify-between mb-4 mt-6">
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link href="/movie/[movieId]/cast" as={`/movie/${data.id}/cast`}>
|
||||
<a className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<a className="inline-flex text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<span>
|
||||
<FormattedMessage {...messages.cast} />
|
||||
</span>
|
||||
@@ -522,7 +520,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
href="/movie/[movieId]/recommendations"
|
||||
as={`/movie/${data.id}/recommendations`}
|
||||
>
|
||||
<a className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<a className="inline-flex text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<span>
|
||||
<FormattedMessage {...messages.recommendations} />
|
||||
</span>
|
||||
@@ -572,7 +570,7 @@ const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => {
|
||||
href="/movie/[movieId]/similar"
|
||||
as={`/movie/${data.id}/similar`}
|
||||
>
|
||||
<a className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<a className="inline-flex text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<span>
|
||||
<FormattedMessage {...messages.similar} />
|
||||
</span>
|
||||
|
||||
@@ -35,12 +35,12 @@ const PendingRequest: React.FC<PendingRequestProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-cool-gray-900 border border-cool-gray-800 sm:rounded-lg mb-6 shadow rounded-lg">
|
||||
<div className="bg-gray-900 border border-gray-800 sm:rounded-lg mb-6 shadow rounded-lg">
|
||||
<div className="px-4 py-5 sm:p-6">
|
||||
<h3 className="text-lg leading-6 font-medium text-cool-gray-100">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-100">
|
||||
<FormattedMessage {...messages.pendingtitle} />
|
||||
</h3>
|
||||
<div className="mt-2 max-w-xl text-sm leading-5 text-cool-gray-400">
|
||||
<div className="mt-2 max-w-xl text-sm leading-5 text-gray-400">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
{...messages.pendingdescription}
|
||||
|
||||
@@ -17,7 +17,7 @@ const PersonCard: React.FC<PersonCardProps> = ({
|
||||
<div
|
||||
className={`relative ${
|
||||
canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'
|
||||
} bg-cool-gray-600 rounded-lg text-white shadow-lg hover:bg-cool-gray-500 transition ease-in-out duration-150 cursor-pointer`}
|
||||
} bg-gray-600 rounded-lg text-white shadow-lg hover:bg-gray-500 transition ease-in-out duration-150 cursor-pointer`}
|
||||
>
|
||||
<div style={{ paddingBottom: '150%' }}>
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center">
|
||||
@@ -45,7 +45,7 @@ const PersonCard: React.FC<PersonCardProps> = ({
|
||||
)}
|
||||
<div className="whitespace-normal text-center">{name}</div>
|
||||
{subName && (
|
||||
<div className="whitespace-normal text-center text-sm text-cool-gray-300">
|
||||
<div className="whitespace-normal text-center text-sm text-gray-300">
|
||||
{subName}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -210,7 +210,7 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
|
||||
<table className="min-w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="px-4 py-3 bg-cool-gray-500 w-16">
|
||||
<th className="px-4 py-3 bg-gray-500 w-16">
|
||||
<span
|
||||
role="checkbox"
|
||||
tabIndex={0}
|
||||
@@ -233,22 +233,22 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
|
||||
aria-hidden="true"
|
||||
className={`${
|
||||
isAllSeasons() ? 'translate-x-5' : 'translate-x-0'
|
||||
} absolute left-0 inline-block h-5 w-5 border border-gray-200 rounded-full bg-white shadow transform group-focus:shadow-outline group-focus:border-blue-300 transition-transform ease-in-out duration-200`}
|
||||
} absolute left-0 inline-block h-5 w-5 border border-gray-200 rounded-full bg-white shadow transform group-focus:ring group-focus:border-blue-300 transition-transform ease-in-out duration-200`}
|
||||
></span>
|
||||
</span>
|
||||
</th>
|
||||
<th className="px-6 py-3 bg-cool-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
Season
|
||||
</th>
|
||||
<th className="px-6 py-3 bg-cool-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
# Of Episodes
|
||||
</th>
|
||||
<th className="px-6 py-3 bg-cool-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
Status
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="bg-cool-gray-600 divide-y">
|
||||
<tbody className="bg-gray-600 divide-y">
|
||||
{data?.seasons
|
||||
.filter((season) => season.seasonNumber !== 0)
|
||||
.map((season) => {
|
||||
@@ -260,7 +260,7 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
|
||||
);
|
||||
return (
|
||||
<tr key={`season-${season.id}`}>
|
||||
<td className="px-4 py-4 whitespace-no-wrap text-sm leading-5 font-medium text-gray-100">
|
||||
<td className="px-4 py-4 whitespace-nowrap text-sm leading-5 font-medium text-gray-100">
|
||||
<span
|
||||
role="checkbox"
|
||||
tabIndex={0}
|
||||
@@ -297,19 +297,19 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
|
||||
isSelectedSeason(season.seasonNumber)
|
||||
? 'translate-x-5'
|
||||
: 'translate-x-0'
|
||||
} absolute left-0 inline-block h-5 w-5 border border-gray-200 rounded-full bg-white shadow transform group-focus:shadow-outline group-focus:border-blue-300 transition-transform ease-in-out duration-200`}
|
||||
} absolute left-0 inline-block h-5 w-5 border border-gray-200 rounded-full bg-white shadow transform group-focus:ring group-focus:border-blue-300 transition-transform ease-in-out duration-200`}
|
||||
></span>
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-no-wrap text-sm leading-5 font-medium text-gray-100">
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm leading-5 font-medium text-gray-100">
|
||||
{season.seasonNumber === 0
|
||||
? 'Extras'
|
||||
: `Season ${season.seasonNumber}`}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-200">
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-200">
|
||||
{season.episodeCount}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-200">
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-200">
|
||||
{!seasonRequest && !mediaSeason && (
|
||||
<Badge>Not Requested</Badge>
|
||||
)}
|
||||
|
||||
@@ -68,13 +68,13 @@ const Search: React.FC = () => {
|
||||
<span className="relative z-0 inline-flex shadow-sm rounded-md">
|
||||
<button
|
||||
type="button"
|
||||
className="relative inline-flex items-center px-4 py-2 rounded-l-md border border-indigo-900 bg-indigo-500 hover:bg-indigo-400 text-sm leading-5 font-medium text-cool-gray-100 hover:text-white focus:z-10 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150"
|
||||
className="relative inline-flex items-center px-4 py-2 rounded-l-md border border-indigo-900 bg-indigo-500 hover:bg-indigo-400 text-sm leading-5 font-medium text-gray-100 hover:text-white focus:z-10 focus:outline-none focus:border-blue-300 focus:ring-blue active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150"
|
||||
>
|
||||
Movies
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="-ml-px relative inline-flex items-center px-4 py-2 rounded-r-md border border-indigo-900 bg-indigo-500 text-sm leading-5 font-medium text-cool-gray-100 hover:text-white focus:z-10 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150"
|
||||
className="-ml-px relative inline-flex items-center px-4 py-2 rounded-r-md border border-indigo-900 bg-indigo-500 text-sm leading-5 font-medium text-gray-100 hover:text-white focus:z-10 focus:outline-none focus:border-blue-300 focus:ring-blue active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150"
|
||||
>
|
||||
TV Shows
|
||||
</button>
|
||||
|
||||
@@ -20,7 +20,7 @@ const CopyButton: React.FC<{ textToCopy: string }> = ({ textToCopy }) => {
|
||||
return (
|
||||
<button
|
||||
onClick={setCopied}
|
||||
className="-ml-px relative inline-flex items-center px-4 py-2 border border-cool-gray-500 text-sm leading-5 font-medium text-white bg-indigo-500 hover:bg-indigo-400 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150"
|
||||
className="-ml-px relative inline-flex items-center px-4 py-2 border border-gray-500 text-sm leading-5 font-medium text-white bg-indigo-500 hover:bg-indigo-400 focus:outline-none focus:ring-blue focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5 text-white"
|
||||
|
||||
@@ -13,7 +13,7 @@ const LibraryItem: React.FC<LibraryItemProps> = ({
|
||||
}) => {
|
||||
return (
|
||||
<li className="col-span-1 flex shadow-sm rounded-md">
|
||||
<div className="flex-1 flex items-center justify-between border-t border-r border-b border-cool-gray-700 bg-cool-gray-600 rounded-md truncate">
|
||||
<div className="flex-1 flex items-center justify-between border-t border-r border-b border-gray-700 bg-gray-600 rounded-md truncate">
|
||||
<div className="flex-1 px-4 py-6 text-sm leading-5 truncate cursor-default">
|
||||
{name}
|
||||
</div>
|
||||
@@ -29,8 +29,8 @@ const LibraryItem: React.FC<LibraryItemProps> = ({
|
||||
}
|
||||
}}
|
||||
className={`${
|
||||
isEnabled ? 'bg-indigo-600' : 'bg-cool-gray-700'
|
||||
} relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:shadow-outline`}
|
||||
isEnabled ? 'bg-indigo-600' : 'bg-gray-700'
|
||||
} relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring`}
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
|
||||
@@ -214,7 +214,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||
<label
|
||||
htmlFor="isDefault"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Default Server
|
||||
</label>
|
||||
@@ -223,14 +223,14 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
type="checkbox"
|
||||
id="isDefault"
|
||||
name="isDefault"
|
||||
className="form-checkbox h-6 w-6 text-indigo-600 transition duration-150 ease-in-out"
|
||||
className="form-checkbox h-6 w-6 text-indigo-600 transition duration-150 ease-in-out rounded-md"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Server Name
|
||||
</label>
|
||||
@@ -239,13 +239,13 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<Field
|
||||
id="name"
|
||||
name="name"
|
||||
type="input"
|
||||
type="text"
|
||||
placeholder="A Radarr Server"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setIsValidated(false);
|
||||
setFieldValue('name', e.target.value);
|
||||
}}
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
</div>
|
||||
{errors.name && touched.name && (
|
||||
@@ -256,7 +256,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="hostname"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Hostname
|
||||
</label>
|
||||
@@ -265,13 +265,13 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<Field
|
||||
id="hostname"
|
||||
name="hostname"
|
||||
type="input"
|
||||
type="text"
|
||||
placeholder="127.0.0.1"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setIsValidated(false);
|
||||
setFieldValue('hostname', e.target.value);
|
||||
}}
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
</div>
|
||||
{errors.hostname && touched.hostname && (
|
||||
@@ -282,7 +282,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||
<label
|
||||
htmlFor="port"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Port
|
||||
</label>
|
||||
@@ -290,13 +290,13 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<Field
|
||||
id="port"
|
||||
name="port"
|
||||
type="input"
|
||||
type="text"
|
||||
placeholder="7878"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setIsValidated(false);
|
||||
setFieldValue('port', e.target.value);
|
||||
}}
|
||||
className="rounded-md shadow-sm form-input block w-24 transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="rounded-md shadow-sm form-input block w-24 transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
{errors.port && touched.port && (
|
||||
<div className="text-red-500 mt-2">{errors.port}</div>
|
||||
@@ -306,7 +306,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||
<label
|
||||
htmlFor="ssl"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
SSL
|
||||
</label>
|
||||
@@ -319,14 +319,14 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
setIsValidated(false);
|
||||
setFieldValue('ssl', !values.ssl);
|
||||
}}
|
||||
className="form-checkbox h-6 w-6 text-indigo-600 transition duration-150 ease-in-out"
|
||||
className="form-checkbox h-6 w-6 rounded-md text-indigo-600 transition duration-150 ease-in-out"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="apiKey"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
API Key
|
||||
</label>
|
||||
@@ -335,13 +335,13 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<Field
|
||||
id="apiKey"
|
||||
name="apiKey"
|
||||
type="input"
|
||||
type="text"
|
||||
placeholder="Your Radarr API Key"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setIsValidated(false);
|
||||
setFieldValue('apiKey', e.target.value);
|
||||
}}
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
</div>
|
||||
{errors.apiKey && touched.apiKey && (
|
||||
@@ -352,7 +352,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="baseUrl"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Base URL
|
||||
</label>
|
||||
@@ -361,13 +361,13 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<Field
|
||||
id="baseUrl"
|
||||
name="baseUrl"
|
||||
type="input"
|
||||
type="text"
|
||||
placeholder="Example: /radarr"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setIsValidated(false);
|
||||
setFieldValue('baseUrl', e.target.value);
|
||||
}}
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
</div>
|
||||
{errors.baseUrl && touched.baseUrl && (
|
||||
@@ -378,7 +378,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="activeProfileId"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Quality Profile
|
||||
</label>
|
||||
@@ -388,7 +388,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
as="select"
|
||||
id="activeProfileId"
|
||||
name="activeProfileId"
|
||||
className="mt-1 form-select block w-full pl-3 pr-10 py-2 text-base leading-6 bg-cool-gray-700 border-cool-gray-500 focus:outline-none focus:shadow-outline-blue focus:border-cool-gray-500 sm:text-sm sm:leading-5"
|
||||
className="mt-1 form-select rounded-md block w-full pl-3 pr-10 py-2 text-base leading-6 bg-gray-700 border-gray-500 focus:outline-none focus:ring-blue focus:border-gray-500 sm:text-sm sm:leading-5"
|
||||
>
|
||||
{testResponse.profiles.length > 0 &&
|
||||
testResponse.profiles.map((profile) => (
|
||||
@@ -411,7 +411,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="rootFolder"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Root Folder
|
||||
</label>
|
||||
@@ -421,7 +421,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
as="select"
|
||||
id="rootFolder"
|
||||
name="rootFolder"
|
||||
className="mt-1 form-select block w-full pl-3 pr-10 py-2 text-base leading-6 bg-cool-gray-700 border-cool-gray-500 focus:outline-none focus:shadow-outline-blue focus:border-cool-gray-500 sm:text-sm sm:leading-5"
|
||||
className="mt-1 form-select rounded-md block w-full pl-3 pr-10 py-2 text-base leading-6 bg-gray-700 border-gray-500 focus:outline-none focus:ring-blue focus:border-gray-500 sm:text-sm sm:leading-5"
|
||||
>
|
||||
{testResponse.rootFolders.length > 0 &&
|
||||
testResponse.rootFolders.map((folder) => (
|
||||
@@ -444,7 +444,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="minimumAvailability"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Minimum Availability
|
||||
</label>
|
||||
@@ -454,7 +454,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
as="select"
|
||||
id="minimumAvailability"
|
||||
name="minimumAvailability"
|
||||
className="mt-1 form-select block w-full pl-3 pr-10 py-2 text-base leading-6 bg-cool-gray-700 border-cool-gray-500 focus:outline-none focus:shadow-outline-blue focus:border-cool-gray-500 sm:text-sm sm:leading-5"
|
||||
className="mt-1 form-select rounded-md block w-full pl-3 pr-10 py-2 text-base leading-6 bg-gray-700 border-gray-500 focus:outline-none focus:ring-blue focus:border-gray-500 sm:text-sm sm:leading-5"
|
||||
>
|
||||
<option value="announced">Announced</option>
|
||||
<option value="inCinemas">In Cinemas</option>
|
||||
@@ -467,7 +467,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||
<label
|
||||
htmlFor="is4k"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Ultra HD Server
|
||||
</label>
|
||||
@@ -476,7 +476,7 @@ const RadarrModal: React.FC<RadarrModalProps> = ({
|
||||
type="checkbox"
|
||||
id="is4k"
|
||||
name="is4k"
|
||||
className="form-checkbox h-6 w-6 text-indigo-600 transition duration-150 ease-in-out"
|
||||
className="form-checkbox h-6 w-6 rounded-md text-indigo-600 transition duration-150 ease-in-out"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,24 +24,24 @@ const SettingsJobs: React.FC = () => {
|
||||
<table className="min-w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="px-6 py-3 bg-cool-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
Job Name
|
||||
</th>
|
||||
<th className="px-6 py-3 bg-cool-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
Next Execution
|
||||
</th>
|
||||
<th className="px-6 py-3 bg-cool-gray-500"></th>
|
||||
<th className="px-6 py-3 bg-gray-500"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="bg-cool-gray-600 divide-y divide-cool-gray-700">
|
||||
<tbody className="bg-gray-600 divide-y divide-gray-700">
|
||||
{data?.map((job, index) => (
|
||||
<tr key={`job-list-${index}`}>
|
||||
<td className="px-6 py-4 whitespace-no-wrap">
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<div className="text-sm leading-5 text-white">
|
||||
{job.name}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-no-wrap">
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<div className="text-sm leading-5 text-white">
|
||||
<FormattedRelativeTime
|
||||
value={Math.floor(
|
||||
@@ -53,7 +53,7 @@ const SettingsJobs: React.FC = () => {
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-no-wrap text-right text-sm leading-5 font-medium">
|
||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm leading-5 font-medium">
|
||||
<Button buttonType="primary">Run Now</Button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -47,7 +47,7 @@ const SettingsLayout: React.FC = ({ children }) => {
|
||||
'border-indigo-600 text-indigo-500 focus:outline-none focus:text-indigo-500 focus:border-indigo-500';
|
||||
|
||||
const inactiveLinkColor =
|
||||
'border-transparent text-cool-gray-500 hover:text-cool-gray-400 hover:border-cool-gray-300 focus:outline-none focus:text-cool-gray-4700 focus:border-cool-gray-300';
|
||||
'border-transparent text-gray-500 hover:text-gray-400 hover:border-gray-300 focus:outline-none focus:text-gray-4700 focus:border-gray-300';
|
||||
|
||||
const SettingsLink: React.FC<{
|
||||
route: string;
|
||||
@@ -61,7 +61,7 @@ const SettingsLayout: React.FC = ({ children }) => {
|
||||
return (
|
||||
<Link href={route}>
|
||||
<a
|
||||
className={`whitespace-no-wrap ml-8 first:ml-0 py-4 px-1 border-b-2 border-transparent font-medium text-sm leading-5 ${
|
||||
className={`whitespace-nowrap ml-8 first:ml-0 py-4 px-1 border-b-2 border-transparent font-medium text-sm leading-5 ${
|
||||
!!router.pathname.match(regex) ? activeLinkColor : inactiveLinkColor
|
||||
}`}
|
||||
aria-current="page"
|
||||
@@ -88,7 +88,7 @@ const SettingsLayout: React.FC = ({ children }) => {
|
||||
)?.route
|
||||
}
|
||||
aria-label="Selected tab"
|
||||
className="bg-cool-gray-800 text-white mt-1 form-select block w-full pl-3 pr-10 py-2 text-base leading-6 border-cool-gray-700 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 sm:text-sm sm:leading-5 transition ease-in-out duration-150"
|
||||
className="bg-gray-800 text-white mt-1 rounded-md form-select block w-full pl-3 pr-10 py-2 text-base leading-6 border-gray-700 focus:outline-none focus:ring-blue focus:border-blue-300 sm:text-sm sm:leading-5 transition ease-in-out duration-150"
|
||||
>
|
||||
{settingsRoutes.map((route, index) => (
|
||||
<SettingsLink
|
||||
@@ -103,7 +103,7 @@ const SettingsLayout: React.FC = ({ children }) => {
|
||||
</select>
|
||||
</div>
|
||||
<div className="hidden sm:block">
|
||||
<div className="border-b border-cool-gray-600">
|
||||
<div className="border-b border-gray-600">
|
||||
<nav className="-mb-px flex">
|
||||
{settingsRoutes.map((route, index) => (
|
||||
<SettingsLink
|
||||
|
||||
@@ -14,10 +14,10 @@ const SettingsMain: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<h3 className="text-lg leading-6 font-medium text-cool-gray-200">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-200">
|
||||
General Settings
|
||||
</h3>
|
||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-cool-gray-500">
|
||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-gray-500">
|
||||
These are settings related to general Overseerr configuration.
|
||||
</p>
|
||||
</div>
|
||||
@@ -25,20 +25,21 @@ const SettingsMain: React.FC = () => {
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="username"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
API Key
|
||||
</label>
|
||||
<div className="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg flex rounded-md shadow-sm">
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-none rounded-l-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-none rounded-l-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
value={data?.apiKey}
|
||||
readOnly
|
||||
/>
|
||||
<CopyButton textToCopy={data?.apiKey ?? ''} />
|
||||
<button className="-ml-px relative inline-flex items-center px-4 py-2 border border-cool-gray-500 text-sm leading-5 font-medium rounded-r-md text-white bg-indigo-500 hover:bg-indigo-400 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150">
|
||||
<button className="-ml-px relative inline-flex items-center px-4 py-2 border border-gray-500 text-sm leading-5 font-medium rounded-r-md text-white bg-indigo-500 hover:bg-indigo-400 focus:outline-none focus:ring-blue focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150">
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="currentColor"
|
||||
|
||||
@@ -157,10 +157,10 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<h3 className="text-lg leading-6 font-medium text-cool-gray-200">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-200">
|
||||
<FormattedMessage {...messages.plexsettings} />
|
||||
</h3>
|
||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-cool-gray-500">
|
||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-gray-500">
|
||||
<FormattedMessage {...messages.plexsettingsDescription} />
|
||||
</p>
|
||||
</div>
|
||||
@@ -174,13 +174,14 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
<FormattedMessage {...messages.servername} />
|
||||
</label>
|
||||
<div className="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg flex rounded-md shadow-sm">
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
placeholder={intl.formatMessage(
|
||||
@@ -188,7 +189,7 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
||||
)}
|
||||
value={data?.name}
|
||||
readOnly
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -196,19 +197,20 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
||||
<div className="mt-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="hostname"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
<FormattedMessage {...messages.hostname} />
|
||||
</label>
|
||||
<div className="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg flex rounded-md shadow-sm">
|
||||
<input
|
||||
type="text"
|
||||
id="hostname"
|
||||
name="hostname"
|
||||
placeholder="127.0.0.1"
|
||||
value={formik.values.hostname}
|
||||
onChange={formik.handleChange}
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -216,25 +218,26 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||
<label
|
||||
htmlFor="port"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
<FormattedMessage {...messages.port} />
|
||||
</label>
|
||||
<div className="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg rounded-md shadow-sm sm:max-w-xs">
|
||||
<input
|
||||
type="text"
|
||||
id="port"
|
||||
name="port"
|
||||
placeholder="32400"
|
||||
value={formik.values.port}
|
||||
onChange={formik.handleChange}
|
||||
className="form-input block w-24 transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="form-input block w-24 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-8 border-t border-cool-gray-700 pt-5">
|
||||
<div className="mt-8 border-t border-gray-700 pt-5">
|
||||
<div className="flex justify-end">
|
||||
<span className="ml-3 inline-flex rounded-md shadow-sm">
|
||||
<Button buttonType="primary" type="submit" disabled={isUpdating}>
|
||||
@@ -247,10 +250,10 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
||||
</div>
|
||||
</form>
|
||||
<div className="mt-10">
|
||||
<h3 className="text-lg leading-6 font-medium text-cool-gray-200">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-200">
|
||||
<FormattedMessage {...messages.plexlibraries} />
|
||||
</h3>
|
||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-cool-gray-500">
|
||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-gray-500">
|
||||
<FormattedMessage {...messages.plexlibrariesDescription} />
|
||||
</p>
|
||||
<div className="mt-6">
|
||||
@@ -284,15 +287,15 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
|
||||
</ul>
|
||||
</div>
|
||||
<div className="mt-10">
|
||||
<h3 className="text-lg leading-6 font-medium text-cool-gray-200">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-200">
|
||||
<FormattedMessage {...messages.manualscan} />
|
||||
</h3>
|
||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-cool-gray-500">
|
||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-gray-500">
|
||||
<FormattedMessage {...messages.manualscanDescription} />
|
||||
</p>
|
||||
<div className="mt-6">
|
||||
<div className="bg-cool-gray-800 p-4 rounded-md">
|
||||
<div className="w-full h-8 rounded-full bg-cool-gray-600 mb-6 relative overflow-hidden">
|
||||
<div className="bg-gray-800 p-4 rounded-md">
|
||||
<div className="w-full h-8 rounded-full bg-gray-600 mb-6 relative overflow-hidden">
|
||||
{dataSync?.running && (
|
||||
<div
|
||||
className="h-8 bg-indigo-600 transition-all ease-in-out duration-200"
|
||||
|
||||
@@ -38,7 +38,7 @@ const ServerInstance: React.FC<ServerInstanceProps> = ({
|
||||
onDelete,
|
||||
}) => {
|
||||
return (
|
||||
<li className="col-span-1 bg-cool-gray-700 rounded-lg shadow">
|
||||
<li className="col-span-1 bg-gray-700 rounded-lg shadow">
|
||||
<div className="w-full flex items-center justify-between p-6 space-x-6">
|
||||
<div className="flex-1 truncate">
|
||||
<div className="flex items-center space-x-3 mb-2">
|
||||
@@ -49,11 +49,11 @@ const ServerInstance: React.FC<ServerInstanceProps> = ({
|
||||
{isDefault4K && <Badge badgeType="warning">Default 4K</Badge>}
|
||||
{isSSL && <Badge badgeType="success">SSL</Badge>}
|
||||
</div>
|
||||
<p className="mt-1 text-cool-gray-300 text-sm leading-5 truncate">
|
||||
<p className="mt-1 text-gray-300 text-sm leading-5 truncate">
|
||||
<span className="font-bold mr-2">Address</span>
|
||||
{address}
|
||||
</p>
|
||||
<p className="mt-1 text-cool-gray-300 text-sm leading-5 truncate">
|
||||
<p className="mt-1 text-gray-300 text-sm leading-5 truncate">
|
||||
<span className="font-bold mr-2">Active Profile</span> {profileName}
|
||||
</p>
|
||||
</div>
|
||||
@@ -63,12 +63,12 @@ const ServerInstance: React.FC<ServerInstanceProps> = ({
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div className="border-t border-cool-gray-800">
|
||||
<div className="border-t border-gray-800">
|
||||
<div className="-mt-px flex">
|
||||
<div className="w-0 flex-1 flex border-r border-cool-gray-800">
|
||||
<div className="w-0 flex-1 flex border-r border-gray-800">
|
||||
<button
|
||||
onClick={() => onEdit()}
|
||||
className="relative -mr-px w-0 flex-1 inline-flex items-center justify-center py-4 text-sm leading-5 text-cool-gray-200 font-medium border border-transparent rounded-bl-lg hover:text-white focus:outline-none focus:shadow-outline-blue focus:border-cool-gray-500 focus:z-10 transition ease-in-out duration-150"
|
||||
className="relative -mr-px w-0 flex-1 inline-flex items-center justify-center py-4 text-sm leading-5 text-gray-200 font-medium border border-transparent rounded-bl-lg hover:text-white focus:outline-none focus:ring-blue focus:border-gray-500 focus:z-10 transition ease-in-out duration-150"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
@@ -84,7 +84,7 @@ const ServerInstance: React.FC<ServerInstanceProps> = ({
|
||||
<div className="-ml-px w-0 flex-1 flex">
|
||||
<button
|
||||
onClick={() => onDelete()}
|
||||
className="relative w-0 flex-1 inline-flex items-center justify-center py-4 text-sm leading-5 text-cool-gray-200 font-medium border border-transparent rounded-br-lg hover:text-white focus:outline-none focus:shadow-outline-blue focus:border-cool-gray-500 focus:z-10 transition ease-in-out duration-150"
|
||||
className="relative w-0 flex-1 inline-flex items-center justify-center py-4 text-sm leading-5 text-gray-200 font-medium border border-transparent rounded-br-lg hover:text-white focus:outline-none focus:ring-blue focus:border-gray-500 focus:z-10 transition ease-in-out duration-150"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
@@ -154,10 +154,10 @@ const SettingsServices: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<h3 className="text-lg leading-6 font-medium text-cool-gray-200">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-200">
|
||||
Radarr Settings
|
||||
</h3>
|
||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-cool-gray-500">
|
||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-gray-500">
|
||||
Configure your Radarr connection below. You can have multiple Radarr
|
||||
configurations but only two can be active as defaults at any time (one
|
||||
for standard HD and one for 4K). Administrations can override a titles
|
||||
@@ -232,7 +232,7 @@ const SettingsServices: React.FC = () => {
|
||||
}
|
||||
/>
|
||||
))}
|
||||
<li className="col-span-1 border-2 border-dashed border-cool-gray-400 rounded-lg shadow h-32 sm:h-32">
|
||||
<li className="col-span-1 border-2 border-dashed border-gray-400 rounded-lg shadow h-32 sm:h-32">
|
||||
<div className="flex items-center justify-center w-full h-full">
|
||||
<Button
|
||||
buttonType="ghost"
|
||||
@@ -260,10 +260,10 @@ const SettingsServices: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-10">
|
||||
<h3 className="text-lg leading-6 font-medium text-cool-gray-200">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-200">
|
||||
Sonarr Settings
|
||||
</h3>
|
||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-cool-gray-500">
|
||||
<p className="mt-1 max-w-2xl text-sm leading-5 text-gray-500">
|
||||
Configure your Sonarr connection below. You can have multiple Sonarr
|
||||
configurations but only two can be active as defaults at any time (one
|
||||
for standard HD and one for 4K). Administrations can override a titles
|
||||
@@ -294,7 +294,7 @@ const SettingsServices: React.FC = () => {
|
||||
}
|
||||
/>
|
||||
))}
|
||||
<li className="col-span-1 border-2 border-dashed border-cool-gray-400 rounded-lg shadow h-32 sm:h-32">
|
||||
<li className="col-span-1 border-2 border-dashed border-gray-400 rounded-lg shadow h-32 sm:h-32">
|
||||
<div className="flex items-center justify-center w-full h-full">
|
||||
<Button
|
||||
buttonType="ghost"
|
||||
|
||||
@@ -214,7 +214,7 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||
<label
|
||||
htmlFor="isDefault"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Default Server
|
||||
</label>
|
||||
@@ -223,14 +223,14 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
type="checkbox"
|
||||
id="isDefault"
|
||||
name="isDefault"
|
||||
className="form-checkbox h-6 w-6 text-indigo-600 transition duration-150 ease-in-out"
|
||||
className="form-checkbox rounded-md h-6 w-6 text-indigo-600 transition duration-150 ease-in-out"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Server Name
|
||||
</label>
|
||||
@@ -239,13 +239,13 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<Field
|
||||
id="name"
|
||||
name="name"
|
||||
type="input"
|
||||
type="text"
|
||||
placeholder="A Sonarr Server"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setIsValidated(false);
|
||||
setFieldValue('name', e.target.value);
|
||||
}}
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
</div>
|
||||
{errors.name && touched.name && (
|
||||
@@ -256,7 +256,7 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="hostname"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Hostname
|
||||
</label>
|
||||
@@ -265,13 +265,13 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<Field
|
||||
id="hostname"
|
||||
name="hostname"
|
||||
type="input"
|
||||
type="text"
|
||||
placeholder="127.0.0.1"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setIsValidated(false);
|
||||
setFieldValue('hostname', e.target.value);
|
||||
}}
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
</div>
|
||||
{errors.hostname && touched.hostname && (
|
||||
@@ -282,7 +282,7 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||
<label
|
||||
htmlFor="port"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Port
|
||||
</label>
|
||||
@@ -290,13 +290,13 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<Field
|
||||
id="port"
|
||||
name="port"
|
||||
type="input"
|
||||
type="text"
|
||||
placeholder="8989"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setIsValidated(false);
|
||||
setFieldValue('port', e.target.value);
|
||||
}}
|
||||
className="rounded-md shadow-sm form-input block w-24 transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="rounded-md shadow-sm form-input block w-24 transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
{errors.port && touched.port && (
|
||||
<div className="text-red-500 mt-2">{errors.port}</div>
|
||||
@@ -306,7 +306,7 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||
<label
|
||||
htmlFor="ssl"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
SSL
|
||||
</label>
|
||||
@@ -319,14 +319,14 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
setIsValidated(false);
|
||||
setFieldValue('ssl', !values.ssl);
|
||||
}}
|
||||
className="form-checkbox h-6 w-6 text-indigo-600 transition duration-150 ease-in-out"
|
||||
className="form-checkbox rounded-md h-6 w-6 text-indigo-600 transition duration-150 ease-in-out"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="apiKey"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
API Key
|
||||
</label>
|
||||
@@ -335,13 +335,13 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<Field
|
||||
id="apiKey"
|
||||
name="apiKey"
|
||||
type="input"
|
||||
type="text"
|
||||
placeholder="Your Sonarr API Key"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setIsValidated(false);
|
||||
setFieldValue('apiKey', e.target.value);
|
||||
}}
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
</div>
|
||||
{errors.apiKey && touched.apiKey && (
|
||||
@@ -352,7 +352,7 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="baseUrl"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Base URL
|
||||
</label>
|
||||
@@ -361,13 +361,13 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<Field
|
||||
id="baseUrl"
|
||||
name="baseUrl"
|
||||
type="input"
|
||||
type="text"
|
||||
placeholder="Example: /sonarr"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setIsValidated(false);
|
||||
setFieldValue('baseUrl', e.target.value);
|
||||
}}
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
/>
|
||||
</div>
|
||||
{errors.baseUrl && touched.baseUrl && (
|
||||
@@ -378,7 +378,7 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="activeProfileId"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Quality Profile
|
||||
</label>
|
||||
@@ -388,7 +388,7 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
as="select"
|
||||
id="activeProfileId"
|
||||
name="activeProfileId"
|
||||
className="mt-1 form-select block w-full pl-3 pr-10 py-2 text-base leading-6 bg-cool-gray-700 border-cool-gray-500 focus:outline-none focus:shadow-outline-blue focus:border-cool-gray-500 sm:text-sm sm:leading-5"
|
||||
className="mt-1 form-select rounded-md block w-full pl-3 pr-10 py-2 text-base leading-6 bg-gray-700 border-gray-500 focus:outline-none focus:ring-blue focus:border-gray-500 sm:text-sm sm:leading-5"
|
||||
>
|
||||
<option value="">Select a Quality Profile</option>
|
||||
{testResponse.profiles.length > 0 &&
|
||||
@@ -412,7 +412,7 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800 sm:pt-5">
|
||||
<label
|
||||
htmlFor="rootFolder"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Root Folder
|
||||
</label>
|
||||
@@ -422,7 +422,7 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
as="select"
|
||||
id="rootFolder"
|
||||
name="rootFolder"
|
||||
className="mt-1 form-select block w-full pl-3 pr-10 py-2 text-base leading-6 bg-cool-gray-700 border-cool-gray-500 focus:outline-none focus:shadow-outline-blue focus:border-cool-gray-500 sm:text-sm sm:leading-5"
|
||||
className="mt-1 form-select block rounded-md w-full pl-3 pr-10 py-2 text-base leading-6 bg-gray-700 border-gray-500 focus:outline-none focus:ring-blue focus:border-gray-500 sm:text-sm sm:leading-5"
|
||||
>
|
||||
<option value="">Select a Root Folder</option>
|
||||
{testResponse.rootFolders.length > 0 &&
|
||||
@@ -446,7 +446,7 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||
<label
|
||||
htmlFor="is4k"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Ultra HD Server
|
||||
</label>
|
||||
@@ -455,14 +455,14 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
type="checkbox"
|
||||
id="is4k"
|
||||
name="is4k"
|
||||
className="form-checkbox h-6 w-6 text-indigo-600 transition duration-150 ease-in-out"
|
||||
className="form-checkbox h-6 w-6 rounded-md text-indigo-600 transition duration-150 ease-in-out"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||
<label
|
||||
htmlFor="enableSeasonFolders"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400 sm:mt-px sm:pt-2"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Season Folders
|
||||
</label>
|
||||
@@ -471,7 +471,7 @@ const SonarrModal: React.FC<SonarrModalProps> = ({
|
||||
type="checkbox"
|
||||
id="enableSeasonFolders"
|
||||
name="enableSeasonFolders"
|
||||
className="form-checkbox h-6 w-6 text-indigo-600 transition duration-150 ease-in-out"
|
||||
className="form-checkbox h-6 w-6 rounded-md text-indigo-600 transition duration-150 ease-in-out"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -55,7 +55,7 @@ const SetupSteps: React.FC<CurrentStep> = ({
|
||||
{!isLastStep && (
|
||||
<div className="hidden md:block absolute top-0 right-0 h-full w-5">
|
||||
<svg
|
||||
className="h-full w-full text-cool-gray-600"
|
||||
className="h-full w-full text-gray-600"
|
||||
viewBox="0 0 22 80"
|
||||
fill="none"
|
||||
preserveAspectRatio="none"
|
||||
|
||||
@@ -34,7 +34,7 @@ const Setup: React.FC = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-cool-gray-900 flex flex-col justify-center py-12 sm:px-6 lg:px-8 relative">
|
||||
<div className="min-h-screen bg-gray-900 flex flex-col justify-center py-12 sm:px-6 lg:px-8 relative">
|
||||
<ImageFader
|
||||
backgroundImages={[
|
||||
'/images/rotate1.jpg',
|
||||
@@ -51,7 +51,7 @@ const Setup: React.FC = () => {
|
||||
/>
|
||||
<nav className="relative z-50">
|
||||
<ul
|
||||
className=" bg-cool-gray-800 bg-opacity-50 border border-cool-gray-600 rounded-md divide-y divide-cool-gray-600 md:flex md:divide-y-0"
|
||||
className=" bg-gray-800 bg-opacity-50 border border-gray-600 rounded-md divide-y divide-gray-600 md:flex md:divide-y-0"
|
||||
style={{ backdropFilter: 'blur(5px)' }}
|
||||
>
|
||||
<SetupSteps
|
||||
@@ -74,14 +74,14 @@ const Setup: React.FC = () => {
|
||||
/>
|
||||
</ul>
|
||||
</nav>
|
||||
<div className="w-full mt-10 p-4 text-white bg-cool-gray-800 bg-opacity-50 border border-cool-gray-600 rounded-md">
|
||||
<div className="w-full mt-10 p-4 text-white bg-gray-800 bg-opacity-50 border border-gray-600 rounded-md">
|
||||
{currentStep === 1 && (
|
||||
<LoginWithPlex onComplete={() => setCurrentStep(2)} />
|
||||
)}
|
||||
{currentStep === 2 && (
|
||||
<div>
|
||||
<SettingsPlex onComplete={() => setPlexSettingsComplete(true)} />
|
||||
<div className="mt-8 border-t border-cool-gray-700 pt-5">
|
||||
<div className="mt-8 border-t border-gray-700 pt-5">
|
||||
<div className="flex justify-end">
|
||||
<span className="ml-3 inline-flex rounded-md shadow-sm">
|
||||
<Button
|
||||
@@ -99,7 +99,7 @@ const Setup: React.FC = () => {
|
||||
{currentStep === 3 && (
|
||||
<div>
|
||||
<SettingsServices />
|
||||
<div className="mt-8 border-t border-cool-gray-700 pt-5">
|
||||
<div className="mt-8 border-t border-gray-700 pt-5">
|
||||
<div className="flex justify-end">
|
||||
<span className="ml-3 inline-flex rounded-md shadow-sm">
|
||||
<Button
|
||||
|
||||
@@ -199,7 +199,7 @@ const Slider: React.FC<SliderProps> = ({
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="overflow-x-scroll whitespace-no-wrap hide-scrollbar scrolling-touch overscroll-x-contain -ml-4 -mr-4 px-2"
|
||||
className="overflow-x-scroll whitespace-nowrap hide-scrollbar overscroll-x-contain -ml-4 -mr-4 px-2"
|
||||
ref={containerRef}
|
||||
onScroll={onScroll}
|
||||
>
|
||||
|
||||
@@ -7,7 +7,7 @@ interface PlaceholderProps {
|
||||
const Placeholder: React.FC<PlaceholderProps> = ({ canExpand = false }) => {
|
||||
return (
|
||||
<div
|
||||
className={`relative animate-pulse rounded-lg bg-cool-gray-700 ${
|
||||
className={`relative animate-pulse rounded-lg bg-gray-700 ${
|
||||
canExpand ? 'w-full' : 'w-36 sm:w-36 md:w-44'
|
||||
}`}
|
||||
>
|
||||
|
||||
@@ -117,7 +117,7 @@ const TitleCard: React.FC<TitleCardProps> = ({
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className="absolute top-0 left-0 right-0 bottom-0 bg-cool-gray-800 bg-opacity-75 z-40 text-white flex items-center justify-center rounded-lg">
|
||||
<div className="absolute top-0 left-0 right-0 bottom-0 bg-gray-800 bg-opacity-75 z-40 text-white flex items-center justify-center rounded-lg">
|
||||
<svg
|
||||
className="w-10 h-10 animate-spin"
|
||||
fill="none"
|
||||
@@ -177,7 +177,7 @@ const TitleCard: React.FC<TitleCardProps> = ({
|
||||
}
|
||||
as={mediaType === 'movie' ? `/movie/${id}` : `/tv/${id}`}
|
||||
>
|
||||
<a className="cursor-pointer flex w-full h-7 text-center text-white bg-indigo-500 rounded-sm hover:bg-indigo-400 focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition ease-in-out duration-150">
|
||||
<a className="cursor-pointer flex w-full h-7 text-center text-white bg-indigo-500 rounded-sm hover:bg-indigo-400 focus:border-indigo-700 focus:ring-indigo active:bg-indigo-700 transition ease-in-out duration-150">
|
||||
<svg
|
||||
className="w-4 mx-auto"
|
||||
fill="none"
|
||||
@@ -203,7 +203,7 @@ const TitleCard: React.FC<TitleCardProps> = ({
|
||||
{!currentStatus && (
|
||||
<button
|
||||
onClick={() => setShowRequestModal(true)}
|
||||
className="w-full h-7 text-center text-white bg-indigo-500 rounded-sm ml-2 hover:bg-indigo-400 focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition ease-in-out duration-150"
|
||||
className="w-full h-7 text-center text-white bg-indigo-500 rounded-sm ml-2 hover:bg-indigo-400 focus:border-indigo-700 focus:ring-indigo active:bg-indigo-700 transition ease-in-out duration-150"
|
||||
>
|
||||
<svg
|
||||
className="w-4 mx-auto"
|
||||
@@ -222,7 +222,7 @@ const TitleCard: React.FC<TitleCardProps> = ({
|
||||
</button>
|
||||
)}
|
||||
{currentStatus === MediaStatus.PENDING && (
|
||||
<button className="w-full h-7 text-center text-white bg-orange-400 hover:bg-orange-300 rounded-sm ml-2 focus:border-orange-700 focus:shadow-outline-orange active:bg-orange-700 transition ease-in-out duration-150">
|
||||
<button className="w-full h-7 text-center text-white bg-orange-400 hover:bg-orange-300 rounded-sm ml-2 focus:border-orange-700 focus:ring-orange active:bg-orange-700 transition ease-in-out duration-150">
|
||||
<svg
|
||||
className="w-4 mx-auto"
|
||||
fill="none"
|
||||
|
||||
@@ -4,8 +4,8 @@ import type { ToastProps } from 'react-toast-notifications';
|
||||
const Toast: React.FC<ToastProps> = ({ appearance, children, onDismiss }) => {
|
||||
return (
|
||||
<div className="toast flex items-end justify-center px-2 py-2 pointer-events-none sm:p-6 sm:items-start sm:justify-end">
|
||||
<div className="max-w-sm w-full bg-cool-gray-700 shadow-lg rounded-lg pointer-events-auto">
|
||||
<div className="rounded-lg shadow-xs overflow-hidden">
|
||||
<div className="max-w-sm w-full bg-gray-700 shadow-lg rounded-lg pointer-events-auto">
|
||||
<div className="rounded-lg ring-1 ring-black ring-opacity-5 overflow-hidden">
|
||||
<div className="p-4">
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0">
|
||||
|
||||
@@ -128,7 +128,7 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
||||
className="bg-cover bg-center -mx-4 -mt-2 px-4 sm:px-8 pt-4 "
|
||||
style={{
|
||||
height: 493,
|
||||
backgroundImage: `linear-gradient(180deg, rgba(45, 55, 72, 0.47) 0%, #1A202E 100%), url(//image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data.backdropPath})`,
|
||||
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})`,
|
||||
}}
|
||||
>
|
||||
<RequestModal
|
||||
@@ -148,20 +148,18 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
||||
subText={data.name}
|
||||
>
|
||||
<h3 className="text-xl mb-2">Requests</h3>
|
||||
<div className="bg-cool-gray-600 shadow overflow-hidden rounded-md">
|
||||
<div className="bg-gray-600 shadow overflow-hidden rounded-md">
|
||||
<ul>
|
||||
{data.mediaInfo?.requests?.map((request) => (
|
||||
<li
|
||||
key={`manage-request-${request.id}`}
|
||||
className="border-b last:border-b-0 border-cool-gray-700"
|
||||
className="border-b last:border-b-0 border-gray-700"
|
||||
>
|
||||
<RequestBlock request={request} onUpdate={() => revalidate()} />
|
||||
</li>
|
||||
))}
|
||||
{(data.mediaInfo?.requests ?? []).length === 0 && (
|
||||
<li className="text-center py-4 text-cool-gray-400">
|
||||
No requests
|
||||
</li>
|
||||
<li className="text-center py-4 text-gray-400">No requests</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
@@ -174,7 +172,7 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
||||
>
|
||||
Clear All Media Data
|
||||
</Button>
|
||||
<div className="text-sm text-cool-gray-400 mt-2">
|
||||
<div className="text-sm text-gray-400 mt-2">
|
||||
This will remove all media data including all requests for this
|
||||
item. This action is irreversible. If this item exists in your
|
||||
Plex library, the media information will be recreated next sync.
|
||||
@@ -363,9 +361,9 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full md:w-80 mt-8 md:mt-0">
|
||||
<div className="bg-cool-gray-900 rounded-lg shadow border border-cool-gray-800">
|
||||
<div className="bg-gray-900 rounded-lg shadow border border-gray-800">
|
||||
{(data.voteCount > 0 || ratingData) && (
|
||||
<div className="flex px-4 py-2 border-b border-cool-gray-800 last:border-b-0 items-center justify-center">
|
||||
<div className="flex px-4 py-2 border-b border-gray-800 last:border-b-0 items-center justify-center">
|
||||
{ratingData?.criticsRating && (
|
||||
<>
|
||||
<span className="text-sm">
|
||||
@@ -375,7 +373,7 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
||||
<RTFresh className="w-6 mr-1" />
|
||||
)}
|
||||
</span>
|
||||
<span className="text-cool-gray-400 text-sm mr-4 last:mr-0">
|
||||
<span className="text-gray-400 text-sm mr-4 last:mr-0">
|
||||
{ratingData.criticsScore}%
|
||||
</span>
|
||||
</>
|
||||
@@ -389,7 +387,7 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
||||
<RTAudFresh className="w-6 mr-1" />
|
||||
)}
|
||||
</span>
|
||||
<span className="text-cool-gray-400 text-sm mr-4 last:mr-0">
|
||||
<span className="text-gray-400 text-sm mr-4 last:mr-0">
|
||||
{ratingData.audienceScore}%
|
||||
</span>
|
||||
</>
|
||||
@@ -399,26 +397,26 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
||||
<span className="text-sm">
|
||||
<TmdbLogo className="w-6 mr-2" />
|
||||
</span>
|
||||
<span className="text-cool-gray-400 text-sm">
|
||||
<span className="text-gray-400 text-sm">
|
||||
{data.voteAverage}/10
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex px-4 py-2 border-b border-cool-gray-800 last:border-b-0">
|
||||
<div className="flex px-4 py-2 border-b border-gray-800 last:border-b-0">
|
||||
<span className="text-sm">
|
||||
<FormattedMessage {...messages.status} />
|
||||
</span>
|
||||
<span className="flex-1 text-right text-cool-gray-400 text-sm">
|
||||
<span className="flex-1 text-right text-gray-400 text-sm">
|
||||
{data.status}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex px-4 py-2 border-b border-cool-gray-800 last:border-b-0">
|
||||
<div className="flex px-4 py-2 border-b border-gray-800 last:border-b-0">
|
||||
<span className="text-sm">
|
||||
<FormattedMessage {...messages.originallanguage} />
|
||||
</span>
|
||||
<span className="flex-1 text-right text-cool-gray-400 text-sm">
|
||||
<span className="flex-1 text-right text-gray-400 text-sm">
|
||||
{data.originalLanguage}
|
||||
</span>
|
||||
</div>
|
||||
@@ -428,7 +426,7 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
||||
<div className="md:flex md:items-center md:justify-between mb-4 mt-6">
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link href="/tv/[tvId]/cast" as={`/tv/${data.id}/cast`}>
|
||||
<a className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<a className="inline-flex text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<span>
|
||||
<FormattedMessage {...messages.cast} />
|
||||
</span>
|
||||
@@ -471,7 +469,7 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
||||
href="/tv/[tvId]/recommendations"
|
||||
as={`/tv/${data.id}/recommendations`}
|
||||
>
|
||||
<a className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<a className="inline-flex text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<span>
|
||||
<FormattedMessage {...messages.recommendations} />
|
||||
</span>
|
||||
@@ -518,7 +516,7 @@ const TvDetails: React.FC<TvDetailsProps> = ({ tv }) => {
|
||||
<div className="md:flex md:items-center md:justify-between mb-4 mt-6">
|
||||
<div className="flex-1 min-w-0">
|
||||
<Link href="/tv/[tvId]/similar" as={`/tv/${data.id}/similar`}>
|
||||
<a className="inline-flex text-xl leading-7 text-cool-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<a className="inline-flex text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate items-center">
|
||||
<span>
|
||||
<FormattedMessage {...messages.similar} />
|
||||
</span>
|
||||
|
||||
@@ -152,14 +152,15 @@ const UserEdit: React.FC = () => {
|
||||
<div className="space-y-1">
|
||||
<label
|
||||
htmlFor="username"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400"
|
||||
className="block text-sm font-medium leading-5 text-gray-400"
|
||||
>
|
||||
<FormattedMessage {...messages.username} />
|
||||
</label>
|
||||
<div className="rounded-md shadow-sm flex">
|
||||
<input
|
||||
id="username"
|
||||
className="form-input flex-grow block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
type="text"
|
||||
className="form-input flex-grow block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
value={user?.username}
|
||||
readOnly
|
||||
/>
|
||||
@@ -168,14 +169,15 @@ const UserEdit: React.FC = () => {
|
||||
<div className="space-y-1">
|
||||
<label
|
||||
htmlFor="email"
|
||||
className="block text-sm font-medium leading-5 text-cool-gray-400"
|
||||
className="block text-sm font-medium leading-5 text-gray-400"
|
||||
>
|
||||
<FormattedMessage {...messages.email} />
|
||||
</label>
|
||||
<div className="rounded-md shadow-sm flex">
|
||||
<input
|
||||
id="email"
|
||||
className="form-input flex-grow block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-cool-gray-700 border border-cool-gray-500"
|
||||
type="text"
|
||||
className="form-input flex-grow block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
|
||||
value={user?.email}
|
||||
readOnly
|
||||
/>
|
||||
@@ -185,7 +187,7 @@ const UserEdit: React.FC = () => {
|
||||
|
||||
<div className="flex-grow space-y-1 lg:flex-grow-0 lg:flex-shrink-0">
|
||||
<p
|
||||
className="block text-sm leading-5 font-medium text-cool-gray-400"
|
||||
className="block text-sm leading-5 font-medium text-gray-400"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<FormattedMessage {...messages.avatar} />
|
||||
@@ -251,7 +253,7 @@ const UserEdit: React.FC = () => {
|
||||
id={permissionOption.id}
|
||||
name="permissions"
|
||||
type="checkbox"
|
||||
className="form-checkbox h-4 w-4 text-indigo-600 transition duration-150 ease-in-out"
|
||||
className="form-checkbox h-4 w-4 rounded-md text-indigo-600 transition duration-150 ease-in-out"
|
||||
disabled={
|
||||
(permissionOption.permission !==
|
||||
Permission.ADMIN &&
|
||||
@@ -302,7 +304,7 @@ const UserEdit: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-8 border-t border-cool-gray-700 pt-5">
|
||||
<div className="mt-8 border-t border-gray-700 pt-5">
|
||||
<div className="flex justify-end">
|
||||
<span className="ml-3 inline-flex rounded-md shadow-sm">
|
||||
<Button
|
||||
|
||||
@@ -28,31 +28,31 @@ const UserList: React.FC = () => {
|
||||
<table className="min-w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="px-6 py-3 bg-cool-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
Name
|
||||
</th>
|
||||
<th className="px-6 py-3 bg-cool-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
Total Requests
|
||||
</th>
|
||||
<th className="px-6 py-3 bg-cool-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
User Type
|
||||
</th>
|
||||
<th className="px-6 py-3 bg-cool-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
Role
|
||||
</th>
|
||||
<th className="px-6 py-3 bg-cool-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
Created
|
||||
</th>
|
||||
<th className="px-6 py-3 bg-cool-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
<th className="px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider">
|
||||
Last Updated
|
||||
</th>
|
||||
<th className="px-6 py-3 bg-cool-gray-500"></th>
|
||||
<th className="px-6 py-3 bg-gray-500"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="bg-cool-gray-600 divide-y divide-cool-gray-700">
|
||||
<tbody className="bg-gray-600 divide-y divide-gray-700">
|
||||
{data?.map((user) => (
|
||||
<tr key={`user-list-${user.id}`}>
|
||||
<td className="px-6 py-4 whitespace-no-wrap">
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<div className="flex items-center">
|
||||
<div className="flex-shrink-0 h-10 w-10">
|
||||
<img
|
||||
@@ -71,26 +71,26 @@ const UserList: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-no-wrap">
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<div className="text-sm leading-5 text-white">
|
||||
{user.requests.length}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-no-wrap">
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<Badge badgeType="warning">Plex User</Badge>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-white">
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm leading-5 text-white">
|
||||
{hasPermission(Permission.ADMIN, user.permissions)
|
||||
? 'Admin'
|
||||
: 'User'}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-white">
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm leading-5 text-white">
|
||||
<FormattedDate value={user.createdAt} />
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-white">
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm leading-5 text-white">
|
||||
<FormattedDate value={user.updatedAt} />
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-no-wrap text-right text-sm leading-5 font-medium">
|
||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm leading-5 font-medium">
|
||||
<Button
|
||||
buttonType="warning"
|
||||
className="mr-2"
|
||||
|
||||
Reference in New Issue
Block a user