Module:ElementHubNavigation: Difference between revisions
// via Wikitext Extension for VSCode |
// via Wikitext Extension for VSCode |
||
| (6 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
--[[ | --[[ | ||
* Name: ElementHubNavigation | * Name: ElementHubNavigation | ||
* Version: 2.1 | |||
* Author: Mark W. Datysgeld | * Author: Mark W. Datysgeld | ||
* Description: Hub navigation module for Main Page | * Description: Hub navigation module for Main Page with responsive design | ||
* Notes: | * Notes: v2.1 fixes MediaWiki <pre> tag wrapping by removing leading whitespace | ||
* Pattern: MediaWiki table syntax + string concatenation (like ElementNavigation) | * Pattern: MediaWiki table syntax + string concatenation (like ElementNavigation) | ||
* Icon Data: CSS backgrounds defined in Hubs.css - see :root custom properties | |||
]] | ]] | ||
local p = {} | local p = {} | ||
-- Hub configuration | -- 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 = { | local hubs = { | ||
{ label = 'Nations', url = 'Hub:Nations' }, | { | ||
{ label = 'People', url = 'Hub:People' }, | id = 'nations', | ||
{ label = 'Organizations', url = 'Hub:Organizations' }, | label = 'Nations', | ||
{ label = 'Events', url = 'Hub:Events' }, | url = 'Hub:Nations', | ||
{ label = 'Topics', url = 'Hub:Topics' } | 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 | 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( | 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.url, | ||
hub.label | hub.label, | ||
submenuHtml | |||
) | ) | ||
end | end | ||
| Line 29: | 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>', | ||