feat(ui): experimental status bar style change for ios pwa app

this might break things. just an experiment. :)
pull/1255/head
sct 4 years ago
parent 8ebc829250
commit 958cdf98fd
No known key found for this signature in database
GPG Key ID: 06A50468C67E272F

@ -17,5 +17,6 @@
], ],
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.organizeImports": true "source.organizeImports": true
} },
"editor.formatOnSave": true
} }

@ -1,8 +1,8 @@
import React, { import React, {
useState,
useEffect,
HTMLAttributes,
ForwardRefRenderFunction, ForwardRefRenderFunction,
HTMLAttributes,
useEffect,
useState,
} from 'react'; } from 'react';
import CachedImage from '../CachedImage'; import CachedImage from '../CachedImage';
@ -59,7 +59,7 @@ const ImageFader: ForwardRefRenderFunction<HTMLDivElement, ImageFaderProps> = (
{backgroundImages.map((imageUrl, i) => ( {backgroundImages.map((imageUrl, i) => (
<div <div
key={`banner-image-${i}`} 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' i === activeIndex ? 'opacity-100' : 'opacity-0'
}`} }`}
{...props} {...props}

@ -1,12 +1,12 @@
import React, { MouseEvent, ReactNode, useRef } from 'react'; import React, { MouseEvent, ReactNode, useRef } from 'react';
import ReactDOM from 'react-dom'; 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 { useIntl } from 'react-intl';
import useClickOutside from '../../../hooks/useClickOutside';
import { useLockBodyScroll } from '../../../hooks/useLockBodyScroll';
import globalMessages from '../../../i18n/globalMessages'; import globalMessages from '../../../i18n/globalMessages';
import Transition from '../../Transition'; import Transition from '../../Transition';
import Button, { ButtonType } from '../Button';
import LoadingSpinner from '../LoadingSpinner';
interface ModalProps { interface ModalProps {
title?: string; title?: string;
@ -98,11 +98,14 @@ const Modal: React.FC<ModalProps> = ({
show={!loading} show={!loading}
> >
<div <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" role="dialog"
aria-modal="true" aria-modal="true"
aria-labelledby="modal-headline" aria-labelledby="modal-headline"
ref={modalRef} ref={modalRef}
style={{
maxHeight: 'calc(100% - env(safe-area-inset-top) * 2)',
}}
> >
<div className="sm:flex sm:items-center"> <div className="sm:flex sm:items-center">
{iconSvg && ( {iconSvg && (

@ -1,8 +1,8 @@
/* eslint-disable jsx-a11y/click-events-have-key-events */ /* 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 ReactDOM from 'react-dom';
import Transition from '../../Transition';
import { useLockBodyScroll } from '../../../hooks/useLockBodyScroll'; import { useLockBodyScroll } from '../../../hooks/useLockBodyScroll';
import Transition from '../../Transition';
interface SlideOverProps { interface SlideOverProps {
show?: boolean; show?: boolean;
@ -70,7 +70,7 @@ const SlideOver: React.FC<SlideOverProps> = ({
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<div className="flex flex-col h-full overflow-y-scroll bg-gray-700 shadow-xl"> <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"> <div className="flex items-center justify-between space-x-3">
<h2 className="text-lg font-medium leading-7 text-white"> <h2 className="text-lg font-medium leading-7 text-white">
{title} {title}

@ -1,10 +1,10 @@
import React, { ReactNode, useRef } from 'react';
import Transition from '../../Transition';
import Link from 'next/link'; import Link from 'next/link';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React, { ReactNode, useRef } from 'react';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import { useUser, Permission } from '../../../hooks/useUser';
import useClickOutside from '../../../hooks/useClickOutside'; import useClickOutside from '../../../hooks/useClickOutside';
import { Permission, useUser } from '../../../hooks/useUser';
import Transition from '../../Transition';
const messages = defineMessages({ const messages = defineMessages({
dashboard: 'Discover', dashboard: 'Discover',
@ -148,8 +148,8 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
leaveTo="-translate-x-full" leaveTo="-translate-x-full"
> >
<> <>
<div className="relative flex flex-col flex-1 w-full max-w-xs bg-gray-800"> <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 -mr-14"> <div className="absolute top-0 right-0 p-1 sidebar-close-button -mr-14">
<button <button
className="flex items-center justify-center w-12 h-12 rounded-full focus:outline-none focus:bg-gray-600" className="flex items-center justify-center w-12 h-12 rounded-full focus:outline-none focus:bg-gray-600"
aria-label="Close sidebar" aria-label="Close sidebar"
@ -233,7 +233,7 @@ const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => {
</div> </div>
<div className="fixed top-0 bottom-0 left-0 hidden md:flex md:flex-shrink-0"> <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 h-0 bg-gray-800">
<div className="flex flex-col flex-1 pt-5 pb-4 overflow-y-auto"> <div className="flex flex-col flex-1 pt-5 pb-4 overflow-y-auto">
<div className="flex items-center flex-shrink-0 px-4"> <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 { useRouter } from 'next/router';
import React, { useEffect, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import { Permission, useUser } from '../../hooks/useUser'; 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({ const messages = defineMessages({
alphawarning: alphawarning:
@ -37,14 +37,14 @@ const Layout: React.FC = ({ children }) => {
return ( return (
<div className="flex h-full min-w-0 min-h-full bg-gray-900"> <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 className="relative inset-0 w-full h-full from-gray-900 to-transparent bg-gradient-to-t" />
</div> </div>
<Sidebar open={isSidebarOpen} setClosed={() => setSidebarOpen(false)} /> <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="relative flex flex-col flex-1 w-0 min-w-0 mb-16 md:ml-64">
<div <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' isScrolled ? 'bg-gray-700' : 'bg-transparent'
} md:left-64`} } md:left-64`}
style={{ 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 axios from 'axios';
import { useRouter } from 'next/dist/client/router'; 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 { 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 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 PageTitle from '../Common/PageTitle';
import LanguagePicker from '../Layout/LanguagePicker';
import PlexLoginButton from '../PlexLoginButton';
import Transition from '../Transition';
import LocalLogin from './LocalLogin';
const messages = defineMessages({ const messages = defineMessages({
signin: 'Sign In', signin: 'Sign In',

@ -1,19 +1,19 @@
import { groupBy } from 'lodash';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React, { useContext, useMemo, useState } from 'react'; import React, { useContext, useMemo, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import TruncateMarkup from 'react-truncate-markup'; import TruncateMarkup from 'react-truncate-markup';
import useSWR from 'swr'; import useSWR from 'swr';
import type { PersonDetail } from '../../../server/models/Person';
import type { PersonCombinedCreditsResponse } from '../../../server/interfaces/api/personInterfaces'; import type { PersonCombinedCreditsResponse } from '../../../server/interfaces/api/personInterfaces';
import Error from '../../pages/_error'; import type { PersonDetail } from '../../../server/models/Person';
import LoadingSpinner from '../Common/LoadingSpinner'; import Ellipsis from '../../assets/ellipsis.svg';
import TitleCard from '../TitleCard';
import { defineMessages, useIntl } from 'react-intl';
import { LanguageContext } from '../../context/LanguageContext'; import { LanguageContext } from '../../context/LanguageContext';
import Error from '../../pages/_error';
import CachedImage from '../Common/CachedImage';
import ImageFader from '../Common/ImageFader'; import ImageFader from '../Common/ImageFader';
import Ellipsis from '../../assets/ellipsis.svg'; import LoadingSpinner from '../Common/LoadingSpinner';
import { groupBy } from 'lodash';
import PageTitle from '../Common/PageTitle'; import PageTitle from '../Common/PageTitle';
import CachedImage from '../Common/CachedImage'; import TitleCard from '../TitleCard';
const messages = defineMessages({ const messages = defineMessages({
appearsin: 'Appearances', appearsin: 'Appearances',
@ -166,7 +166,7 @@ const PersonDetails: React.FC = () => {
<> <>
<PageTitle title={data.name} /> <PageTitle title={data.name} />
{(sortedCrew || sortedCast) && ( {(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 <ImageFader
isDarker isDarker
backgroundImages={[...(sortedCast ?? []), ...(sortedCrew ?? [])] backgroundImages={[...(sortedCast ?? []), ...(sortedCrew ?? [])]

@ -1,22 +1,22 @@
import React, { useEffect, useState } from 'react'; import axios from 'axios';
import '../styles/globals.css';
import App, { AppInitialProps, AppProps } from 'next/app'; import App, { AppInitialProps, AppProps } from 'next/app';
import { SWRConfig } from 'swr'; import Head from 'next/head';
import { ToastProvider } from 'react-toast-notifications';
import { parseCookies, setCookie } from 'nookies'; import { parseCookies, setCookie } from 'nookies';
import Layout from '../components/Layout'; import React, { useEffect, useState } from 'react';
import { UserContext } from '../context/UserContext';
import axios from 'axios';
import { User } from '../hooks/useUser';
import { IntlProvider } from 'react-intl'; import { IntlProvider } from 'react-intl';
import { LanguageContext, AvailableLocales } from '../context/LanguageContext'; import { ToastProvider } from 'react-toast-notifications';
import Head from 'next/head'; 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 Toast from '../components/Toast';
import { InteractionProvider } from '../context/InteractionContext'; import { InteractionProvider } from '../context/InteractionContext';
import StatusChecker from '../components/StatusChacker'; import { AvailableLocales, LanguageContext } from '../context/LanguageContext';
import { PublicSettingsResponse } from '../../server/interfaces/api/settingsInterfaces';
import { SettingsProvider } from '../context/SettingsContext'; 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 // eslint-disable-next-line @typescript-eslint/no-explicit-any
const loadLocaleData = (locale: AvailableLocales): Promise<any> => { const loadLocaleData = (locale: AvailableLocales): Promise<any> => {
@ -122,8 +122,8 @@ const CoreApp: Omit<NextAppComponentType, 'origGetInitialProps'> = ({
<title>Overseerr</title> <title>Overseerr</title>
<meta <meta
name="viewport" name="viewport"
content="width=device-width, initial-scale=1" content="initial-scale=1, viewport-fit=cover, width=device-width"
/> ></meta>
</Head> </Head>
<StatusChecker /> <StatusChecker />
<UserContext initialUser={user}>{component}</UserContext> <UserContext initialUser={user}>{component}</UserContext>

@ -1,12 +1,12 @@
import React from 'react';
import Document, { import Document, {
Html, DocumentContext,
DocumentInitialProps,
Head, Head,
Html,
Main, Main,
NextScript, NextScript,
DocumentContext,
DocumentInitialProps,
} from 'next/document'; } from 'next/document';
import React from 'react';
class MyDocument extends Document { class MyDocument extends Document {
static async getInitialProps( static async getInitialProps(
@ -39,6 +39,11 @@ class MyDocument extends Document {
sizes="16x16" sizes="16x16"
href="/favicon-16x16.png" 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> <link rel="manifest" href="/site.webmanifest"></link>
</Head> </Head>
<body> <body>

@ -3,10 +3,43 @@
@tailwind utilities; @tailwind utilities;
@tailwind screens; @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 { body {
@apply bg-gray-900; @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 { .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; @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; background-color: #cc7b19;
@ -42,7 +75,9 @@ a.slider-title {
} }
.media-page { .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 { .media-page-bg-image {

Loading…
Cancel
Save