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';

1390
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"
} }
} }

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

@@ -21,6 +21,7 @@
* ts-node makeTheme.ts theme.json updatedTheme.json --vivid * ts-node makeTheme.ts theme.json updatedTheme.json --vivid
*/ */
(() => {
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
@@ -47,7 +48,7 @@ Transforms:
*/ */
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);
} }
/** /**
@@ -197,3 +198,4 @@ if (require.main === module) {
process.exit(1); process.exit(1);
}); });
} }
})();

View File

@@ -1,6 +1,7 @@
#!/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.
@@ -26,6 +27,9 @@ Examples:
`); `);
} }
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.
@@ -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];
@@ -170,7 +175,4 @@ if (require.main === module) {
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