@govbr-ds/webcomponents
Version:
Biblioteca de Web Components baseado no GovBR-DS
147 lines (120 loc) • 4.17 kB
JavaScript
// MENU gerado automaticamente (preenchido via menu-index.json)
let MENU_ITEMS = []
// Expõe referências no escopo global para integração com pageLoader.js
window.MENU_ITEMS = MENU_ITEMS
const MENU_BODY = document.querySelector('.menu-body')
window.MENU_BODY = MENU_BODY
const MENU_FILTER = document.getElementById('menu-filter')
const CLEAR_MENU_FILTER = document.getElementById('clear-menu-filter')
const menuButton = document.getElementById('menu-button')
const responsiveMenuButton = document.getElementById('responsive-menu-button')
const menuElement = document.getElementById('main-navigation')
const iconElement = menuButton.querySelector('i')
async function loadMenuItems() {
const baseUrl = getBaseUrl()
try {
const res = await fetch(`${baseUrl}/assets/menu-index.json`, { cache: 'no-cache' })
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const items = await res.json()
if (Array.isArray(items)) {
MENU_ITEMS = items
window.MENU_ITEMS = MENU_ITEMS
} else {
console.warn('menu-index.json inválido, esperado um array')
MENU_ITEMS = []
}
} catch (err) {
console.warn('Falha ao carregar menu-index.json, usando menu vazio.', err)
MENU_ITEMS = []
}
}
function setLinks() {
const baseUrl = getBaseUrl()
MENU_ITEMS.sort(compareByNames).forEach((page) => {
const link = document.createElement('a')
link.href = `${baseUrl}/${page.path}`
link.className = 'menu-item br-link'
link.textContent = page.name
link.addEventListener('click', (event) => {
event.preventDefault()
if (link.classList.contains('active')) {
return
}
removeAllActiveClasses()
link.classList.add('active')
loadPage(page.path, page.files)
window.history.pushState({}, '', `${baseUrl}/${page.path}`)
if (window.innerWidth <= 575) {
toggleMenu()
}
})
MENU_BODY.appendChild(link)
})
const divider = document.createElement('div')
// Garante que o body do menu esteja acessível globalmente após montar os links
window.MENU_BODY = MENU_BODY
}
function filterMenu() {
const filterValue = MENU_FILTER.value.toLowerCase()
const menuItems = MENU_BODY.querySelectorAll('.menu-item')
menuItems.forEach((item) => {
if (item.textContent.toLowerCase().includes(filterValue)) {
item.style.display = ''
} else {
item.style.display = 'none'
}
})
CLEAR_MENU_FILTER.style.display = filterValue ? 'block' : 'none'
}
function clearInput() {
MENU_FILTER.value = ''
filterMenu()
}
window.addEventListener('load', async () => {
await loadMenuItems()
setLinks()
// O roteador será iniciado pelo pageLoader via bootstrapRouting
menuButton.addEventListener('click', toggleMenu)
responsiveMenuButton.addEventListener('click', toggleMenu)
const mediaQuery = window.matchMedia('(min-width: 576px)')
mediaQuery.addEventListener('change', handleMediaChange)
function handleMediaChange(event) {
if (event.matches && responsiveMenuButton) responsiveMenuButton.style.display = 'none'
if (!event.matches && responsiveMenuButton) responsiveMenuButton.style.display = ''
}
handleMediaChange(mediaQuery)
MENU_FILTER.addEventListener('input', filterMenu)
CLEAR_MENU_FILTER.addEventListener('click', clearInput)
// Garante estado inicial do body conforme o menu
syncBodyMenuState()
})
function removeAllActiveClasses() {
const menuItems = document.querySelectorAll('.menu-item')
menuItems.forEach((item) => {
item.classList.remove('active')
})
}
function toggleMenu() {
menuElement.classList.toggle('active')
if (menuElement.classList.contains('active')) {
iconElement.classList.remove('fa-bars')
iconElement.classList.add('fa-times')
} else {
iconElement.classList.add('fa-bars')
iconElement.classList.remove('fa-times')
}
syncBodyMenuState()
}
function compareByNames(a, b) {
if (a.name < b.name) {
return -1
}
if (a.name > b.name) {
return 1
}
return 0
}
function syncBodyMenuState() {
const isOpen = menuElement.classList.contains('active')
document.body.classList.toggle('menu-open', isOpen)
}