forked from github/plane
[WEB-905] chore: kanban card icon color improvement (#4156)
* chore: kanban card icon color improvement * chore: kanban card clickable area improvement
This commit is contained in:
parent
1dac70ecbe
commit
549790ee8a
@ -152,6 +152,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||||||
className={cn("h-2.5 w-2.5 flex-shrink-0", clearIconClassName)}
|
className={cn("h-2.5 w-2.5 flex-shrink-0", clearIconClassName)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
onChange(null);
|
onChange(null);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -3,7 +3,7 @@ import { Draggable, DraggableProvided, DraggableStateSnapshot } from "@hello-pan
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { TIssue, IIssueDisplayProperties, IIssueMap } from "@plane/types";
|
import { TIssue, IIssueDisplayProperties, IIssueMap } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { Tooltip, ControlLink } from "@plane/ui";
|
import { ControlLink, Tooltip } from "@plane/ui";
|
||||||
import RenderIfVisible from "@/components/core/render-if-visible-HOC";
|
import RenderIfVisible from "@/components/core/render-if-visible-HOC";
|
||||||
import { cn } from "@/helpers/common.helper";
|
import { cn } from "@/helpers/common.helper";
|
||||||
import { useApplication, useIssueDetail, useProject } from "@/hooks/store";
|
import { useApplication, useIssueDetail, useProject } from "@/hooks/store";
|
||||||
@ -44,23 +44,16 @@ const KanbanIssueDetailsBlock: React.FC<IssueDetailsBlockProps> = observer((prop
|
|||||||
// hooks
|
// hooks
|
||||||
const { isMobile } = usePlatformOS();
|
const { isMobile } = usePlatformOS();
|
||||||
const { getProjectIdentifierById } = useProject();
|
const { getProjectIdentifierById } = useProject();
|
||||||
const {
|
|
||||||
router: { workspaceSlug },
|
|
||||||
} = useApplication();
|
|
||||||
const { peekIssue, setPeekIssue } = useIssueDetail();
|
|
||||||
|
|
||||||
const handleIssuePeekOverview = (issue: TIssue) =>
|
const handleEventPropagation = (e: React.MouseEvent) => {
|
||||||
workspaceSlug &&
|
e.stopPropagation();
|
||||||
issue &&
|
e.preventDefault();
|
||||||
issue.project_id &&
|
};
|
||||||
issue.id &&
|
|
||||||
peekIssue?.issueId !== issue.id &&
|
|
||||||
setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties || {}} displayPropertyKey="key">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties || {}} displayPropertyKey="key">
|
||||||
<div className="relative">
|
<div className="relative" onClick={handleEventPropagation}>
|
||||||
<div className="line-clamp-1 text-xs text-custom-text-300">
|
<div className="line-clamp-1 text-xs text-custom-text-300">
|
||||||
{getProjectIdentifierById(issue.project_id)}-{issue.sequence_id}
|
{getProjectIdentifierById(issue.project_id)}-{issue.sequence_id}
|
||||||
</div>
|
</div>
|
||||||
@ -73,24 +66,13 @@ const KanbanIssueDetailsBlock: React.FC<IssueDetailsBlockProps> = observer((prop
|
|||||||
<span className="pb-1.5">{issue.name}</span>
|
<span className="pb-1.5">{issue.name}</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
<ControlLink
|
<Tooltip tooltipContent={issue.name} isMobile={isMobile}>
|
||||||
id={`issue-${issue.id}`}
|
<span className="w-full line-clamp-1 cursor-pointer text-sm text-custom-text-100 pb-1.5">{issue.name}</span>
|
||||||
href={`/${workspaceSlug}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}issues/${
|
</Tooltip>
|
||||||
issue.id
|
|
||||||
}`}
|
|
||||||
target="_blank"
|
|
||||||
onClick={() => handleIssuePeekOverview(issue)}
|
|
||||||
className="w-full line-clamp-1 cursor-pointer text-sm text-custom-text-100 pb-1.5"
|
|
||||||
disabled={!!issue?.tempId}
|
|
||||||
>
|
|
||||||
<Tooltip tooltipContent={issue.name} isMobile={isMobile}>
|
|
||||||
<span>{issue.name}</span>
|
|
||||||
</Tooltip>
|
|
||||||
</ControlLink>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<IssueProperties
|
<IssueProperties
|
||||||
className="flex flex-wrap items-center gap-2 whitespace-nowrap"
|
className="flex flex-wrap items-center gap-2 whitespace-nowrap text-custom-text-300"
|
||||||
issue={issue}
|
issue={issue}
|
||||||
displayProperties={displayProperties}
|
displayProperties={displayProperties}
|
||||||
activeLayout="Kanban"
|
activeLayout="Kanban"
|
||||||
@ -118,6 +100,19 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = memo((props) => {
|
|||||||
issueIds,
|
issueIds,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
const {
|
||||||
|
router: { workspaceSlug },
|
||||||
|
} = useApplication();
|
||||||
|
const { peekIssue, setPeekIssue } = useIssueDetail();
|
||||||
|
|
||||||
|
const handleIssuePeekOverview = (issue: TIssue) =>
|
||||||
|
workspaceSlug &&
|
||||||
|
issue &&
|
||||||
|
issue.project_id &&
|
||||||
|
issue.id &&
|
||||||
|
peekIssue?.issueId !== issue.id &&
|
||||||
|
setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id });
|
||||||
|
|
||||||
const issue = issuesMap[issueId];
|
const issue = issuesMap[issueId];
|
||||||
|
|
||||||
if (!issue) return null;
|
if (!issue) return null;
|
||||||
@ -138,32 +133,42 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = memo((props) => {
|
|||||||
{...provided.dragHandleProps}
|
{...provided.dragHandleProps}
|
||||||
ref={provided.innerRef}
|
ref={provided.innerRef}
|
||||||
>
|
>
|
||||||
<div
|
<ControlLink
|
||||||
className={cn(
|
id={`issue-${issue.id}`}
|
||||||
"rounded border-[0.5px] outline-[0.5px] outline-transparent w-full border-custom-border-200 bg-custom-background-100 text-sm transition-all hover:border-custom-border-400",
|
href={`/${workspaceSlug}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}issues/${
|
||||||
{ "hover:cursor-grab": !isDragDisabled },
|
issue.id
|
||||||
{ "border-custom-primary-100": snapshot.isDragging },
|
}`}
|
||||||
{ "border border-custom-primary-70 hover:border-custom-primary-70": peekIssueId === issue.id }
|
target="_blank"
|
||||||
)}
|
onClick={() => handleIssuePeekOverview(issue)}
|
||||||
|
disabled={!!issue?.tempId}
|
||||||
>
|
>
|
||||||
<RenderIfVisible
|
<div
|
||||||
classNames="space-y-2 px-3 py-2"
|
className={cn(
|
||||||
root={scrollableContainerRef}
|
"rounded border-[0.5px] outline-[0.5px] outline-transparent w-full border-custom-border-200 bg-custom-background-100 text-sm transition-all hover:border-custom-border-400",
|
||||||
defaultHeight="100px"
|
{ "hover:cursor-pointer": !isDragDisabled },
|
||||||
horizontalOffset={50}
|
{ "border-custom-primary-100": snapshot.isDragging },
|
||||||
alwaysRender={snapshot.isDragging}
|
{ "border border-custom-primary-70 hover:border-custom-primary-70": peekIssueId === issue.id }
|
||||||
pauseHeightUpdateWhileRendering={isDragStarted}
|
)}
|
||||||
changingReference={issueIds}
|
|
||||||
>
|
>
|
||||||
<KanbanIssueDetailsBlock
|
<RenderIfVisible
|
||||||
issue={issue}
|
classNames="space-y-2 px-3 py-2"
|
||||||
displayProperties={displayProperties}
|
root={scrollableContainerRef}
|
||||||
updateIssue={updateIssue}
|
defaultHeight="100px"
|
||||||
quickActions={quickActions}
|
horizontalOffset={50}
|
||||||
isReadOnly={!canEditIssueProperties}
|
alwaysRender={snapshot.isDragging}
|
||||||
/>
|
pauseHeightUpdateWhileRendering={isDragStarted}
|
||||||
</RenderIfVisible>
|
changingReference={issueIds}
|
||||||
</div>
|
>
|
||||||
|
<KanbanIssueDetailsBlock
|
||||||
|
issue={issue}
|
||||||
|
displayProperties={displayProperties}
|
||||||
|
updateIssue={updateIssue}
|
||||||
|
quickActions={quickActions}
|
||||||
|
isReadOnly={!canEditIssueProperties}
|
||||||
|
/>
|
||||||
|
</RenderIfVisible>
|
||||||
|
</div>
|
||||||
|
</ControlLink>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Draggable>
|
</Draggable>
|
||||||
|
@ -254,12 +254,17 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
const maxDate = getDate(issue.target_date);
|
const maxDate = getDate(issue.target_date);
|
||||||
maxDate?.setDate(maxDate.getDate());
|
maxDate?.setDate(maxDate.getDate());
|
||||||
|
|
||||||
|
const handleEventPropagation = (e: React.MouseEvent) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
{/* basic properties */}
|
{/* basic properties */}
|
||||||
{/* state */}
|
{/* state */}
|
||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="state">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="state">
|
||||||
<div className="h-5">
|
<div className="h-5" onClick={handleEventPropagation}>
|
||||||
<StateDropdown
|
<StateDropdown
|
||||||
buttonContainerClassName="truncate max-w-40"
|
buttonContainerClassName="truncate max-w-40"
|
||||||
value={issue.state_id}
|
value={issue.state_id}
|
||||||
@ -274,7 +279,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
|
|
||||||
{/* priority */}
|
{/* priority */}
|
||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="priority">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="priority">
|
||||||
<div className="h-5">
|
<div className="h-5" onClick={handleEventPropagation}>
|
||||||
<PriorityDropdown
|
<PriorityDropdown
|
||||||
value={issue?.priority || null}
|
value={issue?.priority || null}
|
||||||
onChange={handlePriority}
|
onChange={handlePriority}
|
||||||
@ -288,19 +293,21 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
|
|
||||||
{/* label */}
|
{/* label */}
|
||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="labels">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="labels">
|
||||||
<IssuePropertyLabels
|
<div className="h-5" onClick={handleEventPropagation}>
|
||||||
projectId={issue?.project_id || null}
|
<IssuePropertyLabels
|
||||||
value={issue?.label_ids || null}
|
projectId={issue?.project_id || null}
|
||||||
defaultOptions={defaultLabelOptions}
|
value={issue?.label_ids || null}
|
||||||
onChange={handleLabel}
|
defaultOptions={defaultLabelOptions}
|
||||||
disabled={isReadOnly}
|
onChange={handleLabel}
|
||||||
hideDropdownArrow
|
disabled={isReadOnly}
|
||||||
/>
|
hideDropdownArrow
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</WithDisplayPropertiesHOC>
|
</WithDisplayPropertiesHOC>
|
||||||
|
|
||||||
{/* start date */}
|
{/* start date */}
|
||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="start_date">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="start_date">
|
||||||
<div className="h-5">
|
<div className="h-5" onClick={handleEventPropagation}>
|
||||||
<DateDropdown
|
<DateDropdown
|
||||||
value={issue.start_date ?? null}
|
value={issue.start_date ?? null}
|
||||||
onChange={handleStartDate}
|
onChange={handleStartDate}
|
||||||
@ -316,7 +323,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
|
|
||||||
{/* target/due date */}
|
{/* target/due date */}
|
||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="due_date">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="due_date">
|
||||||
<div className="h-5">
|
<div className="h-5" onClick={handleEventPropagation}>
|
||||||
<DateDropdown
|
<DateDropdown
|
||||||
value={issue?.target_date ?? null}
|
value={issue?.target_date ?? null}
|
||||||
onChange={handleTargetDate}
|
onChange={handleTargetDate}
|
||||||
@ -334,7 +341,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
|
|
||||||
{/* assignee */}
|
{/* assignee */}
|
||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="assignee">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="assignee">
|
||||||
<div className="h-5">
|
<div className="h-5" onClick={handleEventPropagation}>
|
||||||
<MemberDropdown
|
<MemberDropdown
|
||||||
projectId={issue?.project_id}
|
projectId={issue?.project_id}
|
||||||
value={issue?.assignee_ids}
|
value={issue?.assignee_ids}
|
||||||
@ -353,7 +360,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
{/* modules */}
|
{/* modules */}
|
||||||
{projectDetails?.module_view && (
|
{projectDetails?.module_view && (
|
||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="modules">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="modules">
|
||||||
<div className="h-5">
|
<div className="h-5" onClick={handleEventPropagation}>
|
||||||
<ModuleDropdown
|
<ModuleDropdown
|
||||||
buttonContainerClassName="truncate max-w-40"
|
buttonContainerClassName="truncate max-w-40"
|
||||||
projectId={issue?.project_id}
|
projectId={issue?.project_id}
|
||||||
@ -372,7 +379,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
{/* cycles */}
|
{/* cycles */}
|
||||||
{projectDetails?.cycle_view && (
|
{projectDetails?.cycle_view && (
|
||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="cycle">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="cycle">
|
||||||
<div className="h-5">
|
<div className="h-5" onClick={handleEventPropagation}>
|
||||||
<CycleDropdown
|
<CycleDropdown
|
||||||
buttonContainerClassName="truncate max-w-40"
|
buttonContainerClassName="truncate max-w-40"
|
||||||
projectId={issue?.project_id}
|
projectId={issue?.project_id}
|
||||||
@ -389,7 +396,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
{/* estimates */}
|
{/* estimates */}
|
||||||
{areEstimatesEnabledForCurrentProject && (
|
{areEstimatesEnabledForCurrentProject && (
|
||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="estimate">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="estimate">
|
||||||
<div className="h-5">
|
<div className="h-5" onClick={handleEventPropagation}>
|
||||||
<EstimateDropdown
|
<EstimateDropdown
|
||||||
value={issue.estimate_point}
|
value={issue.estimate_point}
|
||||||
onChange={handleEstimate}
|
onChange={handleEstimate}
|
||||||
@ -411,7 +418,11 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
>
|
>
|
||||||
<Tooltip tooltipHeading="Sub-issues" tooltipContent={`${issue.sub_issues_count}`} isMobile={isMobile}>
|
<Tooltip tooltipHeading="Sub-issues" tooltipContent={`${issue.sub_issues_count}`} isMobile={isMobile}>
|
||||||
<div
|
<div
|
||||||
onClick={issue.sub_issues_count ? redirectToIssueDetail : () => {}}
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
if (issue.sub_issues_count) redirectToIssueDetail();
|
||||||
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-5 flex-shrink-0 items-center justify-center gap-2 overflow-hidden rounded border-[0.5px] border-custom-border-300 px-2.5 py-1",
|
"flex h-5 flex-shrink-0 items-center justify-center gap-2 overflow-hidden rounded border-[0.5px] border-custom-border-300 px-2.5 py-1",
|
||||||
{
|
{
|
||||||
@ -432,7 +443,10 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
shouldRenderProperty={(properties) => !!properties.attachment_count && !!issue.attachment_count}
|
shouldRenderProperty={(properties) => !!properties.attachment_count && !!issue.attachment_count}
|
||||||
>
|
>
|
||||||
<Tooltip tooltipHeading="Attachments" tooltipContent={`${issue.attachment_count}`} isMobile={isMobile}>
|
<Tooltip tooltipHeading="Attachments" tooltipContent={`${issue.attachment_count}`} isMobile={isMobile}>
|
||||||
<div className="flex h-5 flex-shrink-0 items-center justify-center gap-2 overflow-hidden rounded border-[0.5px] border-custom-border-300 px-2.5 py-1">
|
<div
|
||||||
|
className="flex h-5 flex-shrink-0 items-center justify-center gap-2 overflow-hidden rounded border-[0.5px] border-custom-border-300 px-2.5 py-1"
|
||||||
|
onClick={handleEventPropagation}
|
||||||
|
>
|
||||||
<Paperclip className="h-3 w-3 flex-shrink-0" strokeWidth={2} />
|
<Paperclip className="h-3 w-3 flex-shrink-0" strokeWidth={2} />
|
||||||
<div className="text-xs">{issue.attachment_count}</div>
|
<div className="text-xs">{issue.attachment_count}</div>
|
||||||
</div>
|
</div>
|
||||||
@ -446,7 +460,10 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
shouldRenderProperty={(properties) => !!properties.link && !!issue.link_count}
|
shouldRenderProperty={(properties) => !!properties.link && !!issue.link_count}
|
||||||
>
|
>
|
||||||
<Tooltip tooltipHeading="Links" tooltipContent={`${issue.link_count}`} isMobile={isMobile}>
|
<Tooltip tooltipHeading="Links" tooltipContent={`${issue.link_count}`} isMobile={isMobile}>
|
||||||
<div className="flex h-5 flex-shrink-0 items-center justify-center gap-2 overflow-hidden rounded border-[0.5px] border-custom-border-300 px-2.5 py-1">
|
<div
|
||||||
|
className="flex h-5 flex-shrink-0 items-center justify-center gap-2 overflow-hidden rounded border-[0.5px] border-custom-border-300 px-2.5 py-1"
|
||||||
|
onClick={handleEventPropagation}
|
||||||
|
>
|
||||||
<Link className="h-3 w-3 flex-shrink-0" strokeWidth={2} />
|
<Link className="h-3 w-3 flex-shrink-0" strokeWidth={2} />
|
||||||
<div className="text-xs">{issue.link_count}</div>
|
<div className="text-xs">{issue.link_count}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -143,7 +143,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
|
|||||||
query === "" ? options : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase()));
|
query === "" ? options : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase()));
|
||||||
|
|
||||||
const label = (
|
const label = (
|
||||||
<div className="flex h-5 w-full flex-wrap items-center gap-2 overflow-hidden text-custom-text-200">
|
<div className="flex h-5 w-full flex-wrap items-center gap-2 overflow-hidden">
|
||||||
{value.length > 0 ? (
|
{value.length > 0 ? (
|
||||||
value.length <= maxRender ? (
|
value.length <= maxRender ? (
|
||||||
<>
|
<>
|
||||||
@ -232,8 +232,8 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
|
|||||||
disabled
|
disabled
|
||||||
? "cursor-not-allowed text-custom-text-200"
|
? "cursor-not-allowed text-custom-text-200"
|
||||||
: value.length <= maxRender
|
: value.length <= maxRender
|
||||||
? "cursor-pointer"
|
? "cursor-pointer"
|
||||||
: "cursor-pointer hover:bg-custom-background-80"
|
: "cursor-pointer hover:bg-custom-background-80"
|
||||||
} ${buttonClassName}`}
|
} ${buttonClassName}`}
|
||||||
onClick={handleOnClick}
|
onClick={handleOnClick}
|
||||||
>
|
>
|
||||||
|
Loading…
Reference in New Issue
Block a user