[WEB-2130] chore: list layout responsiveness improvement (#5276)
* chore: issue list layout responsiveness improvement * fix: list layout item component improvement * chore: cycle, module and view list layout responsiveness improvement
This commit is contained in:
parent
dd3df20319
commit
18df1530c1
8 changed files with 122 additions and 45 deletions
|
|
@ -18,6 +18,9 @@ interface IListItemProps {
|
|||
parentRef: React.RefObject<HTMLDivElement>;
|
||||
disableLink?: boolean;
|
||||
className?: string;
|
||||
actionItemContainerClassName?: string;
|
||||
isSidebarOpen?: boolean;
|
||||
quickActionElement?: JSX.Element;
|
||||
}
|
||||
|
||||
export const ListItem: FC<IListItemProps> = (props) => {
|
||||
|
|
@ -32,6 +35,9 @@ export const ListItem: FC<IListItemProps> = (props) => {
|
|||
parentRef,
|
||||
disableLink = false,
|
||||
className = "",
|
||||
actionItemContainerClassName = "",
|
||||
isSidebarOpen = false,
|
||||
quickActionElement,
|
||||
} = props;
|
||||
|
||||
// router
|
||||
|
|
@ -45,34 +51,49 @@ export const ListItem: FC<IListItemProps> = (props) => {
|
|||
|
||||
return (
|
||||
<div ref={parentRef} className="relative">
|
||||
<ControlLink href={itemLink} target="_self" onClick={handleControlLinkClick} disabled={disableLink}>
|
||||
<div
|
||||
className={cn(
|
||||
"group h-24 sm:h-[52px] flex w-full flex-col items-center justify-between gap-3 sm:gap-5 px-6 py-4 sm:py-0 text-sm border-b border-custom-border-200 bg-custom-background-100 hover:bg-custom-background-90 sm:flex-row",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="relative flex w-full items-center justify-between gap-3 overflow-hidden">
|
||||
<div className="relative flex w-full items-center gap-3 overflow-hidden">
|
||||
<div className="flex items-center gap-4 truncate">
|
||||
{prependTitleElement && <span className="flex items-center flex-shrink-0">{prependTitleElement}</span>}
|
||||
<Tooltip tooltipContent={title} position="top" isMobile={isMobile}>
|
||||
<span className="truncate text-sm">{title}</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{appendTitleElement && <span className="flex items-center flex-shrink-0">{appendTitleElement}</span>}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"group min-h-[52px] flex w-full flex-col items-center justify-between gap-3 px-6 py-4 text-sm border-b border-custom-border-200 bg-custom-background-100 hover:bg-custom-background-90 ",
|
||||
{
|
||||
"xl:gap-5 xl:py-0 xl:flex-row": isSidebarOpen,
|
||||
"lg:gap-5 lg:py-0 lg:flex-row": !isSidebarOpen,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="relative flex w-full items-center justify-between gap-3 overflow-hidden">
|
||||
<div className="relative flex w-full items-center gap-3 overflow-hidden">
|
||||
<ControlLink
|
||||
href={itemLink}
|
||||
target="_self"
|
||||
className="flex items-center gap-4 truncate"
|
||||
onClick={handleControlLinkClick}
|
||||
disabled={disableLink}
|
||||
>
|
||||
{prependTitleElement && <span className="flex items-center flex-shrink-0">{prependTitleElement}</span>}
|
||||
<Tooltip tooltipContent={title} position="top" isMobile={isMobile}>
|
||||
<span className="truncate text-sm">{title}</span>
|
||||
</Tooltip>
|
||||
</ControlLink>
|
||||
{appendTitleElement && <span className="flex items-center flex-shrink-0">{appendTitleElement}</span>}
|
||||
</div>
|
||||
<span className="h-6 w-96 flex-shrink-0" />
|
||||
{quickActionElement && quickActionElement}
|
||||
</div>
|
||||
</ControlLink>
|
||||
{actionableItems && (
|
||||
<div className="absolute right-5 bottom-4 flex items-center gap-1.5">
|
||||
<div className="relative flex items-center gap-4 sm:w-auto sm:flex-shrink-0 sm:justify-end items-center">
|
||||
{actionableItems && (
|
||||
<div
|
||||
className={cn(
|
||||
"relative flex items-center justify-start gap-4 flex-wrap w-full",
|
||||
{
|
||||
"xl:flex-nowrap xl:w-auto xl:flex-shrink-0": isSidebarOpen,
|
||||
"lg:flex-nowrap lg:w-auto lg:flex-shrink-0": !isSidebarOpen,
|
||||
},
|
||||
actionItemContainerClassName
|
||||
)}
|
||||
>
|
||||
{actionableItems}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -161,7 +161,14 @@ export const CycleListItemAction: FC<Props> = observer((props) => {
|
|||
selected={!!cycleDetails.is_favorite}
|
||||
/>
|
||||
)}
|
||||
<CycleQuickActions parentRef={parentRef} cycleId={cycleId} projectId={projectId} workspaceSlug={workspaceSlug} />
|
||||
<div className="hidden md:block">
|
||||
<CycleQuickActions
|
||||
parentRef={parentRef}
|
||||
cycleId={cycleId}
|
||||
projectId={projectId}
|
||||
workspaceSlug={workspaceSlug}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { generateQueryParams } from "@/helpers/router.helper";
|
|||
import { useCycle } from "@/hooks/store";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
import { CycleQuickActions } from "../quick-actions";
|
||||
|
||||
type TCyclesListItem = {
|
||||
cycleId: string;
|
||||
|
|
@ -122,8 +123,19 @@ export const CyclesListItem: FC<TCyclesListItem> = observer((props) => {
|
|||
parentRef={parentRef}
|
||||
/>
|
||||
}
|
||||
quickActionElement={
|
||||
<div className="block md:hidden">
|
||||
<CycleQuickActions
|
||||
parentRef={parentRef}
|
||||
cycleId={cycleId}
|
||||
projectId={projectId}
|
||||
workspaceSlug={workspaceSlug}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
isMobile={isMobile}
|
||||
parentRef={parentRef}
|
||||
isSidebarOpen={searchParams.has("peekCycle")}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { IssueProperties } from "@/components/issues/issue-layouts/properties";
|
|||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useIssueDetail, useProject } from "@/hooks/store";
|
||||
import { useAppTheme, useIssueDetail, useProject } from "@/hooks/store";
|
||||
import { TSelectionHelper } from "@/hooks/use-multiple-select";
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
// types
|
||||
|
|
@ -65,6 +65,7 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||
const workspaceSlug = routerWorkspaceSlug?.toString();
|
||||
const projectId = routerProjectId?.toString();
|
||||
// hooks
|
||||
const { sidebarCollapsed: isSidebarCollapsed } = useAppTheme();
|
||||
const { getProjectIdentifierById } = useProject();
|
||||
const { getIsIssuePeeked, peekIssue, setPeekIssue, subIssues: subIssuesStore } = useIssueDetail();
|
||||
|
||||
|
|
@ -133,13 +134,15 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||
<div
|
||||
ref={issueRef}
|
||||
className={cn(
|
||||
"group/list-block min-h-11 relative flex flex-col md:flex-row md:items-center gap-3 bg-custom-background-100 hover:bg-custom-background-90 p-3 pl-1.5 text-sm transition-colors border border-transparent",
|
||||
"group/list-block min-h-11 relative flex flex-col gap-3 bg-custom-background-100 hover:bg-custom-background-90 p-3 pl-1.5 text-sm transition-colors border border-transparent",
|
||||
{
|
||||
"border-custom-primary-70": getIsIssuePeeked(issue.id) && peekIssue?.nestingLevel === nestingLevel,
|
||||
"border-custom-border-400": isIssueActive,
|
||||
"last:border-b-transparent": !getIsIssuePeeked(issue.id) && !isIssueActive,
|
||||
"bg-custom-primary-100/5 hover:bg-custom-primary-100/10": isIssueSelected,
|
||||
"bg-custom-background-80": isCurrentBlockDragging,
|
||||
"md:flex-row md:items-center": isSidebarCollapsed,
|
||||
"lg:flex-row lg:items-center": !isSidebarCollapsed,
|
||||
}
|
||||
)}
|
||||
onDragStart={() => {
|
||||
|
|
@ -229,7 +232,7 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||
id={`issue-${issue.id}`}
|
||||
href={`/${workspaceSlug}/projects/${issue.project_id}/${issue.archived_at ? "archives/" : ""}issues/${
|
||||
issue.id
|
||||
}`}
|
||||
}`}
|
||||
onClick={() => handleIssuePeekOverview(issue)}
|
||||
className="w-full truncate cursor-pointer text-sm text-custom-text-100"
|
||||
disabled={!!issue?.tempId}
|
||||
|
|
@ -241,7 +244,12 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||
)}
|
||||
</div>
|
||||
{!issue?.tempId && (
|
||||
<div className="block md:hidden border border-custom-border-300 rounded">
|
||||
<div
|
||||
className={cn("block border border-custom-border-300 rounded", {
|
||||
"md:hidden": isSidebarCollapsed,
|
||||
"lg:hidden": !isSidebarCollapsed,
|
||||
})}
|
||||
>
|
||||
{quickActions({
|
||||
issue,
|
||||
parentRef: issueRef,
|
||||
|
|
@ -253,14 +261,19 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||
{!issue?.tempId ? (
|
||||
<>
|
||||
<IssueProperties
|
||||
className="relative flex flex-wrap md:flex-grow md:flex-shrink-0 items-center gap-2 whitespace-nowrap"
|
||||
className={`relative flex flex-wrap ${isSidebarCollapsed ? "md:flex-grow md:flex-shrink-0" : "lg:flex-grow lg:flex-shrink-0"} items-center gap-2 whitespace-nowrap`}
|
||||
issue={issue}
|
||||
isReadOnly={!canEditIssueProperties}
|
||||
updateIssue={updateIssue}
|
||||
displayProperties={displayProperties}
|
||||
activeLayout="List"
|
||||
/>
|
||||
<div className="hidden md:block">
|
||||
<div
|
||||
className={cn("hidden", {
|
||||
"md:flex": isSidebarCollapsed,
|
||||
"lg:flex": !isSidebarCollapsed,
|
||||
})}
|
||||
>
|
||||
{quickActions({
|
||||
issue,
|
||||
parentRef: issueRef,
|
||||
|
|
|
|||
|
|
@ -154,12 +154,14 @@ export const ModuleListItemAction: FC<Props> = observer((props) => {
|
|||
/>
|
||||
)}
|
||||
{workspaceSlug && projectId && (
|
||||
<ModuleQuickActions
|
||||
parentRef={parentRef}
|
||||
moduleId={moduleId}
|
||||
projectId={projectId.toString()}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
/>
|
||||
<div className="hidden md:block">
|
||||
<ModuleQuickActions
|
||||
parentRef={parentRef}
|
||||
moduleId={moduleId}
|
||||
projectId={projectId.toString()}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { Check, Info } from "lucide-react";
|
|||
import { CircularProgressIndicator } from "@plane/ui";
|
||||
// components
|
||||
import { ListItem } from "@/components/core/list";
|
||||
import { ModuleListItemAction } from "@/components/modules";
|
||||
import { ModuleListItemAction, ModuleQuickActions } from "@/components/modules";
|
||||
// helpers
|
||||
import { generateQueryParams } from "@/helpers/router.helper";
|
||||
// hooks
|
||||
|
|
@ -109,6 +109,16 @@ export const ModuleListItem: React.FC<Props> = observer((props) => {
|
|||
</button>
|
||||
}
|
||||
actionableItems={<ModuleListItemAction moduleId={moduleId} moduleDetails={moduleDetails} parentRef={parentRef} />}
|
||||
quickActionElement={
|
||||
<div className="block md:hidden">
|
||||
<ModuleQuickActions
|
||||
parentRef={parentRef}
|
||||
moduleId={moduleId}
|
||||
projectId={projectId.toString()}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
isMobile={isMobile}
|
||||
parentRef={parentRef}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -95,12 +95,14 @@ export const ViewListItemAction: FC<Props> = observer((props) => {
|
|||
/>
|
||||
)}
|
||||
{projectId && workspaceSlug && (
|
||||
<ViewQuickActions
|
||||
parentRef={parentRef}
|
||||
projectId={projectId.toString()}
|
||||
view={view}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
/>
|
||||
<div className="hidden md:block">
|
||||
<ViewQuickActions
|
||||
parentRef={parentRef}
|
||||
projectId={projectId.toString()}
|
||||
view={view}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { IProjectView } from "@plane/types";
|
|||
// components
|
||||
import { Logo } from "@/components/common";
|
||||
import { ListItem } from "@/components/core/list";
|
||||
import { ViewListItemAction } from "@/components/views";
|
||||
import { ViewListItemAction, ViewQuickActions } from "@/components/views";
|
||||
// hooks
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
|
||||
|
|
@ -40,6 +40,16 @@ export const ProjectViewListItem: FC<Props> = observer((props) => {
|
|||
title={view.name}
|
||||
itemLink={`/${workspaceSlug}/projects/${projectId}/views/${view.id}`}
|
||||
actionableItems={<ViewListItemAction parentRef={parentRef} view={view} />}
|
||||
quickActionElement={
|
||||
<div className="block md:hidden">
|
||||
<ViewQuickActions
|
||||
parentRef={parentRef}
|
||||
projectId={projectId.toString()}
|
||||
view={view}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
isMobile={isMobile}
|
||||
parentRef={parentRef}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue