mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 13:17:00 +04:00
105 lines
4.0 KiB
Plaintext
105 lines
4.0 KiB
Plaintext
---
|
|
import Icon from '@ui/Icon.astro'
|
|
import NavbarMenuItem, { type Level2 } from './NavbarMenuItem.astro'
|
|
import menu from '@data/menu.json'
|
|
import menuSample from '@data/menu-sample.json'
|
|
|
|
interface Level1 {
|
|
'title': string
|
|
'title-long'?: string
|
|
'icon'?: string
|
|
'url'?: string
|
|
'badge'?: string
|
|
'active'?: boolean
|
|
'disabled'?: boolean
|
|
'right'?: boolean
|
|
'columns'?: number
|
|
/** section label rendered before this item (sidebar only, needs the `sections` prop) */
|
|
'section'?: string
|
|
'children'?: Record<string, Level2>
|
|
}
|
|
|
|
interface Props {
|
|
/** active menu entry, e.g. "dashboards.default" */
|
|
pageMenu?: string | undefined
|
|
sample?: boolean
|
|
hideIcons?: boolean
|
|
longTitles?: boolean
|
|
keepOpen?: boolean
|
|
autoOpen?: boolean
|
|
/** renders `section` fields from the menu data as group labels */
|
|
sections?: boolean
|
|
class?: string
|
|
}
|
|
|
|
const { pageMenu = '', sample = false, hideIcons = false, longTitles = false, keepOpen = false, autoOpen = false, sections = false, class: className } = Astro.props
|
|
|
|
const currentPage = pageMenu.split('.')
|
|
const items = Object.entries((sample ? menuSample : menu) as Record<string, Level1>)
|
|
|
|
// per-column = ceil(size / columns), break every per-column.
|
|
const chunk = <T,>(arr: T[], size: number): T[][] => {
|
|
const out: T[][] = []
|
|
for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size))
|
|
return out
|
|
}
|
|
---
|
|
|
|
<!-- BEGIN NAVBAR MENU -->
|
|
<ul class:list={['navbar-nav', className]}>
|
|
{
|
|
items.map(([key, item]) => {
|
|
const active = key === currentPage[0] || item.active
|
|
const hasChildren = !!item.children
|
|
const children = Object.entries(item.children ?? {})
|
|
const columns = item.columns ? chunk(children, Math.ceil(children.length / item.columns)) : null
|
|
const title = longTitles ? (item['title-long'] ?? item.title) : item.title
|
|
|
|
return (
|
|
<Fragment>
|
|
{sections && item.section && <li class="nav-section-title">{item.section}</li>}
|
|
<Fragment set:html={'<!-- BEGIN NAVBAR ITEM -->'} />
|
|
<li class:list={['nav-item', active && 'active', hasChildren && 'dropdown']}>
|
|
<a
|
|
class:list={['nav-link', hasChildren && 'dropdown-toggle', item.disabled && 'disabled']}
|
|
href={hasChildren ? '#' : `./${item.url}`}
|
|
data-bs-toggle={hasChildren ? 'dropdown' : undefined}
|
|
data-bs-auto-close={hasChildren ? (keepOpen ? 'false' : 'outside') : undefined}
|
|
role={hasChildren ? 'button' : undefined}
|
|
aria-haspopup={hasChildren ? 'true' : undefined}
|
|
aria-expanded={hasChildren ? (autoOpen && key === currentPage[0] ? 'true' : 'false') : undefined}
|
|
aria-current={active && !hasChildren ? 'page' : undefined}
|
|
>
|
|
{!hideIcons && <span class="nav-link-icon">{item.icon && <Icon name={item.icon} />}</span>}
|
|
|
|
<span class="nav-link-title">{title}</span>
|
|
|
|
{item.badge && <span class="badge badge-sm bg-red text-red-fg">{item.badge}</span>}
|
|
</a>
|
|
|
|
{hasChildren && (
|
|
<div class:list={['dropdown-menu', item.right && 'dropdown-menu-end', autoOpen && key === currentPage[0] && 'show']}>
|
|
{columns ? (
|
|
<div class="dropdown-menu-columns">
|
|
{columns.map((column) => (
|
|
<div class="dropdown-menu-column">
|
|
{column.map(([childKey, child]) => (
|
|
<NavbarMenuItem level1Key={key} itemKey={childKey} item={child} currentPage={currentPage} keepOpen={keepOpen} />
|
|
))}
|
|
</div>
|
|
))}
|
|
</div>
|
|
) : (
|
|
children.map(([childKey, child]) => <NavbarMenuItem level1Key={key} itemKey={childKey} item={child} currentPage={currentPage} keepOpen={keepOpen} />)
|
|
)}
|
|
</div>
|
|
)}
|
|
</li>
|
|
<Fragment set:html={'<!-- END NAVBAR ITEM -->'} />
|
|
</Fragment>
|
|
)
|
|
})
|
|
}
|
|
</ul>
|
|
<!-- END NAVBAR MENU -->
|