chore: added None filter option to the dashboard widgets (#3556)
* chore: added tab change animation * chore: widgets filtering logic updated * refactor: issues list widget * fix: tab navigation transition * fix: extra top spacing on opening the peek overview
This commit is contained in:
parent
ee0e3e2e25
commit
0ee93dfd8c
11 changed files with 270 additions and 147 deletions
|
|
@ -14,7 +14,7 @@ import {
|
|||
IssueListItemProps,
|
||||
} from "components/dashboard/widgets";
|
||||
// ui
|
||||
import { Loader, getButtonStyling } from "@plane/ui";
|
||||
import { getButtonStyling } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "helpers/common.helper";
|
||||
import { getRedirectionFilters } from "helpers/dashboard.helper";
|
||||
|
|
@ -41,16 +41,18 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
|||
const filterParams = getRedirectionFilters(tab);
|
||||
|
||||
const ISSUE_LIST_ITEM: {
|
||||
[key in string]: {
|
||||
[key: string]: {
|
||||
[key in TIssuesListTypes]: React.FC<IssueListItemProps>;
|
||||
};
|
||||
} = {
|
||||
assigned: {
|
||||
pending: AssignedUpcomingIssueListItem,
|
||||
upcoming: AssignedUpcomingIssueListItem,
|
||||
overdue: AssignedOverdueIssueListItem,
|
||||
completed: AssignedCompletedIssueListItem,
|
||||
},
|
||||
created: {
|
||||
pending: CreatedUpcomingIssueListItem,
|
||||
upcoming: CreatedUpcomingIssueListItem,
|
||||
overdue: CreatedOverdueIssueListItem,
|
||||
completed: CreatedCompletedIssueListItem,
|
||||
|
|
@ -61,12 +63,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
|||
<>
|
||||
<div className="h-full">
|
||||
{isLoading ? (
|
||||
<Loader className="mt-7 mx-6 space-y-4">
|
||||
<Loader.Item height="25px" />
|
||||
<Loader.Item height="25px" />
|
||||
<Loader.Item height="25px" />
|
||||
<Loader.Item height="25px" />
|
||||
</Loader>
|
||||
<></>
|
||||
) : issues.length > 0 ? (
|
||||
<>
|
||||
<div className="mt-7 mx-6 border-b-[0.5px] border-custom-border-200 grid grid-cols-6 gap-1 text-xs text-custom-text-300 pb-1">
|
||||
|
|
@ -81,7 +78,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
|||
{totalIssues}
|
||||
</span>
|
||||
</h6>
|
||||
{tab === "upcoming" && <h6 className="text-center">Due date</h6>}
|
||||
{["upcoming", "pending"].includes(tab) && <h6 className="text-center">Due date</h6>}
|
||||
{tab === "overdue" && <h6 className="text-center">Due by</h6>}
|
||||
{type === "assigned" && tab !== "completed" && <h6 className="text-center">Blocked by</h6>}
|
||||
{type === "created" && <h6 className="text-center">Assigned to</h6>}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,63 @@
|
|||
import { observer } from "mobx-react";
|
||||
import { Tab } from "@headlessui/react";
|
||||
// helpers
|
||||
import { cn } from "helpers/common.helper";
|
||||
// types
|
||||
import { TDurationFilterOptions, TIssuesListTypes } from "@plane/types";
|
||||
// constants
|
||||
import { ISSUES_TABS_LIST } from "constants/dashboard";
|
||||
import { FILTERED_ISSUES_TABS_LIST, UNFILTERED_ISSUES_TABS_LIST } from "constants/dashboard";
|
||||
|
||||
export const TabsList = () => (
|
||||
<Tab.List
|
||||
as="div"
|
||||
className="border-[0.5px] border-custom-border-200 rounded grid grid-cols-3 bg-custom-background-80"
|
||||
>
|
||||
{ISSUES_TABS_LIST.map((tab) => (
|
||||
<Tab
|
||||
key={tab.key}
|
||||
className={({ selected }) =>
|
||||
cn("font-semibold text-xs rounded py-1.5 focus:outline-none", {
|
||||
"bg-custom-background-100 text-custom-text-300 shadow-[2px_0_8px_rgba(167,169,174,0.15)]": selected,
|
||||
"text-custom-text-400": !selected,
|
||||
})
|
||||
}
|
||||
>
|
||||
{tab.label}
|
||||
</Tab>
|
||||
))}
|
||||
</Tab.List>
|
||||
);
|
||||
type Props = {
|
||||
durationFilter: TDurationFilterOptions;
|
||||
selectedTab: TIssuesListTypes;
|
||||
};
|
||||
|
||||
export const TabsList: React.FC<Props> = observer((props) => {
|
||||
const { durationFilter, selectedTab } = props;
|
||||
|
||||
const tabsList = durationFilter === "none" ? UNFILTERED_ISSUES_TABS_LIST : FILTERED_ISSUES_TABS_LIST;
|
||||
const selectedTabIndex = tabsList.findIndex((tab) => tab.key === (selectedTab ?? "pending"));
|
||||
|
||||
return (
|
||||
<Tab.List
|
||||
as="div"
|
||||
className="relative border-[0.5px] border-custom-border-200 rounded bg-custom-background-80 grid"
|
||||
style={{
|
||||
gridTemplateColumns: `repeat(${tabsList.length}, 1fr)`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={cn("absolute bg-custom-background-100 rounded transition-all duration-500 ease-in-out", {
|
||||
// right shadow
|
||||
"shadow-[2px_0_8px_rgba(167,169,174,0.15)]": selectedTabIndex !== tabsList.length - 1,
|
||||
// left shadow
|
||||
"shadow-[-2px_0_8px_rgba(167,169,174,0.15)]": selectedTabIndex !== 0,
|
||||
})}
|
||||
style={{
|
||||
height: "calc(100% - 1px)",
|
||||
width: `${100 / tabsList.length}%`,
|
||||
transform: `translateX(${selectedTabIndex * 100}%)`,
|
||||
}}
|
||||
/>
|
||||
{tabsList.map((tab) => (
|
||||
<Tab
|
||||
key={tab.key}
|
||||
className={cn(
|
||||
"relative z-[1] font-semibold text-xs rounded py-1.5 text-custom-text-400 focus:outline-none",
|
||||
"transition duration-500",
|
||||
{
|
||||
"text-custom-text-100 bg-custom-background-100": selectedTab === tab.key,
|
||||
"hover:text-custom-text-300": selectedTab !== tab.key,
|
||||
// // right shadow
|
||||
// "shadow-[2px_0_8px_rgba(167,169,174,0.15)]": selectedTabIndex !== tabsList.length - 1,
|
||||
// // left shadow
|
||||
// "shadow-[-2px_0_8px_rgba(167,169,174,0.15)]": selectedTabIndex !== 0,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<span className="scale-110">{tab.label}</span>
|
||||
</Tab>
|
||||
))}
|
||||
</Tab.List>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue