Module:MasonryLayout: Difference between revisions
// via Wikitext Extension for VSCode |
// via Wikitext Extension for VSCode |
||
| (6 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
--[[ | --[[ | ||
* Name: MasonryLayout | |||
* Author: Mark W. Datysgeld | |||
* Description: Intelligent masonry layout system for content distribution with card organization across columns for optimal visual balance | |||
* Notes: Content-aware size estimation; intelligent card distribution algorithm; responsive column management; aggressive caching for performance; Blueprint integration; error handling integration; integrates with ErrorHandling for protected operations; uses TemplateHelpers caching mechanisms and utility functions; integrates with TemplateStructure for block-based rendering | |||
]] | ]] | ||
| Line 25: | Line 11: | ||
local EMPTY_STRING = '' | local EMPTY_STRING = '' | ||
local DEFAULT_COLUMNS = 3 | local DEFAULT_COLUMNS = 3 | ||
local MOBILE_BREAKPOINT = | local MOBILE_BREAKPOINT = 656 -- 41rem to match CSS breakpoint | ||
-- Size estimation constants (based on typical MediaWiki table rendering) | -- Size estimation constants (based on typical MediaWiki table rendering) | ||
| Line 41: | Line 26: | ||
-- Column distribution weights for different screen sizes | -- Column distribution weights for different screen sizes | ||
local RESPONSIVE_CONFIG = { | local RESPONSIVE_CONFIG = { | ||
desktop = { columns = 3 | desktop = { columns = 3, minWidth = MOBILE_BREAKPOINT + 1 }, | ||
mobile = { columns = 1, maxWidth = MOBILE_BREAKPOINT } | mobile = { columns = 1, maxWidth = MOBILE_BREAKPOINT } | ||
} | } | ||
| Line 669: | Line 653: | ||
if screenWidth <= MOBILE_BREAKPOINT then | if screenWidth <= MOBILE_BREAKPOINT then | ||
return 1 | return 1 | ||
else | else | ||
return 3 | return 3 | ||
| Line 733: | Line 715: | ||
local options = config.options or {} | local options = config.options or {} | ||
local blockRenderers = config.blockRenderers or {} | local blockRenderers = config.blockRenderers or {} | ||
-- Determine render mode (mobile vs desktop) | |||
-- Default to desktop mode, but can be overridden by options | |||
local isMobileMode = options.mobileMode or false | |||
local columnCount = isMobileMode and 1 or (options.columns or DEFAULT_COLUMNS) | |||
-- Build cards with render-time content generation | -- Build cards with render-time content generation | ||
| Line 770: | Line 757: | ||
end | end | ||
-- | -- Branch based on render mode | ||
if isMobileMode or columnCount == 1 then | |||
-- MOBILE MODE: Single column with explicit ordering | |||
local orderedCards = {} | |||
local introCard = nil | |||
local infoBoxCard = nil | |||
local otherCards = {} | |||
-- Separate special cards from regular cards | |||
for _, card in ipairs(cards) do | |||
if card.id == 'intro' then | |||
introCard = card | |||
elseif card.id == 'infoBox' then | |||
table.insert(otherCards, card) | infoBoxCard = card | ||
else | |||
table.insert(otherCards, card) | |||
end | |||
end | |||
-- Build final ordered list: intro → infoBox → others | |||
if introCard then | |||
table.insert(orderedCards, introCard) | |||
end | |||
if infoBoxCard then | |||
table.insert(orderedCards, infoBoxCard) | |||
end | |||
for _, card in ipairs(otherCards) do | |||
table.insert(orderedCards, card) | |||
end | end | ||
-- Render as single column layout | |||
local containerClass = options.containerClass or 'country-hub-masonry-container' | |||
local cardClass = options.cardClass or 'country-hub-masonry-card' | |||
local masonryHtml = string.format('<div class="%s country-hub-mobile-mode">', containerClass) | |||
-- Add debug information | |||
masonryHtml = masonryHtml .. string.format( | masonryHtml = masonryHtml .. string.format( | ||
' | '<!-- Masonry Debug: Total cards: %d, Mobile single column layout -->', | ||
#orderedCards | |||
) | ) | ||
-- Render each card in order | |||
for _, card in ipairs(orderedCards) do | |||
masonryHtml = masonryHtml .. string.format( | |||
'\n<div class="%s" data-card-id="%s">%s</div>', | |||
cardClass, | |||
card.id or 'unknown', | |||
card.content or EMPTY_STRING | |||
) | |||
end | |||
masonryHtml = masonryHtml .. '\n</div>' | |||
return masonryHtml | |||
else | |||
-- DESKTOP MODE: Multi-column with intelligent distribution | |||
local distribution = p.distributeCards(cards, columnCount) | |||
-- Render the complete masonry layout | |||
local containerClass = options.containerClass or 'country-hub-masonry-container' | |||
local masonryHtml = string.format('<div class="%s">', containerClass) | |||
-- Add debug information as HTML comments | |||
if distribution then | |||
masonryHtml = masonryHtml .. string.format( | |||
'<!-- Masonry Debug: Total cards: %d, Columns: %d, Heights: [%s], Balance: %.2f, Extreme cards: %d -->', | |||
#cards, | |||
#(distribution.columns or {}), | |||
table.concat(distribution.heights or {}, ', '), | |||
distribution.balance or 0, | |||
distribution.extremeCards or 0 | |||
) | |||
-- Add per-card debug info | |||
for i, column in ipairs(distribution.columns or {}) do | |||
masonryHtml = masonryHtml .. string.format('\n<!-- Column %d: ', i) | |||
for _, card in ipairs(column) do | |||
masonryHtml = masonryHtml .. string.format('%s(%dpx) ', card.id or 'unknown', card.estimatedSize or 0) | |||
end | |||
masonryHtml = masonryHtml .. '-->' | |||
end | |||
end | |||
masonryHtml = masonryHtml .. '\n' .. p.renderDistributedLayout(distribution, options) | |||
masonryHtml = masonryHtml .. '</div>' | |||
return masonryHtml | |||
end | end | ||
end | end | ||