Skip to content

Commit

Permalink
chore(web): TabsMenu for switching between tabs (#631)
Browse files Browse the repository at this point in the history
Co-authored-by: KaWaite <34051327+KaWaite@users.noreply.github.com>
  • Loading branch information
jashanbhullar and KaWaite committed Aug 22, 2023
1 parent d3335c9 commit 42ad685
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 0 deletions.
95 changes: 95 additions & 0 deletions web/src/beta/components/TabMenu/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { useArgs } from "@storybook/preview-api";
import { Meta, StoryObj } from "@storybook/react";
import { ReactNode, CSSProperties } from "react";

import Button from "@reearth/beta/components/Button";
import Resizable from "@reearth/beta/components/Resizable";
import Text from "@reearth/beta/components/Text";
import { styled } from "@reearth/services/theme";

import TabMenu, { Props } from "./index";

export default {
component: TabMenu,
} as Meta;

type Story = StoryObj<typeof TabMenu>;

const SampleComponent = () => {
return (
<div>
<Button margin="auto" buttonType="primary" text="Disabled Sample Button" disabled />
<JSONTag>
{JSON.stringify(
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [125.6, 10.1],
},
properties: {
name: "Dinagat Islands",
},
},
null,
2,
)}
</JSONTag>
</div>
);
};

const JSONTag = styled.pre`
background: ${({ theme }) => theme.bg[0]};
color: ${({ theme }) => theme.content.main};
border-radius: 10px;
padding: 10px;
`;

const Container: React.FC<{ children?: ReactNode; style?: CSSProperties }> = ({
children,
style,
}) => <div style={{ display: "flex", height: "100vh", ...style }}>{children}</div>;

const Pane = (
<div
style={{
flex: 1,
background: "#ffffff",
color: "black",
fontSize: 24,
textAlign: "center",
padding: "25vh 5rem",
}}>
{" "}
Whatever the main area holds. The tab panel works only when on the <b>left</b> with{" "}
<b>flex 100%</b>. Which is to do with <b>Resizable Component</b> and not the left panel.
</div>
);

export const Default: Story = (args: Props) => {
const [_, updateArgs] = useArgs();

const handleChange = (tab: string) => updateArgs({ selectedTab: tab });

return (
<Container style={{ flexDirection: "row" }}>
{Pane}
<Resizable direction="vertical" gutter="start" initialSize={500} minSize={200}>
<TabMenu {...args} onSelectedTabChange={handleChange} />
</Resizable>
</Container>
);
};

Default.args = {
tabs: [
{ id: "tab1", icon: "infobox", component: <SampleComponent /> },
{
id: "tab2",
icon: "dl",
component: <Text size="body">Tab 2. Can be any react component</Text>,
},
],
selectedTab: "tab1",
};
72 changes: 72 additions & 0 deletions web/src/beta/components/TabMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { FC, ReactNode, useMemo } from "react";

import Icon from "@reearth/beta/components/Icon";
import Icons from "@reearth/beta/components/Icon/icons";
import { styled, useTheme } from "@reearth/services/theme";

interface TabObject {
icon: keyof typeof Icons;
component: ReactNode;
id: string;
}

export type Props = {
tabs: TabObject[];
selectedTab: string;
onSelectedTabChange: (tab: string) => void;
};

const TabMenu: FC<Props> = ({ tabs, selectedTab, onSelectedTabChange }) => {
const theme = useTheme();

const selectedTabItem = useMemo(() => {
return tabs.find(({ id }) => id === selectedTab);
}, [selectedTab, tabs]);

return (
<Wrapper>
<Tabs>
{tabs.map(({ id, icon }) => (
<TabIconWrapper
key={id}
onClick={() => onSelectedTabChange(id)}
selected={id === selectedTab}>
<Icon icon={icon} alt={"Tab " + id} size={20} color={theme.content.main} />
</TabIconWrapper>
))}
</Tabs>
<MainArea>{selectedTabItem ? selectedTabItem.component : null}</MainArea>
</Wrapper>
);
};

export default TabMenu;

const Wrapper = styled.div`
display: grid;
border-radius: 10px;
height: 100%;
grid-template-columns: 28px 1fr;
background: ${({ theme }) => theme.bg[1]};
`;

const Tabs = styled.div`
grid-column: 1/2;
background: ${({ theme }) => theme.bg[0]};
`;

const TabIconWrapper = styled.div<{ selected: boolean }>`
padding: 8px 0;
width: 100%;
display: flex;
justify-content: center;
cursor: pointer;
background: ${props => (props.selected ? props.theme.bg[1] : "inherit")};
`;

const MainArea = styled.div`
grid-column: 2/-1;
display: block;
padding: 12px;
background: ${({ theme }) => theme.bg[1]};
`;

0 comments on commit 42ad685

Please sign in to comment.