Skip to content

Commit

Permalink
wip: form component
Browse files Browse the repository at this point in the history
  • Loading branch information
bouassaba committed Oct 30, 2024
1 parent dea1111 commit a05b753
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 59 deletions.
46 changes: 46 additions & 0 deletions src/components/form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Fragment, ReactElement } from 'react'
import { Divider, Spacer } from '@chakra-ui/react'
import cx from 'classnames'

export type FormProps = {
sections?: FormSection[]
}

export type FormSection = {
title: string
rows?: FormRow[]
}

export type FormRow = {
label: string
content?: ReactElement
}

export const Form = ({ sections }: FormProps) => (
<div className={cx('flex', 'flex-col', 'gap-0')}>
{sections?.map((section, sectionIndex) => (
<Fragment key={`section-${sectionIndex}`}>
<div className={cx('flex', 'flex-col', 'gap-1', 'py-1.5')}>
<span className={cx('font-bold')}>{section.title}</span>
{section.rows?.map((row, rowIndex) => (
<div
key={`row-${rowIndex}`}
className={cx(
'flex',
'flex-row',
'items-center',
'gap-1',
`h-[40px]`,
)}
>
<span>{row.label}</span>
<Spacer />
{row.content}
</div>
))}
</div>
{sectionIndex !== sections?.length - 1 ? <Divider /> : null}
</Fragment>
))}
</div>
)
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ export * from './auxiliary-drawer'
export * from './nav-bar'
export * from './search-bar'
export * from './account-menu'
export * from './form'
34 changes: 16 additions & 18 deletions src/components/nav-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { Link as ChakraLink } from '@chakra-ui/react'
import cx from 'classnames'

export type NavBarProps = {
items: NavItem[]
pathnameFn: () => string
navigateFn: (href: string) => void
items?: NavItem[]
pathnameFn?: () => string
navigateFn?: (href: string) => void
}

export type NavItem = {
Expand All @@ -17,30 +17,28 @@ export type NavItem = {
export const NavBar = ({ items, pathnameFn, navigateFn }: NavBarProps) => {
return (
<div className={cx('flex', 'flex-row', 'gap-1.5')}>
{items
? items.map((item, index) => (
<Item
key={index}
title={item.title}
href={item.href}
pathnameFn={pathnameFn}
navigateFn={navigateFn}
/>
))
: null}
{items?.map((item, index) => (
<Item
key={index}
title={item.title}
href={item.href}
pathnameFn={pathnameFn}
navigateFn={navigateFn}
/>
))}
</div>
)
}

type ItemProps = {
title: string
href: string
pathnameFn: () => string
navigateFn: (href: string) => void
pathnameFn?: () => string
navigateFn?: (href: string) => void
}

const Item = ({ title, href, pathnameFn, navigateFn }: ItemProps) => {
const pathname = pathnameFn()
const pathname = pathnameFn?.() ?? ''
const [isActive, setIsActive] = useState(false)

useEffect(() => {
Expand Down Expand Up @@ -77,7 +75,7 @@ const Item = ({ title, href, pathnameFn, navigateFn }: ItemProps) => {
'bg-transparent': !isActive,
},
)}
onClick={() => navigateFn(href)}
onClick={() => navigateFn?.(href)}
>
{title}
</ChakraLink>
Expand Down
2 changes: 1 addition & 1 deletion src/components/page-pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const PagePagination = ({
) : null}
{hasSizeSelector ? (
<Select defaultValue={size} onChange={handleSizeChange}>
{steps.map((step, index) => (
{steps?.map((step, index) => (
<option key={index} value={step.toString()}>
{step} items
</option>
Expand Down
32 changes: 15 additions & 17 deletions src/components/shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { Sidenav, SidenavItem } from './sidenav'

export type ShellProps = {
storage?: StorageOptions
logo: ReactElement
topBar: ReactElement
logo?: ReactElement
topBar?: ReactElement
items?: ShellItem[]
children?: ReactElement
onContentClick?: (event: MouseEvent) => void
pathnameFn: () => string
navigateFn: (href: string) => void
pathnameFn?: () => string
navigateFn?: (href: string) => void
}

export type ShellItem = {
Expand All @@ -33,19 +33,17 @@ export const Shell = ({
}: ShellProps) => (
<div className={cx('flex', 'flex-row', 'items-center', 'gap-0', 'h-full')}>
<Sidenav storage={storage} logo={logo} navigateFn={navigateFn}>
{items
? items.map((item, index) => (
<SidenavItem
key={index}
href={item.href}
icon={item.icon}
primaryText={item.primaryText}
secondaryText={item.secondaryText}
pathnameFn={pathnameFn}
navigateFn={navigateFn}
/>
))
: null}
{items?.map((item, index) => (
<SidenavItem
key={index}
href={item.href}
icon={item.icon}
primaryText={item.primaryText}
secondaryText={item.secondaryText}
pathnameFn={pathnameFn}
navigateFn={navigateFn}
/>
))}
</Sidenav>
<div
className={cx('flex', 'flex-col', 'items-center', 'h-full', 'w-full')}
Expand Down
8 changes: 4 additions & 4 deletions src/components/sidenav/sidenav-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export type SidenavItemProps = {
href: string
primaryText: string
secondaryText: string
pathnameFn: () => string
navigateFn: (href: string) => void
pathnameFn?: () => string
navigateFn?: (href: string) => void
}

export const SidenavItem = ({
Expand All @@ -20,7 +20,7 @@ export const SidenavItem = ({
pathnameFn,
navigateFn,
}: SidenavItemProps) => {
const pathname = pathnameFn()
const pathname = pathnameFn?.() ?? ''
const [isActive, setIsActive] = useState<boolean>()
const { isCollapsed } = useContext(SidenavContext)

Expand All @@ -39,7 +39,7 @@ export const SidenavItem = ({
<Link
title={isCollapsed ? `${primaryText}: ${secondaryText}` : secondaryText}
className={cx('w-full', 'no-underline')}
onClick={() => navigateFn(href)}
onClick={() => navigateFn?.(href)}
>
<Tooltip label={primaryText} isDisabled={!isCollapsed}>
<div
Expand Down
40 changes: 21 additions & 19 deletions src/components/sidenav/sidenav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type SidenavProps = {
logo?: ReactNode
storage?: StorageOptions
homeHref?: string
navigateFn: (href: string) => void
navigateFn?: (href: string) => void
}

export const Sidenav = ({
Expand Down Expand Up @@ -66,25 +66,27 @@ export const Sidenav = ({
'gap-0',
)}
>
<div
className={cx('flex', 'items-center', 'justify-center', 'h-[80px]')}
>
<Link onClick={() => navigateFn(homeHref ?? '/')}>
<div className={cx('flex', 'h-[40px]')}>
<div
className={cx(
'flex',
'items-center',
'justify-center',
'w-[40px]',
'h-[40px]',
)}
>
{logo}
{logo ? (
<div
className={cx('flex', 'items-center', 'justify-center', 'h-[80px]')}
>
<Link onClick={() => navigateFn?.(homeHref ?? '/')}>
<div className={cx('flex', 'h-[40px]')}>
<div
className={cx(
'flex',
'items-center',
'justify-center',
'w-[40px]',
'h-[40px]',
)}
>
{logo}
</div>
</div>
</div>
</Link>
</div>
</Link>
</div>
) : null}
<div
className={cx(
'flex',
Expand Down
91 changes: 91 additions & 0 deletions src/stories/components/form.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { IconButton, Switch } from '@chakra-ui/react'
// @ts-expect-error ignored
import { Form, IconEdit, IconDelete } from '@koupr/ui'
import { Meta, StoryObj } from '@storybook/react'
import cx from 'classnames'

const meta: Meta<typeof Form> = {
title: 'Components/Form',
component: Form,
}

export default meta
type Story = StoryObj<typeof Form>

export const Default: Story = {
args: {
sections: [
{
title: 'Basics',
rows: [
{
label: 'Full name',
content: (
<>
<span>Bruce Wayne</span>
<IconButton
icon={<IconEdit />}
className={cx('h-[40px]', 'w-[40px]')}
aria-label="Edit"
/>
</>
),
},
],
},
{
title: 'Credentials',
rows: [
{
label: 'Email',
content: (
<>
<span>bruce.wayne@koupr.com</span>
<IconButton
icon={<IconEdit />}
className={cx('h-[40px]', 'w-[40px]')}
aria-label="Edit"
/>
</>
),
},
{
label: 'Password',
content: (
<IconButton
icon={<IconEdit />}
className={cx('h-[40px]', 'w-[40px]')}
aria-label="Edit"
/>
),
},
],
},
{
title: 'Theme',
rows: [
{
label: 'Dark mode',
content: <Switch />,
},
],
},
{
title: 'Advanced',
rows: [
{
label: 'Delete account',
content: (
<IconButton
icon={<IconDelete />}
variant="solid"
colorScheme="red"
aria-label="Delete account"
/>
),
},
],
},
],
},
}

0 comments on commit a05b753

Please sign in to comment.