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 39: Line 39:
end
end


-- Social Icons (Using Standard File Uploads)
-- Helper: Small Team Logo
local function getSmallTeamLogo(teamName)
    if not teamName or teamName == "" then return "" end
    local fileName = teamName .. '.png'
    if mw.title.new('File:' .. fileName).exists then
        return '[[File:' .. fileName .. '|25px|link=' .. teamName .. '|class=team-logo-small]] '
    end
    return ''
end
 
-- Helper: Fetch Winner/RunnerUp from PrizeMoney Table
-- Looks for placement="1" or placement="2"
local function getTeamFromPrizeMoney(pageName, place)
    if not cargo or not pageName then return nil end
   
    -- We assume the PrizeMoney template is on the same page, so we match _pageName
    local results = cargo.query('PrizeMoney', 'team', {
        where = string.format('_pageName="%s" AND placement="%s"', pageName, place),
        limit = 1
    })
   
    if results and #results > 0 then
        return results[1].team
    end
    return nil
end
 
-- Social Icons (File Upload Method)
local function getSocials(args)
local function getSocials(args)
     local container = html.create('div'):addClass('fib-socials')
     local container = html.create('div'):addClass('fib-socials')
     local hasSocials = false
     local hasSocials = false
   
    -- Map args to File Names
     local platforms = {
     local platforms = {
         {arg='instagram', file='Icon_instagram.png'},
         {arg='instagram', file='Icon_instagram.png'},
Line 53: Line 78:
         {arg='website',  file='Icon_website.png'}
         {arg='website',  file='Icon_website.png'}
     }
     }
   
     for _, p in ipairs(platforms) do
     for _, p in ipairs(platforms) do
         if args[p.arg] and args[p.arg] ~= "" then
         if args[p.arg] and args[p.arg] ~= "" then
             hasSocials = true
             hasSocials = true
            -- Standard Image Link: [[File:Name.png|20px|link=URL]]
             container:wikitext('[[File:' .. p.file .. '|24px|link=' .. args[p.arg] .. '|class=social-img]]')
             container:wikitext('[[File:' .. p.file .. '|24px|link=' .. args[p.arg] .. '|class=social-img]]')
         end
         end
     end
     end
   
     if hasSocials then return tostring(container) else return "" end
     if hasSocials then return tostring(container) else return "" end
end
end


-- Smart Series Navigation (Value Based)
-- Smart Series Navigation
local function getSeriesNav(currentSeries, currentValue)
local function getSeriesNav(currentSeries, currentValue)
     if not currentSeries or not currentValue or not cargo then return "" end
     if not currentSeries or not currentValue or not cargo then return "" end
   
     local nav = html.create('div'):addClass('fib-nav')
     local nav = html.create('div'):addClass('fib-nav')
      
      
    -- 1. Find PREVIOUS (Highest value LESS than current)
    -- Example: If current is 2025, finding max value < 2025 (e.g. 2024)
     local prevQuery = cargo.query('Tournaments', '_pageName, series_season', {
     local prevQuery = cargo.query('Tournaments', '_pageName, series_season', {
         where = string.format('series = "%s" AND series_value < %s', currentSeries, currentValue),
         where = string.format('series = "%s" AND series_value < %s', currentSeries, currentValue),
         orderBy = 'series_value DESC', -- Get the closest previous one
         orderBy = 'series_value DESC', limit = 1
        limit = 1
     })
     })
   
     local prevBtn = nav:tag('div'):addClass('fib-nav-btn prev')
     local prevBtn = nav:tag('div'):addClass('fib-nav-btn prev')
     if prevQuery and #prevQuery > 0 then
     if prevQuery and #prevQuery > 0 then
        local row = prevQuery[1]
         prevBtn:wikitext('[[' .. prevQuery[1]._pageName .. '|« ' .. (prevQuery[1].series_season or "Previous") .. ']]')
        local label = row.series_season or "Previous"
         prevBtn:wikitext('[[' .. row._pageName .. '|' .. label .. ']]')
     else
     else
        -- If no previous, show empty or placeholder
         prevBtn:css('opacity', '0.3'):wikitext('« Previous')
         prevBtn:css('opacity', '0.3'):wikitext('Previous')  
     end
     end
      
      
    -- 2. Find NEXT (Lowest value GREATER than current)
    -- Example: If current is 2025, finding min value > 2025 (e.g. 2026)
     local nextQuery = cargo.query('Tournaments', '_pageName, series_season', {
     local nextQuery = cargo.query('Tournaments', '_pageName, series_season', {
         where = string.format('series = "%s" AND series_value > %s', currentSeries, currentValue),
         where = string.format('series = "%s" AND series_value > %s', currentSeries, currentValue),
         orderBy = 'series_value ASC', -- Get the closest next one
         orderBy = 'series_value ASC', limit = 1
        limit = 1
     })
     })
   
     local nextBtn = nav:tag('div'):addClass('fib-nav-btn next')
     local nextBtn = nav:tag('div'):addClass('fib-nav-btn next')
     if nextQuery and #nextQuery > 0 then
     if nextQuery and #nextQuery > 0 then
        local row = nextQuery[1]
         nextBtn:wikitext('[[' .. nextQuery[1]._pageName .. '|' .. (nextQuery[1].series_season or "Next") .. ' »]]')
        local label = row.series_season or "Next"
         nextBtn:wikitext('[[' .. row._pageName .. '|' .. label .. ']]')
     else
     else
         nextBtn:css('opacity', '0.3'):wikitext('Next')  
         nextBtn:css('opacity', '0.3'):wikitext('Next »')
     end
     end
   
     return tostring(nav)
     return tostring(nav)
end
end


-- Helper: Theme Aware Logo
-- Infobox Logo
local function getInfoboxLogo(pageName, image, imageDark)
local function getInfoboxLogo(pageName, image, imageDark)
     local lightFile = (image ~= "" and image) or (pageName .. '.png')
     local lightFile = (image ~= "" and image) or (pageName .. '.png')
Line 128: Line 135:
end
end


-- Helper: List Logo (For Homepage)
-- List Logo
local function getTourneyLogo(imageFile, darkImageFile)
local function getTourneyLogo(imageFile, darkImageFile)
     local container = html.create('div'):addClass('tr-event-logo')
     local container = html.create('div'):addClass('tr-event-logo')
Line 156: Line 163:
     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
    local dbPageName = mw.title.getCurrentTitle().prefixedText
   
    -- 1. Determine Winner (Manual OR Auto-Fetch)
    local finalWinner = args.winner
    if not finalWinner or finalWinner == "" then
        finalWinner = getTeamFromPrizeMoney(dbPageName, "1")
    end
   
    -- 2. Determine Runner Up (Manual OR Auto-Fetch)
    local finalRunnerUp = args.runner_up
    if not finalRunnerUp or finalRunnerUp == "" then
        finalRunnerUp = getTeamFromPrizeMoney(dbPageName, "2")
    end
      
      
     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', {
             _pageName = mw.title.getCurrentTitle().prefixedText,
             _pageName = dbPageName,
             name = args.name or cleanName,
             name = args.name or cleanName,
             series = args.series,
             series = args.series,
Line 176: Line 196:
             start_date = args.start_date,
             start_date = args.start_date,
             end_date = args.end_date,
             end_date = args.end_date,
             winner = args.winner,
             winner = finalWinner,     -- Store the Calculated Winner
            runner_up = finalRunnerUp, -- Store the Calculated Runner Up
             image = args.image,
             image = args.image,
             image_dark = args.image_dark,
             image_dark = args.image_dark,
Line 189: Line 210:


     local root = html.create('div'):addClass('flat-infobox')
     local root = html.create('div'):addClass('flat-infobox')
   
     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)
Line 222: Line 242:
     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 finalWinner then addRow('Winner', "'''[[" .. finalWinner .. "]]'''") end
      
      
     root:wikitext(getSocials(args))
     root:wikitext(getSocials(args))
      
      
    -- Automatic Series Navigation
     if args.series and args.series_value then
     if args.series and args.series_value then
         root:wikitext(getSeriesNav(args.series, args.series_value))
         root:wikitext(getSeriesNav(args.series, args.series_value))
Line 234: Line 253:
end
end


-- ============================================================
-- MAIN 2: TABLE ROW (Sortable Table on Tournaments Page)
-- ============================================================
function p.tableRow(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 prize = args.prize_pool or "0"
   
    -- Auto-Fetch from Database if not provided in args
    local winner = args.winner
    if not winner or winner == "" then
        winner = getTeamFromPrizeMoney(page, "1")
    end
   
    local runnerUp = args.runner_up
    if not runnerUp or runnerUp == "" then
        runnerUp = getTeamFromPrizeMoney(page, "2")
    end
   
    local row = html.create('tr')
   
    row:tag('td'):attr('data-sort-value', startDate):css('white-space', 'nowrap'):wikitext(formatDateRange(startDate, endDate))
    row:tag('td'):css('text-align', 'center'):wikitext(args.tier or '-')
    row:tag('td'):css('font-weight', 'bold'):wikitext('[[' .. page .. '|' .. name .. ']]')
    row:tag('td'):wikitext(args.location or '-')
    row:tag('td'):attr('data-sort-value', prize):css('text-align', 'right'):wikitext(formatCurrency(prize))
     
    local winCell = row:tag('td')
    if winner and winner ~= "" then
        winCell:wikitext(getSmallTeamLogo(winner) .. '[[' .. winner .. ']]')
    else
        winCell:css('text-align', 'center'):wikitext('-')
    end
   
    local runCell = row:tag('td')
    if runnerUp and runnerUp ~= "" then
        runCell:wikitext(getSmallTeamLogo(runnerUp) .. '[[' .. runnerUp .. ']]')
    else
        runCell:css('text-align', 'center'):wikitext('-')
    end
   
    return tostring(row)
end
-- ============================================================
-- MAIN 3: LIST ROW
-- ============================================================
function p.listRow(frame)
function p.listRow(frame)
     local args = frame.args
     local args = frame.args
Line 240: Line 309:
     local startDate = args.start_date or ""
     local startDate = args.start_date or ""
     local endDate = args.end_date or ""
     local endDate = args.end_date or ""
   
    local winner = args.winner
    if not winner or winner == "" then
        winner = getTeamFromPrizeMoney(page, "1")
    end
   
     local row = html.create('div'):addClass('tourney-row')
     local row = html.create('div'):addClass('tourney-row')
     row:tag('div'):addClass('tr-date'):wikitext(formatDateRange(startDate, endDate))
     row:tag('div'):addClass('tr-date'):wikitext(formatDateRange(startDate, endDate))
Line 245: Line 320:
     info:tag('div'):addClass('tr-name'):wikitext('[[' .. page .. '|' .. name .. ']]')
     info:tag('div'):addClass('tr-name'):wikitext('[[' .. page .. '|' .. name .. ']]')
     if args.organizer then info:tag('div'):addClass('tr-org'):wikitext(args.organizer) end
     if args.organizer then info:tag('div'):addClass('tr-org'):wikitext(args.organizer) end
   
     local winDiv = row:tag('div'):addClass('tr-winner mobile-hide')
     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
     if winner and winner ~= "" then winDiv:wikitext("🏆 " .. winner) else winDiv:tag('span'):addClass('dim-text'):wikitext('-') end
   
     local prizeDiv = row:tag('div'):addClass('tr-prize')
     local prizeDiv = row:tag('div'):addClass('tr-prize')
     prizeDiv:wikitext(formatCurrency(args.prize_pool))
     prizeDiv:wikitext(formatCurrency(args.prize_pool))
Line 252: Line 329:
end
end


-- ============================================================
-- MAIN 4: LIST ROW MAIN
-- ============================================================
function p.listRowMain(frame)
function p.listRowMain(frame)
     local args = frame.args
     local args = frame.args

Revision as of 20:00, 27 January 2026

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

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

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

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

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

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: Small Team Logo
local function getSmallTeamLogo(teamName)
    if not teamName or teamName == "" then return "" end
    local fileName = teamName .. '.png'
    if mw.title.new('File:' .. fileName).exists then
        return '[[File:' .. fileName .. '|25px|link=' .. teamName .. '|class=team-logo-small]] '
    end
    return ''
end

-- Helper: Fetch Winner/RunnerUp from PrizeMoney Table
-- Looks for placement="1" or placement="2"
local function getTeamFromPrizeMoney(pageName, place)
    if not cargo or not pageName then return nil end
    
    -- We assume the PrizeMoney template is on the same page, so we match _pageName
    local results = cargo.query('PrizeMoney', 'team', {
        where = string.format('_pageName="%s" AND placement="%s"', pageName, place),
        limit = 1
    })
    
    if results and #results > 0 then
        return results[1].team
    end
    return nil
end

-- Social Icons (File Upload Method)
local function getSocials(args)
    local container = html.create('div'):addClass('fib-socials')
    local hasSocials = false
    local platforms = {
        {arg='instagram', file='Icon_instagram.png'},
        {arg='twitter',   file='Icon_twitter.png'},
        {arg='youtube',   file='Icon_youtube.png'},
        {arg='discord',   file='Icon_discord.png'},
        {arg='facebook',  file='Icon_facebook.png'},
        {arg='website',   file='Icon_website.png'}
    }
    for _, p in ipairs(platforms) do
        if args[p.arg] and args[p.arg] ~= "" then
            hasSocials = true
            container:wikitext('[[File:' .. p.file .. '|24px|link=' .. args[p.arg] .. '|class=social-img]]')
        end
    end
    if hasSocials then return tostring(container) else return "" end
end

-- Smart Series Navigation
local function getSeriesNav(currentSeries, currentValue)
    if not currentSeries or not currentValue or not cargo then return "" end
    local nav = html.create('div'):addClass('fib-nav')
    
    local prevQuery = cargo.query('Tournaments', '_pageName, series_season', {
        where = string.format('series = "%s" AND series_value < %s', currentSeries, currentValue),
        orderBy = 'series_value DESC', limit = 1
    })
    local prevBtn = nav:tag('div'):addClass('fib-nav-btn prev')
    if prevQuery and #prevQuery > 0 then
        prevBtn:wikitext('[[' .. prevQuery[1]._pageName .. '|« ' .. (prevQuery[1].series_season or "Previous") .. ']]')
    else
        prevBtn:css('opacity', '0.3'):wikitext('« Previous')
    end
    
    local nextQuery = cargo.query('Tournaments', '_pageName, series_season', {
        where = string.format('series = "%s" AND series_value > %s', currentSeries, currentValue),
        orderBy = 'series_value ASC', limit = 1
    })
    local nextBtn = nav:tag('div'):addClass('fib-nav-btn next')
    if nextQuery and #nextQuery > 0 then
        nextBtn:wikitext('[[' .. nextQuery[1]._pageName .. '|' .. (nextQuery[1].series_season or "Next") .. ' »]]')
    else
        nextBtn:css('opacity', '0.3'):wikitext('Next »')
    end
    return tostring(nav)
end

-- Infobox Logo
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

-- List Logo
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

-- ============================================================
-- 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
    local dbPageName = mw.title.getCurrentTitle().prefixedText
    
    -- 1. Determine Winner (Manual OR Auto-Fetch)
    local finalWinner = args.winner
    if not finalWinner or finalWinner == "" then
        finalWinner = getTeamFromPrizeMoney(dbPageName, "1")
    end
    
    -- 2. Determine Runner Up (Manual OR Auto-Fetch)
    local finalRunnerUp = args.runner_up
    if not finalRunnerUp or finalRunnerUp == "" then
        finalRunnerUp = getTeamFromPrizeMoney(dbPageName, "2")
    end
    
    if mw.ext.cargo and mw.ext.cargo.store then
        mw.ext.cargo.store('Tournaments', {
            _pageName = dbPageName,
            name = args.name or cleanName,
            series = args.series,
            series_season = args.series_season,
            series_value = args.series_value,
            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 = finalWinner,      -- Store the Calculated Winner
            runner_up = finalRunnerUp, -- Store the Calculated Runner Up
            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)
    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 .. ']]')
    if args.series_season then addRow('Season', args.series_season) end
    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 finalWinner then addRow('Winner', "'''[[" .. finalWinner .. "]]'''") end
    
    root:wikitext(getSocials(args))
    
    if args.series and args.series_value then
        root:wikitext(getSeriesNav(args.series, args.series_value))
    end

    return tostring(root)
end

-- ============================================================
-- MAIN 2: TABLE ROW (Sortable Table on Tournaments Page)
-- ============================================================
function p.tableRow(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 prize = args.prize_pool or "0"
    
    -- Auto-Fetch from Database if not provided in args
    local winner = args.winner
    if not winner or winner == "" then
        winner = getTeamFromPrizeMoney(page, "1")
    end
    
    local runnerUp = args.runner_up
    if not runnerUp or runnerUp == "" then
        runnerUp = getTeamFromPrizeMoney(page, "2")
    end
    
    local row = html.create('tr')
    
    row:tag('td'):attr('data-sort-value', startDate):css('white-space', 'nowrap'):wikitext(formatDateRange(startDate, endDate))
    row:tag('td'):css('text-align', 'center'):wikitext(args.tier or '-')
    row:tag('td'):css('font-weight', 'bold'):wikitext('[[' .. page .. '|' .. name .. ']]')
    row:tag('td'):wikitext(args.location or '-')
    row:tag('td'):attr('data-sort-value', prize):css('text-align', 'right'):wikitext(formatCurrency(prize))
       
    local winCell = row:tag('td')
    if winner and winner ~= "" then
        winCell:wikitext(getSmallTeamLogo(winner) .. '[[' .. winner .. ']]')
    else
        winCell:css('text-align', 'center'):wikitext('-')
    end
    
    local runCell = row:tag('td')
    if runnerUp and runnerUp ~= "" then
        runCell:wikitext(getSmallTeamLogo(runnerUp) .. '[[' .. runnerUp .. ']]')
    else
        runCell:css('text-align', 'center'):wikitext('-')
    end
    
    return tostring(row)
end

-- ============================================================
-- MAIN 3: LIST ROW
-- ============================================================
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 winner = args.winner
    if not winner or winner == "" then
        winner = getTeamFromPrizeMoney(page, "1")
    end
    
    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 winner and winner ~= "" then winDiv:wikitext("🏆 " .. 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 4: LIST ROW MAIN
-- ============================================================
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