편집 요약 없음 |
편집 요약 없음 |
||
| 1번째 줄: | 1번째 줄: | ||
local p = {} | local p = {} | ||
local mw = mw | |||
local tt = mw.text | |||
function | -- 안전 문자열 트림 | ||
local function trim(s) | |||
if not s then return '' end | |||
return tt.trim(tostring(s)) | |||
end | |||
-- 시그니처 기술 수집 (시그니처기술1..10) | |||
local function gather_techs(args) | |||
local techs = {} | |||
for i = 1, 10 do | |||
local k = '시그니처기술' .. i | |||
if args[k] and args[k] ~= '' then | |||
table.insert(techs, trim(args[k])) | |||
end | |||
end | |||
-- 리스트 아이템 HTML로 반환 | |||
if #techs > 0 then | |||
local tstr = '<ul class="prf-list">' | |||
for _, tname in ipairs(techs) do | |||
tstr = tstr .. string.format('<li>%s</li>', mw.text.escape(tname)) | |||
end | |||
tstr = tstr .. '</ul>' | |||
return tstr | |||
end | end | ||
return '' | |||
end | |||
-- 이미지 블록 (탭 기능 대신 선택된 이미지 반환) | |||
local function build_image_block(args) | |||
local version = trim(args['버전'] or 'VN') | |||
local file_name = '' | |||
if version == 'Anime' then | |||
file_name = trim(args['이미지_Anime'] or '') | |||
else -- VN 또는 기본값 | |||
file_name = trim(args['이미지_VN'] or '') | |||
end | |||
if file_name ~= '' then | |||
<div class=" | return string.format('<div class="prf-img-wrapper">[[파일:%s|250px|center]]</div>', mw.text.encode(file_name)) | ||
else | |||
return '<div class="prf-img-wrapper">[[파일:NoImage.png|250px|center]]</div>' | |||
end | |||
end | |||
-- 라벨+값 행 생성 (값 없으면 빈 문자열) | |||
local function info_row(label, value) | |||
if not value or value == '' then return '' end | |||
-- 목록 형태로 반환 | |||
return string.format('<li><strong>%s</strong>: %s</li>', mw.text.escape(label), mw.text.escape(value)) | |||
end | |||
<div class=" | -- 섹션 헤더 생성 | ||
local function section_header(title) | |||
return string.format('<div class="prf-header"><h4>%s</h4></div>', mw.text.escape(title)) | |||
end | |||
-- 나이 출력 규칙 | |||
local function build_age_row(args) | |||
local nv = trim(args['나이_VN']) | |||
local na = trim(args['나이_애니']) | |||
local age_str = '' | |||
if nv ~= '' and na ~= '' then | |||
age_str = string.format('VN %s / Anime %s', mw.text.escape(nv), mw.text.escape(na)) | |||
elseif nv ~= '' then | |||
age_str = string.format('VN %s', mw.text.escape(nv)) | |||
elseif na ~= '' then | |||
age_str = string.format('Anime %s', mw.text.escape(na)) | |||
else | |||
return '' | |||
end | |||
return info_row('나이', age_str) | |||
end | |||
< | -- 메인 생성 함수 | ||
. | function p.main(frame) | ||
. | local parent = frame:getParent() or frame | ||
. | local args = parent.args or {} | ||
for k, v in pairs(args) do args[k] = trim(v) end | |||
. | |||
. | local theme = args['색상'] and args['색상'] ~= '' and args['색상'] or '#007bff' | ||
. | |||
-- ********** 데이터 구성 ********** | |||
local image_block = build_image_block(args) | |||
. | |||
-- 이름 블록 | |||
local name_block = '' | |||
. | name_block = name_block .. string.format('<div class="prf-name-kr">%s</div>', mw.text.escape(args['이름'] or '')) | ||
. | local sub_name = {} | ||
if args['이름_일어'] then table.insert(sub_name, mw.text.escape(args['이름_일어'])) end | |||
</ | if args['이름_영어'] then table.insert(sub_name, mw.text.escape(args['이름_영어'])) end | ||
if #sub_name > 0 then | |||
< | name_block = name_block .. string.format('<div class="prf-name-sub">%s</div>', table.concat(sub_name, ' / ')) | ||
end | |||
-- 섹션별 정보 구성 | |||
local sections = {} | |||
-- 1. 기본 정보 | |||
local basic = { | |||
info_row('성별', args['성별']), | |||
build_age_row(args), | |||
info_row('생일', args['생일']), | |||
info_row('신장', args['신장']), | |||
info_row('체중', args['체중']), | |||
info_row('머리색', args['머리색']), | |||
info_row('눈색', args['눈색']), | |||
} | |||
-- 2. FC 프로필 | |||
local fc_techs = gather_techs(args) | |||
local fc = { | |||
info_row('포지션', args['포지션']), | |||
} | |||
if fc_techs ~= '' then | |||
-- 시그니처 기술은 별도 HTML로 구성 | |||
table.insert(fc, string.format('<li><strong>시그니처 기술</strong>:%s</li>', fc_techs)) | |||
end | |||
-- 3. 개인 정보 | |||
local personal = { | |||
info_row('학교', args['학교']), | |||
info_row('거주지', args['거주지']), | |||
info_row('취미', args['취미']), | |||
info_row('좋아하는 음식', args['좋아하는음식']), | |||
} | |||
-- 4. 성우 | |||
local voice = { | |||
info_row('일본어', args['성우_JP']), | |||
info_row('영어', args['성우_EN']), | |||
} | |||
-- 5. 데뷔 | |||
local debut = { | |||
info_row('애니메이션', args['애니_데뷔']), | |||
info_row('게임(VN)', args['게임_데뷔']), | |||
info_row('만화', args['만화_데뷔']), | |||
} | |||
-- ********** HTML 문자열 조립 ********** | |||
local html = {} | |||
-- 전체 컨테이너 시작 | |||
table.insert(html, string.format('<div class="prf-card-wrap" style="border: 1px solid %s; border-radius: 5px; max-width: 600px; margin: 1em auto;">', theme)) | |||
table.insert(html, '<div class="prf-card-inner" style="display: flex; flex-wrap: wrap;">') | |||
-- 좌측: 이미지 및 스위치 (40%) | |||
table.insert(html, '<div class="prf-left-col" style="flex: 0 0 40%; padding: 10px; border-right: 1px solid #ddd;">') | |||
table.insert(html, image_block) | |||
-- 버전 스위치 (간단한 HTML 텍스트로 대체) | |||
table.insert(html, '<div style="text-align: center; font-size: 85%; margin-top: 5px;">(VN / Anime 스위치 필요)</div>') | |||
table.insert(html, '</div>') | |||
-- 우측: 정보 (60%) | |||
table.insert(html, '<div class="prf-right-col" style="flex: 1 1 58%; padding: 10px; background-color: #f9f9f9;">') | |||
-- 이름 블록 | |||
table.insert(html, string.format('<div class="prf-name-block">%s</div>', name_block)) | |||
table.insert(html, '<hr style="border: 0; border-top: 1px solid #ccc; margin: 8px 0;">') | |||
-- 섹션 추가 함수 (빈 섹션은 제외) | |||
local function add_section(title, data_table) | |||
local content = table.concat(data_table, '\n') | |||
if content ~= '' then | |||
table.insert(html, section_header(title)) | |||
table.insert(html, string.format('<ul class="prf-section-list">%s</ul>', content)) | |||
end | |||
end | |||
add_section('기본 정보', basic) | |||
add_section('FC 프로필', fc) | |||
add_section('개인 정보', personal) | |||
add_section('성우', voice) | |||
add_section('데뷔', debut) | |||
table.insert(html, '</div>') -- prf-right-col 닫기 | |||
table.insert(html, '</div>') -- prf-card-inner 닫기 | |||
table.insert(html, '</div>') -- prf-card-wrap 닫기 | |||
< | |||
-- ********** CSS 정의 ********** | |||
-- 인라인 CSS는 HTML 요소에 직접 넣었지만, 여기서 추가적인 스타일 정의 (선택 사항) | |||
local style = [[ | |||
<style> | |||
/* 폰트, 리스트 스타일 등 추가 정의 가능 */ | |||
.prf-name-kr { font-size: 1.3em; font-weight: bold; color: ]] .. theme .. [[; } | |||
.prf-name-sub { font-size: 0.9em; color: #555; margin-top: 2px; } | |||
.prf-header h4 { margin: 8px 0 4px 0; padding: 0; font-size: 1em; color: ]] .. theme .. [[; border-bottom: 1px solid ]] .. theme .. [[; font-weight: bold; } | |||
) | .prf-section-list, .prf-list { list-style: none; margin: 0 0 10px 0; padding: 0; } | ||
.prf-section-list li, .prf-list li { margin: 3px 0; font-size: 0.95em; } | |||
.prf-img-wrapper { text-align: center; } | |||
@media screen and (max-width: 600px) { | |||
.prf-left-col, .prf-right-col { flex: 0 0 100% !important; border-right: none !important; } | |||
.prf-left-col { border-bottom: 1px solid #ddd; } | |||
} | |||
</style> | |||
]] | |||
-- 최종 출력: 스타일 + HTML 문자열 | |||
return style .. table.concat(html, '\n') | |||
end | end | ||
return p | return p | ||
2025년 12월 5일 (금) 03:18 판
이 모듈에 대한 설명문서는 모듈:푸른 저편의 포리듬/ 캐릭터 프로필/설명문서에서 만들 수 있습니다
local p = {}
local mw = mw
local tt = mw.text
-- 안전 문자열 트림
local function trim(s)
if not s then return '' end
return tt.trim(tostring(s))
end
-- 시그니처 기술 수집 (시그니처기술1..10)
local function gather_techs(args)
local techs = {}
for i = 1, 10 do
local k = '시그니처기술' .. i
if args[k] and args[k] ~= '' then
table.insert(techs, trim(args[k]))
end
end
-- 리스트 아이템 HTML로 반환
if #techs > 0 then
local tstr = '<ul class="prf-list">'
for _, tname in ipairs(techs) do
tstr = tstr .. string.format('<li>%s</li>', mw.text.escape(tname))
end
tstr = tstr .. '</ul>'
return tstr
end
return ''
end
-- 이미지 블록 (탭 기능 대신 선택된 이미지 반환)
local function build_image_block(args)
local version = trim(args['버전'] or 'VN')
local file_name = ''
if version == 'Anime' then
file_name = trim(args['이미지_Anime'] or '')
else -- VN 또는 기본값
file_name = trim(args['이미지_VN'] or '')
end
if file_name ~= '' then
return string.format('<div class="prf-img-wrapper">[[파일:%s|250px|center]]</div>', mw.text.encode(file_name))
else
return '<div class="prf-img-wrapper">[[파일:NoImage.png|250px|center]]</div>'
end
end
-- 라벨+값 행 생성 (값 없으면 빈 문자열)
local function info_row(label, value)
if not value or value == '' then return '' end
-- 목록 형태로 반환
return string.format('<li><strong>%s</strong>: %s</li>', mw.text.escape(label), mw.text.escape(value))
end
-- 섹션 헤더 생성
local function section_header(title)
return string.format('<div class="prf-header"><h4>%s</h4></div>', mw.text.escape(title))
end
-- 나이 출력 규칙
local function build_age_row(args)
local nv = trim(args['나이_VN'])
local na = trim(args['나이_애니'])
local age_str = ''
if nv ~= '' and na ~= '' then
age_str = string.format('VN %s / Anime %s', mw.text.escape(nv), mw.text.escape(na))
elseif nv ~= '' then
age_str = string.format('VN %s', mw.text.escape(nv))
elseif na ~= '' then
age_str = string.format('Anime %s', mw.text.escape(na))
else
return ''
end
return info_row('나이', age_str)
end
-- 메인 생성 함수
function p.main(frame)
local parent = frame:getParent() or frame
local args = parent.args or {}
for k, v in pairs(args) do args[k] = trim(v) end
local theme = args['색상'] and args['색상'] ~= '' and args['색상'] or '#007bff'
-- ********** 데이터 구성 **********
local image_block = build_image_block(args)
-- 이름 블록
local name_block = ''
name_block = name_block .. string.format('<div class="prf-name-kr">%s</div>', mw.text.escape(args['이름'] or ''))
local sub_name = {}
if args['이름_일어'] then table.insert(sub_name, mw.text.escape(args['이름_일어'])) end
if args['이름_영어'] then table.insert(sub_name, mw.text.escape(args['이름_영어'])) end
if #sub_name > 0 then
name_block = name_block .. string.format('<div class="prf-name-sub">%s</div>', table.concat(sub_name, ' / '))
end
-- 섹션별 정보 구성
local sections = {}
-- 1. 기본 정보
local basic = {
info_row('성별', args['성별']),
build_age_row(args),
info_row('생일', args['생일']),
info_row('신장', args['신장']),
info_row('체중', args['체중']),
info_row('머리색', args['머리색']),
info_row('눈색', args['눈색']),
}
-- 2. FC 프로필
local fc_techs = gather_techs(args)
local fc = {
info_row('포지션', args['포지션']),
}
if fc_techs ~= '' then
-- 시그니처 기술은 별도 HTML로 구성
table.insert(fc, string.format('<li><strong>시그니처 기술</strong>:%s</li>', fc_techs))
end
-- 3. 개인 정보
local personal = {
info_row('학교', args['학교']),
info_row('거주지', args['거주지']),
info_row('취미', args['취미']),
info_row('좋아하는 음식', args['좋아하는음식']),
}
-- 4. 성우
local voice = {
info_row('일본어', args['성우_JP']),
info_row('영어', args['성우_EN']),
}
-- 5. 데뷔
local debut = {
info_row('애니메이션', args['애니_데뷔']),
info_row('게임(VN)', args['게임_데뷔']),
info_row('만화', args['만화_데뷔']),
}
-- ********** HTML 문자열 조립 **********
local html = {}
-- 전체 컨테이너 시작
table.insert(html, string.format('<div class="prf-card-wrap" style="border: 1px solid %s; border-radius: 5px; max-width: 600px; margin: 1em auto;">', theme))
table.insert(html, '<div class="prf-card-inner" style="display: flex; flex-wrap: wrap;">')
-- 좌측: 이미지 및 스위치 (40%)
table.insert(html, '<div class="prf-left-col" style="flex: 0 0 40%; padding: 10px; border-right: 1px solid #ddd;">')
table.insert(html, image_block)
-- 버전 스위치 (간단한 HTML 텍스트로 대체)
table.insert(html, '<div style="text-align: center; font-size: 85%; margin-top: 5px;">(VN / Anime 스위치 필요)</div>')
table.insert(html, '</div>')
-- 우측: 정보 (60%)
table.insert(html, '<div class="prf-right-col" style="flex: 1 1 58%; padding: 10px; background-color: #f9f9f9;">')
-- 이름 블록
table.insert(html, string.format('<div class="prf-name-block">%s</div>', name_block))
table.insert(html, '<hr style="border: 0; border-top: 1px solid #ccc; margin: 8px 0;">')
-- 섹션 추가 함수 (빈 섹션은 제외)
local function add_section(title, data_table)
local content = table.concat(data_table, '\n')
if content ~= '' then
table.insert(html, section_header(title))
table.insert(html, string.format('<ul class="prf-section-list">%s</ul>', content))
end
end
add_section('기본 정보', basic)
add_section('FC 프로필', fc)
add_section('개인 정보', personal)
add_section('성우', voice)
add_section('데뷔', debut)
table.insert(html, '</div>') -- prf-right-col 닫기
table.insert(html, '</div>') -- prf-card-inner 닫기
table.insert(html, '</div>') -- prf-card-wrap 닫기
-- ********** CSS 정의 **********
-- 인라인 CSS는 HTML 요소에 직접 넣었지만, 여기서 추가적인 스타일 정의 (선택 사항)
local style = [[
<style>
/* 폰트, 리스트 스타일 등 추가 정의 가능 */
.prf-name-kr { font-size: 1.3em; font-weight: bold; color: ]] .. theme .. [[; }
.prf-name-sub { font-size: 0.9em; color: #555; margin-top: 2px; }
.prf-header h4 { margin: 8px 0 4px 0; padding: 0; font-size: 1em; color: ]] .. theme .. [[; border-bottom: 1px solid ]] .. theme .. [[; font-weight: bold; }
.prf-section-list, .prf-list { list-style: none; margin: 0 0 10px 0; padding: 0; }
.prf-section-list li, .prf-list li { margin: 3px 0; font-size: 0.95em; }
.prf-img-wrapper { text-align: center; }
@media screen and (max-width: 600px) {
.prf-left-col, .prf-right-col { flex: 0 0 100% !important; border-right: none !important; }
.prf-left-col { border-bottom: 1px solid #ddd; }
}
</style>
]]
-- 최종 출력: 스타일 + HTML 문자열
return style .. table.concat(html, '\n')
end
return p