Module:Timeline
Documentation for this module may be created at Module:Timeline/doc
local p = {}
-- Base date for Year 1, Day 1: 2026-07-28
local BASE_TIMESTAMP = 1785206400 -- 2026-07-28 00:00:00 UTC
local SECONDS_PER_DAY = 86400
local dayNames = {
"Early January", "January--February", "February--March", "March--April",
"April--May", "May--June", "June", "June--July",
"July--August", "August--September", "September--October",
"October--November", "November--December", "Late December"
}
local function calculateDate(year, dayIndex)
year = tonumber(year) or 1
dayIndex = tonumber(dayIndex) or 1
local daysOffset = (year - 1) * 14 + (dayIndex - 1)
local targetTimestamp = BASE_TIMESTAMP + (daysOffset * SECONDS_PER_DAY)
return os.date("!%Y-%m-%d", targetTimestamp)
end
local function formatLink(text)
if not text or text == "" then return "" end
text = mw.text.trim(text)
-- If already bracketed, quoted, or styled, don't wrap again
if text:sub(1, 2) == "[[" or text:sub(1, 1) == "'" or text:sub(1, 1) == "<" then
return text
end
return "[[" .. text .. "]]"
end
function p.renderTable(frame)
local args = frame:getParent().args
local year = tonumber(args.Year) or 1
local category = args.Category or "NEWS"
local html = ""
-- Render Section Header Row
html = html .. "|-\n"
html = html .. '! colspan="4" style="background-color: #f1f5f9; color: #0b132b; text-align: center; font-weight: bold; padding: 6px;" | ' .. string.upper(category) .. ' NEWS\n'
-- Collect events per day (up to 9 events per day)
local schedule = {}
for i = 1, 14 do
schedule[i] = {}
for pIdx = 1, 9 do
local post = args['Day' .. i .. '_' .. pIdx .. '_Post']
local char = args['Day' .. i .. '_' .. pIdx .. '_Char']
local dateOverride = args['Day' .. i .. '_' .. pIdx .. '_Date']
if post and post ~= "" then
local formattedPost = formatLink(post)
local formattedChar = formatLink(char)
local finalDate = (dateOverride and dateOverride ~= "") and dateOverride or calculateDate(year, i)
table.insert(schedule[i], {
post = formattedPost,
char = formattedChar,
date = finalDate
})
end
end
end
-- Render Table Rows
local i = 1
while i <= 14 do
if #schedule[i] > 0 then
local count = #schedule[i]
local inUniverseLabel = dayNames[i] .. ", Year " .. year
for idx, event in ipairs(schedule[i]) do
html = html .. "|-\n"
if idx == 1 then
html = html .. '| rowspan="' .. count .. '" | ' .. inUniverseLabel .. '\n'
end
html = html .. '| ' .. event.post .. '\n'
html = html .. '| ' .. event.char .. '\n'
if idx == 1 then
html = html .. '| rowspan="' .. count .. '" | ' .. event.date .. '\n'
end
end
i = i + 1
else
-- Scan ahead for consecutive empty days to collapse ranges
local startEmpty = i
while i <= 14 and #schedule[i] == 0 do
i = i + 1
end
local endEmpty = i - 1
local rangeLabel = ""
if startEmpty == endEmpty then
rangeLabel = dayNames[startEmpty] .. ", Year " .. year
else
rangeLabel = dayNames[startEmpty] .. " to " .. dayNames[endEmpty] .. ", Year " .. year
end
local startDate = calculateDate(year, startEmpty)
local endDate = calculateDate(year, endEmpty)
local dateDisplay = (startEmpty == endEmpty) and startDate or (startDate .. " to " .. endDate)
html = html .. "|-\n"
html = html .. "| " .. rangeLabel .. "\n"
html = html .. "| \n"
html = html .. "| \n"
html = html .. "| " .. dateDisplay .. "\n"
end
end
return html
end
return p