mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
Various detail page refactoring (#5037)
* Refactor repeated code into BackgroundImage * Move BackgroundImage into Details folder * Refactor performer tabs * Refactor studio tabs * Refactor tag tabs * Refactor repeated code into DetailTitle * Refactor repeated collapse button code into component * Reuse FavoriteIcon in details pages * Refactor performer urls into component * Refactor alias list into component * Refactor repeated image code into HeaderImage and LightboxLink components * Replace render functions with inline conditional rendering * Support new twitter hostname
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Button, Tabs, Tab } from "react-bootstrap";
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Tabs, Tab } from "react-bootstrap";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { useHistory, Redirect, RouteComponentProps } from "react-router-dom";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { Helmet } from "react-helmet";
|
||||
@@ -13,14 +13,12 @@ import {
|
||||
useStudioDestroy,
|
||||
mutateMetadataAutoTag,
|
||||
} from "src/core/StashService";
|
||||
import { Counter } from "src/components/Shared/Counter";
|
||||
import { DetailsEditNavbar } from "src/components/Shared/DetailsEditNavbar";
|
||||
import { ModalComponent } from "src/components/Shared/Modal";
|
||||
import { LoadingIndicator } from "src/components/Shared/LoadingIndicator";
|
||||
import { ErrorMessage } from "src/components/Shared/ErrorMessage";
|
||||
import { useToast } from "src/hooks/Toast";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import { Icon } from "src/components/Shared/Icon";
|
||||
import { StudioScenesPanel } from "./StudioScenesPanel";
|
||||
import { StudioGalleriesPanel } from "./StudioGalleriesPanel";
|
||||
import { StudioImagesPanel } from "./StudioImagesPanel";
|
||||
@@ -32,20 +30,23 @@ import {
|
||||
StudioDetailsPanel,
|
||||
} from "./StudioDetailsPanel";
|
||||
import { StudioGroupsPanel } from "./StudioGroupsPanel";
|
||||
import {
|
||||
faTrashAlt,
|
||||
faLink,
|
||||
faChevronDown,
|
||||
faChevronUp,
|
||||
faHeart,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import TextUtils from "src/utils/text";
|
||||
import { faTrashAlt } from "@fortawesome/free-solid-svg-icons";
|
||||
import { RatingSystem } from "src/components/Shared/Rating/RatingSystem";
|
||||
import { DetailImage } from "src/components/Shared/DetailImage";
|
||||
import { useRatingKeybinds } from "src/hooks/keybinds";
|
||||
import { useLoadStickyHeader } from "src/hooks/detailsPanel";
|
||||
import { useScrollToTopOnMount } from "src/hooks/scrollToTop";
|
||||
import { ExternalLink } from "src/components/Shared/ExternalLink";
|
||||
import { BackgroundImage } from "src/components/Shared/DetailsPage/BackgroundImage";
|
||||
import {
|
||||
TabTitleCounter,
|
||||
useTabKey,
|
||||
} from "src/components/Shared/DetailsPage/Tabs";
|
||||
import { DetailTitle } from "src/components/Shared/DetailsPage/DetailTitle";
|
||||
import { ExpandCollapseButton } from "src/components/Shared/CollapseButton";
|
||||
import { FavoriteIcon } from "src/components/Shared/FavoriteIcon";
|
||||
import { ExternalLinkButtons } from "src/components/Shared/ExternalLinksButton";
|
||||
import { AliasList } from "src/components/Shared/DetailsPage/AliasList";
|
||||
import { HeaderImage } from "src/components/Shared/DetailsPage/HeaderImage";
|
||||
|
||||
interface IProps {
|
||||
studio: GQL.StudioDataFragment;
|
||||
@@ -72,34 +73,12 @@ function isTabKey(tab: string): tab is TabKey {
|
||||
return validTabs.includes(tab as TabKey);
|
||||
}
|
||||
|
||||
const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
||||
const history = useHistory();
|
||||
const Toast = useToast();
|
||||
const intl = useIntl();
|
||||
|
||||
// Configuration settings
|
||||
const { configuration } = React.useContext(ConfigurationContext);
|
||||
const uiConfig = configuration?.ui;
|
||||
const abbreviateCounter = uiConfig?.abbreviateCounters ?? false;
|
||||
const enableBackgroundImage = uiConfig?.enableStudioBackgroundImage ?? false;
|
||||
const showAllDetails = uiConfig?.showAllDetails ?? true;
|
||||
const compactExpandedDetails = uiConfig?.compactExpandedDetails ?? false;
|
||||
|
||||
const [collapsed, setCollapsed] = useState<boolean>(!showAllDetails);
|
||||
const loadStickyHeader = useLoadStickyHeader();
|
||||
|
||||
// Editing state
|
||||
const [isEditing, setIsEditing] = useState<boolean>(false);
|
||||
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
|
||||
|
||||
// Editing studio state
|
||||
const [image, setImage] = useState<string | null>();
|
||||
const [encodingImage, setEncodingImage] = useState<boolean>(false);
|
||||
|
||||
const [updateStudio] = useStudioUpdate();
|
||||
const [deleteStudio] = useStudioDestroy({ id: studio.id });
|
||||
|
||||
const showAllCounts = uiConfig?.showChildStudioContent;
|
||||
const StudioTabs: React.FC<{
|
||||
tabKey?: TabKey;
|
||||
studio: GQL.StudioDataFragment;
|
||||
abbreviateCounter: boolean;
|
||||
showAllCounts?: boolean;
|
||||
}> = ({ tabKey, studio, abbreviateCounter, showAllCounts = false }) => {
|
||||
const sceneCount =
|
||||
(showAllCounts ? studio.scene_count_all : studio.scene_count) ?? 0;
|
||||
const galleryCount =
|
||||
@@ -137,23 +116,151 @@ const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
||||
studio,
|
||||
]);
|
||||
|
||||
const setTabKey = useCallback(
|
||||
(newTabKey: string | null) => {
|
||||
if (!newTabKey) newTabKey = populatedDefaultTab;
|
||||
if (newTabKey === tabKey) return;
|
||||
const { setTabKey } = useTabKey({
|
||||
tabKey,
|
||||
validTabs,
|
||||
defaultTabKey: populatedDefaultTab,
|
||||
baseURL: `/studios/${studio.id}`,
|
||||
});
|
||||
|
||||
if (isTabKey(newTabKey)) {
|
||||
history.replace(`/studios/${studio.id}/${newTabKey}`);
|
||||
}
|
||||
},
|
||||
[populatedDefaultTab, tabKey, history, studio.id]
|
||||
return (
|
||||
<Tabs
|
||||
id="studio-tabs"
|
||||
mountOnEnter
|
||||
unmountOnExit
|
||||
activeKey={tabKey}
|
||||
onSelect={setTabKey}
|
||||
>
|
||||
<Tab
|
||||
eventKey="scenes"
|
||||
title={
|
||||
<TabTitleCounter
|
||||
messageID="scenes"
|
||||
count={sceneCount}
|
||||
abbreviateCounter={abbreviateCounter}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<StudioScenesPanel active={tabKey === "scenes"} studio={studio} />
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="galleries"
|
||||
title={
|
||||
<TabTitleCounter
|
||||
messageID="galleries"
|
||||
count={galleryCount}
|
||||
abbreviateCounter={abbreviateCounter}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<StudioGalleriesPanel active={tabKey === "galleries"} studio={studio} />
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="images"
|
||||
title={
|
||||
<TabTitleCounter
|
||||
messageID="images"
|
||||
count={imageCount}
|
||||
abbreviateCounter={abbreviateCounter}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<StudioImagesPanel active={tabKey === "images"} studio={studio} />
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="performers"
|
||||
title={
|
||||
<TabTitleCounter
|
||||
messageID="performers"
|
||||
count={performerCount}
|
||||
abbreviateCounter={abbreviateCounter}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<StudioPerformersPanel
|
||||
active={tabKey === "performers"}
|
||||
studio={studio}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="groups"
|
||||
title={
|
||||
<TabTitleCounter
|
||||
messageID="groups"
|
||||
count={groupCount}
|
||||
abbreviateCounter={abbreviateCounter}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<StudioGroupsPanel active={tabKey === "groups"} studio={studio} />
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="childstudios"
|
||||
title={
|
||||
<TabTitleCounter
|
||||
messageID="subsidiary_studios"
|
||||
count={studio.child_studios.length}
|
||||
abbreviateCounter={abbreviateCounter}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<StudioChildrenPanel
|
||||
active={tabKey === "childstudios"}
|
||||
studio={studio}
|
||||
/>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!tabKey) {
|
||||
setTabKey(populatedDefaultTab);
|
||||
const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
||||
const history = useHistory();
|
||||
const Toast = useToast();
|
||||
const intl = useIntl();
|
||||
|
||||
// Configuration settings
|
||||
const { configuration } = React.useContext(ConfigurationContext);
|
||||
const uiConfig = configuration?.ui;
|
||||
const abbreviateCounter = uiConfig?.abbreviateCounters ?? false;
|
||||
const enableBackgroundImage = uiConfig?.enableStudioBackgroundImage ?? false;
|
||||
const showAllDetails = uiConfig?.showAllDetails ?? true;
|
||||
const compactExpandedDetails = uiConfig?.compactExpandedDetails ?? false;
|
||||
|
||||
const [collapsed, setCollapsed] = useState<boolean>(!showAllDetails);
|
||||
const loadStickyHeader = useLoadStickyHeader();
|
||||
|
||||
// Editing state
|
||||
const [isEditing, setIsEditing] = useState<boolean>(false);
|
||||
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
|
||||
|
||||
// Editing studio state
|
||||
const [image, setImage] = useState<string | null>();
|
||||
const [encodingImage, setEncodingImage] = useState<boolean>(false);
|
||||
|
||||
const [updateStudio] = useStudioUpdate();
|
||||
const [deleteStudio] = useStudioDestroy({ id: studio.id });
|
||||
|
||||
const showAllCounts = uiConfig?.showChildStudioContent;
|
||||
|
||||
// make array of url so that it doesn't re-render on every change
|
||||
const urls = useMemo(() => {
|
||||
return studio?.url ? [studio.url] : [];
|
||||
}, [studio.url]);
|
||||
|
||||
const studioImage = useMemo(() => {
|
||||
const existingPath = studio.image_path;
|
||||
if (isEditing) {
|
||||
if (image === null && existingPath) {
|
||||
const studioImageURL = new URL(existingPath);
|
||||
studioImageURL.searchParams.set("default", "true");
|
||||
return studioImageURL.toString();
|
||||
} else if (image) {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}, [setTabKey, populatedDefaultTab, tabKey]);
|
||||
|
||||
return existingPath;
|
||||
}, [isEditing, image, studio.image_path]);
|
||||
|
||||
function setFavorite(v: boolean) {
|
||||
if (studio.id) {
|
||||
@@ -256,20 +363,6 @@ const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
||||
);
|
||||
}
|
||||
|
||||
function maybeRenderAliases() {
|
||||
if (studio?.aliases?.length) {
|
||||
return (
|
||||
<div>
|
||||
<span className="alias-head">{studio?.aliases?.join(", ")}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getCollapseButtonIcon() {
|
||||
return collapsed ? faChevronDown : faChevronUp;
|
||||
}
|
||||
|
||||
function toggleEditing(value?: boolean) {
|
||||
if (value !== undefined) {
|
||||
setIsEditing(value);
|
||||
@@ -279,46 +372,6 @@ const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
||||
setImage(undefined);
|
||||
}
|
||||
|
||||
function renderImage() {
|
||||
let studioImage = studio.image_path;
|
||||
if (isEditing) {
|
||||
if (image === null && studioImage) {
|
||||
const studioImageURL = new URL(studioImage);
|
||||
studioImageURL.searchParams.set("default", "true");
|
||||
studioImage = studioImageURL.toString();
|
||||
} else if (image) {
|
||||
studioImage = image;
|
||||
}
|
||||
}
|
||||
|
||||
if (studioImage) {
|
||||
return (
|
||||
<DetailImage className="logo" alt={studio.name} src={studioImage} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const renderClickableIcons = () => (
|
||||
<span className="name-icons">
|
||||
<Button
|
||||
className={cx("minimal", studio.favorite ? "favorite" : "not-favorite")}
|
||||
onClick={() => setFavorite(!studio.favorite)}
|
||||
>
|
||||
<Icon icon={faHeart} />
|
||||
</Button>
|
||||
{studio.url && (
|
||||
<Button
|
||||
as={ExternalLink}
|
||||
href={TextUtils.sanitiseURL(studio.url)}
|
||||
className="minimal link"
|
||||
title={studio.url}
|
||||
>
|
||||
<Icon icon={faLink} />
|
||||
</Button>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
|
||||
function setRating(v: number | null) {
|
||||
if (studio.id) {
|
||||
updateStudio({
|
||||
@@ -332,205 +385,6 @@ const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
||||
}
|
||||
}
|
||||
|
||||
function maybeRenderDetails() {
|
||||
if (!isEditing) {
|
||||
return (
|
||||
<StudioDetailsPanel
|
||||
studio={studio}
|
||||
collapsed={collapsed}
|
||||
fullWidth={!collapsed && !compactExpandedDetails}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function maybeRenderShowCollapseButton() {
|
||||
if (!isEditing) {
|
||||
return (
|
||||
<span className="detail-expand-collapse">
|
||||
<Button
|
||||
className="minimal expand-collapse"
|
||||
onClick={() => setCollapsed(!collapsed)}
|
||||
>
|
||||
<Icon className="fa-fw" icon={getCollapseButtonIcon()} />
|
||||
</Button>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function maybeRenderCompressedDetails() {
|
||||
if (!isEditing && loadStickyHeader) {
|
||||
return <CompressedStudioDetailsPanel studio={studio} />;
|
||||
}
|
||||
}
|
||||
|
||||
const renderTabs = () => (
|
||||
<Tabs
|
||||
id="studio-tabs"
|
||||
mountOnEnter
|
||||
unmountOnExit
|
||||
activeKey={tabKey}
|
||||
onSelect={setTabKey}
|
||||
>
|
||||
<Tab
|
||||
eventKey="scenes"
|
||||
title={
|
||||
<>
|
||||
{intl.formatMessage({ id: "scenes" })}
|
||||
<Counter
|
||||
abbreviateCounter={abbreviateCounter}
|
||||
count={sceneCount}
|
||||
hideZero
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<StudioScenesPanel active={tabKey === "scenes"} studio={studio} />
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="galleries"
|
||||
title={
|
||||
<>
|
||||
{intl.formatMessage({ id: "galleries" })}
|
||||
<Counter
|
||||
abbreviateCounter={abbreviateCounter}
|
||||
count={galleryCount}
|
||||
hideZero
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<StudioGalleriesPanel active={tabKey === "galleries"} studio={studio} />
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="images"
|
||||
title={
|
||||
<>
|
||||
{intl.formatMessage({ id: "images" })}
|
||||
<Counter
|
||||
abbreviateCounter={abbreviateCounter}
|
||||
count={imageCount}
|
||||
hideZero
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<StudioImagesPanel active={tabKey === "images"} studio={studio} />
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="performers"
|
||||
title={
|
||||
<>
|
||||
{intl.formatMessage({ id: "performers" })}
|
||||
<Counter
|
||||
abbreviateCounter={abbreviateCounter}
|
||||
count={performerCount}
|
||||
hideZero
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<StudioPerformersPanel
|
||||
active={tabKey === "performers"}
|
||||
studio={studio}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="groups"
|
||||
title={
|
||||
<>
|
||||
{intl.formatMessage({ id: "groups" })}
|
||||
<Counter
|
||||
abbreviateCounter={abbreviateCounter}
|
||||
count={groupCount}
|
||||
hideZero
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<StudioGroupsPanel active={tabKey === "groups"} studio={studio} />
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="childstudios"
|
||||
title={
|
||||
<>
|
||||
{intl.formatMessage({ id: "subsidiary_studios" })}
|
||||
<Counter
|
||||
abbreviateCounter={false}
|
||||
count={studio.child_studios.length}
|
||||
hideZero
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<StudioChildrenPanel
|
||||
active={tabKey === "childstudios"}
|
||||
studio={studio}
|
||||
/>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
);
|
||||
|
||||
function maybeRenderHeaderBackgroundImage() {
|
||||
let studioImage = studio.image_path;
|
||||
if (enableBackgroundImage && !isEditing && studioImage) {
|
||||
const studioImageURL = new URL(studioImage);
|
||||
let isDefaultImage = studioImageURL.searchParams.get("default");
|
||||
if (!isDefaultImage) {
|
||||
return (
|
||||
<div className="background-image-container">
|
||||
<picture>
|
||||
<source src={studioImage} />
|
||||
<img
|
||||
className="background-image"
|
||||
src={studioImage}
|
||||
alt={`${studio.name} background`}
|
||||
/>
|
||||
</picture>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function maybeRenderTab() {
|
||||
if (!isEditing) {
|
||||
return renderTabs();
|
||||
}
|
||||
}
|
||||
|
||||
function maybeRenderEditPanel() {
|
||||
if (isEditing) {
|
||||
return (
|
||||
<StudioEditPanel
|
||||
studio={studio}
|
||||
onSubmit={onSave}
|
||||
onCancel={() => toggleEditing()}
|
||||
onDelete={onDelete}
|
||||
setImage={setImage}
|
||||
setEncodingImage={setEncodingImage}
|
||||
/>
|
||||
);
|
||||
}
|
||||
{
|
||||
return (
|
||||
<DetailsEditNavbar
|
||||
objectName={studio.name ?? intl.formatMessage({ id: "studio" })}
|
||||
isNew={false}
|
||||
isEditing={isEditing}
|
||||
onToggleEdit={() => toggleEditing()}
|
||||
onSave={() => {}}
|
||||
onImageChange={() => {}}
|
||||
onClearImage={() => {}}
|
||||
onAutoTag={onAutoTag}
|
||||
autoTagDisabled={studio.ignore_auto_tag}
|
||||
onDelete={onDelete}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const headerClassName = cx("detail-header", {
|
||||
edit: isEditing,
|
||||
collapsed,
|
||||
@@ -544,41 +398,98 @@ const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
||||
</Helmet>
|
||||
|
||||
<div className={headerClassName}>
|
||||
{maybeRenderHeaderBackgroundImage()}
|
||||
<BackgroundImage
|
||||
imagePath={studio.image_path ?? undefined}
|
||||
show={!enableBackgroundImage && !isEditing}
|
||||
/>
|
||||
<div className="detail-container">
|
||||
<div className="detail-header-image">
|
||||
{encodingImage ? (
|
||||
<LoadingIndicator
|
||||
message={intl.formatMessage({ id: "actions.encoding_image" })}
|
||||
<HeaderImage encodingImage={encodingImage}>
|
||||
{studioImage && (
|
||||
<DetailImage
|
||||
className="logo"
|
||||
alt={studio.name}
|
||||
src={studioImage}
|
||||
/>
|
||||
) : (
|
||||
renderImage()
|
||||
)}
|
||||
</div>
|
||||
</HeaderImage>
|
||||
<div className="row">
|
||||
<div className="studio-head col">
|
||||
<h2>
|
||||
<span className="studio-name">{studio.name}</span>
|
||||
{maybeRenderShowCollapseButton()}
|
||||
{renderClickableIcons()}
|
||||
</h2>
|
||||
{maybeRenderAliases()}
|
||||
<DetailTitle name={studio.name ?? ""} classNamePrefix="studio">
|
||||
{!isEditing && (
|
||||
<ExpandCollapseButton
|
||||
collapsed={collapsed}
|
||||
setCollapsed={(v) => setCollapsed(v)}
|
||||
/>
|
||||
)}
|
||||
<span className="name-icons">
|
||||
<FavoriteIcon
|
||||
favorite={studio.favorite}
|
||||
onToggleFavorite={(v) => setFavorite(v)}
|
||||
/>
|
||||
<ExternalLinkButtons urls={urls} />
|
||||
</span>
|
||||
</DetailTitle>
|
||||
|
||||
<AliasList aliases={studio.aliases} />
|
||||
<RatingSystem
|
||||
value={studio.rating100}
|
||||
onSetRating={(value) => setRating(value)}
|
||||
clickToRate
|
||||
withoutContext
|
||||
/>
|
||||
{maybeRenderDetails()}
|
||||
{maybeRenderEditPanel()}
|
||||
{!isEditing && (
|
||||
<StudioDetailsPanel
|
||||
studio={studio}
|
||||
collapsed={collapsed}
|
||||
fullWidth={!collapsed && !compactExpandedDetails}
|
||||
/>
|
||||
)}
|
||||
{isEditing ? (
|
||||
<StudioEditPanel
|
||||
studio={studio}
|
||||
onSubmit={onSave}
|
||||
onCancel={() => toggleEditing()}
|
||||
onDelete={onDelete}
|
||||
setImage={setImage}
|
||||
setEncodingImage={setEncodingImage}
|
||||
/>
|
||||
) : (
|
||||
<DetailsEditNavbar
|
||||
objectName={
|
||||
studio.name ?? intl.formatMessage({ id: "studio" })
|
||||
}
|
||||
isNew={false}
|
||||
isEditing={isEditing}
|
||||
onToggleEdit={() => toggleEditing()}
|
||||
onSave={() => {}}
|
||||
onImageChange={() => {}}
|
||||
onClearImage={() => {}}
|
||||
onAutoTag={onAutoTag}
|
||||
autoTagDisabled={studio.ignore_auto_tag}
|
||||
onDelete={onDelete}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{maybeRenderCompressedDetails()}
|
||||
|
||||
{!isEditing && loadStickyHeader && (
|
||||
<CompressedStudioDetailsPanel studio={studio} />
|
||||
)}
|
||||
|
||||
<div className="detail-body">
|
||||
<div className="studio-body">
|
||||
<div className="studio-tabs">{maybeRenderTab()}</div>
|
||||
<div className="studio-tabs">
|
||||
{!isEditing && (
|
||||
<StudioTabs
|
||||
studio={studio}
|
||||
tabKey={tabKey}
|
||||
abbreviateCounter={abbreviateCounter}
|
||||
showAllCounts={showAllCounts}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{renderDeleteAlert()}
|
||||
|
||||
Reference in New Issue
Block a user