Module:ElementHubNavigation
Appearance
Documentation for this module may be created at Module:ElementHubNavigation/doc
--[[
* Name: ElementHubNavigation
* Version: 2.1
* Author: Mark W. Datysgeld
* Description: Hub navigation module for Main Page with responsive design
* Notes: v2.1 fixes MediaWiki <pre> tag wrapping by removing leading whitespace
* Pattern: MediaWiki table syntax + string concatenation (like ElementNavigation)
* Icon Data: CSS backgrounds defined in Hubs.css - see :root custom properties
]]
local p = {}
-- Hub configuration with CSS background icon identifiers and submenu items
-- Icon backgrounds defined in Hubs.css :root custom properties (--icon-*)
-- Submenu URLs cross-reference: Special:Ask queries and Category pages
local hubs = {
{
id = 'nations',
label = 'Nations',
url = 'Hub:Nations',
icon = 'globe',
submenu = {
{ label = 'All Nations', url = 'Special:Ask/-5B-5BCategory:Countries-5D-5D' },
{ label = 'ccNSO Members', url = 'Category:ccNSO_Members' },
{ label = 'GAC Representatives', url = 'Category:GAC' },
{ label = 'Regional Groups', url = 'Category:Regional_Internet_Registries' }
}
},
{
id = 'people',
label = 'People',
url = 'Hub:People',
icon = 'user',
submenu = {
{ label = 'All People', url = 'Special:Ask/-5B-5BCategory:People-5D-5D' },
{ label = 'ICANN Board', url = 'Category:ICANN_Board' },
{ label = 'Executives', url = 'Category:Executives' },
{ label = 'Authors', url = 'Category:Authors' }
}
},
{
id = 'organizations',
label = 'Organizations',
url = 'Hub:Organizations',
icon = 'building',
submenu = {
{ label = 'All Organizations', url = 'Special:Ask/-5B-5BCategory:Organizations-5D-5D' },
{ label = 'Supporting Organizations', url = 'Category:Supporting_Organizations' },
{ label = 'Advisory Committees', url = 'Category:Advisory_Committees' },
{ label = 'Registries', url = 'Category:Registries' }
}
},
{
id = 'events',
label = 'Events',
url = 'Hub:Events',
icon = 'calendar',
submenu = {
{ label = 'All Events', url = 'Special:Ask/-5B-5BCategory:Events-5D-5D' },
{ label = 'ICANN Meetings', url = 'Category:ICANN_Meetings' },
{ label = 'Regional Events', url = 'Category:Regional_Events' },
{ label = 'Upcoming', url = 'Special:Ask/-5B-5BHas-20start-20date::-3E{{CURRENTTIMESTAMP}}-5D-5D' }
}
},
{
id = 'topics',
label = 'Topics',
url = 'Hub:Topics',
icon = 'layers',
submenu = {
{ label = 'All Topics', url = 'Special:Ask/-5B-5BCategory:Topics-5D-5D' },
{ label = 'DNS', url = 'Category:DNS' },
{ label = 'Policy', url = 'Category:Policy' },
{ label = 'Technical', url = 'Category:Technical' }
}
}
}
-- Generate submenu HTML from submenu items
local function generateSubmenu(submenu)
if not submenu or #submenu == 0 then
return ''
end
local items = {}
for _, item in ipairs(submenu) do
-- Generate wikilink: [[url|label]] (no leading whitespace to prevent <pre> wrapping)
table.insert(items, string.format(
'<div class="hub-submenu__item">[[%s|%s]]</div>',
item.url,
item.label
))
end
return string.format(
'<div class="hub-item__submenu" hidden>%s</div>',
table.concat(items, '')
)
end
-- Generate a single hub item with expandable structure
local function generateHubItem(hub)
-- Icon as CSS background via data-icon attribute
-- CSS: .hub-icon[data-icon="globe"] { background-image: var(--icon-globe); }
local iconHtml = string.format('<span class="hub-icon" data-icon="%s" aria-hidden="true"></span>', hub.icon)
-- Generate submenu markup
local submenuHtml = generateSubmenu(hub.submenu)
-- Hub item with expandable structure (no leading whitespace to prevent <pre> wrapping)
-- data-hub: identifier for JS targeting
-- data-state: collapsed/expanded state for CSS animations
return string.format(
'<div class="hub-item" data-hub="%s" data-state="collapsed">' ..
'<div class="hub-item__trigger">' ..
'%s' ..
'<span class="hub-label">[[%s|%s]]</span>' ..
'</div>%s' ..
'</div>',
hub.id,
iconHtml,
hub.url,
hub.label,
submenuHtml
)
end
-- Main render function
function p.render(frame)
-- Generate all hub items
local hubItems = {}
for i, hub in ipairs(hubs) do
hubItems[i] = generateHubItem(hub)
end
-- Build complete output using MediaWiki table syntax + HTML
-- data-active-hub: tracks which hub is expanded (for CSS sibling effects)
-- hub-drawer-overlay: dimmed background for mobile drawer
local output = {
'{| class="hub-nav-table"',
'|- class="hub-nav-row"',
'| colspan="2" |',
'<div id="hub" class="hub-navigation" role="navigation" aria-label="Hub Navigation" data-active-hub="">',
' <div class="hub-bar">',
table.concat(hubItems, '\n'),
' </div>',
' <div class="hub-drawer-overlay" hidden></div>',
'</div>',
'<div id="hub-spacer" aria-hidden="true"></div>',
'|}'
}
return table.concat(output, '\n')
end
return p