style: filter issues dropdown (#466)

This commit is contained in:
Aaryan Khandelwal 2023-03-16 18:14:07 +05:30 committed by GitHub
parent 0f06589b83
commit 23c468786d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 115 additions and 59 deletions

View File

@ -13,21 +13,24 @@ import useIssuesProperties from "hooks/use-issue-properties";
import useIssuesView from "hooks/use-issues-view";
// headless ui
import { Popover, Transition } from "@headlessui/react";
// components
import { PRIORITIES } from "constants/project";
// ui
import { CustomMenu, MultiLevelDropdown } from "components/ui";
import { Avatar, CustomMenu, MultiLevelDropdown } from "components/ui";
// icons
import { ChevronDownIcon, ListBulletIcon } from "@heroicons/react/24/outline";
import { Squares2X2Icon } from "@heroicons/react/20/solid";
import { getStateGroupIcon } from "components/icons";
import { getPriorityIcon } from "components/icons/priority-icon";
// helpers
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
import { getStatesList } from "helpers/state.helper";
// types
import { IIssue, IIssueLabels, Properties } from "types";
import { IIssueLabels, Properties } from "types";
// fetch-keys
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS, STATE_LIST } from "constants/fetch-keys";
// constants
import { GROUP_BY_OPTIONS, ORDER_BY_OPTIONS, FILTER_ISSUE_OPTIONS } from "constants/issue";
import { PRIORITIES } from "constants/project";
export const IssuesFilterView: React.FC = () => {
const router = useRouter();
@ -97,7 +100,7 @@ export const IssuesFilterView: React.FC = () => {
</button>
</div>
<MultiLevelDropdown
label="Filter"
label="Filters"
onSelect={(option) => {
setFilters({
...filters,
@ -116,7 +119,11 @@ export const IssuesFilterView: React.FC = () => {
children: [
...PRIORITIES.map((priority) => ({
id: priority ?? "none",
label: priority ?? "None",
label: (
<div className="flex items-center gap-2">
{getPriorityIcon(priority)} {priority ?? "None"}
</div>
),
value: {
key: "priority",
value: priority,
@ -132,7 +139,11 @@ export const IssuesFilterView: React.FC = () => {
children: [
...statesList.map((state) => ({
id: state.id,
label: state.name,
label: (
<div className="flex items-center gap-2">
{getStateGroupIcon(state.group, "16", "16", state.color)} {state.name}
</div>
),
value: {
key: "state",
value: state.id,
@ -148,7 +159,14 @@ export const IssuesFilterView: React.FC = () => {
children: [
...(members?.map((member) => ({
id: member.member.id,
label: member.member.first_name,
label: (
<div className="flex items-center gap-2">
<Avatar user={member.member} />
{member.member.first_name && member.member.first_name !== ""
? member.member.first_name
: member.member.email}
</div>
),
value: {
key: "assignee",
value: member.member.id,
@ -163,12 +181,12 @@ export const IssuesFilterView: React.FC = () => {
{({ open }) => (
<>
<Popover.Button
className={`group flex items-center gap-2 rounded-md border bg-transparent p-2 text-xs font-medium hover:bg-gray-100 hover:text-gray-900 focus:outline-none ${
className={`group flex items-center gap-2 rounded-md border bg-transparent px-3 py-1.5 text-xs hover:bg-gray-100 hover:text-gray-900 focus:outline-none ${
open ? "bg-gray-100 text-gray-900" : "text-gray-500"
}`}
>
View
<ChevronDownIcon className="h-4 w-4" aria-hidden="true" />
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
</Popover.Button>
<Transition

View File

@ -42,6 +42,7 @@ import {
STATE_LIST,
} from "constants/fetch-keys";
import { EmptySpace, EmptySpaceItem } from "components/ui";
import { PrimaryButton } from "components/ui/button/primary-button";
type Props = {
type?: "issue" | "cycle" | "module";
@ -496,20 +497,21 @@ export const IssuesView: React.FC<Props> = ({ type = "issue", openIssuesListModa
})}
</div>
<div>
<button
{Object.keys(filters).length > 0 && (
<PrimaryButton
type="button"
onClick={() =>
setCreateViewModal({
query: filters,
})
}
className="flex items-center gap-x-0.5 text-sm"
className="flex items-center gap-4 text-sm"
size="sm"
>
<PlusIcon className="h-3 w-3" />
<span>Save view</span>
</button>
</div>
<PlusIcon className="h-4 w-4" />
Save view
</PrimaryButton>
)}
</div>
<DragDropContext onDragEnd={handleOnDragEnd}>
<StrictModeDroppable droppableId="trashBox">

View File

@ -18,7 +18,7 @@ export const IssuePrioritySelect: React.FC<Props> = ({ value, onChange }) => (
label={
<div className="flex items-center justify-center gap-2 text-xs">
<span className="flex items-center">
{getPriorityIcon(value, `${value ? "text-xs" : "text-xs text-gray-500"}`)}
{getPriorityIcon(value, `text-xs ${value ? "" : "text-gray-500"}`)}
</span>
<span className={`${value ? "text-gray-600" : "text-gray-500"} capitalize`}>
{value ?? "Priority"}

View File

@ -136,8 +136,12 @@ export const SingleSidebarProject: React.FC<Props> = ({
className={`${sidebarCollapse ? "" : "ml-[2.25rem]"} flex flex-col gap-y-1`}
>
{navigation(workspaceSlug as string, project?.id).map((item) => {
if (item.name === "Cycles" && !project.cycle_view) return;
if (item.name === "Modules" && !project.module_view) return;
if (
(item.name === "Cycles" && !project.cycle_view) ||
(item.name === "Modules" && !project.module_view) ||
(item.name === "Views" && !project.issue_views_view)
)
return;
return (
<Link key={item.name} href={item.href}>

View File

@ -1,6 +1,7 @@
import { Menu, Transition } from "@headlessui/react";
import { Fragment, useState } from "react";
import { ChevronDownIcon, ChevronRightIcon, ChevronLeftIcon } from "@heroicons/react/20/solid";
import { ChevronRightIcon, ChevronLeftIcon } from "@heroicons/react/20/solid";
import { ChevronDownIcon } from "@heroicons/react/24/outline";
type MultiLevelDropdownProps = {
label: string;
@ -11,7 +12,7 @@ type MultiLevelDropdownProps = {
selected?: boolean;
children?: {
id: string;
label: string;
label: string | JSX.Element;
value: any;
selected?: boolean;
}[];
@ -20,26 +21,27 @@ type MultiLevelDropdownProps = {
direction?: "left" | "right";
};
export const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = (props) => {
const { label, options, onSelect, direction = "right" } = props;
export const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = ({
label,
options,
onSelect,
direction = "right",
}) => {
const [openChildFor, setOpenChildFor] = useState<string | null>(null);
return (
<Menu as="div" className="relative inline-block text-left">
<Menu as="div" className="relative z-10 inline-block text-left">
{({ open }) => (
<>
<div>
<Menu.Button
onClick={() => {
setOpenChildFor(null);
}}
className={`group flex items-center gap-2 rounded-md border bg-transparent p-2 text-xs font-medium hover:bg-gray-100 hover:text-gray-900 focus:outline-none ${
onClick={() => setOpenChildFor(null)}
className={`group flex items-center justify-between gap-2 rounded-md border px-3 py-1.5 text-xs shadow-sm duration-300 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 ${
open ? "bg-gray-100 text-gray-900" : "text-gray-500"
}`}
>
{label}
<ChevronDownIcon className="h-4 w-4" aria-hidden="true" />
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
</Menu.Button>
</div>
<Transition
@ -53,10 +55,10 @@ export const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = (props) =>
>
<Menu.Items
static
className="absolute right-0 mt-2 w-36 origin-top-right select-none divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
className="absolute right-0 mt-1 w-36 origin-top-right select-none rounded-md bg-white text-xs shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
>
{options.map((option) => (
<div className="relative px-1 py-1" key={option.id}>
<div className="relative p-1" key={option.id}>
<Menu.Item
as="button"
onClick={(e: any) => {
@ -81,7 +83,9 @@ export const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = (props) =>
<div
className={`${
active || option.selected ? "bg-gray-100" : "text-gray-900"
} group flex w-full items-center justify-between rounded-md px-2 py-2 text-sm`}
} flex items-center gap-1 rounded px-1 py-1.5 ${
direction === "right" ? "justify-between" : ""
}`}
>
{direction === "left" && option.children && (
<ChevronLeftIcon className="h-4 w-4" aria-hidden="true" />
@ -97,33 +101,31 @@ export const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = (props) =>
{option.children && option.id === openChildFor && (
<Menu.Items
static
className={`absolute top-0 mt-2 w-36 origin-top-right select-none divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none ${
className={`absolute top-0 w-36 origin-top-right select-none rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none ${
direction === "left"
? "right-full -translate-x-2"
: "left-full translate-x-2"
? "right-full -translate-x-1"
: "left-full translate-x-1"
}`}
>
{option.children.map((child) => (
<div className="relative px-1 py-1" key={child.id}>
<Menu.Item as="div" className="flex items-center justify-between">
{({ active }) => (
<>
<button
type="button"
onClick={() => {
onSelect(child.value);
}}
className={`${
active || option.selected ? "bg-gray-100" : "text-gray-900"
} group flex w-full items-center rounded-md px-2 py-2 text-sm capitalize`}
>
{child.label}
</button>
</>
)}
<div className="p-1">
{option.children.map((child) => (
<Menu.Item
key={child.id}
as="button"
type="button"
onClick={() => {
onSelect(child.value);
}}
className={({ active }) =>
`${
active || option.selected ? "bg-gray-100" : "text-gray-900"
} flex w-full items-center rounded px-1 py-1.5 capitalize`
}
>
{child.label}
</Menu.Item>
</div>
))}
))}
</div>
</Menu.Items>
)}
</div>

View File

@ -20,7 +20,7 @@ import { IProject, UserAuth } from "types";
import type { NextPage, GetServerSidePropsContext } from "next";
// fetch-keys
import { PROJECTS_LIST, PROJECT_DETAILS } from "constants/fetch-keys";
import { ContrastIcon, PeopleGroupIcon } from "components/icons";
import { ContrastIcon, PeopleGroupIcon, ViewListIcon } from "components/icons";
const FeaturesSettings: NextPage<UserAuth> = (props) => {
const router = useRouter();
@ -93,7 +93,7 @@ const FeaturesSettings: NextPage<UserAuth> = (props) => {
<section className="space-y-8">
<h3 className="text-2xl font-semibold">Features</h3>
<div className="space-y-5">
<div className="flex items-center justify-between gap-x-8 gap-y-2 rounded-[10px] border bg-white p-6">
<div className="flex items-center justify-between gap-x-8 gap-y-2 rounded-[10px] border bg-white p-5">
<div className="flex items-start gap-3">
<ContrastIcon color="#3f76ff" width={28} height={28} className="flex-shrink-0" />
<div>
@ -122,7 +122,7 @@ const FeaturesSettings: NextPage<UserAuth> = (props) => {
/>
</button>
</div>
<div className="flex items-center justify-between gap-x-8 gap-y-2 rounded-[10px] border bg-white p-6">
<div className="flex items-center justify-between gap-x-8 gap-y-2 rounded-[10px] border bg-white p-5">
<div className="flex items-start gap-3">
<PeopleGroupIcon color="#ff6b00" width={28} height={28} className="flex-shrink-0" />
<div>
@ -151,6 +151,35 @@ const FeaturesSettings: NextPage<UserAuth> = (props) => {
/>
</button>
</div>
<div className="flex items-center justify-between gap-x-8 gap-y-2 rounded-[10px] border bg-white p-5">
<div className="flex items-start gap-3">
<ViewListIcon color="#ff6b00" width={28} height={28} className="flex-shrink-0" />
<div>
<h4 className="-mt-1.5 text-xl font-semibold">Views</h4>
<p className="text-gray-500">
Modules are enabled for all the projects in this workspace. Access it from the
navigation bar.
</p>
</div>
</div>
<button
type="button"
className={`relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none ${
projectDetails?.issue_views_view ? "bg-green-500" : "bg-gray-200"
}`}
role="switch"
aria-checked={projectDetails?.issue_views_view}
onClick={() => handleSubmit({ issue_views_view: !projectDetails?.issue_views_view })}
>
<span className="sr-only">Use views</span>
<span
aria-hidden="true"
className={`inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out ${
projectDetails?.issue_views_view ? "translate-x-5" : "translate-x-0"
}`}
/>
</button>
</div>
</div>
<div className="flex items-center gap-2">
<a href="https://plane.so/" target="_blank" rel="noreferrer">

View File

@ -11,6 +11,7 @@ export interface IProject {
id: string;
identifier: string;
is_favorite: boolean;
issue_views_view: boolean;
module_view: boolean;
name: string;
network: number;