From 85c0a3126ea28104bb8f80f869647a47c7af075a Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Mon, 13 Jan 2025 18:01:55 +0530 Subject: [PATCH 1/2] chore: added bar and tree map icons --- packages/ui/src/icons/bar-icon.tsx | 20 ++++++++++++++++++++ packages/ui/src/icons/index.ts | 2 ++ packages/ui/src/icons/tree-map-icon.tsx | 16 ++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 packages/ui/src/icons/bar-icon.tsx create mode 100644 packages/ui/src/icons/tree-map-icon.tsx diff --git a/packages/ui/src/icons/bar-icon.tsx b/packages/ui/src/icons/bar-icon.tsx new file mode 100644 index 00000000000..b20d5ebeaec --- /dev/null +++ b/packages/ui/src/icons/bar-icon.tsx @@ -0,0 +1,20 @@ +import * as React from "react"; + +import { ISvgIcons } from "./type"; + +export const BarIcon: React.FC = ({ className = "", ...rest }) => ( + + + + + +); diff --git a/packages/ui/src/icons/index.ts b/packages/ui/src/icons/index.ts index c09c26057de..f274a341424 100644 --- a/packages/ui/src/icons/index.ts +++ b/packages/ui/src/icons/index.ts @@ -49,3 +49,5 @@ export * from "./off-track-icon"; export * from "./at-risk-icon"; export * from "./multiple-sticky"; export * from "./sticky-note-icon"; +export * from "./bar-icon"; +export * from "./tree-map-icon"; diff --git a/packages/ui/src/icons/tree-map-icon.tsx b/packages/ui/src/icons/tree-map-icon.tsx new file mode 100644 index 00000000000..b8de0106905 --- /dev/null +++ b/packages/ui/src/icons/tree-map-icon.tsx @@ -0,0 +1,16 @@ +import * as React from "react"; + +import { ISvgIcons } from "./type"; + +export const TreeMapIcon: React.FC = ({ className = "", ...rest }) => ( + + + + + + + + + + +); From 22a7beb9ccb11d239f770803ba517c3c4f76eb70 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Mon, 13 Jan 2025 18:03:19 +0530 Subject: [PATCH 2/2] improvement: made tab list items modular for independent use --- packages/ui/src/tabs/index.ts | 1 + packages/ui/src/tabs/tab-list.tsx | 71 +++++++++++++++++++++++++++++++ packages/ui/src/tabs/tabs.tsx | 62 ++++++++------------------- 3 files changed, 89 insertions(+), 45 deletions(-) create mode 100644 packages/ui/src/tabs/tab-list.tsx diff --git a/packages/ui/src/tabs/index.ts b/packages/ui/src/tabs/index.ts index 811d3d4a725..c232b43ab42 100644 --- a/packages/ui/src/tabs/index.ts +++ b/packages/ui/src/tabs/index.ts @@ -1 +1,2 @@ export * from "./tabs"; +export * from "./tab-list"; diff --git a/packages/ui/src/tabs/tab-list.tsx b/packages/ui/src/tabs/tab-list.tsx new file mode 100644 index 00000000000..0e9eb2dbd5b --- /dev/null +++ b/packages/ui/src/tabs/tab-list.tsx @@ -0,0 +1,71 @@ +import { Tab } from "@headlessui/react"; +import { LucideProps } from "lucide-react"; +import React, { FC } from "react"; +// helpers +import { cn } from "../../helpers"; + +export type TabListItem = { + key: string; + icon?: FC; + label?: React.ReactNode; + disabled?: boolean; + onClick?: () => void; +}; + +type TTabListProps = { + tabs: TabListItem[]; + tabListClassName?: string; + tabClassName?: string; + size?: "sm" | "md" | "lg"; + selectedTab?: string; + onTabChange?: (key: string) => void; +}; + +export const TabList: FC = ({ + tabs, + tabListClassName, + tabClassName, + size = "md", + selectedTab, + onTabChange, +}) => ( + + {tabs.map((tab) => ( + + cn( + "flex items-center justify-center p-1 min-w-fit w-full font-medium text-custom-text-100 outline-none focus:outline-none cursor-pointer transition-all rounded", + (selectedTab ? selectedTab === tab.key : selected) + ? "bg-custom-background-100 text-custom-text-100 shadow-sm" + : tab.disabled + ? "text-custom-text-400 cursor-not-allowed" + : "text-custom-text-400 hover:text-custom-text-300 hover:bg-custom-background-80/60", + { + "text-xs": size === "sm", + "text-sm": size === "md", + "text-base": size === "lg", + }, + tabClassName + ) + } + key={tab.key} + onClick={() => { + if (!tab.disabled) { + onTabChange?.(tab.key); + tab.onClick?.(); + } + }} + disabled={tab.disabled} + > + {tab.icon && } + {tab.label} + + ))} + +); diff --git a/packages/ui/src/tabs/tabs.tsx b/packages/ui/src/tabs/tabs.tsx index 92bc3ad7276..b2791c0b8ca 100644 --- a/packages/ui/src/tabs/tabs.tsx +++ b/packages/ui/src/tabs/tabs.tsx @@ -1,19 +1,17 @@ -import React, { FC, Fragment, useEffect, useState } from "react"; import { Tab } from "@headlessui/react"; -import { LucideProps } from "lucide-react"; +import React, { FC, Fragment, useEffect, useState } from "react"; // helpers import { useLocalStorage } from "@plane/hooks"; import { cn } from "../../helpers"; +// types +import { TabList, TabListItem } from "./tab-list"; -type TabItem = { - key: string; - icon?: FC; - label?: React.ReactNode; +export type TabContent = { content: React.ReactNode; - disabled?: boolean; - onClick?: () => void; }; +export type TabItem = TabListItem & TabContent; + type TTabsProps = { tabs: TabItem[]; storageKey?: string; @@ -58,48 +56,22 @@ export const Tabs: FC = (props: TTabsProps) => { const currentTabIndex = (tabKey: string): number => tabs.findIndex((tab) => tab.key === tabKey); + const handleTabChange = (key: string) => { + setSelectedTab(key); + }; + return (
- - {tabs.map((tab) => ( - - cn( - `flex items-center justify-center p-1 min-w-fit w-full font-medium text-custom-text-100 outline-none focus:outline-none cursor-pointer transition-all rounded`, - selected - ? "bg-custom-background-100 text-custom-text-100 shadow-sm" - : tab.disabled - ? "text-custom-text-400 cursor-not-allowed" - : "text-custom-text-400 hover:text-custom-text-300 hover:bg-custom-background-80/60", - { - "text-xs": size === "sm", - "text-sm": size === "md", - "text-base": size === "lg", - }, - tabClassName - ) - } - key={tab.key} - onClick={() => { - if (!tab.disabled) setSelectedTab(tab.key); - tab.onClick?.(); - }} - disabled={tab.disabled} - > - {tab.icon && } - {tab.label} - - ))} - + {actions &&
{actions}
}