### Running Systray Examples Source: https://github.com/glzr-io/zebar/blob/main/crates/systray-util/README.md Command-line instructions to run the synchronous and asynchronous (tokio) examples provided with the systray-util library. ```shell # Run the synchronous example. cargo run -p systray-util --example sync # Run the asynchronous (tokio) example. cargo run -p systray-util --example async ``` -------------------------------- ### Install pnpm and Project Dependencies Source: https://github.com/glzr-io/zebar/blob/main/CONTRIBUTING.md Install the pnpm package manager globally, then install project dependencies. This is a prerequisite for running the development server. ```shell # Install pnpm (package manager). npm i -g pnpm # Install dependencies. pnpm i ``` -------------------------------- ### Run Development Server Source: https://github.com/glzr-io/zebar/blob/main/packages/settings-ui/README.md Starts the application in development mode for active development and testing. ```bash npm run dev ``` -------------------------------- ### Initialize Zebar Providers for GlazeWM Source: https://github.com/glzr-io/zebar/blob/main/resources/starter/with-glazewm.html Sets up various Zebar providers including network, GlazeWM, CPU, date, battery, memory, and weather. This is the initial setup for the status bar. ```javascript import React, { useState, useEffect, } from 'https://esm.sh/react@18?dev'; import { createRoot } from 'https://esm.sh/react-dom@18/client?dev'; import * as zebar from 'https://esm.sh/zebar@3.0'; const providers = zebar.createProviderGroup({ network: { type: 'network' }, glazewm: { type: 'glazewm' }, cpu: { type: 'cpu' }, date: { type: 'date', formatting: 'EEE d MMM t' }, battery: { type: 'battery' }, memory: { type: 'memory' }, weather: { type: 'weather' }, }); createRoot(document.getElementById('root')).render(); ``` -------------------------------- ### Install Dependencies Source: https://github.com/glzr-io/zebar/blob/main/packages/settings-ui/README.md Installs project dependencies using npm, pnpm, or yarn. ```bash npm install # or pnpm install or yarn install ``` -------------------------------- ### Programmatically Start Another Widget Source: https://context7.com/glzr-io/zebar/llms.txt Use `startWidget` or `startWidgetPreset` to spawn new widget windows at specified placements or using presets from `zpack.json`. This is useful for triggering popups from a main widget. ```typescript import { startWidget, startWidgetPreset, type WidgetPlacement } from 'zebar'; // Open a popup at the top-right corner of the primary monitor const placement: WidgetPlacement = { anchor: 'top_right', offsetX: '0', offsetY: '40px', width: '300px', height: '400px', monitorSelection: { type: 'primary' }, dockToEdge: { enabled: false }, }; await startWidget('notification-popup', placement); // Or use a named preset defined in zpack.json await startWidgetPreset('notification-popup', 'compact'); // Open a widget from a different pack await startWidget('volume-overlay', placement, { packId: 'audio-widgets' }); ``` -------------------------------- ### Local Zebar NPM Package Configuration Example Source: https://github.com/glzr-io/zebar/blob/main/CONTRIBUTING.md An example of a package.json file when using a locally linked zebar NPM package. The 'zebar' dependency points to a local path using a 'link:' prefix. ```json { "dependencies": { "zebar": "link:../../repos/zebar/packages/client-api" } } ``` -------------------------------- ### Start Zebar in Development Mode Source: https://github.com/glzr-io/zebar/blob/main/CONTRIBUTING.md Run the Zebar application in development mode. The configuration will be loaded from ~/.glzr/zebar/. ```shell # Start in development mode. (config: ~/.glzr/zebar/) pnpm dev ``` -------------------------------- ### Audio Provider for Device Control Source: https://context7.com/glzr-io/zebar/llms.txt Utilizes the 'audio' provider to access and control audio devices. This example shows how to get default playback device information, list all playback devices, and set volume or mute state for specific devices. Note: This provider is Windows-only. ```typescript import { createProvider } from 'zebar'; const audio = createProvider({ type: 'audio' }); audio.onOutput(async output => { const dev = output.defaultPlaybackDevice; if (!dev) return; console.log(`Device: ${dev.name}`); console.log(`Volume: ${dev.volume}%`); console.log(`Muted: ${dev.isMuted}`); console.log(`Type: ${dev.type}`); // 'playback' | 'recording' // List all playback devices for (const d of output.playbackDevices) { console.log(` [${d.isDefaultPlayback ? 'default' : ' '}] ${d.name} — ${d.volume}%`); } // Set default playback device volume to 50% await output.setVolume(50); // Set volume for a specific device by ID await output.setVolume(30, { deviceId: dev.deviceId }); // Mute/unmute a specific device await output.setMute(true, { deviceId: dev.deviceId }); await output.setMute(false); }); ``` -------------------------------- ### createProvider Source: https://context7.com/glzr-io/zebar/llms.txt Creates a single reactive provider instance for system data. The provider starts fetching data immediately and can be stopped using the `.stop()` method. ```APIDOC ## createProvider ### Description Creates one provider instance from a typed config object. The generic parameter is inferred from the `type` field, so the returned object is fully typed. The provider starts fetching immediately; call `.stop()` when the widget is unmounted to clean up IPC listeners. ### Method Signature ```typescript createProvider(config: ProviderConfig): ProviderInstance ``` ### Parameters #### `config` (object) - Required Configuration object for the provider. - **type** (string) - Required - The type of system data to provide (e.g., 'cpu', 'memory', 'battery'). - **refreshInterval** (number) - Optional - The interval in milliseconds to refresh the data. - **formatting** (string) - Optional - Formatting options for specific provider types (e.g., 'date'). ### Example ```typescript import { createProvider } from 'zebar'; // CPU provider — refreshes every 2 seconds const cpu = createProvider({ type: 'cpu', refreshInterval: 2000 }); cpu.onOutput(output => { console.log(`CPU usage: ${output.usage.toFixed(1)}%`); console.log(`Frequency: ${output.frequency} MHz`); console.log(`Cores: ${output.physicalCoreCount}P / ${output.logicalCoreCount}L`); console.log(`Vendor: ${output.vendor}`); }); cpu.onError(err => console.error('CPU provider error:', err)); // Access the latest snapshot synchronously (null until first emission) console.log(cpu.output?.usage); // Restart or stop when done await cpu.restart(); await cpu.stop(); ``` ``` -------------------------------- ### Get OS Name, Version, Hostname, and Uptime Source: https://context7.com/glzr-io/zebar/llms.txt The host provider retrieves static and semi-static system identification information, including OS name, version, hostname, and uptime. Configure a refresh interval for periodic updates. ```typescript import { createProvider } from 'zebar'; const host = createProvider({ type: 'host', refreshInterval: 60000 }); host.onOutput(output => { console.log(`Hostname: ${output.hostname}`); console.log(`OS name: ${output.osName}`); // => 'Darwin' | 'Windows' | 'Debian GNU/Linux' ... console.log(`OS ver: ${output.osVersion}`); // => '13.2.1' | '11 22000' | '9' console.log(`Friendly: ${output.friendlyOsVersion}`); // => 'macOS 13.2.1' | 'Windows 11 Pro' | 'Linux Debian GNU/Linux 9' const uptimeSec = output.uptime / 1000; const hours = Math.floor(uptimeSec / 3600); const mins = Math.floor((uptimeSec % 3600) / 60); console.log(`Uptime: ${hours}h ${mins}m`); }); ``` -------------------------------- ### Create Keyboard Provider for Active Keyboard Layout Source: https://context7.com/glzr-io/zebar/llms.txt Initializes a keyboard provider to get the active keyboard layout tag. This provider is Windows-only and can be used to adapt UI elements based on the user's input method. ```typescript import { createProvider } from 'zebar'; const keyboard = createProvider({ type: 'keyboard', refreshInterval: 5000 }); keyboard.onOutput(output => { console.log(`Layout: ${output.layout}`); // => 'en-US' document.getElementById('layout')!.textContent = output.layout; }); ``` -------------------------------- ### Execute Shell Commands with Zebar Source: https://context7.com/glzr-io/zebar/llms.txt Use `shellExec` to run a command and get its output, or `shellSpawn` to stream output from a long-running process. Ensure the `shell` privilege is configured in `zpack.json` for the commands you intend to run. The `encoding` option can be set to 'raw' to receive binary output. ```typescript import { shellExec, shellSpawn } from 'zebar'; // One-shot command — await completion const result = await shellExec('git', ['rev-parse', '--short', 'HEAD'], { cwd: '/home/user/project', }); console.log('Git hash:', result.stdout.trim()); console.log('Exit code:', result.code); // Long-running process — stream output const ping = await shellSpawn('ping', ['127.0.0.1', '-c', '5']); ping.onStdout(line => { console.log('stdout:', line); // => stdout: 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.041 ms }); ping.onStderr(line => console.error('stderr:', line)); ping.onExit(({ exitCode, signal }) => { console.log(`Exited with code ${exitCode}`); }); // Send input to stdin or kill the process ping.write('some input\n'); ping.kill(); // Binary output example const raw = await shellExec('ffmpeg', ['-version'], { encoding: 'raw', }); console.log('Bytes:', raw.stdout.byteLength); ``` -------------------------------- ### Create Network Provider for Interface Info and Traffic Source: https://context7.com/glzr-io/zebar/llms.txt Initializes a network provider to get network interface information and real-time traffic statistics. This cross-platform provider returns details about the default interface, gateway, and per-second received/transmitted traffic. ```typescript import { createProvider } from 'zebar'; const network = createProvider({ type: 'network', refreshInterval: 5000 }); network.onOutput(output => { const iface = output.defaultInterface; if (iface) { console.log(`Interface: ${iface.friendlyName ?? iface.name}`); console.log(`Type: ${iface.type}`); // 'wifi' | 'ethernet' | ... console.log(`IPv4: ${iface.ipv4Addresses.join(', ')}`); console.log(`MAC: ${iface.macAddress}`); } const gw = output.defaultGateway; if (gw) { console.log(`SSID: ${gw.ssid ?? 'N/A'}`); console.log(`Signal: ${gw.signalStrength ?? 'N/A'}`); } const traffic = output.traffic; if (traffic) { console.log(`↓ ${traffic.received.siValue.toFixed(1)} ${traffic.received.siUnit}/s`); console.log(`↑ ${traffic.transmitted.siValue.toFixed(1)} ${traffic.transmitted.siUnit}/s`); // => ↓ 1.2 MB/s // => ↑ 0.3 MB/s } }); ``` -------------------------------- ### Initialize Zebar Providers and Render App Source: https://github.com/glzr-io/zebar/blob/main/resources/starter/vanilla.html Sets up Zebar providers for various system metrics and renders the main React application component. Ensure the 'root' element exists in your HTML. ```javascript import React, { useState, useEffect, } from 'https://esm.sh/react@18?dev'; import { createRoot } from 'https://esm.sh/react-dom@18/client?dev'; import * as zebar from 'https://esm.sh/zebar@3.0'; const providers = zebar.createProviderGroup({ network: { type: 'network' }, cpu: { type: 'cpu' }, date: { type: 'date', formatting: 'EEE d MMM t' }, battery: { type: 'battery' }, memory: { type: 'memory' }, weather: { type: 'weather' }, }); createRoot(document.getElementById('root')).render(); ``` -------------------------------- ### Publish Widget Pack (Basic) Source: https://github.com/glzr-io/zebar/blob/main/MARKETPLACE.md Use this command for a basic publish operation. Ensure your API token is provided. ```bash zebar publish --token your-api-token ``` -------------------------------- ### Initialize Zebar Providers and Render React App Source: https://github.com/glzr-io/zebar/blob/main/resources/starter/with-komorebi.html Sets up Zebar providers for various system modules and renders the main React application component. Ensure the 'root' element exists in your HTML. ```javascript import React, { useState, useEffect, } from 'https://esm.sh/react@18?dev'; import { createRoot } from 'https://esm.sh/react-dom@18/client?dev'; import * as zebar from 'https://esm.sh/zebar@3.0'; const providers = zebar.createProviderGroup({ network: { type: 'network' }, komorebi: { type: 'komorebi' }, cpu: { type: 'cpu' }, date: { type: 'date', formatting: 'EEE d MMM t' }, battery: { type: 'battery' }, memory: { type: 'memory' }, weather: { type: 'weather' }, }); createRoot(document.getElementById('root')).render(); ``` -------------------------------- ### startWidget / startWidgetPreset Source: https://context7.com/glzr-io/zebar/llms.txt Open another widget programmatically. Spawns a widget window at a specified placement (or using a named preset from `zpack.json`). Useful for popup widgets triggered from a main bar. ```APIDOC ## startWidget / startWidgetPreset ### Description Open another widget programmatically. Spawns a widget window at a specified placement (or using a named preset from `zpack.json`). Useful for popup widgets triggered from a main bar. ### Usage ```typescript import { startWidget, startWidgetPreset, type WidgetPlacement } from 'zebar'; // Open a popup at the top-right corner of the primary monitor const placement: WidgetPlacement = { anchor: 'top_right', offsetX: '0', offsetY: '40px', width: '300px', height: '400px', monitorSelection: { type: 'primary' }, dockToEdge: { enabled: false }, }; await startWidget('notification-popup', placement); // Or use a named preset defined in zpack.json await startWidgetPreset('notification-popup', 'compact'); // Open a widget from a different pack await startWidget('volume-overlay', placement, { packId: 'audio-widgets' }); ``` ``` -------------------------------- ### Monitor Battery Status with Zebar Source: https://context7.com/glzr-io/zebar/llms.txt Use the battery provider to get real-time charge percentage, health, state, and power consumption. Configure a refresh interval to receive periodic updates. ```typescript import { createProvider } from 'zebar'; const battery = createProvider({ type: 'battery', refreshInterval: 5000 }); battery.onOutput(output => { console.log(`Charge: ${output.chargePercent}%`); console.log(`Health: ${output.healthPercent}%`); console.log(`State: ${output.state}`); // => 'charging' | 'discharging' | 'full' | 'empty' | 'unknown' console.log(`Charging: ${output.isCharging}`); console.log(`Power: ${output.powerConsumption}W`); console.log(`Voltage: ${output.voltage}V`); console.log(`Cycles: ${output.cycleCount}`); if (output.timeTillEmpty !== null) { const mins = Math.round(output.timeTillEmpty / 60000); console.log(`Time till empty: ${mins} min`); } if (output.timeTillFull !== null) { const mins = Math.round(output.timeTillFull / 60000); console.log(`Time till full: ${mins} min`); } }); ``` -------------------------------- ### Create and Use a Provider Group Source: https://context7.com/glzr-io/zebar/llms.txt Shows how to create multiple providers (CPU, memory, battery, date) under named keys using `createProviderGroup`. The `onOutput` callback fires when any provider emits, passing an `outputMap`. Error handling for individual providers is also demonstrated. ```typescript import { createProviderGroup } from 'zebar'; const group = createProviderGroup({ cpu: { type: 'cpu', refreshInterval: 2000 }, memory: { type: 'memory', refreshInterval: 5000 }, battery: { type: 'battery', refreshInterval: 10000 }, date: { type: 'date', formatting: 'HH:mm:ss', refreshInterval: 1000 }, }); group.onOutput(({ cpu, memory, battery, date }) => { const cpuPct = cpu?.usage.toFixed(1) ?? '--'; const memPct = memory?.usage.toFixed(1) ?? '--'; const batPct = battery?.chargePercent ?? '--'; const charging = battery?.isCharging ? '⚡' : '🔋'; const timeStr = date?.formatted ?? '--'; document.getElementById('status-bar')!.textContent = `${timeStr} CPU ${cpuPct}% MEM ${memPct}% ${charging}${batPct}%`; }); group.onError(errorMap => { for (const [name, err] of Object.entries(errorMap)) { if (err) console.error(`[${name}] ${err}`); } }); // Access individual raw providers console.log(group.raw.battery.output?.state); // 'charging' | 'discharging' | ... // Stop all providers at once await group.stopAll(); ``` -------------------------------- ### Build for Production Source: https://github.com/glzr-io/zebar/blob/main/packages/settings-ui/README.md Builds the application for production, optimizing for performance and creating minified assets with hashes. ```bash npm run build ``` -------------------------------- ### Create and Use a Single CPU Provider Source: https://context7.com/glzr-io/zebar/llms.txt Demonstrates creating a CPU provider that refreshes every 2 seconds. It logs CPU usage, frequency, core count, and vendor. Remember to call `.stop()` when the widget is unmounted. ```typescript import { createProvider } from 'zebar'; // CPU provider — refreshes every 2 seconds const cpu = createProvider({ type: 'cpu', refreshInterval: 2000 }); cpu.onOutput(output => { console.log(`CPU usage: ${output.usage.toFixed(1)}%`); console.log(`Frequency: ${output.frequency} MHz`); console.log(`Cores: ${output.physicalCoreCount}P / ${output.logicalCoreCount}L`); console.log(`Vendor: ${output.vendor}`); // => CPU usage: 14.3% // => Frequency: 3600 MHz // => Cores: 8P / 16L // => Vendor: GenuineIntel }); cpu.onError(err => console.error('CPU provider error:', err)); // Access the latest snapshot synchronously (null until first emission) console.log(cpu.output?.usage); // Restart or stop when done await cpu.restart(); await cpu.stop(); ``` -------------------------------- ### Executing Shell Commands Source: https://context7.com/glzr-io/zebar/llms.txt Demonstrates how to execute shell commands from a widget using `shellExec` for one-off commands and `shellSpawn` for long-running processes with streaming output. Requires the `shell` privilege. ```APIDOC ## `shellExec` / `shellSpawn` — Execute shell commands from a widget `shellExec` runs a command and awaits completion, returning stdout/stderr. `shellSpawn` launches a long-running process and provides callbacks for streaming output. Requires the `shell` privilege in the widget config. ```typescript import { shellExec, shellSpawn } from 'zebar'; // One-shot command — await completion const result = await shellExec('git', ['rev-parse', '--short', 'HEAD'], { cwd: '/home/user/project', }); console.log('Git hash:', result.stdout.trim()); console.log('Exit code:', result.code); // Long-running process — stream output const ping = await shellSpawn('ping', ['127.0.0.1', '-c', '5']); ping.onStdout(line => { console.log('stdout:', line); // => stdout: 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.041 ms }); ping.onStderr(line => console.error('stderr:', line)); ping.onExit(({ exitCode, signal }) => { console.log(`Exited with code ${exitCode}`); }); // Send input to stdin or kill the process ping.write('some input\n'); ping.kill(); // Binary output example const raw = await shellExec('ffmpeg', ['-version'], { encoding: 'raw', }); console.log('Bytes:', raw.stdout.byteLength); ``` ``` -------------------------------- ### Systray Provider Source: https://context7.com/glzr-io/zebar/llms.txt Exposes all tray icons as ready-to-use image URLs plus interaction event dispatchers. Windows-only. ```APIDOC ## Systray Provider ### Description Exposes all tray icons as ready-to-use image URLs plus interaction event dispatchers. Windows-only. ### Usage ```typescript import { createProvider } from 'zebar'; const systray = createProvider({ type: 'systray' }); systray.onOutput(output => { const container = document.getElementById('tray')!; container.innerHTML = ''; for (const icon of output.icons) { const img = document.createElement('img'); img.src = icon.iconUrl; // PNG blob URL — safe to put in img.title = icon.tooltip; img.addEventListener('click', () => output.onLeftClick(icon.id)); img.addEventListener('contextmenu', e => { e.preventDefault(); output.onRightClick(icon.id); }); img.addEventListener('mouseenter', () => output.onHoverEnter(icon.id)); img.addEventListener('mouseleave', () => output.onHoverLeave(icon.id)); img.addEventListener('dblclick', () => output.onLeftDoubleClick(icon.id)); container.appendChild(img); } }); ``` ``` -------------------------------- ### React to GlazeWM Tiling Window Manager Events Source: https://context7.com/glzr-io/zebar/llms.txt Connect to GlazeWM's IPC server to receive real-time workspace, monitor, and window state. This provider also allows issuing WM commands like focusing workspaces or changing window states. It is Windows-only. ```typescript import { createProvider } from 'zebar'; const wm = createProvider({ type: 'glazewm' }); wm.onOutput(async output => { // Render workspace buttons for (const ws of output.currentWorkspaces) { const isFocused = ws.name === output.focusedWorkspace.name; const isDisplayed = ws.name === output.displayedWorkspace.name; console.log(`[${ws.name}] focused=${isFocused} displayed=${isDisplayed}`); } // Show focused window title const fc = output.focusedContainer; if (fc.type === 'window') { console.log(`Active window: ${fc.title}`); } console.log(`Tiling direction: ${output.tilingDirection}`); console.log(`WM paused: ${output.isPaused}`); // Issue WM commands await output.runCommand('focus --workspace 2'); await output.runCommand('set-floating'); await output.runCommand('set-tiling', fc.id); }); wm.onError(err => console.error('GlazeWM not running:', err)); ``` -------------------------------- ### Create Komorebi Provider for Tiling Window Manager Info Source: https://context7.com/glzr-io/zebar/llms.txt Connects to Komorebi's named pipe IPC to expose workspace and monitor topology. This provider is Windows-only and useful for integrating with tiling window manager features. ```typescript import { createProvider } from 'zebar'; const km = createProvider({ type: 'komorebi' }); km.onOutput(output => { const ws = output.displayedWorkspace; console.log(`Workspace: ${ws.name ?? '(unnamed)'}`); console.log(`Layout: ${ws.layout}`); // => 'bsp' | 'vertical_stack' | 'grid' | ... const tiled = ws.tilingContainers.flatMap(c => c.windows); for (const win of tiled) { console.log(` Window: ${win.title} (${win.exe})`); } // Monitor info console.log(`Current monitor: ${output.currentMonitor.name}`); console.log(`All monitors: ${output.allMonitors.length}`); console.log(`All workspaces: ${output.allWorkspaces.length}`); }); km.onError(err => console.error('Komorebi not running:', err)); ``` -------------------------------- ### Publish Widget Pack with Metadata Source: https://github.com/glzr-io/zebar/blob/main/MARKETPLACE.md Publish a widget pack with additional metadata for a richer marketplace listing. This includes specifying the pack configuration file, overriding the version, and providing commit SHA, release notes, and a release URL. ```bash zebar publish --token your-api-token \ --pack-config ./my-pack/zpack.json \ --version-override 1.2.0 \ --commit-sha abc123def456 \ --release-notes "Fixed performance issues and added new themes." \ --release-url "https://github.com/username/pack-repo/releases/v1.2.0" ``` -------------------------------- ### React App with Zebar Providers Source: https://github.com/glzr-io/zebar/blob/main/resources/templates/widget-templates/react-buildless/index.html This snippet sets up Zebar providers for various system resources and renders them in a React component. It uses `createProviderGroup` to manage multiple providers and `onOutput` for real-time updates. Ensure React and Zebar are correctly imported. ```javascript import React, { useState, useEffect, } from 'https://esm.sh/react@18?dev'; import { createRoot } from 'https://esm.sh/react-dom@18/client?dev'; import * as zebar from 'https://esm.sh/zebar@3.0'; const providers = zebar.createProviderGroup({ cpu: { type: 'cpu' }, battery: { type: 'battery' }, memory: { type: 'memory' }, weather: { type: 'weather' }, media: { type: 'media' }, audio: { type: 'audio' }, }); createRoot(document.getElementById('root')).render(); function App() { const [output, setOutput] = useState(providers.outputMap); useEffect(() => { providers.onOutput(() => setOutput(providers.outputMap)); }, []); return (
{output.audio?.defaultPlaybackDevice && (
{output.audio.defaultPlaybackDevice.name}- {output.audio.defaultPlaybackDevice.volume} output.audio.setVolume(e.target.valueAsNumber) } />
)}
Media: {output.media?.currentSession?.title}- {output.media?.currentSession?.artist}
CPU usage: {output.cpu?.usage}
Battery charge: {output.battery?.chargePercent}
Memory usage: {output.memory?.usage}
Weather temp: {output.weather?.celsiusTemp}
); } ``` -------------------------------- ### Link Local Zebar Client-API Package Source: https://github.com/glzr-io/zebar/blob/main/CONTRIBUTING.md Link a local version of the zebar client-api package into your widget project. This is useful for developing the client-api and widgets simultaneously. Adjust the path '../../path/to/zebar/packages/client-api' to point to your local client-api directory. ```shell cd path/to/your/widget # If using pnpm: pnpm add --link ../../path/to/zebar/packages/client-api # If using npm: npm install ../../path/to/zebar/packages/client-api ``` -------------------------------- ### Rust Systray Event Handling Source: https://github.com/glzr-io/zebar/blob/main/crates/systray-util/README.md Demonstrates how to initialize the systray, listen for icon events (add, update, remove) using blocking calls, and send a click action to an icon. Use this for synchronous applications. ```rust use systray_util::{Systray, SystrayEvent, SystrayIconAction}; fn main() -> systray_util::Result<()> { let mut systray = Systray::new()?; // Alternatively use `systray.events().await` to get async events for use // with a tokio runtime. while let Some(event) = systray.events_blocking() { match event { SystrayEvent::IconAdd(icon) => { println!("Tray icon added: {:?}", icon); } SystrayEvent::IconUpdate(icon) => { println!("Tray icon updated: {:?}", icon); } SystrayEvent::IconRemove(id) => { println!("Tray icon removed: {:?}", id); } } } // Send click action to first icon. if let Some(icon) = systray.icons().first() { systray.send_action(&icon.stable_id, &SystrayIconAction::LeftClick)?; } Ok(()) } ``` -------------------------------- ### Zebar Widget Pack Configuration (`zpack.json`) Source: https://context7.com/glzr-io/zebar/llms.txt Defines a widget pack, including widget properties like HTML path, window behavior, and security privileges. The `privileges.shellCommands` array explicitly lists programs and their arguments that the widget is allowed to execute. ```json { "$schema": "https://raw.githubusercontent.com/glzr-io/zebar/main/resources/zpack-schema.json", "name": "My Status Bar", "version": "1.0.0", "description": "A minimal status bar with system info.", "tags": ["bar", "minimal"], "widgets": [ { "name": "bar", "htmlPath": "./bar/index.html", "zOrder": "bottom_most", "shownInTaskbar": false, "focused": false, "resizable": false, "transparent": true, "includeFiles": [], "caching": { "defaultOnlineUrl": null, "defaultMonitorId": null }, "privileges": { "shellCommands": [ { "program": "git", "args": [] }, { "program": "ping", "args": [] } ] }, "presets": [ { "name": "default", "anchor": "top_left", "offsetX": "0", "offsetY": "0", "width": "100%", "height": "40px", "monitorSelection": { "type": "all" }, "dockToEdge": { "enabled": true, "edge": "top", "windowMargin": "40px" } } ] } ] } ``` -------------------------------- ### Create Media Provider for Media Playback Control Source: https://context7.com/glzr-io/zebar/llms.txt Initializes a media provider to control and monitor media playback sessions. This provider is Windows-only and allows interacting with the current media session, including play/pause and skip functions. ```typescript import { createProvider } from 'zebar'; const media = createProvider({ type: 'media' }); media.onOutput(async output => { const session = output.currentSession; if (!session) { console.log('No active media session'); return; } console.log(`Title: ${session.title}`); console.log(`Artist: ${session.artist}`); console.log(`Album: ${session.albumTitle}`); console.log(`Playing: ${session.isPlaying}`); console.log(`Position: ${session.position.toFixed(0)}s / ${session.endTime.toFixed(0)}s`); // Playback controls (target current session implicitly) await output.togglePlayPause(); await output.next(); await output.previous(); // Target a specific session by ID const spotifySession = output.allSessions.find(s => s.title === 'Spotify'); if (spotifySession) { await output.play({ sessionId: spotifySession.sessionId }); } }); ``` -------------------------------- ### Create IP Provider to Fetch Public IP and Geolocation Source: https://context7.com/glzr-io/zebar/llms.txt Initializes an IP provider to fetch the public IP address and approximate geolocation. The provider refreshes hourly by default and is cross-platform. Use this to display user's IP and location. ```typescript import { createProvider } from 'zebar'; const ip = createProvider({ type: 'ip', refreshInterval: 3600000 }); ip.onOutput(output => { console.log(`IP: ${output.address}`); // => '203.0.113.42' console.log(`City: ${output.approxCity}`); console.log(`Country: ${output.approxCountry}`); console.log(`Lat/Lon: ${output.approxLatitude}, ${output.approxLongitude}`); }); ``` -------------------------------- ### Disk Information with Space and Filesystem Details Source: https://context7.com/glzr-io/zebar/llms.txt The disk provider enumerates mounted disks, providing total and available space in both SI and IEC units. It also includes filesystem type and removable status. Configure a refresh interval for periodic updates. ```typescript import { createProvider } from 'zebar'; const disk = createProvider({ type: 'disk', refreshInterval: 60000 }); disk.onOutput(output => { for (const d of output.disks) { const usedGB = (d.totalSpace.siValue - d.availableSpace.siValue).toFixed(1); const totalGB = d.totalSpace.siValue.toFixed(1); const pct = ((1 - d.availableSpace.bytes / d.totalSpace.bytes) * 100).toFixed(1); console.log(`${d.mountPoint} (${d.driveType})`); console.log(` FS: ${d.fileSystem}`); console.log(` Used: ${usedGB} ${d.totalSpace.siUnit} / ${totalGB} ${d.totalSpace.siUnit} (${pct}%)`); console.log(` Removable: ${d.isRemovable}`); // => C:\ (SSD) // => FS: NTFS // => Used: 312.4 GB / 512.0 GB (61.0%) // => Removable: false } }); ``` -------------------------------- ### Create Memory Provider for RAM and Swap Usage Source: https://context7.com/glzr-io/zebar/llms.txt Initializes a memory provider to fetch RAM and swap usage statistics. This provider is cross-platform and provides memory usage percentage and absolute free/used/total values in bytes. ```typescript import { createProvider } from 'zebar'; const memory = createProvider({ type: 'memory', refreshInterval: 5000 }); memory.onOutput(output => { const usedGB = (output.usedMemory / 1e9).toFixed(1); const totalGB = (output.totalMemory / 1e9).toFixed(1); console.log(`RAM: ${usedGB}GB / ${totalGB}GB (${output.usage.toFixed(1)}%)`); if (output.totalSwap > 0) { const swapGB = (output.usedSwap / 1e9).toFixed(1); const swapTotalGB = (output.totalSwap / 1e9).toFixed(1); console.log(`Swap: ${swapGB}GB / ${swapTotalGB}GB`); } }); ``` -------------------------------- ### Clone the Zebar Repository Source: https://github.com/glzr-io/zebar/blob/main/CONTRIBUTING.md Clone the Zebar repository to your local machine using Git. Replace 'your-username' with your GitHub username. ```shell git clone git@github.com:your-username/zebar.git ``` -------------------------------- ### Render Windows System Tray Icons with Zebar Source: https://context7.com/glzr-io/zebar/llms.txt Use the systray provider to expose tray icons as image URLs and dispatch interaction events. This is a Windows-only feature. ```typescript import { createProvider } from 'zebar'; const systray = createProvider({ type: 'systray' }); systray.onOutput(output => { const container = document.getElementById('tray')!; container.innerHTML = ''; for (const icon of output.icons) { const img = document.createElement('img'); img.src = icon.iconUrl; // PNG blob URL — safe to put in img.title = icon.tooltip; img.addEventListener('click', () => output.onLeftClick(icon.id)); img.addEventListener('contextmenu', e => { e.preventDefault(); output.onRightClick(icon.id); }); img.addEventListener('mouseenter', () => output.onHoverEnter(icon.id)); img.addEventListener('mouseleave', () => output.onHoverLeave(icon.id)); img.addEventListener('dblclick', () => output.onLeftDoubleClick(icon.id)); container.appendChild(img); } }); ``` -------------------------------- ### Troubleshoot MacOS Settings UI Outdated Dependencies Source: https://github.com/glzr-io/zebar/blob/main/CONTRIBUTING.md Resolve issues with the MacOS settings UI using outdated dependencies by deleting the .vite directory and rerunning the development server. ```shell 1. Delete the `packages/settings-ui/.vite` directory 2. Run `pnpm dev` again ``` -------------------------------- ### Widget Pack Configuration (`zpack.json`) Source: https://context7.com/glzr-io/zebar/llms.txt Defines the manifest file for a widget pack, specifying widget behavior, placement, caching, and security privileges like shell command execution. ```APIDOC ## `zpack.json` Widget Pack Configuration The manifest file that defines a widget pack. Each entry in `widgets` maps to an HTML file and controls window behavior, placement presets, caching, and security privileges. ```json { "$schema": "https://raw.githubusercontent.com/glzr-io/zebar/main/resources/zpack-schema.json", "name": "My Status Bar", "version": "1.0.0", "description": "A minimal status bar with system info.", "tags": ["bar", "minimal"], "widgets": [ { "name": "bar", "htmlPath": "./bar/index.html", "zOrder": "bottom_most", "shownInTaskbar": false, "focused": false, "resizable": false, "transparent": true, "includeFiles": [], "caching": { "defaultOnlineUrl": null, "defaultMonitorId": null }, "privileges": { "shellCommands": [ { "program": "git", "args": [] }, { "program": "ping", "args": [] } ] }, "presets": [ { "name": "default", "anchor": "top_left", "offsetX": "0", "offsetY": "0", "width": "100%", "height": "40px", "monitorSelection": { "type": "all" }, "dockToEdge": { "enabled": true, "edge": "top", "windowMargin": "40px" } } ] } ] } ``` ``` -------------------------------- ### createProviderGroup Source: https://context7.com/glzr-io/zebar/llms.txt Composes multiple providers under named keys, allowing for a unified callback when any provider emits. This is useful for updating the UI efficiently. ```APIDOC ## createProviderGroup ### Description Creates several providers at once under named keys. `onOutput` fires whenever **any** member emits, passing the full `outputMap` so the widget can re-render once even when multiple values change in quick succession. ### Method Signature ```typescript createProviderGroup(providersConfig: { [key: string]: ProviderConfig }): ProviderGroupInstance ``` ### Parameters #### `providersConfig` (object) - Required An object where keys are provider names and values are provider configuration objects. - **cpu** (ProviderConfig) - Configuration for the CPU provider. - **memory** (ProviderConfig) - Configuration for the memory provider. - **battery** (ProviderConfig) - Configuration for the battery provider. - **date** (ProviderConfig) - Configuration for the date provider. ### Example ```typescript import { createProviderGroup } from 'zebar'; const group = createProviderGroup({ cpu: { type: 'cpu', refreshInterval: 2000 }, memory: { type: 'memory', refreshInterval: 5000 }, battery: { type: 'battery', refreshInterval: 10000 }, date: { type: 'date', formatting: 'HH:mm:ss', refreshInterval: 1000 }, }); group.onOutput(({ cpu, memory, battery, date }) => { const cpuPct = cpu?.usage.toFixed(1) ?? '--'; const memPct = memory?.usage.toFixed(1) ?? '--'; const batPct = battery?.chargePercent ?? '--'; const charging = battery?.isCharging ? '⚡' : '🔋'; const timeStr = date?.formatted ?? '--'; document.getElementById('status-bar')!.textContent = `${timeStr} CPU ${cpuPct}% MEM ${memPct}% ${charging}${batPct}%`; }); group.onError(errorMap => { for (const [name, err] of Object.entries(errorMap)) { if (err) console.error(`[${name}] ${err}`); } }); // Access individual raw providers console.log(group.raw.battery.output?.state); // 'charging' | 'discharging' | ... // Stop all providers at once await group.stopAll(); ``` ``` -------------------------------- ### Audio Provider Source: https://context7.com/glzr-io/zebar/llms.txt Controls and monitors audio devices, including setting volume and mute state. This provider is Windows-only. ```APIDOC ## Audio Provider ### Description Exposes all playback/recording devices and allows setting volume or mute state per device. Windows-only. ### Usage Use `createProvider` with `type: 'audio'`. ### Example ```typescript import { createProvider } from 'zebar'; const audio = createProvider({ type: 'audio' }); audio.onOutput(async output => { const dev = output.defaultPlaybackDevice; if (!dev) return; console.log(`Device: ${dev.name}`); console.log(`Volume: ${dev.volume}%`); console.log(`Muted: ${dev.isMuted}`); console.log(`Type: ${dev.type}`); // 'playback' | 'recording' // List all playback devices for (const d of output.playbackDevices) { console.log(` [${d.isDefaultPlayback ? 'default' : ' '}] ${d.name} — ${d.volume}%`); } // Set default playback device volume to 50% await output.setVolume(50); // Set volume for a specific device by ID await output.setVolume(30, { deviceId: dev.deviceId }); // Mute/unmute a specific device await output.setMute(true, { deviceId: dev.deviceId }); await output.setMute(false); }); ``` ```