mirror of
https://github.com/prdlk/noctalia-ostt.git
synced 2026-08-04 10:21:43 +00:00
feat(core): add example plugin with declarative and imperative API examples
This commit is contained in:
+102
@@ -0,0 +1,102 @@
|
||||
--!nonstrict
|
||||
-- Reference [[panel]] entry — a settings-style panel of interactive controls.
|
||||
--
|
||||
-- Panels describe their UI declaratively, exactly like desktop widgets: build a
|
||||
-- tree with the ui.* constructors and hand it to panel.render(). The host diffs
|
||||
-- the tree against the previous one and updates retained native controls, so
|
||||
-- rendering an unchanged tree is free.
|
||||
--
|
||||
-- panel.render(tree) replace the panel's UI tree
|
||||
-- panel.close() ask the host to close this panel
|
||||
-- panel.getConfig(key) settings (seeded from the manifest)
|
||||
-- button/toggle/slider/... onClick / onChange call the plugin global of
|
||||
-- that name; values arrive as string args
|
||||
--
|
||||
-- Layout notes:
|
||||
-- * a Flex (column/row/scroll) centers its children on the cross axis by
|
||||
-- default — pass align = "stretch" so controls fill the panel width.
|
||||
-- * panel size is host-owned: declare width/height on the [[panel]] manifest
|
||||
-- entry, so the surface is the same size on every open.
|
||||
--
|
||||
-- Stateful controls follow a controlled/uncontrolled split:
|
||||
-- * toggle / slider / select are value-driven — pass the current value each
|
||||
-- render; the callback reports the user's new value.
|
||||
-- * input is uncontrolled — `value` seeds the field once; the host owns the
|
||||
-- text buffer afterward, so re-rendering never clobbers what the user typed.
|
||||
-- Observe edits via onChange (live) / onSubmit (Enter).
|
||||
|
||||
local enabled = true
|
||||
local volume = 50
|
||||
local greeting = ""
|
||||
local themeIndex = 0
|
||||
local themes = { "Dark", "Light", "System" }
|
||||
|
||||
-- A labelled section: a heading above a control. ui.column stretches children to
|
||||
-- the panel width by default, so the control fills the row.
|
||||
local function section(title, control)
|
||||
return ui.column({ gap = 8 }, {
|
||||
ui.label({ text = title, fontWeight = "medium", color = "on_surface_variant" }),
|
||||
control,
|
||||
})
|
||||
end
|
||||
|
||||
local function render()
|
||||
-- The panel surface already insets its content (Style::panelPadding), so this
|
||||
-- adds gaps between rows, not its own outer padding.
|
||||
panel.render(ui.column({ flexGrow = 1, gap = 16 }, {
|
||||
-- Header: title on the left, close button pinned to the top right —
|
||||
-- matching the built-in panels (no divider rule).
|
||||
ui.row({ align = "center", justify = "space_between", gap = 8 }, {
|
||||
ui.label({ text = "Example Panel", fontSize = 16, fontWeight = "bold", color = "on_surface", flexGrow = 1 }),
|
||||
ui.button({ glyph = "close", onClick = "onCloseClicked" }),
|
||||
}),
|
||||
|
||||
-- Body: a scrollable stack of settings.
|
||||
ui.scroll({ flexGrow = 1, gap = 16 }, {
|
||||
section("Notifications", ui.row({ gap = 12, align = "center" }, {
|
||||
ui.toggle({ checked = enabled, onChange = "onToggle" }),
|
||||
ui.label({ text = enabled and "Enabled" or "Disabled", flexGrow = 1 }),
|
||||
})),
|
||||
|
||||
section(`Volume — {volume}%`, ui.slider({
|
||||
min = 0, max = 100, step = 1, value = volume, onChange = "onVolume",
|
||||
})),
|
||||
|
||||
section("Your name (press Enter to greet)", ui.column({ gap = 8 }, {
|
||||
ui.input({ key = "name", placeholder = "Type a name…", onSubmit = "onNameSubmit" }),
|
||||
ui.label({ text = greeting, color = "primary" }),
|
||||
})),
|
||||
|
||||
section("Theme", ui.select({ options = themes, selectedIndex = themeIndex, onChange = "onTheme" })),
|
||||
}),
|
||||
}))
|
||||
end
|
||||
|
||||
function onOpen(_context)
|
||||
render()
|
||||
end
|
||||
|
||||
function onToggle(value)
|
||||
enabled = value == "true"
|
||||
render()
|
||||
end
|
||||
|
||||
function onVolume(value)
|
||||
volume = math.floor(tonumber(value) or 0)
|
||||
render()
|
||||
end
|
||||
|
||||
function onNameSubmit(value)
|
||||
greeting = value ~= "" and `Hello, {value}!` or ""
|
||||
noctalia.notify("Example Panel", greeting)
|
||||
render()
|
||||
end
|
||||
|
||||
function onTheme(index, _text)
|
||||
themeIndex = tonumber(index) or 0
|
||||
render()
|
||||
end
|
||||
|
||||
function onCloseClicked()
|
||||
panel.close()
|
||||
end
|
||||
Reference in New Issue
Block a user