Fix: An issue that would cause Matugen colors to not apply. (#929)

* Eslint updates

* linter fixes

* Type fixes

* More type fixes

* Fix isvis

* More type fixes

* Type Fixes

* Consolidate logic to manage options

* Linter fixes

* Package lock update

* Update configs

* Version checker

* Debug pipeline

* Package lock update

* Update ci

* Strict check

* Revert ci

* Eslint

* Remove rule since it causes issues in CI

* Actual matugen fix
This commit is contained in:
Jas Singh
2025-05-11 23:01:55 -07:00
committed by GitHub
parent 0c82ce9704
commit 2bb1449fb6
275 changed files with 4363 additions and 2505 deletions

View File

@@ -1,25 +0,0 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint', 'import'],
extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
root: true,
ignorePatterns: ["/*", "!/src"],
env: {
es6: true,
browser: true,
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'error',
'@typescript-eslint/explicit-module-boundary-types': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'import/extensions': ['off'],
'import/no-unresolved': 'off',
quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }],
},
};

72
.eslintrc.json Normal file
View File

@@ -0,0 +1,72 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json",
"tsconfigRootDir": ".",
"sourceType": "module"
},
"plugins": ["@typescript-eslint/eslint-plugin", "prettier"],
"extends": ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
"root": true,
"env": {
"node": true,
"jest": true
},
"ignorePatterns": ["/*", "!/src"],
"rules": {
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/prefer-enum-initializers": "error",
"@typescript-eslint/no-mixed-enums": "error",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
"accessibility": "explicit",
"overrides": {
"constructors": "no-public"
}
}
],
"quotes": [
"error",
"single",
{
"allowTemplateLiterals": false,
"avoidEscape": true
}
],
"prettier/prettier": [
"error",
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 110,
"tabWidth": 4
}
],
"no-param-reassign": [
"error",
{ "props": true, "ignorePropertyModificationsFor": ["self", "ref", "el"] }
],
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "typeLike",
"format": ["PascalCase"]
},
{
"selector": "enumMember",
"format": ["UPPER_CASE"]
},
{
"selector": "memberLike",
"modifiers": ["private"],
"format": null,
"leadingUnderscore": "require"
}
]
}
}

View File

@@ -2,7 +2,7 @@
"singleQuote": true, "singleQuote": true,
"semi": true, "semi": true,
"trailingComma": "all", "trailingComma": "all",
"printWidth": 120, "printWidth": 110,
"tabWidth": 4, "tabWidth": 4,
"useTabs": false, "useTabs": false,
"overrides": [ "overrides": [

10
app.ts
View File

@@ -1,10 +1,10 @@
import './src/lib/session'; import './src/lib/session';
import './src/scss/style'; import './src/scss/style';
import './src/globals/useTheme'; import './src/shared/useTheme';
import './src/globals/wallpaper'; import './src/shared/wallpaper';
import './src/globals/systray'; import './src/shared/systray';
import './src/globals/dropdown'; import './src/shared/dropdown';
import './src/globals/utilities'; import './src/shared/utilities';
import './src/components/bar/utils/sideEffects'; import './src/components/bar/utils/sideEffects';
import AstalHyprland from 'gi://AstalHyprland?version=0.1'; import AstalHyprland from 'gi://AstalHyprland?version=0.1';

1392
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,8 +4,8 @@
"description": "A customizable panel built for Hyprland.", "description": "A customizable panel built for Hyprland.",
"main": "app.ts", "main": "app.ts",
"scripts": { "scripts": {
"lint": "eslint --config .eslintrc.js .", "lint": "eslint --config .eslintrc.json .",
"lint:fix": "eslint --config .eslintrc.js . --fix", "lint:fix": "eslint --config .eslintrc.json . --fix",
"format": "prettier --write 'modules/**/*.ts'" "format": "prettier --write 'modules/**/*.ts'"
}, },
"keywords": [], "keywords": [],
@@ -24,6 +24,6 @@
"eslint-plugin-prettier": "^5.2.1", "eslint-plugin-prettier": "^5.2.1",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"tsconfig-paths": "^4.2.0", "tsconfig-paths": "^4.2.0",
"typescript": "^5.6.2" "typescript": "5.7.3"
} }
} }

50
scripts/makeTheme.ts Normal file → Executable file
View File

@@ -21,42 +21,43 @@
* ts-node makeTheme.ts theme.json updatedTheme.json --vivid * ts-node makeTheme.ts theme.json updatedTheme.json --vivid
*/ */
const fs = require('fs'); (() => {
const path = require('path'); const fs = require('fs');
const path = require('path');
/** /**
* Prints the usage/help text. * Prints the usage/help text.
*/ */
function printUsage(): void { function printUsage(): void {
console.log(` console.log(`
Usage: Usage:
ts-node makeTheme.ts <input.json> <output.json> [--vivid | --base | --both] ts-node makeTheme.ts <input.json> <output.json> [--vivid | --base | --both]
Options: Options:
--help Show this help message --help Show this help message
Transforms: Transforms:
--vivid Swap .background with .text (or .total), set .icon = old background --vivid Swap .background with .text (or .total), set .icon = old background
--base Set .icon = .text (or .total), leave .background alone --base Set .icon = .text (or .total), leave .background alone
--both Apply makeVividTheme, then makeBaseTheme --both Apply makeVividTheme, then makeBaseTheme
`); `);
} }
/** /**
* Reads a file as UTF-8 and returns a parsed JSON object. * Reads a file as UTF-8 and returns a parsed JSON object.
*/ */
async function readJson(filePath: string): Promise<Record<string, unknown>> { async function readJson(filePath: string): Promise<Record<string, unknown>> {
const raw = await fs.promises.readFile(path.resolve(filePath), 'utf8'); const raw = await fs.promises.readFile(path.resolve(filePath), 'utf8');
return JSON.parse(raw) as Record<string, unknown>; return JSON.parse(raw);
} }
/** /**
* Executes the "vivid" transformation on the input data. * Executes the "vivid" transformation on the input data.
* For each key matching "theme.bar.buttons.*": * For each key matching "theme.bar.buttons.*":
* - If it has .background and .text (or .total), swap them. * - If it has .background and .text (or .total), swap them.
* - Set .icon to the old background. * - Set .icon to the old background.
*/ */
function makeVividTheme(data: Record<string, unknown>): void { function makeVividTheme(data: Record<string, unknown>): void {
data['theme.bar.buttons.style'] = 'default'; data['theme.bar.buttons.style'] = 'default';
const prefix = 'theme.bar.buttons.'; const prefix = 'theme.bar.buttons.';
@@ -105,15 +106,15 @@ function makeVividTheme(data: Record<string, unknown>): void {
data[fullKey] = grouped[name][prop]; data[fullKey] = grouped[name][prop];
} }
} }
} }
/** /**
* Executes the "base" transformation on the input data. * Executes the "base" transformation on the input data.
* For each key matching "theme.bar.buttons.*": * For each key matching "theme.bar.buttons.*":
* - If it has .text or .total, set .icon to that value. * - If it has .text or .total, set .icon to that value.
* - Leave .background alone. * - Leave .background alone.
*/ */
function makeBaseTheme(data: Record<string, unknown>): void { function makeBaseTheme(data: Record<string, unknown>): void {
data['theme.bar.buttons.style'] = 'default'; data['theme.bar.buttons.style'] = 'default';
const prefix = 'theme.bar.buttons.'; const prefix = 'theme.bar.buttons.';
@@ -148,12 +149,12 @@ function makeBaseTheme(data: Record<string, unknown>): void {
data[fullKey] = grouped[name][prop]; data[fullKey] = grouped[name][prop];
} }
} }
} }
/** /**
* Main CLI entry point. * Main CLI entry point.
*/ */
async function main(): Promise<void> { async function main(): Promise<void> {
const [, , ...args] = process.argv; const [, , ...args] = process.argv;
if (args.includes('--help') || args.length < 2) { if (args.includes('--help') || args.length < 2) {
printUsage(); printUsage();
@@ -189,11 +190,12 @@ async function main(): Promise<void> {
console.error(`Failed to write file: ${output}`, e); console.error(`Failed to write file: ${output}`, e);
process.exit(1); process.exit(1);
} }
} }
if (require.main === module) { if (require.main === module) {
main().catch((e) => { main().catch((e) => {
console.error(e); console.error(e);
process.exit(1); process.exit(1);
}); });
} }
})();

View File

@@ -1,32 +1,36 @@
#!/usr/bin/env ts-node #!/usr/bin/env ts-node
/// <reference types="node" /> /// <reference types="node" />
/** (() => {
/**
* Prints usage/help information to the console. * Prints usage/help information to the console.
* Called whenever the user passes `--help` or when arguments are missing/invalid. * Called whenever the user passes `--help` or when arguments are missing/invalid.
*/ */
function printUsage(): void { function printUsage(): void {
console.log(` console.log(`
Usage: Usage:
ts-node updateColors.ts <theme.json> <original_palette.json> <new_palette.json> <output.json> ts-node updateColors.ts <theme.json> <original_palette.json> <new_palette.json> <output.json>
Options: Options:
--help Show this help message --help Show this help message
Description: Description:
This script reads a theme JSON file containing old color codes, an "original" palette JSON This script reads a theme JSON file containing old color codes, an "original" palette JSON
(which maps color name → old hex code), and a "new" palette JSON (mapping the same color name (which maps color name → old hex code), and a "new" palette JSON (mapping the same color name
→ new hex code). It then replaces all old hex codes in the theme with the corresponding new hex codes, → new hex code). It then replaces all old hex codes in the theme with the corresponding new hex codes,
and saves the result to the specified output JSON file. and saves the result to the specified output JSON file.
Examples: Examples:
ts-node updateColors.ts theme.json original_palette.json new_palette.json updated_theme.json ts-node updateColors.ts theme.json original_palette.json new_palette.json updated_theme.json
node updateColors.js theme.json original_palette.json new_palette.json updated_theme.json node updateColors.js theme.json original_palette.json new_palette.json updated_theme.json
`); `);
} }
/** type Palette = Record<string, string | Record<string, string>>;
type ColorMap = Record<string, string>;
/**
* Recursively walks a palette to build a map from old hex → new hex, * Recursively walks a palette to build a map from old hex → new hex,
* keyed by the same property name in the new palette if it exists. * keyed by the same property name in the new palette if it exists.
* *
@@ -43,7 +47,7 @@ Examples:
* @param updated - The "new" palette containing updated hex codes. * @param updated - The "new" palette containing updated hex codes.
* @returns A map of { oldHex.toLowerCase(): newHex }. * @returns A map of { oldHex.toLowerCase(): newHex }.
*/ */
function buildColorMap(original: Palette, updated: Palette): ColorMap { function buildColorMap(original: Palette, updated: Palette): ColorMap {
const map: ColorMap = {}; const map: ColorMap = {};
for (const [key, oldVal] of Object.entries(original)) { for (const [key, oldVal] of Object.entries(original)) {
@@ -53,7 +57,8 @@ function buildColorMap(original: Palette, updated: Palette): ColorMap {
map[oldVal.toLowerCase()] = newVal; map[oldVal.toLowerCase()] = newVal;
} else if (oldVal && typeof oldVal === 'object') { } else if (oldVal && typeof oldVal === 'object') {
const oldNested = oldVal as Record<string, string>; const oldNested = oldVal as Record<string, string>;
const newNested = newVal && typeof newVal === 'object' ? (newVal as Record<string, string>) : {}; const newNested =
newVal && typeof newVal === 'object' ? (newVal as Record<string, string>) : {};
for (const [nestedKey, nestedOldHex] of Object.entries(oldNested)) { for (const [nestedKey, nestedOldHex] of Object.entries(oldNested)) {
const nestedNewHex = newNested[nestedKey]; const nestedNewHex = newNested[nestedKey];
@@ -66,9 +71,9 @@ function buildColorMap(original: Palette, updated: Palette): ColorMap {
} }
return map; return map;
} }
/** /**
* Recursively replace all string values in a data structure (object, array, etc.) * Recursively replace all string values in a data structure (object, array, etc.)
* if they appear in colorMap. * if they appear in colorMap.
* *
@@ -76,7 +81,7 @@ function buildColorMap(original: Palette, updated: Palette): ColorMap {
* @param colorMap - An object with oldHex.toLowerCase() → newHex mappings. * @param colorMap - An object with oldHex.toLowerCase() → newHex mappings.
* @returns The transformed data with replaced colors. * @returns The transformed data with replaced colors.
*/ */
function replaceColorsInTheme(node: unknown, colorMap: ColorMap): unknown { function replaceColorsInTheme(node: unknown, colorMap: ColorMap): unknown {
if (Array.isArray(node)) { if (Array.isArray(node)) {
return node.map((item) => replaceColorsInTheme(item, colorMap)); return node.map((item) => replaceColorsInTheme(item, colorMap));
} else if (node && typeof node === 'object') { } else if (node && typeof node === 'object') {
@@ -92,16 +97,16 @@ function replaceColorsInTheme(node: unknown, colorMap: ColorMap): unknown {
} else { } else {
return node; return node;
} }
} }
/** /**
* A minimal utility wrapper to read a file asynchronously. * A minimal utility wrapper to read a file asynchronously.
* *
* @param filePath - The file path to read from. * @param filePath - The file path to read from.
* @param encoding - The file encoding (default 'utf8'). * @param encoding - The file encoding (default 'utf8').
* @returns A Promise resolving to the file contents as a string. * @returns A Promise resolving to the file contents as a string.
*/ */
async function readFile(filePath: string, encoding: BufferEncoding = 'utf8'): Promise<string> { async function readFile(filePath: string, encoding: BufferEncoding = 'utf8'): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const fs = require('fs'); const fs = require('fs');
fs.readFile(filePath, encoding, (err: Error, data: string) => { fs.readFile(filePath, encoding, (err: Error, data: string) => {
@@ -112,9 +117,9 @@ async function readFile(filePath: string, encoding: BufferEncoding = 'utf8'): Pr
} }
}); });
}); });
} }
/** /**
* Main function that: * Main function that:
* 1. Checks for --help or missing arguments. * 1. Checks for --help or missing arguments.
* 2. Reads and parses the theme, original palette, and new palette. * 2. Reads and parses the theme, original palette, and new palette.
@@ -126,7 +131,7 @@ async function readFile(filePath: string, encoding: BufferEncoding = 'utf8'): Pr
* ts-node updateColors.ts theme.json original_palette.json new_palette.json output.json * ts-node updateColors.ts theme.json original_palette.json new_palette.json output.json
* ``` * ```
*/ */
async function main(): Promise<void> { async function main(): Promise<void> {
const [, , ...args] = process.argv; const [, , ...args] = process.argv;
if (args.length === 0) { if (args.length === 0) {
@@ -162,15 +167,12 @@ async function main(): Promise<void> {
console.error('Error:', err); console.error('Error:', err);
process.exit(1); process.exit(1);
} }
} }
if (require.main === module) { if (require.main === module) {
main().catch((err) => { main().catch((err) => {
console.error(err); console.error(err);
process.exit(1); process.exit(1);
}); });
} }
})();
type Palette = Record<string, string | Record<string, string>>;
type ColorMap = Record<string, string>;

View File

@@ -14,7 +14,7 @@ import { Command, ParsedCommand } from './types';
* 5. Validates required arguments. * 5. Validates required arguments.
*/ */
export class CommandParser { export class CommandParser {
private registry: CommandRegistry; private _registry: CommandRegistry;
/** /**
* Constructs a CommandParser with the provided command registry. * Constructs a CommandParser with the provided command registry.
@@ -22,7 +22,7 @@ export class CommandParser {
* @param registry - The command registry containing available commands. * @param registry - The command registry containing available commands.
*/ */
constructor(registry: CommandRegistry) { constructor(registry: CommandRegistry) {
this.registry = registry; this._registry = registry;
} }
/** /**
@@ -33,20 +33,22 @@ export class CommandParser {
* @throws If no command token is found. * @throws If no command token is found.
* @throws If the command token is not registered. * @throws If the command token is not registered.
*/ */
parse(input: string): ParsedCommand { public parse(input: string): ParsedCommand {
const tokens = this.tokenize(input); const tokens = this._tokenize(input);
if (tokens.length === 0) { if (tokens.length === 0) {
throw new Error('No command provided.'); throw new Error('No command provided.');
} }
const commandName = tokens.shift()!; const commandName = tokens.shift() ?? 'non-existent-command';
const command = this.registry.get(commandName); const command = this._registry.get(commandName);
if (!command) { if (!command) {
throw new Error(`Unknown command: "${commandName}". Use "hyprpanel explain" for available commands.`); throw new Error(
`Unknown command: "${commandName}". Use "hyprpanel explain" for available commands.`,
);
} }
const args = this.parseArgs(command, tokens); const args = this._parseArgs(command, tokens);
return { command, args }; return { command, args };
} }
@@ -56,10 +58,10 @@ export class CommandParser {
* @param input - The raw input string to break into tokens. * @param input - The raw input string to break into tokens.
* @returns An array of tokens. * @returns An array of tokens.
*/ */
private tokenize(input: string): string[] { private _tokenize(input: string): string[] {
const regex = /(?:[^\s"']+|"[^"]*"|'[^']*')+/g; const regex = /(?:[^\s"']+|"[^"]*"|'[^']*')+/g;
const matches = input.match(regex); const matches = input.match(regex);
return matches ? matches.map((token) => this.stripQuotes(token)) : []; return matches ? matches.map((token) => this._stripQuotes(token)) : [];
} }
/** /**
@@ -68,7 +70,7 @@ export class CommandParser {
* @param str - The token from which to strip leading or trailing quotes. * @param str - The token from which to strip leading or trailing quotes.
* @returns The token without its outer quotes. * @returns The token without its outer quotes.
*/ */
private stripQuotes(str: string): string { private _stripQuotes(str: string): string {
return str.replace(/^["'](.+(?=["']$))["']$/, '$1'); return str.replace(/^["'](.+(?=["']$))["']$/, '$1');
} }
@@ -81,13 +83,13 @@ export class CommandParser {
* @throws If required arguments are missing. * @throws If required arguments are missing.
* @throws If there are too many tokens for the command definition. * @throws If there are too many tokens for the command definition.
*/ */
private parseArgs(command: Command, tokens: string[]): Record<string, unknown> { private _parseArgs(command: Command, tokens: string[]): Record<string, unknown> {
const args: Record<string, unknown> = {}; const args: Record<string, unknown> = {};
let currentIndex = 0; let currentIndex = 0;
for (const argDef of command.args) { for (const argDef of command.args) {
if (currentIndex >= tokens.length) { if (currentIndex >= tokens.length) {
if (argDef.required) { if (argDef.required === true) {
throw new Error(`Missing required argument: "${argDef.name}".`); throw new Error(`Missing required argument: "${argDef.name}".`);
} }
if (argDef.default !== undefined) { if (argDef.default !== undefined) {
@@ -97,13 +99,13 @@ export class CommandParser {
} }
if (argDef.type === 'object') { if (argDef.type === 'object') {
const { objectValue, nextIndex } = this.parseObjectTokens(tokens, currentIndex); const { objectValue, nextIndex } = this._parseObjectTokens(tokens, currentIndex);
args[argDef.name] = objectValue; args[argDef.name] = objectValue;
currentIndex = nextIndex; currentIndex = nextIndex;
} else { } else {
const value = tokens[currentIndex]; const value = tokens[currentIndex];
currentIndex++; currentIndex++;
args[argDef.name] = this.convertType(value, argDef.type); args[argDef.name] = this._convertType(value, argDef.type);
} }
} }
@@ -125,7 +127,10 @@ export class CommandParser {
* @returns An object containing the parsed JSON object and the next token index. * @returns An object containing the parsed JSON object and the next token index.
* @throws If the reconstructed JSON is invalid. * @throws If the reconstructed JSON is invalid.
*/ */
private parseObjectTokens(tokens: string[], startIndex: number): { objectValue: unknown; nextIndex: number } { private _parseObjectTokens(
tokens: string[],
startIndex: number,
): { objectValue: unknown; nextIndex: number } {
let braceCount = 0; let braceCount = 0;
let started = false; let started = false;
const objectTokens: string[] = []; const objectTokens: string[] = [];
@@ -142,7 +147,6 @@ export class CommandParser {
objectTokens.push(token); objectTokens.push(token);
// Once we've started and braceCount returns to 0, we assume the object is complete
if (started && braceCount === 0) break; if (started && braceCount === 0) break;
if (token.includes('{')) started = true; if (token.includes('{')) started = true;
} }
@@ -166,7 +170,7 @@ export class CommandParser {
* @returns The converted value. * @returns The converted value.
* @throws If the token cannot be converted to the expected type. * @throws If the token cannot be converted to the expected type.
*/ */
private convertType(value: string, type: 'string' | 'number' | 'boolean' | 'object'): unknown { private _convertType(value: string, type: 'string' | 'number' | 'boolean' | 'object'): unknown {
switch (type) { switch (type) {
case 'number': { case 'number': {
const num = Number(value); const num = Number(value);

View File

@@ -6,7 +6,7 @@ import { Command } from './types';
* and retrieval of all commands for listing and help functionalities. * and retrieval of all commands for listing and help functionalities.
*/ */
export class CommandRegistry { export class CommandRegistry {
private commands: Map<string, Command> = new Map(); private _commands: Map<string, Command> = new Map();
/** /**
* Registers a command. If a command with the same name or alias already exists, * Registers a command. If a command with the same name or alias already exists,
@@ -15,18 +15,18 @@ export class CommandRegistry {
* @param command - The command to register. * @param command - The command to register.
* @throws If a command with the same name or alias already exists. * @throws If a command with the same name or alias already exists.
*/ */
register(command: Command): void { public register(command: Command): void {
if (this.commands.has(command.name)) { if (this._commands.has(command.name)) {
throw new Error(`Command "${command.name}" is already registered.`); throw new Error(`Command "${command.name}" is already registered.`);
} }
this.commands.set(command.name, command); this._commands.set(command.name, command);
if (command.aliases) { if (command.aliases) {
for (const alias of command.aliases) { for (const alias of command.aliases) {
if (this.commands.has(alias)) { if (this._commands.has(alias)) {
throw new Error(`Alias "${alias}" is already in use.`); throw new Error(`Alias "${alias}" is already in use.`);
} }
this.commands.set(alias, command); this._commands.set(alias, command);
} }
} }
} }
@@ -37,8 +37,8 @@ export class CommandRegistry {
* @param commandName - The name or alias of the command to retrieve. * @param commandName - The name or alias of the command to retrieve.
* @returns The command if found, otherwise undefined. * @returns The command if found, otherwise undefined.
*/ */
get(commandName: string): Command | undefined { public get(commandName: string): Command | undefined {
return this.commands.get(commandName); return this._commands.get(commandName);
} }
/** /**
@@ -46,8 +46,8 @@ export class CommandRegistry {
* *
* @returns An array of all registered commands. * @returns An array of all registered commands.
*/ */
getAll(): Command[] { public getAll(): Command[] {
const unique = new Set<Command>(this.commands.values()); const unique = new Set<Command>(this._commands.values());
return Array.from(unique); return Array.from(unique);
} }
} }

View File

@@ -8,7 +8,7 @@ import { ResponseCallback } from './types';
* 3. Handles any errors and passes the result back via the response callback. * 3. Handles any errors and passes the result back via the response callback.
*/ */
export class RequestHandler { export class RequestHandler {
private parser: CommandParser; private _parser: CommandParser;
/** /**
* Creates an instance of RequestHandler. * Creates an instance of RequestHandler.
@@ -16,7 +16,7 @@ export class RequestHandler {
* @param parser - The CommandParser instance to use. * @param parser - The CommandParser instance to use.
*/ */
constructor(parser: CommandParser) { constructor(parser: CommandParser) {
this.parser = parser; this._parser = parser;
} }
/** /**
@@ -26,20 +26,20 @@ export class RequestHandler {
* @param response - The callback to handle the response. * @param response - The callback to handle the response.
* @returns A promise that resolves when the request is handled. * @returns A promise that resolves when the request is handled.
*/ */
async initializeRequestHandler(input: string, response: ResponseCallback): Promise<void> { public async initializeRequestHandler(input: string, response: ResponseCallback): Promise<void> {
try { try {
const parsed = this.parser.parse(input); const parsed = this._parser.parse(input);
const { command, args } = parsed; const { command, args } = parsed;
const result = command.handler(args); const result = command.handler(args);
if (result instanceof Promise) { if (result instanceof Promise) {
const resolved = await result; const resolved = await result;
response(this.formatOutput(resolved)); response(this._formatOutput(resolved));
} else { } else {
response(this.formatOutput(result)); response(this._formatOutput(result));
} }
} catch (error) { } catch (error) {
response(this.formatError(error)); response(this._formatError(error));
} }
} }
@@ -49,7 +49,7 @@ export class RequestHandler {
* @param output - The output to format. * @param output - The output to format.
* @returns A string representation of the output. * @returns A string representation of the output.
*/ */
private formatOutput(output: unknown): string { private _formatOutput(output: unknown): string {
if (typeof output === 'string') { if (typeof output === 'string') {
return output; return output;
} else if (typeof output === 'number' || typeof output === 'boolean') { } else if (typeof output === 'number' || typeof output === 'boolean') {
@@ -71,7 +71,7 @@ export class RequestHandler {
* @param error - The error to format. * @param error - The error to format.
* @returns A string representation of the error. * @returns A string representation of the error.
*/ */
private formatError(error: unknown): string { private _formatError(error: unknown): string {
if (error instanceof Error) { if (error instanceof Error) {
return `Error: ${error.message}`; return `Error: ${error.message}`;
} else if (typeof error === 'string') { } else if (typeof error === 'string') {

View File

@@ -1,6 +1,9 @@
import { errorHandler } from 'src/lib/utils'; import { errorHandler } from 'src/lib/utils';
import { BarLayouts } from 'src/lib/types/options';
import { Command } from '../../types'; import { Command } from '../../types';
import { setWallpaper } from 'src/shared/wallpaper';
import { useTheme } from 'src/shared/useTheme';
import { setLayout } from 'src/shared/utilities';
import { BarLayouts } from 'src/lib/options/options.types';
export const appearanceCommands: Command[] = [ export const appearanceCommands: Command[] = [
{ {
@@ -58,7 +61,8 @@ export const appearanceCommands: Command[] = [
args: [ args: [
{ {
name: 'layout', name: 'layout',
description: 'Bar layout to apply. Wiki: https://hyprpanel.com/configuration/panel.html#layouts', description:
'Bar layout to apply. Wiki: https://hyprpanel.com/configuration/panel.html#layouts',
type: 'object', type: 'object',
required: true, required: true,
}, },

View File

@@ -110,9 +110,9 @@ function checkServiceStatus(services: string[]): ServiceStatus {
const enabledResult = runCommand(`systemctl is-enabled ${svc}`); const enabledResult = runCommand(`systemctl is-enabled ${svc}`);
const enabledStatus = enabledResult.stdout; const enabledStatus = enabledResult.stdout;
if (enabledResult && (enabledStatus === 'enabled' || enabledStatus === 'static')) { if (enabledResult !== undefined && (enabledStatus === 'enabled' || enabledStatus === 'static')) {
return 'INSTALLED'; return 'INSTALLED';
} else if (enabledResult && enabledStatus === 'disabled') { } else if (enabledResult !== undefined && enabledStatus === 'disabled') {
return 'DISABLED'; return 'DISABLED';
} else { } else {
return 'MISSING'; return 'MISSING';
@@ -174,7 +174,7 @@ function getDependencyStatus(dep: Dependency): string {
break; break;
} }
if (!dep.description) { if (dep.description === undefined) {
return ` ${colorText(textStatus, color)} ${dep.package}`; return ` ${colorText(textStatus, color)} ${dep.package}`;
} }

View File

@@ -3,6 +3,10 @@ import { errorHandler } from 'src/lib/utils';
import { Command } from '../../types'; import { Command } from '../../types';
import { execAsync, Gio, GLib } from 'astal'; import { execAsync, Gio, GLib } from 'astal';
import { checkDependencies } from './checkDependencies'; import { checkDependencies } from './checkDependencies';
import options from 'src/options';
import { clearAllNotifications } from 'src/shared/notification';
import { getSystrayItems } from 'src/shared/systray';
import { idleInhibit } from 'src/shared/utilities';
const audio = AstalWp.get_default(); const audio = AstalWp.get_default();
@@ -15,7 +19,7 @@ export const utilityCommands: Command[] = [
args: [], args: [],
handler: (): string => { handler: (): string => {
try { try {
return getSystrayItems(); return getSystrayItems() ?? 'No items found!';
} catch (error) { } catch (error) {
errorHandler(error); errorHandler(error);
} }
@@ -88,7 +92,8 @@ export const utilityCommands: Command[] = [
{ {
name: 'idleInhibit', name: 'idleInhibit',
aliases: ['idi'], aliases: ['idi'],
description: 'Enables/Disables the Idle Inhibitor. Toggles the Inhibitor if no parameter is provided.', description:
'Enables/Disables the Idle Inhibitor. Toggles the Inhibitor if no parameter is provided.',
category: 'Utility', category: 'Utility',
args: [ args: [
{ {
@@ -100,7 +105,7 @@ export const utilityCommands: Command[] = [
], ],
handler: (args: Record<string, unknown>): boolean => { handler: (args: Record<string, unknown>): boolean => {
try { try {
const shouldInhibit = args['shouldInhibit'] ?? !idleInhibit.get(); const shouldInhibit = args['shouldInhibit'] ?? idleInhibit.get() === false;
idleInhibit.set(Boolean(shouldInhibit)); idleInhibit.set(Boolean(shouldInhibit));
return idleInhibit.get(); return idleInhibit.get();

View File

@@ -2,6 +2,7 @@ import { errorHandler } from 'src/lib/utils';
import { Command } from '../../types'; import { Command } from '../../types';
import { App } from 'astal/gtk3'; import { App } from 'astal/gtk3';
import { BarVisibility } from 'src/cli/utils/BarVisibility'; import { BarVisibility } from 'src/cli/utils/BarVisibility';
import { isWindowVisible } from 'src/shared/utilities';
export const windowManagementCommands: Command[] = [ export const windowManagementCommands: Command[] = [
{ {

View File

@@ -58,7 +58,7 @@ export function createExplainCommand(registry: CommandRegistry): Command {
handler: (args: Record<string, unknown>): string => { handler: (args: Record<string, unknown>): string => {
const commandName = args['commandName'] as string | undefined; const commandName = args['commandName'] as string | undefined;
if (commandName) { if (commandName !== undefined) {
return formatCommandExplain(registry, commandName); return formatCommandExplain(registry, commandName);
} }
@@ -134,7 +134,7 @@ function organizeCommandsByCategory(commands: Command[]): CategoryMap {
const categoryMap: CategoryMap = {}; const categoryMap: CategoryMap = {};
commands.forEach((cmd) => { commands.forEach((cmd) => {
if (!categoryMap[cmd.category]) { if (categoryMap[cmd.category] === undefined) {
categoryMap[cmd.category] = []; categoryMap[cmd.category] = [];
} }
categoryMap[cmd.category].push(cmd); categoryMap[cmd.category].push(cmd);
@@ -183,7 +183,8 @@ function formatArguments(args: PositionalArg[]): string {
return ( return (
args args
.map((arg) => { .map((arg) => {
const requirement = arg.required ? `${ANSI_FG_RED}(required)` : `${ANSI_FG_CYAN}(optional)`; const requirement =
arg.required === true ? `${ANSI_FG_RED}(required)` : `${ANSI_FG_CYAN}(optional)`;
const defaultValue = const defaultValue =
arg.default !== undefined arg.default !== undefined
? ` ${ANSI_FG_MAGENTA}[default: ${JSON.stringify(arg.default)}]${ANSI_RESET}` ? ` ${ANSI_FG_MAGENTA}[default: ${JSON.stringify(arg.default)}]${ANSI_RESET}`

View File

@@ -1,4 +1,4 @@
import { BarToggleStates } from 'src/lib/types/cli'; import { BarToggleStates } from 'src/lib/types/cli.types';
export class BarVisibility { export class BarVisibility {
private static _toggleStates: BarToggleStates = {}; private static _toggleStates: BarToggleStates = {};

View File

@@ -23,7 +23,7 @@ export class CustomModules {
return customModuleComponents; return customModuleComponents;
} catch (error) { } catch (error) {
console.log(`Failed to build custom modules in ${CONFIG_DIR}: ${error}`); console.error(`Failed to build custom modules in ${CONFIG_DIR}: ${error}`);
throw new Error(`Failed to build custom modules in ${CONFIG_DIR}: ${error}`); throw new Error(`Failed to build custom modules in ${CONFIG_DIR}: ${error}`);
} }
} }

View File

@@ -48,7 +48,11 @@ export function getIcon(moduleName: string, commandOutput: string, moduleIcon: C
* - No matching icon is found for the alt text * - No matching icon is found for the alt text
* - Corresponding icon value is not a string * - Corresponding icon value is not a string
*/ */
function getIconFromObject(moduleName: string, commandOutput: string, iconObject: Record<string, unknown>): string { function getIconFromObject(
moduleName: string,
commandOutput: string,
iconObject: Record<string, unknown>,
): string {
try { try {
const commandResults: CommandResults = parseCommandOutputJson(moduleName, commandOutput); const commandResults: CommandResults = parseCommandOutputJson(moduleName, commandOutput);
@@ -115,7 +119,7 @@ function getIconFromArray(moduleName: string, commandOutput: string, iconArray:
const iconForStep = iconArray.find((_, index) => resultsPercentage <= step * (index + 1)); const iconForStep = iconArray.find((_, index) => resultsPercentage <= step * (index + 1));
return iconForStep || ERROR_ICON; return iconForStep ?? ERROR_ICON;
} catch { } catch {
return ERROR_ICON; return ERROR_ICON;
} }

View File

@@ -29,7 +29,10 @@ export function getLabel(moduleName: string, commandOutput: string, labelConfig:
* @param commandOutput - The processed command output (either a string or object) * @param commandOutput - The processed command output (either a string or object)
* @returns The extracted value as a string, or empty string if not found * @returns The extracted value as a string, or empty string if not found
*/ */
function getValueForTemplateVariable(templatePath: string, commandOutput: string | Record<string, unknown>): string { function getValueForTemplateVariable(
templatePath: string,
commandOutput: string | Record<string, unknown>,
): string {
if (typeof commandOutput === 'string') { if (typeof commandOutput === 'string') {
return getTemplateValueForStringOutput(templatePath, commandOutput); return getTemplateValueForStringOutput(templatePath, commandOutput);
} }
@@ -62,7 +65,10 @@ function getTemplateValueForStringOutput(templatePath: string, commandOutput: st
* @param commandOutput - The object representing parsed command output * @param commandOutput - The object representing parsed command output
* @returns The extracted value as a string, or empty string if path is invalid or value is not primitive * @returns The extracted value as a string, or empty string if path is invalid or value is not primitive
*/ */
function getTemplateValueForObjectOutput(templatePath: string, commandOutput: Record<string, unknown>): string { function getTemplateValueForObjectOutput(
templatePath: string,
commandOutput: Record<string, unknown>,
): string {
const pathParts = templatePath.split('.'); const pathParts = templatePath.split('.');
function isRecord(value: unknown): value is Record<string, unknown> { function isRecord(value: unknown): value is Record<string, unknown> {

View File

@@ -1,4 +1,3 @@
import { BarBoxChild } from 'src/lib/types/bar.js';
import { CustomBarModule } from '../types'; import { CustomBarModule } from '../types';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
@@ -6,6 +5,7 @@ import { bind, Variable } from 'astal';
import { getIcon } from './helpers/icon'; import { getIcon } from './helpers/icon';
import { getLabel } from './helpers/label'; import { getLabel } from './helpers/label';
import { initActionListener, initCommandPoller, setupModuleInteractions } from './setup'; import { initActionListener, initCommandPoller, setupModuleInteractions } from './setup';
import { BarBoxChild } from 'src/lib/types/bar.types';
export const ModuleContainer = (moduleName: string, moduleMetadata: CustomBarModule): BarBoxChild => { export const ModuleContainer = (moduleName: string, moduleMetadata: CustomBarModule): BarBoxChild => {
const { const {

View File

@@ -37,6 +37,7 @@ import { bind, Variable } from 'astal';
import { getLayoutForMonitor, isLayoutEmpty } from './utils/monitors'; import { getLayoutForMonitor, isLayoutEmpty } from './utils/monitors';
import { GdkMonitorMapper } from './utils/GdkMonitorMapper'; import { GdkMonitorMapper } from './utils/GdkMonitorMapper';
import { CustomModules } from './custom_modules/CustomModules'; import { CustomModules } from './custom_modules/CustomModules';
import { idleInhibit } from 'src/shared/utilities';
const { layouts } = options.bar; const { layouts } = options.bar;
const { location } = options.theme.bar; const { location } = options.theme.bar;
@@ -82,7 +83,7 @@ export const Bar = async (monitor: number): Promise<JSX.Element> => {
...customWidgets, ...customWidgets,
}; };
} catch (error) { } catch (error) {
console.log(error); console.error(error);
} }
const hyprlandMonitor = gdkMonitorMapper.mapGdkToHyprland(monitor); const hyprlandMonitor = gdkMonitorMapper.mapGdkToHyprland(monitor);
@@ -93,7 +94,7 @@ export const Bar = async (monitor: number): Promise<JSX.Element> => {
const computeClassName = bind(layouts).as(() => { const computeClassName = bind(layouts).as(() => {
const foundLayout = getLayoutForMonitor(hyprlandMonitor, layouts.get()); const foundLayout = getLayoutForMonitor(hyprlandMonitor, layouts.get());
return !isLayoutEmpty(foundLayout) ? `bar` : ''; return !isLayoutEmpty(foundLayout) ? 'bar' : '';
}); });
const computeAnchor = bind(location).as((loc) => { const computeAnchor = bind(location).as((loc) => {
@@ -104,7 +105,9 @@ export const Bar = async (monitor: number): Promise<JSX.Element> => {
return Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT; return Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT;
}); });
const computeLayer = Variable.derive([bind(options.theme.bar.layer), bind(options.tear)], (barLayer, tear) => { const computeLayer = Variable.derive(
[bind(options.theme.bar.layer), bind(options.tear)],
(barLayer, tear) => {
if (tear && barLayer === 'overlay') { if (tear && barLayer === 'overlay') {
return Astal.Layer.TOP; return Astal.Layer.TOP;
} }
@@ -116,7 +119,8 @@ export const Bar = async (monitor: number): Promise<JSX.Element> => {
}; };
return layerMap[barLayer]; return layerMap[barLayer];
}); },
);
const computeBorderLocation = bind(borderLocation).as((brdrLcn) => const computeBorderLocation = bind(borderLocation).as((brdrLcn) =>
brdrLcn !== 'none' ? 'bar-panel withBorder' : 'bar-panel', brdrLcn !== 'none' ? 'bar-panel withBorder' : 'bar-panel',

View File

@@ -1,4 +1,4 @@
import { BatteryIconKeys, BatteryIcons } from 'src/lib/types/battery'; import { BatteryIconKeys, BatteryIcons } from 'src/lib/types/battery.types';
const batteryIcons: BatteryIcons = { const batteryIcons: BatteryIcons = {
0: '󰂎', 0: '󰂎',

View File

@@ -2,15 +2,22 @@ import AstalBattery from 'gi://AstalBattery?version=0.1';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { openMenu } from '../../utils/menu'; import { openMenu } from '../../utils/menu';
import options from 'src/options'; import options from 'src/options';
import { BarBoxChild } from 'src/lib/types/bar.js';
import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js'; import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js';
import Variable from 'astal/variable'; import Variable from 'astal/variable';
import { bind } from 'astal'; import { bind } from 'astal';
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers'; import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers';
import { getBatteryIcon } from './helpers'; import { getBatteryIcon } from './helpers';
import { BarBoxChild } from 'src/lib/types/bar.types';
const batteryService = AstalBattery.get_default(); const batteryService = AstalBattery.get_default();
const { label: show_label, rightClick, middleClick, scrollUp, scrollDown, hideLabelWhenFull } = options.bar.battery; const {
label: show_label,
rightClick,
middleClick,
scrollUp,
scrollDown,
hideLabelWhenFull,
} = options.bar.battery;
const BatteryLabel = (): BarBoxChild => { const BatteryLabel = (): BarBoxChild => {
const batIcon = Variable.derive( const batIcon = Variable.derive(
@@ -55,10 +62,18 @@ const BatteryLabel = (): BarBoxChild => {
); );
const componentTooltip = Variable.derive( const componentTooltip = Variable.derive(
[bind(batteryService, 'charging'), bind(batteryService, 'timeToFull'), bind(batteryService, 'timeToEmpty')], [
bind(batteryService, 'charging'),
bind(batteryService, 'timeToFull'),
bind(batteryService, 'timeToEmpty'),
],
(isCharging, timeToFull, timeToEmpty) => { (isCharging, timeToFull, timeToEmpty) => {
const timeRemaining = isCharging ? timeToFull : timeToEmpty; const timeRemaining = isCharging ? timeToFull : timeToEmpty;
return generateTooltip(timeRemaining, isCharging, Math.floor(batteryService.percentage * 100) === 100); return generateTooltip(
timeRemaining,
isCharging,
Math.floor(batteryService.percentage * 100) === 100,
);
}, },
); );
@@ -68,7 +83,9 @@ const BatteryLabel = (): BarBoxChild => {
const isCharged = Math.round(percentage) === 100; const isCharged = Math.round(percentage) === 100;
const icon = <label className={'bar-button-icon battery txt-icon'} label={batIcon()} />; const icon = <label className={'bar-button-icon battery txt-icon'} label={batIcon()} />;
const label = <label className={'bar-button-label battery'} label={`${Math.floor(percentage * 100)}%`} />; const label = (
<label className={'bar-button-label battery'} label={`${Math.floor(percentage * 100)}%`} />
);
const children = [icon]; const children = [icon];
@@ -135,7 +152,9 @@ const BatteryLabel = (): BarBoxChild => {
}), }),
); );
disconnectFunctions.push(onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get())); disconnectFunctions.push(
onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get()),
);
}, },
); );
}, },

View File

@@ -1,11 +1,11 @@
import options from 'src/options.js'; import options from 'src/options.js';
import { openMenu } from '../../utils/menu.js'; import { openMenu } from '../../utils/menu.js';
import { BarBoxChild } from 'src/lib/types/bar.js';
import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js'; import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js';
import { Variable, bind } from 'astal'; import { Variable, bind } from 'astal';
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers.js'; import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers.js';
import AstalBluetooth from 'gi://AstalBluetooth?version=0.1'; import AstalBluetooth from 'gi://AstalBluetooth?version=0.1';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { BarBoxChild } from 'src/lib/types/bar.types.js';
const bluetoothService = AstalBluetooth.get_default(); const bluetoothService = AstalBluetooth.get_default();
@@ -20,7 +20,11 @@ const Bluetooth = (): BarBoxChild => {
const connectDevices = devices.filter((device) => device.connected); const connectDevices = devices.filter((device) => device.connected);
const label = const label =
isPowered && connectDevices.length ? ` Connected (${connectDevices.length})` : isPowered ? 'On' : 'Off'; isPowered && connectDevices.length
? ` Connected (${connectDevices.length})`
: isPowered
? 'On'
: 'Off';
return <label label={label} className={'bar-button-label bluetooth'} />; return <label label={label} className={'bar-button-label bluetooth'} />;
}; };
@@ -102,7 +106,9 @@ const Bluetooth = (): BarBoxChild => {
}), }),
); );
disconnectFunctions.push(onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get())); disconnectFunctions.push(
onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get()),
);
}, },
); );
}, },

View File

@@ -1,11 +1,11 @@
import { Variable, bind } from 'astal'; import { Variable, bind } from 'astal';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { BarBoxChild } from 'src/lib/types/bar';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { inputHandler } from '../../utils/helpers'; import { inputHandler } from '../../utils/helpers';
import options from 'src/options'; import options from 'src/options';
import { initSettingsTracker, initVisibilityTracker } from './helpers'; import { initSettingsTracker, initVisibilityTracker } from './helpers';
import AstalCava from 'gi://AstalCava?version=0.1'; import AstalCava from 'gi://AstalCava?version=0.1';
import { BarBoxChild } from 'src/lib/types/bar.types';
const { const {
icon, icon,
@@ -46,7 +46,7 @@ export const Cava = (): BarBoxChild => {
} }
return Module({ return Module({
isVis, isVis: bind(isVis),
label: labelBinding(), label: labelBinding(),
showIconBinding: bind(label), showIconBinding: bind(label),
textIcon: bind(icon), textIcon: bind(icon),

View File

@@ -1,20 +1,24 @@
import { openMenu } from '../../utils/menu'; import { openMenu } from '../../utils/menu';
import options from 'src/options'; import options from 'src/options';
import { BarBoxChild } from 'src/lib/types/bar.js';
import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js'; import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers'; import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { systemTime } from 'src/globals/time'; import { systemTime } from 'src/shared/time';
import { BarBoxChild } from 'src/lib/types/bar.types';
const { format, icon, showIcon, showTime, rightClick, middleClick, scrollUp, scrollDown } = options.bar.clock; const { format, icon, showIcon, showTime, rightClick, middleClick, scrollUp, scrollDown } = options.bar.clock;
const { style } = options.theme.bar.buttons; const { style } = options.theme.bar.buttons;
const time = Variable.derive([systemTime, format], (c, f) => c.format(f) || ''); const time = Variable.derive([systemTime, format], (c, f) => c.format(f) ?? '');
const Clock = (): BarBoxChild => { const Clock = (): BarBoxChild => {
const ClockTime = (): JSX.Element => <label className={'bar-button-label clock bar'} label={bind(time)} />; const ClockTime = (): JSX.Element => (
const ClockIcon = (): JSX.Element => <label className={'bar-button-icon clock txt-icon bar'} label={bind(icon)} />; <label className={'bar-button-label clock bar'} label={bind(time)} />
);
const ClockIcon = (): JSX.Element => (
<label className={'bar-button-icon clock txt-icon bar'} label={bind(icon)} />
);
const componentClassName = Variable.derive( const componentClassName = Variable.derive(
[bind(style), bind(showIcon), bind(showTime)], [bind(style), bind(showIcon), bind(showTime)],
@@ -95,7 +99,9 @@ const Clock = (): BarBoxChild => {
}), }),
); );
disconnectFunctions.push(onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get())); disconnectFunctions.push(
onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get()),
);
}, },
); );
}, },

View File

@@ -15,7 +15,6 @@ export const computeCPU = (): number => {
const currentCpuData = new GTop.glibtop_cpu(); const currentCpuData = new GTop.glibtop_cpu();
GTop.glibtop_get_cpu(currentCpuData); GTop.glibtop_get_cpu(currentCpuData);
// Calculate the differences from the previous to current data
const totalDiff = currentCpuData.total - previousCpuData.total; const totalDiff = currentCpuData.total - previousCpuData.total;
const idleDiff = currentCpuData.idle - previousCpuData.idle; const idleDiff = currentCpuData.idle - previousCpuData.idle;

View File

@@ -2,10 +2,10 @@ import { Module } from '../../shared/Module';
import options from 'src/options'; import options from 'src/options';
import { inputHandler } from 'src/components/bar/utils/helpers'; import { inputHandler } from 'src/components/bar/utils/helpers';
import { computeCPU } from './helpers'; import { computeCPU } from './helpers';
import { BarBoxChild } from 'src/lib/types/bar';
import { FunctionPoller } from 'src/lib/poller/FunctionPoller'; import { FunctionPoller } from 'src/lib/poller/FunctionPoller';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { BarBoxChild } from 'src/lib/types/bar.types';
const { label, round, leftClick, rightClick, middleClick, scrollUp, scrollDown, pollingInterval, icon } = const { label, round, leftClick, rightClick, middleClick, scrollUp, scrollDown, pollingInterval, icon } =
options.bar.customModules.cpu; options.bar.customModules.cpu;

View File

@@ -1,8 +1,8 @@
import { Variable } from 'astal'; import { Variable } from 'astal';
import GLib from 'gi://GLib?version=2.0'; import GLib from 'gi://GLib?version=2.0';
import { convertCelsiusToFahrenheit } from 'src/globals/weather'; import { convertCelsiusToFahrenheit } from 'src/shared/weather';
import { UnitType } from 'src/lib/types/weather';
import options from 'src/options'; import options from 'src/options';
import { UnitType } from 'src/lib/types/weather.types';
const { sensor } = options.bar.customModules.cpuTemp; const { sensor } = options.bar.customModules.cpuTemp;
/** /**
@@ -25,7 +25,7 @@ export const getCPUTemperature = (round: Variable<boolean>, unit: Variable<UnitT
const [success, tempInfoBytes] = GLib.file_get_contents(sensor.get()); const [success, tempInfoBytes] = GLib.file_get_contents(sensor.get());
const tempInfo = new TextDecoder('utf-8').decode(tempInfoBytes); const tempInfo = new TextDecoder('utf-8').decode(tempInfoBytes);
if (!success || !tempInfoBytes) { if (!success || tempInfoBytes === null) {
console.error(`Failed to read ${sensor.get()} or file content is null.`); console.error(`Failed to read ${sensor.get()} or file content is null.`);
return 0; return 0;
} }

View File

@@ -2,11 +2,11 @@ import options from 'src/options';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { inputHandler } from 'src/components/bar/utils/helpers'; import { inputHandler } from 'src/components/bar/utils/helpers';
import { getCPUTemperature } from './helpers'; import { getCPUTemperature } from './helpers';
import { BarBoxChild } from 'src/lib/types/bar';
import { FunctionPoller } from 'src/lib/poller/FunctionPoller'; import { FunctionPoller } from 'src/lib/poller/FunctionPoller';
import { UnitType } from 'src/lib/types/weather';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { UnitType } from 'src/lib/types/weather.types';
import { BarBoxChild } from 'src/lib/types/bar.types';
const { const {
label, label,

View File

@@ -3,31 +3,37 @@ import { Module } from '../../shared/Module';
import { inputHandler } from '../../utils/helpers'; import { inputHandler } from '../../utils/helpers';
import Variable from 'astal/variable'; import Variable from 'astal/variable';
import { bind } from 'astal'; import { bind } from 'astal';
import { BarBoxChild } from 'src/lib/types/bar';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { idleInhibit } from 'src/shared/utilities';
import { BarBoxChild } from 'src/lib/types/bar.types';
const { label, onIcon, offIcon, onLabel, offLabel, rightClick, middleClick, scrollUp, scrollDown } = const { label, onIcon, offIcon, onLabel, offLabel, rightClick, middleClick, scrollUp, scrollDown } =
options.bar.customModules.hypridle; options.bar.customModules.hypridle;
function toggleInhibit(): void { function toggleInhibit(): void {
idleInhibit.set(!idleInhibit.get()); idleInhibit.set(idleInhibit.get() === false);
} }
export const Hypridle = (): BarBoxChild => { export const Hypridle = (): BarBoxChild => {
const iconBinding = Variable.derive([bind(idleInhibit), bind(onIcon), bind(offIcon)], (active, onIcn, offIcn) => { const iconBinding = Variable.derive(
return active ? onIcn : offIcn; [bind(idleInhibit), bind(onIcon), bind(offIcon)],
}); (active, onIcn, offIcn) => {
return active === true ? onIcn : offIcn;
},
);
const labelBinding = Variable.derive( const labelBinding = Variable.derive(
[bind(idleInhibit), bind(onLabel), bind(offLabel)], [bind(idleInhibit), bind(onLabel), bind(offLabel)],
(active, onLbl, offLbl) => { (active, onLbl, offLbl) => {
return active ? onLbl : offLbl; return active === true ? onLbl : offLbl;
}, },
); );
const hypridleModule = Module({ const hypridleModule = Module({
textIcon: iconBinding(), textIcon: iconBinding(),
tooltipText: bind(idleInhibit).as((active) => `Idle Inhibitor: ${active ? 'Enabled' : 'Disabled'}`), tooltipText: bind(idleInhibit).as(
(active) => `Idle Inhibitor: ${active === true ? 'Enabled' : 'Disabled'}`,
),
boxClass: 'hypridle', boxClass: 'hypridle',
label: labelBinding(), label: labelBinding(),
showLabelBinding: bind(label), showLabelBinding: bind(label),

View File

@@ -9,7 +9,7 @@ const { temperature } = options.bar.customModules.hyprsunset;
* This command checks if the hyprsunset process is currently running by using the `pgrep` command. * This command checks if the hyprsunset process is currently running by using the `pgrep` command.
* It returns 'yes' if the process is found and 'no' otherwise. * It returns 'yes' if the process is found and 'no' otherwise.
*/ */
export const isActiveCommand = `bash -c "pgrep -x 'hyprsunset' > /dev/null && echo 'yes' || echo 'no'"`; export const isActiveCommand = "bash -c \"pgrep -x 'hyprsunset' > /dev/null && echo 'yes' || echo 'no'\"";
/** /**
* A variable to track the active state of the hyprsunset process. * A variable to track the active state of the hyprsunset process.
@@ -33,7 +33,7 @@ export const toggleSunset = (isActive: Variable<boolean>): void => {
}); });
}); });
} else { } else {
execAsync(`bash -c "pkill hyprsunset "`).then(() => { execAsync('bash -c "pkill hyprsunset "').then(() => {
execAsync(isActiveCommand).then((res) => { execAsync(isActiveCommand).then((res) => {
isActive.set(res === 'yes'); isActive.set(res === 'yes');
}); });

View File

@@ -1,11 +1,11 @@
import options from 'src/options'; import options from 'src/options';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { inputHandler, throttleInput } from 'src/components/bar/utils/helpers'; import { inputHandler, throttleInput } from 'src/components/bar/utils/helpers';
import { BarBoxChild } from 'src/lib/types/bar';
import { checkSunsetStatus, isActive, toggleSunset } from './helpers'; import { checkSunsetStatus, isActive, toggleSunset } from './helpers';
import { FunctionPoller } from 'src/lib/poller/FunctionPoller'; import { FunctionPoller } from 'src/lib/poller/FunctionPoller';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { BarBoxChild } from 'src/lib/types/bar.types';
const { const {
label, label,
@@ -25,24 +25,35 @@ const dummyVar = Variable(undefined);
checkSunsetStatus(); checkSunsetStatus();
const sunsetPoller = new FunctionPoller<undefined, []>(dummyVar, [], bind(pollingInterval), checkSunsetStatus); const sunsetPoller = new FunctionPoller<undefined, []>(
dummyVar,
[],
bind(pollingInterval),
checkSunsetStatus,
);
sunsetPoller.initialize('hyprsunset'); sunsetPoller.initialize('hyprsunset');
const throttledToggleSunset = throttleInput(() => toggleSunset(isActive), 1000); const throttledToggleSunset = throttleInput(() => toggleSunset(isActive), 1000);
export const Hyprsunset = (): BarBoxChild => { export const Hyprsunset = (): BarBoxChild => {
const iconBinding = Variable.derive([bind(isActive), bind(onIcon), bind(offIcon)], (active, onIcn, offIcn) => { const iconBinding = Variable.derive(
[bind(isActive), bind(onIcon), bind(offIcon)],
(active, onIcn, offIcn) => {
return active ? onIcn : offIcn; return active ? onIcn : offIcn;
}); },
);
const tooltipBinding = Variable.derive([isActive, temperature], (active, temp) => { const tooltipBinding = Variable.derive([isActive, temperature], (active, temp) => {
return `Hyprsunset ${active ? 'enabled' : 'disabled'}\nTemperature: ${temp}`; return `Hyprsunset ${active ? 'enabled' : 'disabled'}\nTemperature: ${temp}`;
}); });
const labelBinding = Variable.derive([bind(isActive), bind(onLabel), bind(offLabel)], (active, onLbl, offLbl) => { const labelBinding = Variable.derive(
[bind(isActive), bind(onLabel), bind(offLabel)],
(active, onLbl, offLbl) => {
return active ? onLbl : offLbl; return active ? onLbl : offLbl;
}); },
);
const hyprsunsetModule = Module({ const hyprsunsetModule = Module({
textIcon: iconBinding(), textIcon: iconBinding(),

View File

@@ -2,10 +2,8 @@ import {
HyprctlDeviceLayout, HyprctlDeviceLayout,
HyprctlKeyboard, HyprctlKeyboard,
KbLabelType, KbLabelType,
LayoutKeys, } from 'src/lib/types/customModules/kbLayout.types.js';
LayoutValues, import { LayoutKeys, layoutMap, LayoutValues } from './layouts';
} from 'src/lib/types/customModules/kbLayout';
import { layoutMap } from './layouts';
/** /**
* Retrieves the keyboard layout from a given JSON string and format. * Retrieves the keyboard layout from a given JSON string and format.
@@ -32,8 +30,21 @@ export const getKeyboardLayout = (layoutData: string, format: KbLabelType): Layo
mainKb = keyboards[keyboards.length - 1]; mainKb = keyboards[keyboards.length - 1];
} }
const layout: LayoutKeys = mainKb['active_keymap'] as LayoutKeys; if (!isValidLayout(mainKb.active_keymap)) {
return layoutMap['Unknown Layout'];
}
const layout: LayoutKeys = mainKb.active_keymap;
const foundLayout: LayoutValues = layoutMap[layout]; const foundLayout: LayoutValues = layoutMap[layout];
return format === 'code' ? foundLayout || layout : layout; return format === 'code' ? (foundLayout ?? layout) : layout;
}; };
function isValidLayout(kbLayout: string): kbLayout is LayoutKeys {
if (!Object.keys(layoutMap).includes(kbLayout)) {
return false;
}
return true;
}

View File

@@ -1,6 +1,5 @@
import { LayoutKeys, LayoutValues } from 'src/lib/types/customModules/kbLayout'; // Create a const object with all layouts
const layoutMapObj = {
export const layoutMap: Record<LayoutKeys, LayoutValues> = {
'Abkhazian (Russia)': 'RU (Ab)', 'Abkhazian (Russia)': 'RU (Ab)',
Akan: 'GH (Akan)', Akan: 'GH (Akan)',
Albanian: 'AL', Albanian: 'AL',
@@ -585,3 +584,8 @@ export const layoutMap: Record<LayoutKeys, LayoutValues> = {
Yoruba: 'NG (Yoruba)', Yoruba: 'NG (Yoruba)',
'Unknown Layout': 'Unknown', 'Unknown Layout': 'Unknown',
} as const; } as const;
export type LayoutKeys = keyof typeof layoutMapObj;
export type LayoutValues = (typeof layoutMapObj)[LayoutKeys];
export const layoutMap = layoutMapObj;

View File

@@ -2,11 +2,11 @@ import options from 'src/options';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { inputHandler } from 'src/components/bar/utils/helpers'; import { inputHandler } from 'src/components/bar/utils/helpers';
import { getKeyboardLayout } from './helpers'; import { getKeyboardLayout } from './helpers';
import { BarBoxChild } from 'src/lib/types/bar';
import { bind } from 'astal'; import { bind } from 'astal';
import { useHook } from 'src/lib/shared/hookHandler'; import { useHook } from 'src/lib/shared/hookHandler';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import AstalHyprland from 'gi://AstalHyprland?version=0.1'; import AstalHyprland from 'gi://AstalHyprland?version=0.1';
import { BarBoxChild } from 'src/lib/types/bar.types';
const hyprlandService = AstalHyprland.get_default(); const hyprlandService = AstalHyprland.get_default();
const { label, labelType, icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } = const { label, labelType, icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } =

View File

@@ -1,7 +1,7 @@
import { MediaTags } from 'src/lib/types/audio.js';
import { Opt } from 'src/lib/option';
import AstalMpris from 'gi://AstalMpris?version=0.1'; import AstalMpris from 'gi://AstalMpris?version=0.1';
import { Variable } from 'astal'; import { Variable } from 'astal';
import { MediaTags } from 'src/lib/types/audio.types';
import { Opt } from 'src/lib/options';
/** /**
* Retrieves the icon for a given media player. * Retrieves the icon for a given media player.
@@ -82,8 +82,8 @@ export const generateMediaLabel = (
const currentPlayer = activePlayer.get(); const currentPlayer = activePlayer.get();
if (!currentPlayer || !show_label.get()) { if (!currentPlayer || !show_label.get()) {
songIcon.set(getIconForPlayer(activePlayer.get()?.identity || '')); songIcon.set(getIconForPlayer(activePlayer.get()?.identity ?? ''));
return `Media`; return 'Media';
} }
const { title, identity, artist, album, busName } = currentPlayer; const { title, identity, artist, album, busName } = currentPlayer;
@@ -107,7 +107,7 @@ export const generateMediaLabel = (
return ''; return '';
} }
const value = p1 !== undefined ? mediaTags[p1] : ''; const value = p1 !== undefined ? mediaTags[p1] : '';
const suffix = p2?.length ? p2.slice(1) : ''; const suffix = p2 !== undefined && p2.length > 0 ? p2.slice(1) : '';
return value ? value + suffix : ''; return value ? value + suffix : '';
}, },
); );

View File

@@ -4,10 +4,10 @@ import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/util
import { generateMediaLabel } from './helpers/index.js'; import { generateMediaLabel } from './helpers/index.js';
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers.js'; import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers.js';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { BarBoxChild } from 'src/lib/types/bar.js';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { activePlayer, mediaAlbum, mediaArtist, mediaTitle } from 'src/globals/media.js'; import { activePlayer, mediaAlbum, mediaArtist, mediaTitle } from 'src/shared/media.js';
import AstalMpris from 'gi://AstalMpris?version=0.1'; import AstalMpris from 'gi://AstalMpris?version=0.1';
import { BarBoxChild } from 'src/lib/types/bar.types.js';
const mprisService = AstalMpris.get_default(); const mprisService = AstalMpris.get_default();
const { const {
@@ -49,7 +49,9 @@ const Media = (): BarBoxChild => {
}, },
); );
const componentClassName = Variable.derive([options.theme.bar.buttons.style, show_label], (style: string) => { const componentClassName = Variable.derive(
[options.theme.bar.buttons.style, show_label],
(style: string) => {
const styleMap: Record<string, string> = { const styleMap: Record<string, string> = {
default: 'style1', default: 'style1',
split: 'style2', split: 'style2',
@@ -57,7 +59,8 @@ const Media = (): BarBoxChild => {
wave2: 'style3', wave2: 'style3',
}; };
return `media-container ${styleMap[style]}`; return `media-container ${styleMap[style]}`;
}); },
);
const component = ( const component = (
<box <box
@@ -68,14 +71,17 @@ const Media = (): BarBoxChild => {
componentClassName.drop(); componentClassName.drop();
}} }}
> >
<label className={'bar-button-icon media txt-icon bar'} label={bind(songIcon).as((icn) => icn || '󰝚')} /> <label
className={'bar-button-icon media txt-icon bar'}
label={bind(songIcon).as((icn) => icn || '󰝚')}
/>
<label className={'bar-button-label media'} label={mediaLabel()} /> <label className={'bar-button-label media'} label={mediaLabel()} />
</box> </box>
); );
return { return {
component, component,
isVis, isVis: bind(isVis),
boxClass: 'media', boxClass: 'media',
props: { props: {
setup: (self: Astal.Button): void => { setup: (self: Astal.Button): void => {
@@ -113,7 +119,9 @@ const Media = (): BarBoxChild => {
}), }),
); );
disconnectFunctions.push(onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get())); disconnectFunctions.push(
onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get()),
);
}, },
); );
}, },

View File

@@ -4,14 +4,15 @@ import { openMenu } from '../../utils/menu.js';
import { getDistroIcon } from '../../../../lib/utils.js'; import { getDistroIcon } from '../../../../lib/utils.js';
import { Variable, bind } from 'astal'; import { Variable, bind } from 'astal';
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers.js'; import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers.js';
import { BarBoxChild } from 'src/lib/types/bar.js';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { BarBoxChild } from 'src/lib/types/bar.types.js';
const { rightClick, middleClick, scrollUp, scrollDown, autoDetectIcon, icon } = options.bar.launcher; const { rightClick, middleClick, scrollUp, scrollDown, autoDetectIcon, icon } = options.bar.launcher;
const Menu = (): BarBoxChild => { const Menu = (): BarBoxChild => {
const iconBinding = Variable.derive([autoDetectIcon, icon], (autoDetect: boolean, iconValue: string): string => const iconBinding = Variable.derive(
autoDetect ? getDistroIcon() : iconValue, [autoDetectIcon, icon],
(autoDetect: boolean, iconValue: string): string => (autoDetect ? getDistroIcon() : iconValue),
); );
const componentClassName = bind(options.theme.bar.buttons.style).as((style: string) => { const componentClassName = bind(options.theme.bar.buttons.style).as((style: string) => {
@@ -75,7 +76,9 @@ const Menu = (): BarBoxChild => {
}), }),
); );
disconnectFunctions.push(onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get())); disconnectFunctions.push(
onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get()),
);
}, },
); );
}, },

View File

@@ -1,10 +1,10 @@
import options from 'src/options'; import options from 'src/options';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { BarBoxChild } from 'src/lib/types/bar';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { inputHandler } from '../../utils/helpers'; import { inputHandler } from '../../utils/helpers';
import AstalWp from 'gi://AstalWp?version=0.1'; import AstalWp from 'gi://AstalWp?version=0.1';
import { BarBoxChild } from 'src/lib/types/bar.types';
const wireplumber = AstalWp.get_default() as AstalWp.Wp; const wireplumber = AstalWp.get_default() as AstalWp.Wp;
const audioService = wireplumber.audio; const audioService = wireplumber.audio;

View File

@@ -1,8 +1,8 @@
import GLib from 'gi://GLib'; import GLib from 'gi://GLib';
import { Variable } from 'astal'; import { Variable } from 'astal';
import { NetworkResourceData } from 'src/lib/types/customModules/network'; import { RateUnit } from 'src/lib/types/bar.types';
import { GET_DEFAULT_NETSTAT_DATA } from 'src/lib/types/defaults/netstat'; import { NetworkResourceData } from 'src/lib/types/customModules/network.types';
import { RateUnit } from 'src/lib/types/bar'; import { getDefaultNetstatData } from 'src/lib/types/defaults/netstat.types';
let previousNetUsage = { rx: 0, tx: 0, time: 0 }; let previousNetUsage = { rx: 0, tx: 0, time: 0 };
@@ -97,16 +97,20 @@ const isValidInterface = (iface: NetworkUsage | null, interfaceName: string): bo
*/ */
const getNetworkUsage = (interfaceName: string = ''): NetworkUsage => { const getNetworkUsage = (interfaceName: string = ''): NetworkUsage => {
const [success, data] = GLib.file_get_contents('/proc/net/dev'); const [success, data] = GLib.file_get_contents('/proc/net/dev');
const defaultStats = { name: '', rx: 0, tx: 0 };
if (!success) { if (!success) {
console.error('Failed to read /proc/net/dev'); console.error('Failed to read /proc/net/dev');
return { name: '', rx: 0, tx: 0 }; return defaultStats;
} }
const lines = new TextDecoder('utf-8').decode(data).split('\n'); const lines = new TextDecoder('utf-8').decode(data).split('\n');
for (const line of lines) { for (const line of lines) {
const iface = parseInterfaceData(line); const iface = parseInterfaceData(line);
if (isValidInterface(iface, interfaceName)) { if (isValidInterface(iface, interfaceName)) {
return iface!; return iface ?? defaultStats;
} }
} }
@@ -131,9 +135,9 @@ export const computeNetwork = (
dataType: Variable<RateUnit>, dataType: Variable<RateUnit>,
): NetworkResourceData => { ): NetworkResourceData => {
const rateUnit = dataType.get(); const rateUnit = dataType.get();
const interfaceName = interfaceNameVar ? interfaceNameVar.get() : ''; const interfaceName = interfaceNameVar.get();
const DEFAULT_NETSTAT_DATA = GET_DEFAULT_NETSTAT_DATA(rateUnit); const DEFAULT_NETSTAT_DATA = getDefaultNetstatData(rateUnit);
try { try {
const { rx, tx, name } = getNetworkUsage(interfaceName); const { rx, tx, name } = getNetworkUsage(interfaceName);
const currentTime = Date.now(); const currentTime = Date.now();

View File

@@ -2,14 +2,14 @@ import options from 'src/options';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { inputHandler } from 'src/components/bar/utils/helpers'; import { inputHandler } from 'src/components/bar/utils/helpers';
import { computeNetwork } from './helpers'; import { computeNetwork } from './helpers';
import { BarBoxChild, NetstatLabelType, RateUnit } from 'src/lib/types/bar'; import { NETWORK_LABEL_TYPES } from 'src/lib/types/defaults/bar.types';
import { NetworkResourceData } from 'src/lib/types/customModules/network';
import { NETWORK_LABEL_TYPES } from 'src/lib/types/defaults/bar';
import { GET_DEFAULT_NETSTAT_DATA } from 'src/lib/types/defaults/netstat';
import { FunctionPoller } from 'src/lib/poller/FunctionPoller'; import { FunctionPoller } from 'src/lib/poller/FunctionPoller';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import AstalNetwork from 'gi://AstalNetwork?version=0.1'; import AstalNetwork from 'gi://AstalNetwork?version=0.1';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { RateUnit, BarBoxChild, NetstatLabelType } from 'src/lib/types/bar.types';
import { NetworkResourceData } from 'src/lib/types/customModules/network.types';
import { getDefaultNetstatData } from 'src/lib/types/defaults/netstat.types';
const networkService = AstalNetwork.get_default(); const networkService = AstalNetwork.get_default();
const { const {
@@ -28,7 +28,7 @@ const {
pollingInterval, pollingInterval,
} = options.bar.customModules.netstat; } = options.bar.customModules.netstat;
export const networkUsage = Variable<NetworkResourceData>(GET_DEFAULT_NETSTAT_DATA(rateUnit.get())); export const networkUsage = Variable<NetworkResourceData>(getDefaultNetstatData(rateUnit.get()));
const netstatPoller = new FunctionPoller< const netstatPoller = new FunctionPoller<
NetworkResourceData, NetworkResourceData,
@@ -69,7 +69,8 @@ export const Netstat = (): BarBoxChild => {
const labelBinding = Variable.derive( const labelBinding = Variable.derive(
[bind(networkUsage), bind(labelType)], [bind(networkUsage), bind(labelType)],
(networkService: NetworkResourceData, lblTyp: NetstatLabelType) => renderNetworkLabel(lblTyp, networkService), (networkService: NetworkResourceData, lblTyp: NetstatLabelType) =>
renderNetworkLabel(lblTyp, networkService),
); );
const netstatModule = Module({ const netstatModule = Module({
@@ -98,7 +99,8 @@ export const Netstat = (): BarBoxChild => {
fn: () => { fn: () => {
labelType.set( labelType.set(
NETWORK_LABEL_TYPES[ NETWORK_LABEL_TYPES[
(NETWORK_LABEL_TYPES.indexOf(labelType.get()) + 1) % NETWORK_LABEL_TYPES.length (NETWORK_LABEL_TYPES.indexOf(labelType.get()) + 1) %
NETWORK_LABEL_TYPES.length
] as NetstatLabelType, ] as NetstatLabelType,
); );
}, },
@@ -107,7 +109,9 @@ export const Netstat = (): BarBoxChild => {
fn: () => { fn: () => {
labelType.set( labelType.set(
NETWORK_LABEL_TYPES[ NETWORK_LABEL_TYPES[
(NETWORK_LABEL_TYPES.indexOf(labelType.get()) - 1 + NETWORK_LABEL_TYPES.length) % (NETWORK_LABEL_TYPES.indexOf(labelType.get()) -
1 +
NETWORK_LABEL_TYPES.length) %
NETWORK_LABEL_TYPES.length NETWORK_LABEL_TYPES.length
] as NetstatLabelType, ] as NetstatLabelType,
); );

View File

@@ -19,7 +19,7 @@ const handleWiredIcon = (): void => {
wiredIconBinding?.drop(); wiredIconBinding?.drop();
wiredIconBinding = undefined; wiredIconBinding = undefined;
if (!networkService.wired) { if (networkService.wired === null) {
return; return;
} }
@@ -38,7 +38,7 @@ const handleWirelessIcon = (): void => {
wirelessIconBinding?.drop(); wirelessIconBinding?.drop();
wirelessIconBinding = undefined; wirelessIconBinding = undefined;
if (!networkService.wifi) { if (networkService.wifi === null) {
return; return;
} }

View File

@@ -5,8 +5,8 @@ import { bind, Variable } from 'astal';
import { onPrimaryClick, onSecondaryClick, onMiddleClick, onScroll } from 'src/lib/shared/eventHandlers'; import { onPrimaryClick, onSecondaryClick, onMiddleClick, onScroll } from 'src/lib/shared/eventHandlers';
import { Astal, Gtk } from 'astal/gtk3'; import { Astal, Gtk } from 'astal/gtk3';
import AstalNetwork from 'gi://AstalNetwork?version=0.1'; import AstalNetwork from 'gi://AstalNetwork?version=0.1';
import { BarBoxChild } from 'src/lib/types/bar.js';
import { formatWifiInfo, wiredIcon, wirelessIcon } from './helpers'; import { formatWifiInfo, wiredIcon, wirelessIcon } from './helpers';
import { BarBoxChild } from 'src/lib/types/bar.types';
const networkService = AstalNetwork.get_default(); const networkService = AstalNetwork.get_default();
const { label, truncation, truncation_size, rightClick, middleClick, scrollDown, scrollUp, showWifiInfo } = const { label, truncation, truncation_size, rightClick, middleClick, scrollDown, scrollUp, showWifiInfo } =
@@ -20,7 +20,9 @@ const Network = (): BarBoxChild => {
}, },
); );
const NetworkIcon = (): JSX.Element => <icon className={'bar-button-icon network-icon'} icon={iconBinding()} />; const NetworkIcon = (): JSX.Element => (
<icon className={'bar-button-icon network-icon'} icon={iconBinding()} />
);
const networkLabel = Variable.derive( const networkLabel = Variable.derive(
[ [
@@ -32,14 +34,16 @@ const Network = (): BarBoxChild => {
bind(networkService, 'state'), bind(networkService, 'state'),
bind(networkService, 'connectivity'), bind(networkService, 'connectivity'),
...(networkService.wifi ? [bind(networkService.wifi, 'enabled')] : []), ...(networkService.wifi !== null ? [bind(networkService.wifi, 'enabled')] : []),
], ],
(primaryNetwork, showLabel, trunc, tSize, showWifiInfo) => { (primaryNetwork, showLabel, trunc, tSize, showWifiInfo) => {
if (!showLabel) { if (!showLabel) {
return <box />; return <box />;
} }
if (primaryNetwork === AstalNetwork.Primary.WIRED) { if (primaryNetwork === AstalNetwork.Primary.WIRED) {
return <label className={'bar-button-label network-label'} label={'Wired'.substring(0, tSize)} />; return (
<label className={'bar-button-label network-label'} label={'Wired'.substring(0, tSize)} />
);
} }
const networkWifi = networkService.wifi; const networkWifi = networkService.wifi;
if (networkWifi != null) { if (networkWifi != null) {
@@ -54,11 +58,15 @@ const Network = (): BarBoxChild => {
<label <label
className={'bar-button-label network-label'} className={'bar-button-label network-label'}
label={ label={
networkWifi.active_access_point networkWifi.active_access_point !== null
? `${trunc ? networkWifi.ssid.substring(0, tSize) : networkWifi.ssid}` ? `${trunc ? networkWifi.ssid.substring(0, tSize) : networkWifi.ssid}`
: '--' : '--'
} }
tooltipText={showWifiInfo && networkWifi.active_access_point ? formatWifiInfo(networkWifi) : ''} tooltipText={
showWifiInfo && networkWifi.active_access_point !== null
? formatWifiInfo(networkWifi)
: ''
}
/> />
); );
} }
@@ -135,7 +143,9 @@ const Network = (): BarBoxChild => {
}), }),
); );
disconnectFunctions.push(onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get())); disconnectFunctions.push(
onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get()),
);
}, },
); );
}, },

View File

@@ -3,13 +3,14 @@ import { Astal, Gtk } from 'astal/gtk3';
import { openMenu } from '../../utils/menu'; import { openMenu } from '../../utils/menu';
import options from 'src/options'; import options from 'src/options';
import { filterNotifications } from 'src/lib/shared/notifications.js'; import { filterNotifications } from 'src/lib/shared/notifications.js';
import { BarBoxChild } from 'src/lib/types/bar.js';
import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js'; import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers.js';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers'; import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers';
import { BarBoxChild } from 'src/lib/types/bar.types';
const notifdService = AstalNotifd.get_default(); const notifdService = AstalNotifd.get_default();
const { show_total, rightClick, middleClick, scrollUp, scrollDown, hideCountWhenZero } = options.bar.notifications; const { show_total, rightClick, middleClick, scrollUp, scrollDown, hideCountWhenZero } =
options.bar.notifications;
const { ignore } = options.notifications; const { ignore } = options.notifications;
export const Notifications = (): BarBoxChild => { export const Notifications = (): BarBoxChild => {
@@ -122,7 +123,9 @@ export const Notifications = (): BarBoxChild => {
}), }),
); );
disconnectFunctions.push(onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get())); disconnectFunctions.push(
onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get()),
);
}, },
); );
}, },

View File

@@ -1,9 +1,9 @@
import options from 'src/options'; import options from 'src/options';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { inputHandler } from 'src/components/bar/utils/helpers'; import { inputHandler } from 'src/components/bar/utils/helpers';
import { BarBoxChild } from 'src/lib/types/bar';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { BarBoxChild } from 'src/lib/types/bar.types';
const { icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.power; const { icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.power;
@@ -11,7 +11,7 @@ export const Power = (): BarBoxChild => {
const powerModule = Module({ const powerModule = Module({
tooltipText: 'Power Menu', tooltipText: 'Power Menu',
textIcon: bind(icon), textIcon: bind(icon),
showLabelBinding: Variable(false), showLabelBinding: bind(Variable(false)),
boxClass: 'powermodule', boxClass: 'powermodule',
props: { props: {
setup: (self: Astal.Button) => { setup: (self: Astal.Button) => {

View File

@@ -1,6 +1,6 @@
import { divide } from 'src/components/bar/utils/helpers'; import { divide } from 'src/components/bar/utils/helpers';
import { GenericResourceData } from 'src/lib/types/customModules/generic';
import { GLib, Variable } from 'astal'; import { GLib, Variable } from 'astal';
import { GenericResourceData } from 'src/lib/types/customModules/generic.types';
/** /**
* Calculates the RAM usage. * Calculates the RAM usage.
@@ -16,7 +16,7 @@ export const calculateRamUsage = (round: Variable<boolean>): GenericResourceData
try { try {
const [success, meminfoBytes] = GLib.file_get_contents('/proc/meminfo'); const [success, meminfoBytes] = GLib.file_get_contents('/proc/meminfo');
if (!success || !meminfoBytes) { if (!success || meminfoBytes === null) {
throw new Error('Failed to read /proc/meminfo or file content is null.'); throw new Error('Failed to read /proc/meminfo or file content is null.');
} }

View File

@@ -2,12 +2,12 @@ import options from 'src/options';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { calculateRamUsage } from './helpers'; import { calculateRamUsage } from './helpers';
import { formatTooltip, inputHandler, renderResourceLabel } from 'src/components/bar/utils/helpers'; import { formatTooltip, inputHandler, renderResourceLabel } from 'src/components/bar/utils/helpers';
import { LABEL_TYPES } from 'src/lib/types/defaults/bar'; import { LABEL_TYPES } from 'src/lib/types/defaults/bar.types';
import { FunctionPoller } from 'src/lib/poller/FunctionPoller'; import { FunctionPoller } from 'src/lib/poller/FunctionPoller';
import { GenericResourceData } from 'src/lib/types/customModules/generic';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { BarBoxChild, ResourceLabelType } from 'src/lib/types/bar';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { BarBoxChild, ResourceLabelType } from 'src/lib/types/bar.types';
import { GenericResourceData } from 'src/lib/types/customModules/generic.types';
const { label, labelType, round, leftClick, rightClick, middleClick, pollingInterval, icon } = const { label, labelType, round, leftClick, rightClick, middleClick, pollingInterval, icon } =
options.bar.customModules.ram; options.bar.customModules.ram;
@@ -68,7 +68,8 @@ export const Ram = (): BarBoxChild => {
fn: () => { fn: () => {
labelType.set( labelType.set(
LABEL_TYPES[ LABEL_TYPES[
(LABEL_TYPES.indexOf(labelType.get()) - 1 + LABEL_TYPES.length) % LABEL_TYPES.length (LABEL_TYPES.indexOf(labelType.get()) - 1 + LABEL_TYPES.length) %
LABEL_TYPES.length
] as ResourceLabelType, ] as ResourceLabelType,
); );
}, },

View File

@@ -2,7 +2,7 @@ import GTop from 'gi://GTop';
import { divide } from 'src/components/bar/utils/helpers'; import { divide } from 'src/components/bar/utils/helpers';
import { Variable } from 'astal'; import { Variable } from 'astal';
import { GenericResourceData } from 'src/lib/types/customModules/generic'; import { GenericResourceData } from 'src/lib/types/customModules/generic.types';
/** /**
* Computes the storage usage for the root filesystem. * Computes the storage usage for the root filesystem.

View File

@@ -2,12 +2,12 @@ import options from 'src/options';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { formatTooltip, inputHandler, renderResourceLabel } from 'src/components/bar/utils/helpers'; import { formatTooltip, inputHandler, renderResourceLabel } from 'src/components/bar/utils/helpers';
import { computeStorage } from './helpers'; import { computeStorage } from './helpers';
import { BarBoxChild, ResourceLabelType } from 'src/lib/types/bar'; import { LABEL_TYPES } from 'src/lib/types/defaults/bar.types';
import { GenericResourceData } from 'src/lib/types/customModules/generic';
import { LABEL_TYPES } from 'src/lib/types/defaults/bar';
import { FunctionPoller } from 'src/lib/poller/FunctionPoller'; import { FunctionPoller } from 'src/lib/poller/FunctionPoller';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { BarBoxChild, ResourceLabelType } from 'src/lib/types/bar.types';
import { GenericResourceData } from 'src/lib/types/customModules/generic.types';
const { label, labelType, icon, round, leftClick, rightClick, middleClick, pollingInterval } = const { label, labelType, icon, round, leftClick, rightClick, middleClick, pollingInterval } =
options.bar.customModules.storage; options.bar.customModules.storage;
@@ -66,7 +66,8 @@ export const Storage = (): BarBoxChild => {
fn: () => { fn: () => {
labelType.set( labelType.set(
LABEL_TYPES[ LABEL_TYPES[
(LABEL_TYPES.indexOf(labelType.get()) - 1 + LABEL_TYPES.length) % LABEL_TYPES.length (LABEL_TYPES.indexOf(labelType.get()) - 1 + LABEL_TYPES.length) %
LABEL_TYPES.length
] as ResourceLabelType, ] as ResourceLabelType,
); );
}, },

View File

@@ -1,12 +1,12 @@
import options from 'src/options'; import options from 'src/options';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { inputHandler } from 'src/components/bar/utils/helpers'; import { inputHandler } from 'src/components/bar/utils/helpers';
import { BarBoxChild } from 'src/lib/types/bar';
import { capitalizeFirstLetter } from 'src/lib/utils'; import { capitalizeFirstLetter } from 'src/lib/utils';
import { getInitialSubmap, isSubmapEnabled } from './helpers'; import { getInitialSubmap, isSubmapEnabled } from './helpers';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import AstalHyprland from 'gi://AstalHyprland?version=0.1'; import AstalHyprland from 'gi://AstalHyprland?version=0.1';
import { BarBoxChild } from 'src/lib/types/bar.types';
const hyprlandService = AstalHyprland.get_default(); const hyprlandService = AstalHyprland.get_default();
const { const {

View File

@@ -2,8 +2,8 @@ import { isMiddleClick, isPrimaryClick, isSecondaryClick, Notify } from '../../.
import options from '../../../../options'; import options from '../../../../options';
import AstalTray from 'gi://AstalTray?version=0.1'; import AstalTray from 'gi://AstalTray?version=0.1';
import { bind, Gio, Variable } from 'astal'; import { bind, Gio, Variable } from 'astal';
import { BarBoxChild } from 'src/lib/types/bar';
import { Gdk, Gtk } from 'astal/gtk3'; import { Gdk, Gtk } from 'astal/gtk3';
import { BarBoxChild } from 'src/lib/types/bar.types';
const systemtray = AstalTray.get_default(); const systemtray = AstalTray.get_default();
const { ignore, customIcons } = options.bar.systray; const { ignore, customIcons } = options.bar.systray;
@@ -28,7 +28,13 @@ const MenuCustomIcon = ({ iconLabel, iconColor, item }: MenuCustomIconProps): JS
}; };
const MenuDefaultIcon = ({ item }: MenuEntryProps): JSX.Element => { const MenuDefaultIcon = ({ item }: MenuEntryProps): JSX.Element => {
return <icon className={'systray-icon'} gIcon={bind(item, 'gicon')} tooltipMarkup={bind(item, 'tooltipMarkup')} />; return (
<icon
className={'systray-icon'}
gIcon={bind(item, 'gicon')}
tooltipMarkup={bind(item, 'tooltipMarkup')}
/>
);
}; };
const MenuEntry = ({ item, child }: MenuEntryProps): JSX.Element => { const MenuEntry = ({ item, child }: MenuEntryProps): JSX.Element => {
@@ -37,10 +43,10 @@ const MenuEntry = ({ item, child }: MenuEntryProps): JSX.Element => {
const entryBinding = Variable.derive( const entryBinding = Variable.derive(
[bind(item, 'menuModel'), bind(item, 'actionGroup')], [bind(item, 'menuModel'), bind(item, 'actionGroup')],
(menuModel, actionGroup) => { (menuModel, actionGroup) => {
if (!menuModel) { if (menuModel === null) {
return console.error(`Menu Model not found for ${item.id}`); return console.error(`Menu Model not found for ${item.id}`);
} }
if (!actionGroup) { if (actionGroup === null) {
return console.error(`Action Group not found for ${item.id}`); return console.error(`Action Group not found for ${item.id}`);
} }
@@ -85,7 +91,9 @@ const SysTray = (): BarBoxChild => {
isVis.set(filteredTray.length > 0); isVis.set(filteredTray.length > 0);
return filteredTray.map((item) => { return filteredTray.map((item) => {
const matchedCustomIcon = Object.keys(custIcons).find((iconRegex) => item.id.match(iconRegex)); const matchedCustomIcon = Object.keys(custIcons).find((iconRegex) =>
item.id.match(iconRegex),
);
if (matchedCustomIcon !== undefined) { if (matchedCustomIcon !== undefined) {
const iconLabel = custIcons[matchedCustomIcon].icon || '󰠫'; const iconLabel = custIcons[matchedCustomIcon].icon || '󰠫';
@@ -122,7 +130,7 @@ const SysTray = (): BarBoxChild => {
component, component,
isVisible: true, isVisible: true,
boxClass: 'systray', boxClass: 'systray',
isVis, isVis: bind(isVis),
isBox: true, isBox: true,
props: {}, props: {},
}; };

View File

@@ -1,10 +1,10 @@
import options from 'src/options'; import options from 'src/options';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { inputHandler } from 'src/components/bar/utils/helpers'; import { inputHandler } from 'src/components/bar/utils/helpers';
import { BarBoxChild } from 'src/lib/types/bar';
import { BashPoller } from 'src/lib/poller/BashPoller'; import { BashPoller } from 'src/lib/poller/BashPoller';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { BarBoxChild } from 'src/lib/types/bar.types';
const { const {
updateCommand, updateCommand,
@@ -75,7 +75,7 @@ export const Updates = (): BarBoxChild => {
textIcon: updatesIcon(), textIcon: updatesIcon(),
tooltipText: bind(pendingUpdatesTooltip), tooltipText: bind(pendingUpdatesTooltip),
boxClass: 'updates', boxClass: 'updates',
isVis: isVis, isVis: bind(isVis),
label: bind(pendingUpdates), label: bind(pendingUpdates),
showLabelBinding: bind(label), showLabelBinding: bind(label),
props: { props: {

View File

@@ -1,6 +1,4 @@
import { VolumeIcons } from 'src/lib/types/volume'; const icons: Record<number, string> = {
const icons: VolumeIcons = {
101: '󰕾', 101: '󰕾',
66: '󰕾', 66: '󰕾',
34: '󰖀', 34: '󰖀',

View File

@@ -4,9 +4,9 @@ import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/util
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers.js'; import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers.js';
import { getIcon } from './helpers/index.js'; import { getIcon } from './helpers/index.js';
import { BarBoxChild } from 'src/lib/types/bar.js';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import AstalWp from 'gi://AstalWp?version=0.1'; import AstalWp from 'gi://AstalWp?version=0.1';
import { BarBoxChild } from 'src/lib/types/bar.types.js';
const wireplumber = AstalWp.get_default() as AstalWp.Wp; const wireplumber = AstalWp.get_default() as AstalWp.Wp;
const audioService = wireplumber?.audio; const audioService = wireplumber?.audio;
@@ -118,7 +118,9 @@ const Volume = (): BarBoxChild => {
}), }),
); );
disconnectFunctions.push(onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get())); disconnectFunctions.push(
onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get()),
);
}, },
); );
}, },

View File

@@ -1,12 +1,13 @@
import options from 'src/options'; import options from 'src/options';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { inputHandler } from 'src/components/bar/utils/helpers'; import { inputHandler } from 'src/components/bar/utils/helpers';
import { getWeatherStatusTextIcon, globalWeatherVar } from 'src/globals/weather'; import { getWeatherStatusTextIcon, globalWeatherVar } from 'src/shared/weather';
import { BarBoxChild } from 'src/lib/types/bar';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { BarBoxChild } from 'src/lib/types/bar.types';
const { label, unit, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.weather; const { label, unit, leftClick, rightClick, middleClick, scrollUp, scrollDown } =
options.bar.customModules.weather;
export const Weather = (): BarBoxChild => { export const Weather = (): BarBoxChild => {
const iconBinding = Variable.derive([bind(globalWeatherVar)], (wthr) => { const iconBinding = Variable.derive([bind(globalWeatherVar)], (wthr) => {

View File

@@ -15,7 +15,7 @@ function trackClientUpdates(client: AstalHyprland.Client): void {
clientBinding?.drop(); clientBinding?.drop();
clientBinding = undefined; clientBinding = undefined;
if (!client) { if (client === null) {
return; return;
} }
@@ -68,7 +68,11 @@ export const getWindowMatch = (hyprlandClient: AstalHyprland.Client): Record<str
* *
* @returns The title of the window as a string. * @returns The title of the window as a string.
*/ */
export const getTitle = (client: AstalHyprland.Client, useCustomTitle: boolean, useClassName: boolean): string => { export const getTitle = (
client: AstalHyprland.Client,
useCustomTitle: boolean,
useClassName: boolean,
): string => {
if (client === null || useCustomTitle) return getWindowMatch(client).label; if (client === null || useCustomTitle) return getWindowMatch(client).label;
const title = client.title; const title = client.title;

View File

@@ -1,11 +1,11 @@
import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers'; import { runAsyncCommand, throttledScrollHandler } from 'src/components/bar/utils/helpers';
import { BarBoxChild } from 'src/lib/types/bar';
import options from 'src/options'; import options from 'src/options';
import AstalHyprland from 'gi://AstalHyprland?version=0.1'; import AstalHyprland from 'gi://AstalHyprland?version=0.1';
import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers'; import { onMiddleClick, onPrimaryClick, onScroll, onSecondaryClick } from 'src/lib/shared/eventHandlers';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { clientTitle, getTitle, getWindowMatch, truncateTitle } from './helpers/title'; import { clientTitle, getTitle, getWindowMatch, truncateTitle } from './helpers/title';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { BarBoxChild } from 'src/lib/types/bar.types';
const hyprlandService = AstalHyprland.get_default(); const hyprlandService = AstalHyprland.get_default();
const { leftClick, rightClick, middleClick, scrollDown, scrollUp } = options.bar.windowtitle; const { leftClick, rightClick, middleClick, scrollDown, scrollUp } = options.bar.windowtitle;
@@ -14,7 +14,12 @@ const ClientTitle = (): BarBoxChild => {
const { custom_title, class_name, label, icon, truncation, truncation_size } = options.bar.windowtitle; const { custom_title, class_name, label, icon, truncation, truncation_size } = options.bar.windowtitle;
const ClientIcon = ({ client }: ClientIconProps): JSX.Element => { const ClientIcon = ({ client }: ClientIconProps): JSX.Element => {
return <label className={'bar-button-icon windowtitle txt-icon bar'} label={getWindowMatch(client).icon} />; return (
<label
className={'bar-button-icon windowtitle txt-icon bar'}
label={getWindowMatch(client).icon}
/>
);
}; };
const ClientLabel = ({ const ClientLabel = ({
@@ -28,7 +33,10 @@ const ClientTitle = (): BarBoxChild => {
return ( return (
<label <label
className={`bar-button-label windowtitle ${showIcon ? '' : 'no-icon'}`} className={`bar-button-label windowtitle ${showIcon ? '' : 'no-icon'}`}
label={truncateTitle(getTitle(client, useCustomTitle, useClassName), truncate ? truncationSize : -1)} label={truncateTitle(
getTitle(client, useCustomTitle, useClassName),
truncate ? truncationSize : -1,
)}
/> />
); );
}; };
@@ -131,7 +139,9 @@ const ClientTitle = (): BarBoxChild => {
}), }),
); );
disconnectFunctions.push(onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get())); disconnectFunctions.push(
onScroll(self, throttledHandler, scrollUp.get(), scrollDown.get()),
);
}, },
); );
}, },

View File

@@ -1,6 +1,6 @@
import { Variable } from 'astal'; import { Variable } from 'astal';
import AstalHyprland from 'gi://AstalHyprland?version=0.1'; import AstalHyprland from 'gi://AstalHyprland?version=0.1';
import { MonitorMap, WorkspaceMonitorMap, WorkspaceRule } from 'src/lib/types/workspace'; import { MonitorMap, WorkspaceMonitorMap, WorkspaceRule } from 'src/lib/types/workspace.types';
import { range } from 'src/lib/utils'; import { range } from 'src/lib/utils';
import options from 'src/options'; import options from 'src/options';
@@ -172,7 +172,7 @@ function isWorkspaceIgnored(ignoredWorkspacesVariable: Variable<string>, workspa
* @param ignoredWorkspacesVariable - A Variable that contains the ignored workspaces pattern. * @param ignoredWorkspacesVariable - A Variable that contains the ignored workspaces pattern.
*/ */
function navigateWorkspace(direction: 'next' | 'prev', ignoredWorkspacesVariable: Variable<string>): void { function navigateWorkspace(direction: 'next' | 'prev', ignoredWorkspacesVariable: Variable<string>): void {
const allHyprlandWorkspaces = hyprlandService.get_workspaces() || []; const allHyprlandWorkspaces = hyprlandService.get_workspaces() ?? [];
const activeWorkspaceIds = allHyprlandWorkspaces const activeWorkspaceIds = allHyprlandWorkspaces
.filter((workspaceInstance) => hyprlandService.focusedMonitor.id === workspaceInstance.monitor?.id) .filter((workspaceInstance) => hyprlandService.focusedMonitor.id === workspaceInstance.monitor?.id)
@@ -187,7 +187,8 @@ function navigateWorkspace(direction: 'next' | 'prev', ignoredWorkspacesVariable
const workspaceIndex = assignedOrOccupiedWorkspaces.indexOf(hyprlandService.focusedWorkspace?.id); const workspaceIndex = assignedOrOccupiedWorkspaces.indexOf(hyprlandService.focusedWorkspace?.id);
const step = direction === 'next' ? 1 : -1; const step = direction === 'next' ? 1 : -1;
let newIndex = (workspaceIndex + step + assignedOrOccupiedWorkspaces.length) % assignedOrOccupiedWorkspaces.length; let newIndex =
(workspaceIndex + step + assignedOrOccupiedWorkspaces.length) % assignedOrOccupiedWorkspaces.length;
let attempts = 0; let attempts = 0;
while (attempts < assignedOrOccupiedWorkspaces.length) { while (attempts < assignedOrOccupiedWorkspaces.length) {
@@ -196,7 +197,8 @@ function navigateWorkspace(direction: 'next' | 'prev', ignoredWorkspacesVariable
hyprlandService.dispatch('workspace', targetWorkspaceNumber.toString()); hyprlandService.dispatch('workspace', targetWorkspaceNumber.toString());
return; return;
} }
newIndex = (newIndex + step + assignedOrOccupiedWorkspaces.length) % assignedOrOccupiedWorkspaces.length; newIndex =
(newIndex + step + assignedOrOccupiedWorkspaces.length) % assignedOrOccupiedWorkspaces.length;
attempts++; attempts++;
} }
} }
@@ -321,7 +323,9 @@ export function getWorkspacesToRender(
); );
const activeWorkspacesForCurrentMonitor = activeWorkspaceIds.filter((workspaceId) => { const activeWorkspacesForCurrentMonitor = activeWorkspaceIds.filter((workspaceId) => {
const metadataForWorkspace = allWorkspaceInstances.find((workspaceObj) => workspaceObj.id === workspaceId); const metadataForWorkspace = allWorkspaceInstances.find(
(workspaceObj) => workspaceObj.id === workspaceId,
);
if (metadataForWorkspace) { if (metadataForWorkspace) {
return metadataForWorkspace?.monitor?.id === monitorId; return metadataForWorkspace?.monitor?.id === monitorId;
@@ -334,6 +338,8 @@ export function getWorkspacesToRender(
) { ) {
return workspaceMonitorRules[currentMonitorInstance.name].includes(workspaceId); return workspaceMonitorRules[currentMonitorInstance.name].includes(workspaceId);
} }
return false;
}); });
if (isMonitorSpecific) { if (isMonitorSpecific) {
@@ -347,12 +353,16 @@ export function getWorkspacesToRender(
); );
}); });
allPotentialWorkspaces = [...new Set([...activeWorkspacesForCurrentMonitor, ...validWorkspaceNumbers])]; allPotentialWorkspaces = [
...new Set([...activeWorkspacesForCurrentMonitor, ...validWorkspaceNumbers]),
];
} else { } else {
allPotentialWorkspaces = [...new Set([...allPotentialWorkspaces, ...activeWorkspaceIds])]; allPotentialWorkspaces = [...new Set([...allPotentialWorkspaces, ...activeWorkspaceIds])];
} }
return allPotentialWorkspaces.filter((workspace) => !isWorkspaceIgnored(ignored, workspace)).sort((a, b) => a - b); return allPotentialWorkspaces
.filter((workspace) => !isWorkspaceIgnored(ignored, workspace))
.sort((a, b) => a - b);
} }
/** /**

View File

@@ -1,6 +1,6 @@
import AstalHyprland from 'gi://AstalHyprland?version=0.1'; import AstalHyprland from 'gi://AstalHyprland?version=0.1';
import { defaultApplicationIconMap } from 'src/lib/constants/appIcons'; import { defaultApplicationIconMap } from 'src/lib/constants/appIcons';
import { AppIconOptions, WorkspaceIconMap } from 'src/lib/types/workspace'; import { WorkspaceIconMap, AppIconOptions } from 'src/lib/types/workspace.types';
import { isValidGjsColor } from 'src/lib/utils'; import { isValidGjsColor } from 'src/lib/utils';
import options from 'src/options'; import options from 'src/options';
@@ -40,7 +40,7 @@ const getWsIcon = (wsIconMap: WorkspaceIconMap, i: number): string => {
const iconEntry = wsIconMap[i]; const iconEntry = wsIconMap[i];
const defaultIcon = `${i}`; const defaultIcon = `${i}`;
if (!iconEntry) { if (iconEntry === undefined) {
return defaultIcon; return defaultIcon;
} }
@@ -77,8 +77,10 @@ export const getWsColor = (
monitor: number, monitor: number,
): string => { ): string => {
const iconEntry = wsIconMap[i]; const iconEntry = wsIconMap[i];
const hasColor = typeof iconEntry === 'object' && 'color' in iconEntry && isValidGjsColor(iconEntry.color); const hasColor =
if (!iconEntry) { typeof iconEntry === 'object' && 'color' in iconEntry && isValidGjsColor(iconEntry.color);
if (iconEntry === undefined) {
return ''; return '';
} }
@@ -150,7 +152,7 @@ export const getAppIcon = (
let icons = workspaceClients.reduce((iconAccumulator, [clientClass, clientTitle]) => { let icons = workspaceClients.reduce((iconAccumulator, [clientClass, clientTitle]) => {
const icon = findIconForClient(clientClass, clientTitle); const icon = findIconForClient(clientClass, clientTitle);
if (icon) { if (icon !== undefined) {
iconAccumulator.push(icon); iconAccumulator.push(icon);
} }
@@ -193,7 +195,8 @@ export const renderClassnames = (
monitor: number, monitor: number,
i: number, i: number,
): string => { ): string => {
const isWorkspaceActive = hyprlandService.focusedWorkspace?.id === i || isWorkspaceActiveOnMonitor(monitor, i); const isWorkspaceActive =
hyprlandService.focusedWorkspace?.id === i || isWorkspaceActiveOnMonitor(monitor, i);
const isActive = isWorkspaceActive ? 'active' : ''; const isActive = isWorkspaceActive ? 'active' : '';
if (showIcons) { if (showIcons) {

View File

@@ -1,11 +1,11 @@
import options from 'src/options'; import options from 'src/options';
import { initThrottledScrollHandlers } from './helpers'; import { initThrottledScrollHandlers } from './helpers';
import { BarBoxChild } from 'src/lib/types/bar';
import { WorkspaceModule } from './workspaces'; import { WorkspaceModule } from './workspaces';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { GtkWidget } from 'src/lib/types/widget';
import { Astal, Gdk } from 'astal/gtk3'; import { Astal, Gdk } from 'astal/gtk3';
import { isScrollDown, isScrollUp } from 'src/lib/utils'; import { isScrollDown, isScrollUp } from 'src/lib/utils';
import { BarBoxChild } from 'src/lib/types/bar.types';
import { GtkWidget } from 'src/lib/types/widget.types';
const { scroll_speed } = options.bar.workspaces; const { scroll_speed } = options.bar.workspaces;
@@ -29,7 +29,8 @@ const Workspaces = (monitor = -1): BarBoxChild => {
self.disconnect(scrollHandlers); self.disconnect(scrollHandlers);
} }
const { throttledScrollUp, throttledScrollDown } = initThrottledScrollHandlers(scroll_speed); const { throttledScrollUp, throttledScrollDown } =
initThrottledScrollHandlers(scroll_speed);
scrollHandlers = self.connect('scroll-event', (_: GtkWidget, event: Gdk.Event) => { scrollHandlers = self.connect('scroll-event', (_: GtkWidget, event: Gdk.Event) => {
if (isScrollUp(event)) { if (isScrollUp(event)) {

View File

@@ -1,11 +1,11 @@
import options from 'src/options'; import options from 'src/options';
import { forceUpdater, getWorkspacesToRender, initWorkspaceEvents, workspaceRules } from './helpers'; import { forceUpdater, getWorkspacesToRender, initWorkspaceEvents, workspaceRules } from './helpers';
import { getAppIcon, getWsColor, renderClassnames, renderLabel } from './helpers/utils'; import { getAppIcon, getWsColor, renderClassnames, renderLabel } from './helpers/utils';
import { ApplicationIcons, WorkspaceIconMap } from 'src/lib/types/workspace';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import AstalHyprland from 'gi://AstalHyprland?version=0.1'; import AstalHyprland from 'gi://AstalHyprland?version=0.1';
import { Gtk } from 'astal/gtk3'; import { Gtk } from 'astal/gtk3';
import { isPrimaryClick } from 'src/lib/utils'; import { isPrimaryClick } from 'src/lib/utils';
import { WorkspaceIconMap, ApplicationIcons } from 'src/lib/types/workspace.types';
const hyprlandService = AstalHyprland.get_default(); const hyprlandService = AstalHyprland.get_default();
const { const {
@@ -145,7 +145,9 @@ export const WorkspaceModule = ({ monitor }: WorkspaceModuleProps): JSX.Element
monitor, monitor,
)} )}
setup={(self) => { setup={(self) => {
const currentWsClients = clients.filter((client) => client?.workspace?.id === wsId); const currentWsClients = clients.filter(
(client) => client?.workspace?.id === wsId,
);
self.toggleClassName('occupied', currentWsClients.length > 0); self.toggleClassName('occupied', currentWsClients.length > 0);
}} }}
/> />

View File

@@ -1,11 +1,11 @@
import options from 'src/options'; import options from 'src/options';
import { BarBoxChild } from 'src/lib/types/bar.js';
import { inputHandler } from 'src/components/bar/utils/helpers.js'; import { inputHandler } from 'src/components/bar/utils/helpers.js';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { Astal } from 'astal/gtk3'; import { Astal } from 'astal/gtk3';
import { systemTime } from 'src/globals/time'; import { systemTime } from 'src/shared/time';
import { GLib } from 'astal'; import { GLib } from 'astal';
import { Module } from '../../shared/Module'; import { Module } from '../../shared/Module';
import { BarBoxChild } from 'src/lib/types/bar.types';
const { const {
format, format,

View File

@@ -24,18 +24,50 @@ export const CustomModuleSettings = (): JSX.Element => {
type="boolean" type="boolean"
/> />
<Option opt={options.bar.customModules.microphone.label} title="Show Label" type="boolean" /> <Option opt={options.bar.customModules.microphone.label} title="Show Label" type="boolean" />
<Option opt={options.bar.customModules.microphone.mutedIcon} title="Muted Icon" type="string" /> <Option
<Option opt={options.bar.customModules.microphone.unmutedIcon} title="Unmuted Icon" type="string" /> opt={options.bar.customModules.microphone.mutedIcon}
<Option opt={options.theme.bar.buttons.modules.microphone.spacing} title="Spacing" type="string" /> title="Muted Icon"
<Option opt={options.bar.customModules.microphone.leftClick} title="Left Click" type="string" /> type="string"
<Option opt={options.bar.customModules.microphone.rightClick} title="Right Click" type="string" /> />
<Option opt={options.bar.customModules.microphone.middleClick} title="Middle Click" type="string" /> <Option
opt={options.bar.customModules.microphone.unmutedIcon}
title="Unmuted Icon"
type="string"
/>
<Option
opt={options.theme.bar.buttons.modules.microphone.spacing}
title="Spacing"
type="string"
/>
<Option
opt={options.bar.customModules.microphone.leftClick}
title="Left Click"
type="string"
/>
<Option
opt={options.bar.customModules.microphone.rightClick}
title="Right Click"
type="string"
/>
<Option
opt={options.bar.customModules.microphone.middleClick}
title="Middle Click"
type="string"
/>
<Option opt={options.bar.customModules.microphone.scrollUp} title="Scroll Up" type="string" /> <Option opt={options.bar.customModules.microphone.scrollUp} title="Scroll Up" type="string" />
<Option opt={options.bar.customModules.microphone.scrollDown} title="Scroll Down" type="string" /> <Option
opt={options.bar.customModules.microphone.scrollDown}
title="Scroll Down"
type="string"
/>
{/* RAM Section */} {/* RAM Section */}
<Header title="RAM" /> <Header title="RAM" />
<Option opt={options.theme.bar.buttons.modules.ram.enableBorder} title="Button Border" type="boolean" /> <Option
opt={options.theme.bar.buttons.modules.ram.enableBorder}
title="Button Border"
type="boolean"
/>
<Option opt={options.bar.customModules.ram.icon} title="Ram Icon" type="string" /> <Option opt={options.bar.customModules.ram.icon} title="Ram Icon" type="string" />
<Option opt={options.bar.customModules.ram.label} title="Show Label" type="boolean" /> <Option opt={options.bar.customModules.ram.label} title="Show Label" type="boolean" />
<Option opt={options.theme.bar.buttons.modules.ram.spacing} title="Spacing" type="string" /> <Option opt={options.theme.bar.buttons.modules.ram.spacing} title="Spacing" type="string" />
@@ -60,7 +92,11 @@ export const CustomModuleSettings = (): JSX.Element => {
{/* CPU Section */} {/* CPU Section */}
<Header title="CPU" /> <Header title="CPU" />
<Option opt={options.theme.bar.buttons.modules.cpu.enableBorder} title="Button Border" type="boolean" /> <Option
opt={options.theme.bar.buttons.modules.cpu.enableBorder}
title="Button Border"
type="boolean"
/>
<Option opt={options.bar.customModules.cpu.icon} title="Cpu Icon" type="string" /> <Option opt={options.bar.customModules.cpu.icon} title="Cpu Icon" type="string" />
<Option opt={options.bar.customModules.cpu.label} title="Show Label" type="boolean" /> <Option opt={options.bar.customModules.cpu.label} title="Show Label" type="boolean" />
<Option opt={options.theme.bar.buttons.modules.cpu.spacing} title="Spacing" type="string" /> <Option opt={options.theme.bar.buttons.modules.cpu.spacing} title="Spacing" type="string" />
@@ -100,9 +136,17 @@ export const CustomModuleSettings = (): JSX.Element => {
enums={['imperial', 'metric']} enums={['imperial', 'metric']}
/> />
<Option opt={options.bar.customModules.cpuTemp.showUnit} title="Show Unit" type="boolean" /> <Option opt={options.bar.customModules.cpuTemp.showUnit} title="Show Unit" type="boolean" />
<Option opt={options.bar.customModules.cpuTemp.icon} title="Cpu Temperature Icon" type="string" /> <Option
opt={options.bar.customModules.cpuTemp.icon}
title="Cpu Temperature Icon"
type="string"
/>
<Option opt={options.bar.customModules.cpuTemp.label} title="Show Label" type="boolean" /> <Option opt={options.bar.customModules.cpuTemp.label} title="Show Label" type="boolean" />
<Option opt={options.theme.bar.buttons.modules.cpuTemp.spacing} title="Spacing" type="string" /> <Option
opt={options.theme.bar.buttons.modules.cpuTemp.spacing}
title="Spacing"
type="string"
/>
<Option opt={options.bar.customModules.cpuTemp.round} title="Round" type="boolean" /> <Option opt={options.bar.customModules.cpuTemp.round} title="Round" type="boolean" />
<Option <Option
opt={options.bar.customModules.cpuTemp.pollingInterval} opt={options.bar.customModules.cpuTemp.pollingInterval}
@@ -113,10 +157,22 @@ export const CustomModuleSettings = (): JSX.Element => {
increment={1000} increment={1000}
/> />
<Option opt={options.bar.customModules.cpuTemp.leftClick} title="Left Click" type="string" /> <Option opt={options.bar.customModules.cpuTemp.leftClick} title="Left Click" type="string" />
<Option opt={options.bar.customModules.cpuTemp.rightClick} title="Right Click" type="string" /> <Option
<Option opt={options.bar.customModules.cpuTemp.middleClick} title="Middle Click" type="string" /> opt={options.bar.customModules.cpuTemp.rightClick}
title="Right Click"
type="string"
/>
<Option
opt={options.bar.customModules.cpuTemp.middleClick}
title="Middle Click"
type="string"
/>
<Option opt={options.bar.customModules.cpuTemp.scrollUp} title="Scroll Up" type="string" /> <Option opt={options.bar.customModules.cpuTemp.scrollUp} title="Scroll Up" type="string" />
<Option opt={options.bar.customModules.cpuTemp.scrollDown} title="Scroll Down" type="string" /> <Option
opt={options.bar.customModules.cpuTemp.scrollDown}
title="Scroll Down"
type="string"
/>
{/* Storage Section */} {/* Storage Section */}
<Header title="Storage" /> <Header title="Storage" />
@@ -127,7 +183,11 @@ export const CustomModuleSettings = (): JSX.Element => {
/> />
<Option opt={options.bar.customModules.storage.icon} title="Storage Icon" type="string" /> <Option opt={options.bar.customModules.storage.icon} title="Storage Icon" type="string" />
<Option opt={options.bar.customModules.storage.label} title="Show Label" type="boolean" /> <Option opt={options.bar.customModules.storage.label} title="Show Label" type="boolean" />
<Option opt={options.theme.bar.buttons.modules.storage.spacing} title="Spacing" type="string" /> <Option
opt={options.theme.bar.buttons.modules.storage.spacing}
title="Spacing"
type="string"
/>
<Option <Option
opt={options.bar.customModules.storage.labelType} opt={options.bar.customModules.storage.labelType}
title="Label Type" title="Label Type"
@@ -144,8 +204,16 @@ export const CustomModuleSettings = (): JSX.Element => {
increment={1000} increment={1000}
/> />
<Option opt={options.bar.customModules.storage.leftClick} title="Left Click" type="string" /> <Option opt={options.bar.customModules.storage.leftClick} title="Left Click" type="string" />
<Option opt={options.bar.customModules.storage.rightClick} title="Right Click" type="string" /> <Option
<Option opt={options.bar.customModules.storage.middleClick} title="Middle Click" type="string" /> opt={options.bar.customModules.storage.rightClick}
title="Right Click"
type="string"
/>
<Option
opt={options.bar.customModules.storage.middleClick}
title="Middle Click"
type="string"
/>
{/* Netstat Section */} {/* Netstat Section */}
<Header title="Netstat" /> <Header title="Netstat" />
@@ -171,7 +239,11 @@ export const CustomModuleSettings = (): JSX.Element => {
/> />
<Option opt={options.bar.customModules.netstat.icon} title="Netstat Icon" type="string" /> <Option opt={options.bar.customModules.netstat.icon} title="Netstat Icon" type="string" />
<Option opt={options.bar.customModules.netstat.label} title="Show Label" type="boolean" /> <Option opt={options.bar.customModules.netstat.label} title="Show Label" type="boolean" />
<Option opt={options.bar.customModules.netstat.networkInLabel} title="Network In Label" type="string" /> <Option
opt={options.bar.customModules.netstat.networkInLabel}
title="Network In Label"
type="string"
/>
<Option <Option
opt={options.bar.customModules.netstat.networkOutLabel} opt={options.bar.customModules.netstat.networkOutLabel}
title="Network Out Label" title="Network Out Label"
@@ -183,7 +255,11 @@ export const CustomModuleSettings = (): JSX.Element => {
type="enum" type="enum"
enums={['GiB', 'MiB', 'KiB', 'auto']} enums={['GiB', 'MiB', 'KiB', 'auto']}
/> />
<Option opt={options.theme.bar.buttons.modules.netstat.spacing} title="Spacing" type="string" /> <Option
opt={options.theme.bar.buttons.modules.netstat.spacing}
title="Spacing"
type="string"
/>
<Option <Option
opt={options.bar.customModules.netstat.labelType} opt={options.bar.customModules.netstat.labelType}
title="Label Type" title="Label Type"
@@ -200,8 +276,16 @@ export const CustomModuleSettings = (): JSX.Element => {
increment={1000} increment={1000}
/> />
<Option opt={options.bar.customModules.netstat.leftClick} title="Left Click" type="string" /> <Option opt={options.bar.customModules.netstat.leftClick} title="Left Click" type="string" />
<Option opt={options.bar.customModules.netstat.rightClick} title="Right Click" type="string" /> <Option
<Option opt={options.bar.customModules.netstat.middleClick} title="Middle Click" type="string" /> opt={options.bar.customModules.netstat.rightClick}
title="Right Click"
type="string"
/>
<Option
opt={options.bar.customModules.netstat.middleClick}
title="Middle Click"
type="string"
/>
{/* Keyboard Layout Section */} {/* Keyboard Layout Section */}
<Header title="Keyboard Layout" /> <Header title="Keyboard Layout" />
@@ -210,7 +294,11 @@ export const CustomModuleSettings = (): JSX.Element => {
title="Button Border" title="Button Border"
type="boolean" type="boolean"
/> />
<Option opt={options.bar.customModules.kbLayout.icon} title="Keyboard Layout Icon" type="string" /> <Option
opt={options.bar.customModules.kbLayout.icon}
title="Keyboard Layout Icon"
type="string"
/>
<Option opt={options.bar.customModules.kbLayout.label} title="Show Label" type="boolean" /> <Option opt={options.bar.customModules.kbLayout.label} title="Show Label" type="boolean" />
<Option <Option
opt={options.bar.customModules.kbLayout.labelType} opt={options.bar.customModules.kbLayout.labelType}
@@ -218,12 +306,28 @@ export const CustomModuleSettings = (): JSX.Element => {
type="enum" type="enum"
enums={['layout', 'code']} enums={['layout', 'code']}
/> />
<Option opt={options.theme.bar.buttons.modules.kbLayout.spacing} title="Spacing" type="string" /> <Option
opt={options.theme.bar.buttons.modules.kbLayout.spacing}
title="Spacing"
type="string"
/>
<Option opt={options.bar.customModules.kbLayout.leftClick} title="Left Click" type="string" /> <Option opt={options.bar.customModules.kbLayout.leftClick} title="Left Click" type="string" />
<Option opt={options.bar.customModules.kbLayout.rightClick} title="Right Click" type="string" /> <Option
<Option opt={options.bar.customModules.kbLayout.middleClick} title="Middle Click" type="string" /> opt={options.bar.customModules.kbLayout.rightClick}
title="Right Click"
type="string"
/>
<Option
opt={options.bar.customModules.kbLayout.middleClick}
title="Middle Click"
type="string"
/>
<Option opt={options.bar.customModules.kbLayout.scrollUp} title="Scroll Up" type="string" /> <Option opt={options.bar.customModules.kbLayout.scrollUp} title="Scroll Up" type="string" />
<Option opt={options.bar.customModules.kbLayout.scrollDown} title="Scroll Down" type="string" /> <Option
opt={options.bar.customModules.kbLayout.scrollDown}
title="Scroll Down"
type="string"
/>
{/* Updates Section */} {/* Updates Section */}
<Header title="Updates" /> <Header title="Updates" />
@@ -253,7 +357,11 @@ export const CustomModuleSettings = (): JSX.Element => {
title="Updates Available Icon" title="Updates Available Icon"
type="string" type="string"
/> />
<Option opt={options.bar.customModules.updates.icon.updated} title="No Updates Icon" type="string" /> <Option
opt={options.bar.customModules.updates.icon.updated}
title="No Updates Icon"
type="string"
/>
<Option opt={options.bar.customModules.updates.label} title="Show Label" type="boolean" /> <Option opt={options.bar.customModules.updates.label} title="Show Label" type="boolean" />
<Option <Option
opt={options.bar.customModules.updates.autoHide} opt={options.bar.customModules.updates.autoHide}
@@ -262,7 +370,11 @@ export const CustomModuleSettings = (): JSX.Element => {
type="boolean" type="boolean"
/> />
<Option opt={options.bar.customModules.updates.padZero} title="Pad with 0" type="boolean" /> <Option opt={options.bar.customModules.updates.padZero} title="Pad with 0" type="boolean" />
<Option opt={options.theme.bar.buttons.modules.updates.spacing} title="Spacing" type="string" /> <Option
opt={options.theme.bar.buttons.modules.updates.spacing}
title="Spacing"
type="string"
/>
<Option <Option
opt={options.bar.customModules.updates.pollingInterval} opt={options.bar.customModules.updates.pollingInterval}
title="Polling Interval" title="Polling Interval"
@@ -273,10 +385,22 @@ export const CustomModuleSettings = (): JSX.Element => {
increment={1000} increment={1000}
/> />
<Option opt={options.bar.customModules.updates.leftClick} title="Left Click" type="string" /> <Option opt={options.bar.customModules.updates.leftClick} title="Left Click" type="string" />
<Option opt={options.bar.customModules.updates.rightClick} title="Right Click" type="string" /> <Option
<Option opt={options.bar.customModules.updates.middleClick} title="Middle Click" type="string" /> opt={options.bar.customModules.updates.rightClick}
title="Right Click"
type="string"
/>
<Option
opt={options.bar.customModules.updates.middleClick}
title="Middle Click"
type="string"
/>
<Option opt={options.bar.customModules.updates.scrollUp} title="Scroll Up" type="string" /> <Option opt={options.bar.customModules.updates.scrollUp} title="Scroll Up" type="string" />
<Option opt={options.bar.customModules.updates.scrollDown} title="Scroll Down" type="string" /> <Option
opt={options.bar.customModules.updates.scrollDown}
title="Scroll Down"
type="string"
/>
{/* Submap Section */} {/* Submap Section */}
<Header title="Submap" /> <Header title="Submap" />
@@ -291,15 +415,39 @@ export const CustomModuleSettings = (): JSX.Element => {
subtitle="Displays current submap name instead of Enabled/Disabled text." subtitle="Displays current submap name instead of Enabled/Disabled text."
type="boolean" type="boolean"
/> />
<Option opt={options.bar.customModules.submap.enabledIcon} title="Enabled Icon" type="string" /> <Option
<Option opt={options.bar.customModules.submap.disabledIcon} title="Disabled Icon" type="string" /> opt={options.bar.customModules.submap.enabledIcon}
<Option opt={options.bar.customModules.submap.enabledText} title="Enabled Text" type="string" /> title="Enabled Icon"
<Option opt={options.bar.customModules.submap.disabledText} title="Disabled Text" type="string" /> type="string"
/>
<Option
opt={options.bar.customModules.submap.disabledIcon}
title="Disabled Icon"
type="string"
/>
<Option
opt={options.bar.customModules.submap.enabledText}
title="Enabled Text"
type="string"
/>
<Option
opt={options.bar.customModules.submap.disabledText}
title="Disabled Text"
type="string"
/>
<Option opt={options.bar.customModules.submap.label} title="Show Label" type="boolean" /> <Option opt={options.bar.customModules.submap.label} title="Show Label" type="boolean" />
<Option opt={options.theme.bar.buttons.modules.submap.spacing} title="Spacing" type="string" /> <Option
opt={options.theme.bar.buttons.modules.submap.spacing}
title="Spacing"
type="string"
/>
<Option opt={options.bar.customModules.submap.leftClick} title="Left Click" type="string" /> <Option opt={options.bar.customModules.submap.leftClick} title="Left Click" type="string" />
<Option opt={options.bar.customModules.submap.rightClick} title="Right Click" type="string" /> <Option opt={options.bar.customModules.submap.rightClick} title="Right Click" type="string" />
<Option opt={options.bar.customModules.submap.middleClick} title="Middle Click" type="string" /> <Option
opt={options.bar.customModules.submap.middleClick}
title="Middle Click"
type="string"
/>
<Option opt={options.bar.customModules.submap.scrollUp} title="Scroll Up" type="string" /> <Option opt={options.bar.customModules.submap.scrollUp} title="Scroll Up" type="string" />
<Option opt={options.bar.customModules.submap.scrollDown} title="Scroll Down" type="string" /> <Option opt={options.bar.customModules.submap.scrollDown} title="Scroll Down" type="string" />
@@ -317,12 +465,28 @@ export const CustomModuleSettings = (): JSX.Element => {
type="enum" type="enum"
enums={['imperial', 'metric']} enums={['imperial', 'metric']}
/> />
<Option opt={options.theme.bar.buttons.modules.weather.spacing} title="Spacing" type="string" /> <Option
opt={options.theme.bar.buttons.modules.weather.spacing}
title="Spacing"
type="string"
/>
<Option opt={options.bar.customModules.weather.leftClick} title="Left Click" type="string" /> <Option opt={options.bar.customModules.weather.leftClick} title="Left Click" type="string" />
<Option opt={options.bar.customModules.weather.rightClick} title="Right Click" type="string" /> <Option
<Option opt={options.bar.customModules.weather.middleClick} title="Middle Click" type="string" /> opt={options.bar.customModules.weather.rightClick}
title="Right Click"
type="string"
/>
<Option
opt={options.bar.customModules.weather.middleClick}
title="Middle Click"
type="string"
/>
<Option opt={options.bar.customModules.weather.scrollUp} title="Scroll Up" type="string" /> <Option opt={options.bar.customModules.weather.scrollUp} title="Scroll Up" type="string" />
<Option opt={options.bar.customModules.weather.scrollDown} title="Scroll Down" type="string" /> <Option
opt={options.bar.customModules.weather.scrollDown}
title="Scroll Down"
type="string"
/>
{/* Hyprsunset Section */} {/* Hyprsunset Section */}
<Header title="Hyprsunset" /> <Header title="Hyprsunset" />
@@ -337,12 +501,32 @@ export const CustomModuleSettings = (): JSX.Element => {
title="Button Border" title="Button Border"
type="boolean" type="boolean"
/> />
<Option opt={options.bar.customModules.hyprsunset.onIcon} title="Enabled Icon" type="string" /> <Option
<Option opt={options.bar.customModules.hyprsunset.offIcon} title="Disabled Icon" type="string" /> opt={options.bar.customModules.hyprsunset.onIcon}
<Option opt={options.bar.customModules.hyprsunset.onLabel} title="Enabled Label" type="string" /> title="Enabled Icon"
<Option opt={options.bar.customModules.hyprsunset.offLabel} title="Disabled Label" type="string" /> type="string"
/>
<Option
opt={options.bar.customModules.hyprsunset.offIcon}
title="Disabled Icon"
type="string"
/>
<Option
opt={options.bar.customModules.hyprsunset.onLabel}
title="Enabled Label"
type="string"
/>
<Option
opt={options.bar.customModules.hyprsunset.offLabel}
title="Disabled Label"
type="string"
/>
<Option opt={options.bar.customModules.hyprsunset.label} title="Show Label" type="boolean" /> <Option opt={options.bar.customModules.hyprsunset.label} title="Show Label" type="boolean" />
<Option opt={options.theme.bar.buttons.modules.hyprsunset.spacing} title="Spacing" type="string" /> <Option
opt={options.theme.bar.buttons.modules.hyprsunset.spacing}
title="Spacing"
type="string"
/>
<Option <Option
opt={options.bar.customModules.hyprsunset.pollingInterval} opt={options.bar.customModules.hyprsunset.pollingInterval}
title="Polling Interval" title="Polling Interval"
@@ -351,10 +535,22 @@ export const CustomModuleSettings = (): JSX.Element => {
max={60 * 24 * 1000} max={60 * 24 * 1000}
increment={1000} increment={1000}
/> />
<Option opt={options.bar.customModules.hyprsunset.rightClick} title="Right Click" type="string" /> <Option
<Option opt={options.bar.customModules.hyprsunset.middleClick} title="Middle Click" type="string" /> opt={options.bar.customModules.hyprsunset.rightClick}
title="Right Click"
type="string"
/>
<Option
opt={options.bar.customModules.hyprsunset.middleClick}
title="Middle Click"
type="string"
/>
<Option opt={options.bar.customModules.hyprsunset.scrollUp} title="Scroll Up" type="string" /> <Option opt={options.bar.customModules.hyprsunset.scrollUp} title="Scroll Up" type="string" />
<Option opt={options.bar.customModules.hyprsunset.scrollDown} title="Scroll Down" type="string" /> <Option
opt={options.bar.customModules.hyprsunset.scrollDown}
title="Scroll Down"
type="string"
/>
{/* Hypridle Section */} {/* Hypridle Section */}
<Header title="Hypridle" /> <Header title="Hypridle" />
@@ -364,11 +560,27 @@ export const CustomModuleSettings = (): JSX.Element => {
type="boolean" type="boolean"
/> />
<Option opt={options.bar.customModules.hypridle.onIcon} title="Enabled Icon" type="string" /> <Option opt={options.bar.customModules.hypridle.onIcon} title="Enabled Icon" type="string" />
<Option opt={options.bar.customModules.hypridle.offIcon} title="Disabled Icon" type="string" /> <Option
<Option opt={options.bar.customModules.hypridle.onLabel} title="Enabled Label" type="string" /> opt={options.bar.customModules.hypridle.offIcon}
<Option opt={options.bar.customModules.hypridle.offLabel} title="Disabled Label" type="string" /> title="Disabled Icon"
type="string"
/>
<Option
opt={options.bar.customModules.hypridle.onLabel}
title="Enabled Label"
type="string"
/>
<Option
opt={options.bar.customModules.hypridle.offLabel}
title="Disabled Label"
type="string"
/>
<Option opt={options.bar.customModules.hypridle.label} title="Show Label" type="boolean" /> <Option opt={options.bar.customModules.hypridle.label} title="Show Label" type="boolean" />
<Option opt={options.theme.bar.buttons.modules.hypridle.spacing} title="Spacing" type="string" /> <Option
opt={options.theme.bar.buttons.modules.hypridle.spacing}
title="Spacing"
type="string"
/>
<Option <Option
opt={options.bar.customModules.hypridle.pollingInterval} opt={options.bar.customModules.hypridle.pollingInterval}
title="Polling Interval" title="Polling Interval"
@@ -377,10 +589,22 @@ export const CustomModuleSettings = (): JSX.Element => {
max={60 * 24 * 1000} max={60 * 24 * 1000}
increment={1000} increment={1000}
/> />
<Option opt={options.bar.customModules.hypridle.rightClick} title="Right Click" type="string" /> <Option
<Option opt={options.bar.customModules.hypridle.middleClick} title="Middle Click" type="string" /> opt={options.bar.customModules.hypridle.rightClick}
title="Right Click"
type="string"
/>
<Option
opt={options.bar.customModules.hypridle.middleClick}
title="Middle Click"
type="string"
/>
<Option opt={options.bar.customModules.hypridle.scrollUp} title="Scroll Up" type="string" /> <Option opt={options.bar.customModules.hypridle.scrollUp} title="Scroll Up" type="string" />
<Option opt={options.bar.customModules.hypridle.scrollDown} title="Scroll Down" type="string" /> <Option
opt={options.bar.customModules.hypridle.scrollDown}
title="Scroll Down"
type="string"
/>
{/* Cava Section */} {/* Cava Section */}
<Header title="Cava" /> <Header title="Cava" />
@@ -392,8 +616,16 @@ export const CustomModuleSettings = (): JSX.Element => {
<Option opt={options.bar.customModules.cava.icon} title="Icon" type="string" /> <Option opt={options.bar.customModules.cava.icon} title="Icon" type="string" />
<Option opt={options.bar.customModules.cava.showIcon} title="Show Icon" type="boolean" /> <Option opt={options.bar.customModules.cava.showIcon} title="Show Icon" type="boolean" />
<Option opt={options.theme.bar.buttons.modules.cava.spacing} title="Spacing" type="string" /> <Option opt={options.theme.bar.buttons.modules.cava.spacing} title="Spacing" type="string" />
<Option opt={options.bar.customModules.cava.barCharacters} title="Bar Characters" type="object" /> <Option
<Option opt={options.bar.customModules.cava.spaceCharacter} title="Bar Separator" type="string" /> opt={options.bar.customModules.cava.barCharacters}
title="Bar Characters"
type="object"
/>
<Option
opt={options.bar.customModules.cava.spaceCharacter}
title="Bar Separator"
type="string"
/>
<Option <Option
opt={options.bar.customModules.cava.showActiveOnly} opt={options.bar.customModules.cava.showActiveOnly}
title="Auto Hide" title="Auto Hide"
@@ -411,7 +643,11 @@ export const CustomModuleSettings = (): JSX.Element => {
/> />
<Option opt={options.bar.customModules.cava.lowCutoff} title="Low Cutoff" type="number" /> <Option opt={options.bar.customModules.cava.lowCutoff} title="Low Cutoff" type="number" />
<Option opt={options.bar.customModules.cava.highCutoff} title="High Cutoff" type="number" /> <Option opt={options.bar.customModules.cava.highCutoff} title="High Cutoff" type="number" />
<Option opt={options.bar.customModules.cava.noiseReduction} title="Noise Reduction" type="float" /> <Option
opt={options.bar.customModules.cava.noiseReduction}
title="Noise Reduction"
type="float"
/>
<Option opt={options.bar.customModules.cava.stereo} title="Stereo" type="boolean" /> <Option opt={options.bar.customModules.cava.stereo} title="Stereo" type="boolean" />
<Option opt={options.bar.customModules.cava.leftClick} title="Left Click" type="string" /> <Option opt={options.bar.customModules.cava.leftClick} title="Left Click" type="string" />
<Option opt={options.bar.customModules.cava.rightClick} title="Right Click" type="string" /> <Option opt={options.bar.customModules.cava.rightClick} title="Right Click" type="string" />
@@ -427,8 +663,16 @@ export const CustomModuleSettings = (): JSX.Element => {
type="boolean" type="boolean"
/> />
<Option opt={options.bar.customModules.worldclock.icon} title="Icon" type="string" /> <Option opt={options.bar.customModules.worldclock.icon} title="Icon" type="string" />
<Option opt={options.bar.customModules.worldclock.showIcon} title="Show Icon" type="boolean" /> <Option
<Option opt={options.theme.bar.buttons.modules.worldclock.spacing} title="Spacing" type="string" /> opt={options.bar.customModules.worldclock.showIcon}
title="Show Icon"
type="boolean"
/>
<Option
opt={options.theme.bar.buttons.modules.worldclock.spacing}
title="Spacing"
type="string"
/>
<Option opt={options.bar.customModules.worldclock.format} title="Format" type="string" /> <Option opt={options.bar.customModules.worldclock.format} title="Format" type="string" />
<Option <Option
opt={options.bar.customModules.worldclock.formatDiffDate} opt={options.bar.customModules.worldclock.formatDiffDate}
@@ -436,13 +680,37 @@ export const CustomModuleSettings = (): JSX.Element => {
subtitle="Format to use when the timezone is on a different calendar day than the local timezone." subtitle="Format to use when the timezone is on a different calendar day than the local timezone."
type="string" type="string"
/> />
<Option opt={options.bar.customModules.worldclock.divider} title="Date Divider" type="string" /> <Option
<Option opt={options.bar.customModules.worldclock.leftClick} title="Left Click" type="string" /> opt={options.bar.customModules.worldclock.divider}
<Option opt={options.bar.customModules.worldclock.rightClick} title="Right Click" type="string" /> title="Date Divider"
<Option opt={options.bar.customModules.worldclock.middleClick} title="Middle Click" type="string" /> type="string"
/>
<Option
opt={options.bar.customModules.worldclock.leftClick}
title="Left Click"
type="string"
/>
<Option
opt={options.bar.customModules.worldclock.rightClick}
title="Right Click"
type="string"
/>
<Option
opt={options.bar.customModules.worldclock.middleClick}
title="Middle Click"
type="string"
/>
<Option opt={options.bar.customModules.worldclock.scrollUp} title="Scroll Up" type="string" /> <Option opt={options.bar.customModules.worldclock.scrollUp} title="Scroll Up" type="string" />
<Option opt={options.bar.customModules.worldclock.scrollDown} title="Scroll Down" type="string" /> <Option
<Option opt={options.bar.customModules.worldclock.tz} title="Timezones Displayed" type="object" /> opt={options.bar.customModules.worldclock.scrollDown}
title="Scroll Down"
type="string"
/>
<Option
opt={options.bar.customModules.worldclock.tz}
title="Timezones Displayed"
type="object"
/>
{/* Power Section */} {/* Power Section */}
<Header title="Power" /> <Header title="Power" />
@@ -455,7 +723,11 @@ export const CustomModuleSettings = (): JSX.Element => {
<Option opt={options.bar.customModules.power.icon} title="Power Button Icon" type="string" /> <Option opt={options.bar.customModules.power.icon} title="Power Button Icon" type="string" />
<Option opt={options.bar.customModules.power.leftClick} title="Left Click" type="string" /> <Option opt={options.bar.customModules.power.leftClick} title="Left Click" type="string" />
<Option opt={options.bar.customModules.power.rightClick} title="Right Click" type="string" /> <Option opt={options.bar.customModules.power.rightClick} title="Right Click" type="string" />
<Option opt={options.bar.customModules.power.middleClick} title="Middle Click" type="string" /> <Option
opt={options.bar.customModules.power.middleClick}
title="Middle Click"
type="string"
/>
<Option opt={options.bar.customModules.power.scrollUp} title="Scroll Up" type="string" /> <Option opt={options.bar.customModules.power.scrollUp} title="Scroll Up" type="string" />
<Option opt={options.bar.customModules.power.scrollDown} title="Scroll Down" type="string" /> <Option opt={options.bar.customModules.power.scrollDown} title="Scroll Down" type="string" />
</box> </box>

View File

@@ -32,13 +32,21 @@ export const CustomModuleTheme = (): JSX.Element => {
} }
type="color" type="color"
/> />
<Option opt={options.theme.bar.buttons.modules.microphone.border} title="Border" type="color" /> <Option
opt={options.theme.bar.buttons.modules.microphone.border}
title="Border"
type="color"
/>
{/* RAM Module Section */} {/* RAM Module Section */}
<Header title="RAM" /> <Header title="RAM" />
<Option opt={options.theme.bar.buttons.modules.ram.text} title="Text" type="color" /> <Option opt={options.theme.bar.buttons.modules.ram.text} title="Text" type="color" />
<Option opt={options.theme.bar.buttons.modules.ram.icon} title="Icon" type="color" /> <Option opt={options.theme.bar.buttons.modules.ram.icon} title="Icon" type="color" />
<Option opt={options.theme.bar.buttons.modules.ram.background} title="Label Background" type="color" /> <Option
opt={options.theme.bar.buttons.modules.ram.background}
title="Label Background"
type="color"
/>
<Option <Option
opt={options.theme.bar.buttons.modules.ram.icon_background} opt={options.theme.bar.buttons.modules.ram.icon_background}
title="Icon Background" title="Icon Background"
@@ -54,7 +62,11 @@ export const CustomModuleTheme = (): JSX.Element => {
<Header title="CPU" /> <Header title="CPU" />
<Option opt={options.theme.bar.buttons.modules.cpu.text} title="Text" type="color" /> <Option opt={options.theme.bar.buttons.modules.cpu.text} title="Text" type="color" />
<Option opt={options.theme.bar.buttons.modules.cpu.icon} title="Icon" type="color" /> <Option opt={options.theme.bar.buttons.modules.cpu.icon} title="Icon" type="color" />
<Option opt={options.theme.bar.buttons.modules.cpu.background} title="Label Background" type="color" /> <Option
opt={options.theme.bar.buttons.modules.cpu.background}
title="Label Background"
type="color"
/>
<Option <Option
opt={options.theme.bar.buttons.modules.cpu.icon_background} opt={options.theme.bar.buttons.modules.cpu.icon_background}
title="Icon Background" title="Icon Background"
@@ -224,7 +236,11 @@ export const CustomModuleTheme = (): JSX.Element => {
} }
type="color" type="color"
/> />
<Option opt={options.theme.bar.buttons.modules.hyprsunset.border} title="Border" type="color" /> <Option
opt={options.theme.bar.buttons.modules.hyprsunset.border}
title="Border"
type="color"
/>
{/* Hypridle Module Section */} {/* Hypridle Module Section */}
<Header title="Hypridle" /> <Header title="Hypridle" />
@@ -250,7 +266,11 @@ export const CustomModuleTheme = (): JSX.Element => {
<Header title="Cava" /> <Header title="Cava" />
<Option opt={options.theme.bar.buttons.modules.cava.text} title="Bars" type="color" /> <Option opt={options.theme.bar.buttons.modules.cava.text} title="Bars" type="color" />
<Option opt={options.theme.bar.buttons.modules.cava.icon} title="Icon" type="color" /> <Option opt={options.theme.bar.buttons.modules.cava.icon} title="Icon" type="color" />
<Option opt={options.theme.bar.buttons.modules.cava.background} title="Label Background" type="color" /> <Option
opt={options.theme.bar.buttons.modules.cava.background}
title="Label Background"
type="color"
/>
<Option <Option
opt={options.theme.bar.buttons.modules.cava.icon_background} opt={options.theme.bar.buttons.modules.cava.icon_background}
title="Icon Background" title="Icon Background"
@@ -280,7 +300,11 @@ export const CustomModuleTheme = (): JSX.Element => {
} }
type="color" type="color"
/> />
<Option opt={options.theme.bar.buttons.modules.worldclock.border} title="Border" type="color" /> <Option
opt={options.theme.bar.buttons.modules.worldclock.border}
title="Border"
type="color"
/>
{/* Power Module Section */} {/* Power Module Section */}
<Header title="Power" /> <Header title="Power" />

View File

@@ -1,6 +1,6 @@
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { BarBoxChild, BarModule } from 'src/lib/types/bar'; import { BarBoxChild, BarModuleProps } from 'src/lib/types/bar.types';
import { BarButtonStyles } from 'src/lib/types/options'; import { BarButtonStyles } from 'src/lib/options/options.types';
import options from 'src/options'; import options from 'src/options';
const { style } = options.theme.bar.buttons; const { style } = options.theme.bar.buttons;
@@ -17,20 +17,20 @@ export const Module = ({
props = {}, props = {},
showLabelBinding = bind(Variable(true)), showLabelBinding = bind(Variable(true)),
showIconBinding = bind(Variable(true)), showIconBinding = bind(Variable(true)),
showLabel, showLabel = true,
labelHook, labelHook,
hook, hook,
}: BarModule): BarBoxChild => { }: BarModuleProps): BarBoxChild => {
const getIconWidget = (useTxtIcn: boolean): JSX.Element | undefined => { const getIconWidget = (useTxtIcn: boolean): JSX.Element | undefined => {
const className = `txt-icon bar-button-icon module-icon ${boxClass}`; const className = `txt-icon bar-button-icon module-icon ${boxClass}`;
const icn = typeof icon === 'string' ? icon : icon?.get(); const icn = typeof icon === 'string' ? icon : icon?.get();
if (!useTxtIcn && icn?.length) { if (!useTxtIcn && icn !== undefined && icn.length > 0) {
return <icon className={className} icon={icon} />; return <icon className={className} icon={icon} />;
} }
const textIcn = typeof textIcon === 'string' ? textIcon : textIcon?.get(); const textIcn = typeof textIcon === 'string' ? textIcon : textIcon?.get();
if (textIcn?.length) { if (textIcn !== undefined && textIcn.length > 0) {
return <label className={className} label={textIcon} />; return <label className={className} label={textIcon} />;
} }
}; };

View File

@@ -1,15 +1,14 @@
import { BarBoxChild } from 'src/lib/types/bar'; import { BarBoxChild } from 'src/lib/types/bar.types';
import { Bind } from '../../../lib/types/variable';
import options from '../../../options'; import options from '../../../options';
import { bind } from 'astal'; import { bind, Binding } from 'astal';
const computeVisible = (child: BarBoxChild): Bind | boolean => { const computeVisible = (child: BarBoxChild): Binding<boolean> | boolean => {
if (child.isVis !== undefined) { if (child.isVis !== undefined) {
return bind(child.isVis); return child.isVis;
} }
return child.isVisible;
};
return child.isVisible ?? true;
};
export const WidgetContainer = (child: BarBoxChild): JSX.Element => { export const WidgetContainer = (child: BarBoxChild): JSX.Element => {
const buttonClassName = bind(options.theme.bar.buttons.style).as((style) => { const buttonClassName = bind(options.theme.bar.buttons.style).as((style) => {
const styleMap = { const styleMap = {
@@ -24,7 +23,7 @@ export const WidgetContainer = (child: BarBoxChild): JSX.Element => {
return `bar_item_box_visible ${styleMap[style]} ${boxClassName}`; return `bar_item_box_visible ${styleMap[style]} ${boxClassName}`;
}); });
if (child.isBox) { if (child.isBox === true) {
return ( return (
<eventbox visible={computeVisible(child)} {...child.props}> <eventbox visible={computeVisible(child)} {...child.props}>
<box className={buttonClassName}>{child.component}</box> <box className={buttonClassName}>{child.component}</box>

View File

@@ -8,20 +8,20 @@ const hyprlandService = AstalHyprland.get_default();
* It maintains internal state for monitors that have already been used so that duplicate assignments are avoided. * It maintains internal state for monitors that have already been used so that duplicate assignments are avoided.
*/ */
export class GdkMonitorMapper { export class GdkMonitorMapper {
private usedGdkMonitors: Set<number>; private _usedGdkMonitors: Set<number>;
private usedHyprlandMonitors: Set<number>; private _usedHyprlandMonitors: Set<number>;
constructor() { constructor() {
this.usedGdkMonitors = new Set(); this._usedGdkMonitors = new Set();
this.usedHyprlandMonitors = new Set(); this._usedHyprlandMonitors = new Set();
} }
/** /**
* Resets the internal state for both GDK and Hyprland monitor mappings. * Resets the internal state for both GDK and Hyprland monitor mappings.
*/ */
public reset(): void { public reset(): void {
this.usedGdkMonitors.clear(); this._usedGdkMonitors.clear();
this.usedHyprlandMonitors.clear(); this._usedHyprlandMonitors.clear();
} }
/** /**
@@ -44,7 +44,7 @@ export class GdkMonitorMapper {
hyprlandMonitors, hyprlandMonitors,
gdkMonitor, gdkMonitor,
monitor, monitor,
this.usedHyprlandMonitors, this._usedHyprlandMonitors,
(mon) => mon.id, (mon) => mon.id,
(mon, gdkMon) => this._matchMonitorKey(mon, gdkMon), (mon, gdkMon) => this._matchMonitorKey(mon, gdkMon),
); );
@@ -68,13 +68,14 @@ export class GdkMonitorMapper {
} }
const hyprlandMonitors = hyprlandService.get_monitors(); const hyprlandMonitors = hyprlandService.get_monitors();
const foundHyprlandMonitor = hyprlandMonitors.find((mon) => mon.id === monitor) || hyprlandMonitors[0]; const foundHyprlandMonitor =
hyprlandMonitors.find((mon) => mon.id === monitor) || hyprlandMonitors[0];
return this._matchMonitor( return this._matchMonitor(
gdkCandidates, gdkCandidates,
foundHyprlandMonitor, foundHyprlandMonitor,
monitor, monitor,
this.usedGdkMonitors, this._usedGdkMonitors,
(candidate) => candidate.id, (candidate) => candidate.id,
(candidate, hyprlandMonitor) => this._matchMonitorKey(hyprlandMonitor, candidate.monitor), (candidate, hyprlandMonitor) => this._matchMonitorKey(hyprlandMonitor, candidate.monitor),
); );
@@ -105,7 +106,9 @@ export class GdkMonitorMapper {
// Direct match: candidate matches the source and has the same id as the target. // Direct match: candidate matches the source and has the same id as the target.
const directMatch = candidates.find( const directMatch = candidates.find(
(candidate) => (candidate) =>
compare(candidate, source) && !usedMonitors.has(getId(candidate)) && getId(candidate) === target, compare(candidate, source) &&
!usedMonitors.has(getId(candidate)) &&
getId(candidate) === target,
); );
if (directMatch !== undefined) { if (directMatch !== undefined) {
@@ -202,7 +205,7 @@ export class GdkMonitorMapper {
continue; continue;
} }
const model = curMonitor.get_model() || ''; const model = curMonitor.get_model() ?? '';
const geometry = curMonitor.get_geometry(); const geometry = curMonitor.get_geometry();
const scaleFactor = curMonitor.get_scale_factor(); const scaleFactor = curMonitor.get_scale_factor();

View File

@@ -1,14 +1,18 @@
import { ResourceLabelType } from 'src/lib/types/bar';
import { GenericResourceData, Postfix, UpdateHandlers } from 'src/lib/types/customModules/generic';
import { InputHandlerEventArgs, InputHandlerEvents, RunAsyncCommand } from 'src/lib/types/customModules/utils';
import { ThrottleFn } from 'src/lib/types/utils';
import { bind, Binding, execAsync, Variable } from 'astal'; import { bind, Binding, execAsync, Variable } from 'astal';
import { openMenu } from 'src/components/bar/utils/menu'; import { openMenu } from 'src/components/bar/utils/menu';
import options from 'src/options'; import options from 'src/options';
import { Gdk } from 'astal/gtk3'; import { Gdk } from 'astal/gtk3';
import { GtkWidget } from 'src/lib/types/widget';
import { onMiddleClick, onPrimaryClick, onSecondaryClick } from 'src/lib/shared/eventHandlers'; import { onMiddleClick, onPrimaryClick, onSecondaryClick } from 'src/lib/shared/eventHandlers';
import { isScrollDown, isScrollUp } from 'src/lib/utils'; import { isScrollDown, isScrollUp } from 'src/lib/utils';
import { ResourceLabelType } from 'src/lib/types/bar.types';
import { UpdateHandlers, Postfix, GenericResourceData } from 'src/lib/types/customModules/generic.types';
import {
RunAsyncCommand,
InputHandlerEvents,
InputHandlerEventArgs,
} from 'src/lib/types/customModules/utils.types';
import { ThrottleFn } from 'src/lib/types/utils.types';
import { GtkWidget } from 'src/lib/types/widget.types';
const { scrollSpeed } = options.bar.customModules; const { scrollSpeed } = options.bar.customModules;
@@ -38,7 +42,12 @@ const handlePostInputUpdater = (postInputUpdater?: Variable<boolean>): void => {
* @param fn An optional callback function to handle the command output. * @param fn An optional callback function to handle the command output.
* @param postInputUpdater An optional Variable<boolean> that tracks the post input update state. * @param postInputUpdater An optional Variable<boolean> that tracks the post input update state.
*/ */
export const runAsyncCommand: RunAsyncCommand = (cmd, events, fn, postInputUpdater?: Variable<boolean>): void => { export const runAsyncCommand: RunAsyncCommand = (
cmd,
events,
fn,
postInputUpdater?: Variable<boolean>,
): void => {
if (cmd.startsWith('menu:')) { if (cmd.startsWith('menu:')) {
const menuName = cmd.split(':')[1].trim().toLowerCase(); const menuName = cmd.split(':')[1].trim().toLowerCase();
openMenu(events.clicked, events.event, `${menuName}menu`); openMenu(events.clicked, events.event, `${menuName}menu`);
@@ -61,7 +70,8 @@ export const runAsyncCommand: RunAsyncCommand = (cmd, events, fn, postInputUpdat
* which undo the toggle. * which undo the toggle.
*/ */
const throttledAsyncCommand = throttleInput( const throttledAsyncCommand = throttleInput(
(cmd, events, fn, postInputUpdater?: Variable<boolean>) => runAsyncCommand(cmd, events, fn, postInputUpdater), (cmd, events, fn, postInputUpdater?: Variable<boolean>) =>
runAsyncCommand(cmd, events, fn, postInputUpdater),
50, 50,
); );
@@ -165,7 +175,12 @@ export const inputHandler = (
const id = self.connect('scroll-event', (self: GtkWidget, event: Gdk.Event) => { const id = self.connect('scroll-event', (self: GtkWidget, event: Gdk.Event) => {
const handleScroll = (input?: InputHandlerEventArgs): void => { const handleScroll = (input?: InputHandlerEventArgs): void => {
if (input) { if (input) {
throttledHandler(sanitizeInput(input.cmd), { clicked: self, event }, input.fn, postInputUpdater); throttledHandler(
sanitizeInput(input.cmd),
{ clicked: self, event },
input.fn,
postInputUpdater,
);
} }
}; };
@@ -344,7 +359,11 @@ export const getPostfix = (sizeInBytes: number): Postfix => {
* *
* @returns The rendered resource label as a string. * @returns The rendered resource label as a string.
*/ */
export const renderResourceLabel = (lblType: ResourceLabelType, rmUsg: GenericResourceData, round: boolean): string => { export const renderResourceLabel = (
lblType: ResourceLabelType,
rmUsg: GenericResourceData,
round: boolean,
): string => {
const { used, total, percentage, free } = rmUsg; const { used, total, percentage, free } = rmUsg;
const formatFunctions = { const formatFunctions = {
@@ -361,7 +380,7 @@ export const renderResourceLabel = (lblType: ResourceLabelType, rmUsg: GenericRe
const postfix = getPostfix(total); const postfix = getPostfix(total);
// Determine which format function to use // Determine which format function to use
const formatUsed = formatFunctions[postfix] || formatFunctions['B']; const formatUsed = formatFunctions[postfix] ?? formatFunctions['B'];
const usedSizeFormatted = formatUsed(used, round); const usedSizeFormatted = formatUsed(used, round);
if (lblType === 'used/total') { if (lblType === 'used/total') {

View File

@@ -1,5 +1,5 @@
import { App, Gdk } from 'astal/gtk3'; import { App, Gdk } from 'astal/gtk3';
import { GtkWidget } from 'src/lib/types/widget'; import { GtkWidget } from 'src/lib/types/widget.types';
import { calculateMenuPosition } from 'src/components/menus/shared/dropdown/locationHandler'; import { calculateMenuPosition } from 'src/components/menus/shared/dropdown/locationHandler';
export const closeAllMenus = (): void => { export const closeAllMenus = (): void => {

View File

@@ -1,4 +1,4 @@
import { BarLayout, BarLayouts } from 'src/lib/types/options'; import { BarLayout, BarLayouts } from 'src/lib/options/options.types';
/** /**
* Returns the bar layout configuration for a specific monitor * Returns the bar layout configuration for a specific monitor
@@ -11,7 +11,7 @@ export const getLayoutForMonitor = (monitor: number, layouts: BarLayouts): BarLa
const matchingKey = Object.keys(layouts).find((key) => key === monitor.toString()); const matchingKey = Object.keys(layouts).find((key) => key === monitor.toString());
const wildcard = Object.keys(layouts).find((key) => key === '*'); const wildcard = Object.keys(layouts).find((key) => key === '*');
if (matchingKey) { if (matchingKey !== undefined) {
return layouts[matchingKey]; return layouts[matchingKey];
} }

View File

@@ -7,7 +7,7 @@ const audioService = wireplumber.audio;
const ActiveDeviceContainer = ({ children }: ActiveDeviceContainerProps): JSX.Element => { const ActiveDeviceContainer = ({ children }: ActiveDeviceContainerProps): JSX.Element => {
return ( return (
<box className={'menu-items-section selected'} name={ActiveDeviceMenu.Devices} vertical> <box className={'menu-items-section selected'} name={ActiveDeviceMenu.DEVICES} vertical>
{children} {children}
</box> </box>
); );

View File

@@ -5,11 +5,11 @@ import { bind, Variable } from 'astal';
import { isPrimaryClick } from 'src/lib/utils.js'; import { isPrimaryClick } from 'src/lib/utils.js';
export enum ActiveDeviceMenu { export enum ActiveDeviceMenu {
Devices = 'devices', DEVICES = 'devices',
Playbacks = 'playbacks', PLAYBACKS = 'playbacks',
} }
const activeMenu: Variable<ActiveDeviceMenu> = Variable(ActiveDeviceMenu.Devices); const activeMenu: Variable<ActiveDeviceMenu> = Variable(ActiveDeviceMenu.DEVICES);
const Header = (): JSX.Element => ( const Header = (): JSX.Element => (
<box className={'menu-label-container volume selected'} halign={Gtk.Align.FILL}> <box className={'menu-label-container volume selected'} halign={Gtk.Align.FILL}>
@@ -21,15 +21,15 @@ const Header = (): JSX.Element => (
return; return;
} }
if (activeMenu.get() === ActiveDeviceMenu.Devices) { if (activeMenu.get() === ActiveDeviceMenu.DEVICES) {
activeMenu.set(ActiveDeviceMenu.Playbacks); activeMenu.set(ActiveDeviceMenu.PLAYBACKS);
} else { } else {
activeMenu.set(ActiveDeviceMenu.Devices); activeMenu.set(ActiveDeviceMenu.DEVICES);
} }
}} }}
halign={Gtk.Align.END} halign={Gtk.Align.END}
hexpand hexpand
label={bind(activeMenu).as((menu) => (menu === ActiveDeviceMenu.Devices ? '' : '󰤽'))} label={bind(activeMenu).as((menu) => (menu === ActiveDeviceMenu.DEVICES ? '' : '󰤽'))}
/> />
</box> </box>
); );
@@ -40,13 +40,13 @@ export const VolumeSliders = (): JSX.Element => {
<Header /> <Header />
<revealer <revealer
transitionType={Gtk.RevealerTransitionType.NONE} transitionType={Gtk.RevealerTransitionType.NONE}
revealChild={bind(activeMenu).as((curMenu) => curMenu === ActiveDeviceMenu.Devices)} revealChild={bind(activeMenu).as((curMenu) => curMenu === ActiveDeviceMenu.DEVICES)}
> >
<ActiveDevices /> <ActiveDevices />
</revealer> </revealer>
<revealer <revealer
transitionType={Gtk.RevealerTransitionType.NONE} transitionType={Gtk.RevealerTransitionType.NONE}
revealChild={bind(activeMenu).as((curMenu) => curMenu === ActiveDeviceMenu.Playbacks)} revealChild={bind(activeMenu).as((curMenu) => curMenu === ActiveDeviceMenu.PLAYBACKS)}
> >
<ActivePlaybacks /> <ActivePlaybacks />
</revealer> </revealer>

View File

@@ -12,11 +12,11 @@ const NoStreams = (): JSX.Element => {
export const ActivePlaybacks = (): JSX.Element => { export const ActivePlaybacks = (): JSX.Element => {
return ( return (
<box className={'menu-items-section selected'} name={ActiveDeviceMenu.Playbacks} vertical> <box className={'menu-items-section selected'} name={ActiveDeviceMenu.PLAYBACKS} vertical>
<scrollable className={'menu-scroller active-playbacks-scrollable'}> <scrollable className={'menu-scroller active-playbacks-scrollable'}>
<box vertical> <box vertical>
{bind(audioService, 'streams').as((streams) => { {bind(audioService, 'streams').as((streams) => {
if (!streams || streams.length === 0) { if (streams === null || streams.length === 0) {
return <NoStreams />; return <NoStreams />;
} }

View File

@@ -28,8 +28,8 @@ export const Slider = ({ device, type }: SliderProps): JSX.Element => {
max={type === 'playback' ? bind(raiseMaximumVolume).as((raise) => (raise ? 1.5 : 1)) : 1} max={type === 'playback' ? bind(raiseMaximumVolume).as((raise) => (raise ? 1.5 : 1)) : 1}
onDragged={({ value, dragging }) => { onDragged={({ value, dragging }) => {
if (dragging) { if (dragging) {
device.volume = value; device.set_volume(value);
device.mute = false; device.set_mute(false);
} }
}} }}
setup={(self) => { setup={(self) => {

View File

@@ -16,12 +16,14 @@ export const SliderIcon = ({ type, device }: SliderIconProps): JSX.Element => {
return ( return (
<button <button
className={bind(device, 'mute').as((isMuted) => `menu-active-button ${type} ${isMuted ? 'muted' : ''}`)} className={bind(device, 'mute').as(
(isMuted) => `menu-active-button ${type} ${isMuted ? 'muted' : ''}`,
)}
vexpand={false} vexpand={false}
valign={Gtk.Align.END} valign={Gtk.Align.END}
onClick={(_, event) => { onClick={(_, event) => {
if (isPrimaryClick(event)) { if (isPrimaryClick(event)) {
device.mute = !device.mute; device.set_mute(!device.mute);
} }
}} }}
onDestroy={() => { onDestroy={() => {

View File

@@ -20,7 +20,9 @@ const DeviceName = ({ device, type }: Omit<AudioDeviceProps, 'icon'>): JSX.Eleme
truncate truncate
wrap wrap
className={bind(device, 'description').as((currentDesc) => className={bind(device, 'description').as((currentDesc) =>
device.description === currentDesc ? `menu-button-name active ${type}` : `menu-button-name ${type}`, device.description === currentDesc
? `menu-button-name active ${type}`
: `menu-button-name ${type}`,
)} )}
label={device.description} label={device.description}
/> />

View File

@@ -13,7 +13,7 @@ export const InputDevices = (): JSX.Element => {
<box className={'menu-items-section input'} vertical> <box className={'menu-items-section input'} vertical>
<box className={'menu-container input'} vertical> <box className={'menu-container input'} vertical>
{inputDevices.as((devices) => { {inputDevices.as((devices) => {
if (!devices || devices.length === 0) { if (devices === null || devices.length === 0) {
return <NotFoundButton type={'input'} />; return <NotFoundButton type={'input'} />;
} }

View File

@@ -13,7 +13,7 @@ export const PlaybackDevices = (): JSX.Element => {
<box className={'menu-items-section playback'} vertical> <box className={'menu-items-section playback'} vertical>
<box className={'menu-container playback'} vertical> <box className={'menu-container playback'} vertical>
{playbackDevices.as((devices) => { {playbackDevices.as((devices) => {
if (!devices || devices.length === 0) { if (devices === null || devices.length === 0) {
return <NotFoundButton type={'playback'} />; return <NotFoundButton type={'playback'} />;
} }

View File

@@ -29,7 +29,7 @@ type IconVolumes = keyof typeof speakerIcons;
*/ */
const getIcon = (audioVol: number, isMuted: boolean): Record<string, string> => { const getIcon = (audioVol: number, isMuted: boolean): Record<string, string> => {
const thresholds: IconVolumes[] = [101, 66, 34, 1, 0]; const thresholds: IconVolumes[] = [101, 66, 34, 1, 0];
const icon = isMuted ? 0 : thresholds.find((threshold) => threshold <= audioVol * 100) || 0; const icon = isMuted ? 0 : (thresholds.find((threshold) => threshold <= audioVol * 100) ?? 0);
return { return {
spkr: speakerIcons[icon], spkr: speakerIcons[icon],

View File

@@ -2,7 +2,13 @@ import { Gtk } from 'astal/gtk3';
export const BluetoothDisabled = (): JSX.Element => { export const BluetoothDisabled = (): JSX.Element => {
return ( return (
<box className={'bluetooth-items'} vertical expand valign={Gtk.Align.CENTER} halign={Gtk.Align.CENTER}> <box
className={'bluetooth-items'}
vertical
expand
valign={Gtk.Align.CENTER}
halign={Gtk.Align.CENTER}
>
<label className={'bluetooth-disabled dim'} hexpand label={'Bluetooth is disabled'} /> <label className={'bluetooth-disabled dim'} hexpand label={'Bluetooth is disabled'} />
</box> </box>
); );

View File

@@ -2,7 +2,13 @@ import { Gtk } from 'astal/gtk3';
export const NoBluetoothDevices = (): JSX.Element => { export const NoBluetoothDevices = (): JSX.Element => {
return ( return (
<box className={'bluetooth-items'} vertical expand valign={Gtk.Align.CENTER} halign={Gtk.Align.CENTER}> <box
className={'bluetooth-items'}
vertical
expand
valign={Gtk.Align.CENTER}
halign={Gtk.Align.CENTER}
>
<label className={'no-bluetooth-devices dim'} hexpand label={'No devices currently found'} /> <label className={'no-bluetooth-devices dim'} hexpand label={'No devices currently found'} />
<label className={'search-bluetooth-label dim'} hexpand label={"Press '󰑐' to search"} /> <label className={'search-bluetooth-label dim'} hexpand label={"Press '󰑐' to search"} />
</box> </box>

View File

@@ -1,7 +1,12 @@
import { Binding } from 'astal'; import { Binding } from 'astal';
import { ButtonProps } from 'astal/gtk3/widget'; import { ButtonProps } from 'astal/gtk3/widget';
export const ActionButton = ({ name = '', tooltipText = '', label = '', ...props }: ActionButtonProps): JSX.Element => { export const ActionButton = ({
name = '',
tooltipText = '',
label = '',
...props
}: ActionButtonProps): JSX.Element => {
return ( return (
<button className={`menu-icon-button ${name} bluetooth`} {...props}> <button className={`menu-icon-button ${name} bluetooth`} {...props}>
<label <label

View File

@@ -41,7 +41,9 @@ export const getAvailableBluetoothDevices = (): AstalBluetooth.Device[] => {
*/ */
export const getConnectedBluetoothDevices = (): string[] => { export const getConnectedBluetoothDevices = (): string[] => {
const availableDevices = getAvailableBluetoothDevices(); const availableDevices = getAvailableBluetoothDevices();
const connectedDeviceNames = availableDevices.filter((d) => d.connected || d.paired).map((d) => d.address); const connectedDeviceNames = availableDevices
.filter((d) => d.connected || d.paired)
.map((d) => d.address);
return connectedDeviceNames; return connectedDeviceNames;
}; };

View File

@@ -10,7 +10,7 @@ Variable.derive([bind(bluetoothService, 'adapter')], () => {
discoveringBinding?.drop(); discoveringBinding?.drop();
discoveringBinding = undefined; discoveringBinding = undefined;
if (!bluetoothService.adapter) { if (bluetoothService.adapter === null) {
return; return;
} }

View File

@@ -3,7 +3,14 @@ import { Controls } from './Controls';
export const Header = (): JSX.Element => { export const Header = (): JSX.Element => {
const MenuLabel = (): JSX.Element => { const MenuLabel = (): JSX.Element => {
return <label className="menu-label" valign={Gtk.Align.CENTER} halign={Gtk.Align.START} label="Bluetooth" />; return (
<label
className="menu-label"
valign={Gtk.Align.CENTER}
halign={Gtk.Align.START}
label="Bluetooth"
/>
);
}; };
return ( return (

View File

@@ -3,7 +3,12 @@ import Calendar from 'src/components/shared/Calendar';
export const CalendarWidget = (): JSX.Element => { export const CalendarWidget = (): JSX.Element => {
return ( return (
<box className={'calendar-menu-item-container calendar'} halign={Gtk.Align.FILL} valign={Gtk.Align.FILL} expand> <box
className={'calendar-menu-item-container calendar'}
halign={Gtk.Align.FILL}
valign={Gtk.Align.FILL}
expand
>
<box className={'calendar-container-box'}> <box className={'calendar-container-box'}>
<Calendar <Calendar
className={'calendar-menu-widget'} className={'calendar-menu-widget'}

View File

@@ -1,7 +1,7 @@
import options from 'src/options'; import options from 'src/options';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
import { Gtk } from 'astal/gtk3'; import { Gtk } from 'astal/gtk3';
import { systemTime } from 'src/globals/time'; import { systemTime } from 'src/shared/time';
const { military, hideSeconds } = options.menus.clock.time; const { military, hideSeconds } = options.menus.clock.time;
@@ -16,7 +16,7 @@ export const MilitaryTime = (): JSX.Element => {
<label <label
className={'clock-content-time'} className={'clock-content-time'}
label={bind(systemTime).as((time) => { label={bind(systemTime).as((time) => {
return time?.format(hideSeconds ? '%H:%M' : '%H:%M:%S') || ''; return time?.format(hideSeconds ? '%H:%M' : '%H:%M:%S') ?? '';
})} })}
/> />
</box> </box>

View File

@@ -1,11 +1,11 @@
import options from 'src/options'; import options from 'src/options';
import { bind, GLib, Variable } from 'astal'; import { bind, GLib, Variable } from 'astal';
import { Gtk } from 'astal/gtk3'; import { Gtk } from 'astal/gtk3';
import { systemTime } from 'src/globals/time'; import { systemTime } from 'src/shared/time';
const { military, hideSeconds } = options.menus.clock.time; const { military, hideSeconds } = options.menus.clock.time;
const period = Variable('').poll(1000, (): string => GLib.DateTime.new_now_local().format('%p') || ''); const period = Variable('').poll(1000, (): string => GLib.DateTime.new_now_local().format('%p') ?? '');
export const StandardTime = (): JSX.Element => { export const StandardTime = (): JSX.Element => {
const CurrentTime = ({ hideSeconds }: CurrentTimeProps): JSX.Element => { const CurrentTime = ({ hideSeconds }: CurrentTimeProps): JSX.Element => {
@@ -14,7 +14,7 @@ export const StandardTime = (): JSX.Element => {
<label <label
className={'clock-content-time'} className={'clock-content-time'}
label={bind(systemTime).as((time) => { label={bind(systemTime).as((time) => {
return time?.format(hideSeconds ? '%I:%M' : '%I:%M:%S') || ''; return time?.format(hideSeconds ? '%I:%M' : '%I:%M:%S') ?? '';
})} })}
/> />
</box> </box>

View File

@@ -4,8 +4,18 @@ import { StandardTime } from './StandardTime';
export const TimeWidget = (): JSX.Element => { export const TimeWidget = (): JSX.Element => {
return ( return (
<box className={'calendar-menu-item-container clock'} valign={Gtk.Align.CENTER} halign={Gtk.Align.FILL} hexpand> <box
<box className={'clock-content-items'} valign={Gtk.Align.CENTER} halign={Gtk.Align.CENTER} hexpand> className={'calendar-menu-item-container clock'}
valign={Gtk.Align.CENTER}
halign={Gtk.Align.FILL}
hexpand
>
<box
className={'clock-content-items'}
valign={Gtk.Align.CENTER}
halign={Gtk.Align.CENTER}
hexpand
>
<StandardTime /> <StandardTime />
<MilitaryTime /> <MilitaryTime />
</box> </box>

View File

@@ -1,5 +1,5 @@
import { isValidWeatherIconTitle } from 'src/globals/weather'; import { Weather, WeatherIconTitle } from 'src/lib/types/weather.types';
import { Weather, WeatherIconTitle } from 'src/lib/types/weather'; import { isValidWeatherIconTitle } from 'src/shared/weather';
/** /**
* Retrieves the next epoch time for weather data. * Retrieves the next epoch time for weather data.

View File

@@ -1,5 +1,5 @@
import { bind } from 'astal'; import { bind } from 'astal';
import { globalWeatherVar } from 'src/globals/weather'; import { globalWeatherVar } from 'src/shared/weather';
import { Gtk } from 'astal/gtk3'; import { Gtk } from 'astal/gtk3';
import { weatherIcons } from 'src/lib/icons/weather.js'; import { weatherIcons } from 'src/lib/icons/weather.js';
import { getIconQuery } from '../helpers'; import { getIconQuery } from '../helpers';

View File

@@ -1,5 +1,5 @@
import options from 'src/options'; import options from 'src/options';
import { globalWeatherVar } from 'src/globals/weather'; import { globalWeatherVar } from 'src/shared/weather';
import { getNextEpoch } from '../helpers'; import { getNextEpoch } from '../helpers';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';

View File

@@ -1,4 +1,4 @@
import { globalWeatherVar } from 'src/globals/weather'; import { globalWeatherVar } from 'src/shared/weather';
import { getNextEpoch } from '../helpers'; import { getNextEpoch } from '../helpers';
import { bind } from 'astal'; import { bind } from 'astal';

View File

@@ -1,6 +1,6 @@
import { bind } from 'astal'; import { bind } from 'astal';
import { Gtk } from 'astal/gtk3'; import { Gtk } from 'astal/gtk3';
import { getWeatherStatusTextIcon } from 'src/globals/weather.js'; import { getWeatherStatusTextIcon, globalWeatherVar } from 'src/shared/weather';
export const TodayIcon = (): JSX.Element => { export const TodayIcon = (): JSX.Element => {
return ( return (
@@ -11,7 +11,7 @@ export const TodayIcon = (): JSX.Element => {
> >
<label <label
className={'calendar-menu-weather today icon txt-icon'} className={'calendar-menu-weather today icon txt-icon'}
label={bind(globalWeatherVar).as(getWeatherStatusTextIcon)} label={bind(globalWeatherVar).as((weather) => getWeatherStatusTextIcon(weather))}
/> />
</box> </box>
); );

View File

@@ -1,6 +1,6 @@
import { getTemperature, globalWeatherVar } from 'src/globals/weather'; import { getTemperature, globalWeatherVar } from 'src/shared/weather';
import options from 'src/options'; import options from 'src/options';
import { getRainChance } from 'src/globals/weather'; import { getRainChance } from 'src/shared/weather';
import { Gtk } from 'astal/gtk3'; import { Gtk } from 'astal/gtk3';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';

View File

@@ -1,6 +1,6 @@
import options from 'src/options'; import options from 'src/options';
import { globalWeatherVar } from 'src/globals/weather'; import { globalWeatherVar } from 'src/shared/weather';
import { getTemperature, getWeatherIcon } from 'src/globals/weather'; import { getTemperature, getWeatherIcon } from 'src/shared/weather';
import { Gtk } from 'astal/gtk3'; import { Gtk } from 'astal/gtk3';
import { bind, Variable } from 'astal'; import { bind, Variable } from 'astal';
const { unit } = options.menus.clock.weather; const { unit } = options.menus.clock.weather;
@@ -35,7 +35,9 @@ const Temperature = (): JSX.Element => {
(weather) => (weather) =>
`calendar-menu-weather today temp label icon txt-icon ${getWeatherIcon(Math.ceil(weather.current.temp_f)).color}`, `calendar-menu-weather today temp label icon txt-icon ${getWeatherIcon(Math.ceil(weather.current.temp_f)).color}`,
)} )}
label={bind(globalWeatherVar).as((weather) => getWeatherIcon(Math.ceil(weather.current.temp_f)).icon)} label={bind(globalWeatherVar).as(
(weather) => getWeatherIcon(Math.ceil(weather.current.temp_f)).icon,
)}
/> />
); );
}; };

View File

@@ -18,7 +18,9 @@ const notifdService = AstalNotifd.get_default();
export const WifiButton = (): JSX.Element => { export const WifiButton = (): JSX.Element => {
return ( return (
<button <button
className={bind(isWifiEnabled).as((isEnabled) => `dashboard-button wifi ${!isEnabled ? 'disabled' : ''}`)} className={bind(isWifiEnabled).as(
(isEnabled) => `dashboard-button wifi ${!isEnabled ? 'disabled' : ''}`,
)}
onClick={(_, event) => { onClick={(_, event) => {
if (isPrimaryClick(event)) { if (isPrimaryClick(event)) {
networkService.wifi?.set_enabled(!networkService.wifi.enabled); networkService.wifi?.set_enabled(!networkService.wifi.enabled);
@@ -27,7 +29,10 @@ export const WifiButton = (): JSX.Element => {
tooltipText={'Toggle Wifi'} tooltipText={'Toggle Wifi'}
expand expand
> >
<label className={'txt-icon'} label={bind(isWifiEnabled).as((isEnabled) => (isEnabled ? '󰤨' : '󰤭'))} /> <label
className={'txt-icon'}
label={bind(isWifiEnabled).as((isEnabled) => (isEnabled ? '󰤨' : '󰤭'))}
/>
</button> </button>
); );
}; };
@@ -68,7 +73,10 @@ export const NotificationsButton = (): JSX.Element => {
tooltipText={'Toggle Notifications'} tooltipText={'Toggle Notifications'}
expand expand
> >
<label className={'txt-icon'} label={bind(notifdService, 'dontDisturb').as((dnd) => (dnd ? '󰂛' : '󰂚'))} /> <label
className={'txt-icon'}
label={bind(notifdService, 'dontDisturb').as((dnd) => (dnd ? '󰂛' : '󰂚'))}
/>
</button> </button>
); );
}; };

View File

@@ -10,7 +10,7 @@ Variable.derive([bind(networkService, 'wifi')], () => {
wifiEnabledBinding?.drop(); wifiEnabledBinding?.drop();
wifiEnabledBinding = undefined; wifiEnabledBinding = undefined;
if (!networkService.wifi) { if (networkService.wifi === null) {
return; return;
} }

Some files were not shown because too many files have changed in this diff Show More