Module:Stonecutting: Difference between revisions

From I-Pixelmon
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
------------------------------------------------------------
--  Stone-cutter recipe carousel
------------------------------------------------------------
local p      = {}
local getArgs = require('Module:Arguments').getArgs
local trim    = mw.text.trim
------------------------------------------------------------------------
-- slotImage(label, image, link) → wikitext thumbnail
------------------------------------------------------------------------
local function slotImage(label, image, link)
if not label or label == '' then return '' end
local file  = (image ~= '' and image) or ('Grid_' .. label .. '.png')
local tgt  = (link  ~= '' and link ) or label
return string.format(
'[[File:%s|32px|class=pixelated|link=%s|alt=%s]]',
file, tgt, label
)
end
------------------------------------------------------------------------
-- buildFrame(args, idx) → html for one output variant
------------------------------------------------------------------------
local function buildFrame(args, idx)
local inL  = args.input              or args[1] or ''
local inI  = args['input-image']    or ''
local inLn = args['input-link']      or ''
local outL = args['output' .. idx]            or args[idx + 1] or ''
local outI = args['output' .. idx .. '-image'] or ''
local outLn= args['output' .. idx .. '-link']  or ''
local html = mw.html.create('div'):addClass('sc-frame')
html:wikitext('[[File:StonecutterGUI.png|180px|link=|alt=]]')
-- input (left)
html:tag('div'):addClass('sc-slot')
    :css{left = '11px',  top = '50px'}
    :wikitext(slotImage(inL,  inI,  inLn))
-- preview (top-centre)
html:tag('div'):addClass('sc-slot')
    :css{left = '56.5px', top = '23px'}
    :wikitext(slotImage(outL, outI, outLn))
-- output (right)
html:tag('div'):addClass('sc-slot')
    :css{left = '127px', top = '50px'}
    :wikitext(slotImage(outL, outI, outLn))
return tostring(html)
end
------------------------------------------------------------------------
------------------------------------------------------------------------
-- main entry
-- main entry
------------------------------------------------------------------------
------------------------------------------------------------------------
function p.carousel(frame)
function p.carousel(frame)
local args = getArgs(frame, {removeBlanks = false})
    local args   = getArgs(frame, {removeBlanks = false})
 
-- count non-blank outputs
local count = 0
while true do
local raw = args['output' .. (count + 1)] or args[count + 2]
if not raw or trim(tostring(raw)) == '' then break end
count = count + 1
end
if count == 0 then
return '<span style="color:red">Stonecutting: no outputs supplied</span>'
end


-- outer wrapper
local outer = mw.html.create('div')
:addClass('stonecutting-carousel')
:css{width = '180px', height = '131px', position = 'relative'}


for i = 1, count do
outer:wikitext(buildFrame(args, i))
end


-- static stylesheet (positioning etc.)
    --─── STATIC SHEET ────────────────────────────────────────────────
outer:wikitext(frame:extensionTag(
    -- pass nil, not '', or MW emits  src=""  and shows the warning
'templatestyles', '', {src = 'Stonecutting/styles.css'}
    outer:wikitext(frame:extensionTag(
))
        'templatestyles',                   -- name
        nil,                                 -- no inline content
        {src = 'Stonecutting/styles.css'}   -- external stylesheet page
    ))


------------------------------------------------------------------
    ------------------------------------------------------------------
-- dynamic stylesheet: duration & delays
    -- DYNAMIC SHEET: duration & delays
------------------------------------------------------------------
    ------------------------------------------------------------------
local dur = count * 4       -- seconds; 4 s per recipe
    local dur = count * 4         -- 4 s per recipe
local pct = 100 / count     -- slice size
    local pct = 100 / count
    local vis  = pct - 0.01        -- stay visible *almost* to the slice end


local css = {}
    local css = {}


-- global rule
    -- every frame runs the same animation;
css[#css+1] = string.format(
    -- *step-start* guarantees an instant flip with zero “off” gap
'.stonecutting-carousel .sc-frame{animation:sc-cycle %ds steps(1) infinite;}',
    css[#css+1] = string.format(
dur
        '.stonecutting-carousel .sc-frame{animation:sc-cycle %ds step-start infinite;}',
)
        dur
    )


-- per-frame delays
    -- individual start offsets
for i = 1, count do
    for i = 1, count do
css[#css+1] = string.format(
        css[#css+1] = string.format(
'.stonecutting-carousel .sc-frame:nth-child(%d){animation-delay:%ds;}',
            '.stonecutting-carousel .sc-frame:nth-child(%d){animation-delay:%ds;}',
i, (i-1)*4
            i, (i - 1) * 4
)
        )
end
    end


-- keyframes
    -- keyframes:  visible → invisible in the last 0.01 %% of the slice
css[#css+1] = string.format(
    css[#css+1] = string.format(
'@keyframes sc-cycle{0%%{opacity:1;} %.2f%%{opacity:1;} %.2f%%{opacity:0;} 100%%{opacity:0;}}',
        '@keyframes sc-cycle{0%%{opacity:1;} %.2f%%{opacity:1;} %.2f%%{opacity:0;} 100%%{opacity:0;}}',
pct, pct + 0.01
        vis, pct
)
    )


outer:wikitext(frame:extensionTag(
    outer:wikitext(frame:extensionTag(
'templatestyles',
        'templatestyles',
table.concat(css),
        table.concat(css),         -- inline CSS
{lang = 'css'}
        {lang = 'css'}
))
    ))


return tostring(outer)
    return tostring(outer)
end
end
return p

Revision as of 02:11, 14 June 2025

Documentation for this module may be created at Module:Stonecutting/doc

------------------------------------------------------------------------
-- main entry
------------------------------------------------------------------------
function p.carousel(frame)
    local args   = getArgs(frame, {removeBlanks = false})



    --─── STATIC SHEET ────────────────────────────────────────────────
    -- pass nil, not '', or MW emits  src=""  and shows the warning
    outer:wikitext(frame:extensionTag(
        'templatestyles',                    -- name
        nil,                                 -- no inline content
        {src = 'Stonecutting/styles.css'}    -- external stylesheet page
    ))

    ------------------------------------------------------------------
    -- DYNAMIC SHEET: duration & delays
    ------------------------------------------------------------------
    local dur  = count * 4          -- 4 s per recipe
    local pct  = 100 / count
    local vis  = pct - 0.01         -- stay visible *almost* to the slice end

    local css  = {}

    -- every frame runs the same animation;
    -- *step-start* guarantees an instant flip with zero “off” gap
    css[#css+1] = string.format(
        '.stonecutting-carousel .sc-frame{animation:sc-cycle %ds step-start infinite;}',
        dur
    )

    -- individual start offsets
    for i = 1, count do
        css[#css+1] = string.format(
            '.stonecutting-carousel .sc-frame:nth-child(%d){animation-delay:%ds;}',
            i, (i - 1) * 4
        )
    end

    -- keyframes:  visible → invisible in the last 0.01 %% of the slice
    css[#css+1] = string.format(
        '@keyframes sc-cycle{0%%{opacity:1;} %.2f%%{opacity:1;} %.2f%%{opacity:0;} 100%%{opacity:0;}}',
        vis, pct
    )

    outer:wikitext(frame:extensionTag(
        'templatestyles',
        table.concat(css),          -- inline CSS
        {lang = 'css'}
    ))

    return tostring(outer)
end