Module:Color

From Wiki of ZZT
Revision as of 07:53, 12 January 2021 by Quantum (talk | contribs) (WIP: Playing with a different color swatch style)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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

local p = {}

local ega_hex_codes = {
	"#000",
	"#00a",
	"#0a0",
	"#0aa",
	"#a00",
	"#a0a",
	"#a50",
	"#aaa",
	"#555",
	"#55f",
	"#5f5",
	"#5ff",
	"#f55",
	"#f5f",
	"#ff5",
	"#fff"
}

local ega_color_names = {
	"black",
	"dark blue",
	"dark green",
	"dark cyan",
	"dark red",
	"dark purple",
	"dark brown",
	"light gray",
	"dark gray",
	"blue",
	"green",
	"cyan",
	"red",
	"purple",
	"yellow",
	"white"
}

function p.swatch(frame)
	local bg = string_to_index(frame.args.bg)
	local fg = string_to_index(frame.args.fg)
	return combo_name(bg, fg) .. " " .. tostring(swatch_html(bg, fg))
end

function swatch_html(bg, fg)
	local blinking = is_blinking(bg)
	bg = non_blinking(bg)

	local outer = mw.html.create("span")
	outer:css({
		width = "1.25em",
		height = "1em",
		["background-color"] = index_to_hex_color(bg),
		["box-shadow"] = "0 0 1px #808080",
		display = "inline-flex",
		["align-items"] = "center",
		["justify-content"] = "center"
	})
	local inner = outer:tag("span")
	inner:css({
		display = "inline-block",
		width = "0.5em",
		height = "0.5em"
	})
	if blinking then
		local hex_color = index_to_hex_color(fg)
		local gradient = "linear-gradient(135deg, {h} 0% 50%, {h}0 50% 100%)" 
		gradient = string.gsub(gradient, "{h}", hex_color)
		inner:css({
			background = gradient,
			["box-shadow"] = "inset 0 0 0 1px " .. hex_color
		})
	else
		inner:css("background-color", index_to_hex_color(fg))
	end
	return outer
end

function combo_name(bg, fg)
	local blinking = is_blinking(bg)
	if blinking then
		bg = non_blinking(bg)
	end
	result = index_to_name(fg) .. " on " .. index_to_name(bg)
	if blinking then
		result = "blinking " .. result
	end
	return result
end

function is_blinking(index)
	return index ~= nil and index >= 8
end

function non_blinking(index)
	if index == nil then
		return nil
	elseif index < 8 then
		return index
	end
	return index - 8
end

function index_to_name(i)
	if i == nil then
		return "???"
	end
	return ega_color_names[i + 1]
end

function index_to_hex_color(i)
	return ega_hex_codes[i + 1]
end

function string_to_index(input)
	-- Handle decimal numbers, hex numbers starting with "0x"
	local number = tonumber(input)
	if number ~= nil then
		if number ~= math.floor(number) or number < 0 or number > 15 then
			return nil
		end
		return number
	end
	
	-- Handle strings
	local name = string.gsub(input, "grey", "gray")
	name = string.gsub(name, "^light ", "")
	local special_cases = {
		["dark yellow"] = "dark brown",
		brown           = "dark brown",
		gray            = "light gray",
	}
	if special_cases[name] ~= nil then
		name = special_cases[name]
	end
	for i = 1, #ega_color_names do
		if name == ega_color_names[i] then
			return i - 1
		end
	end
	return nil
end

return p