Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:Tournament: Difference between revisions

From eSportsAmaze
No edit summary
No edit summary
Line 18: Line 18:
     local formattedRest = rest:reverse():gsub("(%d%d)", "%1,"):reverse()
     local formattedRest = rest:reverse():gsub("(%d%d)", "%1,"):reverse()
     if formattedRest:sub(1, 1) == "," then formattedRest = formattedRest:sub(2) end
     if formattedRest:sub(1, 1) == "," then formattedRest = formattedRest:sub(2) end
     return currency .. " " .. formattedRest .. "," .. last3
     return '<span class="pz-prize">' .. currency .. " " .. formattedRest .. "," .. last3 .. '</span>'
end
end


Line 33: Line 33:
end
end


-- Helper: Theme Aware Logo (For Infobox)
-- Helper: Clean Title
local function getInfoboxLogo(pageName, image, imageDark)
local function getCleanTitle(pageLink)
    local lightFile = (image ~= "" and image) or (pageName .. '.png')
     if not pageLink then return "" end
      
     local title = mw.title.new(pageLink)
    -- Auto-detect dark if not provided
     if title then return title.subpageText end
    local darkFile = imageDark
     return pageLink
    if not darkFile or darkFile == "" then
        local ext = lightFile:match("^.+(%..+)$") or ".png"
        local name = lightFile:gsub("%..+$", "")
        darkFile = name .. "_dark" .. ext
    end
   
     local hasLight = mw.title.new('File:' .. lightFile).exists
    local hasDark = mw.title.new('File:' .. darkFile).exists
   
    local container = html.create('div'):addClass('fib-image')
   
    -- Light
    local lSpan = container:tag('span'):addClass('logo-lightmode')
     if hasLight then lSpan:wikitext('[[File:' .. lightFile .. '|250px]]') else lSpan:wikitext('[[File:Shield_team.png|150px]]') end
   
    -- Dark
    local dSpan = container:tag('span'):addClass('logo-darkmode')
    if hasDark then dSpan:wikitext('[[File:' .. darkFile .. '|250px]]') elseif hasLight then dSpan:wikitext('[[File:' .. lightFile .. '|250px]]') else dSpan:wikitext('[[File:Shield_team_dark.png|150px]]') end
   
     return tostring(container)
end
end


-- Helper: Social Icon Generator
-- Helper: Social Icon Generator (FIXED: Uses Wikitext Syntax)
local function getSocials(args)
local function getSocials(args)
     local container = html.create('div'):addClass('fib-socials')
     local container = html.create('div'):addClass('fib-socials')
Line 78: Line 58:
         if args[p.arg] and args[p.arg] ~= "" then
         if args[p.arg] and args[p.arg] ~= "" then
             hasSocials = true
             hasSocials = true
             container:tag('a')
             -- We use a span to wrap the icon inside the external link syntax
                :attr('href', args[p.arg])
            -- Syntax: https://www.flaticon.com/free-icons/span
                :addClass('fib-social-icon')
            container:wikitext('[' .. args[p.arg] .. ' <span class="fib-social-icon"><i class="' .. p.icon .. '"></i></span>]')
                :attr('target', '_blank')
                :wikitext('<i class="' .. p.icon .. '"></i>')
         end
         end
     end
     end
      
      
     if hasSocials then return tostring(container) else return "" end
     if hasSocials then return tostring(container) else return "" end
end
-- Helper: Theme Aware Logo (For Lists/Homepage)
local function getTourneyLogo(imageFile, darkImageFile)
    local container = html.create('div'):addClass('tr-event-logo')
    if imageFile and imageFile ~= "" then
        local darkFile = darkImageFile
        if not darkFile or darkFile == "" then
            local ext = imageFile:match("^.+(%..+)$") or ".png"
            local name = imageFile:gsub("%..+$", "")
            darkFile = name .. "_dark" .. ext
        end
        local hasDark = mw.title.new('File:' .. darkFile).exists
        container:tag('span'):addClass('logo-lightmode'):wikitext('[[File:' .. imageFile .. '|40px|link=]]')
        local dSpan = container:tag('span'):addClass('logo-darkmode')
        if hasDark then dSpan:wikitext('[[File:' .. darkFile .. '|40px|link=]]') else dSpan:wikitext('[[File:' .. imageFile .. '|40px|link=]]') end
    else
        container:wikitext('<i class="fa-solid fa-trophy" style="color:var(--text-muted); opacity:0.3;"></i>')
    end
    return tostring(container)
end
-- Helper: Theme Aware Logo (For Infobox)
local function getInfoboxLogo(pageName, image, imageDark)
    local lightFile = (image ~= "" and image) or (pageName .. '.png')
    local darkFile = imageDark
    if not darkFile or darkFile == "" then
        local ext = lightFile:match("^.+(%..+)$") or ".png"
        local name = lightFile:gsub("%..+$", "")
        darkFile = name .. "_dark" .. ext
    end
   
    local hasLight = mw.title.new('File:' .. lightFile).exists
    local hasDark = mw.title.new('File:' .. darkFile).exists
   
    local container = html.create('div'):addClass('fib-image')
    local lSpan = container:tag('span'):addClass('logo-lightmode')
    if hasLight then lSpan:wikitext('[[File:' .. lightFile .. '|250px]]') else lSpan:wikitext('[[File:Shield_team.png|150px]]') end
    local dSpan = container:tag('span'):addClass('logo-darkmode')
    if hasDark then dSpan:wikitext('[[File:' .. darkFile .. '|250px]]') elseif hasLight then dSpan:wikitext('[[File:' .. lightFile .. '|250px]]') else dSpan:wikitext('[[File:Shield_team_dark.png|150px]]') end
    return tostring(container)
end
end


-- ============================================================
-- ============================================================
-- MAIN 1: TOURNAMENT INFOBOX (Redesigned)
-- MAIN 1: TOURNAMENT INFOBOX
-- ============================================================
-- ============================================================
function p.infobox(frame)
function p.infobox(frame)
Line 96: Line 115:
     local page = args.name or mw.title.getCurrentTitle().text
     local page = args.name or mw.title.getCurrentTitle().text
     local cleanName = mw.title.getCurrentTitle().subpageText
     local cleanName = mw.title.getCurrentTitle().subpageText
   
     local prizeMoney = args.prize_pool or args.prizepool
     local prizeMoney = args.prize_pool or args.prizepool
      
      
    -- 1. STORE TO CARGO
     if mw.ext.cargo and mw.ext.cargo.store then
     if mw.ext.cargo and mw.ext.cargo.store then
         mw.ext.cargo.store('Tournaments', {
         mw.ext.cargo.store('Tournaments', {
Line 121: Line 138:
             next = args.next,
             next = args.next,
             image = args.image,
             image = args.image,
             image_dark = args.image_dark
             image_dark = args.image_dark,
            instagram = args.instagram,
            twitter = args.twitter,
            youtube = args.youtube,
            discord = args.discord,
            facebook = args.facebook,
            website = args.website
         })
         })
     end
     end


    -- 2. BUILD FLAT INFOBOX
     local root = html.create('div'):addClass('flat-infobox')
     local root = html.create('div'):addClass('flat-infobox')
      
      
    -- A. Header & Logo
     local header = root:tag('div'):addClass('fib-header')
     local header = root:tag('div'):addClass('fib-header')
     header:tag('div'):addClass('fib-title'):wikitext(args.name or cleanName)
     header:tag('div'):addClass('fib-title'):wikitext(args.name or cleanName)
    header:wikitext(getInfoboxLogo(page, args.image, args.image_dark))
      
      
     -- B. Key Stats Grid (Row 1: Tier | Type)
     -- Logo comes AFTER title in the container, but visual order handled by DOM flow
    root:wikitext(getInfoboxLogo(page, args.image, args.image_dark))
   
     local grid1 = root:tag('div'):addClass('fib-grid')
     local grid1 = root:tag('div'):addClass('fib-grid')
     grid1:tag('div'):addClass('fib-cell')
     grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Event Tier'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.tier or 'Unranked'):done()
        :tag('div'):addClass('fib-label-sm'):wikitext('Event Tier'):done()
     grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Type'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.type or 'Online'):done()
        :tag('div'):addClass('fib-value-sm'):wikitext(args.tier or 'Unranked'):done()
   
     grid1:tag('div'):addClass('fib-cell')
        :tag('div'):addClass('fib-label-sm'):wikitext('Type'):done()
        :tag('div'):addClass('fib-value-sm'):wikitext(args.type or 'Online'):done()
          
          
    -- C. Key Stats Grid (Row 2: Mode | Location)
     local grid2 = root:tag('div'):addClass('fib-grid')
     local grid2 = root:tag('div'):addClass('fib-grid')
     grid2:tag('div'):addClass('fib-cell')
     grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Mode'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.mode or 'TBD'):done()
        :tag('div'):addClass('fib-label-sm'):wikitext('Mode'):done()
     grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Location'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.location or 'India'):done()
        :tag('div'):addClass('fib-value-sm'):wikitext(args.mode or 'TBD'):done()
   
     grid2:tag('div'):addClass('fib-cell')
        :tag('div'):addClass('fib-label-sm'):wikitext('Location'):done()
        :tag('div'):addClass('fib-value-sm'):wikitext(args.location or 'India'):done()
      
      
    -- D. Prize Pool Section
     if prizeMoney then
     if prizeMoney then
         root:tag('div'):addClass('fib-prize')
         root:tag('div'):addClass('fib-prize')
Line 160: Line 170:
     end
     end
      
      
    -- E. Detailed List
     local list = root:tag('div'):addClass('fib-list')
     local list = root:tag('div'):addClass('fib-list')
   
     local function addRow(label, value)
     local function addRow(label, value)
         if value and value ~= "" then
         if value and value ~= "" then
             list:tag('div'):addClass('fib-row')
             list:tag('div'):addClass('fib-row'):tag('div'):addClass('fib-label'):wikitext(label):done():tag('div'):addClass('fib-data'):wikitext(value):done()
                :tag('div'):addClass('fib-label'):wikitext(label):done()
                :tag('div'):addClass('fib-data'):wikitext(value):done()
         end
         end
     end
     end
Line 177: Line 183:
     addRow('Dates', formatDateRange(args.start_date, args.end_date))
     addRow('Dates', formatDateRange(args.start_date, args.end_date))
     addRow('Device', args.device)
     addRow('Device', args.device)
    if args.winner then addRow('Winner', "'''[[" .. args.winner .. "]]'''") end
      
      
    if args.winner then
        addRow('Winner', "'''[[" .. args.winner .. "]]'''")
    end
   
    -- F. Socials
     root:wikitext(getSocials(args))
     root:wikitext(getSocials(args))
      
      
     -- G. Navigation Footer
     -- FIXED: Using FontAwesome Icons instead of File syntax for arrows
     if args.previous or args.next then
     if args.previous or args.next then
         local nav = root:tag('div'):addClass('fib-nav')
         local nav = root:tag('div'):addClass('fib-nav')
          
          
        -- Previous Button
         local prevBtn = nav:tag('div'):addClass('fib-nav-btn prev')
         local prevBtn = nav:tag('div'):addClass('fib-nav-btn prev')
         if args.previous and args.previous ~= "" then
         if args.previous and args.previous ~= "" then  
             prevBtn:wikitext('[[File:Arrow_left.svg|12px|link=]] [[' .. args.previous .. '|Previous]]')
             prevBtn:wikitext('[[' .. args.previous .. '|<i class="fa-solid fa-chevron-left"></i> Previous]]')  
         else
         else  
             prevBtn:css('opacity', '0.3'):wikitext('Previous')
             prevBtn:css('opacity', '0.3'):wikitext('<i class="fa-solid fa-chevron-left"></i> Previous')  
         end
         end
          
          
        -- Next Button
         local nextBtn = nav:tag('div'):addClass('fib-nav-btn next')
         local nextBtn = nav:tag('div'):addClass('fib-nav-btn next')
         if args.next and args.next ~= "" then
         if args.next and args.next ~= "" then  
             nextBtn:wikitext('[[' .. args.next .. '|Next]] [[File:Arrow_right.svg|12px|link=]]')
             nextBtn:wikitext('[[' .. args.next .. '|Next <i class="fa-solid fa-chevron-right"></i>]]')  
         else
         else  
             nextBtn:css('opacity', '0.3'):wikitext('Next')
             nextBtn:css('opacity', '0.3'):wikitext('Next <i class="fa-solid fa-chevron-right"></i>')  
         end
         end
     end
     end
Line 210: Line 210:


-- ============================================================
-- ============================================================
-- MAIN 2 & 3: LIST ROWS (Preserved from before)
-- MAIN 2: LIST ROW (Tournaments Page)
-- ============================================================
-- ============================================================
-- (Keep p.listRow and p.listRowMain exactly as they were in the previous code)
-- For brevity, I am not pasting them again here, but ensure you keep them in the module!
function p.listRow(frame)
function p.listRow(frame)
     -- ... (Keep existing code)
     local args = frame.args
     return "" -- Placeholder
    local page = args.Page or ""
    local name = getCleanTitle(page)
    local startDate = args.start_date or ""
    local endDate = args.end_date or ""
   
    local row = html.create('div'):addClass('tourney-row')
    row:tag('div'):addClass('tr-date'):wikitext(formatDateRange(startDate, endDate))
    local info = row:tag('div'):addClass('tr-info')
    info:tag('div'):addClass('tr-name'):wikitext('[[' .. page .. '|' .. name .. ']]')
    if args.organizer then info:tag('div'):addClass('tr-org'):wikitext(args.organizer) end
    local winDiv = row:tag('div'):addClass('tr-winner mobile-hide')
     if args.winner and args.winner ~= "" then winDiv:wikitext("🏆 " .. args.winner) else winDiv:tag('span'):addClass('dim-text'):wikitext('-') end
    local prizeDiv = row:tag('div'):addClass('tr-prize')
    prizeDiv:wikitext(formatCurrency(args.prize_pool))
    return tostring(row)
end
end
-- ============================================================
-- MAIN 3: LIST ROW MAIN (Homepage)
-- ============================================================
function p.listRowMain(frame)
function p.listRowMain(frame)
     -- ... (Keep existing code)
     local args = frame.args
     return "" -- Placeholder
    local page = args.Page or ""
    local name = getCleanTitle(page)
    local startDate = args.start_date or ""
    local endDate = args.end_date or ""
    local image = args.image or ""
    local imageDark = args.image_dark or ""
   
    local row = html.create('div'):addClass('tourney-row tr-compact')
    row:tag('div'):addClass('tr-date'):wikitext(formatDateRange(startDate, endDate))
    row:tag('div'):addClass('tr-event-logo-col'):wikitext(getTourneyLogo(image, imageDark))
    local info = row:tag('div'):addClass('tr-info')
    info:tag('div'):addClass('tr-name'):wikitext('[[' .. page .. '|' .. name .. ']]')
    if args.organizer then info:tag('div'):addClass('tr-org'):wikitext(args.organizer) end
    local prizeDiv = row:tag('div'):addClass('tr-prize')
    prizeDiv:wikitext(formatCurrency(args.prize_pool))
     return tostring(row)
end
end


return p
return p

Revision as of 14:03, 27 January 2026

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

local p = {}
local html = mw.html
local lang = mw.getContentLanguage()

-- ============================================================
-- HELPER FUNCTIONS
-- ============================================================

-- Helper: Currency Formatter
local function formatCurrency(amount)
    if not amount or amount == "" or amount == "0" then return "TBD" end
    local currency = "₹" 
    if string.find(amount, "%$") then currency = "$" end
    local n = tostring(amount):gsub(",", ""):gsub("₹", ""):gsub("%$", "")
    if #n <= 3 then return currency .. " " .. n end
    local last3 = n:sub(-3)
    local rest = n:sub(1, -4)
    local formattedRest = rest:reverse():gsub("(%d%d)", "%1,"):reverse()
    if formattedRest:sub(1, 1) == "," then formattedRest = formattedRest:sub(2) end
    return '<span class="pz-prize">' .. currency .. " " .. formattedRest .. "," .. last3 .. '</span>'
end

-- Helper: Date Ranger
local function formatDateRange(startStr, endStr)
    if not startStr or startStr == "" then return "TBA" end
    if endStr and endStr ~= "" and endStr ~= startStr then
        local s = lang:formatDate('d M', startStr)
        local e = lang:formatDate('d M, Y', endStr)
        return s .. " – " .. e 
    else
        return lang:formatDate('d M, Y', startStr)
    end
end

-- Helper: Clean Title
local function getCleanTitle(pageLink)
    if not pageLink then return "" end
    local title = mw.title.new(pageLink)
    if title then return title.subpageText end
    return pageLink
end

-- Helper: Social Icon Generator (FIXED: Uses Wikitext Syntax)
local function getSocials(args)
    local container = html.create('div'):addClass('fib-socials')
    local hasSocials = false
    
    local platforms = {
        {arg='instagram', icon='fa-brands fa-instagram'},
        {arg='twitter', icon='fa-brands fa-x-twitter'},
        {arg='youtube', icon='fa-brands fa-youtube'},
        {arg='discord', icon='fa-brands fa-discord'},
        {arg='facebook', icon='fa-brands fa-facebook'},
        {arg='website', icon='fa-solid fa-globe'}
    }
    
    for _, p in ipairs(platforms) do
        if args[p.arg] and args[p.arg] ~= "" then
            hasSocials = true
            -- We use a span to wrap the icon inside the external link syntax
            -- Syntax: https://www.flaticon.com/free-icons/span
            container:wikitext('[' .. args[p.arg] .. ' <span class="fib-social-icon"><i class="' .. p.icon .. '"></i></span>]')
        end
    end
    
    if hasSocials then return tostring(container) else return "" end
end

-- Helper: Theme Aware Logo (For Lists/Homepage)
local function getTourneyLogo(imageFile, darkImageFile)
    local container = html.create('div'):addClass('tr-event-logo')
    if imageFile and imageFile ~= "" then
        local darkFile = darkImageFile
        if not darkFile or darkFile == "" then
            local ext = imageFile:match("^.+(%..+)$") or ".png"
            local name = imageFile:gsub("%..+$", "")
            darkFile = name .. "_dark" .. ext
        end
        local hasDark = mw.title.new('File:' .. darkFile).exists
        container:tag('span'):addClass('logo-lightmode'):wikitext('[[File:' .. imageFile .. '|40px|link=]]')
        local dSpan = container:tag('span'):addClass('logo-darkmode')
        if hasDark then dSpan:wikitext('[[File:' .. darkFile .. '|40px|link=]]') else dSpan:wikitext('[[File:' .. imageFile .. '|40px|link=]]') end
    else
        container:wikitext('<i class="fa-solid fa-trophy" style="color:var(--text-muted); opacity:0.3;"></i>')
    end
    return tostring(container)
end

-- Helper: Theme Aware Logo (For Infobox)
local function getInfoboxLogo(pageName, image, imageDark)
    local lightFile = (image ~= "" and image) or (pageName .. '.png')
    local darkFile = imageDark
    if not darkFile or darkFile == "" then
        local ext = lightFile:match("^.+(%..+)$") or ".png"
        local name = lightFile:gsub("%..+$", "")
        darkFile = name .. "_dark" .. ext
    end
    
    local hasLight = mw.title.new('File:' .. lightFile).exists
    local hasDark = mw.title.new('File:' .. darkFile).exists
    
    local container = html.create('div'):addClass('fib-image')
    local lSpan = container:tag('span'):addClass('logo-lightmode')
    if hasLight then lSpan:wikitext('[[File:' .. lightFile .. '|250px]]') else lSpan:wikitext('[[File:Shield_team.png|150px]]') end
    local dSpan = container:tag('span'):addClass('logo-darkmode')
    if hasDark then dSpan:wikitext('[[File:' .. darkFile .. '|250px]]') elseif hasLight then dSpan:wikitext('[[File:' .. lightFile .. '|250px]]') else dSpan:wikitext('[[File:Shield_team_dark.png|150px]]') end
    return tostring(container)
end

-- ============================================================
-- MAIN 1: TOURNAMENT INFOBOX
-- ============================================================
function p.infobox(frame)
    local args = frame:getParent().args
    local page = args.name or mw.title.getCurrentTitle().text
    local cleanName = mw.title.getCurrentTitle().subpageText
    local prizeMoney = args.prize_pool or args.prizepool
    
    if mw.ext.cargo and mw.ext.cargo.store then
        mw.ext.cargo.store('Tournaments', {
            _pageName = mw.title.getCurrentTitle().prefixedText,
            name = args.name or cleanName,
            series = args.series,
            organizer = args.organizer,
            sponsor = args.sponsor,
            game = args.game or "BGMI",
            mode = args.mode,
            type = args.type,
            tier = args.tier,
            device = args.device,
            location = args.location,
            venue = args.venue,
            prize_pool = prizeMoney,
            start_date = args.start_date,
            end_date = args.end_date,
            winner = args.winner,
            previous = args.previous,
            next = args.next,
            image = args.image,
            image_dark = args.image_dark,
            instagram = args.instagram,
            twitter = args.twitter,
            youtube = args.youtube,
            discord = args.discord,
            facebook = args.facebook,
            website = args.website
        })
    end

    local root = html.create('div'):addClass('flat-infobox')
    
    local header = root:tag('div'):addClass('fib-header')
    header:tag('div'):addClass('fib-title'):wikitext(args.name or cleanName)
    
    -- Logo comes AFTER title in the container, but visual order handled by DOM flow
    root:wikitext(getInfoboxLogo(page, args.image, args.image_dark))
    
    local grid1 = root:tag('div'):addClass('fib-grid')
    grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Event Tier'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.tier or 'Unranked'):done()
    grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Type'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.type or 'Online'):done()
         
    local grid2 = root:tag('div'):addClass('fib-grid')
    grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Mode'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.mode or 'TBD'):done()
    grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Location'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.location or 'India'):done()
    
    if prizeMoney then
        root:tag('div'):addClass('fib-prize')
            :tag('div'):addClass('fib-label-sm'):wikitext('Total Prize Pool'):done()
            :tag('div'):addClass('fib-prize-val'):wikitext(formatCurrency(prizeMoney)):done()
    end
    
    local list = root:tag('div'):addClass('fib-list')
    local function addRow(label, value)
        if value and value ~= "" then
            list:tag('div'):addClass('fib-row'):tag('div'):addClass('fib-label'):wikitext(label):done():tag('div'):addClass('fib-data'):wikitext(value):done()
        end
    end
    
    addRow('Series', args.series and '[[' .. args.series .. ']]')
    addRow('Organizer', args.organizer)
    addRow('Sponsors', args.sponsor)
    addRow('Venue', args.venue)
    addRow('Dates', formatDateRange(args.start_date, args.end_date))
    addRow('Device', args.device)
    if args.winner then addRow('Winner', "'''[[" .. args.winner .. "]]'''") end
    
    root:wikitext(getSocials(args))
    
    -- FIXED: Using FontAwesome Icons instead of File syntax for arrows
    if args.previous or args.next then
        local nav = root:tag('div'):addClass('fib-nav')
        
        local prevBtn = nav:tag('div'):addClass('fib-nav-btn prev')
        if args.previous and args.previous ~= "" then 
            prevBtn:wikitext('[[' .. args.previous .. '|<i class="fa-solid fa-chevron-left"></i> Previous]]') 
        else 
            prevBtn:css('opacity', '0.3'):wikitext('<i class="fa-solid fa-chevron-left"></i> Previous') 
        end
        
        local nextBtn = nav:tag('div'):addClass('fib-nav-btn next')
        if args.next and args.next ~= "" then 
            nextBtn:wikitext('[[' .. args.next .. '|Next <i class="fa-solid fa-chevron-right"></i>]]') 
        else 
            nextBtn:css('opacity', '0.3'):wikitext('Next <i class="fa-solid fa-chevron-right"></i>') 
        end
    end

    return tostring(root)
end

-- ============================================================
-- MAIN 2: LIST ROW (Tournaments Page)
-- ============================================================
function p.listRow(frame)
    local args = frame.args
    local page = args.Page or ""
    local name = getCleanTitle(page)
    local startDate = args.start_date or ""
    local endDate = args.end_date or ""
    
    local row = html.create('div'):addClass('tourney-row')
    row:tag('div'):addClass('tr-date'):wikitext(formatDateRange(startDate, endDate))
    local info = row:tag('div'):addClass('tr-info')
    info:tag('div'):addClass('tr-name'):wikitext('[[' .. page .. '|' .. name .. ']]')
    if args.organizer then info:tag('div'):addClass('tr-org'):wikitext(args.organizer) end
    local winDiv = row:tag('div'):addClass('tr-winner mobile-hide')
    if args.winner and args.winner ~= "" then winDiv:wikitext("🏆 " .. args.winner) else winDiv:tag('span'):addClass('dim-text'):wikitext('-') end
    local prizeDiv = row:tag('div'):addClass('tr-prize')
    prizeDiv:wikitext(formatCurrency(args.prize_pool))
    return tostring(row)
end

-- ============================================================
-- MAIN 3: LIST ROW MAIN (Homepage)
-- ============================================================
function p.listRowMain(frame)
    local args = frame.args
    local page = args.Page or ""
    local name = getCleanTitle(page)
    local startDate = args.start_date or ""
    local endDate = args.end_date or ""
    local image = args.image or ""
    local imageDark = args.image_dark or ""
    
    local row = html.create('div'):addClass('tourney-row tr-compact')
    row:tag('div'):addClass('tr-date'):wikitext(formatDateRange(startDate, endDate))
    row:tag('div'):addClass('tr-event-logo-col'):wikitext(getTourneyLogo(image, imageDark))
    local info = row:tag('div'):addClass('tr-info')
    info:tag('div'):addClass('tr-name'):wikitext('[[' .. page .. '|' .. name .. ']]')
    if args.organizer then info:tag('div'):addClass('tr-org'):wikitext(args.organizer) end
    local prizeDiv = row:tag('div'):addClass('tr-prize')
    prizeDiv:wikitext(formatCurrency(args.prize_pool))
    return tostring(row)
end

return p