mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
feat(ui): experimental status bar style change for ios pwa app
this might break things. just an experiment. :)
This commit is contained in:
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -17,5 +17,6 @@
|
||||
],
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
}
|
||||
},
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import React, {
|
||||
useState,
|
||||
useEffect,
|
||||
HTMLAttributes,
|
||||
ForwardRefRenderFunction,
|
||||
HTMLAttributes,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import CachedImage from '../CachedImage';
|
||||
|
||||
@@ -59,7 +59,7 @@ const ImageFader: ForwardRefRenderFunction<HTMLDivElement, ImageFaderProps> = (
|
||||
{backgroundImages.map((imageUrl, i) => (
|
||||
<div
|
||||
key={`banner-image-${i}`}
|
||||
className={`absolute inset-0 bg-cover bg-center transition-opacity duration-300 ease-in ${
|
||||
className={`absolute absolute-top-shift inset-0 bg-cover bg-center transition-opacity duration-300 ease-in ${
|
||||
i === activeIndex ? 'opacity-100' : 'opacity-0'
|
||||
}`}
|
||||
{...props}
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import React, { MouseEvent, ReactNode, useRef } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Button, { ButtonType } from '../Button';
|
||||
import { useLockBodyScroll } from '../../../hooks/useLockBodyScroll';
|
||||
import LoadingSpinner from '../LoadingSpinner';
|
||||
import useClickOutside from '../../../hooks/useClickOutside';
|
||||
import { useIntl } from 'react-intl';
|
||||
import useClickOutside from '../../../hooks/useClickOutside';
|
||||
import { useLockBodyScroll } from '../../../hooks/useLockBodyScroll';
|
||||
import globalMessages from '../../../i18n/globalMessages';
|
||||
import Transition from '../../Transition';
|
||||
import Button, { ButtonType } from '../Button';
|
||||
import LoadingSpinner from '../LoadingSpinner';
|
||||
|
||||
interface ModalProps {
|
||||
title?: string;
|
||||
@@ -98,11 +98,14 @@ const Modal: React.FC<ModalProps> = ({
|
||||
show={!loading}
|
||||
>
|
||||
<div
|
||||
className="inline-block w-full max-h-full px-4 pt-5 pb-4 overflow-auto text-left align-bottom transition-all transform bg-gray-700 shadow-xl sm:rounded-lg sm:my-8 sm:align-middle sm:max-w-3xl"
|
||||
className="relative inline-block w-full px-4 pt-5 pb-4 overflow-auto text-left align-bottom transition-all transform bg-gray-700 shadow-xl sm:rounded-lg sm:my-8 sm:align-middle sm:max-w-3xl"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline"
|
||||
ref={modalRef}
|
||||
style={{
|
||||
maxHeight: 'calc(100% - env(safe-area-inset-top) * 2)',
|
||||
}}
|
||||
>
|
||||
<div className="sm:flex sm:items-center">
|
||||
{iconSvg && (
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Transition from '../../Transition';
|
||||
import { useLockBodyScroll } from '../../../hooks/useLockBodyScroll';
|
||||
import Transition from '../../Transition';
|
||||
|
||||
interface SlideOverProps {
|
||||
show?: boolean;
|
||||
@@ -70,7 +70,7 @@ const SlideOver: React.FC<SlideOverProps> = ({
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="flex flex-col h-full overflow-y-scroll bg-gray-700 shadow-xl">
|
||||
<header className="px-4 py-6 space-y-1 bg-indigo-600">
|
||||
<header className="px-4 space-y-1 bg-indigo-600 slideover">
|
||||
<div className="flex items-center justify-between space-x-3">
|
||||
<h2 className="text-lg font-medium leading-7 text-white">
|
||||
{title}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import React, { ReactNode, useRef } from 'react';
|
||||
import Transition from '../../Transition';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
import React, { ReactNode, useRef } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { useUser, Permission } from '../../../hooks/useUser';
|
||||
import useClickOutside from '../../../hooks/useClickOutside';
|
||||
import { Permission, useUser } from '../../../hooks/useUser';
|
||||
import Transition from '../../Transition';
|
||||
|
||||
const messages = defineMessages({
|
||||
dashboard: 'Discover',
|
||||
@@ -148,8 +148,8 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
|
||||
leaveTo="-translate-x-full"
|
||||
>
|
||||
<>
|
||||
<div className="relative flex flex-col flex-1 w-full max-w-xs bg-gray-800">
|
||||
<div className="absolute top-0 right-0 p-1 -mr-14">
|
||||
<div className="relative flex flex-col flex-1 w-full max-w-xs bg-gray-800 sidebar">
|
||||
<div className="absolute top-0 right-0 p-1 sidebar-close-button -mr-14">
|
||||
<button
|
||||
className="flex items-center justify-center w-12 h-12 rounded-full focus:outline-none focus:bg-gray-600"
|
||||
aria-label="Close sidebar"
|
||||
@@ -233,7 +233,7 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
|
||||
</div>
|
||||
|
||||
<div className="fixed top-0 bottom-0 left-0 hidden md:flex md:flex-shrink-0">
|
||||
<div className="flex flex-col w-64">
|
||||
<div className="flex flex-col w-64 sidebar">
|
||||
<div className="flex flex-col flex-1 h-0 bg-gray-800">
|
||||
<div className="flex flex-col flex-1 pt-5 pb-4 overflow-y-auto">
|
||||
<div className="flex items-center flex-shrink-0 px-4">
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import SearchInput from './SearchInput';
|
||||
import UserDropdown from './UserDropdown';
|
||||
import Sidebar from './Sidebar';
|
||||
import LanguagePicker from './LanguagePicker';
|
||||
import { useRouter } from 'next/router';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { Permission, useUser } from '../../hooks/useUser';
|
||||
import LanguagePicker from './LanguagePicker';
|
||||
import SearchInput from './SearchInput';
|
||||
import Sidebar from './Sidebar';
|
||||
import UserDropdown from './UserDropdown';
|
||||
|
||||
const messages = defineMessages({
|
||||
alphawarning:
|
||||
@@ -37,14 +37,14 @@ const Layout: React.FC = ({ children }) => {
|
||||
|
||||
return (
|
||||
<div className="flex h-full min-w-0 min-h-full bg-gray-900">
|
||||
<div className="absolute w-full h-64 from-gray-800 to-gray-900 bg-gradient-to-bl">
|
||||
<div className="absolute top-0 w-full h-64 from-gray-800 to-gray-900 bg-gradient-to-bl">
|
||||
<div className="relative inset-0 w-full h-full from-gray-900 to-transparent bg-gradient-to-t" />
|
||||
</div>
|
||||
<Sidebar open={isSidebarOpen} setClosed={() => setSidebarOpen(false)} />
|
||||
|
||||
<div className="relative flex flex-col flex-1 w-0 min-w-0 mb-16 md:ml-64">
|
||||
<div
|
||||
className={`fixed left-0 right-0 z-10 flex flex-shrink-0 h-16 bg-opacity-80 transition duration-300 ${
|
||||
className={`searchbar fixed left-0 right-0 top-0 z-10 flex flex-shrink-0 bg-opacity-80 transition duration-300 ${
|
||||
isScrolled ? 'bg-gray-700' : 'bg-transparent'
|
||||
} md:left-64`}
|
||||
style={{
|
||||
|
@@ -1,16 +1,16 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import PlexLoginButton from '../PlexLoginButton';
|
||||
import { useUser } from '../../hooks/useUser';
|
||||
import axios from 'axios';
|
||||
import { useRouter } from 'next/dist/client/router';
|
||||
import ImageFader from '../Common/ImageFader';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import Transition from '../Transition';
|
||||
import LanguagePicker from '../Layout/LanguagePicker';
|
||||
import LocalLogin from './LocalLogin';
|
||||
import Accordion from '../Common/Accordion';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
import { useUser } from '../../hooks/useUser';
|
||||
import Accordion from '../Common/Accordion';
|
||||
import ImageFader from '../Common/ImageFader';
|
||||
import PageTitle from '../Common/PageTitle';
|
||||
import LanguagePicker from '../Layout/LanguagePicker';
|
||||
import PlexLoginButton from '../PlexLoginButton';
|
||||
import Transition from '../Transition';
|
||||
import LocalLogin from './LocalLogin';
|
||||
|
||||
const messages = defineMessages({
|
||||
signin: 'Sign In',
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { groupBy } from 'lodash';
|
||||
import { useRouter } from 'next/router';
|
||||
import React, { useContext, useMemo, useState } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import TruncateMarkup from 'react-truncate-markup';
|
||||
import useSWR from 'swr';
|
||||
import type { PersonDetail } from '../../../server/models/Person';
|
||||
import type { PersonCombinedCreditsResponse } from '../../../server/interfaces/api/personInterfaces';
|
||||
import Error from '../../pages/_error';
|
||||
import LoadingSpinner from '../Common/LoadingSpinner';
|
||||
import TitleCard from '../TitleCard';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { LanguageContext } from '../../context/LanguageContext';
|
||||
import ImageFader from '../Common/ImageFader';
|
||||
import type { PersonDetail } from '../../../server/models/Person';
|
||||
import Ellipsis from '../../assets/ellipsis.svg';
|
||||
import { groupBy } from 'lodash';
|
||||
import PageTitle from '../Common/PageTitle';
|
||||
import { LanguageContext } from '../../context/LanguageContext';
|
||||
import Error from '../../pages/_error';
|
||||
import CachedImage from '../Common/CachedImage';
|
||||
import ImageFader from '../Common/ImageFader';
|
||||
import LoadingSpinner from '../Common/LoadingSpinner';
|
||||
import PageTitle from '../Common/PageTitle';
|
||||
import TitleCard from '../TitleCard';
|
||||
|
||||
const messages = defineMessages({
|
||||
appearsin: 'Appearances',
|
||||
@@ -166,7 +166,7 @@ const PersonDetails: React.FC = () => {
|
||||
<>
|
||||
<PageTitle title={data.name} />
|
||||
{(sortedCrew || sortedCast) && (
|
||||
<div className="absolute left-0 right-0 z-0 -top-16 h-96">
|
||||
<div className="absolute top-0 left-0 right-0 z-0 h-96">
|
||||
<ImageFader
|
||||
isDarker
|
||||
backgroundImages={[...(sortedCast ?? []), ...(sortedCrew ?? [])]
|
||||
|
@@ -1,22 +1,22 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import '../styles/globals.css';
|
||||
import App, { AppInitialProps, AppProps } from 'next/app';
|
||||
import { SWRConfig } from 'swr';
|
||||
import { ToastProvider } from 'react-toast-notifications';
|
||||
import { parseCookies, setCookie } from 'nookies';
|
||||
import Layout from '../components/Layout';
|
||||
import { UserContext } from '../context/UserContext';
|
||||
import axios from 'axios';
|
||||
import { User } from '../hooks/useUser';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { LanguageContext, AvailableLocales } from '../context/LanguageContext';
|
||||
import App, { AppInitialProps, AppProps } from 'next/app';
|
||||
import Head from 'next/head';
|
||||
import { parseCookies, setCookie } from 'nookies';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { ToastProvider } from 'react-toast-notifications';
|
||||
import { SWRConfig } from 'swr';
|
||||
import { PublicSettingsResponse } from '../../server/interfaces/api/settingsInterfaces';
|
||||
import Layout from '../components/Layout';
|
||||
import LoadingBar from '../components/LoadingBar';
|
||||
import StatusChecker from '../components/StatusChacker';
|
||||
import Toast from '../components/Toast';
|
||||
import { InteractionProvider } from '../context/InteractionContext';
|
||||
import StatusChecker from '../components/StatusChacker';
|
||||
import { PublicSettingsResponse } from '../../server/interfaces/api/settingsInterfaces';
|
||||
import { AvailableLocales, LanguageContext } from '../context/LanguageContext';
|
||||
import { SettingsProvider } from '../context/SettingsContext';
|
||||
import LoadingBar from '../components/LoadingBar';
|
||||
import { UserContext } from '../context/UserContext';
|
||||
import { User } from '../hooks/useUser';
|
||||
import '../styles/globals.css';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const loadLocaleData = (locale: AvailableLocales): Promise<any> => {
|
||||
@@ -122,8 +122,8 @@ const CoreApp: Omit<NextAppComponentType, 'origGetInitialProps'> = ({
|
||||
<title>Overseerr</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1"
|
||||
/>
|
||||
content="initial-scale=1, viewport-fit=cover, width=device-width"
|
||||
></meta>
|
||||
</Head>
|
||||
<StatusChecker />
|
||||
<UserContext initialUser={user}>{component}</UserContext>
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import React from 'react';
|
||||
import Document, {
|
||||
Html,
|
||||
Head,
|
||||
Main,
|
||||
NextScript,
|
||||
DocumentContext,
|
||||
DocumentInitialProps,
|
||||
Head,
|
||||
Html,
|
||||
Main,
|
||||
NextScript,
|
||||
} from 'next/document';
|
||||
import React from 'react';
|
||||
|
||||
class MyDocument extends Document {
|
||||
static async getInitialProps(
|
||||
@@ -39,6 +39,11 @@ class MyDocument extends Document {
|
||||
sizes="16x16"
|
||||
href="/favicon-16x16.png"
|
||||
/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta
|
||||
name="apple-mobile-web-app-status-bar-style"
|
||||
content="black-translucent"
|
||||
/>
|
||||
<link rel="manifest" href="/site.webmanifest"></link>
|
||||
</Head>
|
||||
<body>
|
||||
|
@@ -3,10 +3,43 @@
|
||||
@tailwind utilities;
|
||||
@tailwind screens;
|
||||
|
||||
html {
|
||||
min-height: calc(100% + env(safe-area-inset-top));
|
||||
padding: env(safe-area-inset-top) env(safe-area-inset-right)
|
||||
env(safe-area-inset-bottom) env(safe-area-inset-left);
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-gray-900;
|
||||
}
|
||||
|
||||
.searchbar {
|
||||
padding-top: env(safe-area-inset-top);
|
||||
height: calc(4rem + env(safe-area-inset-top));
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-left: env(safe-area-inset-left);
|
||||
}
|
||||
|
||||
.slideover {
|
||||
padding-top: calc(1.5rem + env(safe-area-inset-top));
|
||||
padding-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.sidebar-close-button {
|
||||
top: env(safe-area-inset-top);
|
||||
}
|
||||
|
||||
.absolute-top-shift {
|
||||
top: calc(-4rem - env(safe-area-inset-top));
|
||||
}
|
||||
|
||||
.min-h-screen-shift {
|
||||
min-height: calc(100vh + env(safe-area-inset-top));
|
||||
}
|
||||
|
||||
.plex-button {
|
||||
@apply flex justify-center w-full px-4 py-2 text-sm font-medium text-center text-white transition duration-150 ease-in-out bg-indigo-600 border border-transparent rounded-md disabled:opacity-50;
|
||||
background-color: #cc7b19;
|
||||
@@ -42,7 +75,9 @@ a.slider-title {
|
||||
}
|
||||
|
||||
.media-page {
|
||||
@apply relative px-4 pt-16 -mx-4 -mt-16 bg-center bg-cover;
|
||||
@apply relative px-4 -mx-4 bg-center bg-cover;
|
||||
margin-top: calc(-4rem - env(safe-area-inset-top));
|
||||
padding-top: calc(4rem + env(safe-area-inset-top));
|
||||
}
|
||||
|
||||
.media-page-bg-image {
|
||||
|
Reference in New Issue
Block a user