[PWA-17] chore: project view list header improvement (#5425)
* chore: project view list header improvement * chore: code refactor
This commit is contained in:
parent
7efda1c392
commit
59697d34f8
4 changed files with 93 additions and 28 deletions
|
|
@ -3,11 +3,12 @@
|
||||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||||
// local components
|
// local components
|
||||||
import { ProjectViewsHeader } from "./header";
|
import { ProjectViewsHeader } from "./header";
|
||||||
|
import { ViewMobileHeader } from "./mobile-header";
|
||||||
|
|
||||||
export default function ProjectViewsListLayout({ children }: { children: React.ReactNode }) {
|
export default function ProjectViewsListLayout({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AppHeader header={<ProjectViewsHeader />} />
|
<AppHeader header={<ProjectViewsHeader />} mobileHeader={<ViewMobileHeader />} />
|
||||||
<ContentWrapper>{children}</ContentWrapper>
|
<ContentWrapper>{children}</ContentWrapper>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
// icons
|
||||||
|
import { ChevronDown, ListFilter } from "lucide-react";
|
||||||
|
// components
|
||||||
|
import { FiltersDropdown } from "@/components/issues/issue-layouts";
|
||||||
|
import { ViewFiltersSelection } from "@/components/views/filters/filter-selection";
|
||||||
|
import { ViewOrderByDropdown } from "@/components/views/filters/order-by";
|
||||||
|
// hooks
|
||||||
|
import { useMember, useProjectView } from "@/hooks/store";
|
||||||
|
|
||||||
|
export const ViewMobileHeader = observer(() => {
|
||||||
|
// store hooks
|
||||||
|
const { filters, updateFilters } = useProjectView();
|
||||||
|
const {
|
||||||
|
project: { projectMemberIds },
|
||||||
|
} = useMember();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="md:hidden flex justify-evenly border-b border-custom-border-200 py-2 z-[13] bg-custom-background-100">
|
||||||
|
<div className="flex flex-grow items-center justify-center border-l border-custom-border-200 text-sm text-custom-text-200">
|
||||||
|
<ViewOrderByDropdown
|
||||||
|
sortBy={filters.sortBy}
|
||||||
|
sortKey={filters.sortKey}
|
||||||
|
onChange={(val) => {
|
||||||
|
if (val.key) updateFilters("sortKey", val.key);
|
||||||
|
if (val.order) updateFilters("sortBy", val.order);
|
||||||
|
}}
|
||||||
|
isMobile
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-grow items-center justify-center border-l border-custom-border-200 text-sm text-custom-text-200">
|
||||||
|
<FiltersDropdown
|
||||||
|
icon={<ListFilter className="h-3 w-3" />}
|
||||||
|
title="Filters"
|
||||||
|
placement="bottom-end"
|
||||||
|
isFiltersApplied={false}
|
||||||
|
menuButton={
|
||||||
|
<span className="flex items-center text-sm text-custom-text-200">
|
||||||
|
Filters
|
||||||
|
<ChevronDown className="ml-2 h-4 w-4 text-custom-text-200" />
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ViewFiltersSelection
|
||||||
|
filters={filters}
|
||||||
|
handleFiltersUpdate={updateFilters}
|
||||||
|
memberIds={projectMemberIds ?? undefined}
|
||||||
|
/>
|
||||||
|
</FiltersDropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
@ -7,17 +7,16 @@ import { TViewFiltersSortBy, TViewFiltersSortKey } from "@plane/types";
|
||||||
import { CustomMenu, getButtonStyling } from "@plane/ui";
|
import { CustomMenu, getButtonStyling } from "@plane/ui";
|
||||||
// constants
|
// constants
|
||||||
import { VIEW_SORTING_KEY_OPTIONS } from "@/constants/views";
|
import { VIEW_SORTING_KEY_OPTIONS } from "@/constants/views";
|
||||||
// helpers
|
|
||||||
import { cn } from "@/helpers/common.helper";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onChange: (value: { key?: TViewFiltersSortKey; order?: TViewFiltersSortBy }) => void;
|
onChange: (value: { key?: TViewFiltersSortKey; order?: TViewFiltersSortBy }) => void;
|
||||||
sortBy: TViewFiltersSortBy;
|
sortBy: TViewFiltersSortBy;
|
||||||
sortKey: TViewFiltersSortKey;
|
sortKey: TViewFiltersSortKey;
|
||||||
|
isMobile?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ViewOrderByDropdown: React.FC<Props> = (props) => {
|
export const ViewOrderByDropdown: React.FC<Props> = (props) => {
|
||||||
const { onChange, sortBy, sortKey } = props;
|
const { onChange, sortBy, sortKey, isMobile = false } = props;
|
||||||
|
|
||||||
const orderByDetails = VIEW_SORTING_KEY_OPTIONS.find((option) => sortKey === option.key);
|
const orderByDetails = VIEW_SORTING_KEY_OPTIONS.find((option) => sortKey === option.key);
|
||||||
const isDescending = sortBy === "desc";
|
const isDescending = sortBy === "desc";
|
||||||
|
|
@ -27,14 +26,20 @@ export const ViewOrderByDropdown: React.FC<Props> = (props) => {
|
||||||
{ key: "desc", label: "Descending", isSelected: isDescending },
|
{ key: "desc", label: "Descending", isSelected: isDescending },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const buttonClassName = isMobile
|
||||||
|
? "flex items-center text-sm text-custom-text-200"
|
||||||
|
: `${getButtonStyling("neutral-primary", "sm")} px-2 text-custom-text-300`;
|
||||||
|
|
||||||
|
const chevronClassName = isMobile ? "h-4 w-4 text-custom-text-200" : "h-3 w-3";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
customButton={
|
customButton={
|
||||||
<div className={cn(getButtonStyling("neutral-primary", "sm"), "px-2 text-custom-text-300")}>
|
<span className={buttonClassName}>
|
||||||
<ArrowDownWideNarrow className="h-3 w-3" />
|
{!isMobile && <ArrowDownWideNarrow className="h-3 w-3" />}
|
||||||
{orderByDetails?.label}
|
<span className="flex-shrink-0"> {orderByDetails?.label}</span>
|
||||||
<ChevronDown className="h-3 w-3" strokeWidth={2} />
|
<ChevronDown className={chevronClassName} strokeWidth={2} />
|
||||||
</div>
|
</span>
|
||||||
}
|
}
|
||||||
placement="bottom-end"
|
placement="bottom-end"
|
||||||
maxHeight="lg"
|
maxHeight="lg"
|
||||||
|
|
|
||||||
|
|
@ -89,26 +89,28 @@ export const ViewListHeader = observer(() => {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ViewOrderByDropdown
|
<div className="hidden md:flex items-center gap-2">
|
||||||
sortBy={filters.sortBy}
|
<ViewOrderByDropdown
|
||||||
sortKey={filters.sortKey}
|
sortBy={filters.sortBy}
|
||||||
onChange={(val) => {
|
sortKey={filters.sortKey}
|
||||||
if (val.key) updateFilters("sortKey", val.key);
|
onChange={(val) => {
|
||||||
if (val.order) updateFilters("sortBy", val.order);
|
if (val.key) updateFilters("sortKey", val.key);
|
||||||
}}
|
if (val.order) updateFilters("sortBy", val.order);
|
||||||
/>
|
}}
|
||||||
<FiltersDropdown
|
|
||||||
icon={<ListFilter className="h-3 w-3" />}
|
|
||||||
title="Filters"
|
|
||||||
placement="bottom-end"
|
|
||||||
isFiltersApplied={false}
|
|
||||||
>
|
|
||||||
<ViewFiltersSelection
|
|
||||||
filters={filters}
|
|
||||||
handleFiltersUpdate={updateFilters}
|
|
||||||
memberIds={projectMemberIds ?? undefined}
|
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
<FiltersDropdown
|
||||||
|
icon={<ListFilter className="h-3 w-3" />}
|
||||||
|
title="Filters"
|
||||||
|
placement="bottom-end"
|
||||||
|
isFiltersApplied={false}
|
||||||
|
>
|
||||||
|
<ViewFiltersSelection
|
||||||
|
filters={filters}
|
||||||
|
handleFiltersUpdate={updateFilters}
|
||||||
|
memberIds={projectMemberIds ?? undefined}
|
||||||
|
/>
|
||||||
|
</FiltersDropdown>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue