Skip to content
This repository has been archived by the owner on Feb 18, 2024. It is now read-only.

Commit

Permalink
Create a HeaderItem component with Dropdown
Browse files Browse the repository at this point in the history
  • Loading branch information
quentinguidee committed Nov 25, 2023
1 parent 6e72377 commit e86f454
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 1 deletion.
45 changes: 45 additions & 0 deletions lib/components/Dropdown/Dropdown.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@use "../../styles/colors"
@use "../../styles/dimensions"

.dropdown
display: none
position: absolute
background-color: colors.$bg-secondary
border-radius: dimensions.$border-radius
border: 1px solid colors.$bg-tertiary
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.2)
top: 100%
right: 0
padding: 4px
min-width: 150px

&-item
display: flex
flex-direction: row
align-items: center
gap: 8px
padding: 12px 18px
color: colors.$fg-primary
text-decoration: none
cursor: pointer
border-radius: calc(dimensions.$border-radius - 4px)

&:hover
color: colors.$bg-accent-hover
background-color: colors.$bg-tertiary-hover

&-red
color: colors.$red

&:hover
color: colors.$red-hover

& .material-icon
font-size: 20px
margin: -4px 0
margin-left: -4px

&-opened
display: block
z-index: 100
animation: dropdown 0.1s ease-in-out
55 changes: 55 additions & 0 deletions lib/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import cx from "classnames";
import "./Dropdown.sass";
import { Fragment, HTMLProps } from "react";
import { Overlay } from "../Overlay/Overlay.tsx";
import { MaterialIcon } from "../MaterialIcon/MaterialIcon.tsx";

export type DropdownProps = HTMLProps<HTMLDivElement> & {
opened?: boolean;
onClose?: () => void;
};

export function Dropdown(props: Readonly<DropdownProps>) {
const { className, opened, onClose, ...others } = props;

return (
<Fragment>
<div
className={cx(
"dropdown",
{
"dropdown-opened": opened,
},
className,
)}
{...others}
/>
<Overlay show={opened} onClick={onClose} />
</Fragment>
);
}

export type DropdownItemProps = HTMLProps<HTMLDivElement> & {
icon?: string;
red?: boolean;
};

export function DropdownItem(props: Readonly<DropdownItemProps>) {
const { className, children, icon, red, ...others } = props;

return (
<div
className={cx(
"dropdown-item",
{
"dropdown-item-red": red,
},
className,
)}
{...others}
>
{icon && <MaterialIcon icon={icon} />}
{children}
</div>
);
}
17 changes: 17 additions & 0 deletions lib/components/Header/Header.sass
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,20 @@

& h1
padding: 10px 0

&-item
display: flex
flex-direction: row
align-items: center
gap: 8px
color: colors.$fg-primary
text-decoration: none
cursor: pointer
position: relative
padding: 10px 0

&:hover
color: colors.$bg-accent-hover

&-opened
z-index: 100
15 changes: 14 additions & 1 deletion lib/components/Header/Header.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { LinkProps } from "../Link/Link.tsx";
import { HTMLProps } from "react";
import { MaterialIcon } from "../MaterialIcon/MaterialIcon.tsx";
import { ProfilePicture } from "../ProfilePicture/ProfilePicture.tsx";
import { HeaderItem } from "./HeaderItem.tsx";
import { DropdownItem } from "../Dropdown/Dropdown.tsx";

const meta: Meta<typeof Header> = {
title: "Components/Header",
Expand All @@ -26,13 +28,24 @@ const linkBackProps: LinkProps<HTMLProps<HTMLAnchorElement>> = {
href: "#",
};

const items = (
<DropdownItem icon="logout" red>
Logout
</DropdownItem>
);

export const Normal: Story = {
args: {
appName: "Vertex App",
linkBack: linkBackProps,
linkLogo: linkLogoProps,
leading: <MaterialIcon icon="arrow_back" />,
trailing: <ProfilePicture size={36} />,
trailing: (
<HeaderItem items={items}>
Arra
<ProfilePicture size={36} />
</HeaderItem>
),
},
render: (props) => (
<Header {...props}>
Expand Down
37 changes: 37 additions & 0 deletions lib/components/Header/HeaderItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import cx from "classnames";
import { HTMLProps, ReactNode, useState } from "react";
import { Dropdown } from "../Dropdown/Dropdown.tsx";

export type HeaderItemProps = HTMLProps<HTMLDivElement> & {
items?: ReactNode;
};

export function HeaderItem(props: Readonly<HeaderItemProps>) {
const { className, children, items, ...others } = props;

const [opened, setOpened] = useState(false);

const onClick = () => setOpened((o: boolean) => !o);
const close = () => setOpened(false);

return (
<div
className={cx(
"header-item",
{
"header-item-opened": opened,
},
className,
)}
onClick={onClick}
{...others}
>
{children}
{items !== undefined && (
<Dropdown opened={opened} onClose={close}>
{items}
</Dropdown>
)}
</div>
);
}
13 changes: 13 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import { Box, BoxProps, BoxType } from "./components/Box/Box";
import { Button, ButtonProps } from "./components/Button/Button";
import { Checkbox, CheckboxProps } from "./components/Checkbox/Checkbox";
import { Code, CodeProps } from "./components/Code/Code";
import {
Dropdown,
DropdownItem,
DropdownItemProps,
DropdownProps,
} from "./components/Dropdown/Dropdown";
import { Header, HeaderProps } from "./components/Header/Header";
import { HeaderItem, HeaderItemProps } from "./components/Header/HeaderItem";
import {
InlineCode,
InlineCodeProps,
Expand Down Expand Up @@ -65,7 +72,10 @@ export type {
ButtonProps,
CheckboxProps,
CodeProps,
DropdownProps,
DropdownItemProps,
HeaderProps,
HeaderItemProps,
InlineCodeProps,
InputProps,
LayoutProps,
Expand Down Expand Up @@ -94,7 +104,10 @@ export {
Button,
Checkbox,
Code,
Dropdown,
DropdownItem,
Header,
HeaderItem,
PageContext,
PageProvider,
ProfilePicture,
Expand Down

0 comments on commit e86f454

Please sign in to comment.