모듈:Style: 두 판 사이의 차이

편집 요약 없음
편집 요약 없음
 
(같은 사용자의 중간 판 27개는 보이지 않습니다)
1번째 줄: 1번째 줄:
local currentFrame
local HSL  = require('Module:HSL')
local HSL2 = require('Module:HSL2')
local p = {}
local p = {}


--------------------------------------------------------
 
-- 유틸: frame args 병합
function p.attr(frame)
--------------------------------------------------------
currentFrame = frame
end
 
function p.css(frame)
currentFrame = frame
end
 
 
local function getArgs(frame)
local function getArgs(frame)
local args = {}
local args = {}
22번째 줄: 34번째 줄:
end
end


--------------------------------------------------------
local function callHSL(moduleName, hex)
-- $xxx → var(--xxx)
if not currentFrame then
--------------------------------------------------------
return hex
local function convertValue(val)
end
 
local r, g, b = hexToRGB(hex)
 
return currentFrame:callParserFunction(
'#invoke',
moduleName,
'main',
'1=' .. hex,    -- ⭐ 이게 핵심
'r=' .. r,
'g=' .. g,
'b=' .. b
)
end
 
 
local function convertValue(val, isBackground)
if not val then return val end
if not val then return val end
val = mw.text.trim(val)
-- <...> 벗기기
if mw.ustring.sub(val, 1, 1) == "<"
  and mw.ustring.sub(val, -1) == ">" then
val = mw.text.trim(mw.ustring.sub(val, 2, -2))
end
-- CSS 변수
if mw.ustring.sub(val, 1, 1) == "$" then
if mw.ustring.sub(val, 1, 1) == "$" then
val = "var(--" .. mw.ustring.sub(val, 2) .. ")"
return "var(--" .. mw.ustring.sub(val, 2) .. ")"
end
end
if mw.ustring.match(val, "^##[%x%X][%x%X][%x%X][%x%X][%x%X][%x%X]$") then
    local hex = "#" .. mw.ustring.sub(val, 3)
    if isBackground then
        return "light-dark(" .. hex .. ", " .. HSL.main{ [1] = hex } .. ")"
    else
        return "light-dark(" .. hex .. ", " .. HSL2.main{ [1] = hex } .. ")"
    end
end
return val
return val
end
end


--------------------------------------------------------
 
-- 단일 속성 매핑
--------------------------------------------------------
local mapSingle = {
local mapSingle = {
-- 색/텍스트
c = "color",       
c = "color",       
bg  = "background",
bg  = "background",
49번째 줄: 96번째 줄:
ta  = "text-align",
ta  = "text-align",
gap  = "gap",
gap  = "gap",
op = "opacity",


-- 박스 크기
w  = "width",
w  = "width",
h  = "height",
h  = "height",
maxw = "max-width",
maxw = "max-width",
minw = "min-width",
minw = "min-width",
fl = "float",


-- 패딩
p  = "padding",
p  = "padding",
pt  = "padding-top",
pt  = "padding-top",
63번째 줄: 110번째 줄:
pl  = "padding-left",
pl  = "padding-left",


-- 마진
m  = "margin",
m  = "margin",
mt  = "margin-top",
mt  = "margin-top",
78번째 줄: 124번째 줄:
va  = "vertical-align",
va  = "vertical-align",
     bdrad  = "border-radius",
     bdrad  = "border-radius",
    wb  = "word-break",
}
}


--------------------------------------------------------
-- border
--------------------------------------------------------
local borderMap = {
local borderMap = {
bd  = "border",
bd  = "border",
89번째 줄: 133번째 줄:
bdb = "border-bottom",
bdb = "border-bottom",
bdl = "border-left",
bdl = "border-left",
bdw = "border-width",
}
}


101번째 줄: 146번째 줄:
ous = "outset",
ous = "outset",
}
}
local function addStyle(list, name, value)
    if not name or name == "" then return end
    if not value or value == "" then return end


local function addStyle(list, name, value)
    -- background-color, background, border-color 등을 포괄하도록 수정
if not name or name == "" then return end
    local isBackground = name:match("background") ~= nil or name:match("border") ~= nil
if not value or value == "" then return end
    value = convertValue(value, isBackground)
value = convertValue(value)
 
table.insert(list, name .. ":" .. value .. ";")
    table.insert(list, name .. ":" .. value .. ";")
end
end


local function buildBorder(token, cssName, styles)
local function buildBorder(token, cssName, styles)
-- token 예: "bd-1px-sld-$borderColor"
local parts = mw.text.split(token, "-")
local parts = mw.text.split(token, "-")
table.remove(parts, 1) -- bd / bdt / ...
table.remove(parts, 1)


local result = {}
local result = {}
119번째 줄: 166번째 줄:
table.insert(result, borderTypeMap[part])
table.insert(result, borderTypeMap[part])
else
else
table.insert(result, convertValue(part))
table.insert(result, convertValue(part, true))
end
end
end
end
126번째 줄: 173번째 줄:
end
end


--------------------------------------------------------
local function tokenizeSpec(spec)
-- 공통 파서: 스타일 + colspan/rowspan
local tokens = {}
--------------------------------------------------------
local i = 1
local len = mw.ustring.len(spec)
 
while i <= len do
local ch = mw.ustring.sub(spec, i, i)
 
if ch == "<" then
local j = i + 1
while j <= len and mw.ustring.sub(spec, j, j) ~= ">" do
j = j + 1
end
table.insert(tokens, mw.ustring.sub(spec, i, j))
i = j + 1
 
elseif ch:match("%s") then
i = i + 1
 
else
            local j = i
            while j <= len do
                local c = mw.ustring.sub(spec, j, j)
 
                if c:match("%s") then
                    break
                elseif c == "<" then
                    -- <...> 블록 통째로 포함
                    j = j + 1
                    while j <= len and mw.ustring.sub(spec, j, j) ~= ">" do
                        j = j + 1
                    end
                    j = j + 1
                else
                    j = j + 1
                end
            end
 
            table.insert(tokens, mw.ustring.sub(spec, i, j - 1))
            i = j
        end
end
 
return tokens
end
local function parseSpec(spec)
local function parseSpec(spec)
local styles = {}
    local styles = {}
local colspan, rowspan
    local colspan, rowspan


for _, token in ipairs(mw.text.split(spec, "%s+")) do
    for _, token in ipairs(tokenizeSpec(spec)) do
token = mw.text.trim(token)
        token = mw.text.trim(token)
if token ~= "" then
        if token ~= "" then
local dashPos = token:find("-")
            local dashPos = token:find("-")
if dashPos then
            if dashPos then
local key = token:sub(1, dashPos - 1)
                local key = token:sub(1, dashPos - 1)
local val = token:sub(dashPos + 1)
                local val = token:sub(dashPos + 1)


-- padding/margin 축약
                if key == "px" then
if key == "px" then
                    -- convertValue를 여기서 호출하지 않고 addStyle에 맡깁니다.
val = convertValue(val)
                    addStyle(styles, "padding-left",  val)
addStyle(styles, "padding-left",  val)
                    addStyle(styles, "padding-right", val)
addStyle(styles, "padding-right", val)
                elseif key == "py" then
elseif key == "py" then
                    addStyle(styles, "padding-top",    val)
val = convertValue(val)
                    addStyle(styles, "padding-bottom", val)
addStyle(styles, "padding-top",    val)
                elseif key == "mx" then
addStyle(styles, "padding-bottom", val)
                    addStyle(styles, "margin-left",  val)
elseif key == "mx" then
                    addStyle(styles, "margin-right", val)
val = convertValue(val)
                elseif key == "my" then
addStyle(styles, "margin-left",  val)
                    addStyle(styles, "margin-top",    val)
addStyle(styles, "margin-right", val)
                    addStyle(styles, "margin-bottom", val)
elseif key == "my" then
val = convertValue(val)
addStyle(styles, "margin-top",    val)
addStyle(styles, "margin-bottom", val)


-- border
                elseif borderMap[key] then
elseif borderMap[key] then
                    buildBorder(token, borderMap[key], styles)
buildBorder(token, borderMap[key], styles)


-- colspan/rowspan (col-3, row-2 만 사용)
                elseif key == "col" then
elseif key == "col" then
                    colspan = val
colspan = val
                elseif key == "row" then
elseif key == "row" then
                    rowspan = val
rowspan = val


-- 일반 속성
                else
else
                    local cssName = mapSingle[key]
local cssName = mapSingle[key]
                    if cssName then
if cssName then
                        -- 🟢 핵심 수정: 여기서 val = convertValue(val)를 삭제했습니다.
val = convertValue(val)
                        addStyle(styles, cssName, val)
addStyle(styles, cssName, val)
                    end
end
                end
end
            end
end
        end
end
    end
end


return table.concat(styles, " "), colspan, rowspan
    return table.concat(styles, " "), colspan, rowspan
end
end


--------------------------------------------------------
-- 1) 속성 전체(attr): style + colspan/rowspan
--    {{스타일|...}} 이 이 함수를 쓰게 할 것.
--------------------------------------------------------
function p.attr(frame)
function p.attr(frame)
local args = getArgs(frame)
local args = getArgs(frame)
195번째 줄: 273번째 줄:
local css, cToken, rToken = parseSpec(spec)
local css, cToken, rToken = parseSpec(spec)


-- 명시 파라미터(col=, row=)도 허용
local colspan = args.col or cToken
local colspan = args.col or cToken
local rowspan = args.row or rToken
local rowspan = args.row or rToken
214번째 줄: 291번째 줄:
end
end


--------------------------------------------------------
-- 2) CSS 문자열만 필요할 때(예전 방식 유지용)
--    <div style="{{스타일CSS|...}}">
--------------------------------------------------------
function p.css(frame)
function p.css(frame)
local args = getArgs(frame)
local args = getArgs(frame)

2026년 1월 2일 (금) 21:57 기준 최신판

이 모듈에 대한 설명문서는 모듈:Style/설명문서에서 만들 수 있습니다

local currentFrame

local HSL  = require('Module:HSL')
local HSL2 = require('Module:HSL2')

local p = {}


function p.attr(frame)
	currentFrame = frame
end

function p.css(frame)
	currentFrame = frame
end


local function getArgs(frame)
	local args = {}
	local parent = frame:getParent()
	if parent then
		for k, v in pairs(parent.args) do
			if v ~= nil and v ~= "" then
				args[k] = v
			end
		end
	end
	for k, v in pairs(frame.args) do
		if v ~= nil and v ~= "" then
			args[k] = v
		end
	end
	return args
end

local function callHSL(moduleName, hex)
	if not currentFrame then
		return hex
	end

	local r, g, b = hexToRGB(hex)

	return currentFrame:callParserFunction(
		'#invoke',
		moduleName,
		'main',
		'1=' .. hex,     -- ⭐ 이게 핵심
		'r=' .. r,
		'g=' .. g,
		'b=' .. b
	)
end


local function convertValue(val, isBackground)
	if not val then return val end
	val = mw.text.trim(val)

	-- <...> 벗기기
	if mw.ustring.sub(val, 1, 1) == "<"
	   and mw.ustring.sub(val, -1) == ">" then
		val = mw.text.trim(mw.ustring.sub(val, 2, -2))
	end

	-- CSS 변수
	if mw.ustring.sub(val, 1, 1) == "$" then
		return "var(--" .. mw.ustring.sub(val, 2) .. ")"
	end

if mw.ustring.match(val, "^##[%x%X][%x%X][%x%X][%x%X][%x%X][%x%X]$") then
    local hex = "#" .. mw.ustring.sub(val, 3)

    if isBackground then
        return "light-dark(" .. hex .. ", " .. HSL.main{ [1] = hex } .. ")"

    else
        return "light-dark(" .. hex .. ", " .. HSL2.main{ [1] = hex } .. ")"
    end
end


	return val
end


local mapSingle = {
	c = "color",      
	bg  = "background",
	bgc = "background-color",
	fs  = "font-size",
	fw  = "font-weight",
	ff  = "font-family",
	lh  = "line-height",
	fd  = "flex-direction",
	ls  = "letter-spacing",
	ta  = "text-align",
	gap  = "gap",
	op = "opacity",

	w   = "width",
	h   = "height",
	maxw = "max-width",
	minw = "min-width",
	fl = "float",

	p   = "padding",
	pt  = "padding-top",
	pr  = "padding-right",
	pb  = "padding-bottom",
	pl  = "padding-left",

	m   = "margin",
	mt  = "margin-top",
	mr  = "margin-right",
	mb  = "margin-bottom",
	ml  = "margin-left",

	ovf = "overflow",
	ovfx = "overflow-x",
	ovfy = "overflow-y",
	dsp = "display",
	pos = "position",
	zi  = "z-index",
	va  = "vertical-align",
    bdrad  = "border-radius",
    wb  = "word-break",
}

local borderMap = {
	bd  = "border",
	bdt = "border-top",
	bdr = "border-right",
	bdb = "border-bottom",
	bdl = "border-left",
	bdw = "border-width",
}

local borderTypeMap = {
	sld = "solid",
	dsh = "dashed",
	dot = "dotted",
	db  = "double",
	grv = "groove",
	rdg = "ridge",
	ins = "inset",
	ous = "outset",
}
local function addStyle(list, name, value)
    if not name or name == "" then return end
    if not value or value == "" then return end

    -- background-color, background, border-color 등을 포괄하도록 수정
    local isBackground = name:match("background") ~= nil or name:match("border") ~= nil
    value = convertValue(value, isBackground)

    table.insert(list, name .. ":" .. value .. ";")
end

local function buildBorder(token, cssName, styles)
	local parts = mw.text.split(token, "-")
	table.remove(parts, 1)

	local result = {}
	for _, part in ipairs(parts) do
		if borderTypeMap[part] then
			table.insert(result, borderTypeMap[part])
		else
			table.insert(result, convertValue(part, true))
		end
	end

	addStyle(styles, cssName, table.concat(result, " "))
end

local function tokenizeSpec(spec)
	local tokens = {}
	local i = 1
	local len = mw.ustring.len(spec)

	while i <= len do
		local ch = mw.ustring.sub(spec, i, i)

		if ch == "<" then
			local j = i + 1
			while j <= len and mw.ustring.sub(spec, j, j) ~= ">" do
				j = j + 1
			end
			table.insert(tokens, mw.ustring.sub(spec, i, j))
			i = j + 1

		elseif ch:match("%s") then
			i = i + 1

		else
            local j = i
            while j <= len do
                local c = mw.ustring.sub(spec, j, j)

                if c:match("%s") then
                    break
                elseif c == "<" then
                    -- <...> 블록 통째로 포함
                    j = j + 1
                    while j <= len and mw.ustring.sub(spec, j, j) ~= ">" do
                        j = j + 1
                    end
                    j = j + 1
                else
                    j = j + 1
                end
            end

            table.insert(tokens, mw.ustring.sub(spec, i, j - 1))
            i = j
        end
	end

	return tokens
end
local function parseSpec(spec)
    local styles = {}
    local colspan, rowspan

    for _, token in ipairs(tokenizeSpec(spec)) do
        token = mw.text.trim(token)
        if token ~= "" then
            local dashPos = token:find("-")
            if dashPos then
                local key = token:sub(1, dashPos - 1)
                local val = token:sub(dashPos + 1)

                if key == "px" then
                    -- convertValue를 여기서 호출하지 않고 addStyle에 맡깁니다.
                    addStyle(styles, "padding-left",  val)
                    addStyle(styles, "padding-right", val)
                elseif key == "py" then
                    addStyle(styles, "padding-top",    val)
                    addStyle(styles, "padding-bottom", val)
                elseif key == "mx" then
                    addStyle(styles, "margin-left",  val)
                    addStyle(styles, "margin-right", val)
                elseif key == "my" then
                    addStyle(styles, "margin-top",    val)
                    addStyle(styles, "margin-bottom", val)

                elseif borderMap[key] then
                    buildBorder(token, borderMap[key], styles)

                elseif key == "col" then
                    colspan = val
                elseif key == "row" then
                    rowspan = val

                else
                    local cssName = mapSingle[key]
                    if cssName then
                        -- 🟢 핵심 수정: 여기서 val = convertValue(val)를 삭제했습니다.
                        addStyle(styles, cssName, val)
                    end
                end
            end
        end
    end

    return table.concat(styles, " "), colspan, rowspan
end

function p.attr(frame)
	local args = getArgs(frame)
	local spec = mw.text.trim(args[1] or "")
	if spec == "" then return "" end

	local css, cToken, rToken = parseSpec(spec)

	local colspan = args.col or cToken
	local rowspan = args.row or rToken

	local attrs = {}

	if css ~= "" then
		table.insert(attrs, 'style="' .. css .. '"')
	end
	if colspan and colspan ~= "" then
		table.insert(attrs, 'colspan="' .. colspan .. '"')
	end
	if rowspan and rowspan ~= "" then
		table.insert(attrs, 'rowspan="' .. rowspan .. '"')
	end

	return table.concat(attrs, " ")
end

function p.css(frame)
	local args = getArgs(frame)
	local spec = mw.text.trim(args[1] or "")
	if spec == "" then return "" end

	local css = parseSpec(spec)
	return css
end

return p