macotron.menubar
Add your own items to the menu bar next to the Macotron icon, give them menus with HTML rows and button rows, and add rows to the Macotron menu itself.
// A countdown in the menu bar with a menu of actions.
let until = 0;
function paint() {
const left = Math.max(0, until - Date.now());
macotron.menubar.status("timer", {
title: left ? new Date(left).toISOString().slice(14, 19) : "",
sfSymbol: "timer",
color: left ? "green" : null,
minWidth: left ? 72 : undefined,
menu: [
{ title: left ? "Running" : "Stopped", dimmed: true },
"-",
{ title: "Start 25 minutes", onClick: () => { until = Date.now() + 25 * 60000; paint(); } },
{ title: "Stop", onClick: () => { until = 0; paint(); } },
],
});
}
paint();
macotron.every(1000, paint);
Status items
A status item is a separate item in the menu bar, to the left of the Macotron icon. Each plugin can add as many as it likes, keyed by id.
status(id: string, opts: StatusOptions): void
Creates the item, or repaints it when an item with that id exists. Call it again whenever the content changes; a call that changes nothing costs almost nothing, so painting on a timer is fine. macOS remembers each item's position by its id.
A left-click runs onClick. With a menu as well, right-click or Control-click opens the menu. With a menu and no onClick, any click opens the menu. Clicks act on mouse-down, like the system items.
The tooltip is the title, followed by the subtitle when there is one.
| Option | Type | What it does |
|---|---|---|
title | string | The text. When you leave it out, the item shows its id, so pass "" for an icon-only item. |
subtitle | string | A second line under the title. Both lines then draw at a smaller size to fit the bar. |
secondary | boolean | Draws the subtitle smaller and dimmer than the title. Off by default, so both lines share one size and color. |
color | string | Text color: red, orange, yellow, green, blue, purple, pink, gray, white, black, or #RGB / #RRGGBB. In an icon-only item it tints the SF Symbol instead. |
subtitleColor | string | Subtitle color, in the same forms. Defaults to color. |
bold, italic | boolean | Font style. With secondary, the subtitle is never bold. |
minWidth | number | Minimum width in points. Use it for a changing number, so proportional digits do not push the neighboring items around. |
sfSymbol | string | An SF Symbol name, such as "timer", drawn before the text. icon is an alias. |
image | string | Path to an image file, scaled to 18 points high. It replaces sfSymbol. A file name that ends in Template (for example meterTemplate.png) is treated as a mask that the bar tints. |
svg | string | SVG markup to draw as the icon. It replaces image and sfSymbol. Its own colors are kept unless template is true. |
template | boolean | Treats svg as a mask that the menu bar tints to suit its background. Off by default. |
sparkline | object | { values, width?, height?, color? }: a line graph of values, scaled between their minimum and maximum. Size defaults to 36 x 18 points. color is #RRGGBB; without it the line is a mask the bar tints. It replaces svg, image and sfSymbol. |
onClick | () => void | Runs on a left-click. |
onHover | (hovering: boolean) => void | Runs with true when the pointer enters the item and false when it leaves. |
menu | MenuBarMenuItem[] | The item's menu. See Menus. |
required | boolean | Default true. When the user Command-drags a required item out of the menu bar, Settings warns and offers a Restore button. Pass false for an item that is fine to hide. |
Pick colors for a non-template svg with isDark(), not macotron.system.darkMode(). The menu bar follows the wallpaper, so it can draw light text while the system is in Light Mode. Repaint on the menubar:appearance event.
isVisible(id: string): boolean
Whether a status item is on screen. It is false when the user dragged the item out of the menu bar, when the bar has no room to draw it (usually because of the notch), and for an unknown id. Settings already warns about both cases, so few plugins need to ask.
remove(id: string): void
Removes the status item with this id, and the Macotron menu row with this id if there is one.
Status items stay on screen while plugins reload. After the reload, Macotron removes every item that no plugin painted again.
Menus
A menu is an array. Each element is a MenuBarMenuItem object, the string "-" for a separator, or any other string for a plain text row.
| Field | Type | What it does |
|---|---|---|
title | string | The row's text. |
icon | string | An SF Symbol name drawn before the title. A one- or two-character string, such as an emoji, goes in front of the title text instead. |
onClick | () => void | Runs when the row is chosen. The menu closes. A row without onClick still draws in full color, so you can use it as a label. |
dimmed | boolean | Draws the title in the secondary label color but keeps the row clickable. Use it for rows such as past events. |
menu | MenuBarMenuItem[] | A submenu. A row with a submenu ignores its own onClick. |
html | string | Shows a web page as the row instead of a title. See below. |
width, height | number | Size of an html row in points, 260 x 160 by default. Width is limited to 60–800 and height to 24–600. For a buttons row, width is the starting width. |
buttons | MenuBarMenuItem[] | Draws these items as buttons across one row. See below. |
HTML rows
An html row is a small web view. Your markup goes into a page with a transparent background, the 13px system font, and light and dark color schemes. The page keeps running while the menu is open, so CSS animations and images work. When the menu is wider than the row, the page is centered.
The row reloads only when the markup changes, so repainting the menu every second does not restart the page.
Menu tracking takes mouse events before the page sees them. Treat an HTML row as a display. Put clickable things in ordinary rows or a buttons row.
Button rows
A row with buttons draws each item's title as a button, spread evenly across the menu width. Clicking a button runs its onClick and leaves the menu open, so you can page or step through content without closing the menu. Repaint the menu in the handler to show the new state. Button icons are not drawn.
// From the mini-calendar plugin: page through months without closing the menu.
menu: [
{ title: monthName },
{ html: grid(cells), width: 220, height: rows * 24 + 6 },
{ buttons: [
{ title: "‹", onClick: () => move(-1) },
{ title: "Today", onClick: () => move(-offset) },
{ title: "›", onClick: () => move(1) },
] },
"-",
{ title: "Open Calendar…", onClick: () => macotron.app.launch("com.apple.iCal") },
]
The Macotron menu
These calls add rows to the menu under the Macotron icon, above the built-in rows.
add(id: string, opts: { title, icon?, section?, onClick?, menu? }): void
Adds a row, or replaces the row with that id. icon works as in a menu item. onClick runs when the row is chosen. With a menu, the row opens that submenu instead.
Rows without a section come first. Rows with a section are grouped under a header with that name, and the sections are sorted by name.
macotron.menubar.add("system-metrics-menu", {
title: "CPU " + cpu + "%",
icon: "cpu",
section: "System",
});
update(id: string, opts: { title?, icon? }): void
Changes the title or icon of an existing row and keeps everything else. Does nothing for an unknown id.
remove(id: string): void
Removes the row. It also removes a status item with the same id.
The Macotron icon
setIcon(sfSymbolName: string): void
Replaces the Macotron glyph with an SF Symbol.
setIconColor(color?: string | null): void
Tints the Macotron icon. Accepts the same color names and hex forms as status. Pass null to go back to the normal menu bar color. The tint is cleared on reload unless a plugin sets it again.
setTitle(text: string): void
Shows text next to the Macotron icon. Pass "" to clear it.
isDark(): boolean
Whether the menu bar draws light text right now. It follows the wallpaper as well as the system theme.
Events
menubar:appearance
Fires when the menu bar switches between light and dark text. There is no payload; call isDark().
macotron.on("menubar:appearance", paint);
See also
- macotron.panel for a full window when a menu is not enough.
- macotron.notify for toasts and banners.
- The
pomodoro.js,mini-calendar.jsandsystem-metrics.jsplugins.