Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
109 lines
2.7 KiB
TypeScript
109 lines
2.7 KiB
TypeScript
'use client'
|
|
|
|
import type { ComponentProps, ReactElement, ReactNode } from 'react'
|
|
|
|
import { Children, isValidElement } from 'react'
|
|
import { Tabs as HeroTabs } from '@heroui/react'
|
|
|
|
export interface TabsClassNames {
|
|
base?: string
|
|
tabList?: string
|
|
tab?: string
|
|
tabContent?: string
|
|
cursor?: string
|
|
panel?: string
|
|
tabWrapper?: string
|
|
}
|
|
|
|
export type TabsProps = Omit<ComponentProps<typeof HeroTabs>, 'children' | 'className' | 'variant'> & {
|
|
children?: ReactNode
|
|
className?: string
|
|
classNames?: TabsClassNames
|
|
color?: string
|
|
fullWidth?: boolean
|
|
placement?: string
|
|
size?: 'sm' | 'md' | 'lg'
|
|
variant?: 'solid' | 'bordered' | 'light' | 'underlined'
|
|
}
|
|
|
|
interface LegacyTabProps {
|
|
children?: ReactNode
|
|
title: ReactNode
|
|
}
|
|
|
|
export function Tab(_props: LegacyTabProps) {
|
|
return null
|
|
}
|
|
|
|
function getLegacyTabs(children: ReactNode): ReactElement<LegacyTabProps>[] {
|
|
return Children.toArray(children).filter((child): child is ReactElement<LegacyTabProps> => isValidElement<LegacyTabProps>(child))
|
|
}
|
|
|
|
function tabId(tab: ReactElement<LegacyTabProps>, index: number): string {
|
|
if (tab.key == null) return String(index)
|
|
|
|
const key = String(tab.key)
|
|
|
|
return key.startsWith('.$') ? key.slice(2) : key
|
|
}
|
|
|
|
export function Tabs({
|
|
children,
|
|
className,
|
|
classNames,
|
|
fullWidth,
|
|
size: _size,
|
|
color: _color,
|
|
placement: _placement,
|
|
variant,
|
|
...props
|
|
}: TabsProps) {
|
|
const tabs = getLegacyTabs(children)
|
|
const mappedVariant = variant === 'light' || variant === 'underlined' ? 'secondary' : 'primary'
|
|
|
|
return (
|
|
<HeroTabs
|
|
className={`${fullWidth ? 'w-full' : ''} ${classNames?.base ?? ''} ${className ?? ''}`.trim()}
|
|
variant={mappedVariant}
|
|
{...props}
|
|
>
|
|
<HeroTabs.ListContainer className={classNames?.tabWrapper}>
|
|
<HeroTabs.List
|
|
aria-label={props['aria-label']}
|
|
className={classNames?.tabList}
|
|
>
|
|
{tabs.map((tab, index) => {
|
|
const id = tabId(tab, index)
|
|
|
|
return (
|
|
<HeroTabs.Tab
|
|
key={id}
|
|
className={classNames?.tab}
|
|
id={id}
|
|
>
|
|
<span className={classNames?.tabContent}>{tab.props.title}</span>
|
|
<HeroTabs.Indicator className={classNames?.cursor} />
|
|
</HeroTabs.Tab>
|
|
)
|
|
})}
|
|
</HeroTabs.List>
|
|
</HeroTabs.ListContainer>
|
|
{tabs.map((tab, index) => {
|
|
if (tab.props.children === undefined) return null
|
|
|
|
const id = tabId(tab, index)
|
|
|
|
return (
|
|
<HeroTabs.Panel
|
|
key={id}
|
|
className={classNames?.panel}
|
|
id={id}
|
|
>
|
|
{tab.props.children}
|
|
</HeroTabs.Panel>
|
|
)
|
|
})}
|
|
</HeroTabs>
|
|
)
|
|
}
|