Implemented strict linting standards and prettier formatting config. (#248)
* Implemented strict linting standards and prettier formatting config. * More linter fixes and type updates. * More linter updates and type fixes * Remove noisy comments * Linter and type updates * Linter, formatting and type updates. * Linter updates * Type updates * Type updates * fixed all linter errors * Fixed all linting, formatting and type issues. * Resolve merge conflicts.
This commit is contained in:
2
.eslintignore
Normal file
2
.eslintignore
Normal file
@@ -0,0 +1,2 @@
|
||||
types
|
||||
node_modules
|
||||
25
.eslintrc.js
Normal file
25
.eslintrc.js
Normal file
@@ -0,0 +1,25 @@
|
||||
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: ['.eslintrc.js', 'types/**/*.ts'],
|
||||
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 }],
|
||||
},
|
||||
};
|
||||
130
.eslintrc.yml
130
.eslintrc.yml
@@ -1,130 +0,0 @@
|
||||
env:
|
||||
es2022: true
|
||||
extends:
|
||||
- "eslint:recommended"
|
||||
- "plugin:@typescript-eslint/recommended"
|
||||
parser: "@typescript-eslint/parser"
|
||||
parserOptions:
|
||||
ecmaVersion: 2022
|
||||
sourceType: "module"
|
||||
project: "./tsconfig.json"
|
||||
warnOnUnsupportedTypeScriptVersion: false
|
||||
root: true
|
||||
ignorePatterns:
|
||||
- types/
|
||||
plugins:
|
||||
- "@typescript-eslint"
|
||||
rules:
|
||||
"@typescript-eslint/ban-ts-comment":
|
||||
- "off"
|
||||
"@typescript-eslint/no-non-null-assertion":
|
||||
- "off"
|
||||
# "@typescript-eslint/no-explicit-any":
|
||||
# - "off"
|
||||
"@typescript-eslint/no-unused-vars":
|
||||
- error
|
||||
- varsIgnorePattern: (^unused|_$)
|
||||
argsIgnorePattern: ^(unused|_)
|
||||
"@typescript-eslint/no-empty-interface":
|
||||
- "off"
|
||||
|
||||
arrow-parens:
|
||||
- error
|
||||
- as-needed
|
||||
comma-dangle:
|
||||
- error
|
||||
- always-multiline
|
||||
comma-spacing:
|
||||
- error
|
||||
- before: false
|
||||
after: true
|
||||
comma-style:
|
||||
- error
|
||||
- last
|
||||
curly:
|
||||
- error
|
||||
- multi-or-nest
|
||||
- consistent
|
||||
dot-location:
|
||||
- error
|
||||
- property
|
||||
eol-last:
|
||||
- error
|
||||
eqeqeq:
|
||||
- error
|
||||
- always
|
||||
indent:
|
||||
- error
|
||||
- 4
|
||||
- SwitchCase: 1
|
||||
keyword-spacing:
|
||||
- error
|
||||
- before: true
|
||||
lines-between-class-members:
|
||||
- error
|
||||
- always
|
||||
- exceptAfterSingleLine: true
|
||||
padded-blocks:
|
||||
- error
|
||||
- never
|
||||
- allowSingleLineBlocks: false
|
||||
prefer-const:
|
||||
- error
|
||||
quotes:
|
||||
- error
|
||||
- double
|
||||
- avoidEscape: true
|
||||
semi:
|
||||
- error
|
||||
- never
|
||||
nonblock-statement-body-position:
|
||||
- error
|
||||
- below
|
||||
no-trailing-spaces:
|
||||
- error
|
||||
no-useless-escape:
|
||||
- off
|
||||
max-len:
|
||||
- error
|
||||
- code: 100
|
||||
func-call-spacing:
|
||||
- error
|
||||
array-bracket-spacing:
|
||||
- error
|
||||
space-before-function-paren:
|
||||
- error
|
||||
- anonymous: never
|
||||
named: never
|
||||
asyncArrow: ignore
|
||||
space-before-blocks:
|
||||
- error
|
||||
key-spacing:
|
||||
- error
|
||||
object-curly-spacing:
|
||||
- error
|
||||
- always
|
||||
globals:
|
||||
Widget: readonly
|
||||
Utils: readonly
|
||||
App: readonly
|
||||
Variable: readonly
|
||||
Service: readonly
|
||||
pkg: readonly
|
||||
ARGV: readonly
|
||||
Debugger: readonly
|
||||
GIRepositoryGType: readonly
|
||||
globalThis: readonly
|
||||
imports: readonly
|
||||
Intl: readonly
|
||||
log: readonly
|
||||
logError: readonly
|
||||
print: readonly
|
||||
printerr: readonly
|
||||
window: readonly
|
||||
TextEncoder: readonly
|
||||
TextDecoder: readonly
|
||||
console: readonly
|
||||
setTimeout: readonly
|
||||
setInterval: readonly
|
||||
clearTimeout: readonly
|
||||
clearInterval: readonly
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
.weather.json
|
||||
node_modules
|
||||
|
||||
2
.prettierignore
Normal file
2
.prettierignore
Normal file
@@ -0,0 +1,2 @@
|
||||
.eslintrc.js
|
||||
types/**/*.ts
|
||||
8
.prettierrc
Normal file
8
.prettierrc
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"semi": true,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4,
|
||||
"useTabs": false
|
||||
}
|
||||
68
config.js
68
config.js
@@ -1,46 +1,58 @@
|
||||
import GLib from "gi://GLib"
|
||||
import GLib from 'gi://GLib';
|
||||
|
||||
const main = "/tmp/ags/hyprpanel/main.js"
|
||||
const entry = `${App.configDir}/main.ts`
|
||||
const bundler = GLib.getenv("AGS_BUNDLER") || "bun"
|
||||
const main = '/tmp/ags/hyprpanel/main.js';
|
||||
const entry = `${App.configDir}/main.ts`;
|
||||
const bundler = GLib.getenv('AGS_BUNDLER') || 'bun';
|
||||
|
||||
const v = {
|
||||
ags: pkg.version?.split(".").map(Number) || [],
|
||||
ags: pkg.version?.split('.').map(Number) || [],
|
||||
expect: [1, 8, 1],
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
switch (bundler) {
|
||||
case "bun": await Utils.execAsync([
|
||||
"bun", "build", entry,
|
||||
"--outfile", main,
|
||||
"--external", "resource://*",
|
||||
"--external", "gi://*",
|
||||
"--external", "file://*",
|
||||
]); break
|
||||
case 'bun':
|
||||
await Utils.execAsync([
|
||||
'bun',
|
||||
'build',
|
||||
entry,
|
||||
'--outfile',
|
||||
main,
|
||||
'--external',
|
||||
'resource://*',
|
||||
'--external',
|
||||
'gi://*',
|
||||
'--external',
|
||||
'file://*',
|
||||
]);
|
||||
break;
|
||||
|
||||
case "esbuild": await Utils.execAsync([
|
||||
"esbuild", "--bundle", entry,
|
||||
"--format=esm",
|
||||
`--outfile=${main}`,
|
||||
"--external:resource://*",
|
||||
"--external:gi://*",
|
||||
"--external:file://*",
|
||||
]); break
|
||||
case 'esbuild':
|
||||
await Utils.execAsync([
|
||||
'esbuild',
|
||||
'--bundle',
|
||||
entry,
|
||||
'--format=esm',
|
||||
`--outfile=${main}`,
|
||||
'--external:resource://*',
|
||||
'--external:gi://*',
|
||||
'--external:file://*',
|
||||
]);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw `"${bundler}" is not a valid bundler`
|
||||
throw `"${bundler}" is not a valid bundler`;
|
||||
}
|
||||
|
||||
if (v.ags[1] < v.expect[1] || v.ags[2] < v.expect[2]) {
|
||||
print(`HyprPanel needs atleast v${v.expect.join(".")} of AGS, yours is v${v.ags.join(".")}`)
|
||||
App.quit()
|
||||
print(`HyprPanel needs atleast v${v.expect.join('.')} of AGS, yours is v${v.ags.join('.')}`);
|
||||
App.quit();
|
||||
}
|
||||
|
||||
await import(`file://${main}`)
|
||||
await import(`file://${main}`);
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
App.quit()
|
||||
console.error(error);
|
||||
App.quit();
|
||||
}
|
||||
|
||||
export { }
|
||||
export {};
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
import GLib from "gi://GLib?version=2.0";
|
||||
import { Binding } from "types/service";
|
||||
import { Variable as VariableType } from "types/variable";
|
||||
|
||||
type GenericFunction = (...args: any[]) => any;
|
||||
import GLib from 'gi://GLib?version=2.0';
|
||||
import { GenericFunction } from 'lib/types/customModules/generic';
|
||||
import { Bind } from 'lib/types/variable';
|
||||
import { Variable as VariableType } from 'types/variable';
|
||||
|
||||
/**
|
||||
* @param {VariableType<T>} targetVariable - The Variable to update with the function's result.
|
||||
* @param {Array<VariableType<any>>} trackers - Array of trackers to watch.
|
||||
* @param {Binding<any, any, unknown>} pollingInterval - The polling interval in milliseconds.
|
||||
* @param {GenericFunction} someFunc - The function to execute at each interval, which updates the Variable.
|
||||
* @param {...any} params - Parameters to pass to someFunc.
|
||||
* @param {Array<Bind>} trackers - Array of trackers to watch.
|
||||
* @param {Bind} pollingInterval - The polling interval in milliseconds.
|
||||
* @param {GenericFunction<T, P>} someFunc - The function to execute at each interval, which updates the Variable.
|
||||
* @param {...P} params - Parameters to pass to someFunc.
|
||||
*/
|
||||
export const pollVariable = <T>(
|
||||
export const pollVariable = <T, P extends unknown[], F extends GenericFunction<T, P>>(
|
||||
targetVariable: VariableType<T>,
|
||||
trackers: Array<Binding<any, any, unknown>>,
|
||||
pollingInterval: Binding<any, any, unknown>,
|
||||
someFunc: GenericFunction,
|
||||
...params: any[]
|
||||
trackers: Array<Bind>,
|
||||
pollingInterval: Bind,
|
||||
someFunc: F,
|
||||
...params: P
|
||||
): void => {
|
||||
let intervalInstance: number | null = null;
|
||||
|
||||
const intervalFn = (pollIntrvl: number) => {
|
||||
const intervalFn = (pollIntrvl: number): void => {
|
||||
if (intervalInstance !== null) {
|
||||
GLib.source_remove(intervalInstance);
|
||||
}
|
||||
@@ -37,34 +36,37 @@ export const pollVariable = <T>(
|
||||
|
||||
/**
|
||||
* @param {VariableType<T>} targetVariable - The Variable to update with the result of the command.
|
||||
* @param {Binding<any, any, unknown>} pollingInterval - The polling interval in milliseconds.
|
||||
* @param {Array<Bind>} trackers - Array of trackers to watch.
|
||||
* @param {Bind} pollingInterval - The polling interval in milliseconds.
|
||||
* @param {string} someCommand - The bash command to execute.
|
||||
* @param {GenericFunction} someFunc - The function to execute after processing the command result.
|
||||
* @param {...any} params - Parameters to pass to someFunc.
|
||||
* @param {GenericFunction<T, [unknown, ...P]>} someFunc - The function to execute after processing the command result;
|
||||
* with the first argument being the result of the command execution.
|
||||
* @param {...P} params - Additional parameters to pass to someFunc.
|
||||
*/
|
||||
export const pollVariableBash = <T>(
|
||||
export const pollVariableBash = <T, P extends unknown[], F extends GenericFunction<T, [string, ...P]>>(
|
||||
targetVariable: VariableType<T>,
|
||||
trackers: Array<Binding<any, any, unknown>>,
|
||||
pollingInterval: Binding<any, any, unknown>,
|
||||
trackers: Array<Bind>,
|
||||
pollingInterval: Bind,
|
||||
someCommand: string,
|
||||
someFunc: (res: any, ...params: any[]) => T,
|
||||
...params: any[]
|
||||
someFunc: F,
|
||||
...params: P
|
||||
): void => {
|
||||
let intervalInstance: number | null = null;
|
||||
|
||||
const intervalFn = (pollIntrvl: number) => {
|
||||
const intervalFn = (pollIntrvl: number): void => {
|
||||
if (intervalInstance !== null) {
|
||||
GLib.source_remove(intervalInstance);
|
||||
}
|
||||
|
||||
intervalInstance = Utils.interval(pollIntrvl, () => {
|
||||
Utils.execAsync(`bash -c "${someCommand}"`).then((res: any) => {
|
||||
try {
|
||||
targetVariable.value = someFunc(res, ...params);
|
||||
} catch (error) {
|
||||
console.warn(`An error occurred when running interval bash function: ${error}`);
|
||||
}
|
||||
})
|
||||
Utils.execAsync(`bash -c "${someCommand}"`)
|
||||
.then((res: string) => {
|
||||
try {
|
||||
targetVariable.value = someFunc(res, ...params);
|
||||
} catch (error) {
|
||||
console.warn(`An error occurred when running interval bash function: ${error}`);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.error(`Error running command "${someCommand}": ${err}`));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,8 +2,10 @@ import { Option } from 'widget/settings/shared/Option';
|
||||
import { Header } from 'widget/settings/shared/Header';
|
||||
|
||||
import options from 'options';
|
||||
import Scrollable from 'types/widgets/scrollable';
|
||||
import { Attribute, GtkWidget } from 'lib/types/widget';
|
||||
|
||||
export const CustomModuleSettings = () =>
|
||||
export const CustomModuleSettings = (): Scrollable<GtkWidget, Attribute> =>
|
||||
Widget.Scrollable({
|
||||
vscroll: 'automatic',
|
||||
hscroll: 'automatic',
|
||||
@@ -12,11 +14,11 @@ export const CustomModuleSettings = () =>
|
||||
class_name: 'menu-theme-page paged-container',
|
||||
vertical: true,
|
||||
children: [
|
||||
/*
|
||||
************************************
|
||||
* GENERAL *
|
||||
************************************
|
||||
*/
|
||||
/*
|
||||
************************************
|
||||
* GENERAL *
|
||||
************************************
|
||||
*/
|
||||
Header('General'),
|
||||
Option({
|
||||
opt: options.bar.customModules.scrollSpeed,
|
||||
@@ -24,11 +26,11 @@ export const CustomModuleSettings = () =>
|
||||
type: 'number',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* RAM *
|
||||
************************************
|
||||
*/
|
||||
/*
|
||||
************************************
|
||||
* RAM *
|
||||
************************************
|
||||
*/
|
||||
Header('RAM'),
|
||||
Option({
|
||||
opt: options.bar.customModules.ram.label,
|
||||
@@ -75,11 +77,11 @@ export const CustomModuleSettings = () =>
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* CPU *
|
||||
************************************
|
||||
*/
|
||||
/*
|
||||
************************************
|
||||
* CPU *
|
||||
************************************
|
||||
*/
|
||||
Header('CPU'),
|
||||
Option({
|
||||
opt: options.bar.customModules.cpu.label,
|
||||
@@ -130,11 +132,11 @@ export const CustomModuleSettings = () =>
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* STORAGE *
|
||||
************************************
|
||||
*/
|
||||
/*
|
||||
************************************
|
||||
* STORAGE *
|
||||
************************************
|
||||
*/
|
||||
Header('Storage'),
|
||||
Option({
|
||||
opt: options.bar.customModules.storage.icon,
|
||||
@@ -187,11 +189,11 @@ export const CustomModuleSettings = () =>
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* NETSTAT *
|
||||
************************************
|
||||
*/
|
||||
/*
|
||||
************************************
|
||||
* NETSTAT *
|
||||
************************************
|
||||
*/
|
||||
Header('Netstat'),
|
||||
Option({
|
||||
opt: options.bar.customModules.netstat.networkInterface,
|
||||
@@ -204,17 +206,7 @@ export const CustomModuleSettings = () =>
|
||||
opt: options.bar.customModules.netstat.icon,
|
||||
title: 'Netstat Icon',
|
||||
type: 'enum',
|
||||
enums: [
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
],
|
||||
enums: ['', '', '', '', '', '', '', '', ''],
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.netstat.label,
|
||||
@@ -267,11 +259,11 @@ export const CustomModuleSettings = () =>
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* KEYBOARD LAYOUT *
|
||||
************************************
|
||||
*/
|
||||
/*
|
||||
************************************
|
||||
* KEYBOARD LAYOUT *
|
||||
************************************
|
||||
*/
|
||||
Header('Keyboard Layout'),
|
||||
Option({
|
||||
opt: options.bar.customModules.kbLayout.icon,
|
||||
@@ -321,11 +313,11 @@ export const CustomModuleSettings = () =>
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* UPDATES *
|
||||
************************************
|
||||
*/
|
||||
/*
|
||||
************************************
|
||||
* UPDATES *
|
||||
************************************
|
||||
*/
|
||||
Header('Updates'),
|
||||
Option({
|
||||
opt: options.bar.customModules.updates.updateCommand,
|
||||
@@ -336,17 +328,7 @@ export const CustomModuleSettings = () =>
|
||||
opt: options.bar.customModules.updates.icon,
|
||||
title: 'Updates Icon',
|
||||
type: 'enum',
|
||||
enums: [
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
],
|
||||
enums: ['', '', '', '', '', '', '', '', ''],
|
||||
}),
|
||||
Option({
|
||||
opt: options.bar.customModules.updates.label,
|
||||
@@ -367,7 +349,7 @@ export const CustomModuleSettings = () =>
|
||||
opt: options.bar.customModules.updates.pollingInterval,
|
||||
title: 'Polling Interval',
|
||||
type: 'number',
|
||||
subtitle: "WARNING: Be careful of your package manager\'s rate limit.",
|
||||
subtitle: "WARNING: Be careful of your package manager's rate limit.",
|
||||
min: 100,
|
||||
max: 60 * 24 * 1000,
|
||||
increment: 1000,
|
||||
@@ -398,11 +380,11 @@ export const CustomModuleSettings = () =>
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* WEATHER *
|
||||
************************************
|
||||
*/
|
||||
/*
|
||||
************************************
|
||||
* WEATHER *
|
||||
************************************
|
||||
*/
|
||||
Header('Weather'),
|
||||
Option({
|
||||
opt: options.bar.customModules.weather.label,
|
||||
@@ -446,11 +428,11 @@ export const CustomModuleSettings = () =>
|
||||
type: 'string',
|
||||
}),
|
||||
|
||||
/*
|
||||
************************************
|
||||
* POWER *
|
||||
************************************
|
||||
*/
|
||||
/*
|
||||
************************************
|
||||
* POWER *
|
||||
************************************
|
||||
*/
|
||||
Header('Power'),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.power.spacing,
|
||||
@@ -491,4 +473,3 @@ export const CustomModuleSettings = () =>
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: This import is a special directive that tells the compiler to use the GTop library
|
||||
import GTop from 'gi://GTop';
|
||||
|
||||
let previousCpuData = new GTop.glibtop_cpu();
|
||||
GTop.glibtop_get_cpu(previousCpuData);
|
||||
|
||||
export const computeCPU = () => {
|
||||
export const computeCPU = (): number => {
|
||||
const currentCpuData = new GTop.glibtop_cpu();
|
||||
GTop.glibtop_get_cpu(currentCpuData);
|
||||
|
||||
@@ -17,5 +17,4 @@ export const computeCPU = () => {
|
||||
previousCpuData = currentCpuData;
|
||||
|
||||
return cpuUsagePercentage;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -1,28 +1,21 @@
|
||||
import options from "options";
|
||||
import options from 'options';
|
||||
|
||||
// Module initializer
|
||||
import { module } from "../module"
|
||||
import { module } from '../module';
|
||||
|
||||
// import { CpuData } from "lib/types/customModules/cpu";
|
||||
import Button from "types/widgets/button";
|
||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
||||
import Button from 'types/widgets/button';
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||
|
||||
// Utility Methods
|
||||
import { inputHandler } from "customModules/utils";
|
||||
import { computeCPU } from "./computeCPU";
|
||||
import { pollVariable } from "customModules/PollVar";
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import { computeCPU } from './computeCPU';
|
||||
import { pollVariable } from 'customModules/PollVar';
|
||||
import { Module } from 'lib/types/bar';
|
||||
|
||||
// All the user configurable options for the cpu module that are needed
|
||||
const {
|
||||
label,
|
||||
round,
|
||||
leftClick,
|
||||
rightClick,
|
||||
middleClick,
|
||||
scrollUp,
|
||||
scrollDown,
|
||||
pollingInterval
|
||||
} = options.bar.customModules.cpu;
|
||||
const { label, round, leftClick, rightClick, middleClick, scrollUp, scrollDown, pollingInterval } =
|
||||
options.bar.customModules.cpu;
|
||||
|
||||
export const cpuUsage = Variable(0);
|
||||
|
||||
@@ -37,21 +30,19 @@ pollVariable(
|
||||
computeCPU,
|
||||
);
|
||||
|
||||
export const Cpu = () => {
|
||||
const renderLabel = (cpuUsg: number, rnd: boolean) => {
|
||||
export const Cpu = (): Module => {
|
||||
const renderLabel = (cpuUsg: number, rnd: boolean): string => {
|
||||
return rnd ? `${Math.round(cpuUsg)}%` : `${cpuUsg.toFixed(2)}%`;
|
||||
}
|
||||
};
|
||||
|
||||
const cpuModule = module({
|
||||
textIcon: "",
|
||||
label: Utils.merge(
|
||||
[cpuUsage.bind("value"), round.bind("value")],
|
||||
(cpuUsg, rnd) => {
|
||||
return renderLabel(cpuUsg, rnd);
|
||||
}),
|
||||
tooltipText: "CPU",
|
||||
boxClass: "cpu",
|
||||
showLabelBinding: label.bind("value"),
|
||||
textIcon: '',
|
||||
label: Utils.merge([cpuUsage.bind('value'), round.bind('value')], (cpuUsg, rnd) => {
|
||||
return renderLabel(cpuUsg, rnd);
|
||||
}),
|
||||
tooltipText: 'CPU',
|
||||
boxClass: 'cpu',
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||
inputHandler(self, {
|
||||
@@ -72,9 +63,8 @@ export const Cpu = () => {
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return cpuModule;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import { HyprctlDeviceLayout, HyprctlKeyboard, KbLabelType, LayoutKeys, LayoutValues } from "lib/types/customModules/kbLayout";
|
||||
import { layoutMap } from "./layouts";
|
||||
import {
|
||||
HyprctlDeviceLayout,
|
||||
HyprctlKeyboard,
|
||||
KbLabelType,
|
||||
LayoutKeys,
|
||||
LayoutValues,
|
||||
} from 'lib/types/customModules/kbLayout';
|
||||
import { layoutMap } from './layouts';
|
||||
|
||||
export const getKeyboardLayout = (obj: string, format: KbLabelType) => {
|
||||
let hyprctlDevices: HyprctlDeviceLayout = JSON.parse(obj);
|
||||
let keyboards = hyprctlDevices['keyboards'];
|
||||
export const getKeyboardLayout = (obj: string, format: KbLabelType): LayoutKeys | LayoutValues => {
|
||||
const hyprctlDevices: HyprctlDeviceLayout = JSON.parse(obj);
|
||||
const keyboards = hyprctlDevices['keyboards'];
|
||||
|
||||
if (keyboards.length === 0) {
|
||||
return "No KB!"
|
||||
return format === 'code' ? 'Unknown' : 'Unknown Layout';
|
||||
}
|
||||
|
||||
let mainKb = keyboards.find((kb: HyprctlKeyboard) => kb.main);
|
||||
@@ -15,8 +21,8 @@ export const getKeyboardLayout = (obj: string, format: KbLabelType) => {
|
||||
mainKb = keyboards[keyboards.length - 1];
|
||||
}
|
||||
|
||||
let layout: LayoutKeys = mainKb['active_keymap'] as LayoutKeys;
|
||||
const layout: LayoutKeys = mainKb['active_keymap'] as LayoutKeys;
|
||||
const foundLayout: LayoutValues = layoutMap[layout];
|
||||
|
||||
return format === "code" ? foundLayout || layout : layout;
|
||||
}
|
||||
return format === 'code' ? foundLayout || layout : layout;
|
||||
};
|
||||
|
||||
@@ -1,49 +1,50 @@
|
||||
const hyprland = await Service.import("hyprland");
|
||||
const hyprland = await Service.import('hyprland');
|
||||
|
||||
import options from "options";
|
||||
import { module } from "../module"
|
||||
import options from 'options';
|
||||
import { module } from '../module';
|
||||
|
||||
import { inputHandler } from "customModules/utils";
|
||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
||||
import Button from "types/widgets/button";
|
||||
import Label from "types/widgets/label";
|
||||
import { getKeyboardLayout } from "./getLayout";
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||
import Button from 'types/widgets/button';
|
||||
import Label from 'types/widgets/label';
|
||||
import { getKeyboardLayout } from './getLayout';
|
||||
import { Module } from 'lib/types/bar';
|
||||
|
||||
const {
|
||||
label,
|
||||
labelType,
|
||||
icon,
|
||||
leftClick,
|
||||
rightClick,
|
||||
middleClick,
|
||||
scrollUp,
|
||||
scrollDown,
|
||||
} = options.bar.customModules.kbLayout;
|
||||
const { label, labelType, icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } =
|
||||
options.bar.customModules.kbLayout;
|
||||
|
||||
export const KbInput = () => {
|
||||
export const KbInput = (): Module => {
|
||||
const keyboardModule = module({
|
||||
textIcon: icon.bind("value"),
|
||||
tooltipText: "",
|
||||
textIcon: icon.bind('value'),
|
||||
tooltipText: '',
|
||||
labelHook: (self: Label<Gtk.Widget>): void => {
|
||||
self.hook(hyprland, () => {
|
||||
Utils.execAsync('hyprctl devices -j')
|
||||
.then((obj) => {
|
||||
self.label = getKeyboardLayout(obj, labelType.value);
|
||||
})
|
||||
.catch((err) => { console.error(err); });
|
||||
}, "keyboard-layout");
|
||||
self.hook(
|
||||
hyprland,
|
||||
() => {
|
||||
Utils.execAsync('hyprctl devices -j')
|
||||
.then((obj) => {
|
||||
self.label = getKeyboardLayout(obj, labelType.value);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
},
|
||||
'keyboard-layout',
|
||||
);
|
||||
|
||||
self.hook(labelType, () => {
|
||||
Utils.execAsync('hyprctl devices -j')
|
||||
.then((obj) => {
|
||||
self.label = getKeyboardLayout(obj, labelType.value);
|
||||
})
|
||||
.catch((err) => { console.error(err); });
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
boxClass: "kblayout",
|
||||
showLabelBinding: label.bind("value"),
|
||||
boxClass: 'kblayout',
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||
inputHandler(self, {
|
||||
@@ -68,6 +69,4 @@ export const KbInput = () => {
|
||||
});
|
||||
|
||||
return keyboardModule;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
import { Module } from "lib/types/bar";
|
||||
import { BarButtonStyles } from "lib/types/options";
|
||||
import options from "options";
|
||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
||||
import { Binding } from "types/service";
|
||||
import { Variable as VariableType } from "types/variable";
|
||||
import { BarBoxChild, Module } from 'lib/types/bar';
|
||||
import { BarButtonStyles } from 'lib/types/options';
|
||||
import { Bind } from 'lib/types/variable';
|
||||
import { GtkWidget } from 'lib/types/widget';
|
||||
import options from 'options';
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||
|
||||
const { style } = options.theme.bar.buttons;
|
||||
|
||||
@@ -16,69 +16,69 @@ export const module = ({
|
||||
tooltipText,
|
||||
boxClass,
|
||||
props = {},
|
||||
showLabelBinding = undefinedVar.bind("value"),
|
||||
showLabelBinding = undefinedVar.bind('value'),
|
||||
showLabel,
|
||||
labelHook,
|
||||
hook
|
||||
}: Module) => {
|
||||
const getIconWidget = () => {
|
||||
hook,
|
||||
}: Module): BarBoxChild => {
|
||||
const getIconWidget = (): GtkWidget | undefined => {
|
||||
let iconWidget: Gtk.Widget | undefined;
|
||||
|
||||
if (icon !== undefined) {
|
||||
iconWidget = Widget.Icon({
|
||||
class_name: `txt-icon bar-button-icon module-icon ${boxClass}`,
|
||||
icon: icon
|
||||
icon: icon,
|
||||
}) as unknown as Gtk.Widget;
|
||||
} else if (textIcon !== undefined) {
|
||||
iconWidget = Widget.Label({
|
||||
class_name: `txt-icon bar-button-icon module-icon ${boxClass}`,
|
||||
label: textIcon
|
||||
label: textIcon,
|
||||
}) as unknown as Gtk.Widget;
|
||||
}
|
||||
|
||||
return iconWidget;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
className: Utils.merge([style.bind("value"), showLabelBinding], (style: BarButtonStyles, shwLabel: boolean) => {
|
||||
const shouldShowLabel = shwLabel || showLabel;
|
||||
const styleMap = {
|
||||
default: "style1",
|
||||
split: "style2",
|
||||
wave: "style3",
|
||||
wave2: "style3",
|
||||
};
|
||||
return `${boxClass} ${styleMap[style]} ${!shouldShowLabel ? "no-label" : ""}`;
|
||||
}),
|
||||
className: Utils.merge(
|
||||
[style.bind('value'), showLabelBinding],
|
||||
(style: BarButtonStyles, shwLabel: boolean) => {
|
||||
const shouldShowLabel = shwLabel || showLabel;
|
||||
const styleMap = {
|
||||
default: 'style1',
|
||||
split: 'style2',
|
||||
wave: 'style3',
|
||||
wave2: 'style3',
|
||||
};
|
||||
return `${boxClass} ${styleMap[style]} ${!shouldShowLabel ? 'no-label' : ''}`;
|
||||
},
|
||||
),
|
||||
tooltip_text: tooltipText,
|
||||
children: Utils.merge(
|
||||
[showLabelBinding],
|
||||
(showLabelBinding): Gtk.Widget[] => {
|
||||
const childrenArray: Gtk.Widget[] = [];
|
||||
const iconWidget = getIconWidget();
|
||||
children: Utils.merge([showLabelBinding], (showLabelBinding): Gtk.Widget[] => {
|
||||
const childrenArray: Gtk.Widget[] = [];
|
||||
const iconWidget = getIconWidget();
|
||||
|
||||
if (iconWidget !== undefined) {
|
||||
childrenArray.push(iconWidget);
|
||||
}
|
||||
|
||||
if (showLabelBinding) {
|
||||
childrenArray.push(
|
||||
Widget.Label({
|
||||
class_name: `bar-button-label module-label ${boxClass}`,
|
||||
label: label,
|
||||
setup: labelHook,
|
||||
}) as unknown as Gtk.Widget
|
||||
);
|
||||
}
|
||||
return childrenArray;
|
||||
if (iconWidget !== undefined) {
|
||||
childrenArray.push(iconWidget);
|
||||
}
|
||||
) as Binding<VariableType<Gtk.Widget[]>, any, Gtk.Widget[]>,
|
||||
|
||||
if (showLabelBinding) {
|
||||
childrenArray.push(
|
||||
Widget.Label({
|
||||
class_name: `bar-button-label module-label ${boxClass}`,
|
||||
label: label,
|
||||
setup: labelHook,
|
||||
}) as unknown as Gtk.Widget,
|
||||
);
|
||||
}
|
||||
return childrenArray;
|
||||
}) as Bind,
|
||||
setup: hook,
|
||||
}),
|
||||
tooltip_text: tooltipText,
|
||||
isVisible: true,
|
||||
boxClass,
|
||||
props
|
||||
props,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -71,7 +71,11 @@ const getNetworkUsage = (interfaceName: string = ''): NetworkUsage => {
|
||||
return { name: '', rx: 0, tx: 0 };
|
||||
};
|
||||
|
||||
export const computeNetwork = (round: VariableType<boolean>, interfaceNameVar: VariableType<string>, dataType: VariableType<RateUnit>): NetworkResourceData => {
|
||||
export const computeNetwork = (
|
||||
round: VariableType<boolean>,
|
||||
interfaceNameVar: VariableType<string>,
|
||||
dataType: VariableType<RateUnit>,
|
||||
): NetworkResourceData => {
|
||||
const rateUnit = dataType.value;
|
||||
const interfaceName = interfaceNameVar ? interfaceNameVar.value : '';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import options from 'options';
|
||||
import { module } from '../module';
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import { computeNetwork } from './computeNetwork';
|
||||
import { NetstatLabelType } from 'lib/types/bar';
|
||||
import { Module, NetstatLabelType } from 'lib/types/bar';
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||
import Button from 'types/widgets/button';
|
||||
import { NetworkResourceData } from 'lib/types/customModules/network';
|
||||
@@ -23,9 +23,7 @@ const {
|
||||
pollingInterval,
|
||||
} = options.bar.customModules.netstat;
|
||||
|
||||
export const networkUsage = Variable<NetworkResourceData>(
|
||||
GET_DEFAULT_NETSTAT_DATA(rateUnit.value),
|
||||
);
|
||||
export const networkUsage = Variable<NetworkResourceData>(GET_DEFAULT_NETSTAT_DATA(rateUnit.value));
|
||||
|
||||
pollVariable(
|
||||
// Variable to poll and update with the result of the function passed in
|
||||
@@ -48,11 +46,8 @@ pollVariable(
|
||||
rateUnit,
|
||||
);
|
||||
|
||||
export const Netstat = () => {
|
||||
const renderNetworkLabel = (
|
||||
lblType: NetstatLabelType,
|
||||
network: NetworkResourceData,
|
||||
): string => {
|
||||
export const Netstat = (): Module => {
|
||||
const renderNetworkLabel = (lblType: NetstatLabelType, network: NetworkResourceData): string => {
|
||||
switch (lblType) {
|
||||
case 'in':
|
||||
return `↓ ${network.in}`;
|
||||
@@ -88,19 +83,17 @@ export const Netstat = () => {
|
||||
},
|
||||
onScrollUp: {
|
||||
fn: () => {
|
||||
labelType.value =
|
||||
NETWORK_LABEL_TYPES[
|
||||
labelType.value = NETWORK_LABEL_TYPES[
|
||||
(NETWORK_LABEL_TYPES.indexOf(labelType.value) + 1) % NETWORK_LABEL_TYPES.length
|
||||
] as NetstatLabelType;
|
||||
] as NetstatLabelType;
|
||||
},
|
||||
},
|
||||
onScrollDown: {
|
||||
fn: () => {
|
||||
labelType.value =
|
||||
NETWORK_LABEL_TYPES[
|
||||
labelType.value = NETWORK_LABEL_TYPES[
|
||||
(NETWORK_LABEL_TYPES.indexOf(labelType.value) - 1 + NETWORK_LABEL_TYPES.length) %
|
||||
NETWORK_LABEL_TYPES.length
|
||||
] as NetstatLabelType;
|
||||
NETWORK_LABEL_TYPES.length
|
||||
] as NetstatLabelType;
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -110,4 +103,3 @@ export const Netstat = () => {
|
||||
|
||||
return netstatModule;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
import options from "options";
|
||||
import { module } from "../module"
|
||||
import options from 'options';
|
||||
import { module } from '../module';
|
||||
|
||||
import { inputHandler } from "customModules/utils";
|
||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
||||
import Button from "types/widgets/button";
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||
import Button from 'types/widgets/button';
|
||||
import { Module } from 'lib/types/bar';
|
||||
|
||||
const {
|
||||
icon,
|
||||
leftClick,
|
||||
rightClick,
|
||||
middleClick,
|
||||
scrollUp,
|
||||
scrollDown,
|
||||
} = options.bar.customModules.power;
|
||||
const { icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.power;
|
||||
|
||||
export const Power = () => {
|
||||
export const Power = (): Module => {
|
||||
const powerModule = module({
|
||||
tooltipText: "Power Menu",
|
||||
textIcon: icon.bind("value"),
|
||||
boxClass: "powermodule",
|
||||
tooltipText: 'Power Menu',
|
||||
textIcon: icon.bind('value'),
|
||||
boxClass: 'powermodule',
|
||||
props: {
|
||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||
inputHandler(self, {
|
||||
@@ -43,4 +37,4 @@ export const Power = () => {
|
||||
});
|
||||
|
||||
return powerModule;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
const GLib = imports.gi.GLib;
|
||||
|
||||
import { divide } from 'customModules/utils';
|
||||
import { GenericResourceData } from 'lib/types/customModules/generic';
|
||||
import { Variable as VariableType } from 'types/variable';
|
||||
|
||||
export const calculateRamUsage = (round: VariableType<boolean>) => {
|
||||
export const calculateRamUsage = (round: VariableType<boolean>): GenericResourceData => {
|
||||
try {
|
||||
const [success, meminfoBytes] = GLib.file_get_contents('/proc/meminfo');
|
||||
|
||||
@@ -26,17 +27,14 @@ export const calculateRamUsage = (round: VariableType<boolean>) => {
|
||||
let usedRam = totalRamInBytes - availableRamInBytes;
|
||||
usedRam = isNaN(usedRam) || usedRam < 0 ? 0 : usedRam;
|
||||
|
||||
|
||||
return {
|
||||
percentage: divide([totalRamInBytes, usedRam], round.value),
|
||||
total: totalRamInBytes,
|
||||
used: usedRam,
|
||||
free: availableRamInBytes,
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error calculating RAM usage:', error);
|
||||
return { total: 0, used: 0, percentage: 0 };
|
||||
return { total: 0, used: 0, percentage: 0, free: 0 };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,62 +1,48 @@
|
||||
import options from "options";
|
||||
import options from 'options';
|
||||
|
||||
// Module initializer
|
||||
import { module } from "../module"
|
||||
import { module } from '../module';
|
||||
|
||||
// Types
|
||||
import { GenericResourceData } from "lib/types/customModules/generic";
|
||||
import Button from "types/widgets/button";
|
||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
||||
import { GenericResourceData } from 'lib/types/customModules/generic';
|
||||
import Button from 'types/widgets/button';
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||
|
||||
// Helper Methods
|
||||
import { calculateRamUsage } from "./computeRam";
|
||||
import { calculateRamUsage } from './computeRam';
|
||||
|
||||
// Utility Methods
|
||||
import { formatTooltip, inputHandler, renderResourceLabel } from "customModules/utils";
|
||||
import { ResourceLabelType } from "lib/types/bar";
|
||||
import { formatTooltip, inputHandler, renderResourceLabel } from 'customModules/utils';
|
||||
import { Module, ResourceLabelType } from 'lib/types/bar';
|
||||
|
||||
// Global Constants
|
||||
import { LABEL_TYPES } from "lib/types/defaults/bar";
|
||||
import { pollVariable } from "customModules/PollVar";
|
||||
import { LABEL_TYPES } from 'lib/types/defaults/bar';
|
||||
import { pollVariable } from 'customModules/PollVar';
|
||||
|
||||
// All the user configurable options for the ram module that are needed
|
||||
const {
|
||||
label,
|
||||
labelType,
|
||||
round,
|
||||
leftClick,
|
||||
rightClick,
|
||||
middleClick,
|
||||
pollingInterval
|
||||
} = options.bar.customModules.ram;
|
||||
const { label, labelType, round, leftClick, rightClick, middleClick, pollingInterval } = options.bar.customModules.ram;
|
||||
|
||||
const defaultRamData: GenericResourceData = { total: 0, used: 0, percentage: 0, free: 0 };
|
||||
const ramUsage = Variable(defaultRamData);
|
||||
const ramUsage = Variable<GenericResourceData>(defaultRamData);
|
||||
|
||||
pollVariable(
|
||||
ramUsage,
|
||||
[round.bind('value')],
|
||||
pollingInterval.bind('value'),
|
||||
calculateRamUsage,
|
||||
round,
|
||||
);
|
||||
|
||||
export const Ram = () => {
|
||||
pollVariable(ramUsage, [round.bind('value')], pollingInterval.bind('value'), calculateRamUsage, round);
|
||||
|
||||
export const Ram = (): Module => {
|
||||
const ramModule = module({
|
||||
textIcon: "",
|
||||
textIcon: '',
|
||||
label: Utils.merge(
|
||||
[ramUsage.bind("value"), labelType.bind("value"), round.bind("value")],
|
||||
[ramUsage.bind('value'), labelType.bind('value'), round.bind('value')],
|
||||
(rmUsg: GenericResourceData, lblTyp: ResourceLabelType, round: boolean) => {
|
||||
const returnValue = renderResourceLabel(lblTyp, rmUsg, round);
|
||||
|
||||
return returnValue;
|
||||
}),
|
||||
tooltipText: labelType.bind("value").as(lblTyp => {
|
||||
},
|
||||
),
|
||||
tooltipText: labelType.bind('value').as((lblTyp) => {
|
||||
return formatTooltip('RAM', lblTyp);
|
||||
}),
|
||||
boxClass: "ram",
|
||||
showLabelBinding: label.bind("value"),
|
||||
boxClass: 'ram',
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||
inputHandler(self, {
|
||||
@@ -71,18 +57,22 @@ export const Ram = () => {
|
||||
},
|
||||
onScrollUp: {
|
||||
fn: () => {
|
||||
labelType.value = LABEL_TYPES[(LABEL_TYPES.indexOf(labelType.value) + 1) % LABEL_TYPES.length] as ResourceLabelType;
|
||||
}
|
||||
labelType.value = LABEL_TYPES[
|
||||
(LABEL_TYPES.indexOf(labelType.value) + 1) % LABEL_TYPES.length
|
||||
] as ResourceLabelType;
|
||||
},
|
||||
},
|
||||
onScrollDown: {
|
||||
fn: () => {
|
||||
labelType.value = LABEL_TYPES[(LABEL_TYPES.indexOf(labelType.value) - 1 + LABEL_TYPES.length) % LABEL_TYPES.length] as ResourceLabelType;
|
||||
}
|
||||
labelType.value = LABEL_TYPES[
|
||||
(LABEL_TYPES.indexOf(labelType.value) - 1 + LABEL_TYPES.length) % LABEL_TYPES.length
|
||||
] as ResourceLabelType;
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return ramModule;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error is a special directive that tells the compiler to use the GTop library
|
||||
import GTop from 'gi://GTop';
|
||||
|
||||
import { divide } from 'customModules/utils';
|
||||
import { Variable as VariableType } from 'types/variable';
|
||||
import { GenericResourceData } from 'lib/types/customModules/generic';
|
||||
|
||||
let previousFsUsage = new GTop.glibtop_fsusage();
|
||||
|
||||
export const computeStorage = (round: VariableType<boolean>) => {
|
||||
export const computeStorage = (round: VariableType<boolean>): GenericResourceData => {
|
||||
try {
|
||||
const currentFsUsage = new GTop.glibtop_fsusage();
|
||||
|
||||
GTop.glibtop_get_fsusage(currentFsUsage, "/");
|
||||
GTop.glibtop_get_fsusage(currentFsUsage, '/');
|
||||
|
||||
const total = currentFsUsage.blocks * currentFsUsage.block_size;
|
||||
const available = currentFsUsage.bavail * currentFsUsage.block_size;
|
||||
const used = total - available;
|
||||
|
||||
previousFsUsage = currentFsUsage;
|
||||
|
||||
return {
|
||||
total,
|
||||
used,
|
||||
@@ -26,7 +23,6 @@ export const computeStorage = (round: VariableType<boolean>) => {
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error calculating RAM usage:', error);
|
||||
return { total: 0, used: 0, percentage: 0 };
|
||||
return { total: 0, used: 0, percentage: 0, free: 0 };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,52 +1,38 @@
|
||||
import options from "options";
|
||||
import { module } from "../module"
|
||||
import options from 'options';
|
||||
import { module } from '../module';
|
||||
|
||||
import { formatTooltip, inputHandler, renderResourceLabel } from "customModules/utils";
|
||||
import { computeStorage } from "./computeStorage";
|
||||
import { ResourceLabelType } from "lib/types/bar";
|
||||
import { GenericResourceData } from "lib/types/customModules/generic";
|
||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
||||
import Button from "types/widgets/button";
|
||||
import { LABEL_TYPES } from "lib/types/defaults/bar";
|
||||
import { pollVariable } from "customModules/PollVar";
|
||||
import { formatTooltip, inputHandler, renderResourceLabel } from 'customModules/utils';
|
||||
import { computeStorage } from './computeStorage';
|
||||
import { Module, ResourceLabelType } from 'lib/types/bar';
|
||||
import { GenericResourceData } from 'lib/types/customModules/generic';
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||
import Button from 'types/widgets/button';
|
||||
import { LABEL_TYPES } from 'lib/types/defaults/bar';
|
||||
import { pollVariable } from 'customModules/PollVar';
|
||||
|
||||
const {
|
||||
label,
|
||||
labelType,
|
||||
icon,
|
||||
round,
|
||||
leftClick,
|
||||
rightClick,
|
||||
middleClick,
|
||||
pollingInterval
|
||||
} = options.bar.customModules.storage;
|
||||
const { label, labelType, icon, round, leftClick, rightClick, middleClick, pollingInterval } =
|
||||
options.bar.customModules.storage;
|
||||
|
||||
const defaultStorageData = { total: 0, used: 0, percentage: 0, free: 0 };
|
||||
|
||||
const storageUsage = Variable(defaultStorageData);
|
||||
const storageUsage = Variable<GenericResourceData>(defaultStorageData);
|
||||
|
||||
pollVariable(
|
||||
storageUsage,
|
||||
[round.bind('value')],
|
||||
pollingInterval.bind('value'),
|
||||
computeStorage,
|
||||
round,
|
||||
);
|
||||
pollVariable(storageUsage, [round.bind('value')], pollingInterval.bind('value'), computeStorage, round);
|
||||
|
||||
export const Storage = () => {
|
||||
export const Storage = (): Module => {
|
||||
const storageModule = module({
|
||||
textIcon: icon.bind("value"),
|
||||
textIcon: icon.bind('value'),
|
||||
label: Utils.merge(
|
||||
[storageUsage.bind("value"), labelType.bind("value"), round.bind("value")],
|
||||
[storageUsage.bind('value'), labelType.bind('value'), round.bind('value')],
|
||||
(storage: GenericResourceData, lblTyp: ResourceLabelType, round: boolean) => {
|
||||
return renderResourceLabel(lblTyp, storage, round);
|
||||
}),
|
||||
tooltipText: labelType.bind("value").as(lblTyp => {
|
||||
},
|
||||
),
|
||||
tooltipText: labelType.bind('value').as((lblTyp) => {
|
||||
return formatTooltip('Storage', lblTyp);
|
||||
|
||||
}),
|
||||
boxClass: "storage",
|
||||
showLabelBinding: label.bind("value"),
|
||||
boxClass: 'storage',
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||
inputHandler(self, {
|
||||
@@ -61,18 +47,22 @@ export const Storage = () => {
|
||||
},
|
||||
onScrollUp: {
|
||||
fn: () => {
|
||||
labelType.value = LABEL_TYPES[(LABEL_TYPES.indexOf(labelType.value) + 1) % LABEL_TYPES.length] as ResourceLabelType;
|
||||
}
|
||||
labelType.value = LABEL_TYPES[
|
||||
(LABEL_TYPES.indexOf(labelType.value) + 1) % LABEL_TYPES.length
|
||||
] as ResourceLabelType;
|
||||
},
|
||||
},
|
||||
onScrollDown: {
|
||||
fn: () => {
|
||||
labelType.value = LABEL_TYPES[(LABEL_TYPES.indexOf(labelType.value) - 1 + LABEL_TYPES.length) % LABEL_TYPES.length] as ResourceLabelType;
|
||||
}
|
||||
labelType.value = LABEL_TYPES[
|
||||
(LABEL_TYPES.indexOf(labelType.value) - 1 + LABEL_TYPES.length) % LABEL_TYPES.length
|
||||
] as ResourceLabelType;
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return storageModule;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,106 +1,146 @@
|
||||
import { Option } from "widget/settings/shared/Option";
|
||||
import { Header } from "widget/settings/shared/Header";
|
||||
import { Option } from 'widget/settings/shared/Option';
|
||||
import { Header } from 'widget/settings/shared/Header';
|
||||
|
||||
import options from "options";
|
||||
import options from 'options';
|
||||
import Scrollable from 'types/widgets/scrollable';
|
||||
import { Attribute, GtkWidget } from 'lib/types/widget';
|
||||
|
||||
export const CustomModuleTheme = () => {
|
||||
export const CustomModuleTheme = (): Scrollable<GtkWidget, Attribute> => {
|
||||
return Widget.Scrollable({
|
||||
vscroll: "automatic",
|
||||
hscroll: "automatic",
|
||||
class_name: "menu-theme-page customModules paged-container",
|
||||
vscroll: 'automatic',
|
||||
hscroll: 'automatic',
|
||||
class_name: 'menu-theme-page customModules paged-container',
|
||||
child: Widget.Box({
|
||||
class_name: "bar-theme-page paged-container",
|
||||
class_name: 'bar-theme-page paged-container',
|
||||
vertical: true,
|
||||
children: [
|
||||
Header('RAM'),
|
||||
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.background, title: 'Label Background', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.ram.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.ram.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
||||
type: 'color'
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
|
||||
Header('CPU'),
|
||||
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.background, title: 'Label Background', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.cpu.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.cpu.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
||||
type: 'color'
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
|
||||
Header('Storage'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.storage.text, title: 'Text', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.storage.icon, title: 'Icon', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.storage.background, title: 'Label Background', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.storage.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.storage.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
||||
type: 'color'
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
|
||||
Header('Netstat'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.netstat.text, title: 'Text', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.netstat.icon, title: 'Icon', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.netstat.background, title: 'Label Background', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.netstat.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.netstat.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
||||
type: 'color'
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
|
||||
Header('Keyboard Layout'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.kbLayout.text, title: 'Text', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.kbLayout.icon, title: 'Icon', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.kbLayout.background, title: 'Label Background', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.kbLayout.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.kbLayout.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
||||
type: 'color'
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
|
||||
Header('Updates'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.updates.text, title: 'Text', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.updates.icon, title: 'Icon', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.updates.background, title: 'Label Background', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.updates.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.updates.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
||||
type: 'color'
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
|
||||
Header('Weather'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.weather.icon, title: 'Icon', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.weather.text, title: 'Text', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.weather.background, title: 'Label Background', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.weather.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.weather.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
||||
type: 'color'
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
|
||||
Header('Power'),
|
||||
Option({ opt: options.theme.bar.buttons.modules.power.icon, title: 'Icon', type: 'color' }),
|
||||
Option({ opt: options.theme.bar.buttons.modules.power.background, title: 'Label Background', type: 'color' }),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.power.background,
|
||||
title: 'Label Background',
|
||||
type: 'color',
|
||||
}),
|
||||
Option({
|
||||
opt: options.theme.bar.buttons.modules.power.icon_background,
|
||||
title: 'Icon Background',
|
||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
||||
type: 'color'
|
||||
subtitle:
|
||||
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||
type: 'color',
|
||||
}),
|
||||
]
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
],
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import options from "options";
|
||||
import { module } from "../module"
|
||||
import options from 'options';
|
||||
import { module } from '../module';
|
||||
|
||||
import { inputHandler } from "customModules/utils";
|
||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
||||
import Button from "types/widgets/button";
|
||||
import { Variable as VariableType } from "types/variable";
|
||||
import { pollVariableBash } from "customModules/PollVar";
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||
import Button from 'types/widgets/button';
|
||||
import { Variable as VariableType } from 'types/variable';
|
||||
import { pollVariableBash } from 'customModules/PollVar';
|
||||
import { Module } from 'lib/types/bar';
|
||||
|
||||
const {
|
||||
updateCommand,
|
||||
@@ -20,12 +21,12 @@ const {
|
||||
scrollDown,
|
||||
} = options.bar.customModules.updates;
|
||||
|
||||
const pendingUpdates: VariableType<string> = Variable(" 0");
|
||||
const pendingUpdates: VariableType<string> = Variable(' 0');
|
||||
|
||||
const processUpdateCount = (updateCount: string) => {
|
||||
const processUpdateCount = (updateCount: string): string => {
|
||||
if (!padZero.value) return updateCount;
|
||||
return `${updateCount.padStart(2, '0')}`;
|
||||
}
|
||||
};
|
||||
|
||||
pollVariableBash(
|
||||
pendingUpdates,
|
||||
@@ -35,13 +36,13 @@ pollVariableBash(
|
||||
processUpdateCount,
|
||||
);
|
||||
|
||||
export const Updates = () => {
|
||||
export const Updates = (): Module => {
|
||||
const updatesModule = module({
|
||||
textIcon: icon.bind("value"),
|
||||
tooltipText: pendingUpdates.bind("value").as(v => `${v} updates available`),
|
||||
boxClass: "updates",
|
||||
label: pendingUpdates.bind("value"),
|
||||
showLabelBinding: label.bind("value"),
|
||||
textIcon: icon.bind('value'),
|
||||
tooltipText: pendingUpdates.bind('value').as((v) => `${v} updates available`),
|
||||
boxClass: 'updates',
|
||||
label: pendingUpdates.bind('value'),
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||
inputHandler(self, {
|
||||
@@ -66,7 +67,4 @@ export const Updates = () => {
|
||||
});
|
||||
|
||||
return updatesModule;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { ResourceLabelType } from 'lib/types/bar';
|
||||
import { GenericResourceData } from 'lib/types/customModules/generic';
|
||||
import { GenericResourceData, Postfix } from 'lib/types/customModules/generic';
|
||||
import { InputHandlerEvents } from 'lib/types/customModules/utils';
|
||||
import { ThrottleFn, ThrottleFnCallback } from 'lib/types/utils';
|
||||
import { GtkWidget } from 'lib/types/widget';
|
||||
import { Binding } from 'lib/utils';
|
||||
import { openMenu } from 'modules/bar/utils';
|
||||
import options from 'options';
|
||||
@@ -13,14 +15,11 @@ const { scrollSpeed } = options.bar.customModules;
|
||||
|
||||
export const runAsyncCommand = (
|
||||
cmd: string,
|
||||
fn: Function,
|
||||
events: { clicked: any; event: Gdk.Event }
|
||||
fn: (output: string) => void,
|
||||
events: { clicked: Button<GtkWidget, GtkWidget>; event: Gdk.Event },
|
||||
): void => {
|
||||
if (cmd.startsWith('menu:')) {
|
||||
// if the command starts with 'menu:', then it is a menu command
|
||||
// and we should App.toggleMenu("menuName") based on the input menu:menuName. Ignoring spaces and case
|
||||
const menuName = cmd.split(':')[1].trim().toLowerCase();
|
||||
|
||||
openMenu(events.clicked, events.event, `${menuName}menu`);
|
||||
|
||||
return;
|
||||
@@ -32,15 +31,10 @@ export const runAsyncCommand = (
|
||||
fn(output);
|
||||
}
|
||||
})
|
||||
.catch((err) =>
|
||||
console.error(`Error running command "${cmd}": ${err})`)
|
||||
);
|
||||
.catch((err) => console.error(`Error running command "${cmd}": ${err})`));
|
||||
};
|
||||
|
||||
export function throttle<T extends (...args: any[]) => void>(
|
||||
func: T,
|
||||
limit: number
|
||||
): T {
|
||||
export function throttle<T extends ThrottleFn>(func: T, limit: number): T {
|
||||
let inThrottle: boolean;
|
||||
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
|
||||
if (!inThrottle) {
|
||||
@@ -53,31 +47,23 @@ export function throttle<T extends (...args: any[]) => void>(
|
||||
} as T;
|
||||
}
|
||||
|
||||
export const throttledScrollHandler = (interval: number) =>
|
||||
throttle((cmd: string, fn: Function | undefined) => {
|
||||
export const throttledScrollHandler = (interval: number): ThrottleFn =>
|
||||
throttle((cmd: string, fn: ThrottleFnCallback) => {
|
||||
Utils.execAsync(`bash -c "${cmd}"`)
|
||||
.then((output) => {
|
||||
if (fn !== undefined) {
|
||||
fn(output);
|
||||
}
|
||||
})
|
||||
.catch((err) =>
|
||||
console.error(`Error running command "${cmd}": ${err}`)
|
||||
);
|
||||
.catch((err) => console.error(`Error running command "${cmd}": ${err}`));
|
||||
}, 200 / interval);
|
||||
|
||||
const dummyVar = Variable('');
|
||||
|
||||
export const inputHandler = (
|
||||
self: Button<Gtk.Widget, Gtk.Widget>,
|
||||
{
|
||||
onPrimaryClick,
|
||||
onSecondaryClick,
|
||||
onMiddleClick,
|
||||
onScrollUp,
|
||||
onScrollDown,
|
||||
}: InputHandlerEvents
|
||||
) => {
|
||||
{ onPrimaryClick, onSecondaryClick, onMiddleClick, onScrollUp, onScrollDown }: InputHandlerEvents,
|
||||
): void => {
|
||||
const sanitizeInput = (input: VariableType<string>): string => {
|
||||
if (input === undefined) {
|
||||
return '';
|
||||
@@ -89,46 +75,25 @@ export const inputHandler = (
|
||||
const interval = scrollSpeed.value;
|
||||
const throttledHandler = throttledScrollHandler(interval);
|
||||
|
||||
self.on_primary_click = (clicked: any, event: Gdk.Event) =>
|
||||
runAsyncCommand(
|
||||
sanitizeInput(onPrimaryClick?.cmd || dummyVar),
|
||||
onPrimaryClick.fn,
|
||||
{ clicked, event }
|
||||
);
|
||||
self.on_primary_click = (clicked: Button<GtkWidget, GtkWidget>, event: Gdk.Event): void =>
|
||||
runAsyncCommand(sanitizeInput(onPrimaryClick?.cmd || dummyVar), onPrimaryClick.fn, { clicked, event });
|
||||
|
||||
self.on_secondary_click = (clicked: any, event: Gdk.Event) =>
|
||||
runAsyncCommand(
|
||||
sanitizeInput(onSecondaryClick?.cmd || dummyVar),
|
||||
onSecondaryClick.fn,
|
||||
{ clicked, event }
|
||||
);
|
||||
self.on_secondary_click = (clicked: Button<GtkWidget, GtkWidget>, event: Gdk.Event): void =>
|
||||
runAsyncCommand(sanitizeInput(onSecondaryClick?.cmd || dummyVar), onSecondaryClick.fn, { clicked, event });
|
||||
|
||||
self.on_middle_click = (clicked: any, event: Gdk.Event) =>
|
||||
runAsyncCommand(
|
||||
sanitizeInput(onMiddleClick?.cmd || dummyVar),
|
||||
onMiddleClick.fn,
|
||||
{ clicked, event }
|
||||
);
|
||||
self.on_middle_click = (clicked: Button<GtkWidget, GtkWidget>, event: Gdk.Event): void =>
|
||||
runAsyncCommand(sanitizeInput(onMiddleClick?.cmd || dummyVar), onMiddleClick.fn, { clicked, event });
|
||||
|
||||
self.on_scroll_up = () =>
|
||||
throttledHandler(
|
||||
sanitizeInput(onScrollUp?.cmd || dummyVar),
|
||||
onScrollUp.fn
|
||||
);
|
||||
self.on_scroll_up = (): void => throttledHandler(sanitizeInput(onScrollUp?.cmd || dummyVar), onScrollUp.fn);
|
||||
|
||||
self.on_scroll_down = () =>
|
||||
throttledHandler(
|
||||
sanitizeInput(onScrollDown?.cmd || dummyVar),
|
||||
onScrollDown.fn
|
||||
);
|
||||
self.on_scroll_down = (): void =>
|
||||
throttledHandler(sanitizeInput(onScrollDown?.cmd || dummyVar), onScrollDown.fn);
|
||||
};
|
||||
|
||||
// Initial setup of event handlers
|
||||
updateHandlers();
|
||||
|
||||
const sanitizeVariable = (
|
||||
someVar: VariableType<string> | undefined
|
||||
): Binding<string> => {
|
||||
const sanitizeVariable = (someVar: VariableType<string> | undefined): Binding<string> => {
|
||||
if (someVar === undefined || typeof someVar.bind !== 'function') {
|
||||
return dummyVar.bind('value');
|
||||
}
|
||||
@@ -145,37 +110,36 @@ export const inputHandler = (
|
||||
sanitizeVariable(onScrollUp),
|
||||
sanitizeVariable(onScrollDown),
|
||||
],
|
||||
updateHandlers
|
||||
updateHandlers,
|
||||
);
|
||||
};
|
||||
|
||||
export const divide = ([total, used]: number[], round: boolean) => {
|
||||
export const divide = ([total, used]: number[], round: boolean): number => {
|
||||
const percentageTotal = (used / total) * 100;
|
||||
if (round) {
|
||||
return total > 0 ? Math.round(percentageTotal) : 0;
|
||||
}
|
||||
return total > 0 ? parseFloat(percentageTotal.toFixed(2)) : 0;
|
||||
|
||||
};
|
||||
|
||||
export const formatSizeInKiB = (sizeInBytes: number, round: boolean) => {
|
||||
const sizeInGiB = sizeInBytes / (1024 ** 1);
|
||||
export const formatSizeInKiB = (sizeInBytes: number, round: boolean): number => {
|
||||
const sizeInGiB = sizeInBytes / 1024 ** 1;
|
||||
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
||||
};
|
||||
export const formatSizeInMiB = (sizeInBytes: number, round: boolean) => {
|
||||
const sizeInGiB = sizeInBytes / (1024 ** 2);
|
||||
export const formatSizeInMiB = (sizeInBytes: number, round: boolean): number => {
|
||||
const sizeInGiB = sizeInBytes / 1024 ** 2;
|
||||
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
||||
};
|
||||
export const formatSizeInGiB = (sizeInBytes: number, round: boolean) => {
|
||||
const sizeInGiB = sizeInBytes / (1024 ** 3);
|
||||
export const formatSizeInGiB = (sizeInBytes: number, round: boolean): number => {
|
||||
const sizeInGiB = sizeInBytes / 1024 ** 3;
|
||||
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
||||
};
|
||||
export const formatSizeInTiB = (sizeInBytes: number, round: boolean) => {
|
||||
const sizeInGiB = sizeInBytes / (1024 ** 4);
|
||||
export const formatSizeInTiB = (sizeInBytes: number, round: boolean): number => {
|
||||
const sizeInGiB = sizeInBytes / 1024 ** 4;
|
||||
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
||||
};
|
||||
|
||||
export const autoFormatSize = (sizeInBytes: number, round: boolean) => {
|
||||
export const autoFormatSize = (sizeInBytes: number, round: boolean): number => {
|
||||
// auto convert to GiB, MiB, KiB, TiB, or bytes
|
||||
if (sizeInBytes >= 1024 ** 4) return formatSizeInTiB(sizeInBytes, round);
|
||||
if (sizeInBytes >= 1024 ** 3) return formatSizeInGiB(sizeInBytes, round);
|
||||
@@ -183,22 +147,18 @@ export const autoFormatSize = (sizeInBytes: number, round: boolean) => {
|
||||
if (sizeInBytes >= 1024 ** 1) return formatSizeInKiB(sizeInBytes, round);
|
||||
|
||||
return sizeInBytes;
|
||||
}
|
||||
};
|
||||
|
||||
export const getPostfix = (sizeInBytes: number) => {
|
||||
export const getPostfix = (sizeInBytes: number): Postfix => {
|
||||
if (sizeInBytes >= 1024 ** 4) return 'TiB';
|
||||
if (sizeInBytes >= 1024 ** 3) return 'GiB';
|
||||
if (sizeInBytes >= 1024 ** 2) return 'MiB';
|
||||
if (sizeInBytes >= 1024 ** 1) return 'KiB';
|
||||
|
||||
return 'B';
|
||||
}
|
||||
};
|
||||
|
||||
export const renderResourceLabel = (
|
||||
lblType: ResourceLabelType,
|
||||
rmUsg: GenericResourceData,
|
||||
round: boolean
|
||||
) => {
|
||||
export const renderResourceLabel = (lblType: ResourceLabelType, rmUsg: GenericResourceData, round: boolean): string => {
|
||||
const { used, total, percentage, free } = rmUsg;
|
||||
|
||||
const formatFunctions = {
|
||||
@@ -206,7 +166,7 @@ export const renderResourceLabel = (
|
||||
GiB: formatSizeInGiB,
|
||||
MiB: formatSizeInMiB,
|
||||
KiB: formatSizeInKiB,
|
||||
B: (size: number, _: boolean) => size
|
||||
B: (size: number): number => size,
|
||||
};
|
||||
|
||||
// Get them datas in proper GiB, MiB, KiB, TiB, or bytes
|
||||
@@ -218,20 +178,20 @@ export const renderResourceLabel = (
|
||||
const formatUsed = formatFunctions[postfix] || formatFunctions['B'];
|
||||
const usedSizeFormatted = formatUsed(used, round);
|
||||
|
||||
if (lblType === "used/total") {
|
||||
if (lblType === 'used/total') {
|
||||
return `${usedSizeFormatted}/${totalSizeFormatted} ${postfix}`;
|
||||
}
|
||||
if (lblType === "used") {
|
||||
if (lblType === 'used') {
|
||||
return `${autoFormatSize(used, round)} ${getPostfix(used)}`;
|
||||
}
|
||||
if (lblType === "free") {
|
||||
if (lblType === 'free') {
|
||||
return `${autoFormatSize(free, round)} ${getPostfix(free)}`;
|
||||
}
|
||||
|
||||
return `${percentage}%`;
|
||||
};
|
||||
|
||||
export const formatTooltip = (dataType: string, lblTyp: ResourceLabelType) => {
|
||||
export const formatTooltip = (dataType: string, lblTyp: ResourceLabelType): string => {
|
||||
switch (lblTyp) {
|
||||
case 'used':
|
||||
return `Used ${dataType}`;
|
||||
@@ -244,4 +204,4 @@ export const formatTooltip = (dataType: string, lblTyp: ResourceLabelType) => {
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,40 +1,30 @@
|
||||
import options from "options";
|
||||
import { module } from "../module"
|
||||
import options from 'options';
|
||||
import { module } from '../module';
|
||||
|
||||
import { inputHandler } from "customModules/utils";
|
||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
||||
import Button from "types/widgets/button";
|
||||
import { getWeatherStatusTextIcon, globalWeatherVar } from "globals/weather";
|
||||
import { inputHandler } from 'customModules/utils';
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||
import Button from 'types/widgets/button';
|
||||
import { getWeatherStatusTextIcon, globalWeatherVar } from 'globals/weather';
|
||||
import { Module } from 'lib/types/bar';
|
||||
|
||||
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 = () => {
|
||||
export const Weather = (): Module => {
|
||||
const weatherModule = module({
|
||||
textIcon: Utils.merge([globalWeatherVar.bind("value")], (wthr) => {
|
||||
textIcon: Utils.merge([globalWeatherVar.bind('value')], (wthr) => {
|
||||
const weatherStatusIcon = getWeatherStatusTextIcon(wthr);
|
||||
return weatherStatusIcon;
|
||||
}),
|
||||
tooltipText: globalWeatherVar.bind("value").as(v => `Weather Status: ${v.current.condition.text}`),
|
||||
boxClass: "weather-custom",
|
||||
label: Utils.merge(
|
||||
[globalWeatherVar.bind("value"), unit.bind("value")],
|
||||
(wthr, unt) => {
|
||||
if (unt === "imperial") {
|
||||
return `${Math.ceil(wthr.current.temp_f)}° F`;
|
||||
} else {
|
||||
return `${Math.ceil(wthr.current.temp_c)}° C`;
|
||||
}
|
||||
},
|
||||
),
|
||||
showLabelBinding: label.bind("value"),
|
||||
tooltipText: globalWeatherVar.bind('value').as((v) => `Weather Status: ${v.current.condition.text}`),
|
||||
boxClass: 'weather-custom',
|
||||
label: Utils.merge([globalWeatherVar.bind('value'), unit.bind('value')], (wthr, unt) => {
|
||||
if (unt === 'imperial') {
|
||||
return `${Math.ceil(wthr.current.temp_f)}° F`;
|
||||
} else {
|
||||
return `${Math.ceil(wthr.current.temp_c)}° C`;
|
||||
}
|
||||
}),
|
||||
showLabelBinding: label.bind('value'),
|
||||
props: {
|
||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||
inputHandler(self, {
|
||||
@@ -59,8 +49,4 @@ export const Weather = () => {
|
||||
});
|
||||
|
||||
return weatherModule;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Service from "resource:///com/github/Aylur/ags/service.js";
|
||||
import App from "resource:///com/github/Aylur/ags/app.js";
|
||||
import { monitorFile } from "resource:///com/github/Aylur/ags/utils.js";
|
||||
import Gio from "gi://Gio";
|
||||
import { FileInfo } from "types/@girs/gio-2.0/gio-2.0.cjs";
|
||||
import Service from 'resource:///com/github/Aylur/ags/service.js';
|
||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import { monitorFile } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
import Gio from 'gi://Gio';
|
||||
import { FileInfo } from 'types/@girs/gio-2.0/gio-2.0.cjs';
|
||||
|
||||
class DirectoryMonitorService extends Service {
|
||||
static {
|
||||
@@ -14,23 +14,19 @@ class DirectoryMonitorService extends Service {
|
||||
this.recursiveDirectoryMonitor(`${App.configDir}/scss`);
|
||||
}
|
||||
|
||||
recursiveDirectoryMonitor(directoryPath: string) {
|
||||
recursiveDirectoryMonitor(directoryPath: string): void {
|
||||
monitorFile(directoryPath, (_, eventType) => {
|
||||
if (eventType === Gio.FileMonitorEvent.CHANGES_DONE_HINT) {
|
||||
this.emit("changed");
|
||||
this.emit('changed');
|
||||
}
|
||||
});
|
||||
|
||||
const directory = Gio.File.new_for_path(directoryPath);
|
||||
const enumerator = directory.enumerate_children(
|
||||
"standard::*",
|
||||
Gio.FileQueryInfoFlags.NONE,
|
||||
null,
|
||||
);
|
||||
const enumerator = directory.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
|
||||
|
||||
let fileInfo: FileInfo;
|
||||
while ((fileInfo = enumerator.next_file(null) as FileInfo) !== null) {
|
||||
const childPath = directoryPath + "/" + fileInfo.get_name();
|
||||
const childPath = directoryPath + '/' + fileInfo.get_name();
|
||||
if (fileInfo.get_file_type() === Gio.FileType.DIRECTORY) {
|
||||
this.recursiveDirectoryMonitor(childPath);
|
||||
}
|
||||
|
||||
9
globals.d.ts
vendored
9
globals.d.ts
vendored
@@ -1,13 +1,14 @@
|
||||
// globals.d.ts
|
||||
/* eslint-disable no-var */
|
||||
|
||||
import { Options, Variable as VariableType } from "types/variable";
|
||||
import { Options, Variable as VariableType } from 'types/variable';
|
||||
|
||||
declare global {
|
||||
var globalMousePos: VariableType<number[]>;
|
||||
var useTheme: Function;
|
||||
var useTheme: (filePath: string) => void;
|
||||
var globalWeatherVar: VariableType<Weather>;
|
||||
var options: Options
|
||||
var options: Options;
|
||||
var removingNotifications: VariableType<boolean>;
|
||||
}
|
||||
|
||||
export { };
|
||||
export {};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Variable as VariableType } from "types/variable";
|
||||
import { Variable as VariableType } from 'types/variable';
|
||||
|
||||
const globalMousePosVar: VariableType<number[]> = Variable([0, 0]);
|
||||
|
||||
globalThis["globalMousePos"] = globalMousePosVar;
|
||||
globalThis['globalMousePos'] = globalMousePosVar;
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
export const WIFI_STATUS_MAP = {
|
||||
unknown: "Status Unknown",
|
||||
unmanaged: "Unmanaged",
|
||||
unavailable: "Unavailable",
|
||||
disconnected: "Disconnected",
|
||||
prepare: "Preparing Connecting",
|
||||
config: "Connecting",
|
||||
need_auth: "Needs Authentication",
|
||||
ip_config: "Requesting IP",
|
||||
ip_check: "Checking Access",
|
||||
secondaries: "Waiting on Secondaries",
|
||||
activated: "Connected",
|
||||
deactivating: "Disconnecting",
|
||||
failed: "Connection Failed",
|
||||
unknown: 'Status Unknown',
|
||||
unmanaged: 'Unmanaged',
|
||||
unavailable: 'Unavailable',
|
||||
disconnected: 'Disconnected',
|
||||
prepare: 'Preparing Connecting',
|
||||
config: 'Connecting',
|
||||
need_auth: 'Needs Authentication',
|
||||
ip_config: 'Requesting IP',
|
||||
ip_check: 'Checking Access',
|
||||
secondaries: 'Waiting on Secondaries',
|
||||
activated: 'Connected',
|
||||
deactivating: 'Disconnecting',
|
||||
failed: 'Connection Failed',
|
||||
} as const;
|
||||
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
import icons from "modules/icons/index";
|
||||
import { Notification } from "types/service/notifications";
|
||||
import icons from 'modules/icons/index';
|
||||
import { Notification } from 'types/service/notifications';
|
||||
|
||||
export const removingNotifications = Variable<boolean>(false);
|
||||
|
||||
export const getNotificationIcon = (app_name: string, app_icon: string, app_entry: string) => {
|
||||
export const getNotificationIcon = (app_name: string, app_icon: string, app_entry: string): string => {
|
||||
let icon: string = icons.fallback.notification;
|
||||
|
||||
if (Utils.lookUpIcon(app_name) || Utils.lookUpIcon(app_name.toLowerCase() || "")) {
|
||||
if (Utils.lookUpIcon(app_name) || Utils.lookUpIcon(app_name.toLowerCase() || '')) {
|
||||
icon = Utils.lookUpIcon(app_name)
|
||||
? app_name
|
||||
: Utils.lookUpIcon(app_name.toLowerCase())
|
||||
? app_name.toLowerCase()
|
||||
: "";
|
||||
? app_name.toLowerCase()
|
||||
: '';
|
||||
}
|
||||
|
||||
if (Utils.lookUpIcon(app_icon) && icon === "") {
|
||||
if (Utils.lookUpIcon(app_icon) && icon === '') {
|
||||
icon = app_icon;
|
||||
}
|
||||
|
||||
if (Utils.lookUpIcon(app_entry || "") && icon === "") {
|
||||
icon = app_entry || "";
|
||||
if (Utils.lookUpIcon(app_entry || '') && icon === '') {
|
||||
icon = app_entry || '';
|
||||
}
|
||||
|
||||
return icon;
|
||||
};
|
||||
|
||||
export const closeNotifications = async (notifications: Notification[]) => {
|
||||
export const closeNotifications = async (notifications: Notification[]): Promise<void> => {
|
||||
removingNotifications.value = true;
|
||||
for (const notif of notifications) {
|
||||
notif.close();
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
removingNotifications.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
globalThis["removingNotifications"] = removingNotifications;
|
||||
globalThis['removingNotifications'] = removingNotifications;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import Gio from "gi://Gio"
|
||||
import { bash, Notify } from "lib/utils";
|
||||
import icons from "lib/icons"
|
||||
import { filterConfigForThemeOnly, loadJsonFile, saveConfigToFile } from "widget/settings/shared/FileChooser";
|
||||
import Gio from 'gi://Gio';
|
||||
import { bash, Notify } from 'lib/utils';
|
||||
import icons from 'lib/icons';
|
||||
import { filterConfigForThemeOnly, loadJsonFile, saveConfigToFile } from 'widget/settings/shared/FileChooser';
|
||||
|
||||
export const hexColorPattern = /^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
|
||||
|
||||
globalThis.useTheme = (filePath: string): void => {
|
||||
let importedConfig = loadJsonFile(filePath);
|
||||
const importedConfig = loadJsonFile(filePath);
|
||||
|
||||
if (!importedConfig) {
|
||||
return;
|
||||
@@ -16,22 +16,22 @@ globalThis.useTheme = (filePath: string): void => {
|
||||
summary: `Importing Theme`,
|
||||
body: `Importing: ${filePath}`,
|
||||
iconName: icons.ui.info,
|
||||
timeout: 7000
|
||||
timeout: 7000,
|
||||
});
|
||||
|
||||
let tmpConfigFile = Gio.File.new_for_path(`${TMP}/config.json`);
|
||||
let optionsConfigFile = Gio.File.new_for_path(OPTIONS);
|
||||
const tmpConfigFile = Gio.File.new_for_path(`${TMP}/config.json`);
|
||||
const optionsConfigFile = Gio.File.new_for_path(OPTIONS);
|
||||
|
||||
let [tmpSuccess, tmpContent] = tmpConfigFile.load_contents(null);
|
||||
let [optionsSuccess, optionsContent] = optionsConfigFile.load_contents(null);
|
||||
const [tmpSuccess, tmpContent] = tmpConfigFile.load_contents(null);
|
||||
const [optionsSuccess, optionsContent] = optionsConfigFile.load_contents(null);
|
||||
|
||||
if (!tmpSuccess || !optionsSuccess) {
|
||||
console.error("Failed to read existing configuration files.");
|
||||
console.error('Failed to read existing configuration files.');
|
||||
return;
|
||||
}
|
||||
|
||||
let tmpConfig = JSON.parse(new TextDecoder("utf-8").decode(tmpContent));
|
||||
let optionsConfig = JSON.parse(new TextDecoder("utf-8").decode(optionsContent));
|
||||
let tmpConfig = JSON.parse(new TextDecoder('utf-8').decode(tmpContent));
|
||||
let optionsConfig = JSON.parse(new TextDecoder('utf-8').decode(optionsContent));
|
||||
|
||||
const filteredConfig = filterConfigForThemeOnly(importedConfig);
|
||||
tmpConfig = { ...tmpConfig, ...filteredConfig };
|
||||
@@ -39,6 +39,5 @@ globalThis.useTheme = (filePath: string): void => {
|
||||
|
||||
saveConfigToFile(tmpConfig, `${TMP}/config.json`);
|
||||
saveConfigToFile(optionsConfig, OPTIONS);
|
||||
bash("pkill ags && ags");
|
||||
}
|
||||
|
||||
bash('pkill ags && ags');
|
||||
};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Opt } from "lib/option";
|
||||
import { HexColor, RecursiveOptionsObject } from "lib/types/options";
|
||||
import { Opt } from 'lib/option';
|
||||
import { HexColor, RecursiveOptionsObject } from 'lib/types/options';
|
||||
|
||||
export const isOpt = <T>(value: unknown): value is Opt<T> =>
|
||||
typeof value === 'object' && value !== null && 'value' in value && value instanceof Opt;
|
||||
|
||||
export const isRecursiveOptionsObject = (value: unknown): value is RecursiveOptionsObject => {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
||||
}
|
||||
};
|
||||
|
||||
export const isHexColor = (value: string): value is HexColor => {
|
||||
return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import options from "options";
|
||||
import { UnitType, Weather, WeatherIconTitle, WeatherIcon } from "lib/types/weather.js";
|
||||
import { DEFAULT_WEATHER } from "lib/types/defaults/weather.js";
|
||||
import GLib from "gi://GLib?version=2.0";
|
||||
import { weatherIcons } from "modules/icons/weather.js";
|
||||
import options from 'options';
|
||||
import { UnitType, Weather, WeatherIconTitle, WeatherIcon } from 'lib/types/weather.js';
|
||||
import { DEFAULT_WEATHER } from 'lib/types/defaults/weather.js';
|
||||
import GLib from 'gi://GLib?version=2.0';
|
||||
import { weatherIcons } from 'modules/icons/weather.js';
|
||||
|
||||
const { key, interval, location } = options.menus.clock.weather;
|
||||
|
||||
@@ -10,12 +10,12 @@ export const globalWeatherVar = Variable<Weather>(DEFAULT_WEATHER);
|
||||
|
||||
let weatherIntervalInstance: null | number = null;
|
||||
|
||||
const weatherIntervalFn = (weatherInterval: number, loc: string, weatherKey: string) => {
|
||||
const weatherIntervalFn = (weatherInterval: number, loc: string, weatherKey: string): void => {
|
||||
if (weatherIntervalInstance !== null) {
|
||||
GLib.source_remove(weatherIntervalInstance);
|
||||
}
|
||||
|
||||
const formattedLocation = loc.replace(" ", "%20");
|
||||
const formattedLocation = loc.replace(' ', '%20');
|
||||
|
||||
weatherIntervalInstance = Utils.interval(weatherInterval, () => {
|
||||
Utils.execAsync(
|
||||
@@ -23,13 +23,13 @@ const weatherIntervalFn = (weatherInterval: number, loc: string, weatherKey: str
|
||||
)
|
||||
.then((res) => {
|
||||
try {
|
||||
if (typeof res !== "string") {
|
||||
if (typeof res !== 'string') {
|
||||
return (globalWeatherVar.value = DEFAULT_WEATHER);
|
||||
}
|
||||
|
||||
const parsedWeather = JSON.parse(res);
|
||||
|
||||
if (Object.keys(parsedWeather).includes("error")) {
|
||||
if (Object.keys(parsedWeather).includes('error')) {
|
||||
return (globalWeatherVar.value = DEFAULT_WEATHER);
|
||||
}
|
||||
|
||||
@@ -46,43 +46,41 @@ const weatherIntervalFn = (weatherInterval: number, loc: string, weatherKey: str
|
||||
});
|
||||
};
|
||||
|
||||
Utils.merge([key.bind("value"), interval.bind("value"), location.bind("value")], (weatherKey, weatherInterval, loc) => {
|
||||
Utils.merge([key.bind('value'), interval.bind('value'), location.bind('value')], (weatherKey, weatherInterval, loc) => {
|
||||
if (!weatherKey) {
|
||||
return (globalWeatherVar.value = DEFAULT_WEATHER);
|
||||
}
|
||||
weatherIntervalFn(weatherInterval, loc, weatherKey);
|
||||
});
|
||||
|
||||
export const getTemperature = (wthr: Weather, unt: UnitType) => {
|
||||
if (unt === "imperial") {
|
||||
export const getTemperature = (wthr: Weather, unt: UnitType): string => {
|
||||
if (unt === 'imperial') {
|
||||
return `${Math.ceil(wthr.current.temp_f)}° F`;
|
||||
} else {
|
||||
return `${Math.ceil(wthr.current.temp_c)}° C`;
|
||||
}
|
||||
};
|
||||
|
||||
export const getWeatherIcon = (fahren: number) => {
|
||||
export const getWeatherIcon = (fahren: number): Record<string, string> => {
|
||||
const icons = {
|
||||
100: "",
|
||||
75: "",
|
||||
50: "",
|
||||
25: "",
|
||||
0: "",
|
||||
100: '',
|
||||
75: '',
|
||||
50: '',
|
||||
25: '',
|
||||
0: '',
|
||||
} as const;
|
||||
const colors = {
|
||||
100: "weather-color red",
|
||||
75: "weather-color orange",
|
||||
50: "weather-color lavender",
|
||||
25: "weather-color blue",
|
||||
0: "weather-color sky",
|
||||
100: 'weather-color red',
|
||||
75: 'weather-color orange',
|
||||
50: 'weather-color lavender',
|
||||
25: 'weather-color blue',
|
||||
0: 'weather-color sky',
|
||||
} as const;
|
||||
|
||||
type IconKeys = keyof typeof icons;
|
||||
|
||||
const threshold: IconKeys =
|
||||
fahren < 0
|
||||
? 0
|
||||
: ([100, 75, 50, 25, 0] as IconKeys[]).find((threshold) => threshold <= fahren) || 0;
|
||||
fahren < 0 ? 0 : ([100, 75, 50, 25, 0] as IconKeys[]).find((threshold) => threshold <= fahren) || 0;
|
||||
|
||||
const icon = icons[threshold || 50];
|
||||
const color = colors[threshold || 50];
|
||||
@@ -93,35 +91,32 @@ export const getWeatherIcon = (fahren: number) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const getWindConditions = (wthr: Weather, unt: UnitType) => {
|
||||
if (unt === "imperial") {
|
||||
export const getWindConditions = (wthr: Weather, unt: UnitType): string => {
|
||||
if (unt === 'imperial') {
|
||||
return `${Math.floor(wthr.current.wind_mph)} mph`;
|
||||
}
|
||||
return `${Math.floor(wthr.current.wind_kph)} kph`;
|
||||
};
|
||||
|
||||
export const getRainChance = (wthr: Weather) => `${wthr.forecast.forecastday[0].day.daily_chance_of_rain}%`;
|
||||
export const getRainChance = (wthr: Weather): string => `${wthr.forecast.forecastday[0].day.daily_chance_of_rain}%`;
|
||||
|
||||
export const isValidWeatherIconTitle = (title: string): title is WeatherIconTitle => {
|
||||
return title in weatherIcons;
|
||||
};
|
||||
|
||||
export const getWeatherStatusTextIcon = (wthr: Weather): WeatherIcon => {
|
||||
let iconQuery = wthr.current.condition.text
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replaceAll(" ", "_");
|
||||
let iconQuery = wthr.current.condition.text.trim().toLowerCase().replaceAll(' ', '_');
|
||||
|
||||
if (!wthr.current.is_day && iconQuery === "partly_cloudy") {
|
||||
iconQuery = "partly_cloudy_night";
|
||||
if (!wthr.current.is_day && iconQuery === 'partly_cloudy') {
|
||||
iconQuery = 'partly_cloudy_night';
|
||||
}
|
||||
|
||||
if (isValidWeatherIconTitle(iconQuery)) {
|
||||
return weatherIcons[iconQuery];
|
||||
} else {
|
||||
console.warn(`Unknown weather icon title: ${iconQuery}`);
|
||||
return weatherIcons["warning"];
|
||||
return weatherIcons['warning'];
|
||||
}
|
||||
};
|
||||
|
||||
globalThis["globalWeatherVar"] = globalWeatherVar;
|
||||
globalThis['globalWeatherVar'] = globalWeatherVar;
|
||||
|
||||
@@ -6,5 +6,5 @@ export const WINDOW_LAYOUTS: string[] = [
|
||||
'top-left',
|
||||
'bottom-left',
|
||||
'bottom-center',
|
||||
'bottom-right'
|
||||
'bottom-right',
|
||||
];
|
||||
|
||||
182
lib/icons.ts
182
lib/icons.ts
@@ -1,145 +1,145 @@
|
||||
export const substitutes = {
|
||||
"transmission-gtk": "transmission",
|
||||
"blueberry.py": "blueberry",
|
||||
"Caprine": "facebook-messenger",
|
||||
"com.raggesilver.BlackBox-symbolic": "terminal-symbolic",
|
||||
"org.wezfurlong.wezterm-symbolic": "terminal-symbolic",
|
||||
"audio-headset-bluetooth": "audio-headphones-symbolic",
|
||||
"audio-card-analog-usb": "audio-speakers-symbolic",
|
||||
"audio-card-analog-pci": "audio-card-symbolic",
|
||||
"preferences-system": "emblem-system-symbolic",
|
||||
"com.github.Aylur.ags-symbolic": "controls-symbolic",
|
||||
"com.github.Aylur.ags": "controls-symbolic",
|
||||
'transmission-gtk': 'transmission',
|
||||
'blueberry.py': 'blueberry',
|
||||
Caprine: 'facebook-messenger',
|
||||
'com.raggesilver.BlackBox-symbolic': 'terminal-symbolic',
|
||||
'org.wezfurlong.wezterm-symbolic': 'terminal-symbolic',
|
||||
'audio-headset-bluetooth': 'audio-headphones-symbolic',
|
||||
'audio-card-analog-usb': 'audio-speakers-symbolic',
|
||||
'audio-card-analog-pci': 'audio-card-symbolic',
|
||||
'preferences-system': 'emblem-system-symbolic',
|
||||
'com.github.Aylur.ags-symbolic': 'controls-symbolic',
|
||||
'com.github.Aylur.ags': 'controls-symbolic',
|
||||
} as const;
|
||||
|
||||
export default {
|
||||
missing: "image-missing-symbolic",
|
||||
missing: 'image-missing-symbolic',
|
||||
nix: {
|
||||
nix: "nix-snowflake-symbolic",
|
||||
nix: 'nix-snowflake-symbolic',
|
||||
},
|
||||
app: {
|
||||
terminal: "terminal-symbolic",
|
||||
terminal: 'terminal-symbolic',
|
||||
},
|
||||
fallback: {
|
||||
executable: "application-x-executable",
|
||||
notification: "dialog-information-symbolic",
|
||||
video: "video-x-generic-symbolic",
|
||||
audio: "audio-x-generic-symbolic",
|
||||
executable: 'application-x-executable',
|
||||
notification: 'dialog-information-symbolic',
|
||||
video: 'video-x-generic-symbolic',
|
||||
audio: 'audio-x-generic-symbolic',
|
||||
},
|
||||
ui: {
|
||||
close: "window-close-symbolic",
|
||||
colorpicker: "color-select-symbolic",
|
||||
info: "info-symbolic",
|
||||
link: "external-link-symbolic",
|
||||
lock: "system-lock-screen-symbolic",
|
||||
menu: "open-menu-symbolic",
|
||||
refresh: "view-refresh-symbolic",
|
||||
search: "system-search-symbolic",
|
||||
settings: "emblem-system-symbolic",
|
||||
themes: "preferences-desktop-theme-symbolic",
|
||||
tick: "object-select-symbolic",
|
||||
time: "hourglass-symbolic",
|
||||
toolbars: "toolbars-symbolic",
|
||||
warning: "dialog-warning-symbolic",
|
||||
avatar: "avatar-default-symbolic",
|
||||
close: 'window-close-symbolic',
|
||||
colorpicker: 'color-select-symbolic',
|
||||
info: 'info-symbolic',
|
||||
link: 'external-link-symbolic',
|
||||
lock: 'system-lock-screen-symbolic',
|
||||
menu: 'open-menu-symbolic',
|
||||
refresh: 'view-refresh-symbolic',
|
||||
search: 'system-search-symbolic',
|
||||
settings: 'emblem-system-symbolic',
|
||||
themes: 'preferences-desktop-theme-symbolic',
|
||||
tick: 'object-select-symbolic',
|
||||
time: 'hourglass-symbolic',
|
||||
toolbars: 'toolbars-symbolic',
|
||||
warning: 'dialog-warning-symbolic',
|
||||
avatar: 'avatar-default-symbolic',
|
||||
arrow: {
|
||||
right: "pan-end-symbolic",
|
||||
left: "pan-start-symbolic",
|
||||
down: "pan-down-symbolic",
|
||||
up: "pan-up-symbolic",
|
||||
right: 'pan-end-symbolic',
|
||||
left: 'pan-start-symbolic',
|
||||
down: 'pan-down-symbolic',
|
||||
up: 'pan-up-symbolic',
|
||||
},
|
||||
},
|
||||
audio: {
|
||||
mic: {
|
||||
muted: "microphone-disabled-symbolic",
|
||||
low: "microphone-sensitivity-low-symbolic",
|
||||
medium: "microphone-sensitivity-medium-symbolic",
|
||||
high: "microphone-sensitivity-high-symbolic",
|
||||
muted: 'microphone-disabled-symbolic',
|
||||
low: 'microphone-sensitivity-low-symbolic',
|
||||
medium: 'microphone-sensitivity-medium-symbolic',
|
||||
high: 'microphone-sensitivity-high-symbolic',
|
||||
},
|
||||
volume: {
|
||||
muted: "audio-volume-muted-symbolic",
|
||||
low: "audio-volume-low-symbolic",
|
||||
medium: "audio-volume-medium-symbolic",
|
||||
high: "audio-volume-high-symbolic",
|
||||
overamplified: "audio-volume-overamplified-symbolic",
|
||||
muted: 'audio-volume-muted-symbolic',
|
||||
low: 'audio-volume-low-symbolic',
|
||||
medium: 'audio-volume-medium-symbolic',
|
||||
high: 'audio-volume-high-symbolic',
|
||||
overamplified: 'audio-volume-overamplified-symbolic',
|
||||
},
|
||||
type: {
|
||||
headset: "audio-headphones-symbolic",
|
||||
speaker: "audio-speakers-symbolic",
|
||||
card: "audio-card-symbolic",
|
||||
headset: 'audio-headphones-symbolic',
|
||||
speaker: 'audio-speakers-symbolic',
|
||||
card: 'audio-card-symbolic',
|
||||
},
|
||||
mixer: "mixer-symbolic",
|
||||
mixer: 'mixer-symbolic',
|
||||
},
|
||||
powerprofile: {
|
||||
balanced: "power-profile-balanced-symbolic",
|
||||
"power-saver": "power-profile-power-saver-symbolic",
|
||||
performance: "power-profile-performance-symbolic",
|
||||
balanced: 'power-profile-balanced-symbolic',
|
||||
'power-saver': 'power-profile-power-saver-symbolic',
|
||||
performance: 'power-profile-performance-symbolic',
|
||||
},
|
||||
asusctl: {
|
||||
profile: {
|
||||
Balanced: "power-profile-balanced-symbolic",
|
||||
Quiet: "power-profile-power-saver-symbolic",
|
||||
Performance: "power-profile-performance-symbolic",
|
||||
Balanced: 'power-profile-balanced-symbolic',
|
||||
Quiet: 'power-profile-power-saver-symbolic',
|
||||
Performance: 'power-profile-performance-symbolic',
|
||||
},
|
||||
mode: {
|
||||
Integrated: "processor-symbolic",
|
||||
Hybrid: "controller-symbolic",
|
||||
Integrated: 'processor-symbolic',
|
||||
Hybrid: 'controller-symbolic',
|
||||
},
|
||||
},
|
||||
battery: {
|
||||
charging: "battery-flash-symbolic",
|
||||
warning: "battery-empty-symbolic",
|
||||
charging: 'battery-flash-symbolic',
|
||||
warning: 'battery-empty-symbolic',
|
||||
},
|
||||
bluetooth: {
|
||||
enabled: "bluetooth-active-symbolic",
|
||||
disabled: "bluetooth-disabled-symbolic",
|
||||
enabled: 'bluetooth-active-symbolic',
|
||||
disabled: 'bluetooth-disabled-symbolic',
|
||||
},
|
||||
brightness: {
|
||||
indicator: "display-brightness-symbolic",
|
||||
keyboard: "keyboard-brightness-symbolic",
|
||||
screen: "display-brightness-symbolic",
|
||||
indicator: 'display-brightness-symbolic',
|
||||
keyboard: 'keyboard-brightness-symbolic',
|
||||
screen: 'display-brightness-symbolic',
|
||||
},
|
||||
powermenu: {
|
||||
sleep: "weather-clear-night-symbolic",
|
||||
reboot: "system-reboot-symbolic",
|
||||
logout: "system-log-out-symbolic",
|
||||
shutdown: "system-shutdown-symbolic",
|
||||
sleep: 'weather-clear-night-symbolic',
|
||||
reboot: 'system-reboot-symbolic',
|
||||
logout: 'system-log-out-symbolic',
|
||||
shutdown: 'system-shutdown-symbolic',
|
||||
},
|
||||
recorder: {
|
||||
recording: "media-record-symbolic",
|
||||
recording: 'media-record-symbolic',
|
||||
},
|
||||
notifications: {
|
||||
noisy: "org.gnome.Settings-notifications-symbolic",
|
||||
silent: "notifications-disabled-symbolic",
|
||||
message: "chat-bubbles-symbolic",
|
||||
noisy: 'org.gnome.Settings-notifications-symbolic',
|
||||
silent: 'notifications-disabled-symbolic',
|
||||
message: 'chat-bubbles-symbolic',
|
||||
},
|
||||
trash: {
|
||||
full: "user-trash-full-symbolic",
|
||||
empty: "user-trash-symbolic",
|
||||
full: 'user-trash-full-symbolic',
|
||||
empty: 'user-trash-symbolic',
|
||||
},
|
||||
mpris: {
|
||||
shuffle: {
|
||||
enabled: "media-playlist-shuffle-symbolic",
|
||||
disabled: "media-playlist-consecutive-symbolic",
|
||||
enabled: 'media-playlist-shuffle-symbolic',
|
||||
disabled: 'media-playlist-consecutive-symbolic',
|
||||
},
|
||||
loop: {
|
||||
none: "media-playlist-repeat-symbolic",
|
||||
track: "media-playlist-repeat-song-symbolic",
|
||||
playlist: "media-playlist-repeat-symbolic",
|
||||
none: 'media-playlist-repeat-symbolic',
|
||||
track: 'media-playlist-repeat-song-symbolic',
|
||||
playlist: 'media-playlist-repeat-symbolic',
|
||||
},
|
||||
playing: "media-playback-pause-symbolic",
|
||||
paused: "media-playback-start-symbolic",
|
||||
stopped: "media-playback-start-symbolic",
|
||||
prev: "media-skip-backward-symbolic",
|
||||
next: "media-skip-forward-symbolic",
|
||||
playing: 'media-playback-pause-symbolic',
|
||||
paused: 'media-playback-start-symbolic',
|
||||
stopped: 'media-playback-start-symbolic',
|
||||
prev: 'media-skip-backward-symbolic',
|
||||
next: 'media-skip-forward-symbolic',
|
||||
},
|
||||
system: {
|
||||
cpu: "org.gnome.SystemMonitor-symbolic",
|
||||
ram: "drive-harddisk-solidstate-symbolic",
|
||||
temp: "temperature-symbolic",
|
||||
cpu: 'org.gnome.SystemMonitor-symbolic',
|
||||
ram: 'drive-harddisk-solidstate-symbolic',
|
||||
temp: 'temperature-symbolic',
|
||||
},
|
||||
color: {
|
||||
dark: "dark-mode-symbolic",
|
||||
light: "light-mode-symbolic",
|
||||
dark: 'dark-mode-symbolic',
|
||||
light: 'light-mode-symbolic',
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
150
lib/option.ts
150
lib/option.ts
@@ -1,70 +1,73 @@
|
||||
import { isHexColor } from "globals/variables"
|
||||
import { Variable } from "resource:///com/github/Aylur/ags/variable.js"
|
||||
import { isHexColor } from 'globals/variables';
|
||||
import { Variable } from 'resource:///com/github/Aylur/ags/variable.js';
|
||||
import { MkOptionsResult } from './types/options';
|
||||
|
||||
type OptProps = {
|
||||
persistent?: boolean
|
||||
}
|
||||
persistent?: boolean;
|
||||
};
|
||||
|
||||
export class Opt<T = unknown> extends Variable<T> {
|
||||
static { Service.register(this) }
|
||||
static {
|
||||
Service.register(this);
|
||||
}
|
||||
|
||||
constructor(initial: T, { persistent = false }: OptProps = {}) {
|
||||
super(initial)
|
||||
this.initial = initial
|
||||
this.persistent = persistent
|
||||
super(initial);
|
||||
this.initial = initial;
|
||||
this.persistent = persistent;
|
||||
}
|
||||
|
||||
initial: T
|
||||
id = ""
|
||||
persistent: boolean
|
||||
toString() { return `${this.value}` }
|
||||
toJSON() { return `opt:${this.value}` }
|
||||
initial: T;
|
||||
id = '';
|
||||
persistent: boolean;
|
||||
toString(): string {
|
||||
return `${this.value}`;
|
||||
}
|
||||
toJSON(): string {
|
||||
return `opt:${this.value}`;
|
||||
}
|
||||
|
||||
getValue = (): T => {
|
||||
return super.getValue()
|
||||
return super.getValue();
|
||||
};
|
||||
init(cacheFile: string): void {
|
||||
const cacheV = JSON.parse(Utils.readFile(cacheFile) || '{}')[this.id];
|
||||
if (cacheV !== undefined) this.value = cacheV;
|
||||
|
||||
this.connect('changed', () => {
|
||||
const cache = JSON.parse(Utils.readFile(cacheFile) || '{}');
|
||||
cache[this.id] = this.value;
|
||||
Utils.writeFileSync(JSON.stringify(cache, null, 2), cacheFile);
|
||||
});
|
||||
}
|
||||
|
||||
init(cacheFile: string) {
|
||||
const cacheV = JSON.parse(Utils.readFile(cacheFile) || "{}")[this.id]
|
||||
if (cacheV !== undefined)
|
||||
this.value = cacheV
|
||||
|
||||
this.connect("changed", () => {
|
||||
const cache = JSON.parse(Utils.readFile(cacheFile) || "{}")
|
||||
cache[this.id] = this.value
|
||||
Utils.writeFileSync(JSON.stringify(cache, null, 2), cacheFile)
|
||||
})
|
||||
}
|
||||
|
||||
reset() {
|
||||
if (this.persistent)
|
||||
return;
|
||||
reset(): string | undefined {
|
||||
if (this.persistent) return;
|
||||
|
||||
if (JSON.stringify(this.value) !== JSON.stringify(this.initial)) {
|
||||
this.value = this.initial
|
||||
this.value = this.initial;
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
||||
doResetColor() {
|
||||
if (this.persistent)
|
||||
return;
|
||||
doResetColor(): string | undefined {
|
||||
if (this.persistent) return;
|
||||
|
||||
const isColor = isHexColor(this.value as string);
|
||||
if ((JSON.stringify(this.value) !== JSON.stringify(this.initial)) && isColor) {
|
||||
this.value = this.initial
|
||||
return this.id
|
||||
if (JSON.stringify(this.value) !== JSON.stringify(this.initial) && isColor) {
|
||||
this.value = this.initial;
|
||||
return this.id;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export const opt = <T>(initial: T, opts?: OptProps) => new Opt(initial, opts)
|
||||
export const opt = <T>(initial: T, opts?: OptProps): Opt<T> => new Opt(initial, opts);
|
||||
|
||||
function getOptions(object: Record<string, unknown>, path = ""): Opt[] {
|
||||
return Object.keys(object).flatMap(key => {
|
||||
const getOptions = (object: Record<string, unknown>, path = ''): Opt[] => {
|
||||
return Object.keys(object).flatMap((key) => {
|
||||
const obj = object[key];
|
||||
const id = path ? path + "." + key : key;
|
||||
const id = path ? path + '.' + key : key;
|
||||
|
||||
if (obj instanceof Variable) {
|
||||
const optValue = obj as Opt;
|
||||
@@ -72,74 +75,73 @@ function getOptions(object: Record<string, unknown>, path = ""): Opt[] {
|
||||
return optValue;
|
||||
}
|
||||
|
||||
if (typeof obj === "object" && obj !== null) {
|
||||
if (typeof obj === 'object' && obj !== null) {
|
||||
return getOptions(obj as Record<string, unknown>, id); // Recursively process nested objects
|
||||
}
|
||||
|
||||
return [];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function mkOptions<T extends object>(cacheFile: string, object: T, confFile: string = "config.json") {
|
||||
for (const opt of getOptions(object as Record<string, unknown>))
|
||||
opt.init(cacheFile)
|
||||
export function mkOptions<T extends object>(
|
||||
cacheFile: string,
|
||||
object: T,
|
||||
confFile: string = 'config.json',
|
||||
): T & MkOptionsResult<T> {
|
||||
for (const opt of getOptions(object as Record<string, unknown>)) opt.init(cacheFile);
|
||||
|
||||
Utils.ensureDirectory(cacheFile.split("/").slice(0, -1).join("/"))
|
||||
Utils.ensureDirectory(cacheFile.split('/').slice(0, -1).join('/'));
|
||||
|
||||
const configFile = `${TMP}/${confFile}`
|
||||
const values = getOptions(object as Record<string, unknown>).reduce((obj, { id, value }) => ({ [id]: value, ...obj }), {})
|
||||
Utils.writeFileSync(JSON.stringify(values, null, 2), configFile)
|
||||
const configFile = `${TMP}/${confFile}`;
|
||||
const values = getOptions(object as Record<string, unknown>).reduce(
|
||||
(obj, { id, value }) => ({ [id]: value, ...obj }),
|
||||
{},
|
||||
);
|
||||
Utils.writeFileSync(JSON.stringify(values, null, 2), configFile);
|
||||
Utils.monitorFile(configFile, () => {
|
||||
const cache = JSON.parse(Utils.readFile(configFile) || "{}")
|
||||
const cache = JSON.parse(Utils.readFile(configFile) || '{}');
|
||||
for (const opt of getOptions(object as Record<string, unknown>)) {
|
||||
if (JSON.stringify(cache[opt.id]) !== JSON.stringify(opt.value))
|
||||
opt.value = cache[opt.id]
|
||||
if (JSON.stringify(cache[opt.id]) !== JSON.stringify(opt.value)) opt.value = cache[opt.id];
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
function sleep(ms = 0): Promise<T> {
|
||||
return new Promise(r => setTimeout(r, ms))
|
||||
return new Promise((r) => setTimeout(r, ms));
|
||||
}
|
||||
|
||||
async function reset(
|
||||
const reset = async (
|
||||
[opt, ...list] = getOptions(object as Record<string, unknown>),
|
||||
id = opt?.reset(),
|
||||
): Promise<Array<string>> {
|
||||
if (!opt)
|
||||
return sleep().then(() => [])
|
||||
): Promise<Array<string>> => {
|
||||
if (!opt) return sleep().then(() => []);
|
||||
|
||||
return id
|
||||
? [id, ...(await sleep(50).then(() => reset(list)))]
|
||||
: await sleep().then(() => reset(list))
|
||||
}
|
||||
return id ? [id, ...(await sleep(50).then(() => reset(list)))] : await sleep().then(() => reset(list));
|
||||
};
|
||||
|
||||
async function resetTheme(
|
||||
const resetTheme = async (
|
||||
[opt, ...list] = getOptions(object as Record<string, unknown>),
|
||||
id = opt?.doResetColor(),
|
||||
): Promise<Array<string>> {
|
||||
if (!opt)
|
||||
return sleep().then(() => [])
|
||||
): Promise<Array<string>> => {
|
||||
if (!opt) return sleep().then(() => []);
|
||||
|
||||
return id
|
||||
? [id, ...(await sleep(50).then(() => resetTheme(list)))]
|
||||
: await sleep().then(() => resetTheme(list))
|
||||
}
|
||||
: await sleep().then(() => resetTheme(list));
|
||||
};
|
||||
|
||||
return Object.assign(object, {
|
||||
configFile,
|
||||
array: () => getOptions(object as Record<string, unknown>),
|
||||
async reset() {
|
||||
return (await reset()).join("\n")
|
||||
return (await reset()).join('\n');
|
||||
},
|
||||
async resetTheme() {
|
||||
return (await resetTheme()).join("\n")
|
||||
return (await resetTheme()).join('\n');
|
||||
},
|
||||
handler(deps: string[], callback: () => void) {
|
||||
for (const opt of getOptions(object as Record<string, unknown>)) {
|
||||
if (deps.some(i => opt.id.startsWith(i)))
|
||||
opt.connect("changed", callback)
|
||||
if (deps.some((i) => opt.id.startsWith(i))) opt.connect('changed', callback);
|
||||
}
|
||||
},
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import GLib from "gi://GLib?version=2.0"
|
||||
import GLib from 'gi://GLib?version=2.0';
|
||||
|
||||
declare global {
|
||||
const OPTIONS: string
|
||||
const TMP: string
|
||||
const USER: string
|
||||
const OPTIONS: string;
|
||||
const TMP: string;
|
||||
const USER: string;
|
||||
}
|
||||
|
||||
Object.assign(globalThis, {
|
||||
OPTIONS: `${GLib.get_user_cache_dir()}/ags/hyprpanel/options.json`,
|
||||
TMP: `${GLib.get_tmp_dir()}/ags/hyprpanel`,
|
||||
USER: GLib.get_user_name(),
|
||||
})
|
||||
});
|
||||
|
||||
Utils.ensureDirectory(TMP)
|
||||
App.addIcons(`${App.configDir}/assets`)
|
||||
Utils.ensureDirectory(TMP);
|
||||
App.addIcons(`${App.configDir}/assets`);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MprisPlayer } from "types/service/mpris";
|
||||
const mpris = await Service.import("mpris");
|
||||
import { MprisPlayer } from 'types/service/mpris';
|
||||
const mpris = await Service.import('mpris');
|
||||
|
||||
export const getCurrentPlayer = (activePlayer: MprisPlayer = mpris.players[0]): MprisPlayer => {
|
||||
const statusOrder = {
|
||||
@@ -12,18 +12,12 @@ export const getCurrentPlayer = (activePlayer: MprisPlayer = mpris.players[0]):
|
||||
return mpris.players[0];
|
||||
}
|
||||
|
||||
const isPlaying = mpris.players.some(
|
||||
(p: MprisPlayer) => p.play_back_status === "Playing",
|
||||
);
|
||||
const isPlaying = mpris.players.some((p: MprisPlayer) => p.play_back_status === 'Playing');
|
||||
|
||||
const playerStillExists = mpris.players.some(
|
||||
(p) => activePlayer.bus_name === p.bus_name
|
||||
);
|
||||
const playerStillExists = mpris.players.some((p) => activePlayer.bus_name === p.bus_name);
|
||||
|
||||
const nextPlayerUp = mpris.players.sort(
|
||||
(a: MprisPlayer, b: MprisPlayer) =>
|
||||
statusOrder[a.play_back_status] -
|
||||
statusOrder[b.play_back_status],
|
||||
(a: MprisPlayer, b: MprisPlayer) => statusOrder[a.play_back_status] - statusOrder[b.play_back_status],
|
||||
)[0];
|
||||
|
||||
if (isPlaying || !playerStillExists) {
|
||||
@@ -31,4 +25,4 @@ export const getCurrentPlayer = (activePlayer: MprisPlayer = mpris.players[0]):
|
||||
}
|
||||
|
||||
return activePlayer;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { Notification } from "types/service/notifications";
|
||||
import { Notification } from 'types/service/notifications';
|
||||
|
||||
export const filterNotifications = (notifications: Notification[], filter: string[]): Notification[] => {
|
||||
|
||||
const notifFilter = new Set(
|
||||
filter.map((name: string) => name.toLowerCase().replace(/\s+/g, '_'))
|
||||
);
|
||||
const notifFilter = new Set(filter.map((name: string) => name.toLowerCase().replace(/\s+/g, '_')));
|
||||
|
||||
const filteredNotifications = notifications.filter((notif: Notification) => {
|
||||
const normalizedAppName = notif.app_name.toLowerCase().replace(/\s+/g, '_');
|
||||
@@ -12,4 +9,4 @@ export const filterNotifications = (notifications: Notification[], filter: strin
|
||||
});
|
||||
|
||||
return filteredNotifications;
|
||||
}
|
||||
};
|
||||
|
||||
5
lib/types/audio.d.ts
vendored
Normal file
5
lib/types/audio.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export type InputDevices = Button<Box<Box<Label<Attribute>, Attribute>, Attribute>, Attribute>[];
|
||||
|
||||
type DummyDevices = Button<Box<Box<Label<Attribute>, Attribute>, Attribute>, Attribute>[];
|
||||
type RealPlaybackDevices = Button<Box<Box<Label<Attribute>, Attribute>, Attribute>, Attribute>[];
|
||||
export type PlaybackDevices = DummyDevices | RealPlaybackDevices;
|
||||
58
lib/types/bar.d.ts
vendored
58
lib/types/bar.d.ts
vendored
@@ -1,43 +1,45 @@
|
||||
import { Binding, Connectable } from "types/service"
|
||||
import { Variable } from "types/variable"
|
||||
import Box from "types/widgets/box";
|
||||
import Label from "types/widgets/label";
|
||||
import { Widget as WidgetType } from "types/widgets/widget"
|
||||
import { Binding, Connectable } from 'types/service';
|
||||
import { Variable } from 'types/variable';
|
||||
import Box from 'types/widgets/box';
|
||||
import Button from 'types/widgets/button';
|
||||
import Label from 'types/widgets/label';
|
||||
import { Attribute, Child } from './widget';
|
||||
|
||||
export type Child = {
|
||||
export type BarBoxChild = {
|
||||
component: Box<Gtk.Widget, unknown>;
|
||||
isVisible?: boolean;
|
||||
isVis?: Variable<boolean>;
|
||||
boxClass: string;
|
||||
props: ButtonProps;
|
||||
};
|
||||
} & ButtonProps;
|
||||
|
||||
export type SelfButton = Button<Child, Attribute>;
|
||||
|
||||
export type BoxHook = (self: Box<Gtk.Widget, Gtk.Widget>) => void;
|
||||
export type LabelHook = (self: Label<Gtk.Widget>) => void;
|
||||
|
||||
export type Module = {
|
||||
icon?: string | Binding<string>,
|
||||
textIcon?: string | Binding<string>,
|
||||
label?: string | Binding<string>,
|
||||
labelHook?: LabelHook,
|
||||
boundLabel?: string,
|
||||
tooltipText?: string | Binding<string>,
|
||||
boxClass: string,
|
||||
props?: ButtonProps,
|
||||
showLabel?: boolean,
|
||||
showLabelBinding?: Binding,
|
||||
hook?: BoxHook,
|
||||
connection?: Binding<Connectable>
|
||||
}
|
||||
icon?: string | Binding<string>;
|
||||
textIcon?: string | Binding<string>;
|
||||
label?: string | Binding<string>;
|
||||
labelHook?: LabelHook;
|
||||
boundLabel?: string;
|
||||
tooltipText?: string | Binding<string>;
|
||||
boxClass: string;
|
||||
props?: ButtonProps;
|
||||
showLabel?: boolean;
|
||||
showLabelBinding?: Binding;
|
||||
hook?: BoxHook;
|
||||
connection?: Binding<Connectable>;
|
||||
};
|
||||
|
||||
export type ResourceLabelType = "used/total" | "used" | "percentage" | "free";
|
||||
export type ResourceLabelType = 'used/total' | 'used' | 'percentage' | 'free';
|
||||
|
||||
export type StorageIcon = "" | "" | "" | "" | "" | "";
|
||||
export type StorageIcon = '' | '' | '' | '' | '' | '';
|
||||
|
||||
export type NetstatIcon = "" | "" | "" | "" | "" | "" | "" | "" | "";
|
||||
export type NetstatLabelType = "full" | "in" | "out";
|
||||
export type RateUnit = "GiB" | "MiB" | "KiB" | "auto";
|
||||
export type NetstatIcon = '' | '' | '' | '' | '' | '' | '' | '' | '';
|
||||
export type NetstatLabelType = 'full' | 'in' | 'out';
|
||||
export type RateUnit = 'GiB' | 'MiB' | 'KiB' | 'auto';
|
||||
|
||||
export type UpdatesIcon = "" | "" | "" | "" | "" | "" | "" | "" | "";
|
||||
export type UpdatesIcon = '' | '' | '' | '' | '' | '' | '' | '' | '';
|
||||
|
||||
export type PowerIcon = "" | "" | "" | "" | "" | "";
|
||||
export type PowerIcon = '' | '' | '' | '' | '' | '';
|
||||
|
||||
13
lib/types/customModules/generic.d.ts
vendored
13
lib/types/customModules/generic.d.ts
vendored
@@ -1,6 +1,13 @@
|
||||
export type GenericResourceData = {
|
||||
export type GenericFunction<T, P extends unknown[] = unknown[]> = (...args: P) => T;
|
||||
|
||||
export type GenericResourceMetrics = {
|
||||
total: number;
|
||||
used: number;
|
||||
free: number;
|
||||
percentage: number;
|
||||
}
|
||||
};
|
||||
|
||||
type GenericResourceData = ResourceUsage & {
|
||||
free: number;
|
||||
};
|
||||
|
||||
export type Postfix = 'TiB' | 'GiB' | 'MiB' | 'KiB' | 'B';
|
||||
|
||||
14
lib/types/customModules/kbLayout.d.ts
vendored
14
lib/types/customModules/kbLayout.d.ts
vendored
@@ -1,7 +1,7 @@
|
||||
import { layoutMap } from "customModules/kblayout/layouts";
|
||||
import { layoutMap } from 'customModules/kblayout/layouts';
|
||||
|
||||
export type KbLabelType = "layout" | "code";
|
||||
export type KbIcon = "" | "" | "" | "" | "";
|
||||
export type KbLabelType = 'layout' | 'code';
|
||||
export type KbIcon = '' | '' | '' | '' | '';
|
||||
|
||||
export type HyprctlKeyboard = {
|
||||
address: string;
|
||||
@@ -24,10 +24,10 @@ export type HyprctlMouse = {
|
||||
export type HyprctlDeviceLayout = {
|
||||
mice: HyprctlMouse[];
|
||||
keyboards: HyprctlKeyboard[];
|
||||
tablets: any[];
|
||||
touch: any[];
|
||||
switches: any[];
|
||||
tablets: unknown[];
|
||||
touch: unknown[];
|
||||
switches: unknown[];
|
||||
};
|
||||
|
||||
export type LayoutKeys = keyof typeof layoutMap;
|
||||
export type LayoutValues = typeof layoutMap[LayoutKeys];
|
||||
export type LayoutValues = (typeof layoutMap)[LayoutKeys];
|
||||
|
||||
3
lib/types/customModules/network.d.ts
vendored
3
lib/types/customModules/network.d.ts
vendored
@@ -1,5 +1,4 @@
|
||||
export type NetworkResourceData = {
|
||||
in: string;
|
||||
out: string;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
14
lib/types/customModules/utils.d.ts
vendored
14
lib/types/customModules/utils.d.ts
vendored
@@ -1,9 +1,9 @@
|
||||
import { Binding } from "lib/utils";
|
||||
import { Binding } from 'lib/utils';
|
||||
|
||||
export type InputHandlerEvents = {
|
||||
onPrimaryClick?: Binding,
|
||||
onSecondaryClick?: Binding,
|
||||
onMiddleClick?: Binding,
|
||||
onScrollUp?: Binding,
|
||||
onScrollDown?: Binding,
|
||||
}
|
||||
onPrimaryClick?: Binding;
|
||||
onSecondaryClick?: Binding;
|
||||
onMiddleClick?: Binding;
|
||||
onScrollUp?: Binding;
|
||||
onScrollDown?: Binding;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NetstatLabelType, ResourceLabelType } from "../bar";
|
||||
import { NetstatLabelType, ResourceLabelType } from '../bar';
|
||||
|
||||
export const LABEL_TYPES: ResourceLabelType[] = ["used/total", "used", "free", "percentage"];
|
||||
export const LABEL_TYPES: ResourceLabelType[] = ['used/total', 'used', 'free', 'percentage'];
|
||||
|
||||
export const NETWORK_LABEL_TYPES: NetstatLabelType[] = ["full", "in", "out"];
|
||||
export const NETWORK_LABEL_TYPES: NetstatLabelType[] = ['full', 'in', 'out'];
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { RateUnit } from "../bar";
|
||||
import { NetworkResourceData } from "../customModules/network";
|
||||
import { RateUnit } from '../bar';
|
||||
import { NetworkResourceData } from '../customModules/network';
|
||||
|
||||
export const GET_DEFAULT_NETSTAT_DATA = (dataType: RateUnit): NetworkResourceData => {
|
||||
if (dataType === 'auto') {
|
||||
return { in: `0 Kib/s`, out: `0 Kib/s` }
|
||||
return { in: `0 Kib/s`, out: `0 Kib/s` };
|
||||
}
|
||||
|
||||
return { in: `0 ${dataType}/s`, out: `0 ${dataType}/s` }
|
||||
return { in: `0 ${dataType}/s`, out: `0 ${dataType}/s` };
|
||||
};
|
||||
|
||||
@@ -1,60 +1,60 @@
|
||||
export const defaultColorMap = {
|
||||
"rosewater": "#f5e0dc",
|
||||
"flamingo": "#f2cdcd",
|
||||
"pink": "#f5c2e7",
|
||||
"mauve": "#cba6f7",
|
||||
"red": "#f38ba8",
|
||||
"maroon": "#eba0ac",
|
||||
"peach": "#fab387",
|
||||
"yellow": "#f9e2af",
|
||||
"green": "#a6e3a1",
|
||||
"teal": "#94e2d5",
|
||||
"sky": "#89dceb",
|
||||
"sapphire": "#74c7ec",
|
||||
"blue": "#89b4fa",
|
||||
"lavender": "#b4befe",
|
||||
"text": "#cdd6f4",
|
||||
"subtext1": "#bac2de",
|
||||
"subtext2": "#a6adc8",
|
||||
"overlay2": "#9399b2",
|
||||
"overlay1": "#7f849c",
|
||||
"overlay0": "#6c7086",
|
||||
"surface2": "#585b70",
|
||||
"surface1": "#45475a",
|
||||
"surface0": "#313244",
|
||||
"base2": "#242438",
|
||||
"base": "#1e1e2e",
|
||||
"mantle": "#181825",
|
||||
"crust": "#11111b",
|
||||
"surface1_2": "#454759",
|
||||
"text2": "#cdd6f3",
|
||||
"pink2": "#f5c2e6",
|
||||
"red2": "#f38ba7",
|
||||
"peach2": "#fab386",
|
||||
"mantle2": "#181824",
|
||||
"surface0_2": "#313243",
|
||||
"surface2_2": "#585b69",
|
||||
"overlay1_2": "#7f849b",
|
||||
"lavender2": "#b4befd",
|
||||
"mauve2": "#cba6f6",
|
||||
"green2": "#a6e3a0",
|
||||
"sky2": "#89dcea",
|
||||
"teal2": "#94e2d4",
|
||||
"yellow2": "#f9e2ad",
|
||||
"maroon2": "#eba0ab",
|
||||
"crust2": "#11111a",
|
||||
"pink3": "#f5c2e8",
|
||||
"red3": "#f38ba9",
|
||||
"mantle3": "#181826",
|
||||
"surface0_3": "#313245",
|
||||
"surface2_3": "#585b71",
|
||||
"overlay1_3": "#7f849d",
|
||||
"lavender3": "#b4beff",
|
||||
"mauve3": "#cba6f8",
|
||||
"green3": "#a6e3a2",
|
||||
"sky3": "#89dcec",
|
||||
"teal3": "#94e2d6",
|
||||
"yellow3": "#f9e2ae",
|
||||
"maroon3": "#eba0ad",
|
||||
"crust3": "#11111c",
|
||||
};
|
||||
rosewater: '#f5e0dc',
|
||||
flamingo: '#f2cdcd',
|
||||
pink: '#f5c2e7',
|
||||
mauve: '#cba6f7',
|
||||
red: '#f38ba8',
|
||||
maroon: '#eba0ac',
|
||||
peach: '#fab387',
|
||||
yellow: '#f9e2af',
|
||||
green: '#a6e3a1',
|
||||
teal: '#94e2d5',
|
||||
sky: '#89dceb',
|
||||
sapphire: '#74c7ec',
|
||||
blue: '#89b4fa',
|
||||
lavender: '#b4befe',
|
||||
text: '#cdd6f4',
|
||||
subtext1: '#bac2de',
|
||||
subtext2: '#a6adc8',
|
||||
overlay2: '#9399b2',
|
||||
overlay1: '#7f849c',
|
||||
overlay0: '#6c7086',
|
||||
surface2: '#585b70',
|
||||
surface1: '#45475a',
|
||||
surface0: '#313244',
|
||||
base2: '#242438',
|
||||
base: '#1e1e2e',
|
||||
mantle: '#181825',
|
||||
crust: '#11111b',
|
||||
surface1_2: '#454759',
|
||||
text2: '#cdd6f3',
|
||||
pink2: '#f5c2e6',
|
||||
red2: '#f38ba7',
|
||||
peach2: '#fab386',
|
||||
mantle2: '#181824',
|
||||
surface0_2: '#313243',
|
||||
surface2_2: '#585b69',
|
||||
overlay1_2: '#7f849b',
|
||||
lavender2: '#b4befd',
|
||||
mauve2: '#cba6f6',
|
||||
green2: '#a6e3a0',
|
||||
sky2: '#89dcea',
|
||||
teal2: '#94e2d4',
|
||||
yellow2: '#f9e2ad',
|
||||
maroon2: '#eba0ab',
|
||||
crust2: '#11111a',
|
||||
pink3: '#f5c2e8',
|
||||
red3: '#f38ba9',
|
||||
mantle3: '#181826',
|
||||
surface0_3: '#313245',
|
||||
surface2_3: '#585b71',
|
||||
overlay1_3: '#7f849d',
|
||||
lavender3: '#b4beff',
|
||||
mauve3: '#cba6f8',
|
||||
green3: '#a6e3a2',
|
||||
sky3: '#89dcec',
|
||||
teal3: '#94e2d6',
|
||||
yellow3: '#f9e2ae',
|
||||
maroon3: '#eba0ad',
|
||||
crust3: '#11111c',
|
||||
} as const;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
7
lib/types/dropdownmenu.d.ts
vendored
7
lib/types/dropdownmenu.d.ts
vendored
@@ -1,10 +1,11 @@
|
||||
import { WindowProps } from "types/widgets/window";
|
||||
import { WindowProps } from 'types/widgets/window';
|
||||
import { GtkWidget, Transition } from './widget';
|
||||
|
||||
export type DropdownMenuProps = {
|
||||
name: string;
|
||||
child: any;
|
||||
child: GtkWidget;
|
||||
layout?: string;
|
||||
transition?: any;
|
||||
transition?: Transition;
|
||||
exclusivity?: Exclusivity;
|
||||
fixed?: boolean;
|
||||
} & WindowProps;
|
||||
|
||||
2
lib/types/filechooser.d.ts
vendored
2
lib/types/filechooser.d.ts
vendored
@@ -1,3 +1,3 @@
|
||||
export type Config = {
|
||||
[key: string]: string | number | boolean | object;
|
||||
}
|
||||
};
|
||||
|
||||
18
lib/types/gpustat.d.ts
vendored
18
lib/types/gpustat.d.ts
vendored
@@ -12,14 +12,14 @@ export type GPU_Stat = {
|
||||
index: number;
|
||||
uuid: string;
|
||||
name: string;
|
||||
"temperature.gpu": number;
|
||||
"fan.speed": number;
|
||||
"utilization.gpu": number;
|
||||
"utilization.enc": number;
|
||||
"utilization.dec": number;
|
||||
"power.draw": number;
|
||||
"enforced.power.limit": number;
|
||||
"memory.used": number;
|
||||
"memory.total": number;
|
||||
'temperature.gpu': number;
|
||||
'fan.speed': number;
|
||||
'utilization.gpu': number;
|
||||
'utilization.enc': number;
|
||||
'utilization.dec': number;
|
||||
'power.draw': number;
|
||||
'enforced.power.limit': number;
|
||||
'memory.used': number;
|
||||
'memory.total': number;
|
||||
processes: Process[];
|
||||
};
|
||||
|
||||
1
lib/types/mpris.d.ts
vendored
1
lib/types/mpris.d.ts
vendored
@@ -1,3 +1,2 @@
|
||||
export type LoopStatus = 'none' | 'track' | 'playlist';
|
||||
export type PlaybackStatus = 'playing' | 'paused' | 'stopped';
|
||||
|
||||
|
||||
6
lib/types/network.d.ts
vendored
6
lib/types/network.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
import { WIFI_STATUS_MAP } from "globals/network";
|
||||
import { WIFI_STATUS_MAP } from 'globals/network';
|
||||
|
||||
export type AccessPoint = {
|
||||
bssid: string | null;
|
||||
@@ -9,6 +9,8 @@ export type AccessPoint = {
|
||||
strength: number;
|
||||
frequency: number;
|
||||
iconName: string | undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export type WifiStatus = keyof typeof WIFI_STATUS_MAP;
|
||||
|
||||
export type WifiIcon = '' | '' | '' | '' | '' | '' | '' | '' | '' | '' | '';
|
||||
|
||||
2
lib/types/notification.d.ts
vendored
2
lib/types/notification.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
import icons from "modules/icons/index";
|
||||
import icons from 'modules/icons/index';
|
||||
|
||||
export interface NotificationArgs {
|
||||
appName?: string;
|
||||
|
||||
301
lib/types/options.d.ts
vendored
301
lib/types/options.d.ts
vendored
@@ -1,126 +1,213 @@
|
||||
import { Opt } from "lib/option";
|
||||
import { Variable } from "types/variable";
|
||||
import { Opt } from 'lib/option';
|
||||
import { Variable } from 'types/variable';
|
||||
import { defaultColorMap } from './defaults/options';
|
||||
|
||||
export type MkOptionsResult<T> = {
|
||||
configFile: string;
|
||||
array: () => Opt[];
|
||||
reset: () => Promise<string>;
|
||||
resetTheme: () => Promise<string>;
|
||||
handler: (deps: string[], callback: () => void) => void;
|
||||
};
|
||||
|
||||
export type RecursiveOptionsObject = {
|
||||
[key: string]: RecursiveOptionsObject | Opt<string | number | boolean> | Opt<any>;
|
||||
};
|
||||
|
||||
export type Unit = "imperial" | "metric";
|
||||
export type PowerOptions = "sleep" | "reboot" | "logout" | "shutdown";
|
||||
export type NotificationAnchor = "top" | "top right" | "top left" | "bottom" | "bottom right" | "bottom left" | "left" | "right";
|
||||
export type OSDAnchor = "top left" | "top" | "top right" | "right" | "bottom right" | "bottom" | "bottom left" | "left";
|
||||
export type BarButtonStyles = "default" | "split" | "wave" | "wave2";
|
||||
export type Unit = 'imperial' | 'metric';
|
||||
export type PowerOptions = 'sleep' | 'reboot' | 'logout' | 'shutdown';
|
||||
export type NotificationAnchor =
|
||||
| 'top'
|
||||
| 'top right'
|
||||
| 'top left'
|
||||
| 'bottom'
|
||||
| 'bottom right'
|
||||
| 'bottom left'
|
||||
| 'left'
|
||||
| 'right';
|
||||
export type OSDAnchor = 'top left' | 'top' | 'top right' | 'right' | 'bottom right' | 'bottom' | 'bottom left' | 'left';
|
||||
export type BarButtonStyles = 'default' | 'split' | 'wave' | 'wave2';
|
||||
|
||||
export type ThemeExportData = {
|
||||
filePath: string,
|
||||
themeOnly: boolean
|
||||
}
|
||||
filePath: string;
|
||||
themeOnly: boolean;
|
||||
};
|
||||
export type RowProps<T> = {
|
||||
opt: Opt<T>
|
||||
title: string
|
||||
note?: string
|
||||
opt: Opt<T>;
|
||||
title: string;
|
||||
note?: string;
|
||||
type?:
|
||||
| "number"
|
||||
| "color"
|
||||
| "float"
|
||||
| "object"
|
||||
| "string"
|
||||
| "enum"
|
||||
| "boolean"
|
||||
| "img"
|
||||
| "wallpaper"
|
||||
| "export"
|
||||
| "import"
|
||||
| "config_import"
|
||||
| "font"
|
||||
enums?: string[]
|
||||
max?: number
|
||||
min?: number
|
||||
disabledBinding?: Variable<boolean>
|
||||
exportData?: ThemeExportData
|
||||
subtitle?: string | VarType<any> | Opt,
|
||||
subtitleLink?: string,
|
||||
dependencies?: string[],
|
||||
increment?: number
|
||||
}
|
||||
| 'number'
|
||||
| 'color'
|
||||
| 'float'
|
||||
| 'object'
|
||||
| 'string'
|
||||
| 'enum'
|
||||
| 'boolean'
|
||||
| 'img'
|
||||
| 'wallpaper'
|
||||
| 'export'
|
||||
| 'import'
|
||||
| 'config_import'
|
||||
| 'font';
|
||||
enums?: T[];
|
||||
max?: number;
|
||||
min?: number;
|
||||
disabledBinding?: Variable<boolean>;
|
||||
exportData?: ThemeExportData;
|
||||
subtitle?: string | VarType<any> | Opt;
|
||||
subtitleLink?: string;
|
||||
dependencies?: string[];
|
||||
increment?: number;
|
||||
};
|
||||
|
||||
export type OSDOrientation = "horizontal" | "vertical";
|
||||
export type OSDOrientation = 'horizontal' | 'vertical';
|
||||
|
||||
export type HexColor = `#${string}`;
|
||||
|
||||
export type WindowLayer = "top" | "bottom" | "overlay" | "background";
|
||||
export type WindowLayer = 'top' | 'bottom' | 'overlay' | 'background';
|
||||
|
||||
export type ActiveWsIndicator = 'underline' | 'highlight' | 'color';
|
||||
|
||||
export type MatugenColors = {
|
||||
"background": HexColor,
|
||||
"error": HexColor,
|
||||
"error_container": HexColor,
|
||||
"inverse_on_surface": HexColor,
|
||||
"inverse_primary": HexColor,
|
||||
"inverse_surface": HexColor,
|
||||
"on_background": HexColor,
|
||||
"on_error": HexColor,
|
||||
"on_error_container": HexColor,
|
||||
"on_primary": HexColor,
|
||||
"on_primary_container": HexColor,
|
||||
"on_primary_fixed": HexColor,
|
||||
"on_primary_fixed_variant": HexColor,
|
||||
"on_secondary": HexColor,
|
||||
"on_secondary_container": HexColor,
|
||||
"on_secondary_fixed": HexColor,
|
||||
"on_secondary_fixed_variant": HexColor,
|
||||
"on_surface": HexColor,
|
||||
"on_surface_variant": HexColor,
|
||||
"on_tertiary": HexColor,
|
||||
"on_tertiary_container": HexColor,
|
||||
"on_tertiary_fixed": HexColor,
|
||||
"on_tertiary_fixed_variant": HexColor,
|
||||
"outline": HexColor,
|
||||
"outline_variant": HexColor,
|
||||
"primary": HexColor,
|
||||
"primary_container": HexColor,
|
||||
"primary_fixed": HexColor,
|
||||
"primary_fixed_dim": HexColor,
|
||||
"scrim": HexColor,
|
||||
"secondary": HexColor,
|
||||
"secondary_container": HexColor,
|
||||
"secondary_fixed": HexColor,
|
||||
"secondary_fixed_dim": HexColor,
|
||||
"shadow": HexColor,
|
||||
"surface": HexColor,
|
||||
"surface_bright": HexColor,
|
||||
"surface_container": HexColor,
|
||||
"surface_container_high": HexColor,
|
||||
"surface_container_highest": HexColor,
|
||||
"surface_container_low": HexColor,
|
||||
"surface_container_lowest": HexColor,
|
||||
"surface_dim": HexColor,
|
||||
"surface_variant": HexColor,
|
||||
"tertiary": HexColor,
|
||||
"tertiary_container": HexColor,
|
||||
"tertiary_fixed": HexColor,
|
||||
"tertiary_fixed_dim": HexColor
|
||||
}
|
||||
background: HexColor;
|
||||
error: HexColor;
|
||||
error_container: HexColor;
|
||||
inverse_on_surface: HexColor;
|
||||
inverse_primary: HexColor;
|
||||
inverse_surface: HexColor;
|
||||
on_background: HexColor;
|
||||
on_error: HexColor;
|
||||
on_error_container: HexColor;
|
||||
on_primary: HexColor;
|
||||
on_primary_container: HexColor;
|
||||
on_primary_fixed: HexColor;
|
||||
on_primary_fixed_variant: HexColor;
|
||||
on_secondary: HexColor;
|
||||
on_secondary_container: HexColor;
|
||||
on_secondary_fixed: HexColor;
|
||||
on_secondary_fixed_variant: HexColor;
|
||||
on_surface: HexColor;
|
||||
on_surface_variant: HexColor;
|
||||
on_tertiary: HexColor;
|
||||
on_tertiary_container: HexColor;
|
||||
on_tertiary_fixed: HexColor;
|
||||
on_tertiary_fixed_variant: HexColor;
|
||||
outline: HexColor;
|
||||
outline_variant: HexColor;
|
||||
primary: HexColor;
|
||||
primary_container: HexColor;
|
||||
primary_fixed: HexColor;
|
||||
primary_fixed_dim: HexColor;
|
||||
scrim: HexColor;
|
||||
secondary: HexColor;
|
||||
secondary_container: HexColor;
|
||||
secondary_fixed: HexColor;
|
||||
secondary_fixed_dim: HexColor;
|
||||
shadow: HexColor;
|
||||
surface: HexColor;
|
||||
surface_bright: HexColor;
|
||||
surface_container: HexColor;
|
||||
surface_container_high: HexColor;
|
||||
surface_container_highest: HexColor;
|
||||
surface_container_low: HexColor;
|
||||
surface_container_lowest: HexColor;
|
||||
surface_dim: HexColor;
|
||||
surface_variant: HexColor;
|
||||
tertiary: HexColor;
|
||||
tertiary_container: HexColor;
|
||||
tertiary_fixed: HexColor;
|
||||
tertiary_fixed_dim: HexColor;
|
||||
};
|
||||
|
||||
type MatugenScheme =
|
||||
| "content"
|
||||
| "expressive"
|
||||
| "fidelity"
|
||||
| "fruit-salad"
|
||||
| "monochrome"
|
||||
| "neutral"
|
||||
| "rainbow"
|
||||
| "tonal-spot";
|
||||
export type MatugenVariation = {
|
||||
rosewater: HexColor;
|
||||
flamingo: HexColor;
|
||||
pink: HexColor;
|
||||
mauve: HexColor;
|
||||
red: HexColor;
|
||||
maroon: HexColor;
|
||||
peach: HexColor;
|
||||
yellow: HexColor;
|
||||
green: HexColor;
|
||||
teal: HexColor;
|
||||
sky: HexColor;
|
||||
sapphire: HexColor;
|
||||
blue: HexColor;
|
||||
lavender: HexColor;
|
||||
text: HexColor;
|
||||
subtext1: HexColor;
|
||||
subtext2: HexColor;
|
||||
overlay2: HexColor;
|
||||
overlay1: HexColor;
|
||||
overlay0: HexColor;
|
||||
surface2: HexColor;
|
||||
surface1: HexColor;
|
||||
surface0: HexColor;
|
||||
base2: HexColor;
|
||||
base: HexColor;
|
||||
mantle: HexColor;
|
||||
crust: HexColor;
|
||||
notifications_closer: HexColor;
|
||||
notifications_background: HexColor;
|
||||
dashboard_btn_text: HexColor;
|
||||
red2: HexColor;
|
||||
peach2: HexColor;
|
||||
pink2: HexColor;
|
||||
mantle2: HexColor;
|
||||
surface1_2: HexColor;
|
||||
surface0_2: HexColor;
|
||||
overlay1_2: HexColor;
|
||||
text2: HexColor;
|
||||
lavender2: HexColor;
|
||||
crust2: HexColor;
|
||||
maroon2: HexColor;
|
||||
mauve2: HexColor;
|
||||
green2: HexColor;
|
||||
surface2_2: HexColor;
|
||||
sky2: HexColor;
|
||||
teal2: HexColor;
|
||||
yellow2: HexColor;
|
||||
pink3: HexColor;
|
||||
red3: HexColor;
|
||||
mantle3: HexColor;
|
||||
surface0_3: HexColor;
|
||||
surface2_3: HexColor;
|
||||
overlay1_3: HexColor;
|
||||
lavender3: HexColor;
|
||||
mauve3: HexColor;
|
||||
green3: HexColor;
|
||||
sky3: HexColor;
|
||||
teal3: HexColor;
|
||||
yellow3: HexColor;
|
||||
maroon3: HexColor;
|
||||
crust3: HexColor;
|
||||
notifications_closer?: HexColor;
|
||||
notifications_background?: HexColor;
|
||||
dashboard_btn_text?: HexColor;
|
||||
};
|
||||
export type MatugenScheme =
|
||||
| 'content'
|
||||
| 'expressive'
|
||||
| 'fidelity'
|
||||
| 'fruit-salad'
|
||||
| 'monochrome'
|
||||
| 'neutral'
|
||||
| 'rainbow'
|
||||
| 'tonal-spot';
|
||||
|
||||
type MatugenVariation =
|
||||
| "standard_1"
|
||||
| "standard_2"
|
||||
| "standard_3"
|
||||
| "monochrome_1"
|
||||
| "monochrome_2"
|
||||
| "monochrome_3"
|
||||
| "vivid_1"
|
||||
| "vivid_2"
|
||||
| "vivid_3"
|
||||
export type MatugenVariations =
|
||||
| 'standard_1'
|
||||
| 'standard_2'
|
||||
| 'standard_3'
|
||||
| 'monochrome_1'
|
||||
| 'monochrome_2'
|
||||
| 'monochrome_3'
|
||||
| 'vivid_1'
|
||||
| 'vivid_2'
|
||||
| 'vivid_3';
|
||||
|
||||
type MatugenTheme = "light" | "dark";
|
||||
type MatugenTheme = 'light' | 'dark';
|
||||
|
||||
export type ColorMapKey = keyof typeof defaultColorMap;
|
||||
export type ColorMapValue = (typeof defaultColorMap)[ColorMapKey];
|
||||
|
||||
30
lib/types/popupwindow.d.ts
vendored
30
lib/types/popupwindow.d.ts
vendored
@@ -1,6 +1,6 @@
|
||||
import { Widget } from "types/widgets/widget";
|
||||
import { WindowProps } from "types/widgets/window";
|
||||
import { Transition } from "./widget";
|
||||
import { Widget } from 'types/widgets/widget';
|
||||
import { WindowProps } from 'types/widgets/window';
|
||||
import { Transition } from './widget';
|
||||
|
||||
export type PopupWindowProps = {
|
||||
name: string;
|
||||
@@ -13,15 +13,23 @@ export type PopupWindowProps = {
|
||||
export type LayoutFunction = (
|
||||
name: string,
|
||||
child: Widget,
|
||||
transition: Transition
|
||||
transition: Transition,
|
||||
) => {
|
||||
center: () => Widget;
|
||||
top: () => Widget;
|
||||
"top-right": () => Widget;
|
||||
"top-center": () => Widget;
|
||||
"top-left": () => Widget;
|
||||
"bottom-left": () => Widget;
|
||||
"bottom-center": () => Widget;
|
||||
"bottom-right": () => Widget;
|
||||
'top-right': () => Widget;
|
||||
'top-center': () => Widget;
|
||||
'top-left': () => Widget;
|
||||
'bottom-left': () => Widget;
|
||||
'bottom-center': () => Widget;
|
||||
'bottom-right': () => Widget;
|
||||
};
|
||||
export type Layouts = 'center' | 'top' | 'top-right' | 'top-center' | 'top-left' | 'bottom-left' | 'bottom-center' | 'bottom-right';
|
||||
export type Layouts =
|
||||
| 'center'
|
||||
| 'top'
|
||||
| 'top-right'
|
||||
| 'top-center'
|
||||
| 'top-left'
|
||||
| 'bottom-left'
|
||||
| 'bottom-center'
|
||||
| 'bottom-right';
|
||||
|
||||
2
lib/types/power.d.ts
vendored
2
lib/types/power.d.ts
vendored
@@ -1 +1 @@
|
||||
export type Action = "sleep" | "reboot" | "logout" | "shutdown";
|
||||
export type Action = 'sleep' | 'reboot' | 'logout' | 'shutdown';
|
||||
|
||||
8
lib/types/powerprofiles.d.ts
vendored
8
lib/types/powerprofiles.d.ts
vendored
@@ -1,8 +1,8 @@
|
||||
import icons from "modules/icons/index";
|
||||
import PowerProfiles from "types/service/powerprofiles.js"
|
||||
import icons from 'modules/icons/index';
|
||||
import PowerProfiles from 'types/service/powerprofiles.js';
|
||||
|
||||
export type PowerProfiles = InstanceType<typeof PowerProfiles>;
|
||||
export type PowerProfile = "power-saver" | "balanced" | "performance";
|
||||
export type PowerProfile = 'power-saver' | 'balanced' | 'performance';
|
||||
export type PowerProfileObject = {
|
||||
[key: string]: string;
|
||||
}
|
||||
};
|
||||
|
||||
0
lib/types/systray.d.ts
vendored
Normal file
0
lib/types/systray.d.ts
vendored
Normal file
5
lib/types/utils.d.ts
vendored
5
lib/types/utils.d.ts
vendored
@@ -1,3 +1,6 @@
|
||||
import { substitutes } from "lib/icons";
|
||||
import { substitutes } from 'lib/icons';
|
||||
|
||||
type SubstituteKeys = keyof typeof substitutes;
|
||||
|
||||
export type ThrottleFn = (cmd: string, fn: ((output: string) => void) | undefined) => void;
|
||||
export type ThrottleFnCallback = ((output: string) => void) | undefined;
|
||||
|
||||
1
lib/types/variable.d.ts
vendored
Normal file
1
lib/types/variable.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export type Bind = OriginalBinding<GObject.Object, keyof Props<GObject.Object>, unknown>;
|
||||
4
lib/types/volume.d.ts
vendored
4
lib/types/volume.d.ts
vendored
@@ -1,3 +1,3 @@
|
||||
export type VolumeIcons = {
|
||||
[index: number]: string
|
||||
}
|
||||
[index: number]: string;
|
||||
};
|
||||
|
||||
24
lib/types/weather.d.ts
vendored
24
lib/types/weather.d.ts
vendored
@@ -1,12 +1,12 @@
|
||||
import { weatherIcons } from "modules/icons/weather";
|
||||
import { weatherIcons } from 'modules/icons/weather';
|
||||
|
||||
export type UnitType = "imperial" | "metric";
|
||||
export type UnitType = 'imperial' | 'metric';
|
||||
|
||||
export type Weather = {
|
||||
location: Location;
|
||||
current: Current;
|
||||
forecast: Forecast;
|
||||
}
|
||||
};
|
||||
|
||||
export type Current = {
|
||||
last_updated_epoch?: number;
|
||||
@@ -45,17 +45,17 @@ export type Current = {
|
||||
chance_of_rain?: number;
|
||||
will_it_snow?: number;
|
||||
chance_of_snow?: number;
|
||||
}
|
||||
};
|
||||
|
||||
export type Condition = {
|
||||
text: string;
|
||||
icon: string;
|
||||
code: number;
|
||||
}
|
||||
};
|
||||
|
||||
export type Forecast = {
|
||||
forecastday: Forecastday[];
|
||||
}
|
||||
};
|
||||
|
||||
export type Forecastday = {
|
||||
date: string;
|
||||
@@ -63,7 +63,7 @@ export type Forecastday = {
|
||||
day: Day;
|
||||
astro: Astro;
|
||||
hour: Current[];
|
||||
}
|
||||
};
|
||||
|
||||
export type Astro = {
|
||||
sunrise: string;
|
||||
@@ -74,7 +74,7 @@ export type Astro = {
|
||||
moon_illumination: number;
|
||||
is_moon_up: number;
|
||||
is_sun_up: number;
|
||||
}
|
||||
};
|
||||
|
||||
export type Day = {
|
||||
maxtemp_c: number;
|
||||
@@ -97,7 +97,7 @@ export type Day = {
|
||||
daily_chance_of_snow: number;
|
||||
condition: Condition;
|
||||
uv: number;
|
||||
}
|
||||
};
|
||||
|
||||
export type Location = {
|
||||
name: string;
|
||||
@@ -108,11 +108,11 @@ export type Location = {
|
||||
tz_id: string;
|
||||
localtime_epoch: number;
|
||||
localtime: string;
|
||||
}
|
||||
};
|
||||
|
||||
export type TemperatureIconColorMap = {
|
||||
[key: number]: string;
|
||||
}
|
||||
};
|
||||
|
||||
export type WeatherIconTitle = keyof typeof weatherIcons;
|
||||
export type WeatherIcon = typeof weatherIcons[WeatherIconTitle];
|
||||
export type WeatherIcon = (typeof weatherIcons)[WeatherIconTitle];
|
||||
|
||||
32
lib/types/widget.d.ts
vendored
32
lib/types/widget.d.ts
vendored
@@ -1,6 +1,28 @@
|
||||
export type Exclusivity = 'normal' | 'ignore' | 'exclusive';
|
||||
export type Anchor = "left" | "right" | "top" | "down";
|
||||
export type Transition = "none" | "crossfade" | "slide_right" | "slide_left" | "slide_up" | "slide_down";
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||
import Box from 'types/widgets/box';
|
||||
|
||||
// Window
|
||||
export type Layouts = 'center' | 'top' | 'top-right' | 'top-center' | 'top-left' | 'bottom-left' | 'bottom-center' | 'bottom-right';
|
||||
export type Exclusivity = 'normal' | 'ignore' | 'exclusive';
|
||||
export type Anchor = 'left' | 'right' | 'top' | 'down';
|
||||
export type Transition = 'none' | 'crossfade' | 'slide_right' | 'slide_left' | 'slide_up' | 'slide_down';
|
||||
|
||||
export type Layouts =
|
||||
| 'center'
|
||||
| 'top'
|
||||
| 'top-right'
|
||||
| 'top-center'
|
||||
| 'top-left'
|
||||
| 'bottom-left'
|
||||
| 'bottom-center'
|
||||
| 'bottom-right';
|
||||
|
||||
export type Attribute = unknown;
|
||||
export type Child = Gtk.Widget;
|
||||
export type GtkWidget = Gtk.Widget;
|
||||
export type BoxWidget = Box<GtkWidget, Child>;
|
||||
|
||||
export type GButton = Gtk.Button;
|
||||
export type GBox = Gtk.Box;
|
||||
export type GLabel = Gtk.Label;
|
||||
export type GCenterBox = Gtk.Box;
|
||||
|
||||
export type EventHandler<Self> = (self: Self, event: Gdk.Event) => boolean | unknown;
|
||||
|
||||
14
lib/types/workspace.d.ts
vendored
14
lib/types/workspace.d.ts
vendored
@@ -1,8 +1,12 @@
|
||||
export type WorkspaceRule = {
|
||||
workspaceString: string,
|
||||
monitor: string,
|
||||
}
|
||||
workspaceString: string;
|
||||
monitor: string;
|
||||
};
|
||||
|
||||
export type WorkspaceMap = {
|
||||
[key: string]: number[],
|
||||
}
|
||||
[key: string]: number[];
|
||||
};
|
||||
|
||||
export type MonitorMap = {
|
||||
[key: number]: string;
|
||||
};
|
||||
|
||||
161
lib/utils.ts
161
lib/utils.ts
@@ -1,29 +1,27 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { type Application } from "types/service/applications"
|
||||
import { NotificationAnchor } from "./types/options"
|
||||
import { OSDAnchor } from "lib/types/options";
|
||||
import icons, { substitutes } from "./icons"
|
||||
import Gtk from "gi://Gtk?version=3.0"
|
||||
import Gdk from "gi://Gdk"
|
||||
import GLib from "gi://GLib?version=2.0"
|
||||
import GdkPixbuf from "gi://GdkPixbuf";
|
||||
import { NotificationArgs } from "types/utils/notify"
|
||||
import { SubstituteKeys } from "./types/utils";
|
||||
|
||||
export type Binding<T> = import("types/service").Binding<any, any, T>
|
||||
import { type Application } from 'types/service/applications';
|
||||
import { NotificationAnchor } from './types/options';
|
||||
import { OSDAnchor } from 'lib/types/options';
|
||||
import icons, { substitutes } from './icons';
|
||||
import Gtk from 'gi://Gtk?version=3.0';
|
||||
import Gdk from 'gi://Gdk';
|
||||
import GLib from 'gi://GLib?version=2.0';
|
||||
import GdkPixbuf from 'gi://GdkPixbuf';
|
||||
import { NotificationArgs } from 'types/utils/notify';
|
||||
import { SubstituteKeys } from './types/utils';
|
||||
import { Window } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
||||
|
||||
export type Binding<T> = import('types/service').Binding<any, any, T>;
|
||||
|
||||
/**
|
||||
* @returns substitute icon || name || fallback icon
|
||||
*/
|
||||
export function icon(name: string | null, fallback = icons.missing) {
|
||||
* @returns substitute icon || name || fallback icon
|
||||
*/
|
||||
export function icon(name: string | null, fallback = icons.missing): string {
|
||||
const validateSubstitute = (name: string): name is SubstituteKeys => name in substitutes;
|
||||
|
||||
if (!name)
|
||||
return fallback || ""
|
||||
if (!name) return fallback || '';
|
||||
|
||||
if (GLib.file_test(name, GLib.FileTest.EXISTS))
|
||||
return name
|
||||
if (GLib.file_test(name, GLib.FileTest.EXISTS)) return name;
|
||||
|
||||
let icon: string = name;
|
||||
|
||||
@@ -31,38 +29,36 @@ export function icon(name: string | null, fallback = icons.missing) {
|
||||
icon = substitutes[name];
|
||||
}
|
||||
|
||||
if (Utils.lookUpIcon(icon))
|
||||
return icon
|
||||
if (Utils.lookUpIcon(icon)) return icon;
|
||||
|
||||
print(`no icon substitute "${icon}" for "${name}", fallback: "${fallback}"`)
|
||||
return fallback
|
||||
print(`no icon substitute "${icon}" for "${name}", fallback: "${fallback}"`);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns execAsync(["bash", "-c", cmd])
|
||||
*/
|
||||
export async function bash(strings: TemplateStringsArray | string, ...values: unknown[]) {
|
||||
const cmd = typeof strings === "string" ? strings : strings
|
||||
.flatMap((str, i) => str + `${values[i] ?? ""}`)
|
||||
.join("")
|
||||
export async function bash(strings: TemplateStringsArray | string, ...values: unknown[]): Promise<string> {
|
||||
const cmd =
|
||||
typeof strings === 'string' ? strings : strings.flatMap((str, i) => str + `${values[i] ?? ''}`).join('');
|
||||
|
||||
return Utils.execAsync(["bash", "-c", cmd]).catch(err => {
|
||||
console.error(cmd, err)
|
||||
return ""
|
||||
})
|
||||
return Utils.execAsync(['bash', '-c', cmd]).catch((err) => {
|
||||
console.error(cmd, err);
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns execAsync(cmd)
|
||||
*/
|
||||
export async function sh(cmd: string | string[]) {
|
||||
return Utils.execAsync(cmd).catch(err => {
|
||||
console.error(typeof cmd === "string" ? cmd : cmd.join(" "), err)
|
||||
return ""
|
||||
})
|
||||
export async function sh(cmd: string | string[]): Promise<string> {
|
||||
return Utils.execAsync(cmd).catch((err) => {
|
||||
console.error(typeof cmd === 'string' ? cmd : cmd.join(' '), err);
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
export function forMonitors(widget: (monitor: number) => Gtk.Window) {
|
||||
export function forMonitors(widget: (monitor: number) => Gtk.Window): Window[] {
|
||||
const n = Gdk.Display.get_default()?.get_n_monitors() || 1;
|
||||
return range(n, 0).flatMap(widget);
|
||||
}
|
||||
@@ -70,64 +66,62 @@ export function forMonitors(widget: (monitor: number) => Gtk.Window) {
|
||||
/**
|
||||
* @returns [start...length]
|
||||
*/
|
||||
export function range(length: number, start = 1) {
|
||||
return Array.from({ length }, (_, i) => i + start)
|
||||
export function range(length: number, start = 1): number[] {
|
||||
return Array.from({ length }, (_, i) => i + start);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns true if all of the `bins` are found
|
||||
*/
|
||||
export function dependencies(...bins: string[]) {
|
||||
const missing = bins.filter(bin => Utils.exec({
|
||||
cmd: `which ${bin}`,
|
||||
out: () => false,
|
||||
err: () => true,
|
||||
}))
|
||||
export function dependencies(...bins: string[]): boolean {
|
||||
const missing = bins.filter((bin) =>
|
||||
Utils.exec({
|
||||
cmd: `which ${bin}`,
|
||||
out: () => false,
|
||||
err: () => true,
|
||||
}),
|
||||
);
|
||||
|
||||
if (missing.length > 0) {
|
||||
console.warn(Error(`missing dependencies: ${missing.join(", ")}`))
|
||||
console.warn(Error(`missing dependencies: ${missing.join(', ')}`));
|
||||
Notify({
|
||||
summary: "Dependencies not found!",
|
||||
body: `The following dependencies are missing: ${missing.join(", ")}`,
|
||||
summary: 'Dependencies not found!',
|
||||
body: `The following dependencies are missing: ${missing.join(', ')}`,
|
||||
iconName: icons.ui.warning,
|
||||
timeout: 7000
|
||||
timeout: 7000,
|
||||
});
|
||||
}
|
||||
|
||||
return missing.length === 0
|
||||
return missing.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* run app detached
|
||||
*/
|
||||
export function launchApp(app: Application) {
|
||||
export function launchApp(app: Application): void {
|
||||
const exe = app.executable
|
||||
.split(/\s+/)
|
||||
.filter(str => !str.startsWith("%") && !str.startsWith("@"))
|
||||
.join(" ")
|
||||
.filter((str) => !str.startsWith('%') && !str.startsWith('@'))
|
||||
.join(' ');
|
||||
|
||||
bash(`${exe} &`)
|
||||
app.frequency += 1
|
||||
bash(`${exe} &`);
|
||||
app.frequency += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* to use with drag and drop
|
||||
*/
|
||||
export function createSurfaceFromWidget(widget: Gtk.Widget) {
|
||||
export function createSurfaceFromWidget(widget: Gtk.Widget): GdkPixbuf.Pixbuf {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const cairo = imports.gi.cairo as any
|
||||
const alloc = widget.get_allocation()
|
||||
const surface = new cairo.ImageSurface(
|
||||
cairo.Format.ARGB32,
|
||||
alloc.width,
|
||||
alloc.height,
|
||||
)
|
||||
const cr = new cairo.Context(surface)
|
||||
cr.setSourceRGBA(255, 255, 255, 0)
|
||||
cr.rectangle(0, 0, alloc.width, alloc.height)
|
||||
cr.fill()
|
||||
widget.draw(cr)
|
||||
return surface
|
||||
const cairo = imports.gi.cairo as any;
|
||||
const alloc = widget.get_allocation();
|
||||
const surface = new cairo.ImageSurface(cairo.Format.ARGB32, alloc.width, alloc.height);
|
||||
const cr = new cairo.Context(surface);
|
||||
cr.setSourceRGBA(255, 255, 255, 0);
|
||||
cr.rectangle(0, 0, alloc.width, alloc.height);
|
||||
cr.fill();
|
||||
widget.draw(cr);
|
||||
return surface;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,9 +132,10 @@ export const isAnImage = (imgFilePath: string): boolean => {
|
||||
GdkPixbuf.Pixbuf.new_from_file(imgFilePath);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const Notify = (notifPayload: NotificationArgs): void => {
|
||||
let command = 'notify-send';
|
||||
@@ -154,20 +149,20 @@ export const Notify = (notifPayload: NotificationArgs): void => {
|
||||
if (notifPayload.transient) command += ` -e`;
|
||||
if (notifPayload.id !== undefined) command += ` -r ${notifPayload.id}`;
|
||||
|
||||
Utils.execAsync(command)
|
||||
}
|
||||
Utils.execAsync(command);
|
||||
};
|
||||
|
||||
export function getPosition(pos: NotificationAnchor | OSDAnchor): ("top" | "bottom" | "left" | "right")[] {
|
||||
const positionMap: { [key: string]: ("top" | "bottom" | "left" | "right")[] } = {
|
||||
"top": ["top"],
|
||||
"top right": ["top", "right"],
|
||||
"top left": ["top", "left"],
|
||||
"bottom": ["bottom"],
|
||||
"bottom right": ["bottom", "right"],
|
||||
"bottom left": ["bottom", "left"],
|
||||
"right": ["right"],
|
||||
"left": ["left"],
|
||||
export function getPosition(pos: NotificationAnchor | OSDAnchor): ('top' | 'bottom' | 'left' | 'right')[] {
|
||||
const positionMap: { [key: string]: ('top' | 'bottom' | 'left' | 'right')[] } = {
|
||||
top: ['top'],
|
||||
'top right': ['top', 'right'],
|
||||
'top left': ['top', 'left'],
|
||||
bottom: ['bottom'],
|
||||
'bottom right': ['bottom', 'right'],
|
||||
'bottom left': ['bottom', 'left'],
|
||||
right: ['right'],
|
||||
left: ['left'],
|
||||
};
|
||||
|
||||
return positionMap[pos] || ["top"];
|
||||
return positionMap[pos] || ['top'];
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import GLib from "gi://GLib"
|
||||
import GLib from 'gi://GLib';
|
||||
import { DateTime } from 'types/@girs/glib-2.0/glib-2.0.cjs';
|
||||
|
||||
export const clock = Variable(GLib.DateTime.new_now_local(), {
|
||||
poll: [1000, () => GLib.DateTime.new_now_local()],
|
||||
})
|
||||
poll: [1000, (): DateTime => GLib.DateTime.new_now_local()],
|
||||
});
|
||||
|
||||
export const uptime = Variable(0, {
|
||||
poll: [60_000, "cat /proc/uptime", line =>
|
||||
Number.parseInt(line.split(".")[0]) / 60,
|
||||
],
|
||||
})
|
||||
poll: [60_000, 'cat /proc/uptime', (line): number => Number.parseInt(line.split('.')[0]) / 60],
|
||||
});
|
||||
|
||||
export const distro = {
|
||||
id: GLib.get_os_info("ID"),
|
||||
logo: GLib.get_os_info("LOGO"),
|
||||
}
|
||||
id: GLib.get_os_info('ID'),
|
||||
logo: GLib.get_os_info('LOGO'),
|
||||
};
|
||||
|
||||
30
main.ts
30
main.ts
@@ -1,27 +1,21 @@
|
||||
import "lib/session";
|
||||
import "scss/style";
|
||||
import "globals/useTheme";
|
||||
import "globals/mousePos";
|
||||
import 'lib/session';
|
||||
import 'scss/style';
|
||||
import 'globals/useTheme';
|
||||
import 'globals/mousePos';
|
||||
|
||||
import { Bar } from "modules/bar/Bar";
|
||||
import MenuWindows from "./modules/menus/main.js";
|
||||
import SettingsDialog from "widget/settings/SettingsDialog";
|
||||
import Notifications from "./modules/notifications/index.js";
|
||||
import { forMonitors } from "lib/utils";
|
||||
import OSD from "modules/osd/index";
|
||||
import { Bar } from 'modules/bar/Bar';
|
||||
import MenuWindows from './modules/menus/main.js';
|
||||
import SettingsDialog from 'widget/settings/SettingsDialog';
|
||||
import Notifications from './modules/notifications/index.js';
|
||||
import { forMonitors } from 'lib/utils';
|
||||
import OSD from 'modules/osd/index';
|
||||
|
||||
App.config({
|
||||
onConfigParsed: () => Utils.execAsync(`python3 ${App.configDir}/services/bluetooth.py`),
|
||||
windows: [
|
||||
...MenuWindows,
|
||||
Notifications(),
|
||||
SettingsDialog(),
|
||||
...forMonitors(Bar),
|
||||
OSD(),
|
||||
],
|
||||
windows: [...MenuWindows, Notifications(), SettingsDialog(), ...forMonitors(Bar), OSD()],
|
||||
closeWindowDelay: {
|
||||
sideright: 350,
|
||||
launcher: 350,
|
||||
bar0: 350,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
const hyprland = await Service.import("hyprland");
|
||||
const hyprland = await Service.import('hyprland');
|
||||
|
||||
import {
|
||||
Menu,
|
||||
Workspaces, ClientTitle, Media,
|
||||
Workspaces,
|
||||
ClientTitle,
|
||||
Media,
|
||||
Notifications,
|
||||
Volume,
|
||||
Network,
|
||||
@@ -20,54 +22,57 @@ import {
|
||||
Updates,
|
||||
Weather,
|
||||
Power,
|
||||
} from "./Exports"
|
||||
} from './Exports';
|
||||
|
||||
import { BarItemBox as WidgetContainer } from "../shared/barItemBox.js";
|
||||
import options from "options";
|
||||
import Gdk from "gi://Gdk?version=3.0";
|
||||
import Button from "types/widgets/button.js";
|
||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0.js";
|
||||
import { BarItemBox as WidgetContainer } from '../shared/barItemBox.js';
|
||||
import options from 'options';
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import Button from 'types/widgets/button.js';
|
||||
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0.js';
|
||||
|
||||
import './SideEffects';
|
||||
import { WindowLayer } from "lib/types/options.js";
|
||||
import { WindowLayer } from 'lib/types/options.js';
|
||||
import { Attribute, Child } from 'lib/types/widget.js';
|
||||
import Window from 'types/widgets/window.js';
|
||||
|
||||
const { layouts } = options.bar;
|
||||
|
||||
export type BarWidget = keyof typeof widget;
|
||||
|
||||
type Section = "battery"
|
||||
| "dashboard"
|
||||
| "workspaces"
|
||||
| "windowtitle"
|
||||
| "media"
|
||||
| "notifications"
|
||||
| "volume"
|
||||
| "network"
|
||||
| "bluetooth"
|
||||
| "clock"
|
||||
| "ram"
|
||||
| "cpu"
|
||||
| "storage"
|
||||
| "netstat"
|
||||
| "kbinput"
|
||||
| "updates"
|
||||
| "weather"
|
||||
| "power"
|
||||
| "systray";
|
||||
type Section =
|
||||
| 'battery'
|
||||
| 'dashboard'
|
||||
| 'workspaces'
|
||||
| 'windowtitle'
|
||||
| 'media'
|
||||
| 'notifications'
|
||||
| 'volume'
|
||||
| 'network'
|
||||
| 'bluetooth'
|
||||
| 'clock'
|
||||
| 'ram'
|
||||
| 'cpu'
|
||||
| 'storage'
|
||||
| 'netstat'
|
||||
| 'kbinput'
|
||||
| 'updates'
|
||||
| 'weather'
|
||||
| 'power'
|
||||
| 'systray';
|
||||
|
||||
type Layout = {
|
||||
left: Section[],
|
||||
middle: Section[],
|
||||
right: Section[],
|
||||
}
|
||||
left: Section[];
|
||||
middle: Section[];
|
||||
right: Section[];
|
||||
};
|
||||
|
||||
type BarLayout = {
|
||||
[key: string]: Layout
|
||||
}
|
||||
[key: string]: Layout;
|
||||
};
|
||||
|
||||
const getLayoutForMonitor = (monitor: number, layouts: BarLayout): Layout => {
|
||||
const matchingKey = Object.keys(layouts).find(key => key === monitor.toString());
|
||||
const wildcard = Object.keys(layouts).find(key => key === "*");
|
||||
const matchingKey = Object.keys(layouts).find((key) => key === monitor.toString());
|
||||
const wildcard = Object.keys(layouts).find((key) => key === '*');
|
||||
|
||||
if (matchingKey) {
|
||||
return layouts[matchingKey];
|
||||
@@ -77,62 +82,48 @@ const getLayoutForMonitor = (monitor: number, layouts: BarLayout): Layout => {
|
||||
return layouts[wildcard];
|
||||
}
|
||||
|
||||
return {
|
||||
left: [
|
||||
"dashboard",
|
||||
"workspaces",
|
||||
"windowtitle"
|
||||
],
|
||||
middle: [
|
||||
"media"
|
||||
],
|
||||
right: [
|
||||
"volume",
|
||||
"network",
|
||||
"bluetooth",
|
||||
"battery",
|
||||
"systray",
|
||||
"clock",
|
||||
"notifications"
|
||||
]
|
||||
return {
|
||||
left: ['dashboard', 'workspaces', 'windowtitle'],
|
||||
middle: ['media'],
|
||||
right: ['volume', 'network', 'bluetooth', 'battery', 'systray', 'clock', 'notifications'],
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const widget = {
|
||||
battery: () => WidgetContainer(BatteryLabel()),
|
||||
dashboard: () => WidgetContainer(Menu()),
|
||||
workspaces: (monitor: number) => WidgetContainer(Workspaces(monitor)),
|
||||
windowtitle: () => WidgetContainer(ClientTitle()),
|
||||
media: () => WidgetContainer(Media()),
|
||||
notifications: () => WidgetContainer(Notifications()),
|
||||
volume: () => WidgetContainer(Volume()),
|
||||
network: () => WidgetContainer(Network()),
|
||||
bluetooth: () => WidgetContainer(Bluetooth()),
|
||||
clock: () => WidgetContainer(Clock()),
|
||||
systray: () => WidgetContainer(SysTray()),
|
||||
ram: () => WidgetContainer(Ram()),
|
||||
cpu: () => WidgetContainer(Cpu()),
|
||||
storage: () => WidgetContainer(Storage()),
|
||||
netstat: () => WidgetContainer(Netstat()),
|
||||
kbinput: () => WidgetContainer(KbInput()),
|
||||
updates: () => WidgetContainer(Updates()),
|
||||
weather: () => WidgetContainer(Weather()),
|
||||
power: () => WidgetContainer(Power()),
|
||||
battery: (): Button<Child, Attribute> => WidgetContainer(BatteryLabel()),
|
||||
dashboard: (): Button<Child, Attribute> => WidgetContainer(Menu()),
|
||||
workspaces: (monitor: number): Button<Child, Attribute> => WidgetContainer(Workspaces(monitor)),
|
||||
windowtitle: (): Button<Child, Attribute> => WidgetContainer(ClientTitle()),
|
||||
media: (): Button<Child, Attribute> => WidgetContainer(Media()),
|
||||
notifications: (): Button<Child, Attribute> => WidgetContainer(Notifications()),
|
||||
volume: (): Button<Child, Attribute> => WidgetContainer(Volume()),
|
||||
network: (): Button<Child, Attribute> => WidgetContainer(Network()),
|
||||
bluetooth: (): Button<Child, Attribute> => WidgetContainer(Bluetooth()),
|
||||
clock: (): Button<Child, Attribute> => WidgetContainer(Clock()),
|
||||
systray: (): Button<Child, Attribute> => WidgetContainer(SysTray()),
|
||||
ram: (): Button<Child, Attribute> => WidgetContainer(Ram()),
|
||||
cpu: (): Button<Child, Attribute> => WidgetContainer(Cpu()),
|
||||
storage: (): Button<Child, Attribute> => WidgetContainer(Storage()),
|
||||
netstat: (): Button<Child, Attribute> => WidgetContainer(Netstat()),
|
||||
kbinput: (): Button<Child, Attribute> => WidgetContainer(KbInput()),
|
||||
updates: (): Button<Child, Attribute> => WidgetContainer(Updates()),
|
||||
weather: (): Button<Child, Attribute> => WidgetContainer(Weather()),
|
||||
power: (): Button<Child, Attribute> => WidgetContainer(Power()),
|
||||
};
|
||||
|
||||
type GdkMonitors = {
|
||||
[key: string]: {
|
||||
key: string,
|
||||
model: string,
|
||||
used: boolean
|
||||
}
|
||||
key: string;
|
||||
model: string;
|
||||
used: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
function getGdkMonitors(): GdkMonitors {
|
||||
const display = Gdk.Display.get_default();
|
||||
|
||||
if (display === null) {
|
||||
console.error("Failed to get Gdk display.");
|
||||
console.error('Failed to get Gdk display.');
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -162,35 +153,35 @@ function getGdkMonitors(): GdkMonitors {
|
||||
* NOTE: Some more funky stuff being done by GDK.
|
||||
* We render windows/bar based on the monitor ID. So if you have 3 monitors, then your
|
||||
* monitor IDs will be [0, 1, 2]. Hyprland will NEVER change what ID belongs to what monitor.
|
||||
*
|
||||
*
|
||||
* So if hyprland determines id 0 = DP-1, even after you unplug, shut off or restart your monitor,
|
||||
* the id 0 will ALWAYS be DP-1.
|
||||
*
|
||||
*
|
||||
* However, GDK (the righteous genius that it is) will change the order of ID anytime your monitor
|
||||
* setup is changed. So if you unplug your monitor and plug it back it, it now becomes the last id.
|
||||
* So if DP-1 was id 0 and you unplugged it, it will reconfigure to id 2. This sucks because now
|
||||
* there's a mismtach between what GDK determines the monitor is at id 2 and what Hyprland determines
|
||||
* is at id 2.
|
||||
*
|
||||
*
|
||||
* So for that reason, we need to redirect the input `monitor` that the Bar module takes in, to the
|
||||
* proper Hyprland monitor. So when monitor id 0 comes in, we need to find what the id of that monitor
|
||||
* is being determined as by Hyprland so the bars show up on the right monitors.
|
||||
*
|
||||
*
|
||||
* Since GTK3 doesn't contain connection names and only monitor models, we have to make the best guess
|
||||
* in the case that there are multiple models in the same resolution with the same scale. We find the
|
||||
* 'right' monitor by checking if the model matches along with the resolution and scale. If monitor at
|
||||
* ID 0 for GDK is being reported as 'MSI MAG271CQR' we find the same model in the Hyprland monitor list
|
||||
* and check if the resolution and scaling is the same... if it is then we determine it's a match.
|
||||
*
|
||||
*
|
||||
* The edge-case that we just can't handle is if you have the same monitors in the same resolution at the same
|
||||
* scale. So if you've got 2 'MSI MAG271CQR' monitors at 2560x1440 at scale 1, then we just match the first
|
||||
* monitor in the list as the first match and then the second 'MSI MAG271CQR' as a match in the 2nd iteration.
|
||||
* You may have the bar showing up on the wrong one in this case because we don't know what the connector id
|
||||
* monitor in the list as the first match and then the second 'MSI MAG271CQR' as a match in the 2nd iteration.
|
||||
* You may have the bar showing up on the wrong one in this case because we don't know what the connector id
|
||||
* is of either of these monitors (DP-1, DP-2) which are unique values - as these are only in GTK4.
|
||||
*
|
||||
*
|
||||
* Keep in mind though, this is ONLY an issue if you change your monitor setup by plugging in a new one, restarting
|
||||
* an existing one or shutting it off.
|
||||
*
|
||||
*
|
||||
* If your monitors aren't changed in the current session you're in then none of this safeguarding is relevant.
|
||||
*
|
||||
* Fun stuff really... :facepalm:
|
||||
@@ -200,7 +191,7 @@ const gdkMonitorIdToHyprlandId = (monitor: number, usedHyprlandMonitors: Set<num
|
||||
const gdkMonitors = getGdkMonitors();
|
||||
|
||||
if (Object.keys(gdkMonitors).length === 0) {
|
||||
console.error("No GDK monitors were found.");
|
||||
console.error('No GDK monitors were found.');
|
||||
return monitor;
|
||||
}
|
||||
|
||||
@@ -208,7 +199,7 @@ const gdkMonitorIdToHyprlandId = (monitor: number, usedHyprlandMonitors: Set<num
|
||||
const gdkMonitor = gdkMonitors[monitor];
|
||||
|
||||
// First pass: Strict matching including the monitor index (i.e., hypMon.id === monitor + resolution+scale criteria)
|
||||
const directMatch = hyprland.monitors.find(hypMon => {
|
||||
const directMatch = hyprland.monitors.find((hypMon) => {
|
||||
const hyprlandKey = `${hypMon.model}_${hypMon.width}x${hypMon.height}_${hypMon.scale}`;
|
||||
return gdkMonitor.key.startsWith(hyprlandKey) && !usedHyprlandMonitors.has(hypMon.id) && hypMon.id === monitor;
|
||||
});
|
||||
@@ -219,7 +210,7 @@ const gdkMonitorIdToHyprlandId = (monitor: number, usedHyprlandMonitors: Set<num
|
||||
}
|
||||
|
||||
// Second pass: Relaxed matching without considering the monitor index
|
||||
const hyprlandMonitor = hyprland.monitors.find(hypMon => {
|
||||
const hyprlandMonitor = hyprland.monitors.find((hypMon) => {
|
||||
const hyprlandKey = `${hypMon.model}_${hypMon.width}x${hypMon.height}_${hypMon.scale}`;
|
||||
return gdkMonitor.key.startsWith(hyprlandKey) && !usedHyprlandMonitors.has(hypMon.id);
|
||||
});
|
||||
@@ -230,7 +221,7 @@ const gdkMonitorIdToHyprlandId = (monitor: number, usedHyprlandMonitors: Set<num
|
||||
}
|
||||
|
||||
// Fallback: Find the first available monitor ID that hasn't been used
|
||||
const fallbackMonitor = hyprland.monitors.find(hypMon => !usedHyprlandMonitors.has(hypMon.id));
|
||||
const fallbackMonitor = hyprland.monitors.find((hypMon) => !usedHyprlandMonitors.has(hypMon.id));
|
||||
|
||||
if (fallbackMonitor) {
|
||||
usedHyprlandMonitors.add(fallbackMonitor.id);
|
||||
@@ -253,62 +244,63 @@ const gdkMonitorIdToHyprlandId = (monitor: number, usedHyprlandMonitors: Set<num
|
||||
export const Bar = (() => {
|
||||
const usedHyprlandMonitors = new Set<number>();
|
||||
|
||||
return (monitor: number) => {
|
||||
return (monitor: number): Window<Child, Attribute> => {
|
||||
const hyprlandMonitor = gdkMonitorIdToHyprlandId(monitor, usedHyprlandMonitors);
|
||||
|
||||
return Widget.Window({
|
||||
name: `bar-${hyprlandMonitor}`,
|
||||
class_name: "bar",
|
||||
class_name: 'bar',
|
||||
monitor,
|
||||
visible: true,
|
||||
anchor: ["top", "left", "right"],
|
||||
exclusivity: "exclusive",
|
||||
anchor: ['top', 'left', 'right'],
|
||||
exclusivity: 'exclusive',
|
||||
layer: Utils.merge(
|
||||
[
|
||||
options.theme.bar.layer.bind("value"),
|
||||
options.tear.bind("value")
|
||||
],
|
||||
(
|
||||
barLayer: WindowLayer,
|
||||
tear: boolean
|
||||
) => {
|
||||
if (tear && barLayer === "overlay") {
|
||||
return "top";
|
||||
[options.theme.bar.layer.bind('value'), options.tear.bind('value')],
|
||||
(barLayer: WindowLayer, tear: boolean) => {
|
||||
if (tear && barLayer === 'overlay') {
|
||||
return 'top';
|
||||
}
|
||||
return barLayer;
|
||||
}),
|
||||
},
|
||||
),
|
||||
child: Widget.Box({
|
||||
class_name: 'bar-panel-container',
|
||||
child: Widget.CenterBox({
|
||||
class_name: 'bar-panel',
|
||||
css: 'padding: 1px',
|
||||
startWidget: Widget.Box({
|
||||
class_name: "box-left",
|
||||
class_name: 'box-left',
|
||||
hexpand: true,
|
||||
setup: self => {
|
||||
setup: (self) => {
|
||||
self.hook(layouts, (self) => {
|
||||
const foundLayout = getLayoutForMonitor(hyprlandMonitor, layouts.value as BarLayout);
|
||||
self.children = foundLayout.left.filter(mod => Object.keys(widget).includes(mod)).map(w => widget[w](hyprlandMonitor) as Button<Gtk.Widget, unknown>);
|
||||
self.children = foundLayout.left
|
||||
.filter((mod) => Object.keys(widget).includes(mod))
|
||||
.map((w) => widget[w](hyprlandMonitor) as Button<Gtk.Widget, unknown>);
|
||||
});
|
||||
},
|
||||
}),
|
||||
centerWidget: Widget.Box({
|
||||
class_name: "box-center",
|
||||
hpack: "center",
|
||||
setup: self => {
|
||||
class_name: 'box-center',
|
||||
hpack: 'center',
|
||||
setup: (self) => {
|
||||
self.hook(layouts, (self) => {
|
||||
const foundLayout = getLayoutForMonitor(hyprlandMonitor, layouts.value as BarLayout);
|
||||
self.children = foundLayout.middle.filter(mod => Object.keys(widget).includes(mod)).map(w => widget[w](hyprlandMonitor) as Button<Gtk.Widget, unknown>);
|
||||
self.children = foundLayout.middle
|
||||
.filter((mod) => Object.keys(widget).includes(mod))
|
||||
.map((w) => widget[w](hyprlandMonitor) as Button<Gtk.Widget, unknown>);
|
||||
});
|
||||
},
|
||||
}),
|
||||
endWidget: Widget.Box({
|
||||
class_name: "box-right",
|
||||
hpack: "end",
|
||||
setup: self => {
|
||||
class_name: 'box-right',
|
||||
hpack: 'end',
|
||||
setup: (self) => {
|
||||
self.hook(layouts, (self) => {
|
||||
const foundLayout = getLayoutForMonitor(hyprlandMonitor, layouts.value as BarLayout);
|
||||
self.children = foundLayout.right.filter(mod => Object.keys(widget).includes(mod)).map(w => widget[w](hyprlandMonitor) as Button<Gtk.Widget, unknown>);
|
||||
self.children = foundLayout.right
|
||||
.filter((mod) => Object.keys(widget).includes(mod))
|
||||
.map((w) => widget[w](hyprlandMonitor) as Button<Gtk.Widget, unknown>);
|
||||
});
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { Menu } from "./menu/index";
|
||||
import { Workspaces } from "./workspaces/index";
|
||||
import { ClientTitle } from "./window_title/index";
|
||||
import { Media } from "./media/index";
|
||||
import { Notifications } from "./notifications/index";
|
||||
import { Volume } from "./volume/index";
|
||||
import { Network } from "./network/index";
|
||||
import { Bluetooth } from "./bluetooth/index";
|
||||
import { BatteryLabel } from "./battery/index";
|
||||
import { Clock } from "./clock/index";
|
||||
import { SysTray } from "./systray/index";
|
||||
import { Menu } from './menu/index';
|
||||
import { Workspaces } from './workspaces/index';
|
||||
import { ClientTitle } from './window_title/index';
|
||||
import { Media } from './media/index';
|
||||
import { Notifications } from './notifications/index';
|
||||
import { Volume } from './volume/index';
|
||||
import { Network } from './network/index';
|
||||
import { Bluetooth } from './bluetooth/index';
|
||||
import { BatteryLabel } from './battery/index';
|
||||
import { Clock } from './clock/index';
|
||||
import { SysTray } from './systray/index';
|
||||
|
||||
// Custom Modules
|
||||
import { Ram } from "../../customModules/ram/index";
|
||||
import { Cpu } from "../../customModules/cpu/index";
|
||||
import { Storage } from "customModules/storage/index";
|
||||
import { Netstat } from "customModules/netstat/index";
|
||||
import { KbInput } from "customModules/kblayout/index";
|
||||
import { Updates } from "customModules/updates/index";
|
||||
import { Weather } from "customModules/weather/index";
|
||||
import { Power } from "customModules/power/index";
|
||||
import { Ram } from '../../customModules/ram/index';
|
||||
import { Cpu } from '../../customModules/cpu/index';
|
||||
import { Storage } from 'customModules/storage/index';
|
||||
import { Netstat } from 'customModules/netstat/index';
|
||||
import { KbInput } from 'customModules/kblayout/index';
|
||||
import { Updates } from 'customModules/updates/index';
|
||||
import { Weather } from 'customModules/weather/index';
|
||||
import { Power } from 'customModules/power/index';
|
||||
|
||||
export {
|
||||
Menu,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import options from "options";
|
||||
import options from 'options';
|
||||
|
||||
const { showIcon, showTime } = options.bar.clock;
|
||||
|
||||
showIcon.connect("changed", () => {
|
||||
showIcon.connect('changed', () => {
|
||||
if (!showTime.value && !showIcon.value) {
|
||||
showTime.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
showTime.connect("changed", () => {
|
||||
showTime.connect('changed', () => {
|
||||
if (!showTime.value && !showIcon.value) {
|
||||
showIcon.value = true;
|
||||
}
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
const battery = await Service.import("battery");
|
||||
const battery = await Service.import('battery');
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
import { openMenu } from '../utils.js';
|
||||
import options from 'options';
|
||||
import { BarBoxChild } from 'lib/types/bar.js';
|
||||
import Button from 'types/widgets/button.js';
|
||||
import { Child } from 'lib/types/widget.js';
|
||||
|
||||
const { label: show_label } = options.bar.battery;
|
||||
|
||||
const BatteryLabel = () => {
|
||||
const BatteryLabel = (): BarBoxChild => {
|
||||
const isVis = Variable(battery.available);
|
||||
|
||||
const batIcon = Utils.merge([battery.bind("percent"), battery.bind("charging"), battery.bind("charged")],
|
||||
const batIcon = Utils.merge(
|
||||
[battery.bind('percent'), battery.bind('charging'), battery.bind('charged')],
|
||||
(batPercent: number, batCharging, batCharged) => {
|
||||
if (batCharged)
|
||||
return `battery-level-100-charged-symbolic`;
|
||||
else
|
||||
return `battery-level-${Math.floor(batPercent / 10) * 10}${batCharging ? '-charging' : ''}-symbolic`;
|
||||
});
|
||||
if (batCharged) return `battery-level-100-charged-symbolic`;
|
||||
else return `battery-level-${Math.floor(batPercent / 10) * 10}${batCharging ? '-charging' : ''}-symbolic`;
|
||||
},
|
||||
);
|
||||
|
||||
battery.connect("changed", ({ available }) => {
|
||||
battery.connect('changed', ({ available }) => {
|
||||
isVis.value = available;
|
||||
});
|
||||
|
||||
const formatTime = (seconds: number) => {
|
||||
const formatTime = (seconds: number): Record<string, number> => {
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
return { hours, minutes };
|
||||
};
|
||||
|
||||
const generateTooltip = (timeSeconds: number, isCharging: boolean, isCharged: boolean) => {
|
||||
const generateTooltip = (timeSeconds: number, isCharging: boolean, isCharged: boolean): string => {
|
||||
if (isCharged) {
|
||||
return "Fully Charged!!!";
|
||||
return 'Fully Charged!!!';
|
||||
}
|
||||
|
||||
const { hours, minutes } = formatTime(timeSeconds);
|
||||
@@ -41,60 +44,56 @@ const BatteryLabel = () => {
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value"), show_label.bind("value")], (style, showLabel) => {
|
||||
const styleMap = {
|
||||
default: "style1",
|
||||
split: "style2",
|
||||
wave: "style3",
|
||||
wave2: "style3",
|
||||
};
|
||||
return `battery ${styleMap[style]} ${!showLabel ? "no-label" : ""}`;
|
||||
}),
|
||||
visible: battery.bind("available"),
|
||||
tooltip_text: battery.bind("time_remaining").as((t) => t.toString()),
|
||||
children: Utils.merge(
|
||||
[battery.bind("available"), show_label.bind("value")],
|
||||
(batAvail, showLabel) => {
|
||||
if (batAvail && showLabel) {
|
||||
return [
|
||||
Widget.Icon({
|
||||
class_name: "bar-button-icon battery",
|
||||
icon: batIcon
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: "bar-button-label battery",
|
||||
label: battery.bind("percent").as((p) => `${Math.floor(p)}%`),
|
||||
}),
|
||||
];
|
||||
} else if (batAvail && !showLabel) {
|
||||
return [
|
||||
Widget.Icon({
|
||||
class_name: "bar-button-icon battery",
|
||||
icon: batIcon
|
||||
})
|
||||
];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
className: Utils.merge(
|
||||
[options.theme.bar.buttons.style.bind('value'), show_label.bind('value')],
|
||||
(style, showLabel) => {
|
||||
const styleMap = {
|
||||
default: 'style1',
|
||||
split: 'style2',
|
||||
wave: 'style3',
|
||||
wave2: 'style3',
|
||||
};
|
||||
return `battery ${styleMap[style]} ${!showLabel ? 'no-label' : ''}`;
|
||||
},
|
||||
),
|
||||
visible: battery.bind('available'),
|
||||
tooltip_text: battery.bind('time_remaining').as((t) => t.toString()),
|
||||
children: Utils.merge([battery.bind('available'), show_label.bind('value')], (batAvail, showLabel) => {
|
||||
if (batAvail && showLabel) {
|
||||
return [
|
||||
Widget.Icon({
|
||||
class_name: 'bar-button-icon battery',
|
||||
icon: batIcon,
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: 'bar-button-label battery',
|
||||
label: battery.bind('percent').as((p) => `${Math.floor(p)}%`),
|
||||
}),
|
||||
];
|
||||
} else if (batAvail && !showLabel) {
|
||||
return [
|
||||
Widget.Icon({
|
||||
class_name: 'bar-button-icon battery',
|
||||
icon: batIcon,
|
||||
}),
|
||||
];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}),
|
||||
setup: (self) => {
|
||||
self.hook(battery, () => {
|
||||
if (battery.available) {
|
||||
self.tooltip_text = generateTooltip(
|
||||
battery.time_remaining,
|
||||
battery.charging,
|
||||
battery.charged,
|
||||
);
|
||||
self.tooltip_text = generateTooltip(battery.time_remaining, battery.charging, battery.charged);
|
||||
}
|
||||
});
|
||||
},
|
||||
}),
|
||||
isVis,
|
||||
boxClass: "battery",
|
||||
boxClass: 'battery',
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "energymenu");
|
||||
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||
openMenu(clicked, event, 'energymenu');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,42 +1,41 @@
|
||||
const bluetooth = await Service.import('bluetooth')
|
||||
const bluetooth = await Service.import('bluetooth');
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import options from "options";
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from 'options';
|
||||
import { openMenu } from '../utils.js';
|
||||
import { BarBoxChild } from 'lib/types/bar.js';
|
||||
import Button from 'types/widgets/button.js';
|
||||
import { Child } from 'lib/types/widget.js';
|
||||
|
||||
const { label } = options.bar.bluetooth;
|
||||
|
||||
const Bluetooth = () => {
|
||||
const Bluetooth = (): BarBoxChild => {
|
||||
const btIcon = Widget.Label({
|
||||
label: bluetooth.bind("enabled").as((v) => v ? "" : ""),
|
||||
class_name: "bar-button-icon bluetooth txt-icon bar",
|
||||
label: bluetooth.bind('enabled').as((v) => (v ? '' : '')),
|
||||
class_name: 'bar-button-icon bluetooth txt-icon bar',
|
||||
});
|
||||
|
||||
const btText = Widget.Label({
|
||||
label: Utils.merge([
|
||||
bluetooth.bind("enabled"),
|
||||
bluetooth.bind("connected_devices"),
|
||||
],
|
||||
(btEnabled, btDevices) => {
|
||||
return btEnabled && btDevices.length ? ` Connected (${btDevices.length})`
|
||||
: btEnabled ? "On"
|
||||
: "Off"
|
||||
|
||||
}),
|
||||
class_name: "bar-button-label bluetooth",
|
||||
label: Utils.merge([bluetooth.bind('enabled'), bluetooth.bind('connected_devices')], (btEnabled, btDevices) => {
|
||||
return btEnabled && btDevices.length ? ` Connected (${btDevices.length})` : btEnabled ? 'On' : 'Off';
|
||||
}),
|
||||
class_name: 'bar-button-label bluetooth',
|
||||
});
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value"), label.bind("value")], (style, showLabel) => {
|
||||
const styleMap = {
|
||||
default: "style1",
|
||||
split: "style2",
|
||||
wave: "style3",
|
||||
wave2: "style3",
|
||||
};
|
||||
return `bluetooth ${styleMap[style]} ${!showLabel ? "no-label" : ""}`;
|
||||
}),
|
||||
children: options.bar.bluetooth.label.bind("value").as((showLabel) => {
|
||||
className: Utils.merge(
|
||||
[options.theme.bar.buttons.style.bind('value'), label.bind('value')],
|
||||
(style, showLabel) => {
|
||||
const styleMap = {
|
||||
default: 'style1',
|
||||
split: 'style2',
|
||||
wave: 'style3',
|
||||
wave2: 'style3',
|
||||
};
|
||||
return `bluetooth ${styleMap[style]} ${!showLabel ? 'no-label' : ''}`;
|
||||
},
|
||||
),
|
||||
children: options.bar.bluetooth.label.bind('value').as((showLabel) => {
|
||||
if (showLabel) {
|
||||
return [btIcon, btText];
|
||||
}
|
||||
@@ -44,14 +43,13 @@ const Bluetooth = () => {
|
||||
}),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "bluetooth",
|
||||
boxClass: 'bluetooth',
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "bluetoothmenu");
|
||||
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||
openMenu(clicked, event, 'bluetoothmenu');
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export { Bluetooth }
|
||||
export { Bluetooth };
|
||||
|
||||
@@ -1,45 +1,46 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import GLib from "gi://GLib";
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
import GLib from 'gi://GLib';
|
||||
import { openMenu } from '../utils.js';
|
||||
import options from 'options';
|
||||
import { DateTime } from 'types/@girs/glib-2.0/glib-2.0.cjs';
|
||||
import { BarBoxChild } from 'lib/types/bar.js';
|
||||
import Button from 'types/widgets/button.js';
|
||||
import { Child } from 'lib/types/widget.js';
|
||||
const { format, icon, showIcon, showTime } = options.bar.clock;
|
||||
const { style } = options.theme.bar.buttons;
|
||||
|
||||
|
||||
const date = Variable(GLib.DateTime.new_now_local(), {
|
||||
poll: [1000, () => GLib.DateTime.new_now_local()],
|
||||
poll: [1000, (): DateTime => GLib.DateTime.new_now_local()],
|
||||
});
|
||||
const time = Utils.derive([date, format], (c, f) => c.format(f) || "");
|
||||
|
||||
const Clock = () => {
|
||||
const time = Utils.derive([date, format], (c, f) => c.format(f) || '');
|
||||
|
||||
const Clock = (): BarBoxChild => {
|
||||
const clockTime = Widget.Label({
|
||||
class_name: "bar-button-label clock bar",
|
||||
class_name: 'bar-button-label clock bar',
|
||||
label: time.bind(),
|
||||
});
|
||||
|
||||
const clockIcon = Widget.Label({
|
||||
label: icon.bind("value"),
|
||||
class_name: "bar-button-icon clock txt-icon bar",
|
||||
label: icon.bind('value'),
|
||||
class_name: 'bar-button-icon clock txt-icon bar',
|
||||
});
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
className: Utils.merge([
|
||||
style.bind("value"),
|
||||
showIcon.bind("value"), showTime.bind("value")
|
||||
], (btnStyle, shwIcn, shwLbl) => {
|
||||
const styleMap = {
|
||||
default: "style1",
|
||||
split: "style2",
|
||||
wave: "style3",
|
||||
wave2: "style3",
|
||||
};
|
||||
|
||||
return `bluetooth ${styleMap[btnStyle]} ${!shwLbl ? "no-label" : ""} ${!shwIcn ? "no-icon" : ""}`;
|
||||
}),
|
||||
children: Utils.merge([showIcon.bind("value"), showTime.bind("value")], (shIcn, shTm) => {
|
||||
className: Utils.merge(
|
||||
[style.bind('value'), showIcon.bind('value'), showTime.bind('value')],
|
||||
(btnStyle, shwIcn, shwLbl) => {
|
||||
const styleMap = {
|
||||
default: 'style1',
|
||||
split: 'style2',
|
||||
wave: 'style3',
|
||||
wave2: 'style3',
|
||||
};
|
||||
|
||||
return `bluetooth ${styleMap[btnStyle]} ${!shwLbl ? 'no-label' : ''} ${!shwIcn ? 'no-icon' : ''}`;
|
||||
},
|
||||
),
|
||||
children: Utils.merge([showIcon.bind('value'), showTime.bind('value')], (shIcn, shTm) => {
|
||||
if (shIcn && !shTm) {
|
||||
return [clockIcon];
|
||||
} else if (shTm && !shIcn) {
|
||||
@@ -47,13 +48,13 @@ const Clock = () => {
|
||||
}
|
||||
|
||||
return [clockIcon, clockTime];
|
||||
})
|
||||
}),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "clock",
|
||||
boxClass: 'clock',
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "calendarmenu");
|
||||
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||
openMenu(clicked, event, 'calendarmenu');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
const mpris = await Service.import("mpris");
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
const mpris = await Service.import('mpris');
|
||||
import { openMenu } from '../utils.js';
|
||||
import options from 'options';
|
||||
import { getCurrentPlayer } from 'lib/shared/media.js';
|
||||
import { BarBoxChild } from 'lib/types/bar.js';
|
||||
import Button from 'types/widgets/button.js';
|
||||
import { Child } from 'lib/types/widget.js';
|
||||
|
||||
const { show_artist, truncation, truncation_size, show_label, show_active_only } = options.bar.media;
|
||||
|
||||
const Media = () => {
|
||||
const Media = (): BarBoxChild => {
|
||||
const activePlayer = Variable(mpris.players[0]);
|
||||
const isVis = Variable(!show_active_only.value);
|
||||
|
||||
show_active_only.connect("changed", () => {
|
||||
show_active_only.connect('changed', () => {
|
||||
isVis.value = !show_active_only.value || mpris.players.length > 0;
|
||||
});
|
||||
|
||||
mpris.connect("changed", () => {
|
||||
mpris.connect('changed', () => {
|
||||
const curPlayer = getCurrentPlayer(activePlayer.value);
|
||||
activePlayer.value = curPlayer;
|
||||
isVis.value = !show_active_only.value || mpris.players.length > 0;
|
||||
@@ -22,41 +25,37 @@ const Media = () => {
|
||||
|
||||
const getIconForPlayer = (playerName: string): string => {
|
||||
const windowTitleMap = [
|
||||
["Firefox", ""],
|
||||
["Microsoft Edge", ""],
|
||||
["Discord", ""],
|
||||
["Plex", ""],
|
||||
["Spotify", ""],
|
||||
["(.*)", ""],
|
||||
['Firefox', ''],
|
||||
['Microsoft Edge', ''],
|
||||
['Discord', ''],
|
||||
['Plex', ''],
|
||||
['Spotify', ''],
|
||||
['(.*)', ''],
|
||||
];
|
||||
|
||||
const foundMatch = windowTitleMap.find((wt) =>
|
||||
RegExp(wt[0], "i").test(playerName),
|
||||
);
|
||||
const foundMatch = windowTitleMap.find((wt) => RegExp(wt[0], 'i').test(playerName));
|
||||
|
||||
return foundMatch ? foundMatch[1] : "";
|
||||
return foundMatch ? foundMatch[1] : '';
|
||||
};
|
||||
|
||||
const songIcon = Variable("");
|
||||
const songIcon = Variable('');
|
||||
|
||||
const mediaLabel = Utils.watch("Media", [mpris, show_artist, truncation, truncation_size, show_label], () => {
|
||||
const mediaLabel = Utils.watch('Media', [mpris, show_artist, truncation, truncation_size, show_label], () => {
|
||||
if (activePlayer.value && show_label.value) {
|
||||
const { track_title, identity, track_artists } = activePlayer.value;
|
||||
songIcon.value = getIconForPlayer(identity);
|
||||
const trackArtist = show_artist.value
|
||||
? ` - ${track_artists.join(', ')}`
|
||||
: ``;
|
||||
const trackArtist = show_artist.value ? ` - ${track_artists.join(', ')}` : ``;
|
||||
const truncatedLabel = truncation.value
|
||||
? `${track_title + trackArtist}`.substring(0, truncation_size.value)
|
||||
: `${track_title + trackArtist}`;
|
||||
|
||||
return track_title.length === 0
|
||||
? `No media playing...`
|
||||
: ((truncatedLabel.length < truncation_size.value) || !truncation.value)
|
||||
? `${truncatedLabel}`
|
||||
: `${truncatedLabel.substring(0, truncatedLabel.length - 3)}...`;
|
||||
: truncatedLabel.length < truncation_size.value || !truncation.value
|
||||
? `${truncatedLabel}`
|
||||
: `${truncatedLabel.substring(0, truncatedLabel.length - 3)}...`;
|
||||
} else {
|
||||
songIcon.value = getIconForPlayer(activePlayer.value?.identity || "");
|
||||
songIcon.value = getIconForPlayer(activePlayer.value?.identity || '');
|
||||
return `Media`;
|
||||
}
|
||||
});
|
||||
@@ -65,23 +64,26 @@ const Media = () => {
|
||||
component: Widget.Box({
|
||||
visible: false,
|
||||
child: Widget.Box({
|
||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value"), show_label.bind("value")], (style, showLabel) => {
|
||||
const styleMap = {
|
||||
default: "style1",
|
||||
split: "style2",
|
||||
wave: "style3",
|
||||
wave2: "style3",
|
||||
};
|
||||
return `media ${styleMap[style]}`;
|
||||
}),
|
||||
className: Utils.merge(
|
||||
[options.theme.bar.buttons.style.bind('value'), show_label.bind('value')],
|
||||
(style) => {
|
||||
const styleMap = {
|
||||
default: 'style1',
|
||||
split: 'style2',
|
||||
wave: 'style3',
|
||||
wave2: 'style3',
|
||||
};
|
||||
return `media ${styleMap[style]}`;
|
||||
},
|
||||
),
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "bar-button-icon media txt-icon bar",
|
||||
label: songIcon.bind("value").as(v => v || ""),
|
||||
class_name: 'bar-button-icon media txt-icon bar',
|
||||
label: songIcon.bind('value').as((v) => v || ''),
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: "bar-button-label media",
|
||||
class_name: 'bar-button-label media',
|
||||
label: mediaLabel,
|
||||
}),
|
||||
],
|
||||
@@ -89,13 +91,13 @@ const Media = () => {
|
||||
}),
|
||||
}),
|
||||
isVis,
|
||||
boxClass: "media",
|
||||
name: "media",
|
||||
boxClass: 'media',
|
||||
name: 'media',
|
||||
props: {
|
||||
on_scroll_up: () => activePlayer.value?.next(),
|
||||
on_scroll_down: () => activePlayer.value?.previous(),
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "mediamenu");
|
||||
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||
openMenu(clicked, event, 'mediamenu');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,29 +1,32 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
import { openMenu } from '../utils.js';
|
||||
import options from 'options';
|
||||
import { BarBoxChild } from 'lib/types/bar.js';
|
||||
import Button from 'types/widgets/button.js';
|
||||
import { Child } from 'lib/types/widget.js';
|
||||
|
||||
const Menu = () => {
|
||||
const Menu = (): BarBoxChild => {
|
||||
return {
|
||||
component: Widget.Box({
|
||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value")], (style) => {
|
||||
className: Utils.merge([options.theme.bar.buttons.style.bind('value')], (style) => {
|
||||
const styleMap = {
|
||||
default: "style1",
|
||||
split: "style2",
|
||||
wave: "style3",
|
||||
wave2: "style3",
|
||||
default: 'style1',
|
||||
split: 'style2',
|
||||
wave: 'style3',
|
||||
wave2: 'style3',
|
||||
};
|
||||
return `dashboard ${styleMap[style]}`;
|
||||
}),
|
||||
child: Widget.Label({
|
||||
class_name: "bar-menu_label bar-button_icon txt-icon bar",
|
||||
label: options.bar.launcher.icon.bind("value"),
|
||||
class_name: 'bar-menu_label bar-button_icon txt-icon bar',
|
||||
label: options.bar.launcher.icon.bind('value'),
|
||||
}),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "dashboard",
|
||||
boxClass: 'dashboard',
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "dashboardmenu");
|
||||
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||
openMenu(clicked, event, 'dashboardmenu');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,70 +1,77 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
const network = await Service.import("network");
|
||||
import options from "options";
|
||||
import { openMenu } from "../utils.js";
|
||||
const network = await Service.import('network');
|
||||
import options from 'options';
|
||||
import { openMenu } from '../utils.js';
|
||||
import { BarBoxChild } from 'lib/types/bar.js';
|
||||
import Button from 'types/widgets/button.js';
|
||||
import { Child } from 'lib/types/widget.js';
|
||||
|
||||
const { label: networkLabel, truncation, truncation_size } = options.bar.network;
|
||||
|
||||
const Network = () => {
|
||||
const Network = (): BarBoxChild => {
|
||||
return {
|
||||
component: Widget.Box({
|
||||
vpack: "fill",
|
||||
vpack: 'fill',
|
||||
vexpand: true,
|
||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value"), networkLabel.bind("value")], (style, showLabel) => {
|
||||
const styleMap = {
|
||||
default: "style1",
|
||||
split: "style2",
|
||||
wave: "style3",
|
||||
wave2: "style3",
|
||||
};
|
||||
return `network ${styleMap[style]}${!showLabel ? " no-label" : ""}`;
|
||||
}),
|
||||
className: Utils.merge(
|
||||
[options.theme.bar.buttons.style.bind('value'), networkLabel.bind('value')],
|
||||
(style, showLabel) => {
|
||||
const styleMap = {
|
||||
default: 'style1',
|
||||
split: 'style2',
|
||||
wave: 'style3',
|
||||
wave2: 'style3',
|
||||
};
|
||||
return `network ${styleMap[style]}${!showLabel ? ' no-label' : ''}`;
|
||||
},
|
||||
),
|
||||
children: [
|
||||
Widget.Icon({
|
||||
class_name: "bar-button-icon network",
|
||||
icon: Utils.merge([
|
||||
network.bind("primary"),
|
||||
network.bind("wifi"),
|
||||
network.bind("wired")
|
||||
], (pmry, wfi, wrd) => {
|
||||
if (pmry === "wired") {
|
||||
return wrd.icon_name;
|
||||
}
|
||||
return wfi.icon_name;
|
||||
})
|
||||
class_name: 'bar-button-icon network',
|
||||
icon: Utils.merge(
|
||||
[network.bind('primary'), network.bind('wifi'), network.bind('wired')],
|
||||
(pmry, wfi, wrd) => {
|
||||
if (pmry === 'wired') {
|
||||
return wrd.icon_name;
|
||||
}
|
||||
return wfi.icon_name;
|
||||
},
|
||||
),
|
||||
}),
|
||||
Widget.Box({
|
||||
vpack: "center",
|
||||
child: Utils.merge([
|
||||
network.bind("primary"),
|
||||
network.bind("wifi"),
|
||||
networkLabel.bind("value"),
|
||||
truncation.bind("value"),
|
||||
truncation_size.bind("value")
|
||||
], (pmry, wfi, showLbl, trunc, tSize) => {
|
||||
if (!showLbl) {
|
||||
return Widget.Box();
|
||||
}
|
||||
if (pmry === "wired") {
|
||||
vpack: 'center',
|
||||
child: Utils.merge(
|
||||
[
|
||||
network.bind('primary'),
|
||||
network.bind('wifi'),
|
||||
networkLabel.bind('value'),
|
||||
truncation.bind('value'),
|
||||
truncation_size.bind('value'),
|
||||
],
|
||||
(pmry, wfi, showLbl, trunc, tSize) => {
|
||||
if (!showLbl) {
|
||||
return Widget.Box();
|
||||
}
|
||||
if (pmry === 'wired') {
|
||||
return Widget.Label({
|
||||
class_name: 'bar-button-label network',
|
||||
label: 'Wired'.substring(0, tSize),
|
||||
});
|
||||
}
|
||||
return Widget.Label({
|
||||
class_name: "bar-button-label network",
|
||||
label: "Wired".substring(0, tSize),
|
||||
})
|
||||
}
|
||||
return Widget.Label({
|
||||
class_name: "bar-button-label network",
|
||||
label: wfi.ssid ? `${trunc ? wfi.ssid.substring(0, tSize) : wfi.ssid}` : "--",
|
||||
})
|
||||
|
||||
})
|
||||
class_name: 'bar-button-label network',
|
||||
label: wfi.ssid ? `${trunc ? wfi.ssid.substring(0, tSize) : wfi.ssid}` : '--',
|
||||
});
|
||||
},
|
||||
),
|
||||
}),
|
||||
]
|
||||
],
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "network",
|
||||
boxClass: 'network',
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "networkmenu");
|
||||
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||
openMenu(clicked, event, 'networkmenu');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,51 +1,49 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
import { openMenu } from '../utils.js';
|
||||
import options from 'options';
|
||||
import { filterNotifications } from 'lib/shared/notifications.js';
|
||||
import { BarBoxChild } from 'lib/types/bar.js';
|
||||
import Button from 'types/widgets/button.js';
|
||||
import { Child } from 'lib/types/widget.js';
|
||||
|
||||
const { show_total } = options.bar.notifications;
|
||||
const { ignore } = options.notifications;
|
||||
|
||||
const notifs = await Service.import("notifications");
|
||||
const notifs = await Service.import('notifications');
|
||||
|
||||
export const Notifications = () => {
|
||||
export const Notifications = (): BarBoxChild => {
|
||||
return {
|
||||
component: Widget.Box({
|
||||
hpack: "start",
|
||||
hpack: 'start',
|
||||
className: Utils.merge(
|
||||
[
|
||||
options.theme.bar.buttons.style.bind("value"),
|
||||
show_total.bind("value")
|
||||
],
|
||||
(
|
||||
style,
|
||||
showTotal
|
||||
) => {
|
||||
[options.theme.bar.buttons.style.bind('value'), show_total.bind('value')],
|
||||
(style, showTotal) => {
|
||||
const styleMap = {
|
||||
default: "style1",
|
||||
split: "style2",
|
||||
wave: "style3",
|
||||
wave2: "style3",
|
||||
default: 'style1',
|
||||
split: 'style2',
|
||||
wave: 'style3',
|
||||
wave2: 'style3',
|
||||
};
|
||||
return `notifications ${styleMap[style]} ${!showTotal ? "no-label" : ""}`;
|
||||
}),
|
||||
return `notifications ${styleMap[style]} ${!showTotal ? 'no-label' : ''}`;
|
||||
},
|
||||
),
|
||||
child: Widget.Box({
|
||||
hpack: "start",
|
||||
class_name: "bar-notifications",
|
||||
hpack: 'start',
|
||||
class_name: 'bar-notifications',
|
||||
children: Utils.merge(
|
||||
[notifs.bind("notifications"), notifs.bind("dnd"), show_total.bind("value"), ignore.bind("value")],
|
||||
[notifs.bind('notifications'), notifs.bind('dnd'), show_total.bind('value'), ignore.bind('value')],
|
||||
(notif, dnd, showTotal, ignoredNotifs) => {
|
||||
const filteredNotifications = filterNotifications(notif, ignoredNotifs);
|
||||
|
||||
const notifIcon = Widget.Label({
|
||||
hpack: "center",
|
||||
class_name: "bar-button-icon notifications txt-icon bar",
|
||||
label: dnd ? "" : filteredNotifications.length > 0 ? "" : "",
|
||||
hpack: 'center',
|
||||
class_name: 'bar-button-icon notifications txt-icon bar',
|
||||
label: dnd ? '' : filteredNotifications.length > 0 ? '' : '',
|
||||
});
|
||||
|
||||
const notifLabel = Widget.Label({
|
||||
hpack: "center",
|
||||
class_name: "bar-button-label notifications",
|
||||
hpack: 'center',
|
||||
class_name: 'bar-button-label notifications',
|
||||
label: filteredNotifications.length.toString(),
|
||||
});
|
||||
|
||||
@@ -58,10 +56,10 @@ export const Notifications = () => {
|
||||
}),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "notifications",
|
||||
boxClass: 'notifications',
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "notificationsmenu");
|
||||
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||
openMenu(clicked, event, 'notificationsmenu');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,49 +1,43 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import { BarBoxChild, SelfButton } from 'lib/types/bar';
|
||||
import { Notify } from 'lib/utils';
|
||||
const systemtray = await Service.import("systemtray");
|
||||
import options from "options";
|
||||
const systemtray = await Service.import('systemtray');
|
||||
import options from 'options';
|
||||
|
||||
const { ignore } = options.bar.systray;
|
||||
|
||||
const SysTray = () => {
|
||||
const SysTray = (): BarBoxChild => {
|
||||
const isVis = Variable(false);
|
||||
|
||||
const items = Utils.merge(
|
||||
[systemtray.bind("items"), ignore.bind("value")],
|
||||
(items, ignored) => {
|
||||
const filteredTray = items.filter(({ id }) => !ignored.includes(id));
|
||||
const items = Utils.merge([systemtray.bind('items'), ignore.bind('value')], (items, ignored) => {
|
||||
const filteredTray = items.filter(({ id }) => !ignored.includes(id));
|
||||
|
||||
isVis.value = filteredTray.length > 0;
|
||||
isVis.value = filteredTray.length > 0;
|
||||
|
||||
return filteredTray.map((item) => {
|
||||
if (item.menu !== undefined) {
|
||||
item.menu["class_name"] = "systray-menu";
|
||||
}
|
||||
|
||||
return Widget.Button({
|
||||
cursor: "pointer",
|
||||
child: Widget.Icon({
|
||||
class_name: "systray-icon",
|
||||
icon: item.bind("icon"),
|
||||
}),
|
||||
on_primary_click: (_: any, event: Gdk.Event) => item.activate(event),
|
||||
on_secondary_click: (_, event) => item.openMenu(event),
|
||||
onMiddleClick: () => Notify({ summary: "App Name", body: item.id }),
|
||||
tooltip_markup: item.bind("tooltip_markup"),
|
||||
});
|
||||
return filteredTray.map((item) => {
|
||||
return Widget.Button({
|
||||
cursor: 'pointer',
|
||||
child: Widget.Icon({
|
||||
class_name: 'systray-icon',
|
||||
icon: item.bind('icon'),
|
||||
}),
|
||||
on_primary_click: (_: SelfButton, event: Gdk.Event) => item.activate(event),
|
||||
on_secondary_click: (_, event) => item.openMenu(event),
|
||||
onMiddleClick: () => Notify({ summary: 'App Name', body: item.id }),
|
||||
tooltip_markup: item.bind('tooltip_markup'),
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
class_name: "systray",
|
||||
class_name: 'systray',
|
||||
children: items,
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "systray",
|
||||
boxClass: 'systray',
|
||||
isVis,
|
||||
props: {}
|
||||
props: {},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import { Child } from 'lib/types/widget';
|
||||
import Button from 'types/widgets/button';
|
||||
|
||||
export const closeAllMenus = () => {
|
||||
export const closeAllMenus = (): void => {
|
||||
const menuWindows = App.windows
|
||||
.filter((w) => {
|
||||
if (w.name) {
|
||||
@@ -18,7 +20,7 @@ export const closeAllMenus = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const openMenu = (clicked: any, event: Gdk.Event, window: string) => {
|
||||
export const openMenu = (clicked: Button<Child, Child>, event: Gdk.Event, window: string): void => {
|
||||
/*
|
||||
* NOTE: We have to make some adjustments so the menu pops up relatively
|
||||
* to the center of the button clicked. We don't want the menu to spawn
|
||||
|
||||
@@ -1,59 +1,63 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
const audio = await Service.import("audio");
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
const audio = await Service.import('audio');
|
||||
import { openMenu } from '../utils.js';
|
||||
import options from 'options';
|
||||
import { Binding } from 'lib/utils.js';
|
||||
import { VolumeIcons } from 'lib/types/volume.js';
|
||||
import { BarBoxChild } from 'lib/types/bar.js';
|
||||
import { Bind } from 'lib/types/variable.js';
|
||||
import Button from 'types/widgets/button.js';
|
||||
import { Child } from 'lib/types/widget.js';
|
||||
|
||||
const Volume = () => {
|
||||
const Volume = (): BarBoxChild => {
|
||||
const icons: VolumeIcons = {
|
||||
101: "",
|
||||
66: "",
|
||||
34: "",
|
||||
1: "",
|
||||
0: "",
|
||||
101: '',
|
||||
66: '',
|
||||
34: '',
|
||||
1: '',
|
||||
0: '',
|
||||
};
|
||||
|
||||
const getIcon = () => {
|
||||
const getIcon = (): Bind => {
|
||||
const icon: Binding<number> = Utils.merge(
|
||||
[audio.speaker.bind("is_muted"), audio.speaker.bind("volume")],
|
||||
[audio.speaker.bind('is_muted'), audio.speaker.bind('volume')],
|
||||
(isMuted, vol) => {
|
||||
return isMuted
|
||||
? 0
|
||||
: [101, 66, 34, 1, 0].find((threshold) => threshold <= vol * 100) || 101;
|
||||
return isMuted ? 0 : [101, 66, 34, 1, 0].find((threshold) => threshold <= vol * 100) || 101;
|
||||
},
|
||||
);
|
||||
|
||||
return icon.as((i: number) => i !== undefined ? icons[i] : icons[101]);
|
||||
return icon.as((i: number) => (i !== undefined ? icons[i] : icons[101]));
|
||||
};
|
||||
|
||||
const volIcn = Widget.Label({
|
||||
hexpand: true,
|
||||
label: getIcon(),
|
||||
class_name: "bar-button-icon volume txt-icon bar",
|
||||
class_name: 'bar-button-icon volume txt-icon bar',
|
||||
});
|
||||
|
||||
const volPct = Widget.Label({
|
||||
hexpand: true,
|
||||
label: audio.speaker.bind("volume").as((v) => `${Math.round(v * 100)}%`),
|
||||
class_name: "bar-button-label volume",
|
||||
label: audio.speaker.bind('volume').as((v) => `${Math.round(v * 100)}%`),
|
||||
class_name: 'bar-button-label volume',
|
||||
});
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
hexpand: true,
|
||||
vexpand: true,
|
||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value"), options.bar.volume.label.bind("value")], (style, showLabel) => {
|
||||
const styleMap = {
|
||||
default: "style1",
|
||||
split: "style2",
|
||||
wave: "style3",
|
||||
wave2: "style3",
|
||||
};
|
||||
|
||||
return `volume ${styleMap[style]} ${!showLabel ? "no-label" : ""}`;
|
||||
}),
|
||||
children: options.bar.volume.label.bind("value").as((showLabel) => {
|
||||
className: Utils.merge(
|
||||
[options.theme.bar.buttons.style.bind('value'), options.bar.volume.label.bind('value')],
|
||||
(style, showLabel) => {
|
||||
const styleMap = {
|
||||
default: 'style1',
|
||||
split: 'style2',
|
||||
wave: 'style3',
|
||||
wave2: 'style3',
|
||||
};
|
||||
return `volume ${styleMap[style]} ${!showLabel ? 'no-label' : ''}`;
|
||||
},
|
||||
),
|
||||
children: options.bar.volume.label.bind('value').as((showLabel) => {
|
||||
if (showLabel) {
|
||||
return [volIcn, volPct];
|
||||
}
|
||||
@@ -61,10 +65,10 @@ const Volume = () => {
|
||||
}),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "volume",
|
||||
boxClass: 'volume',
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "audiomenu");
|
||||
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||
openMenu(clicked, event, 'audiomenu');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,122 +1,119 @@
|
||||
const hyprland = await Service.import("hyprland");
|
||||
const hyprland = await Service.import('hyprland');
|
||||
import { BarBoxChild } from 'lib/types/bar';
|
||||
import options from 'options';
|
||||
import { ActiveClient } from 'types/service/hyprland'
|
||||
import Label from "types/widgets/label";
|
||||
import { ActiveClient } from 'types/service/hyprland';
|
||||
|
||||
const filterTitle = (windowtitle: ActiveClient) => {
|
||||
const filterTitle = (windowtitle: ActiveClient): Record<string, string> => {
|
||||
const windowTitleMap = [
|
||||
// user provided values
|
||||
...options.bar.windowtitle.title_map.value,
|
||||
// Original Entries
|
||||
["kitty", "", "Kitty Terminal"],
|
||||
["firefox", "", "Firefox"],
|
||||
["microsoft-edge", "", "Edge"],
|
||||
["discord", "", "Discord"],
|
||||
["vesktop", "", "Vesktop"],
|
||||
["org.kde.dolphin", "", "Dolphin"],
|
||||
["plex", "", "Plex"],
|
||||
["steam", "", "Steam"],
|
||||
["spotify", "", "Spotify"],
|
||||
["ristretto", "", "Ristretto"],
|
||||
["obsidian", "", "Obsidian"],
|
||||
['kitty', '', 'Kitty Terminal'],
|
||||
['firefox', '', 'Firefox'],
|
||||
['microsoft-edge', '', 'Edge'],
|
||||
['discord', '', 'Discord'],
|
||||
['vesktop', '', 'Vesktop'],
|
||||
['org.kde.dolphin', '', 'Dolphin'],
|
||||
['plex', '', 'Plex'],
|
||||
['steam', '', 'Steam'],
|
||||
['spotify', '', 'Spotify'],
|
||||
['ristretto', '', 'Ristretto'],
|
||||
['obsidian', '', 'Obsidian'],
|
||||
|
||||
// Browsers
|
||||
["google-chrome", "", "Google Chrome"],
|
||||
["brave-browser", "", "Brave Browser"],
|
||||
["chromium", "", "Chromium"],
|
||||
["opera", "", "Opera"],
|
||||
["vivaldi", "", "Vivaldi"],
|
||||
["waterfox", "", "Waterfox"],
|
||||
["thorium", "", "Waterfox"],
|
||||
["tor-browser", "", "Tor Browser"],
|
||||
["floorp", "", "Floorp"],
|
||||
['google-chrome', '', 'Google Chrome'],
|
||||
['brave-browser', '', 'Brave Browser'],
|
||||
['chromium', '', 'Chromium'],
|
||||
['opera', '', 'Opera'],
|
||||
['vivaldi', '', 'Vivaldi'],
|
||||
['waterfox', '', 'Waterfox'],
|
||||
['thorium', '', 'Waterfox'],
|
||||
['tor-browser', '', 'Tor Browser'],
|
||||
['floorp', '', 'Floorp'],
|
||||
|
||||
// Terminals
|
||||
["gnome-terminal", "", "GNOME Terminal"],
|
||||
["konsole", "", "Konsole"],
|
||||
["alacritty", "", "Alacritty"],
|
||||
["wezterm", "", "Wezterm"],
|
||||
["foot", "", "Foot Terminal"],
|
||||
["tilix", "", "Tilix"],
|
||||
["xterm", "", "XTerm"],
|
||||
["urxvt", "", "URxvt"],
|
||||
["st", "", "st Terminal"],
|
||||
['gnome-terminal', '', 'GNOME Terminal'],
|
||||
['konsole', '', 'Konsole'],
|
||||
['alacritty', '', 'Alacritty'],
|
||||
['wezterm', '', 'Wezterm'],
|
||||
['foot', '', 'Foot Terminal'],
|
||||
['tilix', '', 'Tilix'],
|
||||
['xterm', '', 'XTerm'],
|
||||
['urxvt', '', 'URxvt'],
|
||||
['st', '', 'st Terminal'],
|
||||
|
||||
// Development Tools
|
||||
["code", "", "Visual Studio Code"],
|
||||
["vscode", "", "VS Code"],
|
||||
["sublime-text", "", "Sublime Text"],
|
||||
["atom", "", "Atom"],
|
||||
["android-studio", "", "Android Studio"],
|
||||
["intellij-idea", "", "IntelliJ IDEA"],
|
||||
["pycharm", "", "PyCharm"],
|
||||
["webstorm", "", "WebStorm"],
|
||||
["phpstorm", "", "PhpStorm"],
|
||||
["eclipse", "", "Eclipse"],
|
||||
["netbeans", "", "NetBeans"],
|
||||
["docker", "", "Docker"],
|
||||
["vim", "", "Vim"],
|
||||
["neovim", "", "Neovim"],
|
||||
["neovide", "", "Neovide"],
|
||||
["emacs", "", "Emacs"],
|
||||
['code', '', 'Visual Studio Code'],
|
||||
['vscode', '', 'VS Code'],
|
||||
['sublime-text', '', 'Sublime Text'],
|
||||
['atom', '', 'Atom'],
|
||||
['android-studio', '', 'Android Studio'],
|
||||
['intellij-idea', '', 'IntelliJ IDEA'],
|
||||
['pycharm', '', 'PyCharm'],
|
||||
['webstorm', '', 'WebStorm'],
|
||||
['phpstorm', '', 'PhpStorm'],
|
||||
['eclipse', '', 'Eclipse'],
|
||||
['netbeans', '', 'NetBeans'],
|
||||
['docker', '', 'Docker'],
|
||||
['vim', '', 'Vim'],
|
||||
['neovim', '', 'Neovim'],
|
||||
['neovide', '', 'Neovide'],
|
||||
['emacs', '', 'Emacs'],
|
||||
|
||||
// Communication Tools
|
||||
["slack", "", "Slack"],
|
||||
["telegram-desktop", "", "Telegram"],
|
||||
["org.telegram.desktop", "", "Telegram"],
|
||||
["whatsapp", "", "WhatsApp"],
|
||||
["teams", "", "Microsoft Teams"],
|
||||
["skype", "", "Skype"],
|
||||
["thunderbird", "", "Thunderbird"],
|
||||
['slack', '', 'Slack'],
|
||||
['telegram-desktop', '', 'Telegram'],
|
||||
['org.telegram.desktop', '', 'Telegram'],
|
||||
['whatsapp', '', 'WhatsApp'],
|
||||
['teams', '', 'Microsoft Teams'],
|
||||
['skype', '', 'Skype'],
|
||||
['thunderbird', '', 'Thunderbird'],
|
||||
|
||||
// File Managers
|
||||
["nautilus", "", "Files (Nautilus)"],
|
||||
["thunar", "", "Thunar"],
|
||||
["pcmanfm", "", "PCManFM"],
|
||||
["nemo", "", "Nemo"],
|
||||
["ranger", "", "Ranger"],
|
||||
["doublecmd", "", "Double Commander"],
|
||||
["krusader", "", "Krusader"],
|
||||
['nautilus', '', 'Files (Nautilus)'],
|
||||
['thunar', '', 'Thunar'],
|
||||
['pcmanfm', '', 'PCManFM'],
|
||||
['nemo', '', 'Nemo'],
|
||||
['ranger', '', 'Ranger'],
|
||||
['doublecmd', '', 'Double Commander'],
|
||||
['krusader', '', 'Krusader'],
|
||||
|
||||
// Media Players
|
||||
["vlc", "", "VLC Media Player"],
|
||||
["mpv", "", "MPV"],
|
||||
["rhythmbox", "", "Rhythmbox"],
|
||||
['vlc', '', 'VLC Media Player'],
|
||||
['mpv', '', 'MPV'],
|
||||
['rhythmbox', '', 'Rhythmbox'],
|
||||
|
||||
// Graphics Tools
|
||||
["gimp", "", "GIMP"],
|
||||
["inkscape", "", "Inkscape"],
|
||||
["krita", "", "Krita"],
|
||||
["blender", "", "Blender"],
|
||||
['gimp', '', 'GIMP'],
|
||||
['inkscape', '', 'Inkscape'],
|
||||
['krita', '', 'Krita'],
|
||||
['blender', '', 'Blender'],
|
||||
|
||||
// Video Editing
|
||||
["kdenlive", "", "Kdenlive"],
|
||||
['kdenlive', '', 'Kdenlive'],
|
||||
|
||||
// Games and Gaming Platforms
|
||||
["lutris", "", "Lutris"],
|
||||
["heroic", "", "Heroic Games Launcher"],
|
||||
["minecraft", "", "Minecraft"],
|
||||
["csgo", "", "CS:GO"],
|
||||
["dota2", "", "Dota 2"],
|
||||
['lutris', '', 'Lutris'],
|
||||
['heroic', '', 'Heroic Games Launcher'],
|
||||
['minecraft', '', 'Minecraft'],
|
||||
['csgo', '', 'CS:GO'],
|
||||
['dota2', '', 'Dota 2'],
|
||||
|
||||
// Office and Productivity
|
||||
["evernote", "", "Evernote"],
|
||||
["sioyek", "", "Sioyek"],
|
||||
|
||||
['evernote', '', 'Evernote'],
|
||||
['sioyek', '', 'Sioyek'],
|
||||
|
||||
// Cloud Services and Sync
|
||||
["dropbox", "", "Dropbox"],
|
||||
['dropbox', '', 'Dropbox'],
|
||||
|
||||
// Desktop
|
||||
["^$", "", "Desktop"],
|
||||
['^$', '', 'Desktop'],
|
||||
|
||||
// Fallback icon
|
||||
["(.+)", "", `${windowtitle.class.charAt(0).toUpperCase() + windowtitle.class.slice(1)}`],
|
||||
['(.+)', '', `${windowtitle.class.charAt(0).toUpperCase() + windowtitle.class.slice(1)}`],
|
||||
];
|
||||
|
||||
const foundMatch = windowTitleMap.find((wt) =>
|
||||
RegExp(wt[0]).test(windowtitle.class.toLowerCase()),
|
||||
);
|
||||
const foundMatch = windowTitleMap.find((wt) => RegExp(wt[0]).test(windowtitle.class.toLowerCase()));
|
||||
|
||||
// return the default icon if no match is found or
|
||||
// if the array element matched is not of size 3
|
||||
@@ -129,15 +126,15 @@ const filterTitle = (windowtitle: ActiveClient) => {
|
||||
|
||||
return {
|
||||
icon: foundMatch[1],
|
||||
label: foundMatch[2]
|
||||
label: foundMatch[2],
|
||||
};
|
||||
};
|
||||
|
||||
const getTitle = (client: ActiveClient, useCustomTitle: boolean, useClassName: boolean) => {
|
||||
const getTitle = (client: ActiveClient, useCustomTitle: boolean, useClassName: boolean): string => {
|
||||
if (useCustomTitle) return filterTitle(client).label;
|
||||
if (useClassName) return client.class;
|
||||
|
||||
let title = client.title;
|
||||
const title = client.title;
|
||||
// If the title is empty or only filled with spaces, fallback to the class name
|
||||
if (title.length === 0 || title.match(/^ *$/)) {
|
||||
return client.class;
|
||||
@@ -145,51 +142,76 @@ const getTitle = (client: ActiveClient, useCustomTitle: boolean, useClassName: b
|
||||
return title;
|
||||
};
|
||||
|
||||
const truncateTitle = (title: string, max_size: number) => {
|
||||
const truncateTitle = (title: string, max_size: number): string => {
|
||||
if (max_size > 0 && title.length > max_size) {
|
||||
return title.substring(0, max_size).trim() + "...";
|
||||
return title.substring(0, max_size).trim() + '...';
|
||||
}
|
||||
return title;
|
||||
};
|
||||
|
||||
const ClientTitle = () => {
|
||||
const ClientTitle = (): BarBoxChild => {
|
||||
const { custom_title, class_name, label, icon, truncation, truncation_size } = options.bar.windowtitle;
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value"), label.bind("value")], (style, showLabel) => {
|
||||
const styleMap = {
|
||||
default: "style1",
|
||||
split: "style2",
|
||||
wave: "style3",
|
||||
wave2: "style3",
|
||||
};
|
||||
return `windowtitle ${styleMap[style]} ${!showLabel ? "no-label" : ""}`;
|
||||
}),
|
||||
children:
|
||||
Utils.merge(
|
||||
[hyprland.active.bind("client"), custom_title.bind("value"), class_name.bind("value"), label.bind("value"),
|
||||
icon.bind("value"), truncation.bind("value"), truncation_size.bind("value")],
|
||||
(client, useCustomTitle, useClassName, showLabel, showIcon, truncate, truncationSize) => {
|
||||
const children: Label<any>[] = [];
|
||||
if (showIcon) {
|
||||
children.push(Widget.Label({
|
||||
class_name: "bar-button-icon windowtitle txt-icon bar",
|
||||
className: Utils.merge(
|
||||
[options.theme.bar.buttons.style.bind('value'), label.bind('value')],
|
||||
(style, showLabel) => {
|
||||
const styleMap = {
|
||||
default: 'style1',
|
||||
split: 'style2',
|
||||
wave: 'style3',
|
||||
wave2: 'style3',
|
||||
};
|
||||
return `windowtitle ${styleMap[style]} ${!showLabel ? 'no-label' : ''}`;
|
||||
},
|
||||
),
|
||||
children: Utils.merge(
|
||||
[
|
||||
hyprland.active.bind('client'),
|
||||
custom_title.bind('value'),
|
||||
class_name.bind('value'),
|
||||
label.bind('value'),
|
||||
icon.bind('value'),
|
||||
truncation.bind('value'),
|
||||
truncation_size.bind('value'),
|
||||
],
|
||||
(client, useCustomTitle, useClassName, showLabel, showIcon, truncate, truncationSize) => {
|
||||
if (showIcon) {
|
||||
return [
|
||||
Widget.Label({
|
||||
class_name: 'bar-button-icon windowtitle txt-icon bar',
|
||||
label: filterTitle(client).icon,
|
||||
}));
|
||||
}
|
||||
if (showLabel) {
|
||||
children.push(Widget.Label({
|
||||
class_name: `bar-button-label windowtitle ${showIcon ? "" : "no-icon"}`,
|
||||
label: truncateTitle(getTitle(client, useCustomTitle, useClassName), truncate ? truncationSize : -1),
|
||||
}));
|
||||
}
|
||||
return children;
|
||||
}),
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: `bar-button-label windowtitle ${showIcon ? '' : 'no-icon'}`,
|
||||
label: truncateTitle(
|
||||
getTitle(client, useCustomTitle, useClassName),
|
||||
truncate ? truncationSize : -1,
|
||||
),
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
if (showLabel) {
|
||||
return [
|
||||
Widget.Label({
|
||||
class_name: `bar-button-label windowtitle ${showIcon ? '' : 'no-icon'}`,
|
||||
label: truncateTitle(
|
||||
getTitle(client, useCustomTitle, useClassName),
|
||||
truncate ? truncationSize : -1,
|
||||
),
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "windowtitle",
|
||||
props: {}
|
||||
boxClass: 'windowtitle',
|
||||
props: {},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
const hyprland = await Service.import("hyprland");
|
||||
const hyprland = await Service.import('hyprland');
|
||||
|
||||
import { WorkspaceMap, WorkspaceRule } from "lib/types/workspace";
|
||||
import options from "options";
|
||||
import { Variable } from "types/variable";
|
||||
|
||||
const {
|
||||
workspaces,
|
||||
reverse_scroll,
|
||||
} = options.bar.workspaces;
|
||||
import { MonitorMap, WorkspaceMap, WorkspaceRule } from 'lib/types/workspace';
|
||||
import options from 'options';
|
||||
import { Variable } from 'types/variable';
|
||||
|
||||
const { workspaces, reverse_scroll } = options.bar.workspaces;
|
||||
|
||||
export const getWorkspacesForMonitor = (curWs: number, wsRules: WorkspaceMap, monitor: number): boolean => {
|
||||
if (!wsRules || !Object.keys(wsRules).length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const monitorMap = {};
|
||||
const workspaceMonitorList = hyprland?.workspaces?.map(m => ({ id: m.monitorID, name: m.monitor }));
|
||||
const monitors = [...new Map([...workspaceMonitorList, ...hyprland.monitors].map(item => [item.id, item])).values()];
|
||||
const monitorMap: MonitorMap = {};
|
||||
const workspaceMonitorList = hyprland?.workspaces?.map((m) => ({ id: m.monitorID, name: m.monitor }));
|
||||
const monitors = [
|
||||
...new Map([...workspaceMonitorList, ...hyprland.monitors].map((item) => [item.id, item])).values(),
|
||||
];
|
||||
|
||||
monitors.forEach((m) => (monitorMap[m.id] = m.name));
|
||||
|
||||
@@ -32,9 +30,9 @@ export const getWorkspacesForMonitor = (curWs: number, wsRules: WorkspaceMap, mo
|
||||
|
||||
export const getWorkspaceRules = (): WorkspaceMap => {
|
||||
try {
|
||||
const rules = Utils.exec("hyprctl workspacerules -j");
|
||||
const rules = Utils.exec('hyprctl workspacerules -j');
|
||||
|
||||
const workspaceRules = {};
|
||||
const workspaceRules: WorkspaceMap = {};
|
||||
|
||||
JSON.parse(rules).forEach((rule: WorkspaceRule, index: number) => {
|
||||
if (Object.hasOwnProperty.call(workspaceRules, rule.monitor)) {
|
||||
@@ -60,13 +58,13 @@ export const getCurrentMonitorWorkspaces = (monitor: number): number[] => {
|
||||
}
|
||||
|
||||
const monitorWorkspaces = getWorkspaceRules();
|
||||
const monitorMap = {};
|
||||
const monitorMap: MonitorMap = {};
|
||||
hyprland.monitors.forEach((m) => (monitorMap[m.id] = m.name));
|
||||
|
||||
const currentMonitorName = monitorMap[monitor];
|
||||
|
||||
return monitorWorkspaces[currentMonitorName];
|
||||
}
|
||||
};
|
||||
|
||||
export const goToNextWS = (currentMonitorWorkspaces: Variable<number[]>, activeWorkspaces: boolean): void => {
|
||||
if (activeWorkspaces === true) {
|
||||
@@ -74,18 +72,17 @@ export const goToNextWS = (currentMonitorWorkspaces: Variable<number[]>, activeW
|
||||
|
||||
let nextIndex = hyprland.active.workspace.id + 1;
|
||||
if (nextIndex > activeWses[activeWses.length - 1].id) {
|
||||
|
||||
nextIndex = activeWses[0].id;
|
||||
}
|
||||
|
||||
hyprland.messageAsync(`dispatch workspace ${nextIndex}`)
|
||||
hyprland.messageAsync(`dispatch workspace ${nextIndex}`);
|
||||
} else if (currentMonitorWorkspaces.value === undefined) {
|
||||
let nextIndex = hyprland.active.workspace.id + 1;
|
||||
if (nextIndex > workspaces.value) {
|
||||
nextIndex = 0;
|
||||
}
|
||||
|
||||
hyprland.messageAsync(`dispatch workspace ${nextIndex}`)
|
||||
hyprland.messageAsync(`dispatch workspace ${nextIndex}`);
|
||||
} else {
|
||||
const curWorkspace = hyprland.active.workspace.id;
|
||||
const indexOfWs = currentMonitorWorkspaces.value.indexOf(curWorkspace);
|
||||
@@ -94,9 +91,9 @@ export const goToNextWS = (currentMonitorWorkspaces: Variable<number[]>, activeW
|
||||
nextIndex = 0;
|
||||
}
|
||||
|
||||
hyprland.messageAsync(`dispatch workspace ${currentMonitorWorkspaces.value[nextIndex]}`)
|
||||
hyprland.messageAsync(`dispatch workspace ${currentMonitorWorkspaces.value[nextIndex]}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const goToPrevWS = (currentMonitorWorkspaces: Variable<number[]>, activeWorkspaces: boolean): void => {
|
||||
if (activeWorkspaces === true) {
|
||||
@@ -104,11 +101,10 @@ export const goToPrevWS = (currentMonitorWorkspaces: Variable<number[]>, activeW
|
||||
|
||||
let prevIndex = hyprland.active.workspace.id - 1;
|
||||
if (prevIndex < activeWses[0].id) {
|
||||
|
||||
prevIndex = activeWses[activeWses.length - 1].id;
|
||||
}
|
||||
|
||||
hyprland.messageAsync(`dispatch workspace ${prevIndex}`)
|
||||
hyprland.messageAsync(`dispatch workspace ${prevIndex}`);
|
||||
} else if (currentMonitorWorkspaces.value === undefined) {
|
||||
let prevIndex = hyprland.active.workspace.id - 1;
|
||||
|
||||
@@ -116,7 +112,7 @@ export const goToPrevWS = (currentMonitorWorkspaces: Variable<number[]>, activeW
|
||||
prevIndex = workspaces.value;
|
||||
}
|
||||
|
||||
hyprland.messageAsync(`dispatch workspace ${prevIndex}`)
|
||||
hyprland.messageAsync(`dispatch workspace ${prevIndex}`);
|
||||
} else {
|
||||
const curWorkspace = hyprland.active.workspace.id;
|
||||
const indexOfWs = currentMonitorWorkspaces.value.indexOf(curWorkspace);
|
||||
@@ -125,11 +121,11 @@ export const goToPrevWS = (currentMonitorWorkspaces: Variable<number[]>, activeW
|
||||
prevIndex = currentMonitorWorkspaces.value.length - 1;
|
||||
}
|
||||
|
||||
hyprland.messageAsync(`dispatch workspace ${currentMonitorWorkspaces.value[prevIndex]}`)
|
||||
hyprland.messageAsync(`dispatch workspace ${currentMonitorWorkspaces.value[prevIndex]}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function throttle<T extends (...args: any[]) => void>(func: T, limit: number): T {
|
||||
export function throttle<T extends (...args: unknown[]) => void>(func: T, limit: number): T {
|
||||
let inThrottle: boolean;
|
||||
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
|
||||
if (!inThrottle) {
|
||||
@@ -147,7 +143,11 @@ type ThrottledScrollHandlers = {
|
||||
throttledScrollDown: () => void;
|
||||
};
|
||||
|
||||
export const createThrottledScrollHandlers = (scrollSpeed: number, currentMonitorWorkspaces: Variable<number[]>, activeWorkspaces: boolean = false): ThrottledScrollHandlers => {
|
||||
export const createThrottledScrollHandlers = (
|
||||
scrollSpeed: number,
|
||||
currentMonitorWorkspaces: Variable<number[]>,
|
||||
activeWorkspaces: boolean = false,
|
||||
): ThrottledScrollHandlers => {
|
||||
const throttledScrollUp = throttle(() => {
|
||||
if (reverse_scroll.value === true) {
|
||||
goToPrevWS(currentMonitorWorkspaces, activeWorkspaces);
|
||||
@@ -165,4 +165,4 @@ export const createThrottledScrollHandlers = (scrollSpeed: number, currentMonito
|
||||
}, 200 / scrollSpeed);
|
||||
|
||||
return { throttledScrollUp, throttledScrollDown };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,42 +1,54 @@
|
||||
const hyprland = await Service.import("hyprland");
|
||||
import options from "options";
|
||||
import { createThrottledScrollHandlers, getCurrentMonitorWorkspaces, getWorkspaceRules, getWorkspacesForMonitor } from "./helpers";
|
||||
import { Workspace } from "types/service/hyprland";
|
||||
const hyprland = await Service.import('hyprland');
|
||||
import options from 'options';
|
||||
import {
|
||||
createThrottledScrollHandlers,
|
||||
getCurrentMonitorWorkspaces,
|
||||
getWorkspaceRules,
|
||||
getWorkspacesForMonitor,
|
||||
} from './helpers';
|
||||
import { Workspace } from 'types/service/hyprland';
|
||||
import { BoxWidget } from 'lib/types/widget';
|
||||
import { BarBoxChild, SelfButton } from 'lib/types/bar';
|
||||
|
||||
const {
|
||||
workspaces,
|
||||
monitorSpecific,
|
||||
workspaceMask,
|
||||
scroll_speed,
|
||||
spacing
|
||||
} = options.bar.workspaces;
|
||||
const { workspaces, monitorSpecific, workspaceMask, scroll_speed, spacing } = options.bar.workspaces;
|
||||
|
||||
function range(length: number, start = 1) {
|
||||
function range(length: number, start = 1): number[] {
|
||||
return Array.from({ length }, (_, i) => i + start);
|
||||
}
|
||||
|
||||
const Workspaces = (monitor = -1) => {
|
||||
const Workspaces = (monitor = -1): BarBoxChild => {
|
||||
const currentMonitorWorkspaces = Variable(getCurrentMonitorWorkspaces(monitor));
|
||||
|
||||
workspaces.connect("changed", () => {
|
||||
currentMonitorWorkspaces.value = getCurrentMonitorWorkspaces(monitor)
|
||||
})
|
||||
workspaces.connect('changed', () => {
|
||||
currentMonitorWorkspaces.value = getCurrentMonitorWorkspaces(monitor);
|
||||
});
|
||||
|
||||
const renderClassnames = (showIcons: boolean, showNumbered: boolean, numberedActiveIndicator: string, i: number) => {
|
||||
const renderClassnames = (
|
||||
showIcons: boolean,
|
||||
showNumbered: boolean,
|
||||
numberedActiveIndicator: string,
|
||||
i: number,
|
||||
): string => {
|
||||
if (showIcons) {
|
||||
return `workspace-icon txt-icon bar`;
|
||||
}
|
||||
if (showNumbered) {
|
||||
const numActiveInd = hyprland.active.workspace.id === i
|
||||
? numberedActiveIndicator
|
||||
: "";
|
||||
const numActiveInd = hyprland.active.workspace.id === i ? numberedActiveIndicator : '';
|
||||
|
||||
return `workspace-number can_${numberedActiveIndicator} ${numActiveInd}`;
|
||||
}
|
||||
return "default";
|
||||
}
|
||||
return 'default';
|
||||
};
|
||||
|
||||
const renderLabel = (showIcons: boolean, available: string, active: string, occupied: string, workspaceMask: boolean, i: number, index: number) => {
|
||||
const renderLabel = (
|
||||
showIcons: boolean,
|
||||
available: string,
|
||||
active: string,
|
||||
occupied: string,
|
||||
workspaceMask: boolean,
|
||||
i: number,
|
||||
index: number,
|
||||
): string => {
|
||||
if (showIcons) {
|
||||
if (hyprland.active.workspace.id === i) {
|
||||
return active;
|
||||
@@ -44,20 +56,16 @@ const Workspaces = (monitor = -1) => {
|
||||
if ((hyprland.getWorkspace(i)?.windows || 0) > 0) {
|
||||
return occupied;
|
||||
}
|
||||
if (
|
||||
monitor !== -1
|
||||
) {
|
||||
if (monitor !== -1) {
|
||||
return available;
|
||||
}
|
||||
}
|
||||
return workspaceMask
|
||||
? `${index + 1}`
|
||||
: `${i}`;
|
||||
}
|
||||
const defaultWses = () => {
|
||||
return workspaceMask ? `${index + 1}` : `${i}`;
|
||||
};
|
||||
const defaultWses = (): BoxWidget => {
|
||||
return Widget.Box({
|
||||
children: Utils.merge(
|
||||
[workspaces.bind("value"), monitorSpecific.bind()],
|
||||
[workspaces.bind('value'), monitorSpecific.bind()],
|
||||
(workspaces: number, monitorSpecific: boolean) => {
|
||||
return range(workspaces || 8)
|
||||
.filter((i) => {
|
||||
@@ -72,49 +80,57 @@ const Workspaces = (monitor = -1) => {
|
||||
})
|
||||
.map((i, index) => {
|
||||
return Widget.Button({
|
||||
class_name: "workspace-button",
|
||||
class_name: 'workspace-button',
|
||||
on_primary_click: () => {
|
||||
hyprland.messageAsync(`dispatch workspace ${i}`)
|
||||
|
||||
hyprland.messageAsync(`dispatch workspace ${i}`);
|
||||
},
|
||||
child: Widget.Label({
|
||||
attribute: i,
|
||||
vpack: "center",
|
||||
css: spacing.bind("value").as(sp => `margin: 0rem ${0.375 * sp}rem;`),
|
||||
vpack: 'center',
|
||||
css: spacing.bind('value').as((sp) => `margin: 0rem ${0.375 * sp}rem;`),
|
||||
class_name: Utils.merge(
|
||||
[
|
||||
options.bar.workspaces.show_icons.bind("value"),
|
||||
options.bar.workspaces.show_numbered.bind("value"),
|
||||
options.bar.workspaces.numbered_active_indicator.bind("value"),
|
||||
options.bar.workspaces.icons.available.bind("value"),
|
||||
options.bar.workspaces.icons.active.bind("value"),
|
||||
options.bar.workspaces.icons.occupied.bind("value"),
|
||||
hyprland.active.workspace.bind("id")
|
||||
options.bar.workspaces.show_icons.bind('value'),
|
||||
options.bar.workspaces.show_numbered.bind('value'),
|
||||
options.bar.workspaces.numbered_active_indicator.bind('value'),
|
||||
options.bar.workspaces.icons.available.bind('value'),
|
||||
options.bar.workspaces.icons.active.bind('value'),
|
||||
options.bar.workspaces.icons.occupied.bind('value'),
|
||||
hyprland.active.workspace.bind('id'),
|
||||
],
|
||||
(showIcons: boolean, showNumbered: boolean, numberedActiveIndicator: string) => {
|
||||
(
|
||||
showIcons: boolean,
|
||||
showNumbered: boolean,
|
||||
numberedActiveIndicator: string,
|
||||
) => {
|
||||
if (showIcons) {
|
||||
return `workspace-icon txt-icon bar`;
|
||||
}
|
||||
if (showNumbered) {
|
||||
const numActiveInd = hyprland.active.workspace.id === i
|
||||
? numberedActiveIndicator
|
||||
: "";
|
||||
const numActiveInd =
|
||||
hyprland.active.workspace.id === i ? numberedActiveIndicator : '';
|
||||
|
||||
return `workspace-number can_${numberedActiveIndicator} ${numActiveInd}`;
|
||||
}
|
||||
return "default";
|
||||
return 'default';
|
||||
},
|
||||
),
|
||||
label: Utils.merge(
|
||||
[
|
||||
options.bar.workspaces.show_icons.bind("value"),
|
||||
options.bar.workspaces.icons.available.bind("value"),
|
||||
options.bar.workspaces.icons.active.bind("value"),
|
||||
options.bar.workspaces.icons.occupied.bind("value"),
|
||||
workspaceMask.bind("value"),
|
||||
hyprland.active.workspace.bind("id")
|
||||
options.bar.workspaces.show_icons.bind('value'),
|
||||
options.bar.workspaces.icons.available.bind('value'),
|
||||
options.bar.workspaces.icons.active.bind('value'),
|
||||
options.bar.workspaces.icons.occupied.bind('value'),
|
||||
workspaceMask.bind('value'),
|
||||
hyprland.active.workspace.bind('id'),
|
||||
],
|
||||
(showIcons: boolean, available: string, active: string, occupied: string, workspaceMask: boolean, _: number) => {
|
||||
(
|
||||
showIcons: boolean,
|
||||
available: string,
|
||||
active: string,
|
||||
occupied: string,
|
||||
workspaceMask: boolean,
|
||||
) => {
|
||||
if (showIcons) {
|
||||
if (hyprland.active.workspace.id === i) {
|
||||
return active;
|
||||
@@ -122,52 +138,45 @@ const Workspaces = (monitor = -1) => {
|
||||
if ((hyprland.getWorkspace(i)?.windows || 0) > 0) {
|
||||
return occupied;
|
||||
}
|
||||
if (
|
||||
monitor !== -1
|
||||
) {
|
||||
if (monitor !== -1) {
|
||||
return available;
|
||||
}
|
||||
}
|
||||
return workspaceMask
|
||||
? `${index + 1}`
|
||||
: `${i}`;
|
||||
return workspaceMask ? `${index + 1}` : `${i}`;
|
||||
},
|
||||
),
|
||||
setup: (self) => {
|
||||
self.hook(hyprland, () => {
|
||||
self.toggleClassName('active', hyprland.active.workspace.id === i);
|
||||
self.toggleClassName(
|
||||
"active",
|
||||
hyprland.active.workspace.id === i,
|
||||
);
|
||||
self.toggleClassName(
|
||||
"occupied",
|
||||
'occupied',
|
||||
(hyprland.getWorkspace(i)?.windows || 0) > 0,
|
||||
);
|
||||
});
|
||||
},
|
||||
})
|
||||
}),
|
||||
});
|
||||
});
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
const occupiedWses = () => {
|
||||
),
|
||||
});
|
||||
};
|
||||
const occupiedWses = (): BoxWidget => {
|
||||
return Widget.Box({
|
||||
children: Utils.merge(
|
||||
[
|
||||
monitorSpecific.bind("value"),
|
||||
hyprland.bind("workspaces"),
|
||||
workspaceMask.bind("value"),
|
||||
workspaces.bind("value"),
|
||||
options.bar.workspaces.show_icons.bind("value"),
|
||||
options.bar.workspaces.icons.available.bind("value"),
|
||||
options.bar.workspaces.icons.active.bind("value"),
|
||||
options.bar.workspaces.icons.occupied.bind("value"),
|
||||
options.bar.workspaces.show_numbered.bind("value"),
|
||||
options.bar.workspaces.numbered_active_indicator.bind("value"),
|
||||
spacing.bind("value"),
|
||||
hyprland.active.workspace.bind("id"),
|
||||
monitorSpecific.bind('value'),
|
||||
hyprland.bind('workspaces'),
|
||||
workspaceMask.bind('value'),
|
||||
workspaces.bind('value'),
|
||||
options.bar.workspaces.show_icons.bind('value'),
|
||||
options.bar.workspaces.icons.available.bind('value'),
|
||||
options.bar.workspaces.icons.active.bind('value'),
|
||||
options.bar.workspaces.icons.occupied.bind('value'),
|
||||
options.bar.workspaces.show_numbered.bind('value'),
|
||||
options.bar.workspaces.numbered_active_indicator.bind('value'),
|
||||
spacing.bind('value'),
|
||||
hyprland.active.workspace.bind('id'),
|
||||
],
|
||||
(
|
||||
monitorSpecific: boolean,
|
||||
@@ -185,29 +194,37 @@ const Workspaces = (monitor = -1) => {
|
||||
) => {
|
||||
let allWkspcs = range(totalWkspcs || 8);
|
||||
|
||||
const activeWorkspaces = wkSpaces.map(w => w.id);
|
||||
const activeWorkspaces = wkSpaces.map((w) => w.id);
|
||||
const workspaceRules = getWorkspaceRules();
|
||||
|
||||
// Sometimes hyprland doesn't have all the monitors in the list
|
||||
// so we complement it with monitors from the workspace list
|
||||
const workspaceMonitorList = hyprland?.workspaces?.map(m => ({ id: m.monitorID, name: m.monitor }));
|
||||
const curMonitor = hyprland.monitors.find(m => m.id === monitor)
|
||||
|| workspaceMonitorList.find(m => m.id === monitor);
|
||||
const workspaceMonitorList = hyprland?.workspaces?.map((m) => ({
|
||||
id: m.monitorID,
|
||||
name: m.monitor,
|
||||
}));
|
||||
const curMonitor =
|
||||
hyprland.monitors.find((m) => m.id === monitor) ||
|
||||
workspaceMonitorList.find((m) => m.id === monitor);
|
||||
|
||||
// go through each key in workspaceRules and flatten the array
|
||||
const workspacesWithRules = Object.keys(workspaceRules).reduce((acc: number[], k: string) => {
|
||||
return [...acc, ...workspaceRules[k]];
|
||||
}, [] as number[]);
|
||||
|
||||
const activesForMonitor = activeWorkspaces.filter(w => {
|
||||
if (curMonitor && Object.hasOwnProperty.call(workspaceRules, curMonitor.name) && workspacesWithRules.includes(w)) {
|
||||
const activesForMonitor = activeWorkspaces.filter((w) => {
|
||||
if (
|
||||
curMonitor &&
|
||||
Object.hasOwnProperty.call(workspaceRules, curMonitor.name) &&
|
||||
workspacesWithRules.includes(w)
|
||||
) {
|
||||
return workspaceRules[curMonitor.name].includes(w);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (monitorSpecific) {
|
||||
const wrkspcsInRange = range(totalWkspcs).filter(w => {
|
||||
const wrkspcsInRange = range(totalWkspcs).filter((w) => {
|
||||
return getWorkspacesForMonitor(w, workspaceRules, monitor);
|
||||
});
|
||||
allWkspcs = [...new Set([...activesForMonitor, ...wrkspcsInRange])];
|
||||
@@ -221,51 +238,53 @@ const Workspaces = (monitor = -1) => {
|
||||
})
|
||||
.map((i, index) => {
|
||||
return Widget.Button({
|
||||
class_name: "workspace-button",
|
||||
class_name: 'workspace-button',
|
||||
on_primary_click: () => {
|
||||
hyprland.messageAsync(`dispatch workspace ${i}`)
|
||||
|
||||
hyprland.messageAsync(`dispatch workspace ${i}`);
|
||||
},
|
||||
child: Widget.Label({
|
||||
attribute: i,
|
||||
vpack: "center",
|
||||
vpack: 'center',
|
||||
css: `margin: 0rem ${0.375 * spacing}rem;`,
|
||||
class_name: renderClassnames(showIcons, showNumbered, numberedActiveIndicator, i),
|
||||
label: renderLabel(showIcons, available, active, occupied, workspaceMask, i, index),
|
||||
setup: (self) => {
|
||||
self.toggleClassName(
|
||||
"active",
|
||||
activeId === i,
|
||||
);
|
||||
self.toggleClassName(
|
||||
"occupied",
|
||||
(hyprland.getWorkspace(i)?.windows || 0) > 0,
|
||||
);
|
||||
self.toggleClassName('active', activeId === i);
|
||||
self.toggleClassName('occupied', (hyprland.getWorkspace(i)?.windows || 0) > 0);
|
||||
},
|
||||
})
|
||||
}),
|
||||
});
|
||||
});
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
class_name: "workspaces",
|
||||
child: options.bar.workspaces.hideUnoccupied.bind("value").as(hideUnoccupied => hideUnoccupied ? occupiedWses() : defaultWses()),
|
||||
class_name: 'workspaces',
|
||||
child: options.bar.workspaces.hideUnoccupied
|
||||
.bind('value')
|
||||
.as((hideUnoccupied) => (hideUnoccupied ? occupiedWses() : defaultWses())),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "workspaces",
|
||||
boxClass: 'workspaces',
|
||||
props: {
|
||||
setup: (self: any) => {
|
||||
Utils.merge([scroll_speed.bind("value"), options.bar.workspaces.hideUnoccupied.bind("value")], (scroll_speed, hideUnoccupied) => {
|
||||
const { throttledScrollUp, throttledScrollDown } = createThrottledScrollHandlers(scroll_speed, currentMonitorWorkspaces, hideUnoccupied)
|
||||
self.on_scroll_up = throttledScrollUp;
|
||||
self.on_scroll_down = throttledScrollDown;
|
||||
});
|
||||
}
|
||||
}
|
||||
setup: (self: SelfButton): void => {
|
||||
Utils.merge(
|
||||
[scroll_speed.bind('value'), options.bar.workspaces.hideUnoccupied.bind('value')],
|
||||
(scroll_speed, hideUnoccupied) => {
|
||||
const { throttledScrollUp, throttledScrollDown } = createThrottledScrollHandlers(
|
||||
scroll_speed,
|
||||
currentMonitorWorkspaces,
|
||||
hideUnoccupied,
|
||||
);
|
||||
self.on_scroll_up = throttledScrollUp;
|
||||
self.on_scroll_down = throttledScrollDown;
|
||||
},
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
43
modules/bar/workspaces/utils.ts
Normal file
43
modules/bar/workspaces/utils.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
const hyprland = await Service.import('hyprland');
|
||||
|
||||
export const renderClassnames = (
|
||||
showIcons: boolean,
|
||||
showNumbered: boolean,
|
||||
numberedActiveIndicator: string,
|
||||
i: number,
|
||||
): string => {
|
||||
if (showIcons) {
|
||||
return `workspace-icon txt-icon bar`;
|
||||
}
|
||||
if (showNumbered) {
|
||||
const numActiveInd = hyprland.active.workspace.id === i ? numberedActiveIndicator : '';
|
||||
|
||||
return `workspace-number can_${numberedActiveIndicator} ${numActiveInd}`;
|
||||
}
|
||||
return 'default';
|
||||
};
|
||||
|
||||
export const renderLabel = (
|
||||
showIcons: boolean,
|
||||
available: string,
|
||||
active: string,
|
||||
occupied: string,
|
||||
workspaceMask: boolean,
|
||||
i: number,
|
||||
index: number,
|
||||
monitor: number,
|
||||
): string => {
|
||||
if (showIcons) {
|
||||
if (hyprland.active.workspace.id === i) {
|
||||
return active;
|
||||
}
|
||||
if ((hyprland.getWorkspace(i)?.windows || 0) > 0) {
|
||||
return occupied;
|
||||
}
|
||||
if (monitor !== -1) {
|
||||
return available;
|
||||
}
|
||||
}
|
||||
|
||||
return workspaceMask ? `${index + 1}` : `${i}`;
|
||||
};
|
||||
99
modules/bar/workspaces/variants/default.ts
Normal file
99
modules/bar/workspaces/variants/default.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
const hyprland = await Service.import('hyprland');
|
||||
import options from 'options';
|
||||
import { getWorkspaceRules, getWorkspacesForMonitor } from '../helpers';
|
||||
import { range } from 'lib/utils';
|
||||
import { BoxWidget } from 'lib/types/widget';
|
||||
|
||||
const { workspaces, monitorSpecific, workspaceMask, spacing } = options.bar.workspaces;
|
||||
export const defaultWses = (monitor: number): BoxWidget => {
|
||||
return Widget.Box({
|
||||
children: Utils.merge(
|
||||
[workspaces.bind('value'), monitorSpecific.bind()],
|
||||
(workspaces: number, monitorSpecific: boolean) => {
|
||||
return range(workspaces || 8)
|
||||
.filter((i) => {
|
||||
if (!monitorSpecific) {
|
||||
return true;
|
||||
}
|
||||
const workspaceRules = getWorkspaceRules();
|
||||
return getWorkspacesForMonitor(i, workspaceRules, monitor);
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return a - b;
|
||||
})
|
||||
.map((i, index) => {
|
||||
return Widget.Button({
|
||||
class_name: 'workspace-button',
|
||||
on_primary_click: () => {
|
||||
hyprland.messageAsync(`dispatch workspace ${i}`);
|
||||
},
|
||||
child: Widget.Label({
|
||||
attribute: i,
|
||||
vpack: 'center',
|
||||
css: spacing.bind('value').as((sp) => `margin: 0rem ${0.375 * sp}rem;`),
|
||||
class_name: Utils.merge(
|
||||
[
|
||||
options.bar.workspaces.show_icons.bind('value'),
|
||||
options.bar.workspaces.show_numbered.bind('value'),
|
||||
options.bar.workspaces.numbered_active_indicator.bind('value'),
|
||||
options.bar.workspaces.icons.available.bind('value'),
|
||||
options.bar.workspaces.icons.active.bind('value'),
|
||||
options.bar.workspaces.icons.occupied.bind('value'),
|
||||
hyprland.active.workspace.bind('id'),
|
||||
],
|
||||
(showIcons: boolean, showNumbered: boolean, numberedActiveIndicator: string) => {
|
||||
if (showIcons) {
|
||||
return `workspace-icon txt-icon bar`;
|
||||
}
|
||||
if (showNumbered) {
|
||||
const numActiveInd =
|
||||
hyprland.active.workspace.id === i ? numberedActiveIndicator : '';
|
||||
|
||||
return `workspace-number can_${numberedActiveIndicator} ${numActiveInd}`;
|
||||
}
|
||||
return 'default';
|
||||
},
|
||||
),
|
||||
label: Utils.merge(
|
||||
[
|
||||
options.bar.workspaces.show_icons.bind('value'),
|
||||
options.bar.workspaces.icons.available.bind('value'),
|
||||
options.bar.workspaces.icons.active.bind('value'),
|
||||
options.bar.workspaces.icons.occupied.bind('value'),
|
||||
workspaceMask.bind('value'),
|
||||
hyprland.active.workspace.bind('id'),
|
||||
],
|
||||
(
|
||||
showIcons: boolean,
|
||||
available: string,
|
||||
active: string,
|
||||
occupied: string,
|
||||
workspaceMask: boolean,
|
||||
) => {
|
||||
if (showIcons) {
|
||||
if (hyprland.active.workspace.id === i) {
|
||||
return active;
|
||||
}
|
||||
if ((hyprland.getWorkspace(i)?.windows || 0) > 0) {
|
||||
return occupied;
|
||||
}
|
||||
if (monitor !== -1) {
|
||||
return available;
|
||||
}
|
||||
}
|
||||
return workspaceMask ? `${index + 1}` : `${i}`;
|
||||
},
|
||||
),
|
||||
setup: (self) => {
|
||||
self.hook(hyprland, () => {
|
||||
self.toggleClassName('active', hyprland.active.workspace.id === i);
|
||||
self.toggleClassName('occupied', (hyprland.getWorkspace(i)?.windows || 0) > 0);
|
||||
});
|
||||
},
|
||||
}),
|
||||
});
|
||||
});
|
||||
},
|
||||
),
|
||||
});
|
||||
};
|
||||
114
modules/bar/workspaces/variants/occupied.ts
Normal file
114
modules/bar/workspaces/variants/occupied.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
const hyprland = await Service.import('hyprland');
|
||||
import options from 'options';
|
||||
import { getWorkspaceRules, getWorkspacesForMonitor } from '../helpers';
|
||||
import { Workspace } from 'types/service/hyprland';
|
||||
import { renderClassnames, renderLabel } from '../utils';
|
||||
import { range } from 'lib/utils';
|
||||
import { BoxWidget } from 'lib/types/widget';
|
||||
|
||||
const { workspaces, monitorSpecific, workspaceMask, spacing } = options.bar.workspaces;
|
||||
|
||||
export const occupiedWses = (monitor: number): BoxWidget => {
|
||||
return Widget.Box({
|
||||
children: Utils.merge(
|
||||
[
|
||||
monitorSpecific.bind('value'),
|
||||
hyprland.bind('workspaces'),
|
||||
workspaceMask.bind('value'),
|
||||
workspaces.bind('value'),
|
||||
options.bar.workspaces.show_icons.bind('value'),
|
||||
options.bar.workspaces.icons.available.bind('value'),
|
||||
options.bar.workspaces.icons.active.bind('value'),
|
||||
options.bar.workspaces.icons.occupied.bind('value'),
|
||||
options.bar.workspaces.show_numbered.bind('value'),
|
||||
options.bar.workspaces.numbered_active_indicator.bind('value'),
|
||||
spacing.bind('value'),
|
||||
hyprland.active.workspace.bind('id'),
|
||||
],
|
||||
(
|
||||
monitorSpecific: boolean,
|
||||
wkSpaces: Workspace[],
|
||||
workspaceMask: boolean,
|
||||
totalWkspcs: number,
|
||||
showIcons: boolean,
|
||||
available: string,
|
||||
active: string,
|
||||
occupied: string,
|
||||
showNumbered: boolean,
|
||||
numberedActiveIndicator: string,
|
||||
spacing: number,
|
||||
activeId: number,
|
||||
) => {
|
||||
let allWkspcs = range(totalWkspcs || 8);
|
||||
|
||||
const activeWorkspaces = wkSpaces.map((w) => w.id);
|
||||
const workspaceRules = getWorkspaceRules();
|
||||
|
||||
// Sometimes hyprland doesn't have all the monitors in the list
|
||||
// so we complement it with monitors from the workspace list
|
||||
const workspaceMonitorList = hyprland?.workspaces?.map((m) => ({ id: m.monitorID, name: m.monitor }));
|
||||
const curMonitor =
|
||||
hyprland.monitors.find((m) => m.id === monitor) ||
|
||||
workspaceMonitorList.find((m) => m.id === monitor);
|
||||
|
||||
// go through each key in workspaceRules and flatten the array
|
||||
const workspacesWithRules = Object.keys(workspaceRules).reduce((acc: number[], k: string) => {
|
||||
return [...acc, ...workspaceRules[k]];
|
||||
}, [] as number[]);
|
||||
|
||||
const activesForMonitor = activeWorkspaces.filter((w) => {
|
||||
if (
|
||||
curMonitor &&
|
||||
Object.hasOwnProperty.call(workspaceRules, curMonitor.name) &&
|
||||
workspacesWithRules.includes(w)
|
||||
) {
|
||||
return workspaceRules[curMonitor.name].includes(w);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (monitorSpecific) {
|
||||
const wrkspcsInRange = range(totalWkspcs).filter((w) => {
|
||||
return getWorkspacesForMonitor(w, workspaceRules, monitor);
|
||||
});
|
||||
allWkspcs = [...new Set([...activesForMonitor, ...wrkspcsInRange])];
|
||||
} else {
|
||||
allWkspcs = [...new Set([...allWkspcs, ...activeWorkspaces])];
|
||||
}
|
||||
|
||||
return allWkspcs
|
||||
.sort((a, b) => {
|
||||
return a - b;
|
||||
})
|
||||
.map((i, index) => {
|
||||
return Widget.Button({
|
||||
class_name: 'workspace-button',
|
||||
on_primary_click: () => {
|
||||
hyprland.messageAsync(`dispatch workspace ${i}`);
|
||||
},
|
||||
child: Widget.Label({
|
||||
attribute: i,
|
||||
vpack: 'center',
|
||||
css: `margin: 0rem ${0.375 * spacing}rem;`,
|
||||
class_name: renderClassnames(showIcons, showNumbered, numberedActiveIndicator, i),
|
||||
label: renderLabel(
|
||||
showIcons,
|
||||
available,
|
||||
active,
|
||||
occupied,
|
||||
workspaceMask,
|
||||
i,
|
||||
index,
|
||||
monitor,
|
||||
),
|
||||
setup: (self) => {
|
||||
self.toggleClassName('active', activeId === i);
|
||||
self.toggleClassName('occupied', (hyprland.getWorkspace(i)?.windows || 0) > 0);
|
||||
},
|
||||
}),
|
||||
});
|
||||
});
|
||||
},
|
||||
),
|
||||
});
|
||||
};
|
||||
@@ -1,199 +1,199 @@
|
||||
export const substitutes = {
|
||||
"transmission-gtk": "transmission",
|
||||
"blueberry.py": "blueberry",
|
||||
Caprine: "facebook-messenger",
|
||||
"com.raggesilver.BlackBox-symbolic": "terminal-symbolic",
|
||||
"org.wezfurlong.wezterm-symbolic": "terminal-symbolic",
|
||||
"audio-headset-bluetooth": "audio-headphones-symbolic",
|
||||
"audio-card-analog-usb": "audio-speakers-symbolic",
|
||||
"audio-card-analog-pci": "audio-card-symbolic",
|
||||
"preferences-system": "emblem-system-symbolic",
|
||||
"com.github.Aylur.ags-symbolic": "controls-symbolic",
|
||||
"com.github.Aylur.ags": "controls-symbolic",
|
||||
'transmission-gtk': 'transmission',
|
||||
'blueberry.py': 'blueberry',
|
||||
Caprine: 'facebook-messenger',
|
||||
'com.raggesilver.BlackBox-symbolic': 'terminal-symbolic',
|
||||
'org.wezfurlong.wezterm-symbolic': 'terminal-symbolic',
|
||||
'audio-headset-bluetooth': 'audio-headphones-symbolic',
|
||||
'audio-card-analog-usb': 'audio-speakers-symbolic',
|
||||
'audio-card-analog-pci': 'audio-card-symbolic',
|
||||
'preferences-system': 'emblem-system-symbolic',
|
||||
'com.github.Aylur.ags-symbolic': 'controls-symbolic',
|
||||
'com.github.Aylur.ags': 'controls-symbolic',
|
||||
};
|
||||
|
||||
export default {
|
||||
missing: "image-missing-symbolic",
|
||||
missing: 'image-missing-symbolic',
|
||||
nix: {
|
||||
nix: "nix-snowflake-symbolic",
|
||||
nix: 'nix-snowflake-symbolic',
|
||||
},
|
||||
app: {
|
||||
terminal: "terminal-symbolic",
|
||||
terminal: 'terminal-symbolic',
|
||||
},
|
||||
fallback: {
|
||||
executable: "application-x-executable",
|
||||
notification: "dialog-information-symbolic",
|
||||
video: "video-x-generic-symbolic",
|
||||
audio: "audio-x-generic-symbolic",
|
||||
executable: 'application-x-executable',
|
||||
notification: 'dialog-information-symbolic',
|
||||
video: 'video-x-generic-symbolic',
|
||||
audio: 'audio-x-generic-symbolic',
|
||||
},
|
||||
ui: {
|
||||
close: "window-close-symbolic",
|
||||
colorpicker: "color-select-symbolic",
|
||||
info: "info-symbolic",
|
||||
link: "external-link-symbolic",
|
||||
lock: "system-lock-screen-symbolic",
|
||||
menu: "open-menu-symbolic",
|
||||
refresh: "view-refresh-symbolic",
|
||||
search: "system-search-symbolic",
|
||||
settings: "emblem-system-symbolic",
|
||||
themes: "preferences-desktop-theme-symbolic",
|
||||
tick: "object-select-symbolic",
|
||||
time: "hourglass-symbolic",
|
||||
toolbars: "toolbars-symbolic",
|
||||
warning: "dialog-warning-symbolic",
|
||||
avatar: "avatar-default-symbolic",
|
||||
close: 'window-close-symbolic',
|
||||
colorpicker: 'color-select-symbolic',
|
||||
info: 'info-symbolic',
|
||||
link: 'external-link-symbolic',
|
||||
lock: 'system-lock-screen-symbolic',
|
||||
menu: 'open-menu-symbolic',
|
||||
refresh: 'view-refresh-symbolic',
|
||||
search: 'system-search-symbolic',
|
||||
settings: 'emblem-system-symbolic',
|
||||
themes: 'preferences-desktop-theme-symbolic',
|
||||
tick: 'object-select-symbolic',
|
||||
time: 'hourglass-symbolic',
|
||||
toolbars: 'toolbars-symbolic',
|
||||
warning: 'dialog-warning-symbolic',
|
||||
avatar: 'avatar-default-symbolic',
|
||||
arrow: {
|
||||
right: "pan-end-symbolic",
|
||||
left: "pan-start-symbolic",
|
||||
down: "pan-down-symbolic",
|
||||
up: "pan-up-symbolic",
|
||||
right: 'pan-end-symbolic',
|
||||
left: 'pan-start-symbolic',
|
||||
down: 'pan-down-symbolic',
|
||||
up: 'pan-up-symbolic',
|
||||
},
|
||||
},
|
||||
audio: {
|
||||
mic: {
|
||||
muted: "microphone-disabled-symbolic",
|
||||
low: "microphone-sensitivity-low-symbolic",
|
||||
medium: "microphone-sensitivity-medium-symbolic",
|
||||
high: "microphone-sensitivity-high-symbolic",
|
||||
muted: 'microphone-disabled-symbolic',
|
||||
low: 'microphone-sensitivity-low-symbolic',
|
||||
medium: 'microphone-sensitivity-medium-symbolic',
|
||||
high: 'microphone-sensitivity-high-symbolic',
|
||||
},
|
||||
volume: {
|
||||
muted: "audio-volume-muted-symbolic",
|
||||
low: "audio-volume-low-symbolic",
|
||||
medium: "audio-volume-medium-symbolic",
|
||||
high: "audio-volume-high-symbolic",
|
||||
overamplified: "audio-volume-overamplified-symbolic",
|
||||
muted: 'audio-volume-muted-symbolic',
|
||||
low: 'audio-volume-low-symbolic',
|
||||
medium: 'audio-volume-medium-symbolic',
|
||||
high: 'audio-volume-high-symbolic',
|
||||
overamplified: 'audio-volume-overamplified-symbolic',
|
||||
},
|
||||
type: {
|
||||
headset: "audio-headphones-symbolic",
|
||||
speaker: "audio-speakers-symbolic",
|
||||
card: "audio-card-symbolic",
|
||||
headset: 'audio-headphones-symbolic',
|
||||
speaker: 'audio-speakers-symbolic',
|
||||
card: 'audio-card-symbolic',
|
||||
},
|
||||
mixer: "mixer-symbolic",
|
||||
mixer: 'mixer-symbolic',
|
||||
},
|
||||
powerprofile: {
|
||||
balanced: "power-profile-balanced-symbolic",
|
||||
"power-saver": "power-profile-power-saver-symbolic",
|
||||
performance: "power-profile-performance-symbolic",
|
||||
balanced: 'power-profile-balanced-symbolic',
|
||||
'power-saver': 'power-profile-power-saver-symbolic',
|
||||
performance: 'power-profile-performance-symbolic',
|
||||
},
|
||||
asusctl: {
|
||||
profile: {
|
||||
Balanced: "power-profile-balanced-symbolic",
|
||||
Quiet: "power-profile-power-saver-symbolic",
|
||||
Performance: "power-profile-performance-symbolic",
|
||||
Balanced: 'power-profile-balanced-symbolic',
|
||||
Quiet: 'power-profile-power-saver-symbolic',
|
||||
Performance: 'power-profile-performance-symbolic',
|
||||
},
|
||||
mode: {
|
||||
Integrated: "processor-symbolic",
|
||||
Hybrid: "controller-symbolic",
|
||||
Integrated: 'processor-symbolic',
|
||||
Hybrid: 'controller-symbolic',
|
||||
},
|
||||
},
|
||||
battery: {
|
||||
charging: "battery-flash-symbolic",
|
||||
warning: "battery-empty-symbolic",
|
||||
charging: 'battery-flash-symbolic',
|
||||
warning: 'battery-empty-symbolic',
|
||||
},
|
||||
bluetooth: {
|
||||
enabled: "bluetooth-active-symbolic",
|
||||
disabled: "bluetooth-disabled-symbolic",
|
||||
enabled: 'bluetooth-active-symbolic',
|
||||
disabled: 'bluetooth-disabled-symbolic',
|
||||
},
|
||||
brightness: {
|
||||
indicator: "display-brightness-symbolic",
|
||||
keyboard: "keyboard-brightness-symbolic",
|
||||
screen: "display-brightness-symbolic",
|
||||
indicator: 'display-brightness-symbolic',
|
||||
keyboard: 'keyboard-brightness-symbolic',
|
||||
screen: 'display-brightness-symbolic',
|
||||
},
|
||||
powermenu: {
|
||||
sleep: "weather-clear-night-symbolic",
|
||||
reboot: "system-reboot-symbolic",
|
||||
logout: "system-log-out-symbolic",
|
||||
shutdown: "system-shutdown-symbolic",
|
||||
sleep: 'weather-clear-night-symbolic',
|
||||
reboot: 'system-reboot-symbolic',
|
||||
logout: 'system-log-out-symbolic',
|
||||
shutdown: 'system-shutdown-symbolic',
|
||||
},
|
||||
recorder: {
|
||||
recording: "media-record-symbolic",
|
||||
recording: 'media-record-symbolic',
|
||||
},
|
||||
notifications: {
|
||||
noisy: "org.gnome.Settings-notifications-symbolic",
|
||||
silent: "notifications-disabled-symbolic",
|
||||
message: "chat-bubbles-symbolic",
|
||||
noisy: 'org.gnome.Settings-notifications-symbolic',
|
||||
silent: 'notifications-disabled-symbolic',
|
||||
message: 'chat-bubbles-symbolic',
|
||||
},
|
||||
trash: {
|
||||
full: "user-trash-full-symbolic",
|
||||
empty: "user-trash-symbolic",
|
||||
full: 'user-trash-full-symbolic',
|
||||
empty: 'user-trash-symbolic',
|
||||
},
|
||||
mpris: {
|
||||
shuffle: {
|
||||
enabled: "media-playlist-shuffle-symbolic",
|
||||
disabled: "media-playlist-consecutive-symbolic",
|
||||
enabled: 'media-playlist-shuffle-symbolic',
|
||||
disabled: 'media-playlist-consecutive-symbolic',
|
||||
},
|
||||
loop: {
|
||||
none: "media-playlist-repeat-symbolic",
|
||||
track: "media-playlist-repeat-song-symbolic",
|
||||
playlist: "media-playlist-repeat-symbolic",
|
||||
none: 'media-playlist-repeat-symbolic',
|
||||
track: 'media-playlist-repeat-song-symbolic',
|
||||
playlist: 'media-playlist-repeat-symbolic',
|
||||
},
|
||||
playing: "media-playback-pause-symbolic",
|
||||
paused: "media-playback-start-symbolic",
|
||||
stopped: "media-playback-start-symbolic",
|
||||
prev: "media-skip-backward-symbolic",
|
||||
next: "media-skip-forward-symbolic",
|
||||
playing: 'media-playback-pause-symbolic',
|
||||
paused: 'media-playback-start-symbolic',
|
||||
stopped: 'media-playback-start-symbolic',
|
||||
prev: 'media-skip-backward-symbolic',
|
||||
next: 'media-skip-forward-symbolic',
|
||||
},
|
||||
system: {
|
||||
cpu: "org.gnome.SystemMonitor-symbolic",
|
||||
ram: "drive-harddisk-solidstate-symbolic",
|
||||
temp: "temperature-symbolic",
|
||||
cpu: 'org.gnome.SystemMonitor-symbolic',
|
||||
ram: 'drive-harddisk-solidstate-symbolic',
|
||||
temp: 'temperature-symbolic',
|
||||
},
|
||||
color: {
|
||||
dark: "dark-mode-symbolic",
|
||||
light: "light-mode-symbolic",
|
||||
dark: 'dark-mode-symbolic',
|
||||
light: 'light-mode-symbolic',
|
||||
},
|
||||
weather: {
|
||||
warning: "dialog-warning-symbolic",
|
||||
sunny: "weather-clear-symbolic",
|
||||
clear: "weather-clear-night-symbolic",
|
||||
partly_cloudy: "weather-few-clouds-symbolic",
|
||||
partly_cloudy_night: "weather-few-clouds-night-symbolic",
|
||||
cloudy: "weather-overcast-symbolic",
|
||||
overcast: "weather-overcast-symbolic",
|
||||
mist: "weather-overcast-symbolic",
|
||||
patchy_rain_nearby: "weather-showers-scattered-symbolic",
|
||||
patchy_rain_possible: "weather-showers-scattered-symbolic",
|
||||
patchy_snow_possible: "weather-snow-symbolic",
|
||||
patchy_sleet_possible: "weather-snow-symbolic",
|
||||
patchy_freezing_drizzle_possible: "weather-showers-scattered-symbolic",
|
||||
thundery_outbreaks_possible: "weather-overcast-symbolic",
|
||||
blowing_snow: "weather-snow-symbolic",
|
||||
blizzard: "weather-snow-symbolic",
|
||||
fog: "weather-fog-symbolic",
|
||||
freezing_fog: "weather-fog-symbolic",
|
||||
patchy_light_drizzle: "weather-showers-scattered-symbolic",
|
||||
light_drizzle: "weather-showers-symbolic",
|
||||
freezing_drizzle: "weather-showers-symbolic",
|
||||
heavy_freezing_drizzle: "weather-showers-symbolic",
|
||||
patchy_light_rain: "weather-showers-scattered-symbolic",
|
||||
light_rain: "weather-showers-symbolic",
|
||||
moderate_rain_at_times: "weather-showers-symbolic",
|
||||
moderate_rain: "weather-showers-symbolic",
|
||||
heavy_rain_at_times: "weather-showers-symbolic",
|
||||
heavy_rain: "weather-showers-symbolic",
|
||||
light_freezing_rain: "weather-showers-symbolic",
|
||||
moderate_or_heavy_freezing_rain: "weather-showers-symbolic",
|
||||
light_sleet: "weather-snow-symbolic",
|
||||
moderate_or_heavy_sleet: "weather-snow-symbolic",
|
||||
patchy_light_snow: "weather-snow-symbolic",
|
||||
light_snow: "weather-snow-symbolic",
|
||||
patchy_moderate_snow: "weather-snow-symbolic",
|
||||
moderate_snow: "weather-snow-symbolic",
|
||||
patchy_heavy_snow: "weather-snow-symbolic",
|
||||
heavy_snow: "weather-snow-symbolic",
|
||||
ice_pellets: "weather-showers-symbolic",
|
||||
light_rain_shower: "weather-showers-symbolic",
|
||||
moderate_or_heavy_rain_shower: "weather-showers-symbolic",
|
||||
torrential_rain_shower: "weather-showers-symbolic",
|
||||
light_sleet_showers: "weather-showers-symbolic",
|
||||
moderate_or_heavy_sleet_showers: "weather-showers-symbolic",
|
||||
light_snow_showers: "weather-snow-symbolic",
|
||||
moderate_or_heavy_snow_showers: "weather-snow-symbolic",
|
||||
light_showers_of_ice_pellets: "weather-showers-symbolic",
|
||||
moderate_or_heavy_showers_of_ice_pellets: "weather-showers-symbolic",
|
||||
patchy_light_rain_with_thunder: "weather-showers-scattered-symbolic",
|
||||
moderate_or_heavy_rain_with_thunder: "weather-showers-symbolic",
|
||||
patchy_light_snow_with_thunder: "weather-snow-symbolic",
|
||||
moderate_or_heavy_snow_with_thunder: "weather-snow-symbolic",
|
||||
warning: 'dialog-warning-symbolic',
|
||||
sunny: 'weather-clear-symbolic',
|
||||
clear: 'weather-clear-night-symbolic',
|
||||
partly_cloudy: 'weather-few-clouds-symbolic',
|
||||
partly_cloudy_night: 'weather-few-clouds-night-symbolic',
|
||||
cloudy: 'weather-overcast-symbolic',
|
||||
overcast: 'weather-overcast-symbolic',
|
||||
mist: 'weather-overcast-symbolic',
|
||||
patchy_rain_nearby: 'weather-showers-scattered-symbolic',
|
||||
patchy_rain_possible: 'weather-showers-scattered-symbolic',
|
||||
patchy_snow_possible: 'weather-snow-symbolic',
|
||||
patchy_sleet_possible: 'weather-snow-symbolic',
|
||||
patchy_freezing_drizzle_possible: 'weather-showers-scattered-symbolic',
|
||||
thundery_outbreaks_possible: 'weather-overcast-symbolic',
|
||||
blowing_snow: 'weather-snow-symbolic',
|
||||
blizzard: 'weather-snow-symbolic',
|
||||
fog: 'weather-fog-symbolic',
|
||||
freezing_fog: 'weather-fog-symbolic',
|
||||
patchy_light_drizzle: 'weather-showers-scattered-symbolic',
|
||||
light_drizzle: 'weather-showers-symbolic',
|
||||
freezing_drizzle: 'weather-showers-symbolic',
|
||||
heavy_freezing_drizzle: 'weather-showers-symbolic',
|
||||
patchy_light_rain: 'weather-showers-scattered-symbolic',
|
||||
light_rain: 'weather-showers-symbolic',
|
||||
moderate_rain_at_times: 'weather-showers-symbolic',
|
||||
moderate_rain: 'weather-showers-symbolic',
|
||||
heavy_rain_at_times: 'weather-showers-symbolic',
|
||||
heavy_rain: 'weather-showers-symbolic',
|
||||
light_freezing_rain: 'weather-showers-symbolic',
|
||||
moderate_or_heavy_freezing_rain: 'weather-showers-symbolic',
|
||||
light_sleet: 'weather-snow-symbolic',
|
||||
moderate_or_heavy_sleet: 'weather-snow-symbolic',
|
||||
patchy_light_snow: 'weather-snow-symbolic',
|
||||
light_snow: 'weather-snow-symbolic',
|
||||
patchy_moderate_snow: 'weather-snow-symbolic',
|
||||
moderate_snow: 'weather-snow-symbolic',
|
||||
patchy_heavy_snow: 'weather-snow-symbolic',
|
||||
heavy_snow: 'weather-snow-symbolic',
|
||||
ice_pellets: 'weather-showers-symbolic',
|
||||
light_rain_shower: 'weather-showers-symbolic',
|
||||
moderate_or_heavy_rain_shower: 'weather-showers-symbolic',
|
||||
torrential_rain_shower: 'weather-showers-symbolic',
|
||||
light_sleet_showers: 'weather-showers-symbolic',
|
||||
moderate_or_heavy_sleet_showers: 'weather-showers-symbolic',
|
||||
light_snow_showers: 'weather-snow-symbolic',
|
||||
moderate_or_heavy_snow_showers: 'weather-snow-symbolic',
|
||||
light_showers_of_ice_pellets: 'weather-showers-symbolic',
|
||||
moderate_or_heavy_showers_of_ice_pellets: 'weather-showers-symbolic',
|
||||
patchy_light_rain_with_thunder: 'weather-showers-scattered-symbolic',
|
||||
moderate_or_heavy_rain_with_thunder: 'weather-showers-symbolic',
|
||||
patchy_light_snow_with_thunder: 'weather-snow-symbolic',
|
||||
moderate_or_heavy_snow_with_thunder: 'weather-snow-symbolic',
|
||||
},
|
||||
} as const;
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
export const weatherIcons = {
|
||||
warning: "",
|
||||
sunny: "",
|
||||
clear: "",
|
||||
partly_cloudy: "",
|
||||
partly_cloudy_night: "",
|
||||
cloudy: "",
|
||||
overcast: "",
|
||||
mist: "",
|
||||
patchy_rain_nearby: "",
|
||||
patchy_rain_possible: "",
|
||||
patchy_snow_possible: "",
|
||||
patchy_sleet_possible: "",
|
||||
patchy_freezing_drizzle_possible: "",
|
||||
thundery_outbreaks_possible: "",
|
||||
blowing_snow: "",
|
||||
blizzard: "",
|
||||
fog: "",
|
||||
freezing_fog: "",
|
||||
patchy_light_drizzle: "",
|
||||
light_drizzle: "",
|
||||
freezing_drizzle: "",
|
||||
heavy_freezing_drizzle: "",
|
||||
patchy_light_rain: "",
|
||||
light_rain: "",
|
||||
moderate_rain_at_times: "",
|
||||
moderate_rain: "",
|
||||
heavy_rain_at_times: "",
|
||||
heavy_rain: "",
|
||||
light_freezing_rain: "",
|
||||
moderate_or_heavy_freezing_rain: "",
|
||||
light_sleet: "",
|
||||
moderate_or_heavy_sleet: "",
|
||||
patchy_light_snow: "",
|
||||
light_snow: "",
|
||||
patchy_moderate_snow: "",
|
||||
moderate_snow: "",
|
||||
patchy_heavy_snow: "",
|
||||
heavy_snow: "",
|
||||
ice_pellets: "",
|
||||
light_rain_shower: "",
|
||||
moderate_or_heavy_rain_shower: "",
|
||||
torrential_rain_shower: "",
|
||||
light_sleet_showers: "",
|
||||
moderate_or_heavy_sleet_showers: "",
|
||||
light_snow_showers: "",
|
||||
moderate_or_heavy_snow_showers: "",
|
||||
light_showers_of_ice_pellets: "",
|
||||
moderate_or_heavy_showers_of_ice_pellets: "",
|
||||
patchy_light_rain_with_thunder: "",
|
||||
moderate_or_heavy_rain_with_thunder: "",
|
||||
patchy_light_snow_with_thunder: "",
|
||||
moderate_or_heavy_snow_with_thunder: "",
|
||||
warning: '',
|
||||
sunny: '',
|
||||
clear: '',
|
||||
partly_cloudy: '',
|
||||
partly_cloudy_night: '',
|
||||
cloudy: '',
|
||||
overcast: '',
|
||||
mist: '',
|
||||
patchy_rain_nearby: '',
|
||||
patchy_rain_possible: '',
|
||||
patchy_snow_possible: '',
|
||||
patchy_sleet_possible: '',
|
||||
patchy_freezing_drizzle_possible: '',
|
||||
thundery_outbreaks_possible: '',
|
||||
blowing_snow: '',
|
||||
blizzard: '',
|
||||
fog: '',
|
||||
freezing_fog: '',
|
||||
patchy_light_drizzle: '',
|
||||
light_drizzle: '',
|
||||
freezing_drizzle: '',
|
||||
heavy_freezing_drizzle: '',
|
||||
patchy_light_rain: '',
|
||||
light_rain: '',
|
||||
moderate_rain_at_times: '',
|
||||
moderate_rain: '',
|
||||
heavy_rain_at_times: '',
|
||||
heavy_rain: '',
|
||||
light_freezing_rain: '',
|
||||
moderate_or_heavy_freezing_rain: '',
|
||||
light_sleet: '',
|
||||
moderate_or_heavy_sleet: '',
|
||||
patchy_light_snow: '',
|
||||
light_snow: '',
|
||||
patchy_moderate_snow: '',
|
||||
moderate_snow: '',
|
||||
patchy_heavy_snow: '',
|
||||
heavy_snow: '',
|
||||
ice_pellets: '',
|
||||
light_rain_shower: '',
|
||||
moderate_or_heavy_rain_shower: '',
|
||||
torrential_rain_shower: '',
|
||||
light_sleet_showers: '',
|
||||
moderate_or_heavy_sleet_showers: '',
|
||||
light_snow_showers: '',
|
||||
moderate_or_heavy_snow_showers: '',
|
||||
light_showers_of_ice_pellets: '',
|
||||
moderate_or_heavy_showers_of_ice_pellets: '',
|
||||
patchy_light_rain_with_thunder: '',
|
||||
moderate_or_heavy_rain_with_thunder: '',
|
||||
patchy_light_snow_with_thunder: '',
|
||||
moderate_or_heavy_snow_with_thunder: '',
|
||||
} as const;
|
||||
|
||||
@@ -1,25 +1,34 @@
|
||||
const hyprland = await Service.import("hyprland");
|
||||
import { DropdownMenuProps } from "lib/types/dropdownmenu";
|
||||
import { Exclusivity } from "lib/types/widget";
|
||||
import { bash } from "lib/utils";
|
||||
import { Monitor } from "types/service/hyprland";
|
||||
const hyprland = await Service.import('hyprland');
|
||||
import { DropdownMenuProps } from 'lib/types/dropdownmenu';
|
||||
import { Attribute, Child, Exclusivity, GtkWidget } from 'lib/types/widget';
|
||||
import { bash } from 'lib/utils';
|
||||
import { Widget as TWidget } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
||||
import { Monitor } from 'types/service/hyprland';
|
||||
import Box from 'types/widgets/box';
|
||||
import EventBox from 'types/widgets/eventbox';
|
||||
import Revealer from 'types/widgets/revealer';
|
||||
import Window from 'types/widgets/window';
|
||||
|
||||
export const Padding = (name: string) =>
|
||||
type NestedRevealer = Revealer<Box<TWidget, unknown>, unknown>;
|
||||
type NestedBox = Box<NestedRevealer, unknown>;
|
||||
type NestedEventBox = EventBox<NestedBox, unknown>;
|
||||
|
||||
export const Padding = (name: string): EventBox<Box<GtkWidget, Attribute>, Attribute> =>
|
||||
Widget.EventBox({
|
||||
hexpand: true,
|
||||
vexpand: true,
|
||||
can_focus: true,
|
||||
child: Widget.Box(),
|
||||
setup: (w) => w.on("button-press-event", () => App.toggleWindow(name)),
|
||||
setup: (w) => w.on('button-press-event', () => App.toggleWindow(name)),
|
||||
});
|
||||
|
||||
const moveBoxToCursor = (self: any, fixed: boolean) => {
|
||||
const moveBoxToCursor = <T extends NestedEventBox>(self: T, fixed: boolean): void => {
|
||||
if (fixed) {
|
||||
return;
|
||||
}
|
||||
|
||||
globalMousePos.connect("changed", async ({ value }) => {
|
||||
const curHyprlandMonitor = hyprland.monitors.find(m => m.id === hyprland.active.monitor.id);
|
||||
globalMousePos.connect('changed', async ({ value }) => {
|
||||
const curHyprlandMonitor = hyprland.monitors.find((m) => m.id === hyprland.active.monitor.id);
|
||||
const dropdownWidth = self.child.get_allocation().width;
|
||||
|
||||
let hyprScaling = 1;
|
||||
@@ -27,8 +36,8 @@ const moveBoxToCursor = (self: any, fixed: boolean) => {
|
||||
const monitorInfo = await bash('hyprctl monitors -j');
|
||||
const parsedMonitorInfo = JSON.parse(monitorInfo);
|
||||
|
||||
const foundMonitor = parsedMonitorInfo.find((monitor: Monitor) =>
|
||||
monitor.id === hyprland.active.monitor.id
|
||||
const foundMonitor = parsedMonitorInfo.find(
|
||||
(monitor: Monitor) => monitor.id === hyprland.active.monitor.id,
|
||||
);
|
||||
hyprScaling = foundMonitor?.scale || 1;
|
||||
} catch (error) {
|
||||
@@ -58,9 +67,7 @@ const moveBoxToCursor = (self: any, fixed: boolean) => {
|
||||
}
|
||||
|
||||
// If monitor is vertical (transform = 1 || 3) swap height and width
|
||||
const isVertical = curHyprlandMonitor?.transform !== undefined
|
||||
? curHyprlandMonitor.transform % 2 !== 0
|
||||
: false;
|
||||
const isVertical = curHyprlandMonitor?.transform !== undefined ? curHyprlandMonitor.transform % 2 !== 0 : false;
|
||||
|
||||
if (isVertical) {
|
||||
[monWidth, monHeight] = [monHeight, monWidth];
|
||||
@@ -100,58 +107,55 @@ setTimeout(() => {
|
||||
initRender.value = false;
|
||||
}, 2000);
|
||||
|
||||
export default (
|
||||
{
|
||||
name,
|
||||
child,
|
||||
layout = "center",
|
||||
transition,
|
||||
exclusivity = "ignore" as Exclusivity,
|
||||
fixed = false,
|
||||
...props
|
||||
}: DropdownMenuProps
|
||||
) =>
|
||||
export default ({
|
||||
name,
|
||||
child,
|
||||
transition,
|
||||
exclusivity = 'ignore' as Exclusivity,
|
||||
fixed = false,
|
||||
...props
|
||||
}: DropdownMenuProps): Window<Child, Attribute> =>
|
||||
Widget.Window({
|
||||
name,
|
||||
class_names: [name, "dropdown-menu"],
|
||||
setup: (w) => w.keybind("Escape", () => App.closeWindow(name)),
|
||||
visible: initRender.bind("value"),
|
||||
keymode: "on-demand",
|
||||
class_names: [name, 'dropdown-menu'],
|
||||
setup: (w) => w.keybind('Escape', () => App.closeWindow(name)),
|
||||
visible: initRender.bind('value'),
|
||||
keymode: 'on-demand',
|
||||
exclusivity,
|
||||
layer: "top",
|
||||
anchor: ["top", "left"],
|
||||
layer: 'top',
|
||||
anchor: ['top', 'left'],
|
||||
child: Widget.EventBox({
|
||||
class_name: "parent-event",
|
||||
class_name: 'parent-event',
|
||||
on_primary_click: () => App.closeWindow(name),
|
||||
on_secondary_click: () => App.closeWindow(name),
|
||||
child: Widget.Box({
|
||||
class_name: "top-eb",
|
||||
class_name: 'top-eb',
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.EventBox({
|
||||
class_name: "mid-eb event-top-padding-static",
|
||||
class_name: 'mid-eb event-top-padding-static',
|
||||
hexpand: true,
|
||||
vexpand: false,
|
||||
can_focus: false,
|
||||
child: Widget.Box(),
|
||||
setup: (w) => {
|
||||
w.on("button-press-event", () => App.toggleWindow(name));
|
||||
w.on('button-press-event', () => App.toggleWindow(name));
|
||||
w.set_margin_top(1);
|
||||
},
|
||||
}),
|
||||
Widget.EventBox({
|
||||
class_name: "mid-eb event-top-padding",
|
||||
class_name: 'mid-eb event-top-padding',
|
||||
hexpand: true,
|
||||
vexpand: false,
|
||||
can_focus: false,
|
||||
child: Widget.Box(),
|
||||
setup: (w) => {
|
||||
w.on("button-press-event", () => App.toggleWindow(name));
|
||||
w.on('button-press-event', () => App.toggleWindow(name));
|
||||
w.set_margin_top(1);
|
||||
},
|
||||
}),
|
||||
Widget.EventBox({
|
||||
class_name: "in-eb menu-event-box",
|
||||
class_name: 'in-eb menu-event-box',
|
||||
on_primary_click: () => {
|
||||
return true;
|
||||
},
|
||||
@@ -162,18 +166,18 @@ export default (
|
||||
moveBoxToCursor(self, fixed);
|
||||
},
|
||||
child: Widget.Box({
|
||||
class_name: "dropdown-menu-container",
|
||||
css: "padding: 1px; margin: -1px;",
|
||||
class_name: 'dropdown-menu-container',
|
||||
css: 'padding: 1px; margin: -1px;',
|
||||
child: Widget.Revealer({
|
||||
revealChild: false,
|
||||
setup: (self) =>
|
||||
self.hook(App, (_, wname, visible) => {
|
||||
if (wname === name) self.reveal_child = visible;
|
||||
}),
|
||||
transition: "crossfade",
|
||||
transition,
|
||||
transitionDuration: 350,
|
||||
child: Widget.Box({
|
||||
class_name: "dropdown-menu-container",
|
||||
class_name: 'dropdown-menu-container',
|
||||
can_focus: true,
|
||||
children: [child],
|
||||
}),
|
||||
|
||||
@@ -1,25 +1,32 @@
|
||||
import { WINDOW_LAYOUTS } from "globals/window";
|
||||
import { LayoutFunction, Layouts, PopupWindowProps } from "lib/types/popupwindow";
|
||||
import { Exclusivity, Transition } from "lib/types/widget";
|
||||
import { WINDOW_LAYOUTS } from 'globals/window';
|
||||
import { LayoutFunction, Layouts, PopupWindowProps } from 'lib/types/popupwindow';
|
||||
import { Attribute, Child, Exclusivity, GtkWidget, Transition } from 'lib/types/widget';
|
||||
import Box from 'types/widgets/box';
|
||||
import EventBox from 'types/widgets/eventbox';
|
||||
import Window from 'types/widgets/window';
|
||||
|
||||
type Opts = {
|
||||
className: string
|
||||
vexpand: boolean
|
||||
}
|
||||
className: string;
|
||||
vexpand: boolean;
|
||||
};
|
||||
|
||||
export const Padding = (name: string, opts: Opts) =>
|
||||
export const Padding = (name: string, opts: Opts): EventBox<Box<GtkWidget, Attribute>, unknown> =>
|
||||
Widget.EventBox({
|
||||
class_name: opts?.className || "",
|
||||
class_name: opts?.className || '',
|
||||
hexpand: true,
|
||||
vexpand: typeof opts?.vexpand === "boolean" ? opts.vexpand : true,
|
||||
vexpand: typeof opts?.vexpand === 'boolean' ? opts.vexpand : true,
|
||||
can_focus: false,
|
||||
child: Widget.Box(),
|
||||
setup: (w) => w.on("button-press-event", () => App.toggleWindow(name)),
|
||||
setup: (w) => w.on('button-press-event', () => App.toggleWindow(name)),
|
||||
});
|
||||
|
||||
const PopupRevealer = (name: string, child: any, transition = "slide_down" as Transition) =>
|
||||
const PopupRevealer = (
|
||||
name: string,
|
||||
child: GtkWidget,
|
||||
transition = 'slide_down' as Transition,
|
||||
): Box<Child, Attribute> =>
|
||||
Widget.Box(
|
||||
{ css: "padding: 1px;" },
|
||||
{ css: 'padding: 1px;' },
|
||||
Widget.Revealer({
|
||||
transition,
|
||||
child: Widget.Box({
|
||||
@@ -34,7 +41,7 @@ const PopupRevealer = (name: string, child: any, transition = "slide_down" as Tr
|
||||
}),
|
||||
);
|
||||
|
||||
const Layout: LayoutFunction = (name: string, child: any, transition: Transition) => ({
|
||||
const Layout: LayoutFunction = (name: string, child: GtkWidget, transition: Transition) => ({
|
||||
center: () =>
|
||||
Widget.CenterBox(
|
||||
{},
|
||||
@@ -51,14 +58,10 @@ const Layout: LayoutFunction = (name: string, child: any, transition: Transition
|
||||
Widget.CenterBox(
|
||||
{},
|
||||
Padding(name, {} as Opts),
|
||||
Widget.Box(
|
||||
{ vertical: true },
|
||||
PopupRevealer(name, child, transition),
|
||||
Padding(name, {} as Opts),
|
||||
),
|
||||
Widget.Box({ vertical: true }, PopupRevealer(name, child, transition), Padding(name, {} as Opts)),
|
||||
Padding(name, {} as Opts),
|
||||
),
|
||||
"top-right": () =>
|
||||
'top-right': () =>
|
||||
Widget.Box(
|
||||
{},
|
||||
Padding(name, {} as Opts),
|
||||
@@ -69,13 +72,13 @@ const Layout: LayoutFunction = (name: string, child: any, transition: Transition
|
||||
},
|
||||
Padding(name, {
|
||||
vexpand: false,
|
||||
className: "event-top-padding",
|
||||
className: 'event-top-padding',
|
||||
}),
|
||||
PopupRevealer(name, child, transition),
|
||||
Padding(name, {} as Opts),
|
||||
),
|
||||
),
|
||||
"top-center": () =>
|
||||
'top-center': () =>
|
||||
Widget.Box(
|
||||
{},
|
||||
Padding(name, {} as Opts),
|
||||
@@ -86,14 +89,14 @@ const Layout: LayoutFunction = (name: string, child: any, transition: Transition
|
||||
},
|
||||
Padding(name, {
|
||||
vexpand: false,
|
||||
className: "event-top-padding",
|
||||
className: 'event-top-padding',
|
||||
}),
|
||||
PopupRevealer(name, child, transition),
|
||||
Padding(name, {} as Opts),
|
||||
),
|
||||
Padding(name, {} as Opts),
|
||||
),
|
||||
"top-left": () =>
|
||||
'top-left': () =>
|
||||
Widget.Box(
|
||||
{},
|
||||
Widget.Box(
|
||||
@@ -103,14 +106,14 @@ const Layout: LayoutFunction = (name: string, child: any, transition: Transition
|
||||
},
|
||||
Padding(name, {
|
||||
vexpand: false,
|
||||
className: "event-top-padding",
|
||||
className: 'event-top-padding',
|
||||
}),
|
||||
PopupRevealer(name, child, transition),
|
||||
Padding(name, {} as Opts),
|
||||
),
|
||||
Padding(name, {} as Opts),
|
||||
),
|
||||
"bottom-left": () =>
|
||||
'bottom-left': () =>
|
||||
Widget.Box(
|
||||
{},
|
||||
Widget.Box(
|
||||
@@ -123,7 +126,7 @@ const Layout: LayoutFunction = (name: string, child: any, transition: Transition
|
||||
),
|
||||
Padding(name, {} as Opts),
|
||||
),
|
||||
"bottom-center": () =>
|
||||
'bottom-center': () =>
|
||||
Widget.Box(
|
||||
{},
|
||||
Padding(name, {} as Opts),
|
||||
@@ -137,7 +140,7 @@ const Layout: LayoutFunction = (name: string, child: any, transition: Transition
|
||||
),
|
||||
Padding(name, {} as Opts),
|
||||
),
|
||||
"bottom-right": () =>
|
||||
'bottom-right': () =>
|
||||
Widget.Box(
|
||||
{},
|
||||
Padding(name, {} as Opts),
|
||||
@@ -159,25 +162,25 @@ const isValidLayout = (layout: string): layout is Layouts => {
|
||||
export default ({
|
||||
name,
|
||||
child,
|
||||
layout = "center",
|
||||
layout = 'center',
|
||||
transition,
|
||||
exclusivity = "ignore" as Exclusivity,
|
||||
exclusivity = 'ignore' as Exclusivity,
|
||||
...props
|
||||
}: PopupWindowProps) => {
|
||||
const layoutFn = isValidLayout(layout) ? layout : "center";
|
||||
}: PopupWindowProps): Window<Child, Attribute> => {
|
||||
const layoutFn = isValidLayout(layout) ? layout : 'center';
|
||||
|
||||
const layoutWidget = Layout(name, child, transition)[layoutFn]();
|
||||
|
||||
return Widget.Window({
|
||||
name,
|
||||
class_names: [name, "popup-window"],
|
||||
setup: (w) => w.keybind("Escape", () => App.closeWindow(name)),
|
||||
class_names: [name, 'popup-window'],
|
||||
setup: (w) => w.keybind('Escape', () => App.closeWindow(name)),
|
||||
visible: false,
|
||||
keymode: "on-demand",
|
||||
keymode: 'on-demand',
|
||||
exclusivity,
|
||||
layer: "top",
|
||||
anchor: ["top", "bottom", "right", "left"],
|
||||
layer: 'top',
|
||||
anchor: ['top', 'bottom', 'right', 'left'],
|
||||
child: layoutWidget,
|
||||
...props,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,31 +1,36 @@
|
||||
const audio = await Service.import("audio");
|
||||
const audio = await Service.import('audio');
|
||||
import { BarBoxChild } from 'lib/types/bar.js';
|
||||
import { getIcon } from '../utils.js';
|
||||
|
||||
const renderActiveInput = () => {
|
||||
const renderActiveInput = (): BarBoxChild => {
|
||||
return [
|
||||
Widget.Box({
|
||||
class_name: "menu-slider-container input",
|
||||
class_name: 'menu-slider-container input',
|
||||
children: [
|
||||
Widget.Button({
|
||||
vexpand: false,
|
||||
vpack: "end",
|
||||
vpack: 'end',
|
||||
setup: (self) => {
|
||||
self.hook(audio, () => {
|
||||
const mic = audio.microphone;
|
||||
const className = `menu-active-button input ${mic.is_muted ? "muted" : ""}`;
|
||||
const className = `menu-active-button input ${mic.is_muted ? 'muted' : ''}`;
|
||||
return (self.class_name = className);
|
||||
});
|
||||
},
|
||||
on_primary_click: () =>
|
||||
(audio.microphone.is_muted = !audio.microphone.is_muted),
|
||||
on_primary_click: () => (audio.microphone.is_muted = !audio.microphone.is_muted),
|
||||
child: Widget.Icon({
|
||||
class_name: "menu-active-icon input",
|
||||
class_name: 'menu-active-icon input',
|
||||
setup: (self) => {
|
||||
self.hook(audio, () => {
|
||||
self.icon = getIcon(
|
||||
audio.microphone.volume,
|
||||
audio.microphone.is_muted,
|
||||
)["mic"];
|
||||
const isMicMuted =
|
||||
audio.microphone.is_muted !== null ? audio.microphone.is_muted : true;
|
||||
|
||||
if (audio.microphone.volume > 0) {
|
||||
self.icon = getIcon(audio.microphone.volume, isMicMuted)['mic'];
|
||||
return;
|
||||
}
|
||||
|
||||
self.icon = getIcon(100, false)['mic'];
|
||||
});
|
||||
},
|
||||
}),
|
||||
@@ -34,15 +39,17 @@ const renderActiveInput = () => {
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "menu-active input",
|
||||
hpack: "start",
|
||||
truncate: "end",
|
||||
class_name: 'menu-active input',
|
||||
hpack: 'start',
|
||||
truncate: 'end',
|
||||
wrap: true,
|
||||
label: audio.bind("microphone").as((v) => v.description === null ? "No input device found..." : v.description),
|
||||
label: audio
|
||||
.bind('microphone')
|
||||
.as((v) => (v.description === null ? 'No input device found...' : v.description)),
|
||||
}),
|
||||
Widget.Slider({
|
||||
value: audio.microphone.bind("volume").as((v) => v),
|
||||
class_name: "menu-active-slider menu-slider inputs",
|
||||
value: audio.microphone.bind('volume').as((v) => v),
|
||||
class_name: 'menu-active-slider menu-slider inputs',
|
||||
draw_value: false,
|
||||
hexpand: true,
|
||||
min: 0,
|
||||
@@ -52,11 +59,9 @@ const renderActiveInput = () => {
|
||||
],
|
||||
}),
|
||||
Widget.Label({
|
||||
class_name: "menu-active-percentage input",
|
||||
vpack: "end",
|
||||
label: audio.microphone
|
||||
.bind("volume")
|
||||
.as((v) => `${Math.round(v * 100)}%`),
|
||||
class_name: 'menu-active-percentage input',
|
||||
vpack: 'end',
|
||||
label: audio.microphone.bind('volume').as((v) => `${Math.round(v * 100)}%`),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
const audio = await Service.import("audio");
|
||||
import { getIcon } from "../utils.js";
|
||||
const audio = await Service.import('audio');
|
||||
import { BarBoxChild } from 'lib/types/bar.js';
|
||||
import { getIcon } from '../utils.js';
|
||||
|
||||
const renderActivePlayback = () => {
|
||||
const renderActivePlayback = (): BarBoxChild => {
|
||||
return [
|
||||
Widget.Box({
|
||||
class_name: "menu-slider-container playback",
|
||||
class_name: 'menu-slider-container playback',
|
||||
children: [
|
||||
Widget.Button({
|
||||
vexpand: false,
|
||||
vpack: "end",
|
||||
vpack: 'end',
|
||||
setup: (self) => {
|
||||
self.hook(audio, () => {
|
||||
const spkr = audio.speaker;
|
||||
const className = `menu-active-button playback ${spkr.is_muted ? "muted" : ""}`;
|
||||
const className = `menu-active-button playback ${spkr.is_muted ? 'muted' : ''}`;
|
||||
return (self.class_name = className);
|
||||
});
|
||||
},
|
||||
on_primary_click: () =>
|
||||
(audio.speaker.is_muted = !audio.speaker.is_muted),
|
||||
on_primary_click: () => (audio.speaker.is_muted = !audio.speaker.is_muted),
|
||||
child: Widget.Icon({
|
||||
class_name: "menu-active-icon playback",
|
||||
class_name: 'menu-active-icon playback',
|
||||
setup: (self) => {
|
||||
self.hook(audio, () => {
|
||||
self.icon = getIcon(
|
||||
audio.speaker.volume,
|
||||
audio.speaker.is_muted,
|
||||
)["spkr"];
|
||||
const isSpeakerMuted = audio.speaker.is_muted !== null ? audio.speaker.is_muted : true;
|
||||
self.icon = getIcon(audio.speaker.volume, isSpeakerMuted)['spkr'];
|
||||
});
|
||||
},
|
||||
}),
|
||||
@@ -34,16 +32,16 @@ const renderActivePlayback = () => {
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "menu-active playback",
|
||||
hpack: "start",
|
||||
truncate: "end",
|
||||
class_name: 'menu-active playback',
|
||||
hpack: 'start',
|
||||
truncate: 'end',
|
||||
expand: true,
|
||||
wrap: true,
|
||||
label: audio.bind("speaker").as((v) => v.description || ""),
|
||||
label: audio.bind('speaker').as((v) => v.description || ''),
|
||||
}),
|
||||
Widget.Slider({
|
||||
value: audio["speaker"].bind("volume"),
|
||||
class_name: "menu-active-slider menu-slider playback",
|
||||
value: audio['speaker'].bind('volume'),
|
||||
class_name: 'menu-active-slider menu-slider playback',
|
||||
draw_value: false,
|
||||
hexpand: true,
|
||||
min: 0,
|
||||
@@ -53,11 +51,9 @@ const renderActivePlayback = () => {
|
||||
],
|
||||
}),
|
||||
Widget.Label({
|
||||
vpack: "end",
|
||||
class_name: "menu-active-percentage playback",
|
||||
label: audio.speaker
|
||||
.bind("volume")
|
||||
.as((v) => `${Math.round(v * 100)}%`),
|
||||
vpack: 'end',
|
||||
class_name: 'menu-active-percentage playback',
|
||||
label: audio.speaker.bind('volume').as((v) => `${Math.round(v * 100)}%`),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -1,39 +1,40 @@
|
||||
import { renderActiveInput } from "./SelectedInput.js";
|
||||
import { renderActivePlayback } from "./SelectedPlayback.js";
|
||||
import { BarBoxChild } from 'lib/types/bar.js';
|
||||
import { renderActiveInput } from './SelectedInput.js';
|
||||
import { renderActivePlayback } from './SelectedPlayback.js';
|
||||
|
||||
const activeDevices = () => {
|
||||
return Widget.Box({
|
||||
class_name: "menu-section-container volume",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
class_name: "menu-label-container volume selected",
|
||||
hpack: "fill",
|
||||
child: Widget.Label({
|
||||
class_name: "menu-label audio volume",
|
||||
hexpand: true,
|
||||
hpack: "start",
|
||||
label: "Volume",
|
||||
}),
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "menu-items-section selected",
|
||||
const activeDevices = (): BarBoxChild => {
|
||||
return Widget.Box({
|
||||
class_name: 'menu-section-container volume',
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
class_name: "menu-active-container playback",
|
||||
vertical: true,
|
||||
children: renderActivePlayback(),
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "menu-active-container input",
|
||||
vertical: true,
|
||||
children: renderActiveInput(),
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: 'menu-label-container volume selected',
|
||||
hpack: 'fill',
|
||||
child: Widget.Label({
|
||||
class_name: 'menu-label audio volume',
|
||||
hexpand: true,
|
||||
hpack: 'start',
|
||||
label: 'Volume',
|
||||
}),
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: 'menu-items-section selected',
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
class_name: 'menu-active-container playback',
|
||||
vertical: true,
|
||||
children: renderActivePlayback(),
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: 'menu-active-container input',
|
||||
vertical: true,
|
||||
children: renderActiveInput(),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export { activeDevices };
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const audio = await Service.import("audio");
|
||||
import { Stream } from "types/service/audio";
|
||||
const audio = await Service.import('audio');
|
||||
import { InputDevices } from 'lib/types/audio';
|
||||
import { Stream } from 'types/service/audio';
|
||||
|
||||
const renderInputDevices = (inputDevices: Stream[]) => {
|
||||
const renderInputDevices = (inputDevices: Stream[]): InputDevices => {
|
||||
if (inputDevices.length === 0) {
|
||||
return [
|
||||
Widget.Button({
|
||||
@@ -9,11 +10,11 @@ const renderInputDevices = (inputDevices: Stream[]) => {
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
Widget.Box({
|
||||
hpack: "start",
|
||||
hpack: 'start',
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "menu-button-name input",
|
||||
label: "No input devices found...",
|
||||
class_name: 'menu-button-name input',
|
||||
label: 'No input devices found...',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
@@ -29,28 +30,28 @@ const renderInputDevices = (inputDevices: Stream[]) => {
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
Widget.Box({
|
||||
hpack: "start",
|
||||
hpack: 'start',
|
||||
children: [
|
||||
Widget.Label({
|
||||
wrap: true,
|
||||
class_name: audio.microphone
|
||||
.bind("description")
|
||||
.bind('description')
|
||||
.as((v) =>
|
||||
device.description === v
|
||||
? "menu-button-icon active input txt-icon"
|
||||
: "menu-button-icon input txt-icon",
|
||||
? 'menu-button-icon active input txt-icon'
|
||||
: 'menu-button-icon input txt-icon',
|
||||
),
|
||||
label: "",
|
||||
label: '',
|
||||
}),
|
||||
Widget.Label({
|
||||
truncate: "end",
|
||||
truncate: 'end',
|
||||
wrap: true,
|
||||
class_name: audio.microphone
|
||||
.bind("description")
|
||||
.bind('description')
|
||||
.as((v) =>
|
||||
device.description === v
|
||||
? "menu-button-name active input"
|
||||
: "menu-button-name input",
|
||||
? 'menu-button-name active input'
|
||||
: 'menu-button-name input',
|
||||
),
|
||||
label: device.description,
|
||||
}),
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
const audio = await Service.import("audio");
|
||||
import { Stream } from "types/service/audio";
|
||||
const audio = await Service.import('audio');
|
||||
import { PlaybackDevices } from 'lib/types/audio';
|
||||
import { Stream } from 'types/service/audio';
|
||||
|
||||
const renderPlaybacks = (playbackDevices: Stream[]) => {
|
||||
const renderPlaybacks = (playbackDevices: Stream[]): PlaybackDevices => {
|
||||
return playbackDevices.map((device) => {
|
||||
if (device.description === "Dummy Output") {
|
||||
if (device.description === 'Dummy Output') {
|
||||
return Widget.Box({
|
||||
class_name: "menu-unfound-button playback",
|
||||
class_name: 'menu-unfound-button playback',
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "menu-button-name playback",
|
||||
label: "No playback devices found...",
|
||||
class_name: 'menu-button-name playback',
|
||||
label: 'No playback devices found...',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
@@ -22,29 +23,29 @@ const renderPlaybacks = (playbackDevices: Stream[]) => {
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
Widget.Box({
|
||||
hpack: "start",
|
||||
hpack: 'start',
|
||||
children: [
|
||||
Widget.Label({
|
||||
truncate: "end",
|
||||
truncate: 'end',
|
||||
wrap: true,
|
||||
class_name: audio.speaker
|
||||
.bind("description")
|
||||
.bind('description')
|
||||
.as((v) =>
|
||||
device.description === v
|
||||
? "menu-button-icon active playback txt-icon"
|
||||
: "menu-button-icon playback txt-icon",
|
||||
? 'menu-button-icon active playback txt-icon'
|
||||
: 'menu-button-icon playback txt-icon',
|
||||
),
|
||||
label: "",
|
||||
label: '',
|
||||
}),
|
||||
Widget.Label({
|
||||
truncate: "end",
|
||||
truncate: 'end',
|
||||
wrap: true,
|
||||
class_name: audio.speaker
|
||||
.bind("description")
|
||||
.bind('description')
|
||||
.as((v) =>
|
||||
device.description === v
|
||||
? "menu-button-name active playback"
|
||||
: "menu-button-name playback",
|
||||
? 'menu-button-name active playback'
|
||||
: 'menu-button-name playback',
|
||||
),
|
||||
label: device.description,
|
||||
}),
|
||||
|
||||
@@ -1,66 +1,63 @@
|
||||
const audio = await Service.import("audio");
|
||||
import { renderInputDevices } from "./InputDevices.js";
|
||||
import { renderPlaybacks } from "./PlaybackDevices.js";
|
||||
const audio = await Service.import('audio');
|
||||
import { BoxWidget } from 'lib/types/widget.js';
|
||||
import { renderInputDevices } from './InputDevices.js';
|
||||
import { renderPlaybacks } from './PlaybackDevices.js';
|
||||
|
||||
const availableDevices = () => {
|
||||
const availableDevices = (): BoxWidget => {
|
||||
return Widget.Box({
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
class_name: "menu-section-container playback",
|
||||
class_name: 'menu-section-container playback',
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
class_name: "menu-label-container playback",
|
||||
hpack: "fill",
|
||||
class_name: 'menu-label-container playback',
|
||||
hpack: 'fill',
|
||||
child: Widget.Label({
|
||||
class_name: "menu-label audio playback",
|
||||
class_name: 'menu-label audio playback',
|
||||
hexpand: true,
|
||||
hpack: "start",
|
||||
label: "Playback Devices",
|
||||
hpack: 'start',
|
||||
label: 'Playback Devices',
|
||||
}),
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "menu-items-section playback",
|
||||
class_name: 'menu-items-section playback',
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
class_name: "menu-container playback",
|
||||
class_name: 'menu-container playback',
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
vertical: true,
|
||||
children: audio
|
||||
.bind("speakers")
|
||||
.as((v) => renderPlaybacks(v)),
|
||||
children: audio.bind('speakers').as((v) => renderPlaybacks(v)),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "menu-label-container input",
|
||||
hpack: "fill",
|
||||
class_name: 'menu-label-container input',
|
||||
hpack: 'fill',
|
||||
child: Widget.Label({
|
||||
class_name: "menu-label audio input",
|
||||
class_name: 'menu-label audio input',
|
||||
hexpand: true,
|
||||
hpack: "start",
|
||||
label: "Input Devices",
|
||||
hpack: 'start',
|
||||
label: 'Input Devices',
|
||||
}),
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "menu-items-section input",
|
||||
class_name: 'menu-items-section input',
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
class_name: "menu-container input",
|
||||
class_name: 'menu-container input',
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
vertical: true,
|
||||
children: audio
|
||||
.bind("microphones")
|
||||
.as((v) => renderInputDevices(v)),
|
||||
children: audio.bind('microphones').as((v) => renderInputDevices(v)),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
import DropdownMenu from "../DropdownMenu.js";
|
||||
import { activeDevices } from "./active/index.js";
|
||||
import { availableDevices } from "./available/index.js";
|
||||
import Window from 'types/widgets/window.js';
|
||||
import DropdownMenu from '../DropdownMenu.js';
|
||||
import { activeDevices } from './active/index.js';
|
||||
import { availableDevices } from './available/index.js';
|
||||
import { Attribute, Child } from 'lib/types/widget.js';
|
||||
|
||||
export default () => {
|
||||
export default (): Window<Child, Attribute> => {
|
||||
return DropdownMenu({
|
||||
name: "audiomenu",
|
||||
transition: "crossfade",
|
||||
name: 'audiomenu',
|
||||
transition: 'crossfade',
|
||||
child: Widget.Box({
|
||||
class_name: "menu-items audio",
|
||||
hpack: "fill",
|
||||
class_name: 'menu-items audio',
|
||||
hpack: 'fill',
|
||||
hexpand: true,
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
hpack: "fill",
|
||||
hpack: 'fill',
|
||||
hexpand: true,
|
||||
class_name: "menu-items-container audio",
|
||||
children: [
|
||||
activeDevices(),
|
||||
availableDevices(),
|
||||
],
|
||||
class_name: 'menu-items-container audio',
|
||||
children: [activeDevices(), availableDevices()],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user