From 332a675fe810ea851c1d8b439289c07c2d453286 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Sun, 22 Mar 2026 17:30:15 +0900 Subject: [PATCH 01/13] use label in swiss standings --- .../Widget/Standings/MatchOverview.lua | 95 +++++++++++++++---- lua/wikis/commons/Widget/Standings/Swiss.lua | 19 +--- stylesheets/commons/Label.scss | 36 +++---- 3 files changed, 98 insertions(+), 52 deletions(-) diff --git a/lua/wikis/commons/Widget/Standings/MatchOverview.lua b/lua/wikis/commons/Widget/Standings/MatchOverview.lua index 6997976ebc4..3f1e9d72cf6 100644 --- a/lua/wikis/commons/Widget/Standings/MatchOverview.lua +++ b/lua/wikis/commons/Widget/Standings/MatchOverview.lua @@ -9,19 +9,26 @@ local Lua = require('Module:Lua') local Array = Lua.import('Module:Array') local Class = Lua.import('Module:Class') +local FnUtil = Lua.import('Module:FnUtil') local Widget = Lua.import('Module:Widget') local HtmlWidgets = Lua.import('Module:Widget/Html/All') +local Label = Lua.import('Module:Widget/Basic/Label') +local WidgetUtil = Lua.import('Module:Widget/Util') local OpponentDisplay = Lua.import('Module:OpponentDisplay/Custom') +---@class MatchOverviewWidgetProps +---@field match MatchGroupUtilMatch +---@field showOpponent integer + ---@class MatchOverviewWidget: Widget ----@operator call(table): MatchOverviewWidget +---@operator call(MatchOverviewWidgetProps): MatchOverviewWidget +---@field props MatchOverviewWidgetProps local MatchOverviewWidget = Class.new(Widget) ---@return Widget? function MatchOverviewWidget:render() - ---@type MatchGroupUtilMatch local match = self.props.match local opponentIndexToShow = tonumber(self.props.showOpponent) if not match or not opponentIndexToShow or #match.opponents ~= 2 then @@ -40,30 +47,76 @@ function MatchOverviewWidget:render() return HtmlWidgets.Div{ css = { - ['display'] = 'flex', + display = 'flex', ['justify-content'] = 'space-between', ['flex-direction'] = 'column', ['align-items'] = 'center', + gap = '0.25rem', }, - children = { - HtmlWidgets.Span{ - children = OpponentDisplay.BlockOpponent{ - opponent = opponentToShow, - overflow = 'ellipsis', - teamStyle = 'icon', - } - }, - HtmlWidgets.Span{ - css = { - ['font-size'] = '0.8em', - }, - children = { - OpponentDisplay.InlineScore(leftOpponent), - ' - ', - OpponentDisplay.InlineScore(opponentToShow), - }, - }, + children = WidgetUtil.collect( + self:_createResultDisplay( + OpponentDisplay.InlineScore(leftOpponent), + OpponentDisplay.InlineScore(opponentToShow) + ), + OpponentDisplay.InlineOpponent{ + opponent = opponentToShow, + overflow = 'ellipsis', + teamStyle = 'icon', + } + ), + } +end + +---@private +---@param self MatchOverviewWidget +---@return string +MatchOverviewWidget._getMatchResultType = FnUtil.memoize(function (self) + local match = self.props.match + local opponentIndexToShow = tonumber(self.props.showOpponent) + + if match.winner == opponentIndexToShow then + return 'loss' + elseif match.winner == 0 then + return 'draw' + end + return 'win' +end) + +---@private +---@param leftScore string +---@param rightScore string +---@return Widget[] +function MatchOverviewWidget:_createScoreContainer(leftScore, rightScore) + local resultType = self:_getMatchResultType() + return { + HtmlWidgets.Span{ + css = resultType == 'win' and {['font-weight'] = 'bold'} or nil, + children = leftScore + }, + HtmlWidgets.Span{children = ':'}, + HtmlWidgets.Span{ + css = resultType == 'loss' and {['font-weight'] = 'bold'} or nil, + children = rightScore + } + } +end + +---@private +---@return Widget? +function MatchOverviewWidget:_createResultDisplay(leftScore, rightScore) + if not self.props.match.finished then + return + end + local resultType = self:_getMatchResultType() + return Label{ + css = { + display = 'grid', + ['grid-template-columns'] = '1fr auto 1fr', + ['justify-items'] = 'center', + padding = '0.25rem', }, + labelType = 'result-' .. resultType, + children = self:_createScoreContainer(leftScore, rightScore) } end diff --git a/lua/wikis/commons/Widget/Standings/Swiss.lua b/lua/wikis/commons/Widget/Standings/Swiss.lua index 583610bcc9a..de350fd41a8 100644 --- a/lua/wikis/commons/Widget/Standings/Swiss.lua +++ b/lua/wikis/commons/Widget/Standings/Swiss.lua @@ -120,21 +120,10 @@ function StandingsSwissWidget:render() return HtmlWidgets.Td{} end - local bgClassSuffix - if match.finished then - local winner = match.winner - bgClassSuffix = winner == opposingOpponentIndex and 'down' or winner == 0 and 'draw' or 'up' - end - - return HtmlWidgets.Td{ - classes = { - bgClassSuffix and ('bg-' .. bgClassSuffix) or nil, - }, - children = MatchOverview{ - match = match, - showOpponent = opposingOpponentIndex, - }, - } + return HtmlWidgets.Td{children = MatchOverview{ + match = match, + showOpponent = opposingOpponentIndex, + }} end) ), } diff --git a/stylesheets/commons/Label.scss b/stylesheets/commons/Label.scss index d2f0ca97369..5123bef7b2a 100644 --- a/stylesheets/commons/Label.scss +++ b/stylesheets/commons/Label.scss @@ -9,7 +9,7 @@ padding: calc( var( --label-scale ) * 0.125rem ) calc( var( --label-scale ) * 0.5rem ); display: inline-flex; align-items: center; - justify-content: center; + place-content: center center; gap: calc( var( --label-scale ) * 0.25rem ); align-self: center; white-space: nowrap; @@ -75,26 +75,30 @@ } } - &[ data-label-type^="result" ]:empty { + &[ data-label-type^="result" ] { height: calc( var( --label-scale ) * 1.25rem ); - width: calc( var( --label-scale ) * 1.25rem ); - font-weight: bold; - padding: unset; + gap: unset; - &[ data-label-type="result-win" ]::before { - content: "W"; - } + &:empty { + width: calc( var( --label-scale ) * 1.25rem ); + font-weight: bold; + padding: unset; - &[ data-label-type="result-draw" ]::before { - content: "D"; - } + &[ data-label-type="result-win" ]::before { + content: "W"; + } - &[ data-label-type="result-loss" ]::before { - content: "L"; - } + &[ data-label-type="result-draw" ]::before { + content: "D"; + } + + &[ data-label-type="result-loss" ]::before { + content: "L"; + } - &[ data-label-type="result-default" ]::before { - content: "-"; + &[ data-label-type="result-default" ]::before { + content: "-"; + } } } From c91b7631cf4fa495bbeb31d9b1cb242f6813ee28 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:03:11 +0900 Subject: [PATCH 02/13] implement placement labels --- stylelint.config.mjs | 1 + stylesheets/commons/Label.scss | 87 ++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/stylelint.config.mjs b/stylelint.config.mjs index 9e18b4a72fd..c6d46bd5c98 100644 --- a/stylelint.config.mjs +++ b/stylelint.config.mjs @@ -18,6 +18,7 @@ export default { "no-duplicate-selectors": null, "function-url-no-scheme-relative": null, "declaration-no-important": null, + "function-disallowed-list": null, "function-no-unknown": null, "scss/function-no-unknown": true, "@stylistic/string-quotes": "double" diff --git a/stylesheets/commons/Label.scss b/stylesheets/commons/Label.scss index 5123bef7b2a..897c3fb94da 100644 --- a/stylesheets/commons/Label.scss +++ b/stylesheets/commons/Label.scss @@ -106,4 +106,91 @@ text-transform: uppercase; font-weight: bold; } + + &.label--placement { + height: calc( var( --label-scale ) * 1.25rem ); + width: calc( var( --label-scale ) * 1.25rem ); + font-weight: bold; + color: var( --placement-text-color ); + background-color: var( --placement-solid-color ); + + --placement-text-color: var( --clr-secondary-100, #ffffff ); + + .theme--dark & { + --placement-text-color: var( --clr-secondary-9, #181818 ); + } + + &:not( [ data-placement-type ] ) { + --placement-solid-color: var( --clr-on-surface-light-primary-4 ); + --placement-text-color: var( --clr-secondary-25 ); + + .theme--dark & { + --placement-solid-color: var( --clr-on-surface-dark-primary-8 ); + --placement-text-color: var( --clr-secondary-90 ); + } + } + + &[ data-label-type="placement-minimum" ] { + color: var( --placement-solid-color ); + background-color: rgb( from var( --placement-solid-color ) r g b / 0.08 ); + box-shadow: 0 0 0 calc( var( --label-scale ) * 0.0125rem ) var( --placement-solid-color ) inset; + } + + &[ data-placement-type="byeup" ] { + --placement-solid-color: #8046a3; + + .theme--dark & { + --placement-solid-color: #cc9fe7; + } + } + + &[ data-placement-type="seedup" ] { + --placement-solid-color: #006bd4; + + .theme--dark & { + --placement-solid-color: #a9caeb; + } + } + + &[ data-placement-type="up" ] { + --placement-solid-color: var( --clr-semantic-positive-30 ); + + .theme--dark & { + --placement-solid-color: #65a765; + } + } + + &[ data-placement-type="stayup" ] { + --placement-solid-color: #094e09; + + .theme--dark & { + --placement-solid-color: #b6f8b6; + } + } + + &[ data-placement-type="stay" ] { + --placement-solid-color: #966f00; + + .theme--dark & { + --placement-solid-color: #e5c976; + } + } + + &[ data-placement-type="staydown" ] { + --placement-solid-color: #d4400f; + + .theme--dark & { + --placement-solid-color: #f2a288; + } + } + + &[ data-placement-type="down" ], + &[ data-placement-type="drop" ] { + --placement-solid-color: var( --clr-semantic-negative-40 ); + + .theme--dark & { + --placement-solid-color: #fc6868; + } + } + } } From f41db82d24e82e3ffcb8d196761d046205930d62 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:11:21 +0900 Subject: [PATCH 03/13] type annotation --- lua/wikis/commons/Widget/Standings/Swiss.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lua/wikis/commons/Widget/Standings/Swiss.lua b/lua/wikis/commons/Widget/Standings/Swiss.lua index de350fd41a8..f379bff9afc 100644 --- a/lua/wikis/commons/Widget/Standings/Swiss.lua +++ b/lua/wikis/commons/Widget/Standings/Swiss.lua @@ -20,8 +20,12 @@ local MatchOverview = Lua.import('Module:Widget/Standings/MatchOverview') local Opponent = Lua.import('Module:Opponent/Custom') local OpponentDisplay = Lua.import('Module:OpponentDisplay/Custom') +---@class StandingsSwissWidgetProps +---@field standings StandingsModel + ---@class StandingsSwissWidget: Widget ----@operator call(table): StandingsSwissWidget +---@operator call(StandingsSwissWidgetProps): StandingsSwissWidget +---@field props StandingsSwissWidgetProps local StandingsSwissWidget = Class.new(Widget) ---@return Widget? @@ -30,7 +34,6 @@ function StandingsSwissWidget:render() return end - ---@type StandingsModel local standings = self.props.standings local lastRound = standings.rounds[#standings.rounds] From 52bb96a8698d9cffd8711417cee1db14370e4aa1 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:47:19 +0900 Subject: [PATCH 04/13] use table2 in swiss standings --- lua/wikis/commons/Widget/Basic/Label.lua | 10 +- lua/wikis/commons/Widget/Standings/Swiss.lua | 185 ++++++++++--------- stylesheets/commons/Label.scss | 1 - stylesheets/commons/Standings.scss | 76 +++++++- 4 files changed, 176 insertions(+), 96 deletions(-) diff --git a/lua/wikis/commons/Widget/Basic/Label.lua b/lua/wikis/commons/Widget/Basic/Label.lua index 9b34a1682d8..ea8d72a072f 100644 --- a/lua/wikis/commons/Widget/Basic/Label.lua +++ b/lua/wikis/commons/Widget/Basic/Label.lua @@ -13,6 +13,7 @@ local Widget = Lua.import('Module:Widget') local HtmlWidgets = Lua.import('Module:Widget/Html/All') ---@class GenericLabelProps +---@field attributes table? ---@field css table? ---@field children Renderable|Renderable[] ---@field labelScheme string? @@ -31,10 +32,13 @@ function GenericLabel:render() props.css = props.css or {} props.css['--label-scale'] = props.labelScale end + if props.labelType then + props.attributes = props.attributes or {} + props.attributes['data-label-type'] = props.labelType + end + return HtmlWidgets.Div{ - attributes = props.labelType and { - ['data-label-type'] = props.labelType - } or nil, + attributes = props.attributes, classes = { 'generic-label', props.labelScheme and ('label--' .. props.labelScheme) or nil, diff --git a/lua/wikis/commons/Widget/Standings/Swiss.lua b/lua/wikis/commons/Widget/Standings/Swiss.lua index f379bff9afc..754166b8080 100644 --- a/lua/wikis/commons/Widget/Standings/Swiss.lua +++ b/lua/wikis/commons/Widget/Standings/Swiss.lua @@ -14,8 +14,9 @@ local Logic = Lua.import('Module:Logic') local WidgetUtil = Lua.import('Module:Widget/Util') local Widget = Lua.import('Module:Widget') local HtmlWidgets = Lua.import('Module:Widget/Html/All') -local DataTable = Lua.import('Module:Widget/Basic/DataTable') +local Label = Lua.import('Module:Widget/Basic/Label') local MatchOverview = Lua.import('Module:Widget/Standings/MatchOverview') +local TableWidgets = Lua.import('Module:Widget/Table2/All') local Opponent = Lua.import('Module:Opponent/Custom') local OpponentDisplay = Lua.import('Module:OpponentDisplay/Custom') @@ -37,101 +38,105 @@ function StandingsSwissWidget:render() local standings = self.props.standings local lastRound = standings.rounds[#standings.rounds] - return DataTable{ - wrapperClasses = {'standings-swiss'}, - classes = {'wikitable-bordered', 'wikitable-striped'}, + return TableWidgets.Table{ + classes = {'standings-swiss'}, + title = Logic.nilIfEmpty(standings.title), children = WidgetUtil.collect( - -- Outer header - Logic.isNotEmpty(standings.title) and HtmlWidgets.Tr{children = HtmlWidgets.Th{ - attributes = { - colspan = 100, - }, - children = { - HtmlWidgets.Div{ - css = {['position'] = 'relative'}, - children = { - HtmlWidgets.Span{ - children = standings.title - }, - }, - }, - }, - }} or nil, -- Column Header - HtmlWidgets.Tr{children = WidgetUtil.collect( - HtmlWidgets.Th{children = '#'}, - HtmlWidgets.Th{children = 'Participant'}, - Array.map(standings.tiebreakers, function(tiebreaker) - if not tiebreaker.title then - return - end - return HtmlWidgets.Th{children = tiebreaker.title} - end), - Array.map(standings.rounds, function(round) - return HtmlWidgets.Th{children = round.title} - end) - )}, + self:_headerRow(), -- Rows - Array.map(lastRound.opponents, function(slot) - local positionBackground = slot.positionStatus and ('bg-' .. slot.positionStatus) or nil - local teamBackground - if slot.definitiveStatus then - teamBackground = 'bg-' .. slot.definitiveStatus + TableWidgets.TableBody{children = Array.map(lastRound.opponents, function(slot) + return self:_createRow(slot) + end)} + ) + } +end + +---@private +---@return Widget +function StandingsSwissWidget:_headerRow() + local standings = self.props.standings + + ---@param text string? + ---@return Widget + local makeHeaderCell = function(text) + return TableWidgets.CellHeader{children = text} + end + + return TableWidgets.TableHeader{children = { + TableWidgets.Row{children = WidgetUtil.collect( + makeHeaderCell('#'), + makeHeaderCell('Participant'), + Array.map(standings.tiebreakers, function(tiebreaker) + if not tiebreaker.title then + return end - return HtmlWidgets.Tr{ - children = WidgetUtil.collect( - HtmlWidgets.Td{ - children = {slot.placement, '.'}, - css = {['font-weight'] = 'bold'}, - classes = {positionBackground}, - }, - HtmlWidgets.Td{ - classes = {teamBackground}, - children = OpponentDisplay.BlockOpponent{ - opponent = slot.opponent, - overflow = 'ellipsis', - teamStyle = 'hybrid', - showPlayerTeam = true, - } - }, - Array.map(standings.tiebreakers, function(tiebreaker, tiebreakerIndex) - if not tiebreaker.title then - return - end - return HtmlWidgets.Td{ - classes = {teamBackground}, - css = {['font-weight'] = tiebreakerIndex == 1 and 'bold' or nil, ['text-align'] = 'center'}, - children = slot.tiebreakerValues[tiebreaker.id] and slot.tiebreakerValues[tiebreaker.id].display or '' - } - end), - Array.map(standings.rounds, function(columnRound) - local entry = Array.find(columnRound.opponents, function(columnSlot) - return Opponent.same(columnSlot.opponent, slot.opponent) - end) - if not entry then - return HtmlWidgets.Td{} - end - local match = entry.match - if not match then - return HtmlWidgets.Td{} - end - - local opposingOpponentIndex = Array.indexOf(match.opponents, function(opponent) - return not Opponent.same(entry.opponent, opponent) - end) - if not entry.match.opponents[opposingOpponentIndex] then - return HtmlWidgets.Td{} - end - - return HtmlWidgets.Td{children = MatchOverview{ - match = match, - showOpponent = opposingOpponentIndex, - }} - end) - ), + return HtmlWidgets.Th{children = tiebreaker.title} + end), + Array.map(standings.rounds, function(round) + return HtmlWidgets.Th{children = round.title} + end) + )} + }} +end + +---@private +---@param slot StandingsEntryModel +---@return Widget +function StandingsSwissWidget:_createRow(slot) + local standings = self.props.standings + return TableWidgets.Row{ + attributes = {['data-position-status'] = slot.positionStatus}, + children = WidgetUtil.collect( + TableWidgets.Cell{ + children = Label{ + children = slot.placement, + attributes = {['data-placement-type'] = slot.definitiveStatus}, + labelScheme = 'placement', + }, + }, + TableWidgets.Cell{ + children = OpponentDisplay.BlockOpponent{ + opponent = slot.opponent, + overflow = 'ellipsis', + teamStyle = 'hybrid', + showPlayerTeam = true, } + }, + Array.map(standings.tiebreakers, function(tiebreaker, tiebreakerIndex) + if not tiebreaker.title then + return + end + return TableWidgets.Cell{ + css = {['font-weight'] = tiebreakerIndex == 1 and 'bold' or nil, ['text-align'] = 'center'}, + children = slot.tiebreakerValues[tiebreaker.id] and slot.tiebreakerValues[tiebreaker.id].display or '' + } + end), + Array.map(standings.rounds, function(columnRound) + local entry = Array.find(columnRound.opponents, function(columnSlot) + return Opponent.same(columnSlot.opponent, slot.opponent) + end) + if not entry then + return TableWidgets.Cell{} + end + local match = entry.match + if not match then + return TableWidgets.Cell{} + end + + local opposingOpponentIndex = Array.indexOf(match.opponents, function(opponent) + return not Opponent.same(entry.opponent, opponent) + end) + if not entry.match.opponents[opposingOpponentIndex] then + return TableWidgets.Cell{} + end + + return TableWidgets.Cell{children = MatchOverview{ + match = match, + showOpponent = opposingOpponentIndex, + }} end) - ) + ), } end diff --git a/stylesheets/commons/Label.scss b/stylesheets/commons/Label.scss index 897c3fb94da..66fb3ed733a 100644 --- a/stylesheets/commons/Label.scss +++ b/stylesheets/commons/Label.scss @@ -108,7 +108,6 @@ } &.label--placement { - height: calc( var( --label-scale ) * 1.25rem ); width: calc( var( --label-scale ) * 1.25rem ); font-weight: bold; color: var( --placement-text-color ); diff --git a/stylesheets/commons/Standings.scss b/stylesheets/commons/Standings.scss index 1703250eaa0..a66299ae5d4 100644 --- a/stylesheets/commons/Standings.scss +++ b/stylesheets/commons/Standings.scss @@ -1,5 +1,4 @@ -div.standings-ffa, -div.standings-swiss { +div.standings-ffa { & > table > * > tr > th { padding: 12px; } @@ -18,3 +17,76 @@ div.standings-swiss { align-items: center; } } + +.table2.standings-swiss { + tr.table2__row--body[ data-position-status ] { + position: relative; + + &::after { + content: ""; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 0.25rem; + background-color: var( --placement-row-color ); + } + + &[ data-position-status="byeup" ] { + --placement-row-color: #8046a3; + + .theme--dark & { + --placement-row-color: #cc9fe7; + } + } + + &[ data-position-status="seedup" ] { + --placement-row-color: #006bd4; + + .theme--dark & { + --placement-row-color: #a9caeb; + } + } + + &[ data-position-status="up" ] { + --placement-row-color: var( --clr-semantic-positive-30 ); + + .theme--dark & { + --placement-row-color: #65a765; + } + } + + &[ data-position-status="stayup" ] { + --placement-row-color: #094e09; + + .theme--dark & { + --placement-row-color: #b6f8b6; + } + } + + &[ data-position-status="stay" ] { + --placement-row-color: #966f00; + + .theme--dark & { + --placement-row-color: #e5c976; + } + } + + &[ data-position-status="staydown" ] { + --placement-row-color: #d4400f; + + .theme--dark & { + --placement-row-color: #f2a288; + } + } + + &[ data-position-status="down" ], + &[ data-position-status="drop" ] { + --placement-row-color: var( --clr-semantic-negative-40 ); + + .theme--dark & { + --placement-row-color: #fc6868; + } + } + } +} From 4505641b1065f8012d4a4ba39f71ca7046fdb5de Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:50:06 +0900 Subject: [PATCH 05/13] update export config --- javascript/commons/ExportImage.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/javascript/commons/ExportImage.js b/javascript/commons/ExportImage.js index f6f6e19a6df..bfcf35805bf 100644 --- a/javascript/commons/ExportImage.js +++ b/javascript/commons/ExportImage.js @@ -83,7 +83,12 @@ const EXPORT_IMAGE_CONFIG = { typeName: 'Participants' }, { selector: '.standings-ffa', targetSelector: 'tbody', typeName: 'BR/FFA Standings Table' }, - { selector: '.standings-swiss', targetSelector: 'tbody', typeName: 'Swiss Standings Table' }, + { + selector: '.table2.standings-swiss', + targetSelector: 'table.table2__table', + titleSelector: '.table2__title', + typeName: 'Swiss Standings Table' + }, { selector: '.table2#MvpTable', targetSelector: '.table2__container', From ca6c46c1b7c2c38d4635180403c3ca7e6663a31f Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:57:49 +0900 Subject: [PATCH 06/13] adjust column definitions --- lua/wikis/commons/Widget/Standings/Swiss.lua | 22 +++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/lua/wikis/commons/Widget/Standings/Swiss.lua b/lua/wikis/commons/Widget/Standings/Swiss.lua index 754166b8080..a6dc170b155 100644 --- a/lua/wikis/commons/Widget/Standings/Swiss.lua +++ b/lua/wikis/commons/Widget/Standings/Swiss.lua @@ -41,6 +41,7 @@ function StandingsSwissWidget:render() return TableWidgets.Table{ classes = {'standings-swiss'}, title = Logic.nilIfEmpty(standings.title), + columns = self:_buildColumnDefinitions(), children = WidgetUtil.collect( -- Column Header self:_headerRow(), @@ -52,6 +53,25 @@ function StandingsSwissWidget:render() } end +---@private +---@return table[] +function StandingsSwissWidget:_buildColumnDefinitions() + local standings = self.props.standings + return WidgetUtil.collect( + {align = 'left'}, + {align = 'left'}, + Array.map(standings.tiebreakers, function(tiebreaker) + if not tiebreaker.title then + return + end + return {align = 'center'} + end), + Array.map(standings.rounds, function(round) + return {align = 'center'} + end) + ) +end + ---@private ---@return Widget function StandingsSwissWidget:_headerRow() @@ -108,7 +128,7 @@ function StandingsSwissWidget:_createRow(slot) return end return TableWidgets.Cell{ - css = {['font-weight'] = tiebreakerIndex == 1 and 'bold' or nil, ['text-align'] = 'center'}, + css = {['font-weight'] = tiebreakerIndex == 1 and 'bold' or nil}, children = slot.tiebreakerValues[tiebreaker.id] and slot.tiebreakerValues[tiebreaker.id].display or '' } end), From 384be442c2f5acf8853314a76ad0b42ff964c19c Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Wed, 25 Mar 2026 18:45:20 +0900 Subject: [PATCH 07/13] make stylelint behave --- stylelint.config.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stylelint.config.mjs b/stylelint.config.mjs index c6d46bd5c98..4a07eecaaae 100644 --- a/stylelint.config.mjs +++ b/stylelint.config.mjs @@ -12,13 +12,13 @@ export default { "scss/at-rule-no-unknown": true, "color-hex-length": "long", "unit-disallowed-list": null, - "declaration-property-unit-disallowed-list": {}, + "declaration-property-unit-disallowed-list": [], "no-descending-specificity": null, "selector-max-id": null, "no-duplicate-selectors": null, "function-url-no-scheme-relative": null, "declaration-no-important": null, - "function-disallowed-list": null, + "function-disallowed-list": [], "function-no-unknown": null, "scss/function-no-unknown": true, "@stylistic/string-quotes": "double" From d7aeb5a53d03b35b9c738934d5dd5e8d5fa7d47c Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Mar 2026 09:15:04 +0900 Subject: [PATCH 08/13] decouple selectors from table2 --- stylesheets/commons/Standings.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stylesheets/commons/Standings.scss b/stylesheets/commons/Standings.scss index a66299ae5d4..6b8e20ead1d 100644 --- a/stylesheets/commons/Standings.scss +++ b/stylesheets/commons/Standings.scss @@ -18,8 +18,8 @@ div.standings-ffa { } } -.table2.standings-swiss { - tr.table2__row--body[ data-position-status ] { +.standings-swiss { + tr[ data-position-status ] { position: relative; &::after { From b958449caf5eaa1fee4f6c1f1c93f41c30489b71 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Mar 2026 09:20:00 +0900 Subject: [PATCH 09/13] kick "drop" type --- stylesheets/commons/Standings.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stylesheets/commons/Standings.scss b/stylesheets/commons/Standings.scss index 6b8e20ead1d..d07ca80c248 100644 --- a/stylesheets/commons/Standings.scss +++ b/stylesheets/commons/Standings.scss @@ -80,8 +80,7 @@ div.standings-ffa { } } - &[ data-position-status="down" ], - &[ data-position-status="drop" ] { + &[ data-position-status="down" ] { --placement-row-color: var( --clr-semantic-negative-40 ); .theme--dark & { From 9ec19a649ef0336fda2585ac1a6529265afa7bd9 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Mar 2026 18:38:15 +0900 Subject: [PATCH 10/13] move inline css to stylesheet --- lua/wikis/commons/Widget/Standings/MatchOverview.lua | 7 +------ stylesheets/commons/Label.scss | 7 +++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lua/wikis/commons/Widget/Standings/MatchOverview.lua b/lua/wikis/commons/Widget/Standings/MatchOverview.lua index 3f1e9d72cf6..776209e0d2f 100644 --- a/lua/wikis/commons/Widget/Standings/MatchOverview.lua +++ b/lua/wikis/commons/Widget/Standings/MatchOverview.lua @@ -109,12 +109,7 @@ function MatchOverviewWidget:_createResultDisplay(leftScore, rightScore) end local resultType = self:_getMatchResultType() return Label{ - css = { - display = 'grid', - ['grid-template-columns'] = '1fr auto 1fr', - ['justify-items'] = 'center', - padding = '0.25rem', - }, + labelScheme = 'standings-result', labelType = 'result-' .. resultType, children = self:_createScoreContainer(leftScore, rightScore) } diff --git a/stylesheets/commons/Label.scss b/stylesheets/commons/Label.scss index 66fb3ed733a..85cea767037 100644 --- a/stylesheets/commons/Label.scss +++ b/stylesheets/commons/Label.scss @@ -192,4 +192,11 @@ } } } + + &.label--standings-result { + display: grid; + grid-template-columns: 1fr auto 1fr; + justify-items: center; + padding: 0.25rem; + } } From c6b621cd6d0fb5a369309deb6f53c07acdef4d07 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 26 Mar 2026 21:37:45 +0900 Subject: [PATCH 11/13] use table2 header cells --- lua/wikis/commons/Widget/Standings/Swiss.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lua/wikis/commons/Widget/Standings/Swiss.lua b/lua/wikis/commons/Widget/Standings/Swiss.lua index a6dc170b155..30d753d9a1c 100644 --- a/lua/wikis/commons/Widget/Standings/Swiss.lua +++ b/lua/wikis/commons/Widget/Standings/Swiss.lua @@ -13,7 +13,6 @@ local Logic = Lua.import('Module:Logic') local WidgetUtil = Lua.import('Module:Widget/Util') local Widget = Lua.import('Module:Widget') -local HtmlWidgets = Lua.import('Module:Widget/Html/All') local Label = Lua.import('Module:Widget/Basic/Label') local MatchOverview = Lua.import('Module:Widget/Standings/MatchOverview') local TableWidgets = Lua.import('Module:Widget/Table2/All') @@ -91,10 +90,10 @@ function StandingsSwissWidget:_headerRow() if not tiebreaker.title then return end - return HtmlWidgets.Th{children = tiebreaker.title} + return makeHeaderCell(tiebreaker.title) end), Array.map(standings.rounds, function(round) - return HtmlWidgets.Th{children = round.title} + return makeHeaderCell(round.title) end) )} }} From 8ed422cb2ba41fa2a4cd9d1b96489241b9ff4c0b Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 27 Mar 2026 09:15:41 +0900 Subject: [PATCH 12/13] remove drop label --- stylesheets/commons/Label.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stylesheets/commons/Label.scss b/stylesheets/commons/Label.scss index 85cea767037..cf49825c8e3 100644 --- a/stylesheets/commons/Label.scss +++ b/stylesheets/commons/Label.scss @@ -183,8 +183,7 @@ } } - &[ data-placement-type="down" ], - &[ data-placement-type="drop" ] { + &[ data-placement-type="down" ] { --placement-solid-color: var( --clr-semantic-negative-40 ); .theme--dark & { From 12e977d87dd1cc138aa3d4925a0a844655ef28eb Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:22:07 +0900 Subject: [PATCH 13/13] better upcoming&ongoing match handling --- lua/wikis/commons/Widget/Standings/MatchOverview.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lua/wikis/commons/Widget/Standings/MatchOverview.lua b/lua/wikis/commons/Widget/Standings/MatchOverview.lua index 776209e0d2f..9f0520cd120 100644 --- a/lua/wikis/commons/Widget/Standings/MatchOverview.lua +++ b/lua/wikis/commons/Widget/Standings/MatchOverview.lua @@ -74,7 +74,9 @@ MatchOverviewWidget._getMatchResultType = FnUtil.memoize(function (self) local match = self.props.match local opponentIndexToShow = tonumber(self.props.showOpponent) - if match.winner == opponentIndexToShow then + if match.phase == 'ongoing' then + return 'default' + elseif match.winner == opponentIndexToShow then return 'loss' elseif match.winner == 0 then return 'draw' @@ -104,7 +106,7 @@ end ---@private ---@return Widget? function MatchOverviewWidget:_createResultDisplay(leftScore, rightScore) - if not self.props.match.finished then + if self.props.match.phase == 'upcoming' then return end local resultType = self:_getMatchResultType()