Add ready-to-use example modules
All checks were successful
Mirror to GitHub / mirror (push) Successful in 2s
Build and publish package / package (push) Successful in 2m4s

examples/modules/ ships complete, drop-in bread modules for common desktop
automations (low-battery warning, pause-media-on-headphone-unplug,
dock-monitors) plus a README on installing them. Complements Examples.md,
which teaches the porting patterns.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Breadway 2026-06-16 17:06:44 +08:00
parent 13f54ad4ca
commit c47d50d16e
4 changed files with 108 additions and 0 deletions

View file

@ -0,0 +1,28 @@
# Example bread modules
Ready-to-use modules for common desktop automations. Unlike the snippets in
[`../../Examples.md`](../../Examples.md) (which teach the porting patterns),
these are complete files you can drop in as-is.
## Installing
Modules in `~/.config/bread/modules/` are **auto-discovered** — copy a file in
and reload; no `init.lua` edit needed:
```sh
cp low-battery-warning.lua ~/.config/bread/modules/
bread reload
```
## Modules
| File | What it does | Config needed |
|------|--------------|---------------|
| `low-battery-warning.lua` | Critical notification once when the battery runs low; resets on AC. | none |
| `pause-media-on-headphone-unplug.lua` | Runs `playerctl pause` when a headphone/earbud device disconnects. | none (needs `playerctl`) |
| `dock-monitors.lua` | Applies a multi-monitor layout when an external display connects, reverts when removed. | edit output names/resolutions |
Each module is the standard skeleton — `bread.module{...}`, an `on_load` that
registers subscriptions, `return M` — so they double as references for writing
your own. See [`../../Documentation.md`](../../Documentation.md) for the full
event list and Lua API.

View file

@ -0,0 +1,26 @@
-- dock-monitors — apply a monitor layout when an external display is plugged
-- in (a "dock") and revert to the laptop panel when it's removed.
--
-- Drop-in: copy into ~/.config/bread/modules/ and edit the output names /
-- resolutions for your machine (see `hyprctl monitors`).
local monitors = require("bread.monitors")
local M = bread.module({ name = "dock-monitors", version = "1.0.0" })
-- Named layouts ----------------------------------------------------------------
monitors.layout("docked", function()
bread.hyprland.keyword("monitor", "eDP-1, 1920x1200@60, 0x0, 1")
bread.hyprland.keyword("monitor", "HDMI-A-1, preferred, 1920x0, 1")
end)
monitors.layout("solo", function()
bread.hyprland.keyword("monitor", "eDP-1, preferred, 0x0, 1")
end)
-- React to the external display ------------------------------------------------
function M.on_load()
monitors.on({ when = "connected", monitors = { "HDMI-A-1" }, run = monitors.apply("docked") })
monitors.on({ when = "disconnected", monitors = { "HDMI-A-1" }, run = monitors.apply("solo") })
end
return M

View file

@ -0,0 +1,29 @@
-- low-battery-warning — notify once when the battery runs low.
--
-- Drop-in: copy into ~/.config/bread/modules/ (auto-discovered; no init.lua
-- edit needed). Zero configuration.
local M = bread.module({ name = "low-battery-warning", version = "1.0.0" })
-- Latch so we warn once per low-battery episode, not on every poll.
local warned = false
function M.on_load()
bread.on("bread.power.battery.low", function(event)
if warned then return end
warned = true
local pct = event.data.battery_percent or "?"
bread.notify("Battery low (" .. pct .. "%). Plug in soon.", {
urgency = "critical",
title = "Battery",
timeout = 10000,
})
end)
-- Reset once back on AC so the next low episode warns again.
bread.on("bread.power.ac.connected", function()
warned = false
end)
end
return M

View file

@ -0,0 +1,25 @@
-- pause-media-on-headphone-unplug — pause playback when headphones disconnect,
-- so sound doesn't suddenly blast out of the speakers.
--
-- Drop-in: copy into ~/.config/bread/modules/. Requires `playerctl`.
local M = bread.module({ name = "pause-media-on-headphone-unplug", version = "1.0.0" })
local function looks_like_headphones(name)
if not name then return false end
name = name:lower()
return name:find("head") ~= nil
or name:find("earbud") ~= nil
or name:find("airpod") ~= nil
or name:find("buds") ~= nil
end
function M.on_load()
bread.on("bread.device.disconnected", function(event)
if looks_like_headphones(event.data.name) then
bread.exec("playerctl pause")
end
end)
end
return M