模块:CardData
来自夜幕之下
更多操作
此模块的文档可以在模块:CardData/doc创建
-- Module:CardData
-- 生成卡片页面完整 HTML 骨架,数据由前端 JS 从 Directus API 获取后填充
-- 用法:{{#invoke:CardData|render|复仇童谣}}
--
-- 骨架结构对应 Sandbox/2.0,分为左栏(基础信息)和右栏(技能/觉醒/小传/邀约)
-- JS 会找到所有 [data-cardname] 元素,请求 Directus 后将数据注入各 [data-card-field] 占位节点
local p = {}
-- ──────────────────────────────────────────────
-- 辅助:创建"标题行"(如「战斗技能 Tactical」)
-- ──────────────────────────────────────────────
local function makeTitle(titleText, subtitleText, extraClass)
local div = mw.html.create("div")
:addClass("card_content-item-title")
if extraClass then div:addClass(extraClass) end
div:wikitext(titleText)
div:tag("span")
:addClass("card_content-item-subtitle")
:wikitext(subtitleText)
return div
end
-- ──────────────────────────────────────────────
-- 辅助:创建分隔线
-- ──────────────────────────────────────────────
local function makeHr(extraClass)
local div = mw.html.create("div")
:addClass("card_content-item-hr")
if extraClass then div:addClass(extraClass) end
return div
end
-- ──────────────────────────────────────────────
-- 辅助:创建一个技能卡片骨架
-- skillKey = "normal_attack" | "passive" | "ultimate"
-- ──────────────────────────────────────────────
local function makeSkillCard(skillKey)
-- 外层卡片
local card = mw.html.create("div")
:addClass("card_content_skill-card")
-- 左侧内容区
local left = card:tag("div"):addClass("card_content_skill-left")
-- 技能标题行
local titleWrap = left:tag("div"):addClass("card_content_skill-title")
titleWrap:tag("div"):addClass("card_content_skill-icon") -- 图标占位
local titleText = titleWrap:tag("div"):addClass("card_content_skill-title-text")
-- 技能名 + 类型 行
local nameRow = titleText:tag("div")
nameRow:tag("span")
:addClass("card_content_skill-name")
:attr("data-card-field", "skill_" .. skillKey .. ".name")
:wikitext("—")
nameRow:tag("span")
:addClass("card_content_skill-type card_accent--type")
:attr("data-card-field", "skill_" .. skillKey .. ".type_label")
:wikitext("—")
-- meta 行(普攻显示武器;被动显示触发条件;终结技显示欲火消耗)
local metaRow = titleText:tag("div"):addClass("card_content_skill-meta")
if skillKey == "normal_attack" then
metaRow:wikitext("使用武器 ")
metaRow:tag("span")
:addClass("card_content_skill-meta-val card_accent")
:attr("data-card-field", "skill_normal_attack.weapon")
:wikitext("—")
elseif skillKey == "passive" then
metaRow:wikitext("触发条件 ")
metaRow:tag("span")
:addClass("card_content_skill-meta-val")
:attr("data-card-field", "skill_passive.trigger_label")
:wikitext("—")
elseif skillKey == "ultimate" then
metaRow:wikitext("欲火消耗 ")
metaRow:tag("span")
:addClass("card_content_skill-meta-val")
:tag("span")
:addClass("card_accent")
:attr("data-card-field", "skill_ultimate.desire_cost")
:wikitext("—")
end
-- 被动/终结技才有 tags 行
if skillKey == "passive" or skillKey == "ultimate" then
left:tag("div")
:addClass("card_content_skill-tags")
:attr("data-card-field", "skill_" .. skillKey .. ".tags")
-- JS 会把 tag 列表渲染到这里
end
-- 技能描述
left:tag("div")
:addClass("card_content_skill_effect")
:attr("data-card-field", "skill_" .. skillKey .. ".description_html")
:wikitext("—")
-- 右侧升级表格占位(JS 负责生成具体列数和内容)
card:tag("div")
:addClass("card_content_skill-upgrade")
:attr("data-card-field", "skill_" .. skillKey .. ".levels_table")
return card
end
-- ──────────────────────────────────────────────
-- 主渲染函数
-- ──────────────────────────────────────────────
function p.render(frame)
local name = frame.args[1] or frame.args.name or ""
name = mw.text.trim(name)
if name == "" then
return '<span class="error">错误:请提供卡片名称,例如 {{#invoke:CardData|render|复仇童谣}}</span>'
end
-- ── 最外层容器,JS 以此为根节点 ──
local root = mw.html.create("div")
:addClass("ron-card")
:attr("data-cardname", name)
-- 全屏卡面图
root:tag("div")
:addClass("card_fullscreen-img")
:attr("data-card-field", "fullscreen_img")
-- 英雄区占位高度
root:tag("div")
:addClass("card_hero")
:css("height", "100vh")
-- ── 主内容容器 ──
local container = root:tag("div"):addClass("card_content-container")
local bg = container:tag("div"):addClass("card_content-background")
local inner = bg:tag("div"):addClass("card_content-inner")
local layout = inner:tag("div"):addClass("card_content card_content--layout")
-- ════════════════════════════════
-- 左栏(sticky)
-- ════════════════════════════════
local left = layout:tag("div"):addClass("card_content_left")
-- 1. 卡名区
local nameContainer = left:tag("div"):addClass("card_content_name-container")
local nameRow = nameContainer:tag("div"):addClass("card_content_name-row")
-- 职业图标 + 文字
nameRow:tag("div")
:addClass("card_content_name-icon")
:attr("data-card-field", "profession_icon")
nameRow:tag("div")
:addClass("card_content_name-classtext")
:attr("data-card-field", "profession.name")
:wikitext("—")
-- 欲望图标 + 文字
nameRow:tag("div")
:addClass("card_content_name-icon card_content_name-icon--ml")
:attr("data-card-field", "desire_icon")
nameRow:tag("div")
:addClass("card_content_name-classtext")
:attr("data-card-field", "desire.name")
:wikitext("—")
-- 卡名 + 角色名
nameContainer:tag("div")
:addClass("card_content_name-text")
:attr("data-card-field", "card_title")
-- JS 会把「风格名 · 角色名」填进来
:wikitext("—")
-- 2. 信息(稀有度等,目前 API 只有 rarity,其他待补)
left:node(makeTitle("信息", "Info", "card_content-item-title--mt"))
left:node(makeHr())
local infoGrid = left:tag("div"):addClass("card_content_info")
-- 四项情报:JS 填充(data-card-field="info_grid")
infoGrid:attr("data-card-field", "info_grid")
-- 3. 满级属性(API 暂无,先留骨架)
left:node(makeTitle("等级 100", "Lv. Max", "card_content-item-title--mt"))
left:node(makeHr())
left:tag("div")
:addClass("card_content_attributes")
:attr("data-card-field", "attributes")
:wikitext("—")
-- 4. 映像(API 暂无,先留骨架)
left:node(makeTitle("映像", "Reflection", "card_content-item-title--mt"))
left:node(makeHr())
left:tag("div")
:addClass("card_content_reflection")
:attr("data-card-field", "reflection")
:wikitext("—")
-- 5. 认知(API 暂无,先留骨架)
left:node(makeTitle("认知", "Cognition", "card_content-item-title--mt"))
left:node(makeHr())
left:tag("div")
:addClass("card_content_cognition")
:attr("data-card-field", "cognition")
:wikitext("—")
-- ════════════════════════════════
-- 右栏
-- ════════════════════════════════
local right = layout:tag("div"):addClass("card_content_right")
-- ── 2-1. 战斗技能 ──
right:node(makeTitle("战斗技能", "Tactical", "card_content-item-title--mt"))
right:node(makeHr("card_content-item-hr--mb12"))
-- 普攻
right:node(makeSkillCard("normal_attack"))
right:tag("div"):addClass("card_content_skill-gap")
-- 被动
right:node(makeSkillCard("passive"))
right:tag("div"):addClass("card_content_skill-gap")
-- 终结技
right:node(makeSkillCard("ultimate"))
-- ── 2-2. 觉醒 ──
right:node(makeTitle("觉醒", "Feat", "card_content-item-title--mt"))
right:node(makeHr("card_content-item-hr--mb12"))
-- 觉醒列表,JS 根据 feats.stages 数组填充
right:tag("ul")
:addClass("card_content_feat-ul")
:attr("data-card-field", "feats_list")
-- ── 2-3. 小传 ──
local storySection = right:tag("div"):addClass("card_content_story")
local storyHeader = storySection:tag("div"):addClass("card_content_story-header")
local storyLeft = storyHeader:tag("div"):addClass("card_content_story-header-left")
storyLeft:node(makeTitle("小传", "Story", "card_content-item-title--mt"))
storyLeft:node(makeHr("card_content-item-hr--mb12"))
storyLeft:tag("div")
:addClass("card_content_story-toggle")
:attr("data-collapsed", "false")
:tag("span"):addClass("story-toggle-text"):wikitext("收起"):done()
:tag("span"):addClass("story-toggle-icon"):wikitext("-")
storyHeader:tag("div"):addClass("card_content_story-header-spacer")
-- 时间线,JS 根据 story 数据填充
storyHeader:tag("div")
:addClass("card_timeline card_content_story-timeline")
:attr("data-card-field", "story_timeline")
:tag("div"):addClass("card_timeline-line")
-- ── 2-4. 邀约 ──
right:tag("div"):css("height", "12px"):css("width", "100%")
right:node(makeTitle("邀约", "Date", "card_content-item-title--mt"))
right:node(makeHr("card_content-item-hr--mb12"))
-- 邀约卡片轨道,JS 填充
local dateWrap = right:tag("div"):addClass("card_content_date")
dateWrap:tag("div")
:addClass("card_content_date-track")
:tag("ul")
:addClass("card_content_date-list")
:attr("data-card-field", "date_list")
-- 邀约故事面板(点击卡片后展开)
local dateStory = right:tag("div")
:addClass("card_date_story")
:attr("id", "date-story-panel")
:attr("aria-live", "polite")
dateStory:tag("div")
:addClass("card_date_story-scene")
:attr("id", "date-story-scene")
:attr("data-card-field", "date_story_scene")
dateStory:tag("div")
:addClass("card_date_story-body")
:attr("id", "date-story-body")
:attr("data-card-field", "date_story_body")
-- ── 加载提示(JS 完成后移除)──
root:tag("div")
:addClass("ron-card-loading")
:wikitext("⏳ 加载中…")
-- 输出 HTML + CSS 模板
return tostring(root) .. frame:expandTemplate{ title = "cardcss" }
end
return p