模块:System map:修订间差异
来自Blockland Wiki
更多操作
无编辑摘要 |
无编辑摘要 |
||
| 第102行: | 第102行: | ||
if name=='' then return nil end | if name=='' then return nil end | ||
return {name=name,page=arg(args,b..'链接'),english=arg(args,b..'英文'), | return {name=name,page=arg(args,b..'链接'),english=arg(args,b..'英文'), | ||
icon=arg(args,b..'图'),radiusEarth=number(arg(args,b..'半径'),nil), | icon=arg(args,b..'图'),rotate=number(arg(args,b..'图旋转'),0),radiusEarth=number(arg(args,b..'半径'),nil), | ||
diameterKm=number(arg(args,b..'直径km'),nil),color=tint(arg(args,b..'颜色'),'#bac3cc'), | diameterKm=number(arg(args,b..'直径km'),nil),color=tint(arg(args,b..'颜色'),'#bac3cc'), | ||
designation=arg(args,b..'编号')} | designation=arg(args,b..'编号')} | ||
end | end | ||
local function append(parts,s) parts[#parts+1]=s end | local function append(parts,s) parts[#parts+1]=s end | ||
-- | -- The orbital rail is positioned independently from the Navbox cell intrinsic width. | ||
local function renderChild(ch, title) | -- All moon glyphs sit on the same vertical descendant line as their parent disc centre. | ||
local function rotationStyle(deg) | |||
local n=number(deg,0) | |||
if n == 0 then return '' end | |||
return ' style="transform:rotate('..string.format('%.2f',clamp(n,-180,180))..'deg)"' | |||
end | |||
local function renderChild(ch,title) | |||
local current=ch.page~='' and (title==ch.page or title=='模板:'..ch.page) | local current=ch.page~='' and (title==ch.page or title=='模板:'..ch.page) | ||
local d=discSize(ch.type=='star' and 'star' or 'moon',ch.radiusEarth,ch.radiusSolar,ch.diameterKm) | local d=math.min(discSize(ch.type=='star' and 'star' or 'moon',ch.radiusEarth,ch.radiusSolar,ch.diameterKm),24) | ||
local tip=ch.name | local tip=ch.name | ||
if ch.english~='' then tip=tip..' · '..ch.english end | if ch.english~='' then tip=tip..' · '..ch.english end | ||
local parts={'<div class="blsm-child'..(current and ' blsm-current' or '')..'" title="'..html(tip)..'">', | |||
'<span class="blsm-child-glyph"><span class="blsm-child-art"'..rotationStyle(ch.rotate)..'>'} | |||
if ch.icon~='' then | if ch.icon~='' then | ||
append(parts,imageWiki(ch.icon,d)) | append(parts,imageWiki(ch.icon,d)) | ||
| 第122行: | 第126行: | ||
append(parts,'<span class="blsm-child-disc" style="width:'..math.floor(d)..'px;height:'..math.floor(d)..'px;background-color:'..ch.color..'"></span>') | append(parts,'<span class="blsm-child-disc" style="width:'..math.floor(d)..'px;height:'..math.floor(d)..'px;background-color:'..ch.color..'"></span>') | ||
end | end | ||
append(parts,'</span><span class="blsm-child-name">'..wikiLink(ch.page~='' and ch.page or ch.name,ch.name)..'</span>') | append(parts,'</span></span><span class="blsm-child-name">'..wikiLink(ch.page~='' and ch.page or ch.name,ch.name)..'</span>') | ||
if ch.designation~='' then append(parts,'<span class="blsm-child-code">'..html(ch.designation)..'</span>') end | if ch.designation~='' then append(parts,'<span class="blsm-child-code">'..html(ch.designation)..'</span>') end | ||
append(parts,'</ | append(parts,'</div>') | ||
return table.concat(parts) | return table.concat(parts) | ||
end | end | ||
local function renderRing(name, page, current) | local function renderRing(name,page,current) | ||
return '<div class="blsm-child blsm-child--ring'..(current and ' blsm-current' or '')..'" title="行星环">' | |||
..'<span class="blsm-child-glyph"><span class="blsm-ring-band"></span></span>' | ..'<span class="blsm-child-glyph"><span class="blsm-ring-band"></span></span>' | ||
..'<span class="blsm-child-name">'..wikiLink(page~='' and page or name,name)..'</span></ | ..'<span class="blsm-child-name">'..wikiLink(page~='' and page or name,name)..'</span></div>' | ||
end | end | ||
local function renderDisc(o | local function renderDisc(o) | ||
local size=discSize(o.type,o.radiusEarth,o.radiusSolar,o.diameterKm) | local size=discSize(o.type,o.radiusEarth,o.radiusSolar,o.diameterKm) | ||
if o.type=='belt' or o.type=='debris' then | if o.type=='belt' or o.type=='debris' then | ||
return '<span class="blsm-belt-band" title="小天体带"></span>' | |||
end | |||
if o.icon~='' then | |||
return '<span class="blsm-image"'..rotationStyle(o.rotate)..'>'..imageWiki(o.icon,size)..'</span>' | |||
end | end | ||
return | local c=tint(o.color,colors[o.visual] or colors.unknown) | ||
return '<span class="blsm-disc blsm-disc--'..o.visual..'" style="width:'..math.floor(size)..'px;height:'..math.floor(size)..'px;background-color:'..c..'"></span>' | |||
end | end | ||
local function renderBody(o, title, opts) | local function renderBody(o,title,opts) | ||
local parts={} | local parts={} | ||
local isBelt= | local isBelt=o.type=='belt' or o.type=='debris' | ||
local ringShown=opts.showRings and o.ring~='' | local ringShown=opts.showRings and o.ring~='' | ||
local | local childCount=#o.moons+(ringShown and 1 or 0) | ||
local width=isBelt and | local width=isBelt and 175 or (o.type=='star' and 196 or (childCount>0 and 226 or 190)) | ||
local active=(title==o.page or (opts.highlight~='' and (opts.highlight==o.page or opts.highlight==o.name))) | local active=(title==o.page or (opts.highlight~='' and (opts.highlight==o.page or opts.highlight==o.name))) | ||
local meta={o.name} | local meta={o.name} | ||
if o.english~='' then meta | if o.english~='' then append(meta,o.english) end | ||
if o.orbit~='' then meta | if o.orbit~='' then append(meta,'轨道: '..o.orbit) end | ||
if o.radiusEarth then meta | if o.radiusEarth then append(meta,'半径: '..tostring(o.radiusEarth)..' R⊕') end | ||
if o.radiusSolar then meta | if o.radiusSolar then append(meta,'半径: '..tostring(o.radiusSolar)..' R☉') end | ||
local cls=isBelt and 'blsm-slot--belt' or 'blsm-slot--body' | local cls=isBelt and 'blsm-slot--belt' or 'blsm-slot--body' | ||
if o.type=='star' then cls=cls..' blsm-slot--star' end | if o.type=='star' then cls=cls..' blsm-slot--star' end | ||
if active then cls=cls..' blsm-current' end | if active then cls=cls..' blsm-current' end | ||
append(parts,'<div class="blsm-slot '..cls..'" style="width:'..width..'px" title="'..html(table.concat(meta,' · '))..'">') | append(parts,'<div class="blsm-slot '..cls..'" style="width:'..width..'px" title="'..html(table.concat(meta,' · '))..'">') | ||
append(parts,'<div class="blsm-glyph">'..renderDisc(o)..'</div>') | |||
append(parts,'<div class="blsm-glyph">'..renderDisc(o | |||
append(parts,'<div class="blsm-name">'..wikiLink(o.page,o.name)..'</div>') | append(parts,'<div class="blsm-name">'..wikiLink(o.page,o.name)..'</div>') | ||
if opts. | local subtitle='' | ||
append(parts,'<div class="blsm-caption">'..html( | if isBelt then | ||
subtitle=o.orbit~='' and o.orbit or o.english | |||
append(parts,'<div class="blsm- | elseif o.type=='star' then | ||
subtitle=o.english | |||
elseif o.designation~='' then | |||
subtitle=(opts.numberPrefix~='' and (opts.numberPrefix..' ') or '')..o.designation | |||
elseif o.english~='' then | |||
subtitle=o.english | |||
end | |||
append(parts,'<div class="blsm-caption">'..html(subtitle)..'</div>') | |||
if opts.details and o.english~='' and o.type~='star' and not isBelt then | |||
append(parts,'<div class="blsm-extra">'..html(o.english)..'</div>') | |||
end | end | ||
if | if childCount>0 then | ||
append(parts,'<div class="blsm-children | append(parts,'<div class="blsm-children">') | ||
if ringShown then append(parts,renderRing(o.ring,o.ringPage,title==o.ringPage)) end | if ringShown then append(parts,renderRing(o.ring,o.ringPage,title==o.ringPage)) end | ||
for _,ch in ipairs(o.moons) do append(parts,renderChild(ch,title)) end | for _,ch in ipairs(o.moons) do append(parts,renderChild(ch,title)) end | ||
| 第185行: | 第194行: | ||
return {name=name,english=arg(args,base..'英文'),page=arg(args,base..'链接')~='' and arg(args,base..'链接') or name, | return {name=name,english=arg(args,base..'英文'),page=arg(args,base..'链接')~='' and arg(args,base..'链接') or name, | ||
type='star',visual='star',designation=arg(args,base..'序号')~='' and arg(args,base..'序号') or '★', | type='star',visual='star',designation=arg(args,base..'序号')~='' and arg(args,base..'序号') or '★', | ||
icon=arg(args,base..'图'),color=arg(args,base..'颜色'),orbit='', | icon=arg(args,base..'图'),rotate=number(arg(args,base..'图旋转'),0),color=arg(args,base..'颜色'),orbit='', | ||
radiusSolar=number(arg(args,base..'半径'),nil),diameterKm=number(arg(args,base..'直径km'),nil), | radiusSolar=number(arg(args,base..'半径'),nil),diameterKm=number(arg(args,base..'直径km'),nil), | ||
moons={},ring='',ringPage=''} | moons={},ring='',ringPage=''} | ||
| 第202行: | 第211行: | ||
if num=='' and ty~='belt' and ty~='debris' then num=roman(planetIndex) end | if num=='' and ty~='belt' and ty~='debris' then num=roman(planetIndex) end | ||
local o={name=name,page=fld('链接')~='' and fld('链接') or name,english=fld('英文'),type=ty,visual=visual, | local o={name=name,page=fld('链接')~='' and fld('链接') or name,english=fld('英文'),type=ty,visual=visual, | ||
designation=num,icon=fld('图'),color=fld('颜色'),orbit=fld('轨道'), | designation=num,icon=fld('图'),rotate=number(fld('图旋转'),0),color=fld('颜色'),orbit=fld('轨道'), | ||
radiusEarth=radiusEarth,diameterKm=diameterKm,moons={},ring=fld('环'),ringPage=fld('环链接')} | radiusEarth=radiusEarth,diameterKm=diameterKm,moons={},ring=fld('环'),ringPage=fld('环链接')} | ||
for j=1,16 do | for j=1,16 do | ||
| 第216行: | 第225行: | ||
args=args or {} | args=args or {} | ||
local title=trim(currentTitle) | local title=trim(currentTitle) | ||
local opts={details=arg(args,'显示详情')=='1' or arg(args,'显示详情')=='yes',highlight=arg(args,'highlight','高亮'),showRings=arg(args,'显示行星环')=='1' or arg(args,'显示行星环')=='yes'} | local opts={details=arg(args,'显示详情')=='1' or arg(args,'显示详情')=='yes',highlight=arg(args,'highlight','高亮'),showRings=arg(args,'显示行星环')=='1' or arg(args,'显示行星环')=='yes',numberPrefix=arg(args,'编号前缀')} | ||
local bodies={} | local bodies={} | ||
local primary=makeStar(args,1) | local primary=makeStar(args,1) | ||
| 第235行: | 第244行: | ||
end | end | ||
if #bodies==0 then return '<span class="blsm-empty">没有配置天体。</span>' end | if #bodies==0 then return '<span class="blsm-empty">没有配置天体。</span>' end | ||
local parts={'<div class="blsm-map"><div class="blsm-scroll" tabindex="0" role="region" aria-label="星系轨道与天体导航"> | local maxChildren=0 | ||
for _,o in ipairs(bodies) do | |||
local c=#o.moons+(opts.showRings and o.ring~='' and 1 or 0) | |||
if c>maxChildren then maxChildren=c end | |||
end | |||
local viewportHeight=math.min(460,math.max(166,148+maxChildren*30+(opts.details and 15 or 0))) | |||
-- Crucial: the scroll container is position:absolute inside a width-constrained | |||
-- relative viewport. Its max-content orbital rail does NOT participate in the | |||
-- intrinsic sizing of the Navbox table cell (Vector 2022 page overflow fix). | |||
local parts={'<div class="blsm-map"><div class="blsm-viewport" style="height:'..viewportHeight..'px">', | |||
'<div class="blsm-scroll" tabindex="0" role="region" aria-label="星系轨道与天体导航"><div class="blsm-rail">'} | |||
for _,o in ipairs(bodies) do append(parts,renderBody(o,title,opts)) end | for _,o in ipairs(bodies) do append(parts,renderBody(o,title,opts)) end | ||
append(parts,'</div></div> | append(parts,'</div></div></div></div>') | ||
return table.concat(parts) | return table.concat(parts) | ||
end | end | ||
2026年10月31日 (六) 12:43的最新版本
此模块的文档可以在模块:System map/doc创建
-- 模块:System map
-- Blockland Wiki: horizontal stellar-system map, traditional Navbox data input.
-- Self-contained: only Scribunto, TemplateStyles and the site's existing Navbox are needed.
local p = {}
local function trim(v)
local s = tostring(v or '')
s = s:gsub('^%s+', '')
s = s:gsub('%s+$','')
return s
end
local function arg(args, key, alt)
local v=trim(args[key])
if v == '' and alt then v=trim(args[alt]) end
return v
end
local function html(v)
return trim(v):gsub('&','&'):gsub('<','<'):gsub('>','>'):gsub('"','"')
end
local function wikiLink(page,label)
page=trim(page);label=trim(label)
if label=='' then label=page end
page=page:gsub('[%[%]|{}<>\r\n]','')
label=label:gsub('[%[%]|{}<>\r\n]','')
if page=='' then return html(label) end
return '[['..page..'|'..label..']]'
end
local function imageWiki(file,size)
file=trim(file):gsub('^[Ff]ile:', ''):gsub('^文件:', '')
if file=='' or file:find('[%[%]|{}<>\r\n]') then return '' end
return '[[File:'..file..'|x'..math.floor(size+0.5)..'px|link=|alt=]]'
end
local function number(v,default)
local n=tonumber(trim(v))
if not n or n ~= n or math.abs(n)>1e15 then return default end
return n
end
local function clamp(v,a,b) return math.max(a,math.min(b,v)) end
local function roman(n)
local vs={1000,900,500,400,100,90,50,40,10,9,5,4,1}
local ss={'M','CM','D','CD','C','XC','L','XL','X','IX','V','IV','I'}
local s=''
for i,v in ipairs(vs) do while n>=v do n=n-v;s=s..ss[i] end end
return s
end
local function kind(v)
v=trim(v):lower()
if v=='带' or v=='小行星带' or v=='belt' or v=='asteroid' or v=='cluster' then return 'belt' end
if v=='碎片' or v=='碎片带' or v=='debris' then return 'debris' end
if v=='ring' or v=='环' then return 'ring' end
if v=='star' or v=='恒星' then return 'star' end
if v=='dwarf' or v=='矮行星' then return 'dwarf' end
return 'planet'
end
local function tint(v, fallback)
v=trim(v)
if v:match('^#%x%x%x%x%x%x$') then return v end
return fallback
end
local colors={
star='#f0c775', rock='#b67653', lava='#e16f2e', desert='#b69a79',
ocean='#2e83ab', habitable='#2475ac', gas='#b9a9a1',
['gas-blue']='#87c7e0', ['gas-purple']='#8868b5',
['gas-orange']='#d4a279', ice='#8ec3cc', ['ice-dark']='#566c80',
dwarf='#d2dadd', moon='#b8b8b1', unknown='#a2a9b1'
}
local function styleKind(ty,classification)
local c=trim(classification):lower()
if ty=='star' then return 'star' end
if ty=='dwarf' then return 'dwarf' end
if c=='lava' or c=='熔岩' then return 'lava' end
if c=='desert' or c=='荒漠' then return 'desert' end
if c=='ocean' or c=='海洋' then return 'ocean' end
if c=='habitable' or c=='宜居' then return 'habitable' end
if c=='gas' or c=='气态' then return 'gas' end
if c=='gas-blue' or c=='蓝色气态' then return 'gas-blue' end
if c=='gas-purple' or c=='紫色气态' then return 'gas-purple' end
if c=='gas-orange' or c=='橙色气态' then return 'gas-orange' end
if c=='ice' or c=='冰质' then return 'ice' end
if c=='ice-dark' or c=='暗冰' then return 'ice-dark' end
if c=='rock' or c=='岩质' then return 'rock' end
return 'rock'
end
-- Fixed scale across systems, inspired by logarithmic tier scaling rather than AU scale.
-- Values are visual conventions, not strict physical size ratios.
local function discSize(tier, radiusEarth, radiusSolar, diameterKm)
if tier=='star' then
local r=radiusSolar or (diameterKm and diameterKm/1392700) or 1
return clamp(52+11*math.log(clamp(r,0.03,25))/math.log(3.5),36,66)
elseif tier=='moon' then
local r=radiusEarth or (diameterKm and diameterKm/12742) or .18
return clamp(8+9*math.log(clamp(r,.02,1.2)/.02)/math.log(1.2/.02),8,20)
elseif tier=='belt' or tier=='debris' then return 40
elseif tier=='ring' then return 39
end
local r=radiusEarth or (diameterKm and diameterKm/12742) or 1
return clamp(15+38*math.log(clamp(r,.13,20)/.13)/math.log(20/.13),15,53)
end
local function child(args,prefix,i)
local b=prefix..'卫星'..i
local name=arg(args,b)
if name=='' then return nil end
return {name=name,page=arg(args,b..'链接'),english=arg(args,b..'英文'),
icon=arg(args,b..'图'),rotate=number(arg(args,b..'图旋转'),0),radiusEarth=number(arg(args,b..'半径'),nil),
diameterKm=number(arg(args,b..'直径km'),nil),color=tint(arg(args,b..'颜色'),'#bac3cc'),
designation=arg(args,b..'编号')}
end
local function append(parts,s) parts[#parts+1]=s end
-- The orbital rail is positioned independently from the Navbox cell intrinsic width.
-- All moon glyphs sit on the same vertical descendant line as their parent disc centre.
local function rotationStyle(deg)
local n=number(deg,0)
if n == 0 then return '' end
return ' style="transform:rotate('..string.format('%.2f',clamp(n,-180,180))..'deg)"'
end
local function renderChild(ch,title)
local current=ch.page~='' and (title==ch.page or title=='模板:'..ch.page)
local d=math.min(discSize(ch.type=='star' and 'star' or 'moon',ch.radiusEarth,ch.radiusSolar,ch.diameterKm),24)
local tip=ch.name
if ch.english~='' then tip=tip..' · '..ch.english end
local parts={'<div class="blsm-child'..(current and ' blsm-current' or '')..'" title="'..html(tip)..'">',
'<span class="blsm-child-glyph"><span class="blsm-child-art"'..rotationStyle(ch.rotate)..'>'}
if ch.icon~='' then
append(parts,imageWiki(ch.icon,d))
else
append(parts,'<span class="blsm-child-disc" style="width:'..math.floor(d)..'px;height:'..math.floor(d)..'px;background-color:'..ch.color..'"></span>')
end
append(parts,'</span></span><span class="blsm-child-name">'..wikiLink(ch.page~='' and ch.page or ch.name,ch.name)..'</span>')
if ch.designation~='' then append(parts,'<span class="blsm-child-code">'..html(ch.designation)..'</span>') end
append(parts,'</div>')
return table.concat(parts)
end
local function renderRing(name,page,current)
return '<div class="blsm-child blsm-child--ring'..(current and ' blsm-current' or '')..'" title="行星环">'
..'<span class="blsm-child-glyph"><span class="blsm-ring-band"></span></span>'
..'<span class="blsm-child-name">'..wikiLink(page~='' and page or name,name)..'</span></div>'
end
local function renderDisc(o)
local size=discSize(o.type,o.radiusEarth,o.radiusSolar,o.diameterKm)
if o.type=='belt' or o.type=='debris' then
return '<span class="blsm-belt-band" title="小天体带"></span>'
end
if o.icon~='' then
return '<span class="blsm-image"'..rotationStyle(o.rotate)..'>'..imageWiki(o.icon,size)..'</span>'
end
local c=tint(o.color,colors[o.visual] or colors.unknown)
return '<span class="blsm-disc blsm-disc--'..o.visual..'" style="width:'..math.floor(size)..'px;height:'..math.floor(size)..'px;background-color:'..c..'"></span>'
end
local function renderBody(o,title,opts)
local parts={}
local isBelt=o.type=='belt' or o.type=='debris'
local ringShown=opts.showRings and o.ring~=''
local childCount=#o.moons+(ringShown and 1 or 0)
local width=isBelt and 175 or (o.type=='star' and 196 or (childCount>0 and 226 or 190))
local active=(title==o.page or (opts.highlight~='' and (opts.highlight==o.page or opts.highlight==o.name)))
local meta={o.name}
if o.english~='' then append(meta,o.english) end
if o.orbit~='' then append(meta,'轨道: '..o.orbit) end
if o.radiusEarth then append(meta,'半径: '..tostring(o.radiusEarth)..' R⊕') end
if o.radiusSolar then append(meta,'半径: '..tostring(o.radiusSolar)..' R☉') end
local cls=isBelt and 'blsm-slot--belt' or 'blsm-slot--body'
if o.type=='star' then cls=cls..' blsm-slot--star' end
if active then cls=cls..' blsm-current' end
append(parts,'<div class="blsm-slot '..cls..'" style="width:'..width..'px" title="'..html(table.concat(meta,' · '))..'">')
append(parts,'<div class="blsm-glyph">'..renderDisc(o)..'</div>')
append(parts,'<div class="blsm-name">'..wikiLink(o.page,o.name)..'</div>')
local subtitle=''
if isBelt then
subtitle=o.orbit~='' and o.orbit or o.english
elseif o.type=='star' then
subtitle=o.english
elseif o.designation~='' then
subtitle=(opts.numberPrefix~='' and (opts.numberPrefix..' ') or '')..o.designation
elseif o.english~='' then
subtitle=o.english
end
append(parts,'<div class="blsm-caption">'..html(subtitle)..'</div>')
if opts.details and o.english~='' and o.type~='star' and not isBelt then
append(parts,'<div class="blsm-extra">'..html(o.english)..'</div>')
end
if childCount>0 then
append(parts,'<div class="blsm-children">')
if ringShown then append(parts,renderRing(o.ring,o.ringPage,title==o.ringPage)) end
for _,ch in ipairs(o.moons) do append(parts,renderChild(ch,title)) end
append(parts,'</div>')
end
append(parts,'</div>')
return table.concat(parts)
end
local function makeStar(args,i)
local base=i==1 and '恒星' or ('恒星'..i)
local name=arg(args,base)
if name=='' then return nil end
return {name=name,english=arg(args,base..'英文'),page=arg(args,base..'链接')~='' and arg(args,base..'链接') or name,
type='star',visual='star',designation=arg(args,base..'序号')~='' and arg(args,base..'序号') or '★',
icon=arg(args,base..'图'),rotate=number(arg(args,base..'图旋转'),0),color=arg(args,base..'颜色'),orbit='',
radiusSolar=number(arg(args,base..'半径'),nil),diameterKm=number(arg(args,base..'直径km'),nil),
moons={},ring='',ringPage=''}
end
local function makeBody(args,i,planetIndex)
local base='天体'..i
local name=arg(args,base,'行星'..i)
if name=='' then return nil end
local legacy='行星'..i
local function fld(k) return arg(args,base..k,legacy..k) end
local ty=kind(fld('类型'))
local visual=styleKind(ty,fld('外观'))
local radiusEarth=number(fld('半径'),nil)
local diameterKm=number(fld('直径km'),nil)
local num=fld('序号')
if num=='' and ty~='belt' and ty~='debris' then num=roman(planetIndex) end
local o={name=name,page=fld('链接')~='' and fld('链接') or name,english=fld('英文'),type=ty,visual=visual,
designation=num,icon=fld('图'),rotate=number(fld('图旋转'),0),color=fld('颜色'),orbit=fld('轨道'),
radiusEarth=radiusEarth,diameterKm=diameterKm,moons={},ring=fld('环'),ringPage=fld('环链接')}
for j=1,16 do
local ch=child(args,base,j)
if not ch and legacy~=base then ch=child(args,legacy,j) end
if ch then o.moons[#o.moons+1]=ch end
end
if ty=='belt' or ty=='debris' then o.ring='';o.moons={} end
if ty=='ring' then o.type='belt' end
return o
end
function p.render(args,currentTitle)
args=args or {}
local title=trim(currentTitle)
local opts={details=arg(args,'显示详情')=='1' or arg(args,'显示详情')=='yes',highlight=arg(args,'highlight','高亮'),showRings=arg(args,'显示行星环')=='1' or arg(args,'显示行星环')=='yes',numberPrefix=arg(args,'编号前缀')}
local bodies={}
local primary=makeStar(args,1)
local second=makeStar(args,2)
if primary then bodies[#bodies+1]=primary end
if second and arg(args,'双星布局')~='伴星' then bodies[#bodies+1]=second end
if second and primary and arg(args,'双星布局')=='伴星' then
primary.moons[#primary.moons+1]={name=second.name,page=second.page,english=second.english,icon=second.icon,
radiusEarth=nil,radiusSolar=second.radiusSolar,diameterKm=second.diameterKm,color=tint(second.color,'#f5d78c'),type='star',designation='B'}
end
local planetCounter=0
for i=1,48 do
local o=makeBody(args,i,planetCounter+1)
if o then
if o.type~='belt' and o.type~='debris' then planetCounter=planetCounter+1 end
bodies[#bodies+1]=o
end
end
if #bodies==0 then return '<span class="blsm-empty">没有配置天体。</span>' end
local maxChildren=0
for _,o in ipairs(bodies) do
local c=#o.moons+(opts.showRings and o.ring~='' and 1 or 0)
if c>maxChildren then maxChildren=c end
end
local viewportHeight=math.min(460,math.max(166,148+maxChildren*30+(opts.details and 15 or 0)))
-- Crucial: the scroll container is position:absolute inside a width-constrained
-- relative viewport. Its max-content orbital rail does NOT participate in the
-- intrinsic sizing of the Navbox table cell (Vector 2022 page overflow fix).
local parts={'<div class="blsm-map"><div class="blsm-viewport" style="height:'..viewportHeight..'px">',
'<div class="blsm-scroll" tabindex="0" role="region" aria-label="星系轨道与天体导航"><div class="blsm-rail">'}
for _,o in ipairs(bodies) do append(parts,renderBody(o,title,opts)) end
append(parts,'</div></div></div></div>')
return table.concat(parts)
end
function p.main(frame)
local args=frame:getParent() and frame:getParent().args or frame.args
local title=''
if mw and mw.title and mw.title.getCurrentTitle then
local t=mw.title.getCurrentTitle();title=t and (t.text or t.prefixedText) or ''
end
return p.render(args,title)
end
return p