UI - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: горизонтальное меню карточек без изменения сетки канбана
This commit is contained in:
parent
4dbb7b500c
commit
5f9d9c418e
|
|
@ -330,14 +330,14 @@ export const ExternalContoursBoardItem = observer(function ExternalContoursBoard
|
|||
</div>
|
||||
}
|
||||
buttonClassName="h-12 w-12"
|
||||
menuClassName="min-w-[18rem]"
|
||||
menuClassName="nodedc-work-item-action-menu"
|
||||
onOpenChange={(isOpen) => {
|
||||
if (isOpen) void ensureSourceOptions();
|
||||
}}
|
||||
items={[]}
|
||||
menuContent={({ closeDropdown }) => (
|
||||
<div className="max-h-[calc(100vh-2rem)] space-y-2 overflow-y-auto" onClick={stopCardPropagation}>
|
||||
<div className="space-y-1">
|
||||
<div className="nodedc-work-item-action-grid" onClick={stopCardPropagation}>
|
||||
<div className="nodedc-work-item-action-section space-y-1">
|
||||
<div className="px-2 text-[10px] font-semibold tracking-[0.16em] text-tertiary uppercase">
|
||||
Приоритет
|
||||
</div>
|
||||
|
|
@ -358,7 +358,7 @@ export const ExternalContoursBoardItem = observer(function ExternalContoursBoard
|
|||
))}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1 border-t border-white/8 pt-2">
|
||||
<div className="nodedc-work-item-action-section space-y-1">
|
||||
<div className="px-2 text-[10px] font-semibold tracking-[0.16em] text-tertiary uppercase">
|
||||
Статус
|
||||
</div>
|
||||
|
|
@ -388,7 +388,7 @@ export const ExternalContoursBoardItem = observer(function ExternalContoursBoard
|
|||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1 border-t border-white/8 pt-2">
|
||||
<div className="nodedc-work-item-action-section space-y-1">
|
||||
<div className="px-2 text-[10px] font-semibold tracking-[0.16em] text-tertiary uppercase">
|
||||
Быстрые действия
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ export const InternalContourKanbanCard = observer(function InternalContourKanban
|
|||
};
|
||||
const menuContentBefore = ({ closeDropdown }: { closeDropdown: () => void }) => (
|
||||
<>
|
||||
<div className="space-y-1">
|
||||
<div className="nodedc-work-item-action-section space-y-1">
|
||||
<div className="px-2 text-[10px] font-semibold tracking-[0.16em] text-tertiary uppercase">Приоритет</div>
|
||||
{priorityOptions.map((priority) => (
|
||||
<button
|
||||
|
|
@ -115,7 +115,7 @@ export const InternalContourKanbanCard = observer(function InternalContourKanban
|
|||
))}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1 border-t border-white/8 pt-2">
|
||||
<div className="nodedc-work-item-action-section space-y-1">
|
||||
<div className="px-2 text-[10px] font-semibold tracking-[0.16em] text-tertiary uppercase">Статус</div>
|
||||
{stateOptions.map((state) => (
|
||||
<button
|
||||
|
|
@ -138,12 +138,6 @@ export const InternalContourKanbanCard = observer(function InternalContourKanban
|
|||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="border-t border-white/8 pt-2">
|
||||
<div className="px-2 text-[10px] font-semibold tracking-[0.16em] text-tertiary uppercase">
|
||||
Быстрые действия
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
const dateButton = (
|
||||
|
|
@ -214,7 +208,7 @@ export const InternalContourKanbanCard = observer(function InternalContourKanban
|
|||
issue,
|
||||
parentRef: cardRef,
|
||||
customActionButton,
|
||||
menuClassName: "min-w-[18rem]",
|
||||
menuClassName: "nodedc-work-item-action-menu",
|
||||
menuContentBefore,
|
||||
placement: "bottom-end",
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ import { useParams } from "next/navigation";
|
|||
import { ARCHIVABLE_STATE_GROUPS, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
import type { TIssue } from "@plane/types";
|
||||
import { EIssuesStoreType } from "@plane/types";
|
||||
import { ActionDropdown, ContextMenu } from "@plane/ui";
|
||||
import { ActionDropdown, ContextMenu, type TContextMenuItem } from "@plane/ui";
|
||||
import { cn } from "@plane/utils";
|
||||
// hooks
|
||||
import { useIssues } from "@/hooks/store/use-issues";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
|
|
@ -102,6 +103,56 @@ export const ProjectIssueQuickActions = observer(function ProjectIssueQuickActio
|
|||
};
|
||||
|
||||
const MENU_ITEMS = useProjectIssueMenuItems(menuItemProps);
|
||||
const shouldUseNodedcActionGrid = menuClassName?.includes("nodedc-work-item-action-menu") ?? false;
|
||||
const DROPDOWN_MENU_ITEMS = shouldUseNodedcActionGrid
|
||||
? MENU_ITEMS.filter((item) => item.key !== "open-in-new-tab")
|
||||
: MENU_ITEMS;
|
||||
|
||||
const renderNodedcMenuItem = (item: TContextMenuItem, closeDropdown: () => void) => {
|
||||
if (item.shouldRender === false) return null;
|
||||
|
||||
const Icon = item.icon;
|
||||
|
||||
return (
|
||||
<button
|
||||
key={item.key}
|
||||
type="button"
|
||||
className={cn(
|
||||
"flex w-full items-center gap-2 rounded-[0.9rem] px-2.5 py-2 text-left text-12 text-secondary transition-colors",
|
||||
{
|
||||
"cursor-not-allowed text-placeholder": item.disabled,
|
||||
"hover:bg-white/6": !item.disabled,
|
||||
},
|
||||
item.className
|
||||
)}
|
||||
disabled={item.disabled}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (item.disabled) return;
|
||||
|
||||
item.action();
|
||||
closeDropdown();
|
||||
}}
|
||||
>
|
||||
{Icon && <Icon className={cn("h-3.5 w-3.5 shrink-0", item.iconClassName)} />}
|
||||
<span className="min-w-0 truncate">{item.title}</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
const renderNodedcMenuContent = ({ closeDropdown }: { closeDropdown: () => void }) => (
|
||||
<div className="nodedc-work-item-action-grid">
|
||||
{typeof menuContentBefore === "function" ? menuContentBefore({ closeDropdown }) : menuContentBefore}
|
||||
<div className="nodedc-work-item-action-section space-y-1">
|
||||
<div className="px-2 text-[10px] font-semibold tracking-[0.16em] text-tertiary uppercase">
|
||||
Быстрые действия
|
||||
</div>
|
||||
{DROPDOWN_MENU_ITEMS.map((item) => renderNodedcMenuItem(item, closeDropdown))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const CONTEXT_MENU_ITEMS = MENU_ITEMS.map(function CONTEXT_MENU_ITEMS(item) {
|
||||
return {
|
||||
|
|
@ -153,9 +204,10 @@ export const ProjectIssueQuickActions = observer(function ProjectIssueQuickActio
|
|||
<ContextMenu parentRef={parentRef} items={CONTEXT_MENU_ITEMS} />
|
||||
<ActionDropdown
|
||||
button={customActionButton}
|
||||
items={MENU_ITEMS}
|
||||
items={shouldUseNodedcActionGrid ? [] : MENU_ITEMS}
|
||||
menuClassName={menuClassName}
|
||||
menuContentBefore={menuContentBefore}
|
||||
menuContent={shouldUseNodedcActionGrid ? renderNodedcMenuContent : undefined}
|
||||
menuContentBefore={shouldUseNodedcActionGrid ? undefined : menuContentBefore}
|
||||
placement={placements}
|
||||
portalElement={portalElement}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -347,6 +347,37 @@
|
|||
0 6px 18px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.nodedc-tall-action-menu > div {
|
||||
max-height: calc(100vh - 24px) !important;
|
||||
}
|
||||
|
||||
.nodedc-work-item-action-menu {
|
||||
width: min(calc(100vw - 24px), 46rem);
|
||||
}
|
||||
|
||||
.nodedc-work-item-action-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 0.5rem;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.nodedc-work-item-action-section {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.nodedc-work-item-action-menu {
|
||||
width: min(calc(100vw - 24px), 18rem);
|
||||
}
|
||||
|
||||
.nodedc-work-item-action-grid {
|
||||
grid-template-columns: 1fr;
|
||||
max-height: calc(100vh - 24px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.nodedc-bottom-dock {
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.024) 0%, rgba(255, 255, 255, 0.008) 100%), rgba(7, 7, 10, 0.72) !important;
|
||||
|
|
|
|||
Loading…
Reference in New Issue