Module:Mainpage: Difference between revisions
More actions
starcitizen>Alistar Bot Correct the stylesheet note: the patch card no longer uses CardLua, so only the event card does (via update-page on MediaWiki MCP Server) |
Bonsaibauer (talk | contribs) m 1 revision imported: Import of Star-Citizen-Modules |
||
(No difference)
| |||
Latest revision as of 21:58, 4 November 2026
|type = website |description = Module:Mainpage is a template page used on the Star Citizen Wiki. Templates are pages that are embedded (transcluded) into other pages to allow for the repetition of information. |site_name = Star Citizen Wiki |locale = en-gb }}
Renders the main page: hero, highlights, featured article, on this day, the editing invitation, two community cards, and the directory.
Editors use this through {{Mainpage}}; see Template:Mainpage for what an editor can change and where.
For module editors
Submodules
| Submodule | Renders |
|---|---|
Mainpage/Config
|
Loads settings.json; normalises it to plain Lua and resolves which build is live.
|
Mainpage/Nav
|
Turns a settings link entry into wikitext; the hero chips and the directory both read it. |
Mainpage/Hero
|
The full-bleed hero band: patch status, wiki statline, lede, search trigger, chip strip. |
Mainpage/Highlights
|
The band under the hero: the event card (whichever design applies) and the current-patch card. |
Mainpage/Event
|
The event card built on a 1080×83 banner strip. |
Mainpage/Event/Legacy
|
The event card built on an ordinary photograph. |
Mainpage/Featured
|
The featured card: a whole-card link over the featured article's picture. |
Mainpage/OnThisDay
|
Today's date page, transcluded as a two-panel tabber. |
Mainpage/Editing
|
The editing invitation; the recent-changes list beneath it is built entirely by the mainpage gadget. |
Mainpage/Community
|
The funding card and the Discord/follow card. |
Mainpage/Directory
|
The grouped text directory at the foot. |
Mainpage.lua composes these into the page and renders the foot row itself; that row is small enough to not need a submodule of its own. Buttons come from Module:ButtonLua, the badge from Module:BadgeLua, and the clock from Module:Countdown: each keeps its own look, and this module supplies only content and placement.
Settings contract
Every other submodule reads settings through Config, never through mw.loadJsonData directly:
Config.section(name)/Config.list(name): one top-level object or array,{}/empty when the section is missing or blank, so a caller never has to nil-check first (Config.lua:101-116).Config.toIso(value): a settings date to ISO 8601 UTC, ornilfor anything it can't read; it never raises (Config.lua:134-163).Config.livePatch(): the build every consumer agrees is "live" (the firstpatchesentry withchannel: "LIVE", else the first with aname), resolved once so the hero's status chip and the patch card can't disagree (Config.lua:177-193).load()wrapsmw.loadJsonDatainpcall; a moved or deleted settings page degrades to{}rather than raising (Config.lua:80-90).
toPlain (Config.lua:47-77) copies the loaded page's read-only table (whose metatable breaks # and next()) into a plain one, dropping blank strings to nil, compacting arrays, and discarding every _-prefixed key as editor guidance. Read a new settings field through Config, never a second mw.loadJsonData call.
Styles
| Page | Holds |
|---|---|
Mainpage/styles.css
|
The hero, the bands, the grid, and the responsive stages. |
Mainpage/cards.css
|
The individual cards, the directory, and the foot. |
Mainpage/ground.css
|
The graduation tapes and the dot lattice behind the page. |
The page runs full bleed: MediaWiki:Citizen.css drops the body container's gutter for this page, letting the bands paint edge to edge; that rule lives outside this module and this repository (Mainpage/styles.css:11-12).
Gadget
MediaWiki:Gadget-mainpage.js enhances the rendered page: it loads the hero artwork after page load, rolls the stat digits and search-label tail, drives the clock, manages the two scrolling cards' fade cues, and builds the activity list, reading its context from data-gadget-mainpage-* attributes (so grep gadget-mainpage- finds every emitter). The page renders and reads correctly with the gadget absent, except the activity list: without the gadget it stays empty and the card offers its "See all changes" link instead.
Previewing
<syntaxhighlight lang="wikitext">
</syntaxhighlight>
Gotchas
Module:Mainpage/settings.jsonis editor-owned content, not tracked in this repository (gitignored:.gitignore:20);deploy-to-wikiskips it even if a stale copy is sitting on disk, since deploying it would silently revert an editor's changes.STYLESHEETSlists Module:CardLua'sstyles.cssexplicitly: six of the seven cards use plain.t-carddivs, so their surface, border, and radius would otherwise depend on the event card (the only CardLua consumer) rendering (Mainpage.lua:41-54).- Card spans (
.home-card--read,--aside,--tall) are placement properties, not display ones: a class that setsdisplaymust never share an element witht-card, since CardLua's owndisplaywould collide (Mainpage.lua:18-21). - The split event card's clock is restyled from the page for one viewport range (640-899.98px,
Mainpage/styles.css:541-603), duplicating Module:Countdown's stacked/flat declarations by hand, since a CSS class can't be conditional on viewport width. The banner card avoids this by asking Countdown fort-countdown--flatat every width instead. band()takes varargs, not a table, sinceipairsstops at the firstniland would let one declined card drop every card listed after it (Mainpage.lua:87-105).- The foot row's edit link and
Mainpage/OnThisDay's "Add an event" link both usemw.uri.fullUrl, notcallParserFunction:fullurlis a colon magic word (fullurl:) thatcallParserFunctioncannot resolve (Mainpage.lua:107-130,OnThisDay.lua:94-104). Mainpage/Editing's recent-changes list is built entirely byMediaWiki:Gadget-mainpage.jsfromlist=recentchanges: without JS the container renders empty and the card falls back to its "See all changes" link (Editing.lua:10-12).- The directory's column count isn't set in Lua:
.home-dirisrepeat(auto-fit, minmax(125px, 1fr)), so the groups reflow on their own andMainpage/Directoryjust emits them (Directory.lua:10-13).
Extending
Every band shares one layout contract: .home-band is the full-bleed ground, .home-band__inner the measured column inside it, and a band of cards adds .home-grid on that inner element, all off one shared twelve-column grid; a band with its own column ratios breaks alignment for every other band (Mainpage.lua:11-17).
A new card is a submodule with a render() that returns nil or a string; wire its call into Mainpage.render's band composition and, if it ships its own stylesheet, add it to STYLESHEETS explicitly. It then picks one of the three span classes (.home-card--read spans 8, .home-card--aside 4, .home-card--tall 8 across two rows); between 640 and 899.98px every span collapses to 6, and below 640 the page is one column in DOM order, so a new span value needs checking against both breakpoints.
require('strict')
--- @module Mainpage
--- Renders the main page.
---
--- Everything editors change — the featured article, the running event, the
--- build chips, the hero, and both link lists — lives in
--- [[Module:Mainpage/settings.json]]. Nothing on this page needs a module edit
--- to keep it current, and the foot links straight to it.
---
--- LAYOUT CONTRACT. Every band is `.home-band` for its full-bleed ground and
--- `.home-band__inner` for the measured column inside it, and every band of
--- cards puts `.home-grid` on that inner element. One twelve-column grid is
--- shared by all of them, so a card edge in one band lands on the same line as
--- a card edge in the next. A band that sets its own column ratios breaks that
--- alignment for every band on the page.
---
--- Card spans go on the card itself (`.home-card--read`, `--aside`, `--tall`)
--- because `grid-column` is a placement property and cannot collide with
--- Module:CardLua's own `display` on `.t-card`. A class that sets `display`
--- must never share an element with `t-card`.
---
--- Structure:
---
--- hero full bleed, gadget-loaded artwork
--- highlights [ event 8 ][ patch 4 ]
--- band 1 [ featured 8 ][ on this day 4 ]
--- band 2 [ editing 8, two rows ][ support 4 ]
--- [ discussion 4 ]
--- directory six groups, no card
--- foot where to edit what the page says
local community = require('Module:Mainpage/Community')
local directory = require('Module:Mainpage/Directory')
local editing = require('Module:Mainpage/Editing')
local featured = require('Module:Mainpage/Featured')
local hero = require('Module:Mainpage/Hero')
local highlights = require('Module:Mainpage/Highlights')
local onThisDay = require('Module:Mainpage/OnThisDay')
--- Loaded in this order: the card primitive first, then the grid and hero, then
--- the components that sit on the grid, then the ground behind both.
---
--- CardLua's sheet is listed EXPLICITLY rather than left to arrive with a
--- CardLua call. Six of the seven cards are built here with `.t-card` on a
--- plain div, so the card surface, border and radius would otherwise depend on
--- the event card happening to render — and it does not when the settings
--- carry no event.
local STYLESHEETS = {
'Module:CardLua/styles.css',
'Module:Mainpage/styles.css',
'Module:Mainpage/cards.css',
'Module:Mainpage/ground.css',
}
--- Where to go to change what the page says, linked at the foot.
---
--- NOT "edit this page". The page is a single transclusion, so an edit link on
--- it lands an editor in a file with nothing in it to change. This is the one
--- surface that holds content, and it covers everything an editor can change
--- without touching Lua.
local EDIT_TARGETS = {
{ page = 'Module:Mainpage/settings.json', label = 'Settings' },
}
--- What loads [[MediaWiki:Gadget-mainpage.js]]. Emitted by the module so the
--- invocation is self-sufficient: a page that renders this and does not carry
--- the category gets no lazy artwork, no rolling digits and a clock that never
--- starts, with nothing on the page to say why.
local GADGET_CATEGORY = 'Pages using main page gadget'
local p = {}
--- @param frame mw.frame
--- @return string
local function stylesheets(frame)
local tags = {}
for _, src in ipairs(STYLESHEETS) do
tags[#tags + 1] = frame:extensionTag({
name = 'templatestyles',
args = { src = src },
})
end
return table.concat(tags)
end
--- One band of cards on the shared grid.
---
--- Varargs and not a table: a table would be walked with ipairs, which stops at
--- the first nil, so a card that declined to render would silently take every
--- card after it with it. select('#') counts the nils.
---
--- @param ... string|nil
--- @return string
local function band(...)
local root = mw.html.create('div'):addClass('home-band'):addClass('home-wiki')
local inner = root:tag('div'):addClass('home-band__inner'):addClass('home-grid')
for i = 1, select('#', ...) do
inner:wikitext((select(i, ...)))
end
return tostring(root)
end
--- The maintenance affordance at the foot of the page.
---
--- External-link syntax because an internal link cannot carry a query string,
--- and `plainlinks` because the destinations are on this wiki and the arrow
--- icon would say otherwise.
---
--- mw.uri.fullUrl and NOT callParserFunction: `fullurl` is a colon magic word,
--- registered under the name `fullurl:`, and callParserFunction resolves it as
--- `fullurl`, which does not exist. mw.uri is the addressable API for this.
---
--- @return string
local function footer()
local root = mw.html.create('div'):addClass('home-band'):addClass('home-wiki')
local inner = root:tag('div'):addClass('home-band__inner'):addClass('home-foot'):addClass('plainlinks')
for _, target in ipairs(EDIT_TARGETS) do
inner
:tag('span')
:wikitext(string.format('[%s %s]', tostring(mw.uri.fullUrl(target.page, 'action=edit')), target.label))
end
return tostring(root)
end
--- @return string
function p.render()
local frame = mw.getCurrentFrame()
local root = mw.html.create('div'):addClass('home-page')
-- Both are empty and painted entirely in CSS: the dot lattice outside the
-- tapes, and the tapes themselves. The tape is `position: fixed` and the
-- dots are not, so the instrument holds still while the page scrolls past.
root:tag('div'):addClass('home-sky')
root:tag('div'):addClass('home-tape')
root:wikitext(hero.render({}))
root:wikitext(highlights.render())
root:wikitext(band(featured.render(), onThisDay.render()))
root:wikitext(band(editing.render(), community.renderSupport(), community.renderDiscussion()))
root:wikitext(directory.render())
root:wikitext(footer())
return stylesheets(frame) .. tostring(root) .. string.format('[[Category:%s]]', GADGET_CATEGORY)
end
--- Wikitext entry point. Reached through [[Template:Mainpage]] rather than
--- invoked directly, so the page that carries it stays one transclusion.
---
--- @param frame mw.frame
--- @return string
function p.main(frame)
return p.render()
end
--- The hero on its own, for previewing it outside the page. `noscript=yes`
--- renders it without the gadget's artwork hook, which is what a reader with
--- scripts off or Save-Data on receives.
---
--- @param frame mw.frame
--- @return string
function p.hero(frame)
local args = require('Module:Arguments').getArgs(frame)
local yesno = require('Module:Yesno')
return stylesheets(frame)
.. tostring(
mw.html
.create('div')
:addClass('home-page')
:wikitext(hero.render({ lazyArt = yesno(args.noscript, false) ~= true }))
)
end
return p