Files
community-plugins/ds4-color/panel.luau
T

144 lines
3.8 KiB
Luau

--!nonstrict
--!nocheck
--!nolint UnknownGlobal
local tr = noctalia.tr("ds4_color")
local SERVICE = "hy4ri/ds4-color:service"
-- Validate a color is exactly 6 hex chars (no metachars / quote-breakers can
-- survive this, so it is safe to interpolate into the runAsync shell string).
local function isHex6(s)
return type(s) == "string" and s:match("^[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]$") ~= nil
end
local function sendToService(event, payload)
local cmd = "noctalia msg plugin " .. SERVICE .. " all " .. event
if payload ~= nil then cmd = cmd .. " '" .. payload .. "'" end
noctalia.runAsync(cmd, function() end)
end
local function currentColor()
return noctalia.state.get("lastColor") or "990000"
end
local applyPreset
local function render()
local color = currentColor()
local presets = noctalia.state.get("presets") or {}
local presetRow = {}
for i, p in ipairs(presets) do
local presetIndex = i
local selected = (p.hex:lower() == color:lower())
table.insert(presetRow, ui.box({
width = 34,
height = 34,
fill = "#" .. p.hex,
radius = 8,
border = "outline",
borderWidth = selected and 3 or 1,
onClick = function() applyPreset(presetIndex) end,
}))
end
panel.render(ui.column({ gap = 10, padding = 12 }, {
ui.row({ align = "center", justify = "space_between" }, {
ui.label({ text = tr, fontSize = 18, fontWeight = "bold", color = "primary", flexGrow = 1 }),
ui.button({ glyph = "close", onClick = "onCloseClicked" }),
}),
-- Live swatch preview
ui.box({
width = 200,
height = 72,
fill = "#" .. color,
radius = 12,
border = "outline",
borderWidth = 2,
onClick = "onNativePicker",
}),
-- Hex field + native picker button
ui.row({ gap = 8, align = "center" }, {
ui.input({
key = "hex-input",
value = "#" .. color,
flexGrow = 1,
onSubmit = "onSubmitHex",
}),
ui.button({ glyph = "color-picker", variant = "ghost", onClick = "onNativePicker" }),
}),
ui.label({ text = noctalia.tr("presets"), fontSize = 13, color = "on_surface_variant" }),
ui.row({ gap = 8, align = "center" }, presetRow),
ui.row({ gap = 8 }, {
ui.button({
text = noctalia.tr("save"),
variant = "ghost",
onClick = "onSave",
flexGrow = 1,
}),
ui.button({
text = noctalia.tr("apply"),
variant = "primary",
onClick = "onApply",
flexGrow = 1,
}),
}),
}))
end
--==== callbacks ====
function onApply()
local c = currentColor()
if isHex6(c) then sendToService("apply", c) end
end
function onSave()
local c = currentColor()
if isHex6(c) then sendToService("save", c) end
end
function onSubmitHex(text)
local hex = text:match("^#?([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])$")
or text:match("^0x([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])$")
if hex == nil or not isHex6(hex) then
noctalia.notifyError(tr, noctalia.tr("bad_color"))
return
end
noctalia.state.set("lastColor", hex:upper())
render()
end
function onNativePicker()
noctalia.openColorPicker("#" .. currentColor(), function(color)
if color == nil then return end
local hex = color:match("#?(%x%x%x%x%x%x)")
if hex ~= nil then
noctalia.state.set("lastColor", hex:upper())
render()
end
end)
end
function onCloseClicked()
panel.close()
end
function onClose()
end
applyPreset = function(i)
local presets = noctalia.state.get("presets") or {}
local p = presets[i]
if p == nil then return end
noctalia.state.set("lastColor", p.hex:upper())
render()
end
function onOpen(context)
noctalia.state.watch("lastColor", function() render() end)
render()
end