Detail redesign round 2 bug fixes (#3990)

* increase full-width for measurement issue in apple devices
* trade left margin for more full-width
* removed isApple code from details page
This commit is contained in:
CJ
2023-08-02 01:15:09 -05:00
committed by GitHub
parent 65826fdbb3
commit 00ae40ad72
11 changed files with 104 additions and 51 deletions

View File

@@ -39,6 +39,7 @@ import { IUIConfig } from "./core/config";
import { releaseNotes } from "./docs/en/ReleaseNotes"; import { releaseNotes } from "./docs/en/ReleaseNotes";
import { getPlatformURL } from "./core/createClient"; import { getPlatformURL } from "./core/createClient";
import { lazyComponent } from "./utils/lazyComponent"; import { lazyComponent } from "./utils/lazyComponent";
import { isPlatformUniquelyRenderedByApple } from "./utils/apple";
const Performers = lazyComponent( const Performers = lazyComponent(
() => import("./components/Performers/Performers") () => import("./components/Performers/Performers")
@@ -67,6 +68,8 @@ const SceneDuplicateChecker = lazyComponent(
() => import("./components/SceneDuplicateChecker/SceneDuplicateChecker") () => import("./components/SceneDuplicateChecker/SceneDuplicateChecker")
); );
const appleRendering = isPlatformUniquelyRenderedByApple();
initPolyfills(); initPolyfills();
MousetrapPause(Mousetrap); MousetrapPause(Mousetrap);
@@ -274,7 +277,11 @@ export const App: React.FC = () => {
defaultTitle="Stash" defaultTitle="Stash"
/> />
{maybeRenderNavbar()} {maybeRenderNavbar()}
<div className="main container-fluid"> <div
className={`main container-fluid ${
appleRendering ? "apple" : ""
}`}
>
{renderContent()} {renderContent()}
</div> </div>
</InteractiveProvider> </InteractiveProvider>

View File

@@ -35,7 +35,6 @@ import { ConfigurationContext } from "src/hooks/Config";
import { IUIConfig } from "src/core/config"; import { IUIConfig } from "src/core/config";
import ImageUtils from "src/utils/image"; import ImageUtils from "src/utils/image";
import { useRatingKeybinds } from "src/hooks/keybinds"; import { useRatingKeybinds } from "src/hooks/keybinds";
import { isPlatformUniquelyRenderedByApple } from "src/utils/apple";
interface IProps { interface IProps {
movie: GQL.MovieDataFragment; movie: GQL.MovieDataFragment;
@@ -65,8 +64,6 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
const [backImage, setBackImage] = useState<string | null>(); const [backImage, setBackImage] = useState<string | null>();
const [encodingImage, setEncodingImage] = useState<boolean>(false); const [encodingImage, setEncodingImage] = useState<boolean>(false);
const appleRendering = isPlatformUniquelyRenderedByApple();
const defaultImage = const defaultImage =
movie.front_image_path && movie.front_image_path.includes("default=true") movie.front_image_path && movie.front_image_path.includes("default=true")
? true ? true
@@ -417,7 +414,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
<div <div
className={`detail-header ${isEditing ? "edit" : ""} ${ className={`detail-header ${isEditing ? "edit" : ""} ${
collapsed ? "collapsed" : !compactExpandedDetails ? "full-width" : "" collapsed ? "collapsed" : !compactExpandedDetails ? "full-width" : ""
} ${appleRendering ? "apple" : ""}`} }`}
> >
{maybeRenderHeaderBackgroundImage()} {maybeRenderHeaderBackgroundImage()}
<div className="detail-container"> <div className="detail-container">

View File

@@ -64,6 +64,7 @@ export const CompressedMovieDetailsPanel: React.FC<IMovieDetailsPanel> = ({
<a className="movie-name" onClick={() => scrollToTop()}> <a className="movie-name" onClick={() => scrollToTop()}>
{movie.name} {movie.name}
</a> </a>
<span className="detail-divider">/</span>
{movie?.studio?.name ? ( {movie?.studio?.name ? (
<span className="movie-studio">{movie?.studio?.name}</span> <span className="movie-studio">{movie?.studio?.name}</span>
) : ( ) : (

View File

@@ -43,7 +43,6 @@ import { faInstagram, faTwitter } from "@fortawesome/free-brands-svg-icons";
import { IUIConfig } from "src/core/config"; import { IUIConfig } from "src/core/config";
import { useRatingKeybinds } from "src/hooks/keybinds"; import { useRatingKeybinds } from "src/hooks/keybinds";
import ImageUtils from "src/utils/image"; import ImageUtils from "src/utils/image";
import { isPlatformUniquelyRenderedByApple } from "src/utils/apple";
interface IProps { interface IProps {
performer: GQL.PerformerDataFragment; performer: GQL.PerformerDataFragment;
@@ -73,8 +72,6 @@ const PerformerPage: React.FC<IProps> = ({ performer }) => {
const [encodingImage, setEncodingImage] = useState<boolean>(false); const [encodingImage, setEncodingImage] = useState<boolean>(false);
const [loadStickyHeader, setLoadStickyHeader] = useState<boolean>(false); const [loadStickyHeader, setLoadStickyHeader] = useState<boolean>(false);
const appleRendering = isPlatformUniquelyRenderedByApple();
const activeImage = useMemo(() => { const activeImage = useMemo(() => {
const performerImage = performer.image_path; const performerImage = performer.image_path;
if (isEditing) { if (isEditing) {
@@ -549,7 +546,7 @@ const PerformerPage: React.FC<IProps> = ({ performer }) => {
<div <div
className={`detail-header ${isEditing ? "edit" : ""} ${ className={`detail-header ${isEditing ? "edit" : ""} ${
collapsed ? "collapsed" : !compactExpandedDetails ? "full-width" : "" collapsed ? "collapsed" : !compactExpandedDetails ? "full-width" : ""
} ${appleRendering ? "apple" : ""}`} }`}
> >
{maybeRenderHeaderBackgroundImage()} {maybeRenderHeaderBackgroundImage()}
<div className="detail-container"> <div className="detail-container">

View File

@@ -97,6 +97,21 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
); );
}; };
const formatAge = (birthdate?: string | null, deathdate?: string | null) => {
if (!birthdate) {
return "";
}
const age = TextUtils.age(birthdate, deathdate);
return (
<span className="performer-age">
<span className="age">{age}</span>
<span className="birthdate"> ({birthdate})</span>
</span>
);
};
const formatWeight = (weight?: number | null) => { const formatWeight = (weight?: number | null) => {
if (!weight) { if (!weight) {
return ""; return "";
@@ -220,8 +235,16 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
)} )}
<DetailItem <DetailItem
id="age" id="age"
value={TextUtils.age(performer.birthdate, performer.death_date)} value={
title={TextUtils.formatDate(intl, performer.birthdate ?? undefined)} !fullWidth
? TextUtils.age(performer.birthdate, performer.death_date)
: formatAge(performer.birthdate, performer.death_date)
}
title={
!fullWidth
? TextUtils.formatDate(intl, performer.birthdate ?? undefined)
: ""
}
fullWidth={fullWidth} fullWidth={fullWidth}
/> />
<DetailItem id="death_date" value={performer.death_date} /> <DetailItem id="death_date" value={performer.death_date} />
@@ -306,6 +329,7 @@ export const CompressedPerformerDetailsPanel: React.FC<IPerformerDetails> = ({
<a className="performer-name" onClick={() => scrollToTop()}> <a className="performer-name" onClick={() => scrollToTop()}>
{performer.name} {performer.name}
</a> </a>
<span className="detail-divider">/</span>
{performer.gender ? ( {performer.gender ? (
<span className="performer-gender"> <span className="performer-gender">
{intl.formatMessage({ id: "gender_types." + performer.gender })} {intl.formatMessage({ id: "gender_types." + performer.gender })}
@@ -313,6 +337,7 @@ export const CompressedPerformerDetailsPanel: React.FC<IPerformerDetails> = ({
) : ( ) : (
"" ""
)} )}
<span className="detail-divider">/</span>
{performer.birthdate ? ( {performer.birthdate ? (
<span <span
className="performer-age" className="performer-age"
@@ -323,6 +348,7 @@ export const CompressedPerformerDetailsPanel: React.FC<IPerformerDetails> = ({
) : ( ) : (
"" ""
)} )}
<span className="detail-divider">/</span>
{performer.country ? ( {performer.country ? (
<span className="performer-country"> <span className="performer-country">
<CountryFlag <CountryFlag

View File

@@ -48,6 +48,7 @@
} }
} }
.col-md-8 .details-edit div:nth-last-child(2),
.detail-header.edit .details-edit div:nth-last-child(2) { .detail-header.edit .details-edit div:nth-last-child(2) {
flex: 1; flex: 1;
max-width: 100%; max-width: 100%;

View File

@@ -42,7 +42,6 @@ import TextUtils from "src/utils/text";
import { RatingSystem } from "src/components/Shared/Rating/RatingSystem"; import { RatingSystem } from "src/components/Shared/Rating/RatingSystem";
import ImageUtils from "src/utils/image"; import ImageUtils from "src/utils/image";
import { useRatingKeybinds } from "src/hooks/keybinds"; import { useRatingKeybinds } from "src/hooks/keybinds";
import { isPlatformUniquelyRenderedByApple } from "src/utils/apple";
interface IProps { interface IProps {
studio: GQL.StudioDataFragment; studio: GQL.StudioDataFragment;
@@ -69,8 +68,6 @@ const StudioPage: React.FC<IProps> = ({ studio }) => {
const [collapsed, setCollapsed] = useState<boolean>(!showAllDetails); const [collapsed, setCollapsed] = useState<boolean>(!showAllDetails);
const [loadStickyHeader, setLoadStickyHeader] = useState<boolean>(false); const [loadStickyHeader, setLoadStickyHeader] = useState<boolean>(false);
const appleRendering = isPlatformUniquelyRenderedByApple();
// Editing state // Editing state
const [isEditing, setIsEditing] = useState<boolean>(false); const [isEditing, setIsEditing] = useState<boolean>(false);
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false); const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
@@ -507,7 +504,7 @@ const StudioPage: React.FC<IProps> = ({ studio }) => {
<div <div
className={`detail-header ${isEditing ? "edit" : ""} ${ className={`detail-header ${isEditing ? "edit" : ""} ${
collapsed ? "collapsed" : !compactExpandedDetails ? "full-width" : "" collapsed ? "collapsed" : !compactExpandedDetails ? "full-width" : ""
} ${appleRendering ? "apple" : ""}`} }`}
> >
{maybeRenderHeaderBackgroundImage()} {maybeRenderHeaderBackgroundImage()}
<div className="detail-container"> <div className="detail-container">

View File

@@ -89,6 +89,7 @@ export const CompressedStudioDetailsPanel: React.FC<IStudioDetailsPanel> = ({
<a className="studio-name" onClick={() => scrollToTop()}> <a className="studio-name" onClick={() => scrollToTop()}>
{studio.name} {studio.name}
</a> </a>
<span className="detail-divider">/</span>
{studio?.parent_studio?.name ? ( {studio?.parent_studio?.name ? (
<span className="studio-parent">{studio?.parent_studio?.name}</span> <span className="studio-parent">{studio?.parent_studio?.name}</span>
) : ( ) : (

View File

@@ -38,7 +38,6 @@ import {
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { IUIConfig } from "src/core/config"; import { IUIConfig } from "src/core/config";
import ImageUtils from "src/utils/image"; import ImageUtils from "src/utils/image";
import { isPlatformUniquelyRenderedByApple } from "src/utils/apple";
interface IProps { interface IProps {
tag: GQL.TagDataFragment; tag: GQL.TagDataFragment;
@@ -64,8 +63,6 @@ const TagPage: React.FC<IProps> = ({ tag }) => {
const [collapsed, setCollapsed] = useState<boolean>(!showAllDetails); const [collapsed, setCollapsed] = useState<boolean>(!showAllDetails);
const [loadStickyHeader, setLoadStickyHeader] = useState<boolean>(false); const [loadStickyHeader, setLoadStickyHeader] = useState<boolean>(false);
const appleRendering = isPlatformUniquelyRenderedByApple();
const { tab = "scenes" } = useParams<ITabParams>(); const { tab = "scenes" } = useParams<ITabParams>();
// Editing state // Editing state
@@ -499,7 +496,7 @@ const TagPage: React.FC<IProps> = ({ tag }) => {
<div <div
className={`detail-header ${isEditing ? "edit" : ""} ${ className={`detail-header ${isEditing ? "edit" : ""} ${
collapsed ? "collapsed" : !compactExpandedDetails ? "full-width" : "" collapsed ? "collapsed" : !compactExpandedDetails ? "full-width" : ""
} ${appleRendering ? "apple" : ""}`} }`}
> >
{maybeRenderHeaderBackgroundImage()} {maybeRenderHeaderBackgroundImage()}
<div className="detail-container"> <div className="detail-container">

View File

@@ -79,6 +79,7 @@ export const CompressedTagDetailsPanel: React.FC<ITagDetails> = ({ tag }) => {
<a className="tag-name" onClick={() => scrollToTop()}> <a className="tag-name" onClick={() => scrollToTop()}>
{tag.name} {tag.name}
</a> </a>
<span className="detail-divider">/</span>
{tag.description ? ( {tag.description ? (
<span className="tag-desc">{tag.description}</span> <span className="tag-desc">{tag.description}</span>
) : ( ) : (

View File

@@ -69,26 +69,6 @@ dd {
white-space: pre-line; white-space: pre-line;
} }
.sticky.detail-header-group {
padding: 1rem 2.5rem;
a.movie-name,
a.performer-name,
a.studio-name,
a.tag-name {
color: #f5f8fa;
cursor: pointer;
font-weight: 800;
}
a,
span {
color: #d7d9db;
font-weight: 600;
padding-right: 1.5rem;
}
}
.sticky.detail-header { .sticky.detail-header {
display: block; display: block;
min-height: 50px; min-height: 50px;
@@ -107,6 +87,32 @@ dd {
.tag-name { .tag-name {
font-weight: 800; font-weight: 800;
} }
.sticky.detail-header-group {
padding: 1rem 2.5rem;
a.movie-name,
a.performer-name,
a.studio-name,
a.tag-name {
color: #f5f8fa;
cursor: pointer;
font-weight: 800;
}
a,
span {
color: #d7d9db;
font-weight: 600;
padding-right: 0.5rem;
}
.detail-divider {
font-size: 1rem;
font-weight: 400;
opacity: 0.6;
}
}
} }
.detail-expand-collapse { .detail-expand-collapse {
@@ -170,6 +176,11 @@ dd {
border-bottom: 1px dotted #f5f8fa; border-bottom: 1px dotted #f5f8fa;
margin-right: auto; margin-right: auto;
} }
.performer-disambiguation {
letter-spacing: -0.04rem;
opacity: 0.65;
}
} }
h2 { h2 {
@@ -195,7 +206,7 @@ dd {
.detail-header.edit { .detail-header.edit {
background-color: unset; background-color: unset;
overflow: auto; overflow: visible;
form { form {
padding-top: 0.5rem; padding-top: 0.5rem;
@@ -208,6 +219,11 @@ dd {
.detail-header-image { .detail-header-image {
height: auto; height: auto;
} }
/* StashID alignment fix */
.form-group.row .row.no-gutters {
padding-top: calc(0.375rem + 1px);
}
} }
.detail-header.collapsed { .detail-header.collapsed {
@@ -255,14 +271,11 @@ dd {
.detail-item-title { .detail-item-title {
display: table-cell; display: table-cell;
width: 100px; width: 130px;
}
.detail-item-value {
margin-left: 1.5rem;
} }
.detail-item-value.age { .detail-item-value.age {
border-bottom: unset;
width: fit-content; width: fit-content;
} }
} }
@@ -360,13 +373,21 @@ dd {
/* the .apple class denotes areas where rendering on some apple platforms has been inconsistent with other platforms /* the .apple class denotes areas where rendering on some apple platforms has been inconsistent with other platforms
these rules aim to address those inconsistences */ these rules aim to address those inconsistences */
.detail-header.apple .detail-container { .apple {
display: flex; .detail-header {
} .detail-container {
display: flex;
}
}
.detail-header.full-width.apple .detail-header-image, .detail-header.edit .row {
.detail-header.edit.apple .detail-header-image { flex: 1;
display: unset; }
.detail-header.full-width .detail-header-image,
.detail-header.edit .detail-header-image {
display: unset;
}
} }
.detail-item-title { .detail-item-title {
@@ -379,6 +400,13 @@ dd {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
white-space: pre-line; white-space: pre-line;
.birthdate,
.height-imperial,
.penis-length-imperial,
.weight-imperial {
opacity: 0.65;
}
} }
.input-control, .input-control,