Add charging icon and fix errors

This commit is contained in:
Supertiger
2025-08-02 09:09:07 +01:00
parent c3c9d99967
commit 994302978c
4 changed files with 231 additions and 292 deletions

View File

@@ -5,7 +5,7 @@ interface LabelOpts {
config?: { config?: {
[key: string]: any; [key: string]: any;
format?: string; format?: string;
states: string[]; states?: Record<string, number>;
"format-icons"?: string[]; "format-icons"?: string[];
}; };
module: Module; module: Module;
@@ -20,9 +20,11 @@ export const createLabel = (opts: LabelOpts) => {
if (!format) { if (!format) {
return opts.config?.format || undefined; return opts.config?.format || undefined;
} }
return opts.config["format-" + format] || undefined; return format;
}; };
const setFormat = (value?: string) => (format = value || "format");
const element = document.createElement("span"); const element = document.createElement("span");
if (opts.interval && opts.update) { if (opts.interval && opts.update) {
setInterval(opts.update, opts.interval); setInterval(opts.update, opts.interval);
@@ -86,5 +88,6 @@ export const createLabel = (opts: LabelOpts) => {
set, set,
getIcon, getIcon,
getState, getState,
setFormat,
}; };
}; };

View File

@@ -1,212 +1,176 @@
import { parse } from "jsonc-parser"; import { parse } from "jsonc-parser";
/** export interface WaybarConfig {
* A general interface for icon mappings, where a key maps to a single icon string or an array of icon strings. height: number;
*/ spacing: number;
interface IconMap { "modules-left": string[];
[key: string]: string | string[]; "modules-center": string[];
"modules-right": string[];
"keyboard-state": KeyboardState;
"sway/mode": Memory;
"sway/scratchpad": SwayScratchpad;
mpd: Mpd;
idle_inhibitor: IdleInhibitor;
tray: Tray;
clock: Clock;
cpu: CPU;
memory: Memory;
temperature: Temperature;
backlight: Backlight;
battery: Battery;
"battery#bat2": BatteryBat2;
"power-profiles-daemon": PowerProfilesDaemon;
network: Network;
pulseaudio: Pulseaudio;
"custom/media": CustomMedia;
"custom/power": CustomPower;
}
interface Backlight {
format: string;
"format-icons": string[];
}
interface Battery {
states: States;
format: string;
"format-full": string;
"format-charging": string;
"format-plugged": string;
"format-alt": string;
"format-icons": string[];
[key: string]: any; // Allow additional properties
}
interface States {
warning: number;
critical: number;
[key: string]: number; // Allow additional properties
}
interface BatteryBat2 {
bat: string;
}
interface Clock {
"tooltip-format": string;
"format-alt": string;
}
interface CPU {
format: string;
tooltip: boolean;
}
interface CustomMedia {
format: string;
"return-type": string;
"max-length": number;
"format-icons": CustomMediaFormatIcons;
escape: boolean;
exec: string;
}
interface CustomMediaFormatIcons {
spotify: string;
default: string;
}
interface CustomPower {
format: string;
tooltip: boolean;
menu: string;
"menu-file": string;
"menu-actions": MenuActions;
}
interface MenuActions {
shutdown: string;
reboot: string;
suspend: string;
hibernate: string;
} }
/** interface IdleInhibitor {
* Common configuration properties for many Waybar modules. format: string;
*/ "format-icons": IdleInhibitorFormatIcons;
interface BaseModule {
format?: string;
"format-icons"?: IconMap;
tooltip?: boolean;
} }
/** interface IdleInhibitorFormatIcons {
* Defines the states and icons for a module.
*/
interface ModuleWithStates extends BaseModule {
states?: {
[state: string]: number;
};
"format-critical"?: string;
"format-alt"?: string;
}
/**
* Interface for the `sway/workspaces` module.
* Note: This module is commented out in the original JSON, but the interface is included for completeness.
*/
interface SwayWorkspacesModule extends BaseModule {
"disable-scroll"?: boolean;
"all-outputs"?: boolean;
"warp-on-scroll"?: boolean;
"format-icons"?: {
[key: string]: string;
};
}
/**
* Interface for the `keyboard-state` module.
*/
interface KeyboardStateModule extends BaseModule {
numlock?: boolean;
capslock?: boolean;
"format-icons"?: {
locked: string;
unlocked: string;
};
}
/**
* Interface for the `sway/mode` module.
*/
interface SwayModeModule {
format?: string;
}
/**
* Interface for the `sway/scratchpad` module.
*/
interface SwayScratchpadModule extends BaseModule {
"show-empty"?: boolean;
"format-icons"?: string[];
"tooltip-format"?: string;
}
/**
* Interface for the `mpd` module.
*/
interface MpdModule extends BaseModule {
"format-disconnected"?: string;
"format-stopped"?: string;
"unknown-tag"?: string;
interval?: number;
"consume-icons"?: {
on: string;
};
"random-icons"?: {
on: string;
off: string;
};
"repeat-icons"?: {
on: string;
};
"single-icons"?: {
on: string;
};
"state-icons"?: {
paused: string;
playing: string;
};
"tooltip-format"?: string;
"tooltip-format-disconnected"?: string;
}
/**
* Interface for the `idle_inhibitor` module.
*/
interface IdleInhibitorModule extends BaseModule {
"format-icons"?: {
activated: string; activated: string;
deactivated: string; deactivated: string;
};
} }
/** interface KeyboardState {
* Interface for the `tray` module. numlock: boolean;
*/ capslock: boolean;
interface TrayModule { format: string;
"icon-size"?: number; "format-icons": KeyboardStateFormatIcons;
spacing?: number;
icons?: {
[appName: string]: string;
};
} }
/** interface KeyboardStateFormatIcons {
* Interface for the `clock` module. locked: string;
*/ unlocked: string;
interface ClockModule {
timezone?: string;
"tooltip-format"?: string;
"format-alt"?: string;
} }
/** interface Memory {
* Interface for the `cpu` module. format: string;
*/
interface CpuModule extends BaseModule {
tooltip?: boolean;
} }
/** interface Mpd {
* Interface for the `memory` module. format: string;
*/ "format-disconnected": string;
interface MemoryModule extends BaseModule {} "format-stopped": string;
"unknown-tag": string;
/** interval: number;
* Interface for the `temperature` module. "consume-icons": Icons;
*/ "random-icons": RandomIcons;
interface TemperatureModule extends ModuleWithStates { "repeat-icons": Icons;
"thermal-zone"?: number; "single-icons": Icons;
"hwmon-path"?: string; "state-icons": StateIcons;
"critical-threshold"?: number; "tooltip-format": string;
"format-icons"?: string[]; "tooltip-format-disconnected": string;
} }
/** interface Icons {
* Interface for the `backlight` module. on: string;
*/
interface BacklightModule extends BaseModule {
device?: string;
"format-icons"?: string[];
} }
/** interface RandomIcons {
* Interface for the `battery` module. off: string;
*/ on: string;
interface BatteryModule extends ModuleWithStates {
bat?: string; // Used for battery#bat2
"format-full"?: string;
"format-charging"?: string;
"format-plugged"?: string;
"format-good"?: string;
"format-icons"?: string[];
} }
/** interface StateIcons {
* Interface for the `power-profiles-daemon` module. paused: string;
*/ playing: string;
interface PowerProfilesDaemonModule extends BaseModule { }
tooltip?: boolean;
"tooltip-format"?: string; interface Network {
"format-icons"?: { "format-wifi": string;
"format-ethernet": string;
"tooltip-format": string;
"format-linked": string;
"format-disconnected": string;
"format-alt": string;
}
interface PowerProfilesDaemon {
format: string;
"tooltip-format": string;
tooltip: boolean;
"format-icons": PowerProfilesDaemonFormatIcons;
}
interface PowerProfilesDaemonFormatIcons {
default: string; default: string;
performance: string; performance: string;
balanced: string; balanced: string;
"power-saver": string; "power-saver": string;
};
} }
/** interface Pulseaudio {
* Interface for the `network` module. format: string;
*/ "format-bluetooth": string;
interface NetworkModule { "format-bluetooth-muted": string;
interface?: string; "format-muted": string;
"format-wifi"?: string; "format-source": string;
"format-ethernet"?: string; "format-source-muted": string;
"tooltip-format"?: string; "format-icons": PulseaudioFormatIcons;
"format-linked"?: string; "on-click": string;
"format-disconnected"?: string;
"format-alt"?: string;
} }
/** interface PulseaudioFormatIcons {
* Interface for the `pulseaudio` module.
*/
interface PulseaudioModule extends BaseModule {
"scroll-step"?: number;
"format-bluetooth"?: string;
"format-bluetooth-muted"?: string;
"format-muted"?: string;
"format-source"?: string;
"format-source-muted"?: string;
"format-icons"?: {
headphone: string; headphone: string;
"hands-free": string; "hands-free": string;
headset: string; headset: string;
@@ -214,71 +178,24 @@ interface PulseaudioModule extends BaseModule {
portable: string; portable: string;
car: string; car: string;
default: string[]; default: string[];
};
"on-click"?: string;
} }
/** interface SwayScratchpad {
* Interface for the `custom/media` module. format: string;
*/ "show-empty": boolean;
interface CustomMediaModule extends BaseModule { "format-icons": string[];
"return-type"?: "json" | "text"; tooltip: boolean;
"max-length"?: number; "tooltip-format": string;
"format-icons"?: {
[key: string]: string;
};
escape?: boolean;
exec?: string;
} }
/** interface Temperature {
* Interface for the `custom/power` module. "critical-threshold": number;
*/ format: string;
interface CustomPowerModule extends BaseModule { "format-icons": string[];
menu?: string;
"menu-file"?: string;
"menu-actions"?: {
shutdown: string;
reboot: string;
suspend: string;
hibernate: string;
};
} }
/** interface Tray {
* The main interface for the entire Waybar configuration file. spacing: number;
* It combines the main settings with a generic index signature for module configurations.
*/
export interface WaybarConfig {
layer?: "top" | "bottom" | "overlay";
position?: "top" | "bottom" | "left" | "right";
height?: number;
width?: number;
spacing?: number;
"modules-left"?: string[];
"modules-center"?: string[];
"modules-right"?: string[];
// Module-specific configurations
"sway/workspaces"?: SwayWorkspacesModule;
"sway/mode"?: SwayModeModule;
"sway/scratchpad"?: SwayScratchpadModule;
"keyboard-state"?: KeyboardStateModule;
mpd?: MpdModule;
idle_inhibitor?: IdleInhibitorModule;
tray?: TrayModule;
clock?: ClockModule;
cpu?: CpuModule;
memory?: MemoryModule;
temperature?: TemperatureModule;
backlight?: BacklightModule;
battery?: BatteryModule;
"battery#bat2"?: BatteryModule;
"power-profiles-daemon"?: PowerProfilesDaemonModule;
network?: NetworkModule;
pulseaudio?: PulseaudioModule;
"custom/media"?: CustomMediaModule;
"custom/power"?: CustomPowerModule;
} }
export const parseConfig = async () => { export const parseConfig = async () => {

View File

@@ -2,6 +2,8 @@ import type { WaybarConfig } from "../configParser";
import type { Module } from "../createModule"; import type { Module } from "../createModule";
import { createLabel } from "../Label"; import { createLabel } from "../Label";
type Status = "Unknown" | "Charging" | "Discharging" | "Plugged" | "Full";
export const createBatteryModule = ( export const createBatteryModule = (
module: Module, module: Module,
config: WaybarConfig["battery"] config: WaybarConfig["battery"]
@@ -15,8 +17,8 @@ export const createBatteryModule = (
module.element.appendChild(label.element); module.element.appendChild(label.element);
const getState = (battery: {level: number, charging: boolean}) => { const getState = (battery: { level: number; charging: boolean }) => {
let status = "Unknown"; let status: Status = "Unknown";
if (battery.charging && battery.level < 1) { if (battery.charging && battery.level < 1) {
status = "Charging"; status = "Charging";
@@ -26,34 +28,47 @@ export const createBatteryModule = (
} }
if (battery.charging && battery.level === 1) { if (battery.charging && battery.level === 1) {
status = "Plugged" status = "Plugged";
} }
if (!battery.charging && battery.level < 1) { if (!battery.charging && battery.level < 1) {
status = "Discharging" status = "Discharging";
} }
return status; return status;
} };
let lastStatus = "Unknown" let lastStatus = "Unknown";
const update = async () => { const update = async () => {
// const battery = await navigator.getBattery(); // const battery = await navigator.getBattery();
const battery = { const battery = {
level: Math.random(), // level: Math.random(),
charging: Math.random() > 0.5, // charging: Math.random() > 0.5,
level: 0.1,
charging: true,
}; };
const batteryPercent = Math.round(battery.level * 100); const batteryPercent = Math.round(battery.level * 100);
const status = getState(battery); const status = getState(battery);
module.element.classList.remove(lastStatus.toLowerCase()); module.element.classList.remove(lastStatus.toLowerCase());
module.element.classList.add(status.toLowerCase()) module.element.classList.add(status.toLowerCase());
lastStatus = status; lastStatus = status;
module.element.title = status; module.element.title = status;
const state = label.getState(batteryPercent, true); const state = label.getState(batteryPercent, true);
console.log(state)
if (config) {
const _status = status.toLowerCase();
let format = "";
if (state && config["format-" + _status + "-" + state]) {
format = config["format-" + _status + "-" + state];
} else if (config["format-" + _status]) {
format = config["format-" + _status];
} else if (state && config["format-" + state]) {
format = config["format-" + state];
}
label.setFormat(format);
}
label.set({ label.set({
capacity: batteryPercent, capacity: batteryPercent,

View File

@@ -1,6 +1,10 @@
import type { WaybarConfig } from "../configParser";
import type { Module } from "../createModule"; import type { Module } from "../createModule";
export const createClockModule = (module: Module) => { export const createClockModule = (
module: Module,
config: WaybarConfig["clock"]
) => {
const update = () => { const update = () => {
const date = new Date(); const date = new Date();