[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:
Anmol Singh Bhatia 2024-04-10 14:03:22 +05:30 committed by GitHub
parent 1dac70ecbe
commit 549790ee8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 97 additions and 74 deletions

View File

@ -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);
}} }}
/> />

View File

@ -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>

View File

@ -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>

View File

@ -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}
> >