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

This commit is contained in:
DCCONSTRUCTIONS 2026-04-24 15:49:20 +03:00
parent eff71d7258
commit b3c6b37399
4 changed files with 62 additions and 12 deletions

View File

@ -23,7 +23,12 @@ import { ControlLink, DropIndicator } from "@plane/ui";
import { cn, generateWorkItemLink } from "@plane/utils"; import { cn, generateWorkItemLink } from "@plane/utils";
// components // components
import RenderIfVisible from "@/components/core/render-if-visible-HOC"; import RenderIfVisible from "@/components/core/render-if-visible-HOC";
import { HIGHLIGHT_CLASS, getIssueBlockId } from "@/components/issues/issue-layouts/utils"; import {
HIGHLIGHT_CLASS,
HIGHLIGHT_WITH_LINE,
NODEDC_DROP_FILL_HIGHLIGHT_CLASS,
getIssueBlockId,
} from "@/components/issues/issue-layouts/utils";
// helpers // helpers
// hooks // hooks
import { useIssueDetail } from "@/hooks/store/use-issue-detail"; import { useIssueDetail } from "@/hooks/store/use-issue-detail";
@ -87,9 +92,7 @@ const KanbanIssueDetailsBlock = observer(function KanbanIssueDetailsBlock(props:
const { isMobile } = usePlatformOS(); const { isMobile } = usePlatformOS();
const customActionButton = ( const customActionButton = (
<div <div className="flex h-full w-full cursor-pointer items-center rounded-sm p-1 text-secondary hover:bg-layer-1 hover:text-primary">
className="flex h-full w-full cursor-pointer items-center rounded-sm p-1 text-secondary hover:bg-layer-1 hover:text-primary"
>
<MoreHorizontal className="h-3.5 w-3.5" /> <MoreHorizontal className="h-3.5 w-3.5" />
</div> </div>
); );
@ -226,7 +229,7 @@ export const KanbanIssueBlock = observer(function KanbanIssueBlock(props: IssueB
}); });
useOutsideClickDetector(cardRef, () => { useOutsideClickDetector(cardRef, () => {
cardRef?.current?.classList?.remove(HIGHLIGHT_CLASS); cardRef?.current?.classList?.remove(HIGHLIGHT_CLASS, HIGHLIGHT_WITH_LINE, NODEDC_DROP_FILL_HIGHLIGHT_CLASS);
}); });
// Make Issue block both as as Draggable and, // Make Issue block both as as Draggable and,
@ -297,15 +300,16 @@ export const KanbanIssueBlock = observer(function KanbanIssueBlock(props: IssueB
className={cn( className={cn(
"block w-full text-13 transition-all", "block w-full text-13 transition-all",
cardVariant === "internal-contour" cardVariant === "internal-contour"
? "rounded-[28px] border-0 p-0 shadow-none outline-none ring-0 hover:border-0 hover:outline-none hover:ring-0" ? "rounded-[28px] border-0 p-0 shadow-none ring-0 outline-none hover:border-0 hover:ring-0 hover:outline-none focus:!ring-0 focus:!outline-none focus-visible:!ring-0 focus-visible:!outline-none active:!outline-none"
: "rounded-lg border border-subtle bg-layer-2 p-3 shadow-raised-100 outline-[0.5px] outline-transparent hover:border-strong hover:shadow-raised-200", : "rounded-lg border border-subtle bg-layer-2 p-3 shadow-raised-100 outline-[0.5px] outline-transparent hover:border-strong hover:shadow-raised-200",
{ "hover:cursor-pointer": isDragAllowed }, { "hover:cursor-pointer": isDragAllowed },
{ {
"border border-accent-strong hover:border-accent-strong": cardVariant !== "internal-contour" && isPeeked, "border border-accent-strong hover:border-accent-strong": cardVariant !== "internal-contour" && isPeeked,
}, },
{ "z-[100] bg-layer-1": isCurrentBlockDragging && cardVariant !== "internal-contour" }, { "z-[100] bg-layer-1": isCurrentBlockDragging && cardVariant !== "internal-contour" },
{ "z-[100] bg-[rgb(var(--nodedc-card-active-rgb))]": isCurrentBlockDragging && cardVariant === "internal-contour" } { "z-[100]": isCurrentBlockDragging && cardVariant === "internal-contour" }
)} )}
data-card-variant={cardVariant}
onClick={() => handleIssuePeekOverview(issue)} onClick={() => handleIssuePeekOverview(issue)}
disabled={!!issue?.tempId} disabled={!!issue?.tempId}
> >
@ -325,7 +329,7 @@ export const KanbanIssueBlock = observer(function KanbanIssueBlock(props: IssueB
quickActions={quickActions} quickActions={quickActions}
isReadOnly={!canEditIssueProperties} isReadOnly={!canEditIssueProperties}
isEpic={isEpic} isEpic={isEpic}
isActive={isPeeked} isActive={isPeeked || (cardVariant === "internal-contour" && isCurrentBlockDragging)}
cardVariant={cardVariant} cardVariant={cardVariant}
/> />
</RenderIfVisible> </RenderIfVisible>

View File

@ -25,7 +25,9 @@ export const getNodedcWorkItemCardAppearance = (isActive: boolean) => ({
surfaceClassName: isActive surfaceClassName: isActive
? "bg-[rgb(var(--nodedc-card-active-rgb))] text-[rgb(var(--nodedc-on-card-active-rgb))]" ? "bg-[rgb(var(--nodedc-card-active-rgb))] text-[rgb(var(--nodedc-on-card-active-rgb))]"
: "bg-[rgb(var(--nodedc-card-passive-rgb))] text-white", : "bg-[rgb(var(--nodedc-card-passive-rgb))] text-white",
foregroundClasses: isActive ? "text-[rgb(var(--nodedc-on-card-active-rgb))]" : "text-[rgb(var(--nodedc-on-card-passive-rgb))]", foregroundClasses: isActive
? "text-[rgb(var(--nodedc-on-card-active-rgb))]"
: "text-[rgb(var(--nodedc-on-card-passive-rgb))]",
subtleTextClasses: isActive ? "text-[#2F4721]" : "text-[#B3B3B8]", subtleTextClasses: isActive ? "text-[#2F4721]" : "text-[#B3B3B8]",
pillBackgroundClasses: isActive pillBackgroundClasses: isActive
? "bg-black/10 text-[rgb(var(--nodedc-on-card-active-rgb))]" ? "bg-black/10 text-[rgb(var(--nodedc-on-card-active-rgb))]"
@ -51,7 +53,7 @@ export const NodedcWorkItemCard = ({
return ( return (
<div <div
className={cn( className={cn(
"rounded-[28px] border-0 p-4 shadow-none outline-none ring-0", "nodedc-work-item-card rounded-[28px] border-0 p-4 shadow-none ring-0 outline-none",
appearance.surfaceClassName, appearance.surfaceClassName,
surfaceClassName surfaceClassName
)} )}
@ -60,14 +62,20 @@ export const NodedcWorkItemCard = ({
<div className="space-y-0.5"> <div className="space-y-0.5">
{header} {header}
{subtitle && ( {subtitle && (
<div className={cn("truncate -mt-0.5 pl-8 text-[11px] font-medium leading-4", appearance.subtleTextClasses, subtitleClassName)}> <div
className={cn(
"-mt-0.5 truncate pl-8 text-[11px] leading-4 font-medium",
appearance.subtleTextClasses,
subtitleClassName
)}
>
{subtitle} {subtitle}
</div> </div>
)} )}
</div> </div>
<div className={cn("flex flex-1 items-center justify-center px-5 py-4 text-center", titleContainerClassName)}> <div className={cn("flex flex-1 items-center justify-center px-5 py-4 text-center", titleContainerClassName)}>
<div className={cn("line-clamp-4 max-w-full text-lg font-semibold leading-6", titleClassName)}>{title}</div> <div className={cn("text-lg line-clamp-4 max-w-full leading-6 font-semibold", titleClassName)}>{title}</div>
</div> </div>
<div className={cn("flex items-center justify-between gap-3", footerClassName)}>{footer}</div> <div className={cn("flex items-center justify-between gap-3", footerClassName)}>{footer}</div>

View File

@ -46,6 +46,7 @@ import { DEFAULT_DISPLAY_PROPERTIES } from "@/store/issue/issue-details/sub_issu
export const HIGHLIGHT_CLASS = "highlight"; export const HIGHLIGHT_CLASS = "highlight";
export const HIGHLIGHT_WITH_LINE = "highlight-with-line"; export const HIGHLIGHT_WITH_LINE = "highlight-with-line";
export const NODEDC_DROP_FILL_HIGHLIGHT_CLASS = "nodedc-drop-fill-highlight";
const getAllItemsGroupLabel = (isEpic: boolean): string => { const getAllItemsGroupLabel = (isEpic: boolean): string => {
const locale = const locale =
@ -355,6 +356,18 @@ export const highlightIssueOnDrop = (
setTimeout(async () => { setTimeout(async () => {
const sourceElementId = elementId ?? ""; const sourceElementId = elementId ?? "";
const sourceElement = document.getElementById(sourceElementId); const sourceElement = document.getElementById(sourceElementId);
if (sourceElement?.dataset.cardVariant === "internal-contour") {
sourceElement.classList.remove(HIGHLIGHT_CLASS, HIGHLIGHT_WITH_LINE);
sourceElement.classList.add(NODEDC_DROP_FILL_HIGHLIGHT_CLASS);
window.setTimeout(() => sourceElement.classList.remove(NODEDC_DROP_FILL_HIGHLIGHT_CLASS), 1600);
if (shouldScrollIntoView)
await scrollIntoView(sourceElement, { behavior: "smooth", block: "center", duration: 1500 });
return;
}
sourceElement?.classList?.add(shouldHighLightWithLine ? HIGHLIGHT_WITH_LINE : HIGHLIGHT_CLASS); sourceElement?.classList?.add(shouldHighLightWithLine ? HIGHLIGHT_WITH_LINE : HIGHLIGHT_CLASS);
if (shouldScrollIntoView && sourceElement) if (shouldScrollIntoView && sourceElement)
await scrollIntoView(sourceElement, { behavior: "smooth", block: "center", duration: 1500 }); await scrollIntoView(sourceElement, { behavior: "smooth", block: "center", duration: 1500 });

View File

@ -190,6 +190,31 @@
} }
} }
@keyframes nodedcDropFillHighlight {
0%,
72% {
background-color: rgb(var(--nodedc-card-active-rgb));
color: rgb(var(--nodedc-on-card-active-rgb));
}
100% {
background-color: rgb(var(--nodedc-card-passive-rgb));
color: rgb(var(--nodedc-on-card-passive-rgb));
}
}
[data-card-variant="internal-contour"].nodedc-drop-fill-highlight {
border: 0 !important;
outline: none !important;
box-shadow: none !important;
}
[data-card-variant="internal-contour"].nodedc-drop-fill-highlight .nodedc-work-item-card {
border: 0 !important;
outline: none !important;
box-shadow: none !important;
animation: nodedcDropFillHighlight 1.6s ease-out;
}
/* Progress Bar Styles */ /* Progress Bar Styles */
:root { :root {
--bprogress-color: var(--background-color-accent-primary); --bprogress-color: var(--background-color-accent-primary);