diff --git a/lua/spec/league_icon_spec.lua b/lua/spec/league_icon_spec.lua
index 455700d019a..c82b72b9e6b 100644
--- a/lua/spec/league_icon_spec.lua
+++ b/lua/spec/league_icon_spec.lua
@@ -1,7 +1,7 @@
--- Triple Comment to Enable our LLS Plugin
local LeagueIcon = require('Module:LeagueIcon')
-local FILLER_EXPECT = '[[File:Logo filler event.png|link=]]'
+local FILLER_EXPECT = ''
local ICON_DARK_EXPECT = '[[File:DarkIcon.png|link=||50x50px]]'
local ICON_BOTH_EXPECT =
diff --git a/lua/wikis/apexlegends/MainPageLayout/data.lua b/lua/wikis/apexlegends/MainPageLayout/data.lua
index cb2a4aa8502..882f99fdfd0 100644
--- a/lua/wikis/apexlegends/MainPageLayout/data.lua
+++ b/lua/wikis/apexlegends/MainPageLayout/data.lua
@@ -10,7 +10,7 @@ local Lua = require('Module:Lua')
local MainPageLayoutUtil = Lua.import('Module:MainPageLayout/Util')
local FilterButtonsWidget = Lua.import('Module:Widget/FilterButtons')
-local TournamentsTicker = Lua.import('Module:Widget/Tournaments/Ticker')
+local TournamentsTicker = Lua.import('Module:Widget/Tournaments/Ticker/List')
local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local Div = HtmlWidgets.Div
@@ -76,9 +76,10 @@ local CONTENT = {
heading = 'Tournaments',
body = TournamentsTicker{
upcomingDays = 30,
- completedDays = 30
+ completedDays = 30,
+ tierColorScheme = 'top3',
},
- padding = true,
+ padding = false,
boxid = MainPageLayoutUtil.BoxId.TOURNAMENTS_TICKER,
},
headlines = {
diff --git a/lua/wikis/commons/LeagueIcon.lua b/lua/wikis/commons/LeagueIcon.lua
index c577c240791..08aca3291a9 100644
--- a/lua/wikis/commons/LeagueIcon.lua
+++ b/lua/wikis/commons/LeagueIcon.lua
@@ -9,11 +9,10 @@ local Lua = require('Module:Lua')
local LeagueIcon = {}
local Class = Lua.import('Module:Class')
+local Icon = Lua.import('Module:Icon')
local Template = Lua.import('Module:Template')
local Logic = Lua.import('Module:Logic')
local String = Lua.import('Module:StringUtils')
-
-local FILLER = '[[File:Logo filler event.png|link=]]'
local NO_ICON_BUT_ICONDARK_TRACKING_CATEGORY = '[[Category:Pages with only icondark]]'
---@class LeagueIconDisplayArgs
@@ -56,7 +55,9 @@ function LeagueIcon.display(args)
--if icon and iconDark are not given and can not be retrieved return filler icon
if String.isEmpty(icon) and String.isEmpty(iconDark) then
- return FILLER
+ return tostring(mw.html.create('span')
+ :addClass('league-icon-small-image')
+ :node(Icon.makeIcon{iconName = 'firstplace'}))
end
if String.isEmpty(icon) then
diff --git a/lua/wikis/commons/TournamentsTicker/Data.lua b/lua/wikis/commons/TournamentsTicker/Data.lua
new file mode 100644
index 00000000000..589e855ea6d
--- /dev/null
+++ b/lua/wikis/commons/TournamentsTicker/Data.lua
@@ -0,0 +1,149 @@
+---
+-- @Liquipedia
+-- page=Module:TournamentsTicker/Data
+--
+-- Please see https://github.com/Liquipedia/Lua-Modules to contribute
+--
+
+local Lua = require('Module:Lua')
+
+local Array = Lua.import('Module:Array')
+local Condition = Lua.import('Module:Condition')
+local DateExt = Lua.import('Module:Date/Ext')
+local Operator = Lua.import('Module:Operator')
+
+local Tournament = Lua.import('Module:Tournament')
+
+local TournamentsTickerData = {}
+
+---@class TournamentsTickerDataProps
+---@field upcomingDays number
+---@field completedDays number
+---@field modifierTier1 number?
+---@field modifierTier2 number?
+---@field modifierTier3 number?
+---@field modifierTier4 number?
+---@field modifierTier5 number?
+---@field modifierTierMisc number?
+---@field modifierTypeQualifier number?
+
+---@class TournamentsTickerDataResult
+---@field upcoming StandardTournament[]
+---@field ongoing StandardTournament[]
+---@field completed StandardTournament[]
+
+---@param props TournamentsTickerDataProps
+---@return TournamentsTickerDataResult
+function TournamentsTickerData.get(props)
+ local upcomingDays = props.upcomingDays or 5
+ local completedDays = props.completedDays or 5
+
+ local tierThresholdModifiers = {
+ [1] = props.modifierTier1,
+ [2] = props.modifierTier2,
+ [3] = props.modifierTier3,
+ [4] = props.modifierTier4,
+ [5] = props.modifierTier5,
+ [-1] = props.modifierTierMisc,
+ }
+
+ --- The Tier Type thresholds only affect completed tournaments.
+ local tierTypeThresholdModifiers = {
+ ['qualifier'] = props.modifierTypeQualifier,
+ }
+
+ local currentTimestamp = DateExt.getCurrentTimestamp()
+
+ ---@param tournament StandardTournament
+ ---@return boolean
+ local function isWithinDateRange(tournament)
+ local modifiedThreshold = tierThresholdModifiers[tournament.liquipediaTier] or 0
+ local modifiedCompletedThreshold = tierTypeThresholdModifiers[tournament.liquipediaTierType] or modifiedThreshold
+
+ if not tournament.startDate then
+ return false
+ end
+
+ local startDateThreshold = currentTimestamp + DateExt.daysToSeconds(upcomingDays + modifiedThreshold)
+ local endDateThreshold = currentTimestamp - DateExt.daysToSeconds(completedDays + modifiedCompletedThreshold)
+
+ if tournament.phase == 'ONGOING' then
+ return true
+ elseif tournament.phase == 'UPCOMING' then
+ return tournament.startDate.timestamp < startDateThreshold
+ elseif tournament.phase == 'FINISHED' then
+ assert(tournament.endDate, 'Tournament without end date: ' .. tournament.pageName)
+ return tournament.endDate.timestamp > endDateThreshold
+ end
+ return false
+ end
+
+ local lpdbFilter = Condition.Tree(Condition.BooleanOperator.all):add{
+ Condition.Util.anyOf(Condition.ColumnName('status'), {'', 'finished'}),
+ Condition.Node(Condition.ColumnName('liquipediatiertype'), Condition.Comparator.neq, 'Points')
+ }
+
+ local allTournaments = Tournament.getAllTournaments(lpdbFilter, function(tournament)
+ return isWithinDateRange(tournament)
+ end)
+
+ ---@param a StandardTournament
+ ---@param b StandardTournament
+ ---@param dateProperty 'endDate'|'startDate'
+ ---@param operator fun(a: integer, b: integer): boolean
+ ---@return boolean?
+ local function sortByDateProperty(a, b, dateProperty, operator)
+ if not a[dateProperty] and not b[dateProperty] then return nil end
+ if not a[dateProperty] then return true end
+ if not b[dateProperty] then return false end
+ if a[dateProperty].timestamp ~= b[dateProperty].timestamp then
+ return operator(a[dateProperty].timestamp, b[dateProperty].timestamp)
+ end
+ return nil
+ end
+
+ ---@param a StandardTournament
+ ---@param b StandardTournament
+ ---@return boolean
+ local function sortByDate(a, b)
+ local endDateSort = sortByDateProperty(a, b, 'endDate', Operator.gt)
+ if endDateSort ~= nil then return endDateSort end
+ local startDateSort = sortByDateProperty(a, b, 'startDate', Operator.gt)
+ if startDateSort ~= nil then return startDateSort end
+ return a.pageName < b.pageName
+ end
+
+ ---@param a StandardTournament
+ ---@param b StandardTournament
+ ---@return boolean
+ local function sortByDateUpcoming(a, b)
+ local startDateSort = sortByDateProperty(a, b, 'startDate', Operator.gt)
+ if startDateSort ~= nil then return startDateSort end
+ local endDateSort = sortByDateProperty(a, b, 'endDate', Operator.gt)
+ if endDateSort ~= nil then return endDateSort end
+ return a.pageName < b.pageName
+ end
+
+ ---@param phase TournamentPhase
+ ---@return fun(tournament: StandardTournament): boolean
+ local function filterByPhase(phase)
+ return function(tournament)
+ return tournament.phase == phase
+ end
+ end
+
+ local upcomingTournaments = Array.filter(allTournaments, filterByPhase('UPCOMING'))
+ local ongoingTournaments = Array.filter(allTournaments, filterByPhase('ONGOING'))
+ local completedTournaments = Array.filter(allTournaments, filterByPhase('FINISHED'))
+ table.sort(upcomingTournaments, sortByDateUpcoming)
+ table.sort(ongoingTournaments, sortByDate)
+ table.sort(completedTournaments, sortByDate)
+
+ return {
+ upcoming = upcomingTournaments,
+ ongoing = ongoingTournaments,
+ completed = completedTournaments,
+ }
+end
+
+return TournamentsTickerData
diff --git a/lua/wikis/commons/Widget/Participants/Team/ChevronToggle.lua b/lua/wikis/commons/Widget/GeneralCollapsible/ChevronToggle.lua
similarity index 95%
rename from lua/wikis/commons/Widget/Participants/Team/ChevronToggle.lua
rename to lua/wikis/commons/Widget/GeneralCollapsible/ChevronToggle.lua
index a8866b13ad3..e3c98047382 100644
--- a/lua/wikis/commons/Widget/Participants/Team/ChevronToggle.lua
+++ b/lua/wikis/commons/Widget/GeneralCollapsible/ChevronToggle.lua
@@ -1,6 +1,6 @@
---
-- @Liquipedia
--- page=Module:Widget/Participants/Team/ChevronToggle
+-- page=Module:Widget/GeneralCollapsible/ChevronToggle
--
-- Please see https://github.com/Liquipedia/Lua-Modules to contribute
--
diff --git a/lua/wikis/commons/Widget/Participants/Team/Header.lua b/lua/wikis/commons/Widget/Participants/Team/Header.lua
index 295b9e01e93..834f6516b22 100644
--- a/lua/wikis/commons/Widget/Participants/Team/Header.lua
+++ b/lua/wikis/commons/Widget/Participants/Team/Header.lua
@@ -14,7 +14,7 @@ local Opponent = Lua.import('Module:Opponent/Custom')
local OpponentDisplay = Lua.import('Module:OpponentDisplay/Custom')
local Widget = Lua.import('Module:Widget')
-local ChevronToggle = Lua.import('Module:Widget/Participants/Team/ChevronToggle')
+local ChevronToggle = Lua.import('Module:Widget/GeneralCollapsible/ChevronToggle')
local WidgetUtil = Lua.import('Module:Widget/Util')
local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local Div = HtmlWidgets.Div
diff --git a/lua/wikis/commons/Widget/Tournament/TierPill.lua b/lua/wikis/commons/Widget/Tournament/TierPill.lua
index fe7c3b56829..20eab8d907d 100644
--- a/lua/wikis/commons/Widget/Tournament/TierPill.lua
+++ b/lua/wikis/commons/Widget/Tournament/TierPill.lua
@@ -10,13 +10,25 @@ local Lua = require('Module:Lua')
local Class = Lua.import('Module:Class')
local Tier = Lua.import('Module:Tier/Utils')
+local WidgetUtil = Lua.import('Module:Widget/Util')
local Widget = Lua.import('Module:Widget')
local HtmlWidgets = Lua.import('Module:Widget/Html/All')
+---@class TournamentsTickerPillWidgetProps
+---@field tournament StandardTournament
+---@field variant 'solid'|'subtle'?
+---@field colorScheme 'full'|'top3'?
+
---@class TournamentsTickerPillWidget: Widget
----@operator call(table): TournamentsTickerPillWidget
+---@operator call(TournamentsTickerPillWidgetProps): TournamentsTickerPillWidget
+---@field props TournamentsTickerPillWidgetProps
local TournamentsTickerPillWidget = Class.new(Widget)
+TournamentsTickerPillWidget.defaultProps = {
+ variant = 'solid',
+ colorScheme = 'full',
+}
+
local COLOR_CLASSES = {
[1] = 'tier1',
[2] = 'tier2',
@@ -41,32 +53,40 @@ function TournamentsTickerPillWidget:render()
return
end
- local tierShort, tierTypeShort = Tier.toShortName(tournament.liquipediaTier,tournament.liquipediaTierType)
+ local subtle = self.props.variant == 'subtle'
+ local tierShort, tierTypeShort = Tier.toShortName(tournament.liquipediaTier, tournament.liquipediaTierType)
- local tierNode, tierTypeNode, colorClass
- if tierTypeShort then
+ local colorClass
+ if tierTypeShort and not subtle then
colorClass = COLOR_CLASSES[tournament.liquipediaTierType]
- tierNode = HtmlWidgets.Div{
- classes = {'tournament-badge__chip', 'chip--' .. COLOR_CLASSES[tournament.liquipediaTier]},
- children = tierShort,
- }
- tierTypeNode = HtmlWidgets.Div{
- classes = {'tournament-badge__text'},
- children = tierTypeShort,
- }
else
colorClass = COLOR_CLASSES[tournament.liquipediaTier]
- tierNode = HtmlWidgets.Div{
- classes = {'tournament-badge__text'},
- children = Tier.toName(tournament.liquipediaTier),
- }
end
-
colorClass = colorClass or COLOR_CLASSES.default
+ local chipText = subtle and Tier.toName(tournament.liquipediaTier) or tierShort
+ local textContent = tierTypeShort and tierTypeShort or Tier.toName(tournament.liquipediaTier)
+
return HtmlWidgets.Div{
- classes = {'tournament-badge', 'badge--' .. colorClass},
- children = {tierNode, tierTypeNode},
+ classes = WidgetUtil.collect(
+ 'tournament-badge',
+ 'badge--' .. colorClass,
+ subtle and 'tournament-badge--subtle' or nil,
+ self.props.colorScheme == 'top3' and 'tournament-badge--top3' or nil
+ ),
+ children = WidgetUtil.collect(
+ tierTypeShort and HtmlWidgets.Div{
+ classes = WidgetUtil.collect(
+ 'tournament-badge__chip',
+ not subtle and 'chip--' .. COLOR_CLASSES[tournament.liquipediaTier] or nil
+ ),
+ children = chipText,
+ } or nil,
+ HtmlWidgets.Div{
+ classes = {'tournament-badge__text'},
+ children = textContent,
+ }
+ ),
}
end
diff --git a/lua/wikis/commons/Widget/Tournaments/Ticker.lua b/lua/wikis/commons/Widget/Tournaments/Ticker.lua
index 859a63f17ff..2e6f5a2dc00 100644
--- a/lua/wikis/commons/Widget/Tournaments/Ticker.lua
+++ b/lua/wikis/commons/Widget/Tournaments/Ticker.lua
@@ -7,19 +7,14 @@
local Lua = require('Module:Lua')
-local Array = Lua.import('Module:Array')
-local Condition = Lua.import('Module:Condition')
local Class = Lua.import('Module:Class')
-local DateExt = Lua.import('Module:Date/Ext')
local I18n = Lua.import('Module:I18n')
local Logic = Lua.import('Module:Logic')
-local Operator = Lua.import('Module:Operator')
local Widget = Lua.import('Module:Widget')
local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local Sublist = Lua.import('Module:Widget/Tournaments/Ticker/Sublist')
-
-local Tournament = Lua.import('Module:Tournament')
+local TickerData = Lua.import('Module:TournamentsTicker/Data')
---@class TournamentsTickerWidget: Widget
---@operator call(table): TournamentsTickerWidget
@@ -31,123 +26,8 @@ TournamentsTickerWidget.defaultProps = {
---@return Widget
function TournamentsTickerWidget:render()
- local upcomingDays = self.props.upcomingDays
- local completedDays = self.props.completedDays
-
- local tierThresholdModifiers = {
- [1] = self.props.modifierTier1,
- [2] = self.props.modifierTier2,
- [3] = self.props.modifierTier3,
- [4] = self.props.modifierTier4,
- [5] = self.props.modifierTier5,
- [-1] = self.props.modifierTierMisc,
- }
-
- --- The Tier Type thresholds only affect completed tournaments.
- local tierTypeThresholdModifiers = {
- ['qualifier'] = self.props.modifierTypeQualifier,
- }
-
- local currentTimestamp = DateExt.getCurrentTimestamp()
-
- ---@param tournament StandardTournament
- ---@return boolean
- local function isWithinDateRange(tournament)
- local modifiedThreshold = tierThresholdModifiers[tournament.liquipediaTier] or 0
- local modifiedCompletedThreshold = tierTypeThresholdModifiers[tournament.liquipediaTierType] or modifiedThreshold
-
- if not tournament.startDate then
- return false
- end
-
- local startDateThreshold = currentTimestamp + (upcomingDays + modifiedThreshold) * 24 * 60 * 60
- local endDateThreshold = currentTimestamp - (completedDays + modifiedCompletedThreshold) * 24 * 60 * 60
-
- if tournament.phase == 'ONGOING' then
- return true
- elseif tournament.phase == 'UPCOMING' then
- return tournament.startDate.timestamp < startDateThreshold
- elseif tournament.phase == 'FINISHED' then
- assert(tournament.endDate, 'Tournament without end date: ' .. tournament.pageName)
- return tournament.endDate.timestamp > endDateThreshold
- end
- return false
- end
-
- local lpdbFilter = Condition.Tree(Condition.BooleanOperator.all):add{
- Condition.Util.anyOf(Condition.ColumnName('status'), {'', 'finished'}),
- Condition.Node(Condition.ColumnName('liquipediatiertype'), Condition.Comparator.neq, 'Points')
- }
-
- local allTournaments = Tournament.getAllTournaments(lpdbFilter, function(tournament)
- return isWithinDateRange(tournament)
- end)
-
- ---@param phase TournamentPhase
- ---@return fun(tournament: StandardTournament): boolean
- local function filterByPhase(phase)
- return function(tournament)
- return tournament.phase == phase
- end
- end
-
- ---@param a StandardTournament
- ---@param b StandardTournament
- ---@param dateProperty 'endDate' | 'startDate'
- ---@param operator fun(a: integer, b: integer): boolean
- ---@return boolean?
- local function sortByDateProperty(a, b, dateProperty, operator)
- if not a[dateProperty] and not b[dateProperty] then
- return nil
- end
- if not a[dateProperty] then
- return true
- end
- if not b[dateProperty] then
- return false
- end
- if a[dateProperty].timestamp ~= b[dateProperty].timestamp then
- return operator(a[dateProperty].timestamp, b[dateProperty].timestamp)
- end
- return nil
- end
-
- ---@param a StandardTournament
- ---@param b StandardTournament
- ---@return boolean
- local function sortByDate(a, b)
- local endDateSort = sortByDateProperty(a, b, 'endDate', Operator.gt)
- if endDateSort ~= nil then
- return endDateSort
- end
- local startDateSort = sortByDateProperty(a, b, 'startDate', Operator.gt)
- if startDateSort ~= nil then
- return startDateSort
- end
- return a.pageName < b.pageName
- end
-
- ---@param a StandardTournament
- ---@param b StandardTournament
- ---@return boolean
- local function sortByDateUpcoming(a, b)
- local endDateSort = sortByDateProperty(a, b, 'startDate', Operator.gt)
- if endDateSort ~= nil then
- return endDateSort
- end
- local startDateSort = sortByDateProperty(a, b, 'endDate', Operator.gt)
- if startDateSort ~= nil then
- return startDateSort
- end
- return a.pageName < b.pageName
- end
-
- local upcomingTournaments = Array.filter(allTournaments, filterByPhase('UPCOMING'))
- local ongoingTournaments = Array.filter(allTournaments, filterByPhase('ONGOING'))
- local completedTournaments = Array.filter(allTournaments, filterByPhase('FINISHED'))
- table.sort(upcomingTournaments, sortByDateUpcoming)
- table.sort(ongoingTournaments, sortByDate)
- table.sort(completedTournaments, sortByDate)
+ local data = TickerData.get(self.props)
+ local displayGameIcons = Logic.readBool(self.props.displayGameIcons)
local fallbackElement = HtmlWidgets.Div{
attributes = {
@@ -164,21 +44,18 @@ function TournamentsTickerWidget:render()
}
}
-
- local displayGameIcons = Logic.readBool(self.props.displayGameIcons)
-
return HtmlWidgets.Div{
children = {
- HtmlWidgets.Ul{
+ HtmlWidgets.Div{
classes = {'tournaments-list'},
attributes = {
['data-filter-hideable-group'] = '',
['data-filter-effect'] = 'fade',
},
children = {
- Sublist{title = 'Upcoming', tournaments = upcomingTournaments, displayGameIcons = displayGameIcons} ,
- Sublist{title = 'Ongoing', tournaments = ongoingTournaments, displayGameIcons = displayGameIcons},
- Sublist{title = 'Completed', tournaments = completedTournaments, displayGameIcons = displayGameIcons},
+ Sublist{title = 'Upcoming', tournaments = data.upcoming, displayGameIcons = displayGameIcons},
+ Sublist{title = 'Ongoing', tournaments = data.ongoing, displayGameIcons = displayGameIcons},
+ Sublist{title = 'Completed', tournaments = data.completed, displayGameIcons = displayGameIcons},
fallbackElement
}
}
diff --git a/lua/wikis/commons/Widget/Tournaments/Ticker/List.lua b/lua/wikis/commons/Widget/Tournaments/Ticker/List.lua
new file mode 100644
index 00000000000..30fdc8af848
--- /dev/null
+++ b/lua/wikis/commons/Widget/Tournaments/Ticker/List.lua
@@ -0,0 +1,103 @@
+---
+-- @Liquipedia
+-- page=Module:Widget/Tournaments/Ticker/List
+--
+-- Please see https://github.com/Liquipedia/Lua-Modules to contribute
+--
+
+local Lua = require('Module:Lua')
+
+local Class = Lua.import('Module:Class')
+local I18n = Lua.import('Module:I18n')
+local Widget = Lua.import('Module:Widget')
+local ContentSwitch = Lua.import('Module:Widget/ContentSwitch')
+local HtmlWidgets = Lua.import('Module:Widget/Html/All')
+local ListItem = Lua.import('Module:Widget/Tournaments/Ticker/ListItem')
+local PhaseCollapsible = Lua.import('Module:Widget/Tournaments/Ticker/PhaseCollapsible')
+local Sublist = Lua.import('Module:Widget/Tournaments/Ticker/Sublist')
+local TickerData = Lua.import('Module:TournamentsTicker/Data')
+
+---@class TournamentsTickerListWidgetProps: TournamentsTickerDataProps
+---@field variant 'tabs'|'collapsible'?
+---@field displayGameIcons boolean?
+---@field tierColorScheme string?
+
+---@class TournamentsTickerListWidget: Widget
+---@operator call(TournamentsTickerListWidgetProps): TournamentsTickerListWidget
+---@field props TournamentsTickerListWidgetProps
+local TournamentsTickerListWidget = Class.new(Widget)
+TournamentsTickerListWidget.defaultProps = {
+ upcomingDays = 5,
+ completedDays = 5,
+ variant = 'tabs',
+}
+
+---@return Widget
+function TournamentsTickerListWidget:render()
+ local data = TickerData.get(self.props)
+ local displayGameIcons = self.props.displayGameIcons
+
+ ---@param tournament StandardTournament
+ ---@return Widget
+ local function createItem(tournament)
+ return ListItem{
+ tournament = tournament,
+ displayGameIcon = displayGameIcons,
+ tierColorScheme = self.props.tierColorScheme,
+ }
+ end
+
+ ---@param tournaments StandardTournament[]
+ ---@return Widget
+ local function buildSublist(tournaments)
+ return Sublist{
+ tournaments = tournaments,
+ createItem = createItem,
+ fallback = HtmlWidgets.Div{
+ attributes = {
+ ['data-filter-hideable-group-fallback'] = '',
+ ['data-filter-effect'] = 'fade',
+ },
+ children = HtmlWidgets.Center{
+ css = {margin = '1.5rem 0', ['font-style'] = 'italic'},
+ children = I18n.translate('tournament-ticker-no-tournaments'),
+ },
+ },
+ }
+ end
+
+ local tabsWidget = ContentSwitch{
+ css = { margin = '0.75rem'},
+ switchGroup = 'tournament-list-phase',
+ defaultActive = 2,
+ storeValue = false,
+ tabs = {
+ {label = 'Upcoming', value = 'upcoming', content = buildSublist(data.upcoming)},
+ {label = 'Ongoing', value = 'ongoing', content = buildSublist(data.ongoing)},
+ {label = 'Completed', value = 'completed', content = buildSublist(data.completed)},
+ },
+ }
+
+ if self.props.variant ~= 'collapsible' then
+ return tabsWidget
+ end
+
+ return HtmlWidgets.Div{
+ children = {
+ HtmlWidgets.Div{
+ classes = {'tournaments-list--tabs'},
+ children = tabsWidget,
+ },
+ HtmlWidgets.Div{
+ classes = {'tournaments-list--collapsible'},
+ children = {
+ PhaseCollapsible{label = 'Ongoing', children = buildSublist(data.ongoing)},
+ PhaseCollapsible{label = 'Upcoming', children = buildSublist(data.upcoming)},
+ PhaseCollapsible{label = 'Completed', collapsed = true, children = buildSublist(data.completed)},
+ },
+ },
+ },
+ }
+end
+
+return TournamentsTickerListWidget
diff --git a/lua/wikis/commons/Widget/Tournaments/Ticker/ListItem.lua b/lua/wikis/commons/Widget/Tournaments/Ticker/ListItem.lua
new file mode 100644
index 00000000000..41d148d6dfb
--- /dev/null
+++ b/lua/wikis/commons/Widget/Tournaments/Ticker/ListItem.lua
@@ -0,0 +1,98 @@
+---
+-- @Liquipedia
+-- page=Module:Widget/Tournaments/Ticker/ListItem
+--
+-- Please see https://github.com/Liquipedia/Lua-Modules to contribute
+--
+
+local Lua = require('Module:Lua')
+
+local Class = Lua.import('Module:Class')
+local Game = Lua.import('Module:Game')
+local LeagueIcon = Lua.import('Module:LeagueIcon')
+local WidgetUtil = Lua.import('Module:Widget/Util')
+local Widget = Lua.import('Module:Widget')
+local HtmlWidgets = Lua.import('Module:Widget/Html/All')
+local DateRange = Lua.import('Module:Widget/Misc/DateRange')
+local Link = Lua.import('Module:Widget/Basic/Link')
+local TierPill = Lua.import('Module:Widget/Tournament/TierPill')
+
+---@class TournamentsTickerListItemProps
+---@field tournament StandardTournament
+---@field displayGameIcon boolean
+---@field tierColorScheme string?
+
+---@class TournamentsTickerListItemWidget: Widget
+---@operator call(TournamentsTickerListItemProps): TournamentsTickerListItemWidget
+---@field props TournamentsTickerListItemProps
+local TournamentsTickerListItemWidget = Class.new(Widget)
+
+---@return Widget?
+function TournamentsTickerListItemWidget:render()
+ local tournament = self.props.tournament
+ if not tournament then
+ return
+ end
+
+ local iconWidget = LeagueIcon.display{
+ icon = tournament.icon,
+ iconDark = tournament.iconDark,
+ series = tournament.series,
+ link = tournament.pageName,
+ options = {noTemplate = true},
+ }
+
+ local badgeChildren = WidgetUtil.collect(
+ iconWidget,
+ self.props.displayGameIcon and Game.icon{
+ game = tournament.game,
+ noLink = true,
+ spanClass = 'tournaments-list-item__game-icon',
+ } or nil,
+ TierPill{
+ tournament = tournament,
+ variant = 'subtle',
+ colorScheme = self.props.tierColorScheme,
+ }
+ )
+
+ return HtmlWidgets.Div{
+ classes = {'tournaments-list-item'},
+ children = {
+ HtmlWidgets.Span{
+ classes = {'tournament-icon'},
+ children = iconWidget,
+ },
+ HtmlWidgets.Div{
+ classes = {'tournaments-list-item__content'},
+ children = {
+ HtmlWidgets.Div{
+ classes = {'tournaments-list-item__name'},
+ children = Link{
+ link = tournament.pageName,
+ children = tournament.displayName,
+ },
+ },
+ HtmlWidgets.Div{
+ classes = {'tournaments-list-item__meta'},
+ children = {
+ HtmlWidgets.Div{
+ classes = {'tournaments-list-item__badges'},
+ children = badgeChildren,
+ },
+ HtmlWidgets.Div{
+ classes = {'tournaments-list-item__date'},
+ children = DateRange{
+ startDate = tournament.startDate,
+ endDate = tournament.endDate,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+end
+
+return TournamentsTickerListItemWidget
diff --git a/lua/wikis/commons/Widget/Tournaments/Ticker/PhaseCollapsible.lua b/lua/wikis/commons/Widget/Tournaments/Ticker/PhaseCollapsible.lua
new file mode 100644
index 00000000000..868246c6440
--- /dev/null
+++ b/lua/wikis/commons/Widget/Tournaments/Ticker/PhaseCollapsible.lua
@@ -0,0 +1,49 @@
+---
+-- @Liquipedia
+-- page=Module:Widget/Tournaments/Ticker/PhaseCollapsible
+--
+-- Please see https://github.com/Liquipedia/Lua-Modules to contribute
+--
+
+local Lua = require('Module:Lua')
+
+local Class = Lua.import('Module:Class')
+
+local Widget = Lua.import('Module:Widget')
+local ChevronToggle = Lua.import('Module:Widget/GeneralCollapsible/ChevronToggle')
+local GeneralCollapsible = Lua.import('Module:Widget/GeneralCollapsible/Default')
+local HtmlWidgets = Lua.import('Module:Widget/Html/All')
+
+---@class TournamentsTickerPhaseCollapsibleProps
+---@field label string
+---@field children Widget|Widget[]
+---@field collapsed boolean?
+
+---@class TournamentsTickerPhaseCollapsible: Widget
+---@operator call(TournamentsTickerPhaseCollapsibleProps): TournamentsTickerPhaseCollapsible
+---@field props TournamentsTickerPhaseCollapsibleProps
+local TournamentsTickerPhaseCollapsible = Class.new(Widget)
+
+---@return Widget
+function TournamentsTickerPhaseCollapsible:render()
+ return GeneralCollapsible{
+ classes = {'tournaments-phase-collapsible'},
+ shouldCollapse = self.props.collapsed,
+ titleWidget = HtmlWidgets.Div{
+ classes = {'tournaments-phase-collapsible__header'},
+ attributes = {
+ ['data-collapsible-click-region'] = 'true',
+ },
+ children = {
+ HtmlWidgets.Span{
+ classes = {'tournaments-phase-collapsible__label'},
+ children = self.props.label,
+ },
+ ChevronToggle{},
+ },
+ },
+ children = self.props.children,
+ }
+end
+
+return TournamentsTickerPhaseCollapsible
diff --git a/lua/wikis/commons/Widget/Tournaments/Ticker/Sublist.lua b/lua/wikis/commons/Widget/Tournaments/Ticker/Sublist.lua
index d13d1bcd0df..6c81f26c3c8 100644
--- a/lua/wikis/commons/Widget/Tournaments/Ticker/Sublist.lua
+++ b/lua/wikis/commons/Widget/Tournaments/Ticker/Sublist.lua
@@ -11,14 +11,17 @@ local Array = Lua.import('Module:Array')
local Class = Lua.import('Module:Class')
local Widget = Lua.import('Module:Widget')
+local WidgetUtil = Lua.import('Module:Widget/Util')
local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local TournamentLabel = Lua.import('Module:Widget/Tournament/Label')
local FilterConfig = Lua.import('Module:FilterButtons/Config')
---@class TournamentsTickerSublistWidgetProps
----@field title string
+---@field title string?
---@field tournaments StandardTournament[]
---@field displayGameIcons boolean
+---@field createItem (fun(tournament: StandardTournament): Widget)?
+---@field fallback Widget?
---@class TournamentsTickerSublistWidget: Widget
---@operator call(TournamentsTickerSublistWidgetProps): TournamentsTickerSublistWidget
@@ -31,6 +34,13 @@ function TournamentsTickerSublistWidget:render()
return
end
+ local createItem = self.props.createItem or function(tournament)
+ return TournamentLabel{
+ tournament = tournament,
+ displayGameIcon = self.props.displayGameIcons,
+ }
+ end
+
---@param tournament StandardTournament
---@param child Widget
---@return Widget
@@ -54,27 +64,23 @@ function TournamentsTickerSublistWidget:render()
local list = HtmlWidgets.Ul{
classes = {'tournaments-list-type-list'},
children = Array.map(self.props.tournaments, function(tournament)
- return HtmlWidgets.Li{children = createFilterWrapper(tournament, TournamentLabel{
- tournament = tournament,
- displayGameIcon = self.props.displayGameIcons
- })}
+ return HtmlWidgets.Li{children = createFilterWrapper(tournament, createItem(tournament))}
end),
}
- return HtmlWidgets.Li{
+ return HtmlWidgets.Div{
attributes = {
['data-filter-hideable-group'] = '',
['data-filter-effect'] = 'fade',
},
- children = {
- HtmlWidgets.Span{
+ children = WidgetUtil.collect(
+ self.props.title and HtmlWidgets.Span{
classes = {'tournaments-list-heading'},
children = self.props.title,
- },
- HtmlWidgets.Div{
- children = list,
- }
- },
+ } or nil,
+ list,
+ self.props.fallback
+ ),
}
end
diff --git a/lua/wikis/fortnite/MainPageLayout/data.lua b/lua/wikis/fortnite/MainPageLayout/data.lua
index b0827e447cd..7383f7eeaf1 100644
--- a/lua/wikis/fortnite/MainPageLayout/data.lua
+++ b/lua/wikis/fortnite/MainPageLayout/data.lua
@@ -10,7 +10,7 @@ local Lua = require('Module:Lua')
local MainPageLayoutUtil = Lua.import('Module:MainPageLayout/Util')
local FilterButtonsWidget = Lua.import('Module:Widget/FilterButtons')
-local TournamentsTicker = Lua.import('Module:Widget/Tournaments/Ticker')
+local TournamentsTicker = Lua.import('Module:Widget/Tournaments/Ticker/List')
local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local Div = HtmlWidgets.Div
@@ -62,9 +62,10 @@ local CONTENT = {
heading = 'Tournaments',
body = TournamentsTicker{
upcomingDays = 14,
- completedDays = 7
+ completedDays = 7,
+ variant = 'collapsible',
},
- padding = true,
+ padding = false,
boxid = MainPageLayoutUtil.BoxId.TOURNAMENTS_TICKER,
},
}
diff --git a/lua/wikis/leagueoflegends/MainPageLayout/data.lua b/lua/wikis/leagueoflegends/MainPageLayout/data.lua
index a9c3188f4df..30285ff75e7 100644
--- a/lua/wikis/leagueoflegends/MainPageLayout/data.lua
+++ b/lua/wikis/leagueoflegends/MainPageLayout/data.lua
@@ -16,7 +16,7 @@ local Comparator = Condition.Comparator
local ColumnName = Condition.ColumnName
local FilterButtonsWidget = Lua.import('Module:Widget/FilterButtons')
-local TournamentsTicker = Lua.import('Module:Widget/Tournaments/Ticker')
+local TournamentsTicker = Lua.import('Module:Widget/Tournaments/Ticker/List')
local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local Div = HtmlWidgets.Div
@@ -102,9 +102,10 @@ local CONTENT = {
modifierTypeQualifier = -2,
modifierTier1 = 55,
modifierTier2 = 55,
- modifierTier3 = 10
+ modifierTier3 = 10,
+ tierColorScheme = 'top3',
},
- padding = true,
+ padding = false,
boxid = MainPageLayoutUtil.BoxId.TOURNAMENTS_TICKER,
},
headlines = {
diff --git a/lua/wikis/pubgmobile/MainPageLayout/data.lua b/lua/wikis/pubgmobile/MainPageLayout/data.lua
index 7ee8d5ddfe8..e54fa7e6046 100644
--- a/lua/wikis/pubgmobile/MainPageLayout/data.lua
+++ b/lua/wikis/pubgmobile/MainPageLayout/data.lua
@@ -10,7 +10,7 @@ local Lua = require('Module:Lua')
local MainPageLayoutUtil = Lua.import('Module:MainPageLayout/Util')
local FilterButtonsWidget = Lua.import('Module:Widget/FilterButtons')
-local TournamentsTicker = Lua.import('Module:Widget/Tournaments/Ticker')
+local TournamentsTicker = Lua.import('Module:Widget/Tournaments/Ticker/List')
local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local Div = HtmlWidgets.Div
@@ -68,9 +68,9 @@ local CONTENT = {
heading = 'Tournaments',
body = TournamentsTicker{
upcomingDays = 30,
- completedDays = 30
+ completedDays = 30,
},
- padding = true,
+ padding = false,
boxid = MainPageLayoutUtil.BoxId.TOURNAMENTS_TICKER,
},
headlines = {
diff --git a/lua/wikis/trackmania/MainPageLayout/data.lua b/lua/wikis/trackmania/MainPageLayout/data.lua
index 8adcb77ca84..1adfe826969 100644
--- a/lua/wikis/trackmania/MainPageLayout/data.lua
+++ b/lua/wikis/trackmania/MainPageLayout/data.lua
@@ -11,7 +11,7 @@ local MainPageLayoutUtil = Lua.import('Module:MainPageLayout/Util')
local FilterButtonsWidget = Lua.import('Module:Widget/FilterButtons')
local MatchTicker = Lua.import('Module:Widget/MainPage/MatchTicker')
-local TournamentsTicker = Lua.import('Module:Widget/Tournaments/Ticker')
+local TournamentsTicker = Lua.import('Module:Widget/Tournaments/Ticker/List')
local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local Div = HtmlWidgets.Div
@@ -72,8 +72,10 @@ local CONTENT = {
upcomingDays = 30,
modifierTier1 = 50,
completedDays = 20,
+ tierColorScheme = 'top3',
+ variant = 'collapsible',
},
- padding = true,
+ padding = false,
boxid = MainPageLayoutUtil.BoxId.TOURNAMENTS_TICKER,
},
}
diff --git a/stylesheets/commons/Mainpage.scss b/stylesheets/commons/Mainpage.scss
index e3bad969567..f57d3a1ee70 100644
--- a/stylesheets/commons/Mainpage.scss
+++ b/stylesheets/commons/Mainpage.scss
@@ -84,6 +84,190 @@ div.main-page-banner .main-page-banner-bottom-row {
list-style-type: none;
}
+.tournaments-list-item {
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+ padding: 0.5rem;
+ border-bottom: 1px solid;
+ border-color: var( --clr-on-surface-light-primary-8 );
+
+ .theme--dark & {
+ border-color: var( --clr-on-surface-dark-primary-8 );
+ }
+
+ > .tournament-icon {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 0.25rem;
+ width: 2.25rem;
+ height: 2.25rem;
+
+ @media ( max-width: 359px ) {
+ display: none;
+ }
+ }
+
+ &__content {
+ flex: 1;
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+ font-weight: bold;
+ gap: 0.125rem;
+ }
+
+ &__name {
+ font-size: 0.8125rem;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ &__meta {
+ display: flex;
+ justify-content: space-between;
+ }
+
+ &__badges {
+ display: flex;
+ gap: 0.25rem;
+
+ > .league-icon-small-image {
+ width: 1.25rem;
+ height: 1.25rem;
+ min-width: unset;
+ min-height: unset;
+ padding: 0.125rem;
+ background-color: var( --clr-on-surface-light-primary-4 );
+ border-radius: 0.25rem;
+ flex-shrink: 0;
+ overflow: hidden;
+
+ @media ( min-width: 360px ) {
+ display: none;
+ }
+
+ img {
+ max-width: 1rem;
+ max-height: 1rem;
+ }
+
+ i {
+ font-size: 0.75rem;
+ }
+
+ .theme--dark & {
+ background-color: var( --clr-on-surface-dark-primary-4 );
+ }
+ }
+ }
+
+ &__game-icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 1.25rem;
+ height: 1.25rem;
+ background-color: var( --clr-on-surface-light-primary-4 );
+ border-radius: 0.25rem;
+ padding: 0.125rem;
+
+ .theme--dark & {
+ background-color: var( --clr-on-surface-dark-primary-4 );
+ }
+
+ img {
+ max-width: 100%;
+ max-height: 100%;
+ }
+ }
+
+ &__date {
+ font-size: 0.6875rem;
+ line-height: 1rem;
+ background-color: var( --clr-on-surface-light-primary-8 );
+ color: var( --clr-secondary-25 );
+ border-radius: 0.25rem;
+ padding: 0.125rem 0.5rem;
+
+ .theme--dark & {
+ background-color: var( --clr-on-surface-dark-primary-8 );
+ color: var( --clr-secondary-100 );
+ }
+ }
+}
+
+.tournaments-list--collapsible {
+ display: none;
+
+ @media ( min-width: 1024px ) {
+ display: block;
+ }
+}
+
+@media ( min-width: 1024px ) {
+ .tournaments-list--tabs {
+ display: none;
+ }
+}
+
+.tournaments-phase-collapsible {
+ &:last-child.collapsed {
+ padding-bottom: 0.75rem;
+ }
+
+ &__header {
+ background-color: var( --clr-on-surface-light-primary-4 );
+ border-radius: 0.625rem;
+ padding: 0.625rem 0.75rem;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ user-select: none;
+ margin: 0.75rem 0.75rem 0.25rem;
+
+ & + & {
+ margin-top: 0;
+ }
+
+ &:hover {
+ background-color: var( --clr-on-surface-light-primary-12 );
+ }
+
+ .theme--dark & {
+ background-color: var( --clr-on-surface-dark-primary-4 );
+
+ &:hover {
+ background-color: var( --clr-on-surface-dark-primary-12 );
+ }
+ }
+ }
+
+ &__label {
+ flex: 1;
+ font-size: 0.875rem;
+ font-weight: bold;
+ color: var( --clr-secondary-25 );
+
+ .theme--dark & {
+ color: var( --clr-secondary-100 );
+ }
+ }
+
+ .general-collapsible-expand-button,
+ .general-collapsible-collapse-button {
+ outline: unset;
+ color: var( --clr-secondary-25 );
+
+ .theme--dark & {
+ color: var( --clr-secondary-100 );
+ opacity: 0.7;
+ }
+ }
+}
+
.tournaments-list-dates {
float: right;
padding-right: 10px;
diff --git a/stylesheets/commons/Miscellaneous.scss b/stylesheets/commons/Miscellaneous.scss
index 3916c85b756..1f49ac0ac1f 100644
--- a/stylesheets/commons/Miscellaneous.scss
+++ b/stylesheets/commons/Miscellaneous.scss
@@ -363,6 +363,10 @@ span.icon-small {
a {
display: contents;
}
+
+ i {
+ font-size: 1.125rem;
+ }
}
/* LeagueIconSmall dark mode support */
diff --git a/stylesheets/commons/TournamentTags.scss b/stylesheets/commons/TournamentTags.scss
index bc3a8a23852..0df3da88922 100644
--- a/stylesheets/commons/TournamentTags.scss
+++ b/stylesheets/commons/TournamentTags.scss
@@ -139,3 +139,140 @@ $showmatch-border-color: var( --tournament-tag-showmatch-badge-border-color, #00
justify-content: center;
}
}
+
+.tournament-badge--subtle {
+ height: auto;
+ width: auto;
+ background-color: var( --clr-on-surface-light-primary-4 ) !important;
+ border-width: 0;
+ border-left: 0.25rem solid;
+ border-left-color: var( --tournament-badge-color ) !important;
+ border-radius: 0.25rem;
+ padding: 0.125rem 0.5rem;
+ gap: 0.375rem;
+
+ .theme--dark & {
+ background-color: var( --clr-on-surface-dark-primary-4 ) !important;
+ }
+
+ .tournament-badge__chip {
+ width: auto;
+ height: auto;
+ padding: 0 0.375rem;
+ background-color: var( --clr-on-surface-light-primary-8 );
+ color: var( --clr-secondary-25 );
+ font-size: 0.6875rem;
+ font-weight: bold;
+ line-height: 1rem;
+ margin-left: -0.25rem;
+
+ .theme--dark & {
+ background-color: var( --clr-on-surface-dark-primary-8 );
+ color: var( --clr-secondary-100 );
+ }
+ }
+
+ &.badge--tier1 {
+ --tournament-badge-color: #ef6532;
+
+ .theme--dark & {
+ --tournament-badge-color: #ff4500;
+ }
+ }
+
+ &.badge--tier2 {
+ --tournament-badge-color: #b38f00;
+
+ .theme--dark & {
+ --tournament-badge-color: #ffcc00;
+ }
+ }
+
+ &.badge--tier3 {
+ --tournament-badge-color: #0097ca;
+
+ .theme--dark & {
+ --tournament-badge-color: #00bfff;
+ }
+ }
+
+ &.badge--tier4 {
+ --tournament-badge-color: #2d712f;
+
+ .theme--dark & {
+ --tournament-badge-color: #65c877;
+ }
+ }
+
+ &.badge--tier5 {
+ --tournament-badge-color: #9166ff;
+
+ .theme--dark & {
+ --tournament-badge-color: #8858ff;
+ }
+ }
+
+ &.badge--misc,
+ &.badge--qualifier,
+ &.badge--monthly,
+ &.badge--weekly,
+ &.badge--showmatch {
+ --tournament-badge-color: #949494;
+
+ .theme--dark & {
+ --tournament-badge-color: #707176;
+ }
+ }
+
+ &.tournament-badge--top3 {
+ &.badge--tier1 {
+ --tournament-badge-color: #f16c0e;
+
+ .theme--dark & {
+ --tournament-badge-color: #ffa500;
+ }
+ }
+
+ &.badge--tier2 {
+ --tournament-badge-color: #2563eb;
+
+ .theme--dark & {
+ --tournament-badge-color: #3b82f6;
+ }
+ }
+
+ &.badge--tier3 {
+ --tournament-badge-color: #262626;
+
+ .theme--dark & {
+ --tournament-badge-color: #ffffff;
+ }
+ }
+
+ &.badge--tier4,
+ &.badge--tier5,
+ &.badge--misc,
+ &.badge--qualifier,
+ &.badge--monthly,
+ &.badge--weekly,
+ &.badge--showmatch {
+ --tournament-badge-color: #949494;
+
+ .theme--dark & {
+ --tournament-badge-color: #8d8d8d;
+ }
+ }
+ }
+
+ .tournament-badge__text {
+ color: var( --clr-secondary-25 );
+ font-size: 0.6875rem;
+ font-weight: bold;
+ line-height: 1rem;
+ justify-content: flex-start;
+
+ .theme--dark & {
+ color: var( --clr-secondary-100 );
+ }
+ }
+}