Files
community-plugins/mango_layouts/panel.luau
T
EzequielandGitHub 44925e4be6 feat: add mango_layouts plugin (#192)
* feat: add mango_layouts plugin

* fix: address CI validation errors

* refactor: inline apply_layout script for cross-device portability

* fix: commit inlined script changes in panel.luau

* fix: address official PR review feedback

* fix: revert noctalia.translate which caused runtime crash

* fix: remove setGlyph empty string to prevent fallback skull icon

* feat: restore translations using correct noctalia.tr API

* refactor: remove unused label fields from layouts table
2026-08-03 16:17:29 -04:00

175 lines
5.7 KiB
Luau

local layouts = {
{ sym = "T", name = "tile", glyph = "layout-sidebar" },
{ sym = "S", name = "scroller", glyph = "carousel-horizontal" },
{ sym = "M", name = "monocle", glyph = "square" },
{ sym = "G", name = "grid", glyph = "layout-grid" },
{ sym = "F", name = "fair", glyph = "layout-board-split" },
{ sym = "D", name = "deck", glyph = "layers-difference" },
{ sym = "DW", name = "dwindle", glyph = "layout-2" },
{ sym = "CT", name = "center_tile", glyph = "layout-distribute-vertical" },
{ sym = "VT", name = "vertical_tile", glyph = "layout-rows" },
{ sym = "RT", name = "right_tile", glyph = "layout-sidebar-right" },
{ sym = "VS", name = "vertical_scroller",glyph = "carousel-vertical" },
{ sym = "VG", name = "vertical_grid", glyph = "grid-dots" },
{ sym = "VD", name = "vertical_deck", glyph = "chart-funnel" },
{ sym = "VF", name = "vertical_fair", glyph = "layout-board" },
}
local COLUMNS = 4
local COLUMN_GAP = 2
local selectedLayout = ""
local pickSlots = {}
local render
local function onPickAt(index)
local slot = pickSlots[index]
if slot == nil then return end
selectedLayout = slot.sym
noctalia.runAsync("mmsg dispatch setlayout," .. slot.entry.name)
panel.close()
end
local function makeGrid(children)
local rows = {}
local row = {}
for i, child in ipairs(children) do
table.insert(row, child)
if #row >= COLUMNS or i == #children then
while #row < COLUMNS do
table.insert(row, ui.spacer({ flexGrow = 1 }))
end
table.insert(rows, ui.row({ gap = COLUMN_GAP, align = "stretch" }, row))
row = {}
end
end
return ui.column({ gap = COLUMN_GAP }, rows)
end
local function getShowConfig(name)
if name == "tile" then return noctalia.getConfig("show_tile") end
if name == "scroller" then return noctalia.getConfig("show_scroller") end
if name == "monocle" then return noctalia.getConfig("show_monocle") end
if name == "grid" then return noctalia.getConfig("show_grid") end
if name == "fair" then return noctalia.getConfig("show_fair") end
if name == "deck" then return noctalia.getConfig("show_deck") end
if name == "dwindle" then return noctalia.getConfig("show_dwindle") end
if name == "center_tile" then return noctalia.getConfig("show_center_tile") end
if name == "vertical_tile" then return noctalia.getConfig("show_vertical_tile") end
if name == "right_tile" then return noctalia.getConfig("show_right_tile") end
if name == "vertical_scroller" then return noctalia.getConfig("show_vertical_scroller") end
if name == "vertical_grid" then return noctalia.getConfig("show_vertical_grid") end
if name == "vertical_deck" then return noctalia.getConfig("show_vertical_deck") end
if name == "vertical_fair" then return noctalia.getConfig("show_vertical_fair") end
return true
end
local function renderButtons(is_list_mode)
local buttons = {}
local i = 0
for _, entry in ipairs(layouts) do
local raw_val = getShowConfig(entry.name)
local enabled = (raw_val == true) or (raw_val == "true") or (raw_val == nil)
if enabled then
local slotIndex = i
local isSelected = selectedLayout == entry.sym
pickSlots[slotIndex] = { sym = entry.sym, entry = entry }
if is_list_mode then
table.insert(buttons, ui.button({
key = entry.sym,
glyph = entry.glyph,
text = noctalia.tr("name_" .. entry.name),
variant = if isSelected then "primary" else "ghost",
onClick = `onPick{slotIndex}`,
-- If noctalia supports button alignment, this will align it to the left:
-- (If not, it will just remain centered like an elegant menu)
}))
else
-- Grid Mode
table.insert(buttons, ui.column({
key = entry.sym,
gap = 2,
align = "center",
flexGrow = 1,
}, {
ui.button({
glyph = entry.glyph,
glyphSize = 18,
variant = if isSelected then "primary" else "ghost",
onClick = `onPick{slotIndex}`,
}),
ui.label({
text = noctalia.tr("name_" .. entry.name),
fontSize = 9,
fontWeight = "bold",
color = if isSelected then "primary" else "on_surface_variant",
textAlign = "center",
maxLines = 1,
}),
}))
end
i += 1
end
end
return buttons
end
render = function()
pickSlots = {}
local list_mode_raw = noctalia.getConfig("list_mode")
local is_list_mode = (list_mode_raw == true) or (list_mode_raw == "true")
local content
if is_list_mode then
content = ui.column({ padding = 8, gap = 4 }, renderButtons(true))
else
content = ui.column({ padding = 12, gap = COLUMN_GAP }, {
makeGrid(renderButtons(false))
})
end
panel.render(ui.column({ flexGrow = 1 }, {
ui.scroll({ flexGrow = 1 }, {
content
})
}))
end
function onOpen(context)
selectedLayout = ""
render()
noctalia.runAsync(
"mmsg get all-monitors | jq -r '.monitors[] | select(.active == true and .last_open_surface != null) | .layout_symbol'",
function(result)
if result == nil or result.exitCode ~= 0 then return end
local sym = result.stdout:gsub("%s+", "")
-- Check if sym exists in our ordered list
local exists = false
for _, l in ipairs(layouts) do
if l.sym == sym then exists = true end
end
selectedLayout = if exists then sym else ""
render()
end
)
end
function onPick0() onPickAt(0) end
function onPick1() onPickAt(1) end
function onPick2() onPickAt(2) end
function onPick3() onPickAt(3) end
function onPick4() onPickAt(4) end
function onPick5() onPickAt(5) end
function onPick6() onPickAt(6) end
function onPick7() onPickAt(7) end
function onPick8() onPickAt(8) end
function onPick9() onPickAt(9) end
function onPick10() onPickAt(10) end
function onPick11() onPickAt(11) end
function onPick12() onPickAt(12) end
function onPick13() onPickAt(13) end