Module:ElementHubNavigation

Revision as of 12:16, 28 October 2025 by MarkWD (talk | contribs) (// via Wikitext Extension for VSCode)

Documentation for this module may be created at Module:ElementHubNavigation/doc

--[[
* Name: ElementHubNavigation
* Author: Mark W. Datysgeld
* Description: Hub navigation module for Main Page with zero-CLS responsive design
* Notes: Single SSR block with data-URI icons; mobile sticky bottom bar; desktop inline grid
* Uses mw.html builder to prevent HTML escaping
]]

local p = {}

-- Icon data URIs (URL-encoded SVGs with currentColor for CSS theming)
local icons = {
    nations = 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22currentColor%22 stroke-width=%221.75%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22 aria-hidden=%22true%22%3E%3Ccircle cx=%2212%22 cy=%2212%22 r=%229%22/%3E%3Cpath d=%22M3 12h18%22/%3E%3Cpath d=%22M12 3c3.5 3.5 3.5 14.5 0 18M12 3c-3.5 3.5-3.5 14.5 0 18%22/%3E%3C/svg%3E',
    people = 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22currentColor%22 stroke-width=%221.75%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22 aria-hidden=%22true%22%3E%3Cpath d=%22M20 21a8 8 0 0 0-16 0%22/%3E%3Ccircle cx=%2212%22 cy=%227%22 r=%224%22/%3E%3C/svg%3E',
    organizations = 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22currentColor%22 stroke-width=%221.75%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22 aria-hidden=%22true%22%3E%3Crect x=%224%22 y=%223%22 width=%2216%22 height=%2218%22 rx=%221%22/%3E%3Cpath d=%22M9 7h6M9 11h6M9 15h6M12 21v-4%22/%3E%3C/svg%3E',
    events = 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22currentColor%22 stroke-width=%221.75%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22 aria-hidden=%22true%22%3E%3Crect x=%223%22 y=%225%22 width=%2218%22 height=%2216%22 rx=%222%22/%3E%3Cpath d=%22M16 3v4M8 3v4M3 9h18%22/%3E%3C/svg%3E',
    topics = 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22currentColor%22 stroke-width=%221.75%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22 aria-hidden=%22true%22%3E%3Cpath d=%22M12 3 3 8l9 5 9-5-9-5z%22/%3E%3Cpath d=%22m3 13 9 5 9-5%22/%3E%3C/svg%3E'
}

-- Hub configuration
local hubs = {
    { id = 'nations', label = 'Nations', url = 'Hub:Nations', icon = icons.nations },
    { id = 'people', label = 'People', url = 'Hub:People', icon = icons.people },
    { id = 'organizations', label = 'Organizations', url = 'Hub:Organizations', icon = icons.organizations },
    { id = 'events', label = 'Events', url = 'Hub:Events', icon = icons.events },
    { id = 'topics', label = 'Topics', url = 'Hub:Topics', icon = icons.topics }
}

-- Generate a single hub link item using mw.html
local function generateHubLink(hub)
    local li = mw.html.create('li'):addClass('cdx-hub__item')
    
    local a = li:tag('a')
        :attr('href', '/wiki/' .. hub.url)
        :addClass('cdx-hub__link')
        :attr('data-hub', hub.id)
    
    -- Icon span with img
    local iconSpan = a:tag('span'):addClass('cdx-hub__icon')
    iconSpan:tag('img')
        :attr('src', hub.icon)
        :attr('alt', '')
        :attr('width', '24')
        :attr('height', '24')
        :attr('aria-hidden', 'true')
    
    -- Label span
    a:tag('span')
        :addClass('cdx-hub__label')
        :wikitext(hub.label)
    
    return tostring(li)
end

-- Main render function
function p.render(frame)
    -- Create main hub container
    local container = mw.html.create('div')
        :attr('id', 'hub')
        :addClass('cdx-hub')
        :attr('role', 'navigation')
        :attr('aria-label', 'Hub Navigation')
    
    -- Create list
    local ul = container:tag('ul'):addClass('cdx-hub__list')
    
    -- Add hub links
    for _, hub in ipairs(hubs) do
        ul:wikitext(generateHubLink(hub))
    end
    
    -- Add empty panel for future use
    container:tag('div')
        :addClass('cdx-hub__panel')
        :attr('aria-hidden', 'true')
    
    -- Create spacer
    local spacer = mw.html.create('div')
        :attr('id', 'hub-spacer')
        :attr('aria-hidden', 'true')
    
    -- Wrap in MediaWiki table syntax for compatibility
    local output = {
        '{| class="hub-nav-table"',
        '|- class="hub-nav-row"',
        '| colspan="2" |',
        tostring(container),
        tostring(spacer),
        '|}'
    }
    
    return table.concat(output, '\n')
end

return p