UI - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: исправление ширины карточек внешних контуров

This commit is contained in:
DCCONSTRUCTIONS 2026-04-21 08:03:03 +03:00
parent d3b4c0689c
commit ba34162eeb
10 changed files with 48 additions and 37 deletions

View File

@ -41,15 +41,15 @@ export const ExternalContoursBoardColumn = observer(function ExternalContoursBoa
: t("external_contours_page.board.empty.incoming_description"); : t("external_contours_page.board.empty.incoming_description");
return ( return (
<section className="flex min-h-0 flex-1 flex-col overflow-hidden rounded-[28px] bg-surface-2/30"> <section className="flex h-full min-h-0 w-[350px] flex-shrink-0 flex-col">
<div className="flex items-center justify-between gap-3 border-b border-subtle/40 px-5 py-4"> <div className="flex items-center justify-between gap-3 py-1.5">
<div className="text-15 font-semibold text-primary">{title}</div> <div className="text-15 font-semibold text-primary">{title}</div>
<div className="rounded-full bg-white/5 px-2 py-1 text-12 font-semibold text-secondary">{totalCount}</div> <div className="rounded-full bg-white/5 px-2 py-1 text-12 font-semibold text-secondary">{totalCount}</div>
</div> </div>
<div className="vertical-scrollbar scrollbar-md min-h-0 flex-1 overflow-y-auto p-4"> <div className="vertical-scrollbar scrollbar-md -mr-2 h-full min-h-[120px] flex-1 overflow-y-auto pr-2 pt-3">
{requestIds.length > 0 ? ( {requestIds.length > 0 ? (
<div className="space-y-4"> <>
{requestIds.map((requestId) => { {requestIds.map((requestId) => {
const request = getRequestById(requestId); const request = getRequestById(requestId);
if (!request) return null; if (!request) return null;
@ -65,7 +65,7 @@ export const ExternalContoursBoardColumn = observer(function ExternalContoursBoa
/> />
); );
})} })}
</div> </>
) : ( ) : (
<div className="flex h-full min-h-[18rem] items-center justify-center"> <div className="flex h-full min-h-[18rem] items-center justify-center">
<ExternalContoursEmptyState title={emptyTitle} description={emptyDescription} /> <ExternalContoursEmptyState title={emptyTitle} description={emptyDescription} />

View File

@ -219,10 +219,10 @@ export const ExternalContoursBoardItem = observer(function ExternalContoursBoard
}; };
return ( return (
<div className="block"> <div className="group/kanban-block relative mb-2">
<div <div
data-active={isActive} data-active={isActive}
className="nodedc-external-card relative flex min-h-[15rem] cursor-pointer flex-col px-6 py-5 transition-all hover:bg-white/5" className="nodedc-external-card relative flex min-h-[220px] w-full cursor-pointer flex-col p-4 transition-all hover:bg-white/5"
role="button" role="button"
tabIndex={0} tabIndex={0}
onClick={openDetail} onClick={openDetail}

View File

@ -77,7 +77,12 @@ export const ExternalContoursBoardRoot = observer(function ExternalContoursBoard
</div> </div>
)} )}
<div className={cn("grid min-h-0 h-full grid-cols-1 gap-5 transition-opacity xl:grid-cols-2", { "opacity-60": isFiltering })}> <div
className={cn(
"horizontal-scrollbar flex h-full min-h-0 items-stretch gap-4 overflow-x-auto overflow-y-hidden pb-1 transition-opacity",
{ "opacity-60": isFiltering }
)}
>
<ExternalContoursBoardColumn <ExternalContoursBoardColumn
currentTab={currentTab} currentTab={currentTab}
direction="outgoing" direction="outgoing"

View File

@ -216,11 +216,11 @@ export const ExternalContoursIssueActionsHeader = observer(function ExternalCont
/> />
<Row <Row
className={`relative z-15 hidden h-full w-full items-center justify-between gap-4 px-6 py-5 lg:flex ${ className={`relative z-15 hidden w-full items-center justify-between gap-3 px-5 py-3.5 lg:flex ${
currentMode?.key === "full-screen" ? "border-b border-subtle/70" : "" currentMode?.key === "full-screen" ? "border-b border-subtle/70" : ""
}`} }`}
> >
<div className="flex min-w-0 items-center gap-4"> <div className="flex min-w-0 items-center gap-3">
<Tooltip tooltipContent={t("common.close_peek_view")}> <Tooltip tooltipContent={t("common.close_peek_view")}>
<button onClick={removeRoutePeekId}> <button onClick={removeRoutePeekId}>
<MoveRight className="h-4 w-4 text-tertiary hover:text-secondary" /> <MoveRight className="h-4 w-4 text-tertiary hover:text-secondary" />
@ -320,7 +320,8 @@ export const ExternalContoursIssueActionsHeader = observer(function ExternalCont
isSubscribed={isSubscribed} isSubscribed={isSubscribed}
loading={isSubscriptionLoading} loading={isSubscriptionLoading}
onToggle={handleToggleSubscription} onToggle={handleToggleSubscription}
buttonClassName="!h-10 rounded-[18px] border-transparent bg-layer-2/80 px-4 shadow-none backdrop-blur-xl hover:!bg-layer-2-active focus-visible:outline-none" iconOnly
buttonClassName="size-10 rounded-[18px] border-transparent bg-layer-2/80 px-0 shadow-none backdrop-blur-xl hover:!bg-layer-2-active focus-visible:outline-none"
/> />
)} )}
@ -347,7 +348,7 @@ export const ExternalContoursIssueActionsHeader = observer(function ExternalCont
</div> </div>
</Row> </Row>
<Header className="justify-start lg:hidden"> <Header className="justify-start px-4 py-3 lg:hidden">
<div className="flex w-full items-center gap-2"> <div className="flex w-full items-center gap-2">
<button onClick={removeRoutePeekId}> <button onClick={removeRoutePeekId}>
<MoveRight className="h-4 w-4 text-tertiary hover:text-secondary" /> <MoveRight className="h-4 w-4 text-tertiary hover:text-secondary" />

View File

@ -37,7 +37,7 @@ export const ExternalContoursIssueContentProperties = observer(function External
<div className="w-full overflow-visible"> <div className="w-full overflow-visible">
<h5 className="mb-2 text-body-sm-medium">{t("external_contours_page.properties.section_title")}</h5> <h5 className="mb-2 text-body-sm-medium">{t("external_contours_page.properties.section_title")}</h5>
<div className={`${!isEditable ? "opacity-60" : ""}`}> <div className={`${!isEditable ? "opacity-60" : ""}`}>
<div className="flex flex-col gap-3"> <div className="grid grid-cols-2 gap-3">
<div className="nodedc-external-property-row"> <div className="nodedc-external-property-row">
<div className="nodedc-external-property-label"> <div className="nodedc-external-property-label">
<PriorityPropertyIcon className="h-4 w-4 flex-shrink-0" /> <PriorityPropertyIcon className="h-4 w-4 flex-shrink-0" />

View File

@ -193,7 +193,7 @@ export const ExternalContoursIssueMainContent = observer(function ExternalContou
<div className="nodedc-external-section flex flex-col gap-3 px-4 py-4"> <div className="nodedc-external-section flex flex-col gap-3 px-4 py-4">
<div className="text-body-sm-medium">{t("external_contours_page.properties.section_title")}</div> <div className="text-body-sm-medium">{t("external_contours_page.properties.section_title")}</div>
<div className="flex flex-col gap-3 text-13 text-secondary"> <div className="grid grid-cols-2 gap-3 text-13 text-secondary">
<div className="nodedc-external-property-row"> <div className="nodedc-external-property-row">
<div className="nodedc-external-property-label"> <div className="nodedc-external-property-label">
<PriorityPropertyIcon className="h-4 w-4 flex-shrink-0" /> <PriorityPropertyIcon className="h-4 w-4 flex-shrink-0" />

View File

@ -195,9 +195,9 @@ export const ExternalContoursPeekShell = observer(function ExternalContoursPeekS
/> />
<div className="vertical-scrollbar relative scrollbar-md h-full w-full overflow-hidden overflow-y-auto"> <div className="vertical-scrollbar relative scrollbar-md h-full w-full overflow-hidden overflow-y-auto">
{["side-peek", "modal"].includes(peekMode) ? ( {["side-peek", "modal"].includes(peekMode) ? (
<div className="relative flex flex-col gap-4 px-8 py-6">{children}</div> <div className="relative flex flex-col gap-4 px-6 pt-3 pb-5">{children}</div>
) : ( ) : (
<div className="relative h-full w-full overflow-auto px-6 py-5">{children}</div> <div className="relative h-full w-full overflow-auto px-5 pt-3 pb-4">{children}</div>
)} )}
</div> </div>
</div> </div>

View File

@ -84,18 +84,19 @@ type TExternalContourSubscriptionButtonProps = {
loading: boolean; loading: boolean;
onToggle: () => Promise<void>; onToggle: () => Promise<void>;
buttonClassName?: string; buttonClassName?: string;
iconOnly?: boolean;
}; };
export const ExternalContourSubscriptionButton = observer(function ExternalContourSubscriptionButton( export const ExternalContourSubscriptionButton = observer(function ExternalContourSubscriptionButton(
props: TExternalContourSubscriptionButtonProps props: TExternalContourSubscriptionButtonProps
) { ) {
const { isSubscribed, loading, onToggle, buttonClassName } = props; const { isSubscribed, loading, onToggle, buttonClassName, iconOnly = false } = props;
const { t } = useTranslation(); const { t } = useTranslation();
if (isSubscribed === undefined) { if (isSubscribed === undefined) {
return ( return (
<Loader> <Loader>
<Loader.Item width="106px" height="40px" /> <Loader.Item width={iconOnly ? "40px" : "106px"} height="40px" />
</Loader> </Loader>
); );
} }
@ -109,13 +110,14 @@ export const ExternalContourSubscriptionButton = observer(function ExternalConto
disabled={loading} disabled={loading}
size="lg" size="lg"
> >
{loading ? ( {!iconOnly &&
<span className="hidden sm:block">{t("common.loading")}</span> (loading ? (
) : isSubscribed ? ( <span className="hidden sm:block">{t("common.loading")}</span>
<span className="hidden sm:block">{t("common.actions.unsubscribe")}</span> ) : isSubscribed ? (
) : ( <span className="hidden sm:block">{t("common.actions.unsubscribe")}</span>
<span className="hidden sm:block">{t("common.actions.subscribe")}</span> ) : (
)} <span className="hidden sm:block">{t("common.actions.subscribe")}</span>
))}
</Button> </Button>
); );
}); });

View File

@ -27,10 +27,11 @@ export type TIssueSubscription = {
issueId: string; issueId: string;
serviceType?: EIssueServiceType; serviceType?: EIssueServiceType;
buttonClassName?: string; buttonClassName?: string;
iconOnly?: boolean;
}; };
export const IssueSubscription = observer(function IssueSubscription(props: TIssueSubscription) { export const IssueSubscription = observer(function IssueSubscription(props: TIssueSubscription) {
const { workspaceSlug, projectId, issueId, serviceType = EIssueServiceType.ISSUES, buttonClassName } = props; const { workspaceSlug, projectId, issueId, serviceType = EIssueServiceType.ISSUES, buttonClassName, iconOnly = false } = props;
const { t } = useTranslation(); const { t } = useTranslation();
// hooks // hooks
const { const {
@ -77,7 +78,7 @@ export const IssueSubscription = observer(function IssueSubscription(props: TIss
if (isNil(isSubscribed)) if (isNil(isSubscribed))
return ( return (
<Loader> <Loader>
<Loader.Item width="106px" height="28px" /> <Loader.Item width={iconOnly ? "40px" : "106px"} height={iconOnly ? "40px" : "28px"} />
</Loader> </Loader>
); );
@ -91,15 +92,16 @@ export const IssueSubscription = observer(function IssueSubscription(props: TIss
disabled={!isEditable || loading} disabled={!isEditable || loading}
size="lg" size="lg"
> >
{loading ? ( {!iconOnly &&
<span> (loading ? (
<span className="hidden sm:block">{t("common.loading")}</span> <span>
</span> <span className="hidden sm:block">{t("common.loading")}</span>
) : isSubscribed ? ( </span>
<div className="hidden sm:block">{t("common.actions.unsubscribe")}</div> ) : isSubscribed ? (
) : ( <div className="hidden sm:block">{t("common.actions.unsubscribe")}</div>
<div className="hidden sm:block">{t("common.actions.subscribe")}</div> ) : (
)} <div className="hidden sm:block">{t("common.actions.subscribe")}</div>
))}
</Button> </Button>
</div> </div>
); );

View File

@ -207,7 +207,8 @@ export const IssuePeekOverviewHeader = observer(function IssuePeekOverviewHeader
workspaceSlug={workspaceSlug} workspaceSlug={workspaceSlug}
projectId={projectId} projectId={projectId}
issueId={issueId} issueId={issueId}
buttonClassName="!h-10 rounded-[18px] border-transparent bg-layer-2/80 px-4 shadow-none backdrop-blur-xl hover:!bg-layer-2-active focus-visible:outline-none" iconOnly
buttonClassName="size-10 rounded-[18px] border-transparent bg-layer-2/80 px-0 shadow-none backdrop-blur-xl hover:!bg-layer-2-active focus-visible:outline-none"
/> />
)} )}
<Tooltip tooltipContent={t("common.actions.copy_link")} isMobile={isMobile}> <Tooltip tooltipContent={t("common.actions.copy_link")} isMobile={isMobile}>