mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
feat(frontend): adjust person details design and add improved truncate
This commit is contained in:
@@ -44,6 +44,7 @@
|
||||
"react-spring": "^8.0.27",
|
||||
"react-toast-notifications": "^2.4.0",
|
||||
"react-transition-group": "^4.4.1",
|
||||
"react-truncate-markup": "^5.0.1",
|
||||
"react-use-clipboard": "1.0.2",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"sqlite3": "^5.0.0",
|
||||
|
6
src/assets/ellipsis.svg
Normal file
6
src/assets/ellipsis.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="22" height="10" viewBox="0 0 22 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="22" height="10" rx="2" fill="#718096"/>
|
||||
<circle cx="5" cy="5" r="2" fill="#E2E8F0"/>
|
||||
<circle cx="11" cy="5" r="2" fill="#E2E8F0"/>
|
||||
<circle cx="17" cy="5" r="2" fill="#E2E8F0"/>
|
||||
</svg>
|
After Width: | Height: | Size: 293 B |
@@ -8,12 +8,18 @@ import React, {
|
||||
interface ImageFaderProps extends HTMLAttributes<HTMLDivElement> {
|
||||
backgroundImages: string[];
|
||||
rotationSpeed?: number;
|
||||
isDarker?: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_ROTATION_SPEED = 6000;
|
||||
|
||||
const ImageFader: ForwardRefRenderFunction<HTMLDivElement, ImageFaderProps> = (
|
||||
{ backgroundImages, rotationSpeed = DEFAULT_ROTATION_SPEED, ...props },
|
||||
{
|
||||
backgroundImages,
|
||||
rotationSpeed = DEFAULT_ROTATION_SPEED,
|
||||
isDarker,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const [activeIndex, setIndex] = useState(0);
|
||||
@@ -29,6 +35,14 @@ const ImageFader: ForwardRefRenderFunction<HTMLDivElement, ImageFaderProps> = (
|
||||
};
|
||||
}, [backgroundImages, rotationSpeed]);
|
||||
|
||||
let gradient =
|
||||
'linear-gradient(180deg, rgba(45, 55, 72, 0.47) 0%, #1A202E 100%)';
|
||||
|
||||
if (isDarker) {
|
||||
gradient =
|
||||
'linear-gradient(180deg, rgba(17, 24, 39, 0.47) 0%, rgba(17, 24, 39, 1) 100%)';
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
{backgroundImages.map((imageUrl, i) => (
|
||||
@@ -38,7 +52,7 @@ const ImageFader: ForwardRefRenderFunction<HTMLDivElement, ImageFaderProps> = (
|
||||
i === activeIndex ? 'opacity-100' : 'opacity-0'
|
||||
}`}
|
||||
style={{
|
||||
backgroundImage: `linear-gradient(180deg, rgba(45, 55, 72, 0.47) 0%, #1A202E 100%), url(${imageUrl})`,
|
||||
backgroundImage: `${gradient}, url(${imageUrl})`,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { useRouter } from 'next/router';
|
||||
import React, { useContext, useState } from 'react';
|
||||
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';
|
||||
@@ -8,6 +9,8 @@ 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 Ellipsis from '../../assets/ellipsis.svg';
|
||||
|
||||
const messages = defineMessages({
|
||||
appearsin: 'Appears in',
|
||||
@@ -74,7 +77,21 @@ const PersonDetails: React.FC = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col items-center mt-8 mb-8 md:flex-row md:items-start">
|
||||
{(sortedCrew || sortedCast) && (
|
||||
<div className="absolute top-0 left-0 right-0 z-0 h-96">
|
||||
<ImageFader
|
||||
isDarker
|
||||
backgroundImages={[...(sortedCrew ?? []), ...(sortedCast ?? [])]
|
||||
.filter((media) => media.posterPath)
|
||||
.map(
|
||||
(media) =>
|
||||
`//image.tmdb.org/t/p/w1920_and_h800_multi_faces/${media.posterPath}`
|
||||
)
|
||||
.slice(0, 6)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="relative z-10 flex flex-col items-center mt-8 mb-8 md:flex-row md:items-start">
|
||||
{data.profilePath && (
|
||||
<div
|
||||
style={{
|
||||
@@ -88,30 +105,30 @@ const PersonDetails: React.FC = () => {
|
||||
<div className="relative">
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
|
||||
<div
|
||||
className={`transition-max-height duration-300 ${
|
||||
showBio
|
||||
? 'overflow-visible extra-max-height'
|
||||
: 'overflow-hidden max-h-44'
|
||||
}`}
|
||||
className="outline-none group ring-0"
|
||||
onClick={() => setShowBio((show) => !show)}
|
||||
role="button"
|
||||
tabIndex={-1}
|
||||
>
|
||||
<div className={showBio ? 'h-auto' : 'h-36'}>
|
||||
{data.biography
|
||||
? data.biography
|
||||
: intl.formatMessage(messages.nobiography)}
|
||||
</div>
|
||||
{!showBio && (
|
||||
<div className="absolute bottom-0 left-0 right-0 w-full h-8 bg-gradient-to-t from-gray-900" />
|
||||
)}
|
||||
<TruncateMarkup
|
||||
lines={showBio ? 200 : 6}
|
||||
ellipsis={
|
||||
<Ellipsis className="relative inline-block ml-2 -top-0.5 opacity-70 group-hover:opacity-100 transition duration-300" />
|
||||
}
|
||||
>
|
||||
<div>
|
||||
{data.biography
|
||||
? data.biography
|
||||
: intl.formatMessage(messages.nobiography)}
|
||||
</div>
|
||||
</TruncateMarkup>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{(sortedCast ?? []).length > 0 && (
|
||||
<>
|
||||
<div className="mt-6 mb-4 md:flex md:items-center md:justify-between">
|
||||
<div className="relative z-10 mt-6 mb-4 md:flex md:items-center md:justify-between">
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="inline-flex items-center text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate">
|
||||
<span>{intl.formatMessage(messages.appearsin)}</span>
|
||||
@@ -157,7 +174,7 @@ const PersonDetails: React.FC = () => {
|
||||
)}
|
||||
{(sortedCrew ?? []).length > 0 && (
|
||||
<>
|
||||
<div className="mt-6 mb-4 md:flex md:items-center md:justify-between">
|
||||
<div className="relative z-10 mt-6 mb-4 md:flex md:items-center md:justify-between">
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="inline-flex items-center text-xl leading-7 text-gray-300 hover:text-white sm:text-2xl sm:leading-9 sm:truncate">
|
||||
<span>{intl.formatMessage(messages.crewmember)}</span>
|
||||
|
@@ -62,7 +62,7 @@ module.exports = {
|
||||
borderWidth: ['first', 'last'],
|
||||
margin: ['first', 'last', 'responsive'],
|
||||
boxShadow: ['group-focus'],
|
||||
opacity: ['disabled', 'hover'],
|
||||
opacity: ['disabled', 'hover', 'group-hover'],
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/forms'),
|
||||
|
34
yarn.lock
34
yarn.lock
@@ -4162,6 +4162,11 @@ compose-function@3.0.3:
|
||||
dependencies:
|
||||
arity-n "^1.0.4"
|
||||
|
||||
computed-style@~0.1.3:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/computed-style/-/computed-style-0.1.4.tgz#7f344fd8584b2e425bedca4a1afc0e300bb05d74"
|
||||
integrity sha1-fzRP2FhLLkJb7cpKGvwOMAuwXXQ=
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
@@ -8155,6 +8160,13 @@ line-column@^1.0.2:
|
||||
isarray "^1.0.0"
|
||||
isobject "^2.0.0"
|
||||
|
||||
line-height@0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/line-height/-/line-height-0.3.1.tgz#4b1205edde182872a5efa3c8f620b3187a9c54c9"
|
||||
integrity sha1-SxIF7d4YKHKl76PI9iCzGHqcVMk=
|
||||
dependencies:
|
||||
computed-style "~0.1.3"
|
||||
|
||||
lines-and-columns@^1.1.6:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
|
||||
@@ -8713,6 +8725,11 @@ mem@^1.1.0:
|
||||
dependencies:
|
||||
mimic-fn "^1.0.0"
|
||||
|
||||
memoize-one@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0"
|
||||
integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==
|
||||
|
||||
memory-fs@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
|
||||
@@ -11019,7 +11036,7 @@ promzard@^0.3.0:
|
||||
dependencies:
|
||||
read "1"
|
||||
|
||||
prop-types@15.7.2, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
prop-types@15.7.2, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||
@@ -11448,6 +11465,16 @@ react-transition-group@^4.3.0, react-transition-group@^4.4.1:
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.6.2"
|
||||
|
||||
react-truncate-markup@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-truncate-markup/-/react-truncate-markup-5.0.1.tgz#5c52bda712f7e185e84969b2b79440ec8b422441"
|
||||
integrity sha512-WG1E9FLyTrq5ERaDbIq0DjWVs3JrAdr93fasdQqbVlEifBUp27kGM7ws4xCBIh2keDjumTPjw3iiHNNmD+YtcQ==
|
||||
dependencies:
|
||||
line-height "0.3.1"
|
||||
memoize-one "^5.1.1"
|
||||
prop-types "^15.6.0"
|
||||
resize-observer-polyfill "1.5.x"
|
||||
|
||||
react-use-clipboard@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-use-clipboard/-/react-use-clipboard-1.0.2.tgz#e00254ffc70b989daa41638325fa6557c7b89dd2"
|
||||
@@ -11852,6 +11879,11 @@ require-main-filename@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
|
||||
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
|
||||
|
||||
resize-observer-polyfill@1.5.x:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
|
||||
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
|
||||
|
||||
resolve-dir@^1.0.0, resolve-dir@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
|
||||
|
Reference in New Issue
Block a user