Skip to content

Commit

Permalink
chore(web): refactor tabs (#1010)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkumbobeaty authored Jun 12, 2024
1 parent 4a926d4 commit 2f0c3a8
Show file tree
Hide file tree
Showing 2 changed files with 214 additions and 0 deletions.
112 changes: 112 additions & 0 deletions web/src/beta/lib/reearth-ui/components/Tabs/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { Meta, StoryObj } from "@storybook/react";
import { FC, useCallback, useState } from "react";

import { TabItems, Tabs as TabsMenu, TabsProps } from ".";

const meta: Meta<TabsProps> = {
component: TabsMenu,
};

export default meta;

type Story = StoryObj<TabsProps>;

const Tabs: FC<TabsProps> = ({ position, tabs, tabStyle }) => {
const [activeTab, setActiveTab] = useState("tab1");
const handleTabChange = useCallback((newTab: string) => {
setActiveTab(newTab);
}, []);

return (
<TabsMenu
position={position}
activeTab={activeTab}
tabStyle={tabStyle}
tabs={tabs}
onChange={handleTabChange}
/>
);
};

const tabsItem: TabItems[] = [
{
id: "tab1",
name: "Tab One",
children: (
<div>
<p>Here is tab one content</p>
<p>Here is tab one content</p>
</div>
),
},
{
id: "tab2",
name: "Tab Two",
icon: "editor",
children: <div>This is tab two content</div>,
},
{
id: "tab3",
name: "Tab Three",
children: <div>Content for Tab 3 </div>,
},
];

const tabsIcons: TabItems[] = [
{
id: "tab1",
icon: "data",
children: (
<div>
<p>Here is tab one content</p>
</div>
),
},
{
id: "tab2",
icon: "editor",
children: <div>This is tab two content</div>,
},
{
id: "tab3",
icon: "layers",
children: <div>Content for Tab 3 </div>,
},
];

export const Default: Story = {
render: arg => (
<div style={{ width: "500px", marginTop: "10px", marginLeft: "10px" }}>
<Tabs {...arg} />
</div>
),
args: {
position: "top",
tabs: tabsItem,
},
};

export const LeftSideTabs: Story = {
render: arg => (
<div style={{ width: "500px" }}>
<Tabs {...arg} />
</div>
),
args: {
position: "left",
tabs: tabsItem,
tabStyle: "separated",
},
};

export const IconTabs: Story = {
render: arg => (
<div style={{ width: "500px", height: "100vh" }}>
<Tabs {...arg} />
</div>
),
args: {
position: "left",
tabs: tabsIcons,
},
};
102 changes: 102 additions & 0 deletions web/src/beta/lib/reearth-ui/components/Tabs/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { FC, ReactNode, useMemo } from "react";

import { Icon, IconName, Typography } from "@reearth/beta/lib/reearth-ui";
import { styled, useTheme } from "@reearth/services/theme";

export type TabItems = {
id: string;
name?: string;
icon?: IconName;
children?: ReactNode;
};

export type TabsProps = {
tabs: TabItems[];
position?: "top" | "left";
tabStyle?: "normal" | "separated";
activeTab?: string;
onChange?: (tab: string) => void;
};

export const Tabs: FC<TabsProps> = ({
tabs,
position = "top",
tabStyle = "normal",
activeTab,
onChange,
}) => {
const theme = useTheme();
const selectedTabItem = useMemo(() => {
return tabs.find(({ id }) => id === activeTab);
}, [activeTab, tabs]);

return (
<Wrapper position={position}>
<TabsMenu position={position} tabStyle={tabStyle}>
{tabs.map(({ id, icon, name }) => (
<Tab
key={id}
onClick={() => onChange?.(id)}
selected={id === activeTab}
position={position}
tabStyle={tabStyle}>
{icon && (
<Icon
icon={icon}
color={id === activeTab ? theme.content.main : theme.content.weak}
/>
)}
{name && (
<Typography
size="body"
weight="regular"
color={id === activeTab ? theme.content.main : theme.content.weak}>
{name}
</Typography>
)}
</Tab>
))}
</TabsMenu>
<Content>{selectedTabItem ? selectedTabItem.children : null}</Content>
</Wrapper>
);
};

const Wrapper = styled("div")<{ position?: "top" | "left" }>(({ position, theme }) => ({
display: "flex",
flexFlow: position === "top" ? "column nowrap" : "row nowrap",
background: theme.bg[1],
height: "100%",
}));

const TabsMenu = styled("div")<{ position?: "top" | "left"; tabStyle?: "normal" | "separated" }>(
({ position, tabStyle, theme }) => ({
display: "flex",
flexFlow: position === "top" ? "row nowrap" : "column nowrap",
background: theme.bg[0],
padding: tabStyle === "normal" ? " " : theme.spacing.large,
gap: theme.spacing.micro,
}),
);

const Tab = styled("div")<{
position?: "top" | "left";
selected: boolean;
tabStyle?: "normal" | "separated";
}>(({ position, selected, tabStyle, theme }) => ({
display: "flex",
alignItems: "center",
cursor: "pointer",
gap: theme.spacing.smallest,
background: selected ? theme.bg[1] : "inherit",
padding: `${theme.spacing.smallest}px ${theme.spacing.small}px`,
borderRadius: tabStyle === "separated" ? theme.radius.small : 0,
borderTopRightRadius: position === "top" && tabStyle === "normal" ? theme.radius.small : "",
borderTopLeftRadius: tabStyle === "normal" ? theme.radius.small : "",
borderBottomLeftRadius: position === "left" && tabStyle === "normal" ? theme.radius.small : "",
}));

const Content = styled("div")(({ theme }) => ({
padding: theme.spacing.normal,
height: "auto",
}));

0 comments on commit 2f0c3a8

Please sign in to comment.