diff --git a/todo/README.md b/todo/README.md index bb3e701..5b67cf3 100644 --- a/todo/README.md +++ b/todo/README.md @@ -33,6 +33,14 @@ noctalia msg panel-toggle nightwatch75/todo:panel | **Enter**, or ✓ (row) | Commit the edit — the row goes back to a static line | | ☐ / ☑ button (row) | Toggle done/to-do (done tasks are struck through) | | 🗑 button (row) | Delete the task | +| ⚙ button (panel header) | Open this plugin's page in *Settings → Plugins* | + +That settings page also opens from the command line, so it can be bound in your +compositor too: + +```sh +noctalia msg settings-open-plugin nightwatch75/todo +``` ## Priorities @@ -79,6 +87,10 @@ close. Tick a task (☐ → ☑) to complete it — its text is struck through until you un-tick it. The bar glyph's tooltip shows how many tasks are still to do. +A task longer than the row wraps onto further lines and the row grows to fit, +so the whole text stays readable and never runs under the buttons on the +right. + ## Storage Tasks live in one file, `todo.json`, inside the configured **To Do folder** @@ -111,7 +123,9 @@ noctalia msg plugins enable nightwatch75/todo ## Requirements -- noctalia with plugin API ≥ 5 (declarative drag-and-drop) +- noctalia v5.0.0-beta.6 or newer — the first tagged release that accepts + `plugin_api = 15` (`noctalia.openSettings()`, the panel's ⚙ button; + declarative drag-and-drop needs 5) - No external dependencies ## License diff --git a/todo/panel.luau b/todo/panel.luau index ca55e3f..b74440a 100644 --- a/todo/panel.luau +++ b/todo/panel.luau @@ -30,6 +30,38 @@ -- The bar widget (todo.luau) lights its glyph while the panel is open via the -- shared "todo_open" state; it reads todo.json itself for the pending count. +-- Row width budget. A Button constrains its label only when it has an explicit +-- width (the host derives the label's max width from it); flexGrow alone lets a +-- long task overrun the buttons to its right instead of shrinking. So the text +-- button is given whatever the fixed parts of the row leave over. +-- +-- The constrained label WRAPS, it does not ellipsize: Button sets the label's +-- maxWidth and TextEllipsize::End but never a maxLines, and the text renderer +-- only ellipsizes against an explicit line budget — with maxLines 0 Pango is +-- given the full 500-line backstop and wraps freely. Wrapping is what we want +-- here (the whole task stays readable), and the row grows to fit because +-- Button pins only a minimum height. +-- Every constant below mirrors one in noctalia's Style, named so the sum can be +-- re-checked against the host rather than re-measured by eye. +local PANEL_WIDTH = 400 -- keep in sync with [[panel]] width in plugin.toml +local PANEL_PADDING = 14 -- Style::panelPadding, applied left and right +local SCROLLBAR_GUTTER = 14 -- Style::scrollbarWidth (6) + Style::scrollbarGap (8) +local ROW_GAP = 8 -- the task row's own gap +local CHIP_W = 16 -- the priority chip +local GRIP_W = 24 -- the ☰ drag grip, manual mode only +local GLYPH_BTN_W = 30 -- ghost glyph button: 2 × Style::spaceSm + a 14px glyph +local ROW_CONTENT_W = PANEL_WIDTH - (2 * PANEL_PADDING) - SCROLLBAR_GUTTER + +-- Width left for the task text once the chip, the optional grip and the +-- `trailing` glyph buttons (each preceded by a gap) have taken their share. +local function taskTextWidth(withGrip, trailing) + local width = ROW_CONTENT_W - CHIP_W - ROW_GAP - (trailing * (GLYPH_BTN_W + ROW_GAP)) + if withGrip then + width -= GRIP_W + ROW_GAP + end + return width +end + local PRIORITIES = { "important", "medium", "low" } local RANK = { important = 1, medium = 2, low = 3 } local COLORS = { important = "#e06c75", medium = "#e5c07b", low = "#98c379" } @@ -403,12 +435,14 @@ local function taskRow(item) })) else -- Static text; clicking it re-opens the editor ("press on the text"). + -- The explicit width is what makes a long task wrap onto another line + -- instead of running under the three buttons that follow it. table.insert(children, ui.button({ key = "view-" .. id, text = item.done and strike(item.text) or item.text, variant = "ghost", contentAlign = "start", - flexGrow = 1, + width = taskTextWidth(grip ~= nil, 3), onClick = function() enterEdit(id) end, @@ -510,6 +544,7 @@ render = function() onClick = "onClearDone", }), ui.button({ key = "header-add", glyph = "plus", variant = "primary", tooltip = tr("tip_add"), onClick = "onAdd" }), + ui.button({ key = "header-settings", glyph = "settings", variant = "ghost", tooltip = tr("tip_settings"), onClick = "onOpenSettings" }), ui.button({ key = "header-close", glyph = "close", variant = "ghost", tooltip = tr("tip_close"), onClick = "onClosePanel" }), }) @@ -650,6 +685,13 @@ function onClearDoneCancel() render() end +-- Opens the settings window on this plugin's own page (the host supplies the +-- plugin id, so a plugin can only ever open its own). It closes the panel on +-- the way, so onClose flushes any pending edit first. +function onOpenSettings() + noctalia.openSettings() +end + function onClosePanel() panel.close() end diff --git a/todo/plugin.toml b/todo/plugin.toml index 1e525d0..58addfc 100644 --- a/todo/plugin.toml +++ b/todo/plugin.toml @@ -8,8 +8,8 @@ id = "nightwatch75/todo" name = "To Do" -version = "0.0.10" -plugin_api = 9 +version = "0.0.14" +plugin_api = 15 author = "nightwatch75" license = "MIT" dependencies = [] diff --git a/todo/translations/en.json b/todo/translations/en.json index f2c7764..4ffc04a 100644 --- a/todo/translations/en.json +++ b/todo/translations/en.json @@ -30,6 +30,7 @@ "tip_grip": "Drag to reorder", "tip_grip_drop": "Click another grip to drop here, or this one to cancel", "tip_sort": "Switch ordering mode", + "tip_settings": "Plugin settings", "tip_undone": "Mark as to do", "title": "To Do", "tooltip": "To Do — {count} to do"