Module:Tournament: Difference between revisions
From eSportsAmaze
More actions
Esportsamaze (talk | contribs) No edit summary |
Esportsamaze (talk | contribs) No edit summary |
||
| (18 intermediate revisions by the same user not shown) | |||
| Line 39: | Line 39: | ||
end | 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 | |||
local function getTeamFromPrizeMoney(pageName, tournamentName, placeType) | |||
if not cargo then return nil end | |||
local placeClause = "" | |||
if placeType == "1" then | |||
placeClause = '(placement="1" OR placement="1st" OR placement="Winner" OR placement="Champion")' | |||
elseif placeType == "2" then | |||
placeClause = '(placement="2" OR placement="2nd" OR placement="Runner-up" OR placement="Runner Up")' | |||
else | |||
return nil | |||
end | |||
local pageClause = "" | |||
if tournamentName and tournamentName ~= "" then | |||
pageClause = string.format('(tournament="%s" OR _pageName="%s" OR _pageName LIKE "%%%s%%")', tournamentName, pageName, tournamentName) | |||
else | |||
pageClause = string.format('(_pageName="%s" OR _pageName LIKE "%s/%%")', pageName, pageName) | |||
end | |||
local results = cargo.query('PrizeMoney', 'team', { | |||
where = pageClause .. ' AND ' .. placeClause, | |||
limit = 1 | |||
}) | |||
if results and #results > 0 then | |||
return results[1].team | |||
end | |||
return nil | |||
end | |||
-- Social Icons | |||
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 | ||
local platforms = { | local platforms = { | ||
{arg='instagram', file='Icon_instagram.png'}, | {arg='instagram', file='Icon_instagram.png'}, | ||
| Line 53: | Line 92: | ||
{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 | ||
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 | -- 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') | ||
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', | orderBy = 'series_value DESC', 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 | ||
prevBtn:wikitext('[[' .. prevQuery[1]._pageName .. '|« ' .. (prevQuery[1].series_season or "Previous") .. ']]') | |||
prevBtn:wikitext('[[' .. | |||
else | else | ||
prevBtn:css('opacity', '0.3'):wikitext('« Previous') | |||
prevBtn:css('opacity', '0.3'):wikitext('Previous') | |||
end | end | ||
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', | orderBy = 'series_value ASC', 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 | ||
nextBtn:wikitext('[[' .. nextQuery[1]._pageName .. '|' .. (nextQuery[1].series_season or "Next") .. ' »]]') | |||
nextBtn:wikitext('[[' .. | |||
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 | ||
-- | -- 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 149: | ||
end | end | ||
-- | -- 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 146: | Line 167: | ||
end | end | ||
return tostring(container) | return tostring(container) | ||
end | |||
-- Helper: Get Tier Class (NEW) | |||
local function getTierClass(tier) | |||
if not tier then return "tier-misc" end | |||
local t = tier:lower() | |||
if string.find(t, "s") and string.find(t, "tier") then return "tier-s" end | |||
if string.find(t, "a") and string.find(t, "tier") then return "tier-a" end | |||
if string.find(t, "b") and string.find(t, "tier") then return "tier-b" end | |||
if string.find(t, "c") and string.find(t, "tier") then return "tier-c" end | |||
return "tier-misc" | |||
end | end | ||
| Line 156: | Line 188: | ||
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 | |||
local finalWinner = args.winner | |||
if not finalWinner or finalWinner == "" then | |||
finalWinner = getTeamFromPrizeMoney(dbPageName, cleanName, "1") | |||
end | |||
local finalRunnerUp = args.runner_up | |||
if not finalRunnerUp or finalRunnerUp == "" then | |||
finalRunnerUp = getTeamFromPrizeMoney(dbPageName, cleanName, "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 = | _pageName = dbPageName, | ||
name = args.name or cleanName, | name = args.name or cleanName, | ||
series = args.series, | series = args.series, | ||
| Line 176: | Line 219: | ||
start_date = args.start_date, | start_date = args.start_date, | ||
end_date = args.end_date, | end_date = args.end_date, | ||
winner = | winner = finalWinner, | ||
runner_up = finalRunnerUp, | |||
image = args.image, | image = args.image, | ||
image_dark = args.image_dark, | image_dark = args.image_dark, | ||
| Line 189: | Line 233: | ||
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 265: | ||
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 | if finalWinner then addRow('Winner', "'''[[" .. finalWinner .. "]]'''") end | ||
if finalRunnerUp then addRow('Runner Up', "'''[[" .. finalRunnerUp .. "]]'''") end | |||
root:wikitext(getSocials(args)) | 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 (UPDATED FOR HYBRID DESIGN) | |||
-- ============================================================ | |||
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" | |||
local tier = args.tier or "-" | |||
-- | -- Auto-Fetch Winners | ||
if args. | local winner = args.winner | ||
if not winner or winner == "" then winner = getTeamFromPrizeMoney(page, name, "1") end | |||
local runnerUp = args.runner_up | |||
if not runnerUp or runnerUp == "" then runnerUp = getTeamFromPrizeMoney(page, name, "2") end | |||
local row = html.create('tr') | |||
-- 1. Date (Desktop: Box, Mobile: Label) | |||
row:tag('td') | |||
:attr('data-label', 'Date') | |||
:attr('data-sort-value', startDate) | |||
:tag('div'):addClass('tr-date'):wikitext(formatDateRange(startDate, endDate)) | |||
-- 2. Tier (Color Coded Pill) | |||
row:tag('td') | |||
:attr('data-label', 'Tier') | |||
:css('text-align', 'center') | |||
:tag('span'):addClass('tier-badge'):addClass(getTierClass(tier)):wikitext(tier) | |||
-- 3. Tournament Name | |||
row:tag('td') | |||
:attr('data-label', 'Tournament') | |||
:css('font-weight', 'bold'):wikitext('[[' .. page .. '|' .. name .. ']]') | |||
-- 4. Location | |||
row:tag('td') | |||
:attr('data-label', 'Location') | |||
:wikitext(args.location or '-') | |||
-- 5. Prize | |||
row:tag('td') | |||
:attr('data-label', 'Prize') | |||
:attr('data-sort-value', prize) | |||
:addClass('tr-prize') | |||
:css('text-align', 'right') | |||
:wikitext(formatCurrency(prize)) | |||
-- 6. Winner (Gold Background on Desktop) | |||
local winCell = row:tag('td') | |||
:attr('data-label', 'Winner') | |||
:addClass('cell-winner') | |||
if winner and winner ~= "" then | |||
winCell:wikitext(getSmallTeamLogo(winner) .. '[[' .. winner .. ']]') | |||
else | |||
winCell:css('text-align', 'center'):wikitext('-') | |||
end | |||
-- 7. Runner Up | |||
local runCell = row:tag('td'):attr('data-label', 'Runner Up') | |||
if runnerUp and runnerUp ~= "" then | |||
runCell:wikitext(getSmallTeamLogo(runnerUp) .. '[[' .. runnerUp .. ']]') | |||
else | |||
runCell:css('text-align', 'center'):wikitext('-') | |||
end | end | ||
return tostring( | return tostring(row) | ||
end | end | ||
-- ============================================================ | |||
-- MAIN 3: LIST ROW (With Left Strip Logic) | |||
-- ============================================================ | |||
function p.listRow(frame) | function p.listRow(frame) | ||
local args = frame.args | local args = frame.args | ||
local page = args.Page or "" | local page = args.Page or "" | ||
local name = getCleanTitle(page) | local name = getCleanTitle(page) | ||
local startDate = args.start_date or "" | |||
local endDate = args.end_date or "" | local startDate = args.start_date or args.date or args.startdate or "" | ||
local endDate = args.end_date or args.enddate or "" | |||
local prize = args.prize_pool or args.prizepool or args.prize or "0" | |||
local tier = args.tier or "" | |||
local image = args.image or "" | |||
local imageDark = args.image_dark or "" | |||
local winner = args.winner | |||
if not winner or winner == "" then | |||
winner = getTeamFromPrizeMoney(page, name, "1") | |||
end | |||
-- CREATE ROW: Removed inline background styles to allow CSS variables to work | |||
local row = html.create('div'):addClass('tourney-row') | local row = html.create('div'):addClass('tourney-row') | ||
if tier ~= "" then | |||
row:addClass('row-' .. getTierClass(tier)) | |||
end | |||
-- Date Box | |||
row:tag('div'):addClass('tr-date'):wikitext(formatDateRange(startDate, endDate)) | row:tag('div'):addClass('tr-date'):wikitext(formatDateRange(startDate, endDate)) | ||
-- Logo | |||
row:tag('div'):addClass('tr-event-logo-col'):wikitext(getTourneyLogo(image, imageDark)) | |||
-- Info | |||
local info = row:tag('div'):addClass('tr-info') | local info = row:tag('div'):addClass('tr-info') | ||
info:tag('div'):addClass('tr-name'):wikitext('[[' .. page .. '|' .. name .. ']]') | local nameRow = info:tag('div'):addClass('tr-name-row') | ||
nameRow:tag('span'):addClass('tr-name'):wikitext('[[' .. page .. '|' .. name .. ']]') | |||
if tier ~= "" then | |||
local tierClass = getTierClass(tier) | |||
nameRow:tag('span'):addClass('tier-badge'):addClass(tierClass):css('margin-left','8px'):wikitext(tier) | |||
end | |||
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 | ||
-- Winner | |||
local winDiv = row:tag('div'):addClass('tr-winner mobile-hide') | local winDiv = row:tag('div'):addClass('tr-winner mobile-hide') | ||
if | if winner and winner ~= "" then | ||
winDiv:wikitext("🏆 " .. winner) | |||
else | |||
winDiv:tag('span'):css('opacity', '0.3'):wikitext('-') | |||
end | |||
-- Prize | |||
local prizeDiv = row:tag('div'):addClass('tr-prize') | local prizeDiv = row:tag('div'):addClass('tr-prize') | ||
prizeDiv:wikitext(formatCurrency( | prizeDiv:wikitext(formatCurrency(prize)) | ||
return tostring(row) | return tostring(row) | ||
end | end | ||
-- ============================================================ | |||
-- MAIN 4: LIST ROW MAIN | |||
-- ============================================================ | |||
function p.listRowMain(frame) | function p.listRowMain(frame) | ||
local args = frame.args | local args = frame.args | ||
| Line 269: | Line 426: | ||
prizeDiv:wikitext(formatCurrency(args.prize_pool)) | prizeDiv:wikitext(formatCurrency(args.prize_pool)) | ||
return tostring(row) | return tostring(row) | ||
end | |||
-- ============================================================ | |||
-- MAIN 5: PAGINATED QUERY (Connects to listRow) | |||
-- ============================================================ | |||
function p.mainQuery(frame) | |||
local args = frame.args | |||
-- 1. PAGINATION SETUP | |||
-- Get offset from URL (defaults to 0 if missing) | |||
local offset = tonumber(args.offset) or 0 | |||
local limit = 50 -- Show 50 tournaments per page | |||
-- 2. BUILD QUERY | |||
local whereClause = "start_date IS NOT NULL" | |||
-- 3. RUN CARGO QUERY | |||
-- We select the exact fields required by your p.listRow function | |||
local results = cargo.query( | |||
'Tournaments', | |||
'_pageName, start_date, end_date, tier, prize_pool, winner, organizer, image, image_dark', | |||
{ | |||
where = whereClause, | |||
orderBy = 'start_date DESC', | |||
limit = limit, | |||
offset = offset | |||
} | |||
) | |||
-- 4. CONTAINER & EMPTY STATE | |||
local container = html.create('div'):addClass('tournament-list-wrapper') | |||
if not results or #results == 0 then | |||
if offset > 0 then | |||
-- User went too far, give a link back to start | |||
return '<div style="padding:40px; text-align:center; color:#64748b;">No more tournaments found.<br><br><b>[[' .. tostring(mw.uri.fullUrl(mw.title.getCurrentTitle().text)) .. '|Back to Start]]</b></div>' | |||
else | |||
return '<div style="padding:40px; text-align:center; color:#64748b;">No tournaments found in database.</div>' | |||
end | |||
end | |||
-- 5. RENDER ROWS (Using your Main 3 logic) | |||
for _, row in ipairs(results) do | |||
-- We structure the data exactly how p.listRow expects it | |||
local rowArgs = { | |||
Page = row._pageName, | |||
start_date = row.start_date, | |||
end_date = row.end_date, | |||
tier = row.tier, | |||
prize_pool = row.prize_pool, | |||
winner = row.winner, | |||
organizer = row.organizer, | |||
image = row.image, | |||
image_dark = row.image_dark | |||
} | |||
-- Call your existing function | |||
container:wikitext(p.listRow({ args = rowArgs })) | |||
end | |||
-- 6. ADD PAGINATION BUTTONS | |||
local navDiv = container:tag('div'):addClass('pagination-controls') | |||
-- "Previous" Button (Hide if on first page) | |||
if offset > 0 then | |||
local prevOffset = math.max(0, offset - limit) | |||
local prevUrl = mw.uri.fullUrl(mw.title.getCurrentTitle().text, {offset=prevOffset}) | |||
navDiv:tag('span'):addClass('page-btn') | |||
:wikitext('[' .. tostring(prevUrl) .. ' « Newer Events]') | |||
end | |||
-- "Next" Button (Hide if we have fewer results than the limit) | |||
if #results == limit then | |||
local nextOffset = offset + limit | |||
local nextUrl = mw.uri.fullUrl(mw.title.getCurrentTitle().text, {offset=nextOffset}) | |||
navDiv:tag('span'):addClass('page-btn') | |||
:wikitext('[' .. tostring(nextUrl) .. ' Older Events »]') | |||
end | |||
return tostring(container) | |||
end | end | ||
return p | return p | ||
Latest revision as of 09:17, 28 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
local function getTeamFromPrizeMoney(pageName, tournamentName, placeType)
if not cargo then return nil end
local placeClause = ""
if placeType == "1" then
placeClause = '(placement="1" OR placement="1st" OR placement="Winner" OR placement="Champion")'
elseif placeType == "2" then
placeClause = '(placement="2" OR placement="2nd" OR placement="Runner-up" OR placement="Runner Up")'
else
return nil
end
local pageClause = ""
if tournamentName and tournamentName ~= "" then
pageClause = string.format('(tournament="%s" OR _pageName="%s" OR _pageName LIKE "%%%s%%")', tournamentName, pageName, tournamentName)
else
pageClause = string.format('(_pageName="%s" OR _pageName LIKE "%s/%%")', pageName, pageName)
end
local results = cargo.query('PrizeMoney', 'team', {
where = pageClause .. ' AND ' .. placeClause,
limit = 1
})
if results and #results > 0 then
return results[1].team
end
return nil
end
-- Social Icons
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
-- Helper: Get Tier Class (NEW)
local function getTierClass(tier)
if not tier then return "tier-misc" end
local t = tier:lower()
if string.find(t, "s") and string.find(t, "tier") then return "tier-s" end
if string.find(t, "a") and string.find(t, "tier") then return "tier-a" end
if string.find(t, "b") and string.find(t, "tier") then return "tier-b" end
if string.find(t, "c") and string.find(t, "tier") then return "tier-c" end
return "tier-misc"
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
local finalWinner = args.winner
if not finalWinner or finalWinner == "" then
finalWinner = getTeamFromPrizeMoney(dbPageName, cleanName, "1")
end
local finalRunnerUp = args.runner_up
if not finalRunnerUp or finalRunnerUp == "" then
finalRunnerUp = getTeamFromPrizeMoney(dbPageName, cleanName, "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,
runner_up = finalRunnerUp,
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
if finalRunnerUp then addRow('Runner Up', "'''[[" .. finalRunnerUp .. "]]'''") 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 (UPDATED FOR HYBRID DESIGN)
-- ============================================================
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"
local tier = args.tier or "-"
-- Auto-Fetch Winners
local winner = args.winner
if not winner or winner == "" then winner = getTeamFromPrizeMoney(page, name, "1") end
local runnerUp = args.runner_up
if not runnerUp or runnerUp == "" then runnerUp = getTeamFromPrizeMoney(page, name, "2") end
local row = html.create('tr')
-- 1. Date (Desktop: Box, Mobile: Label)
row:tag('td')
:attr('data-label', 'Date')
:attr('data-sort-value', startDate)
:tag('div'):addClass('tr-date'):wikitext(formatDateRange(startDate, endDate))
-- 2. Tier (Color Coded Pill)
row:tag('td')
:attr('data-label', 'Tier')
:css('text-align', 'center')
:tag('span'):addClass('tier-badge'):addClass(getTierClass(tier)):wikitext(tier)
-- 3. Tournament Name
row:tag('td')
:attr('data-label', 'Tournament')
:css('font-weight', 'bold'):wikitext('[[' .. page .. '|' .. name .. ']]')
-- 4. Location
row:tag('td')
:attr('data-label', 'Location')
:wikitext(args.location or '-')
-- 5. Prize
row:tag('td')
:attr('data-label', 'Prize')
:attr('data-sort-value', prize)
:addClass('tr-prize')
:css('text-align', 'right')
:wikitext(formatCurrency(prize))
-- 6. Winner (Gold Background on Desktop)
local winCell = row:tag('td')
:attr('data-label', 'Winner')
:addClass('cell-winner')
if winner and winner ~= "" then
winCell:wikitext(getSmallTeamLogo(winner) .. '[[' .. winner .. ']]')
else
winCell:css('text-align', 'center'):wikitext('-')
end
-- 7. Runner Up
local runCell = row:tag('td'):attr('data-label', 'Runner Up')
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 (With Left Strip Logic)
-- ============================================================
function p.listRow(frame)
local args = frame.args
local page = args.Page or ""
local name = getCleanTitle(page)
local startDate = args.start_date or args.date or args.startdate or ""
local endDate = args.end_date or args.enddate or ""
local prize = args.prize_pool or args.prizepool or args.prize or "0"
local tier = args.tier or ""
local image = args.image or ""
local imageDark = args.image_dark or ""
local winner = args.winner
if not winner or winner == "" then
winner = getTeamFromPrizeMoney(page, name, "1")
end
-- CREATE ROW: Removed inline background styles to allow CSS variables to work
local row = html.create('div'):addClass('tourney-row')
if tier ~= "" then
row:addClass('row-' .. getTierClass(tier))
end
-- Date Box
row:tag('div'):addClass('tr-date'):wikitext(formatDateRange(startDate, endDate))
-- Logo
row:tag('div'):addClass('tr-event-logo-col'):wikitext(getTourneyLogo(image, imageDark))
-- Info
local info = row:tag('div'):addClass('tr-info')
local nameRow = info:tag('div'):addClass('tr-name-row')
nameRow:tag('span'):addClass('tr-name'):wikitext('[[' .. page .. '|' .. name .. ']]')
if tier ~= "" then
local tierClass = getTierClass(tier)
nameRow:tag('span'):addClass('tier-badge'):addClass(tierClass):css('margin-left','8px'):wikitext(tier)
end
if args.organizer then info:tag('div'):addClass('tr-org'):wikitext(args.organizer) end
-- Winner
local winDiv = row:tag('div'):addClass('tr-winner mobile-hide')
if winner and winner ~= "" then
winDiv:wikitext("🏆 " .. winner)
else
winDiv:tag('span'):css('opacity', '0.3'):wikitext('-')
end
-- Prize
local prizeDiv = row:tag('div'):addClass('tr-prize')
prizeDiv:wikitext(formatCurrency(prize))
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
-- ============================================================
-- MAIN 5: PAGINATED QUERY (Connects to listRow)
-- ============================================================
function p.mainQuery(frame)
local args = frame.args
-- 1. PAGINATION SETUP
-- Get offset from URL (defaults to 0 if missing)
local offset = tonumber(args.offset) or 0
local limit = 50 -- Show 50 tournaments per page
-- 2. BUILD QUERY
local whereClause = "start_date IS NOT NULL"
-- 3. RUN CARGO QUERY
-- We select the exact fields required by your p.listRow function
local results = cargo.query(
'Tournaments',
'_pageName, start_date, end_date, tier, prize_pool, winner, organizer, image, image_dark',
{
where = whereClause,
orderBy = 'start_date DESC',
limit = limit,
offset = offset
}
)
-- 4. CONTAINER & EMPTY STATE
local container = html.create('div'):addClass('tournament-list-wrapper')
if not results or #results == 0 then
if offset > 0 then
-- User went too far, give a link back to start
return '<div style="padding:40px; text-align:center; color:#64748b;">No more tournaments found.<br><br><b>[[' .. tostring(mw.uri.fullUrl(mw.title.getCurrentTitle().text)) .. '|Back to Start]]</b></div>'
else
return '<div style="padding:40px; text-align:center; color:#64748b;">No tournaments found in database.</div>'
end
end
-- 5. RENDER ROWS (Using your Main 3 logic)
for _, row in ipairs(results) do
-- We structure the data exactly how p.listRow expects it
local rowArgs = {
Page = row._pageName,
start_date = row.start_date,
end_date = row.end_date,
tier = row.tier,
prize_pool = row.prize_pool,
winner = row.winner,
organizer = row.organizer,
image = row.image,
image_dark = row.image_dark
}
-- Call your existing function
container:wikitext(p.listRow({ args = rowArgs }))
end
-- 6. ADD PAGINATION BUTTONS
local navDiv = container:tag('div'):addClass('pagination-controls')
-- "Previous" Button (Hide if on first page)
if offset > 0 then
local prevOffset = math.max(0, offset - limit)
local prevUrl = mw.uri.fullUrl(mw.title.getCurrentTitle().text, {offset=prevOffset})
navDiv:tag('span'):addClass('page-btn')
:wikitext('[' .. tostring(prevUrl) .. ' « Newer Events]')
end
-- "Next" Button (Hide if we have fewer results than the limit)
if #results == limit then
local nextOffset = offset + limit
local nextUrl = mw.uri.fullUrl(mw.title.getCurrentTitle().text, {offset=nextOffset})
navDiv:tag('span'):addClass('page-btn')
:wikitext('[' .. tostring(nextUrl) .. ' Older Events »]')
end
return tostring(container)
end
return p