Module:ElementHubNavigation: Difference between revisions
// via Wikitext Extension for VSCode |
// via Wikitext Extension for VSCode |
||
| Line 11: | Line 11: | ||
local p = {} | local p = {} | ||
-- Hub configuration with CSS background icon identifiers | -- Hub configuration with CSS background icon identifiers and submenu items | ||
-- Icon backgrounds defined in Hubs.css :root custom properties (--icon-*) | -- Icon backgrounds defined in Hubs.css :root custom properties (--icon-*) | ||
-- Submenu URLs cross-reference: Special:Ask queries and Category pages | |||
local hubs = { | local hubs = { | ||
{ label = 'Nations', url = 'Hub:Nations', icon = 'globe' }, | { | ||
{ label = 'People', url = 'Hub:People', icon = 'user' }, | id = 'nations', | ||
{ label = 'Organizations', url = 'Hub:Organizations', icon = 'building' }, | label = 'Nations', | ||
{ label = 'Events', url = 'Hub:Events', icon = 'calendar' }, | url = 'Hub:Nations', | ||
{ label = 'Topics', url = 'Hub:Topics', icon = 'layers' } | 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 a single hub | -- Generate submenu HTML from submenu items | ||
local function | 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]] | |||
table.insert(items, string.format( | |||
' <div class="hub-submenu__item">[[%s|%s]]</div>', | |||
item.url, | |||
item.label | |||
)) | |||
end | |||
return string.format( | |||
'\n <div class="hub-item__submenu" hidden>\n%s\n </div>', | |||
table.concat(items, '\n') | |||
) | |||
end | |||
-- Generate a single hub item with expandable structure | |||
local function generateHubItem(hub) | |||
-- Icon as CSS background via data-icon attribute | -- Icon as CSS background via data-icon attribute | ||
-- CSS: .hub-icon[data-icon="globe"] { background-image: var(--icon-globe); } | -- 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) | 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 | |||
-- data-hub: identifier for JS targeting | |||
-- data-state: collapsed/expanded state for CSS animations | |||
return string.format( | return string.format( | ||
'< | ' <div class="hub-item" data-hub="%s" data-state="collapsed">\n' .. | ||
' <div class="hub-item__trigger">\n' .. | |||
' %s\n' .. | |||
' <span class="hub-label">[[%s|%s]]</span>\n' .. | |||
' </div>%s\n' .. | |||
' </div>', | |||
hub.id, | |||
iconHtml, | iconHtml, | ||
hub.url, | hub.url, | ||
hub.label | hub.label, | ||
submenuHtml | |||
) | ) | ||
end | end | ||
| Line 37: | Line 128: | ||
-- Main render function | -- Main render function | ||
function p.render(frame) | function p.render(frame) | ||
-- Generate all hub | -- Generate all hub items | ||
local | local hubItems = {} | ||
for i, hub in ipairs(hubs) do | for i, hub in ipairs(hubs) do | ||
hubItems[i] = generateHubItem(hub) | |||
end | end | ||
-- Build complete output using MediaWiki table syntax + HTML | -- 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 = { | local output = { | ||
'{| class="hub-nav-table"', | '{| class="hub-nav-table"', | ||
'|- class="hub-nav-row"', | '|- class="hub-nav-row"', | ||
'| colspan="2" |', | '| colspan="2" |', | ||
'<div id="hub" class=" | '<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>', | ||
'<div id="hub-spacer" aria-hidden="true"></div>', | '<div id="hub-spacer" aria-hidden="true"></div>', | ||