Module:ItemBox: Difference between revisions

Jannepg (talk | contribs)
m added a min font size.
Vergir (talk | contribs)
Emit the name size in cqw against the name area, dropping the em conversion and grid snapping (with help from vergir-bot LLM)
 
(5 intermediate revisions by 2 users not shown)
Line 1: Line 1:
local p = {}
local p = {}
local ustring = mw.ustring
local textfit = require "Module:TextFit"


-- ============================================================================
--  Name box geometry, in em of .itembox's font-size (1em = 10px at size=1).
--  Mirrors Template:ItemBox/styles.css:
--    .itembox            width: 8em
--    .itembox-name-area  height: 4.5em; padding: 0.5em 0.4em (border-box)
--    .itembox-name      line-height: 1.2; font-size: 1.5em (overridden inline)
--  so the name's content box is 8 - 2*0.4 = 7.2em wide and 4.5 - 2*0.5 = 3.5em
--  tall. Only the ratio and the size limits are read from those figures: the
--  size is emitted in cqw against .itembox-name-area, so the browser supplies
--  the actual width. Glyph widths live in [[Module:TextFit]].
-- ============================================================================
local NAME_W = 7.2
local NAME_H = 3.5
local LINE_H = 1.2
local MAX_EM = 1.5
local MIN_EM = 0.8
-- Returns the name font size as a cqw string, measured against
-- .itembox-name-area, which [[Template:ItemBox]] makes a query container.
function p.getFontSize(frame)
function p.getFontSize(frame)
     local name = frame.args[1] or ""
     local name = ustring.gsub(frame.args[1] or "", "^%s*(.-)%s*$", "%1")
    local words = {}
     local max = MAX_EM / NAME_W * 100          -- 20.83cqw
    for word in name:gmatch("%S+") do
     if name == "" then return string.format("%.2fcqw", max) end
        table.insert(words, word)
    end
   
    local function wordWidth(word)
    word = word:lower()
        local width = 0
        for i = 1, #word do
            local c = word:sub(i, i)
            if c == "i" or c == "l" then
                width = width + 0.5
            elseif c == "m" or c == "w" then
                width = width + 1.5
            else
                width = width + 1
            end
        end
        return math.ceil(width)
    end
   
     local longestLine
 
    if #words == 1 then
        longestLine = wordWidth(words[1])
 
    elseif #words == 2 then
        longestLine = math.max(wordWidth(words[1]), wordWidth(words[2]))
 
     elseif #words == 3 then
        local first = wordWidth(words[1])
        local mid  = wordWidth(words[2])
        local last  = wordWidth(words[3])
 
        local shorterOuter = math.min(first, last)
        local longerOuter  = math.max(first, last)
 
        local combined = mid + 1 + shorterOuter
 
        longestLine = math.max(combined, longerOuter)
    end


local fullSize = 15
    return string.format("%.2fcqw", textfit.fit(name, {
     local fontSize
        aspect    = NAME_H / NAME_W,
        lineHeight = LINE_H,
        max        = max,
        min        = MIN_EM / NAME_W * 100,    -- 11.11cqw
     }))
end


     if longestLine <= 8 then
-- User for stable per-item texture variety
        fontSize = fullSize
local function hash(s)
    else
     local h = 5381
         fontSize = fullSize - (longestLine - 8) * 1
    for i = 1, #s do
         h = (h * 33 + s:byte(i)) % 2147483647
     end
     end
      
     return h
    fontSize = math.max(6, fontSize)
end


     return fontSize
function p.variants(frame)
    local h = hash(frame.args[1] or "")
    local icon = (h % 3) + 1
    local wear = (math.floor(h / 3) % 4) + 1
    local tex  = (math.floor(h / 12) % 3) + 1
     return string.format("itembox-icon-v%d itembox-wear-v%d itembox-texture-v%d",
        icon, wear, tex)
end
end


return p
return p