익명
×
새 문서 만들기
여기에 문서 제목을 쓰세요:
We currently have 900 articles on 루리위키. Type your article name above or click on one of the titles below and start writing!



900Articles

모듈:푸른 저편의 포리듬/ 캐릭터 프로필: 두 판 사이의 차이

편집 요약 없음
편집 요약 없음
1번째 줄: 1번째 줄:
local p = {}
local p = {}


function p.main(frame)
local function safe(v)
    local args = frame:getParent().args
return v and mw.text.trim(v) or ""
end


    local color = args["색상"] or "#444"
local function row(label, value)
value = safe(value)
if value ~= "" then
return string.format('<tr><th style="width:30%%">%s</th><td>%s</td></tr>', label, value)
end
return ""
end


    local html = mw.html.create("div")
local function signatureTech(args)
    html:addClass("profile-card")
local text = ""
    html:css({
for i = 1, 5 do
        ["border"] = "2px solid "..color,
local skill = safe(args["시그니처기술" .. i])
        ["border-radius"] = "10px",
if skill ~= "" then
        ["padding"] = "12px",
text = text .. "· " .. skill .. "<br>"
        ["width"] = "100%",
end
        ["box-sizing"] = "border-box",
end
        ["background"] = "#fafafa",
return text ~= "" and text or ""
        ["font-family"] = "'Noto Sans KR', sans-serif"
end
    })


    -- 이름 영역
function p.main(frame)
    local nameBlock = mw.html.create("div")
local args = frame:getParent().args
    nameBlock:css({["text-align"] = "center", ["margin-bottom"] = "10px"})
local color = safe(args["색상"]) ~= "" and args["색상"] or "#E6E9F5"
 
    nameBlock:tag("div"):css({["font-size"] = "20px", ["font-weight"] = "bold", ["color"] = color})
        :wikitext(args["이름"] or "")


    nameBlock:tag("div"):css({["font-size"] = "13px", ["color"] = "#555"})
-- 이미지 영역 (탭 방식)
        :wikitext((args["이름_일어"] or "").." / "..(args["이름_영어"] or ""))
local imageTabs = '<div class="profile-image-tabs">'
.. '<div class="tab-buttons">'
.. '<button class="tab-btn active">애니</button>'
.. '<button class="tab-btn">VN</button>'
.. '</div><div class="tab-content active">'


    html:node(nameBlock)
if safe(args["이미지_애니"]) ~= "" then
imageTabs = imageTabs .. string.format('[[파일:%s|250px]]', args["이미지_애니"])
else
imageTabs = imageTabs .. "이미지 없음"
end


    -- 이미지 + 탭
imageTabs = imageTabs .. '</div><div class="tab-content">'
    local images = {}
    if args["이미지_VN"] and args["이미지_VN"]~="" then
        table.insert(images,'|비주얼 노벨=[[File:'..args["이미지_VN"]..'|200px]]')
    end
    if args["이미지_애니"] and args["이미지_애니"]~="" then
        table.insert(images,'|애니메이션=[[File:'..args["이미지_애니"]..'|200px]]')
    end
    if args["이미지_추가"] and args["이미지_추가"]~="" then
        table.insert(images,'|추가='..args["이미지_추가"])
    end


    if #images > 0 then
if safe(args["이미지_VN"]) ~= "" then
        html:wikitext('<div style="text-align:center; margin:10px 0;"><tabber>'..table.concat(images,"\n")..'</tabber></div>')
imageTabs = imageTabs .. string.format('[[파일:%s|250px]]', args["이미지_VN"])
    end
else
imageTabs = imageTabs .. "이미지 없음"
end


    -- 테이블 생성 함수
imageTabs = imageTabs .. '</div></div>'
    local function addRow(tbl, label, value)
        if value and value ~= "" then
            tbl:tag("tr")
                :tag("th"):wikitext(label).done()
                :tag("td"):wikitext(value)
        end
    end


    -- ▶ 기본정보 영역
-- 정보 테이블
    local infoTable = mw.html.create("table")
local info = '<table class="wikitable" style="width:100%; background:' .. color .. '; font-size:14px;">'
    infoTable:css({
.. '<tr><th colspan="2" style="text-align:center; font-size:20px;">'
        ["width"]="100%",
.. safe(args["이름"]) .. '<br><span style="font-size:13px; opacity:0.6;">'
        ["border-collapse"]="collapse",
.. safe(args["이름_일어"]) .. ' / ' .. safe(args["이름_영어"]) .. '</span></th></tr>'
        ["font-size"]="13px"
    })


    addRow(infoTable,"성별",args["성별"])
info = info
    addRow(infoTable,"나이", (args["나이_VN"]~="" and "VN: "..args["나이_VN"] or "").." / "..(args["나이_애니"]~="" and "애니: "..args["나이_애니"] or ""))   
.. '<tr><th colspan="2" style="text-align:center; background:#ccc;">기본 정보</th></tr>'
    addRow(infoTable,"생일",args["생일"])
.. row("성별", args["성별"])
    addRow(infoTable,"신장",args["신장"])
.. row("나이", (safe(args["나이_VN"]) ~= "" or safe(args["나이_애니"]) ~= "") and ("VN: " .. safe(args["나이_VN"]) .. " / Anime: " .. safe(args["나이_애니"])) or "")
    addRow(infoTable,"체중",args["체중"])
.. row("생일", args["생일"])
    addRow(infoTable,"머리색",args["머리색"])
.. row("신장", args["신장"])
    addRow(infoTable,"눈색",args["눈색"])
.. row("체중", args["체중"])
    addRow(infoTable,"학교",args["학교"])
.. row("머리색", args["머리색"])
.. row("눈색", args["눈색"])


    -- ▶ FC 프로필
info = info
    addRow(infoTable,"소속 팀",args["소속_팀"])
.. '<tr><th colspan="2" style="text-align:center; background:#ccc;">FC 프로필</th></tr>'
    addRow(infoTable,"포지션",args["포지션"])
.. row("포지션", args["포지션"])
.. row("소속 팀", args["소속_팀"])
.. row("시그니처 기술", signatureTech(args))


    for i=1,5 do
info = info
        addRow(infoTable,"시그니처 기술 "..i,args["시그니처기술"..i])
.. '<tr><th colspan="2" style="text-align:center; background:#ccc;">개인 정보</th></tr>'
    end
.. row("학교", args["학교"])
.. row("거주지", args["거주지"])
.. row("취미", args["취미"])
.. row("좋아하는 음식", args["좋아하는음식"])


    -- ▶ 기타
info = info
    addRow(infoTable,"거주지",args["거주지"])
.. '<tr><th colspan="2" style="text-align:center; background:#ccc;">성우</th></tr>'
    addRow(infoTable,"취미",args["취미"])
.. row("일본어", args["성우_JP"])
    addRow(infoTable,"좋아하는 음식",args["좋아하는음식"])
.. row("영어", args["성우_EN"])


    -- ▶ 성우 및 출연
info = info
    addRow(infoTable,"성우(JP)",args["성우_JP"])
.. '<tr><th colspan="2" style="text-align:center; background:#ccc;">데뷔</th></tr>'
    addRow(infoTable,"성우(EN)",args["성우_EN"])
.. row("애니", args["애니_데뷔"])
    addRow(infoTable,"애니 데뷔",args["애니_데뷔"])
.. row("게임(VN)", args["게임_데뷔"])
    addRow(infoTable,"게임 데뷔",args["게임_데뷔"])
.. row("만화", args["만화_데뷔"])
    addRow(infoTable,"만화 데뷔",args["만화_데뷔"])
.. "</table>"


    html:node(infoTable)
-- 구조: 데스크톱= 좌이미지+우정보 / 모바일= 이미지 위 → 정보 아래
local container = '<div class="profile-container">' .. imageTabs .. info .. "</div>"
-- CSS 삽입
container = container .. [[
<style>
.profile-container{
display:flex;
gap:10px;
align-items:flex-start;
}
@media(max-width:720px){
.profile-container{flex-direction:column; text-align:center;}
}
.profile-image-tabs{width:250px;}
.tab-buttons{display:flex; gap:5px; margin-bottom:5px;}
.tab-btn{flex:1; padding:5px; cursor:pointer; background:#ddd; border:none;}
.tab-btn.active{background:#999; font-weight:bold;}
.tab-content{display:none;}
.tab-content.active{display:block;}
</style>
<script>
document.addEventListener("DOMContentLoaded", function(){
const buttons = document.querySelectorAll(".tab-btn");
const tabs = document.querySelectorAll(".tab-content");
buttons.forEach((btn,i)=>{
btn.onclick=function(){
buttons.forEach(b=>b.classList.remove("active"));
tabs.forEach(t=>t.classList.remove("active"));
btn.classList.add("active");
tabs[i].classList.add("active");
}
})
});
</script>
]]


    return tostring(html)
return container
end
end


return p
return p

2025년 12월 5일 (금) 03:14 판

이 모듈에 대한 설명문서는 모듈:푸른 저편의 포리듬/ 캐릭터 프로필/설명문서에서 만들 수 있습니다

local p = {}

local function safe(v)
	return v and mw.text.trim(v) or ""
end

local function row(label, value)
	value = safe(value)
	if value ~= "" then
		return string.format('<tr><th style="width:30%%">%s</th><td>%s</td></tr>', label, value)
	end
	return ""
end

local function signatureTech(args)
	local text = ""
	for i = 1, 5 do
		local skill = safe(args["시그니처기술" .. i])
		if skill ~= "" then
			text = text .. "· " .. skill .. "<br>"
		end
	end
	return text ~= "" and text or ""
end

function p.main(frame)
	local args = frame:getParent().args
	local color = safe(args["색상"]) ~= "" and args["색상"] or "#E6E9F5"

	-- 이미지 영역 (탭 방식)
	local imageTabs = '<div class="profile-image-tabs">'
		.. '<div class="tab-buttons">'
		.. '<button class="tab-btn active">애니</button>'
		.. '<button class="tab-btn">VN</button>'
		.. '</div><div class="tab-content active">'

	if safe(args["이미지_애니"]) ~= "" then
		imageTabs = imageTabs .. string.format('[[파일:%s|250px]]', args["이미지_애니"])
	else
		imageTabs = imageTabs .. "이미지 없음"
	end

	imageTabs = imageTabs .. '</div><div class="tab-content">'

	if safe(args["이미지_VN"]) ~= "" then
		imageTabs = imageTabs .. string.format('[[파일:%s|250px]]', args["이미지_VN"])
	else
		imageTabs = imageTabs .. "이미지 없음"
	end

	imageTabs = imageTabs .. '</div></div>'

	-- 정보 테이블
	local info = '<table class="wikitable" style="width:100%; background:' .. color .. '; font-size:14px;">'
		.. '<tr><th colspan="2" style="text-align:center; font-size:20px;">'
		.. safe(args["이름"]) .. '<br><span style="font-size:13px; opacity:0.6;">'
		.. safe(args["이름_일어"]) .. ' / ' .. safe(args["이름_영어"]) .. '</span></th></tr>'

	info = info
		.. '<tr><th colspan="2" style="text-align:center; background:#ccc;">기본 정보</th></tr>'
		.. row("성별", args["성별"])
		.. row("나이", (safe(args["나이_VN"]) ~= "" or safe(args["나이_애니"]) ~= "") and ("VN: " .. safe(args["나이_VN"]) .. " / Anime: " .. safe(args["나이_애니"])) or "")
		.. row("생일", args["생일"])
		.. row("신장", args["신장"])
		.. row("체중", args["체중"])
		.. row("머리색", args["머리색"])
		.. row("눈색", args["눈색"])

	info = info
		.. '<tr><th colspan="2" style="text-align:center; background:#ccc;">FC 프로필</th></tr>'
		.. row("포지션", args["포지션"])
		.. row("소속 팀", args["소속_팀"])
		.. row("시그니처 기술", signatureTech(args))

	info = info
		.. '<tr><th colspan="2" style="text-align:center; background:#ccc;">개인 정보</th></tr>'
		.. row("학교", args["학교"])
		.. row("거주지", args["거주지"])
		.. row("취미", args["취미"])
		.. row("좋아하는 음식", args["좋아하는음식"])

	info = info
		.. '<tr><th colspan="2" style="text-align:center; background:#ccc;">성우</th></tr>'
		.. row("일본어", args["성우_JP"])
		.. row("영어", args["성우_EN"])

	info = info
		.. '<tr><th colspan="2" style="text-align:center; background:#ccc;">데뷔</th></tr>'
		.. row("애니", args["애니_데뷔"])
		.. row("게임(VN)", args["게임_데뷔"])
		.. row("만화", args["만화_데뷔"])
		.. "</table>"

	-- 구조: 데스크톱= 좌이미지+우정보 / 모바일= 이미지 위 → 정보 아래
	local container = '<div class="profile-container">' .. imageTabs .. info .. "</div>"
	
	-- CSS 삽입
	container = container .. [[
<style>
.profile-container{
	display:flex;
	gap:10px;
	align-items:flex-start;
}
@media(max-width:720px){
	.profile-container{flex-direction:column; text-align:center;}
}
.profile-image-tabs{width:250px;}
.tab-buttons{display:flex; gap:5px; margin-bottom:5px;}
.tab-btn{flex:1; padding:5px; cursor:pointer; background:#ddd; border:none;}
.tab-btn.active{background:#999; font-weight:bold;}
.tab-content{display:none;}
.tab-content.active{display:block;}
</style>
<script>
document.addEventListener("DOMContentLoaded", function(){
	const buttons = document.querySelectorAll(".tab-btn");
	const tabs = document.querySelectorAll(".tab-content");
	buttons.forEach((btn,i)=>{
		btn.onclick=function(){
			buttons.forEach(b=>b.classList.remove("active"));
			tabs.forEach(t=>t.classList.remove("active"));
			btn.classList.add("active");
			tabs[i].classList.add("active");
		}
	})
});
</script>
]]

	return container
end

return p