Module:StoryCard

From FictionBase
Revision as of 08:41, 3 March 2026 by SuperHamster (talk | contribs) (Creating)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Documentation for this module may be created at Module:StoryCard/doc

local p = {}

local function trim(s)
	if s == nil then return nil end
	s = tostring(s)
	s = mw.text.trim(s)
	if s == "" then return nil end
	return s
end

local function split_semicolons(s)
	s = trim(s)
	if not s then return {} end
	local parts = mw.text.split(s, "%s*;%s*", false)
	local out = {}
	for _, part in ipairs(parts) do
		part = trim(part)
		if part then table.insert(out, part) end
	end
	return out
end

local function makeNsLink(ns, label)
	label = trim(label)
	if not label then return nil end
	local target = mw.ustring.gsub(label, "%s+", "_")
	return string.format("[[%s:%s|%s]]", ns, target, label)
end

local function safeInt(s)
	s = trim(s)
	if not s then return nil end
	s = mw.ustring.gsub(s, "[^0-9]", "")
	if s == "" then return nil end
	return tonumber(s)
end

local function fmtWords(n)
	if not n then return nil end
	local s = tostring(n)
	local out = s:reverse():gsub("(%d%d%d)", "%1,"):reverse()
	if out:sub(1,1) == "," then out = out:sub(2) end
	return out
end

local function addChips(container, raw, ns, maxItems)
	local items = split_semicolons(raw)
	if #items == 0 then return end
	local shown = 0
	for _, item in ipairs(items) do
		if maxItems and shown >= maxItems then break end
		local w = makeNsLink(ns, item) or item
		container:tag("span"):addClass("storycard-chip"):wikitext(w)
		shown = shown + 1
	end
	local remaining = #items - shown
	if remaining > 0 then
		container:tag("span"):addClass("storycard-chip storycard-chip-muted"):wikitext("+" .. tostring(remaining))
	end
end

function p.main(frame)
	local args = frame:getParent() and frame:getParent().args or frame.args

	local title = trim(args.title) or "Untitled"
	local page = trim(args.page)
	local author = trim(args.author)
	local publication = trim(args.publication)
	local year = trim(args.year)
	local words = fmtWords(safeInt(args.words))

	local root = mw.html.create("div"):addClass("storycard")

	local titleNode = root:tag("div"):addClass("storycard-title")
	if page then
		titleNode:wikitext(string.format("[[%s|%s]]", page, title))
	else
		titleNode:wikitext(title)
	end

	local meta = root:tag("div"):addClass("storycard-meta")
	if author then
		meta:tag("span"):addClass("storycard-metaitem"):wikitext(makeNsLink("Author", author) or author)
	end
	if publication then
		meta:tag("span"):addClass("storycard-metaitem"):wikitext(makeNsLink("Publication", publication) or publication)
	end
	if year then
		meta:tag("span"):addClass("storycard-metaitem"):wikitext(makeNsLink("Year", year) or year)
	end
	if words then
		meta:tag("span"):addClass("storycard-metaitem"):wikitext(words .. " words")
	end

	local chips = root:tag("div"):addClass("storycard-chips")
	addChips(chips, args.genres, "Genre", 3)
	addChips(chips, args.tags, "Tag", 4)

	return tostring(root)
end

return p