Module:SummonIconTable: Difference between revisions

From Liquipedia Wildcard Wiki
No edit summary
No edit summary
Tag: Manual revert
Line 1: Line 1:
local Class = require('Module:Class')
local Class = require('Module:Class')
local CharacterIcon = require('Module:CharacterIcon')
local HeroIcon = require('Module:CharacterIcon')
local Lua = require('Module:Lua')
local Lua = require('Module:Lua')


local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local Br = HtmlWidgets.Br
local Div = HtmlWidgets.Div
local Div = HtmlWidgets.Div
local Span = HtmlWidgets.Span


local SummonIconTable = {}
local HeroIconTable = {}


-- Constants for house themes and icons
-- Constants for house themes and icons
local DEFAULT_CATEGORY = {theme = 'gray-theme-dark-bg', text = 'All Summons'}
local DEFAULT = {theme = 'gray-theme-dark-bg', text = 'All Summons'}
local SUMMON_HOUSE = {
local HERO_HOUSE = {
['malus'] = {
['malus'] = {
theme = 'wildcard-malus-theme',
theme = 'wildcard-malus-theme',
Line 28: Line 30:
}
}


---Main function to display a table of summon icons based on provided arguments
function HeroIconTable.display(args)
---@param args table|nil
---@return Html
function SummonIconTable.display(args)
args = args or {}
args = args or {}
-- Build conditions for the database query based on the provided arguments
local conditions = HeroIconTable._buildConditions(args)
local conditions = SummonIconTable._buildConditions(args)
local heroes = mw.ext.LiquipediaDB.lpdb('datapoint', {
-- Fetch summons from the database using the built conditions
local summons = mw.ext.LiquipediaDB.lpdb('datapoint', {
conditions = conditions,
conditions = conditions,
order = 'name asc',
order = 'name asc',
Line 42: Line 39:
})
})


-- Normalize results to ensure it's always a table of summons, even for single or invalid results
-- Normalize results if single item
if type(summons) == 'table' and summons.name then
if type(heroes) == 'table' and heroes.name then
summons = {summons}
heroes = {heroes}
elseif type(summons) ~= 'table' then
elseif type(heroes) ~= 'table' then
summons = {}
heroes = {}
end
end


local count = #summons
local count = #heroes
-- Get category data (house or default) based on the arguments
local data = HeroIconTable._getCategoryData(args)
local categoryData = SummonIconTable._getCategoryData(args)
-- Create and return the HTML structure with a header and body containing summon icons
return Div{
return Div{
classes = {'white-text'},
classes = {'white-text'},
css = {['text-align'] = 'center', ['font-weight'] = 'bold'},
css = {['text-align'] = 'center', ['font-weight'] = 'bold'},
children = {
children = {
SummonIconTable._createHeader(categoryData, count),
HeroIconTable._createHeader(data, count),
SummonIconTable._createBody(summons)
HeroIconTable._createBody(heroes)
}
}
}
}
end
end


---Retrieve category data for the specified house, or use default if no house is provided
function HeroIconTable._getCategoryData(args)
---@param args table
---@return table
function SummonIconTable._getCategoryData(args)
local house = args.house and string.lower(args.house) or nil
local house = args.house and string.lower(args.house) or nil
return SUMMON_HOUSE[house] or DEFAULT_CATEGORY
return HERO_HOUSE[house] or DEFAULT
end
end


---Create the header section of the table, including house icon and text with summon count
function HeroIconTable._createHeader(data, count)
---@param categoryData table
local headerText = data.text
---@param count integer
---@return Html
function SummonIconTable._createHeader(categoryData, count)
local headerText = categoryData.text
local headerChildren = {}
local headerChildren = {}


-- Add the house icon to the header if available
-- Add House Icon if available in data and it's not the default "All Summons"
-- The original 'data.text ~= DEFAULT.text' was redundant because if data.icon is nil (as for DEFAULT_CATEGORY), it won't pass.
if data.icon and data.text ~= DEFAULT.text then
if categoryData.icon then
table.insert(headerChildren,
table.insert(headerChildren,
'[[' .. categoryData.icon .. '|30x30px|link=]] '
'[[' .. data.icon .. '|30x30px|link=]] '
)
)
end
end


-- Append the formatted text with the total count of summons
table.insert(headerChildren, string.format('%s (%d)', headerText, count))
table.insert(headerChildren, string.format('%s (%d)', headerText, count))


return Div{
return Div{
classes = {categoryData.theme},
classes = {data.theme},
css = {padding = '5px 10px', ['font-size'] = '18px', ['border-radius'] = '0.5rem'},
css = {padding = '5px 10px', ['font-size'] = '18px', ['border-radius'] = '0.5rem'},
children = headerChildren
children = headerChildren
Line 97: Line 84:
end
end


---Create the body section of the table containing the summon icons
function HeroIconTable._createBody(heroes)
---@param summons table[]
---@return Html
function SummonIconTable._createBody(summons)
return Div{
return Div{
css = {
css = {
Line 110: Line 94:
['flex-wrap'] = 'wrap'
['flex-wrap'] = 'wrap'
},
},
children = SummonIconTable._generateSummonIcons(summons)
children = HeroIconTable._generateHeroIcons(heroes)
}
}
end
end


---Generate a table of individual summon icon elements for display
function HeroIconTable._generateHeroIcons(heroes)
---@param summons table[]
---@return table
function SummonIconTable._generateSummonIcons(summons)
local icons = {}
local icons = {}
for _, entry in ipairs(summons) do
for _, entry in ipairs(heroes) do
if entry.name then
if entry.name then
-- Create a container Div for each summon icon with styling and zoom capability
-- Determine house-based theme
local heroTheme = DEFAULT.theme
if entry.extradata and entry.extradata.house then
local house = string.lower(entry.extradata.house)
if HERO_HOUSE[house] then
heroTheme = HERO_HOUSE[house].theme
end
end
 
table.insert(icons, Div{
table.insert(icons, Div{
classes = {'zoom-container'},
classes = {'zoom-container'},
css = {
css = {width = '85px', display = 'inline-block'},
width = '115px',
height = '115px',
display = 'inline-block',
['margin'] = '4px',
overflow = 'hidden',
['vertical-align'] = 'middle'
},
children = {
children = {
CharacterIcon.Icon{
Div{
character = entry.name,
classes = {heroTheme},
size = 'x115px'
css = {
['border-radius'] = '0.5rem 0.5rem 0 0',
overflow = 'hidden',
['margin-bottom'] = '2px',
['text-align'] = 'center'
},
children = {HeroIconTable._getHeroIconContainer(entry)}
},
Div{
classes = {heroTheme},
css = {
['border-radius'] = '0 0 0.5rem 0.5rem',
overflow = 'hidden',
padding = '2px',
['margin-bottom'] = '10px',
['text-align'] = 'center'
},
children = {
Span{
css = {
['font-size'] = entry.name == 'Bolgar' and '10.5px' or '13.5px',
['font-weight'] = 'bold',
['word-break'] = 'break-word'
},
children = {entry.name}
}
}
}
}
}
}
Line 144: Line 152:
end
end


---Build the conditions string for the database query based on arguments
function HeroIconTable._getHeroIconContainer(entry)
---@param args table
return Div{
---@return string
css = {
function SummonIconTable._buildConditions(args)
width = '85px',
-- Initialize base conditions to filter for summons with names
height = '85px',
display = 'flex',
['align-items'] = 'center',
['justify-content'] = 'center',
overflow = 'hidden'
},
children = {
HeroIconTable._getHeroIcon(entry)
}
}
end
 
function HeroIconTable._getHeroIcon(entry)
return HeroIcon.Icon{
character = entry.name,
size = 'x85px'
}
end
 
function HeroIconTable._buildConditions(args)
local conditions = {
local conditions = {
'[[type::Summon]]',
'[[type::Summon]]',
'[[name::!]]'
'[[name::!]]'
}
}
-- Add house-specific condition if a house is provided in the arguments
if args.house then
if args.house then
table.insert(conditions, '[[extradata_house::' .. args.house .. ']]')
table.insert(conditions, '[[extradata_house::' .. args.house .. ']]')
end
end
-- Concatenate conditions with ' AND ' to form the final query string
return table.concat(conditions, ' AND ')
return table.concat(conditions, ' AND ')
end
end


return Class.export(SummonIconTable)
return Class.export(HeroIconTable)

Revision as of 16:39, 6 May 2025

Overview

[edit]

This module creates a responsive grid display of summons icons with automatic categorization into their houses.
It pulls data from Liquipedia's database and applies theme-appropriate styling.
By default this module show all heroes available.


You can either use invoke or simple template. For invoke use:

  • {{#invoke:Lua|invoke|module=SummonIconTable|fn=display}} (All Heroes)
  • {{#invoke:Lua|invoke|module=SummonIconTable|house=Malus|fn=display}}
  • {{#invoke:Lua|invoke|module=SummonIconTable|house=Lubabub|fn=display}}
  • {{#invoke:Lua|invoke|module=SummonIconTable|house=Chronos|fn=display}}

Parameters

[edit]
|house= (optional)
Malus: Shows only summons within Malus house (cinnabar-theme-dark-bg)
Lubabub: Shows only summons within Lubabub house (forest-theme-dark-bg)
Chronos: Shows only summons within Chronos house (gold-bg-alt)

Usage Examples

[edit]
  • All Summons
{{SummonIconTable}}
All Summons (268)
Aloe
Aloe
Aloe Cleanse
Aloe Cleanse
Aloe Immobile
Aloe Immobile
Aloe Mitigation
Aloe Mitigation
Aloe Overheal
Aloe Overheal
Aloe Poison
Aloe Poison
Badaboom
Badaboom
Badaboom LastStand
Badaboom LastStand
Badaboom Leftover
Badaboom Leftover
Badaboom Overtime
Badaboom Overtime
Badaboom Rebirth
Badaboom Rebirth
Badaboom Squad
Badaboom Squad
Beakit
Beakit
Beakit Chain
Beakit Chain
Beakit LastStand
Beakit LastStand
Beakit Mitiation
Beakit Mitigation
Blitzbois
Blitzbois
Blitzbois Fire
Blitzbois Fire
Blitzbois OnCast
Blitzbois OnCast
Blitzbois Rampage
Blitzbois Rampage
Broc
Broc
Broc Cleanse
Broc Cleanse
Broc LastStand
Broc LastStand
Broc Overclock
Broc Overclock
Broc Poison
Broc Poison
Broc Rampage
Broc Rampage
Broc Regeneration
Broc Regeneration
Buckshot
Buckshot
Buckshot Aura
Buckshot Aura
Buckshot LastStand
Buckshot LastStand
Buckshot LifeLink
Buckshot Lifelink
Buckshot Overclock
Buckshot Overclock
Buckshot Overheal
Buckshot Overheal
Buckshot Overtime
Buckshot Overtime
Buckshot Poison
Buckshot Poison
Buckshot Squad
Buckshot Squad
Burnout
Burnout
Burnout Chain
Burnout Chain
Burnout Evolved
Burnout Evolved
Burnout Fire
Burnout Fire
Burnout Overtime
Burnout Overtime
Burnout Squad
Burnout Squad
Cacticrue
Cacticrue
Cacticrue LastStand
Cacticrue LastStand
Cacticrue Poison
Cacticrue Poison
Cacticrue Rebirth
Cacticrue Rebirth
Cacticrue Regeneration
Cacticrue Regeneration
Cacticrue Taunt
Cacticrue Taunt
Cactiking
Cactiking
Cactiking Evolved
Cactiking Evolved
Cactiking Immobile
Cactiking Immobile
Cactiking Leftover
Cactiking Leftover
Cactiking Poison
Cactiking Poison
Cactiking Squad
Cactiking Squad
Cactiking Taunt
Cactiking Taunt
Chonk
Chonk
Chonk Aura
Chonk Aura
Chonk Immobile
Chonk Immobile
Chonk Reflect
Chonk Reflect
Chronodrop
Chronodrop
Chronodrop Immobile
Chronodrop Immobile
Chronodrop LastStand
Chronodrop LastStand
Chronodrop Overclock
Chronodrop Overclock
D.F.A.
D.F.A.
D.F.A. Damage
D.F.A. Damage
D.F.A. Enraged
D.F.A. Enraged
D.F.A. Evolved
D.F.A. Evolved
D.F.A. Fire
D.F.A. Fire
D.F.A. Squad
D.F.A. Squad
Deadeye
Deadeye
Deadeye Aura
Deadeye Aura
Deadeye Chain
Deadeye Chain
Deadeye Hunter
Deadeye Hunter
Deadeye LastStand
Deadeye LastStand
Deadeye Partner
Deadeye Partner
Deadeye TimeDilation
Deadeye TimeDilation
Deadeye Warp
Deadeye Warp
Fendor
Fendor
Fendor Aura
Fendor Aura
Fendor Evolved
Fendor Evolved
Fendor Immobile
Fendor Immobile
Fendor LastStand
Fendor LastStand
Fendor Mitigation
Fendor Mitigation
Fendor Reflect
Fendor Reflect
Flingshot
Flingshot
Flingshot Damage
Flingshot Damage
Flingshot Evolved
Flingshot Evolved
Flingshot Mitigation
Flingshot Mitigation
Flingshot Overclock
Flingshot Overclock
Floraphant
Floraphant
Floraphant Aura
Floraphant Aura
Floraphant Damaged
Floraphant Damaged
Floraphant LastStand
Floraphant LastStand
Floraphant Squad
Floraphant Squad
Floraphant Taunt
Floraphant Taunt
Furble
Furble
Furble Knockback
Furble Knockback
Furble OnCast
Furble OnCast
Furble Squad
Furble Squad
Furble TimeDilation
Furble TimeDilation
Gorrit
Gorrit
Gorrit Aura
Gorrit Aura
Gorrit Evolved
Gorrit Evolved
Gorrit Knockback
Gorrit Knockback
Gorrit Rampage
Gorrit Rampage
Gorrit Regeneration
Gorrit Regeneration
Gorrit Taunt
Gorrit Taunt
Grumph
Grumph
Grumph Enraged
Grumph Enraged
Grumph Fire
Grumph Fire
Grumph Frenzy
Grumph Frenzy
Grumph Immobile
Grumph Immobile
Grumph LastStand
Grumph LastStand
Heartburn
Heartburn
Heartburn Chain
Heartburn Chain
Heartburn Evolved
Heartburn Evolved
Heartburn Fire
Heartburn Fire
Heartburn LastStand
Heartburn LastStand
Hornelius
Hornelius
Hornelius Evolved
Hornelius Evolved
Hornelius Frenzy
Hornelius Frenzy
Hornelius Hunter
Hornelius Hunter
Hornelius Immobile
Hornelius Immobile
Hornelius OnCast
Hornelius OnCast
Infernus
Infernus
Infernus Blitz
Infernus Blitz
Infernus Evolved
Infernus Evolved
Infernus LastStand
Infernus LastStand
Infernus OnCast
Infernus OnCast
Infernus Push
Infernus Push
Infernus Rampage
Infernus Rampage
Janz
Janz
Janz Chain
Janz Chain
Janz Damaged
Janz Damaged
Janz Overclock
Janz Overclock
Janz Warp
Janz Warp
Lavadrop
Lavadrop
Lavadrop Blitz
Lavadrop Blitz
Lavadrop LastStand
Lavadrop LastStand
Lavadrop Leftover
Lavadrop Leftover
Lumph
Lumph
Lumph Cleanse
Lumph Cleanse
Lumph LastStand
Lumph LastStand
Lumph Poison
Lumph Poison
Lumph Reflect
Lumph Reflect
Lumph Regeneration
Lumph Regeneration
Magmalisk
Magmalisk
Magmalisk Evolved
Magmalisk Evolved
Magmalisk Frenzy
Magmalisk Frenzy
Magmalisk OnCast
Magmalisk OnCast
Magmalisk Partner
Magmalisk Partner
Magmalisk Rampage
Magmalisk Rampage
Magmalisk Rebirth
Magmalisk Rebirth
Pocus
Pocus
Pocus Knockback
Pocus Knockback
Pocus Lifelink
Pocus Lifelink
Pocus Rampage
Pocus Rampage
Pocus Taunt
Pocus Taunt
Punks
Punks
Punks LastStand
Punks LastStand
Punks Overclock
Punks Overclock
Punks Push
Punks Push
Punks Squad
Punks Squad
Punks Taunt
Punks Taunt
Pyrokeet
Pyrokeet
Pyrokeet Enraged
Pyrokeet Enraged
Pyrokeet Fire
Pyrokeet Fire
Pyrokeet LastStand
Pyrokeet LastStand
Pyrokeet Rampage
Pyrokeet Rampage
Pyrokeet Squad
Pyrokeet Squad
RB-IT
RB-IT
RB-IT Evolved
RB-IT Evolved
RB-IT OnCast
RB-IT OnCast
RB-IT Warp
RB-IT Warp
Razorpaw
Razorpaw
Razorpaw Damaged
Razorpaw Damaged
Razorpaw Frenzy
Razorpaw Frenzy
Razorpaw Hunter
Razorpaw Hunter
Razorpaw OnCast
Razorpaw OnCast
Razorpaw TimeDilation
Razorpaw TimeDilation
Rekkit
Rekkit
Rekkit Enraged
Rekkit Enraged
Rekkit Frenzy
Rekkit Frenzy
Rekkit LastStand
Rekkit LastStand
Rekkit OnCast
Rekkit OnCast
Rekkit Overclock
Rekkit Overclock
Rekkit Rampage
Rekkit Rampage
Sembler
Sembler
Sembler Damage
Sembler Damage
Sembler Evolved
Sembler Evolved
Sembler Mitigation
Sembler Mitigation
Sembler OnCast
Sembler OnCast
Sembler Partner
Sembler Partner
Sembler Squad
Sembler Squad
Shellshock
Shellshock
Shellshock Evolved
Shellshock Evolved
Shellshock Immobile
Shellshock Immobile
Shellshock Rampage
Shellshock Rampage
Shellshock TimeDilation
Shellshock TimeDilation
Shooticrue
Shooticrue
Shooticrue Enraged
Shooticrue Enraged
Shooticrue LastStand
Shooticrue LastStand
Shooticrue Leftover
Shooticrue Leftover
Shooticrue OnCast
Shooticrue OnCast
Shooticrue Overclock
Shooticrue Overclock
Shooticrue TimeDilation
Shooticrue TimeDilation
Shortfuse
Shortfuse
Shortfuze Chain
Shortfuze Chain
Shortfuze Evolved
Shortfuze Evolved
Shortfuze Fire
Shortfuze Fire
Shortfuze LastStand
Shortfuze LastStand
Shortfuze Rampage
Shortfuze Rampage
Skye
Skye
Skye Aura
Skye Aura
Skye Cleanse
Skye Cleanse
Skye Evolved
Skye Evolved
Skye OnCast
Skye OnCast
Skye Overclocked
Skye Overclocked
Slowclaw
Slowclaw
Slowclaw Frenzy
Slowclaw Frenzy
Slowclaw Poison
Slowclaw Poison
Slowclaw Rampage
Slowclaw Rampage
Slowclaw Reflect
Slowclaw Reflect
Spord
Spord
Spord Enraged
Spord Enraged
Spord LastStand
Spord LastStand
Spord Leftover
Spord Leftover
Spord OnCast
Spord OnCast
Spord Overtime
Spord Overtime
Spord Poison
Spord Poison
Spord Rampage
Spord Rampage
Spord Squad
Spord Squad
Spord Taunt
Spord Taunt
TD-PL
TD-PL
TD-PL Blitz
TD-PL Blitz
TD-PL Damaged
TD-PL Damaged
TD-PL Leftover
TD-PL Leftover
TD-PL OnCast
TD-PL OnCast
TD-PL Squad
TD-PL Squad
Tailblazer
Tailblazer
Tailblazer Aura
Tailblazer Aura
Tailblazer Lifelink
Tailblazer Lifelink
Tailblazer Mitigation
Tailblazer Mitigation
Tailblazer Overtime
Tailblazer Overtime
Tailblazer Push
Tailblazer Push
Vitadrop
Vitadrop
Vitadrop Chain
Vitadrop Chain
Vitadrop Cleanse
Vitadrop Cleanse
Vitadrop LastStand
Vitadrop LastStand
Vitadrop Lifelink
Vitadrop Lifelink
Vitadrop Regeneration
Vitadrop Regeneration
Volcrab
Volcrab
Volcrab Blitz
Volcrab Blitz
Volcrab Enraged
Volcrab Enraged
Volcrab Immobile
Volcrab Immobile
Volcrab LastStand
Volcrab LastStand
Volcrab Squad
Volcrab Squad
Wotchy
Wotchy
Wotchy Damage
Wotchy Damage
Wotchy Damaged
Wotchy Damaged
Wotchy Evolved
Wotchy Evolved
Wotchy Mitigation
Wotchy Mitigation
Wotchy Partner
Wotchy Partner
Wotchy Rampage
Wotchy Rampage
Zip-Zap
Zip-Zap
Zip-Zap Lifelink
Zip-Zap Lifelink
Zip-Zap Overtime
Zip-Zap Overtime
Zip-Zap Squad
Zip-Zap Squad
  • Only Summons in Malus House
{{SummonIconTable|house=Malus}}
 Malus (15)
Badaboom
Badaboom
Blitzbois
Blitzbois
Burnout
Burnout
D.F.A.
D.F.A.
Grumph
Grumph
Heartburn
Heartburn
Infernus
Infernus
Lavadrop
Lavadrop
Magmalisk
Magmalisk
Punks
Punks
Pyrokeet
Pyrokeet
Rekkit
Rekkit
Shortfuse
Shortfuse
Tailblazer
Tailblazer
Volcrab
Volcrab

Copy/Paste

[edit]
All Summons
{{SummonIconTable}}
Categorized Champions
{{SummonIconTable|house=Malus}}
{{SummonIconTable|house=Chronos}}
{{SummonIconTable|house=Lubabub}}


For more information on how to contribute, please refer to our Help:Edit an Article.



local Class = require('Module:Class')
local HeroIcon = require('Module:CharacterIcon')
local Lua = require('Module:Lua')

local HtmlWidgets = Lua.import('Module:Widget/Html/All')
local Br = HtmlWidgets.Br
local Div = HtmlWidgets.Div
local Span = HtmlWidgets.Span

local HeroIconTable = {}

-- Constants for house themes and icons
local DEFAULT = {theme = 'gray-theme-dark-bg', text = 'All Summons'}
local HERO_HOUSE = {
	['malus'] = {
		theme = 'wildcard-malus-theme',
		text = 'Malus',
		icon = 'File:Wildcard_gameasset_Malus_Faction_Icon_White.png'
	},
	['chronos'] = {
		theme = 'wildcard-chronos-theme',
		text = 'Chronos',
		icon = 'File:Wildcard_gameasset_Chronos_Faction_Icon_White.png'
	},
	['lubabub'] = {
		theme = 'wildcard-lubabub-theme',
		text = 'Lubabub',
		icon = 'File:Wildcard_gameasset_Lubabub_Faction_Icon_White.png'
	}
}

function HeroIconTable.display(args)
	args = args or {}
	local conditions = HeroIconTable._buildConditions(args)
	local heroes = mw.ext.LiquipediaDB.lpdb('datapoint', {
		conditions = conditions,
		order = 'name asc',
		limit = 5000
	})

	-- Normalize results if single item
	if type(heroes) == 'table' and heroes.name then
		heroes = {heroes}
	elseif type(heroes) ~= 'table' then
		heroes = {}
	end

	local count = #heroes
	local data = HeroIconTable._getCategoryData(args)
	return Div{
		classes = {'white-text'},
		css = {['text-align'] = 'center', ['font-weight'] = 'bold'},
		children = {
			HeroIconTable._createHeader(data, count),
			HeroIconTable._createBody(heroes)
		}
	}
end

function HeroIconTable._getCategoryData(args)
	local house = args.house and string.lower(args.house) or nil
	return HERO_HOUSE[house] or DEFAULT
end

function HeroIconTable._createHeader(data, count)
	local headerText = data.text
	local headerChildren = {}

	-- Add House Icon if available in data and it's not the default "All Summons"
	if data.icon and data.text ~= DEFAULT.text then
		table.insert(headerChildren,
			'[[' .. data.icon .. '|30x30px|link=]] '
		)
	end

	table.insert(headerChildren, string.format('%s (%d)', headerText, count))


	return Div{
		classes = {data.theme},
		css = {padding = '5px 10px', ['font-size'] = '18px', ['border-radius'] = '0.5rem'},
		children = headerChildren
	}
end

function HeroIconTable._createBody(heroes)
	return Div{
		css = {
			gap = '8px',
			padding = '8px 6px',
			display = 'flex',
			['justify-content'] = 'center',
			['align-items'] = 'center',
			['flex-wrap'] = 'wrap'
		},
		children = HeroIconTable._generateHeroIcons(heroes)
	}
end

function HeroIconTable._generateHeroIcons(heroes)
	local icons = {}
	for _, entry in ipairs(heroes) do
		if entry.name then
			-- Determine house-based theme
			local heroTheme = DEFAULT.theme
			if entry.extradata and entry.extradata.house then
				local house = string.lower(entry.extradata.house)
				if HERO_HOUSE[house] then
					heroTheme = HERO_HOUSE[house].theme
				end
			end

			table.insert(icons, Div{
				classes = {'zoom-container'},
				css = {width = '85px', display = 'inline-block'},
				children = {
					Div{
						classes = {heroTheme},
						css = {
							['border-radius'] = '0.5rem 0.5rem 0 0',
							overflow = 'hidden',
							['margin-bottom'] = '2px',
							['text-align'] = 'center'
						},
						children = {HeroIconTable._getHeroIconContainer(entry)}
					},
					Div{
						classes = {heroTheme},
						css = {
							['border-radius'] = '0 0 0.5rem 0.5rem',
							overflow = 'hidden',
							padding = '2px',
							['margin-bottom'] = '10px',
							['text-align'] = 'center'
						},
						children = {
							Span{
								css = {
									['font-size'] = entry.name == 'Bolgar' and '10.5px' or '13.5px',
									['font-weight'] = 'bold',
									['word-break'] = 'break-word'
								},
								children = {entry.name}
							}
						}
					}
				}
			})
		end
	end
	return icons
end

function HeroIconTable._getHeroIconContainer(entry)
	return Div{
		css = {
			width = '85px',
			height = '85px',
			display = 'flex',
			['align-items'] = 'center',
			['justify-content'] = 'center',
			overflow = 'hidden'
		},
		children = {
			HeroIconTable._getHeroIcon(entry)
		}
	}
end

function HeroIconTable._getHeroIcon(entry)
	return HeroIcon.Icon{
		character = entry.name,
		size = 'x85px'
	}
end

function HeroIconTable._buildConditions(args)
	local conditions = {
		'[[type::Summon]]',
		'[[name::!]]'
	}
	if args.house then
		table.insert(conditions, '[[extradata_house::' .. args.house .. ']]')
	end
	return table.concat(conditions, ' AND ')
end

return Class.export(HeroIconTable)