Module:SocialMedia

Revision as of 05:24, 12 April 2025 by MarkWD (talk | contribs) (// via Wikitext Extension for VSCode)

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

-- Module:SocialMedia
-- Reusable social media component meant to be called from other modules

-- ###############################################################
-- Currently supported platforms are:
-- 🪝Facebook, Github, Instagram, LinkedIn, Telegram, Threads, TikTok, X/Twitter, Youtube🪝
-- (UPDATE THE LIST BETWEEN THE HOOK EMOJIS AS PLATFORMS GET ADDED OR REMOVED)
-- ###############################################################

local sf = {}

-- This section defines the social platforms; can be added or deleted without consequence
-- param = handle for the platform; for "x", we also accept "twitter" for legacy purposes
-- icon  = wiki file for the icon
-- prefix = URL prefix
-- label  = used for alt text/screen readers
local socialPlatforms = {
    {
        param  = "facebook",
        icon   = "File:SocialFacebookIcon.svg",
        prefix = "https://www.facebook.com/",
        label  = "Facebook"
    },
    {
        param  = "instagram",
        icon   = "File:SocialInstagramIcon.svg",
        prefix = "https://www.instagram.com/",
        label  = "Instagram"
    },
    {
        param  = "linkedin",
        icon   = "File:SocialLinkedInIcon.svg",
        prefix = "https://www.linkedin.com/in/",
        label  = "LinkedIn"
    },
    {
        param  = "telegram",
        icon   = "File:SocialTelegramIcon.svg",
        prefix = "https://t.me/",
        label  = "Telegram"
    },
    {
        param  = "threads",
        icon   = "File:SocialThreadsIcon.svg",
        prefix = "https://www.threads.net/@",
        label  = "Threads"
    },
    {
        param  = "tiktok",
        icon   = "File:SocialTikTokIcon.svg",
        prefix = "https://www.tiktok.com/@",
        label  = "TikTok"
    },
    {
        param  = { "x", "twitter" },
        icon   = "File:SocialXIcon.svg",
        prefix = "https://x.com/",
        label  = "X (Twitter)"
    },
    {
        param  = "youtube",
        icon   = "File:SocialYouTubeIcon.svg",
        prefix = "https://www.youtube.com/@",
        label  = "YouTube"
    },
    {
        param  = "github",
        icon   = "File:SocialGithub.svg",
        prefix = "https://github.com/",
        label  = "Github"
    },
}

-- Helper to find the first non-empty user handle from a param or table of params
local function getUserHandle(args, param)
    local handle
    if type(param) == "string" then
        handle = args[param]
    else
        for _, alias in ipairs(param) do
            handle = args[alias]
            if handle and handle ~= "" then break end
        end
    end
    if handle then
        return mw.text.trim(handle)
    end
    return nil
end

-- Build a clickable icon link (24px) with alt text for accessibility: [[File:Name.svg|24px|alt=ALT_TEXT|link=URL]]
local function buildIconLink(iconFile, altText, url)
    return string.format("[[%s|24px|alt=%s|link=%s]]", iconFile, altText, url)
end

-- Build a single table row with colspan=2, containing a flex container for icons
local function buildSocialRow(icons)
    local iconMarkup = table.concat({
        '<div class="social-icons external-social" style="display: flex; flex-wrap: wrap; gap: 1em; margin-top: 0.2em; justify-content: center;">',
            table.concat(icons, ""),
        '</div>'
    }, "\n")
    
    return table.concat({
        "|-",
        '| colspan="2" |',
        iconMarkup
    }, "\n")
end

-- Main render function, takes a table of arguments (handles), returns wiki markup with social icons
function sf.render(args)
    -- Early return if args is empty or nil
    if not args or next(args) == nil then
        return ""
    end
    
    -- Pre-allocate icons table based on maximum possible size (number of platforms)
    local icons = {}
    icons[#socialPlatforms] = nil  -- Pre-allocate table to avoid reallocation
    local iconCount = 0

    for _, platform in ipairs(socialPlatforms) do
        local handle = getUserHandle(args, platform.param)
        if handle and handle ~= "" then
            local url = platform.prefix .. handle
            local iconLink = buildIconLink(platform.icon, platform.label, url)
            iconCount = iconCount + 1
            icons[iconCount] = iconLink  -- Direct index assignment is faster than table.insert
        end
    end

    -- If no handles were provided, return nothing.
    if #icons == 0 then
        return ""
    end

    -- Return a row that fits nicely in the template, with a flex container for icons
    return buildSocialRow(icons)
end

return sf