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
|
.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
|
||||||
|
}
|
||||||
66
config.js
66
config.js
@@ -1,46 +1,58 @@
|
|||||||
import GLib from "gi://GLib"
|
import GLib from 'gi://GLib';
|
||||||
|
|
||||||
const main = "/tmp/ags/hyprpanel/main.js"
|
const main = '/tmp/ags/hyprpanel/main.js';
|
||||||
const entry = `${App.configDir}/main.ts`
|
const entry = `${App.configDir}/main.ts`;
|
||||||
const bundler = GLib.getenv("AGS_BUNDLER") || "bun"
|
const bundler = GLib.getenv('AGS_BUNDLER') || 'bun';
|
||||||
|
|
||||||
const v = {
|
const v = {
|
||||||
ags: pkg.version?.split(".").map(Number) || [],
|
ags: pkg.version?.split('.').map(Number) || [],
|
||||||
expect: [1, 8, 1],
|
expect: [1, 8, 1],
|
||||||
}
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (bundler) {
|
switch (bundler) {
|
||||||
case "bun": await Utils.execAsync([
|
case 'bun':
|
||||||
"bun", "build", entry,
|
await Utils.execAsync([
|
||||||
"--outfile", main,
|
'bun',
|
||||||
"--external", "resource://*",
|
'build',
|
||||||
"--external", "gi://*",
|
entry,
|
||||||
"--external", "file://*",
|
'--outfile',
|
||||||
]); break
|
main,
|
||||||
|
'--external',
|
||||||
|
'resource://*',
|
||||||
|
'--external',
|
||||||
|
'gi://*',
|
||||||
|
'--external',
|
||||||
|
'file://*',
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
|
||||||
case "esbuild": await Utils.execAsync([
|
case 'esbuild':
|
||||||
"esbuild", "--bundle", entry,
|
await Utils.execAsync([
|
||||||
"--format=esm",
|
'esbuild',
|
||||||
|
'--bundle',
|
||||||
|
entry,
|
||||||
|
'--format=esm',
|
||||||
`--outfile=${main}`,
|
`--outfile=${main}`,
|
||||||
"--external:resource://*",
|
'--external:resource://*',
|
||||||
"--external:gi://*",
|
'--external:gi://*',
|
||||||
"--external:file://*",
|
'--external:file://*',
|
||||||
]); break
|
]);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
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]) {
|
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(".")}`)
|
print(`HyprPanel needs atleast v${v.expect.join('.')} of AGS, yours is v${v.ags.join('.')}`);
|
||||||
App.quit()
|
App.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
await import(`file://${main}`)
|
await import(`file://${main}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error);
|
||||||
App.quit()
|
App.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
export { }
|
export {};
|
||||||
|
|||||||
@@ -1,26 +1,25 @@
|
|||||||
import GLib from "gi://GLib?version=2.0";
|
import GLib from 'gi://GLib?version=2.0';
|
||||||
import { Binding } from "types/service";
|
import { GenericFunction } from 'lib/types/customModules/generic';
|
||||||
import { Variable as VariableType } from "types/variable";
|
import { Bind } from 'lib/types/variable';
|
||||||
|
import { Variable as VariableType } from 'types/variable';
|
||||||
type GenericFunction = (...args: any[]) => any;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {VariableType<T>} targetVariable - The Variable to update with the function's result.
|
* @param {VariableType<T>} targetVariable - The Variable to update with the function's result.
|
||||||
* @param {Array<VariableType<any>>} trackers - Array of trackers to watch.
|
* @param {Array<Bind>} trackers - Array of trackers to watch.
|
||||||
* @param {Binding<any, any, unknown>} pollingInterval - The polling interval in milliseconds.
|
* @param {Bind} pollingInterval - The polling interval in milliseconds.
|
||||||
* @param {GenericFunction} someFunc - The function to execute at each interval, which updates the Variable.
|
* @param {GenericFunction<T, P>} someFunc - The function to execute at each interval, which updates the Variable.
|
||||||
* @param {...any} params - Parameters to pass to someFunc.
|
* @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>,
|
targetVariable: VariableType<T>,
|
||||||
trackers: Array<Binding<any, any, unknown>>,
|
trackers: Array<Bind>,
|
||||||
pollingInterval: Binding<any, any, unknown>,
|
pollingInterval: Bind,
|
||||||
someFunc: GenericFunction,
|
someFunc: F,
|
||||||
...params: any[]
|
...params: P
|
||||||
): void => {
|
): void => {
|
||||||
let intervalInstance: number | null = null;
|
let intervalInstance: number | null = null;
|
||||||
|
|
||||||
const intervalFn = (pollIntrvl: number) => {
|
const intervalFn = (pollIntrvl: number): void => {
|
||||||
if (intervalInstance !== null) {
|
if (intervalInstance !== null) {
|
||||||
GLib.source_remove(intervalInstance);
|
GLib.source_remove(intervalInstance);
|
||||||
}
|
}
|
||||||
@@ -37,28 +36,31 @@ export const pollVariable = <T>(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {VariableType<T>} targetVariable - The Variable to update with the result of the command.
|
* @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 {string} someCommand - The bash command to execute.
|
||||||
* @param {GenericFunction} someFunc - The function to execute after processing the command result.
|
* @param {GenericFunction<T, [unknown, ...P]>} someFunc - The function to execute after processing the command result;
|
||||||
* @param {...any} params - Parameters to pass to someFunc.
|
* 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>,
|
targetVariable: VariableType<T>,
|
||||||
trackers: Array<Binding<any, any, unknown>>,
|
trackers: Array<Bind>,
|
||||||
pollingInterval: Binding<any, any, unknown>,
|
pollingInterval: Bind,
|
||||||
someCommand: string,
|
someCommand: string,
|
||||||
someFunc: (res: any, ...params: any[]) => T,
|
someFunc: F,
|
||||||
...params: any[]
|
...params: P
|
||||||
): void => {
|
): void => {
|
||||||
let intervalInstance: number | null = null;
|
let intervalInstance: number | null = null;
|
||||||
|
|
||||||
const intervalFn = (pollIntrvl: number) => {
|
const intervalFn = (pollIntrvl: number): void => {
|
||||||
if (intervalInstance !== null) {
|
if (intervalInstance !== null) {
|
||||||
GLib.source_remove(intervalInstance);
|
GLib.source_remove(intervalInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
intervalInstance = Utils.interval(pollIntrvl, () => {
|
intervalInstance = Utils.interval(pollIntrvl, () => {
|
||||||
Utils.execAsync(`bash -c "${someCommand}"`).then((res: any) => {
|
Utils.execAsync(`bash -c "${someCommand}"`)
|
||||||
|
.then((res: string) => {
|
||||||
try {
|
try {
|
||||||
targetVariable.value = someFunc(res, ...params);
|
targetVariable.value = someFunc(res, ...params);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ import { Option } from 'widget/settings/shared/Option';
|
|||||||
import { Header } from 'widget/settings/shared/Header';
|
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 CustomModuleSettings = () =>
|
export const CustomModuleSettings = (): Scrollable<GtkWidget, Attribute> =>
|
||||||
Widget.Scrollable({
|
Widget.Scrollable({
|
||||||
vscroll: 'automatic',
|
vscroll: 'automatic',
|
||||||
hscroll: 'automatic',
|
hscroll: 'automatic',
|
||||||
@@ -204,17 +206,7 @@ export const CustomModuleSettings = () =>
|
|||||||
opt: options.bar.customModules.netstat.icon,
|
opt: options.bar.customModules.netstat.icon,
|
||||||
title: 'Netstat Icon',
|
title: 'Netstat Icon',
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
enums: [
|
enums: ['', '', '', '', '', '', '', '', ''],
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
Option({
|
Option({
|
||||||
opt: options.bar.customModules.netstat.label,
|
opt: options.bar.customModules.netstat.label,
|
||||||
@@ -336,17 +328,7 @@ export const CustomModuleSettings = () =>
|
|||||||
opt: options.bar.customModules.updates.icon,
|
opt: options.bar.customModules.updates.icon,
|
||||||
title: 'Updates Icon',
|
title: 'Updates Icon',
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
enums: [
|
enums: ['', '', '', '', '', '', '', '', ''],
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
Option({
|
Option({
|
||||||
opt: options.bar.customModules.updates.label,
|
opt: options.bar.customModules.updates.label,
|
||||||
@@ -367,7 +349,7 @@ export const CustomModuleSettings = () =>
|
|||||||
opt: options.bar.customModules.updates.pollingInterval,
|
opt: options.bar.customModules.updates.pollingInterval,
|
||||||
title: 'Polling Interval',
|
title: 'Polling Interval',
|
||||||
type: 'number',
|
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,
|
min: 100,
|
||||||
max: 60 * 24 * 1000,
|
max: 60 * 24 * 1000,
|
||||||
increment: 1000,
|
increment: 1000,
|
||||||
@@ -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';
|
import GTop from 'gi://GTop';
|
||||||
|
|
||||||
let previousCpuData = new GTop.glibtop_cpu();
|
let previousCpuData = new GTop.glibtop_cpu();
|
||||||
GTop.glibtop_get_cpu(previousCpuData);
|
GTop.glibtop_get_cpu(previousCpuData);
|
||||||
|
|
||||||
export const computeCPU = () => {
|
export const computeCPU = (): number => {
|
||||||
const currentCpuData = new GTop.glibtop_cpu();
|
const currentCpuData = new GTop.glibtop_cpu();
|
||||||
GTop.glibtop_get_cpu(currentCpuData);
|
GTop.glibtop_get_cpu(currentCpuData);
|
||||||
|
|
||||||
@@ -17,5 +17,4 @@ export const computeCPU = () => {
|
|||||||
previousCpuData = currentCpuData;
|
previousCpuData = currentCpuData;
|
||||||
|
|
||||||
return cpuUsagePercentage;
|
return cpuUsagePercentage;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,21 @@
|
|||||||
import options from "options";
|
import options from 'options';
|
||||||
|
|
||||||
// Module initializer
|
// Module initializer
|
||||||
import { module } from "../module"
|
import { module } from '../module';
|
||||||
|
|
||||||
// import { CpuData } from "lib/types/customModules/cpu";
|
// import { CpuData } from "lib/types/customModules/cpu";
|
||||||
import Button from "types/widgets/button";
|
import Button from 'types/widgets/button';
|
||||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||||
|
|
||||||
// Utility Methods
|
// Utility Methods
|
||||||
import { inputHandler } from "customModules/utils";
|
import { inputHandler } from 'customModules/utils';
|
||||||
import { computeCPU } from "./computeCPU";
|
import { computeCPU } from './computeCPU';
|
||||||
import { pollVariable } from "customModules/PollVar";
|
import { pollVariable } from 'customModules/PollVar';
|
||||||
|
import { Module } from 'lib/types/bar';
|
||||||
|
|
||||||
// All the user configurable options for the cpu module that are needed
|
// All the user configurable options for the cpu module that are needed
|
||||||
const {
|
const { label, round, leftClick, rightClick, middleClick, scrollUp, scrollDown, pollingInterval } =
|
||||||
label,
|
options.bar.customModules.cpu;
|
||||||
round,
|
|
||||||
leftClick,
|
|
||||||
rightClick,
|
|
||||||
middleClick,
|
|
||||||
scrollUp,
|
|
||||||
scrollDown,
|
|
||||||
pollingInterval
|
|
||||||
} = options.bar.customModules.cpu;
|
|
||||||
|
|
||||||
export const cpuUsage = Variable(0);
|
export const cpuUsage = Variable(0);
|
||||||
|
|
||||||
@@ -37,21 +30,19 @@ pollVariable(
|
|||||||
computeCPU,
|
computeCPU,
|
||||||
);
|
);
|
||||||
|
|
||||||
export const Cpu = () => {
|
export const Cpu = (): Module => {
|
||||||
const renderLabel = (cpuUsg: number, rnd: boolean) => {
|
const renderLabel = (cpuUsg: number, rnd: boolean): string => {
|
||||||
return rnd ? `${Math.round(cpuUsg)}%` : `${cpuUsg.toFixed(2)}%`;
|
return rnd ? `${Math.round(cpuUsg)}%` : `${cpuUsg.toFixed(2)}%`;
|
||||||
}
|
};
|
||||||
|
|
||||||
const cpuModule = module({
|
const cpuModule = module({
|
||||||
textIcon: "",
|
textIcon: '',
|
||||||
label: Utils.merge(
|
label: Utils.merge([cpuUsage.bind('value'), round.bind('value')], (cpuUsg, rnd) => {
|
||||||
[cpuUsage.bind("value"), round.bind("value")],
|
|
||||||
(cpuUsg, rnd) => {
|
|
||||||
return renderLabel(cpuUsg, rnd);
|
return renderLabel(cpuUsg, rnd);
|
||||||
}),
|
}),
|
||||||
tooltipText: "CPU",
|
tooltipText: 'CPU',
|
||||||
boxClass: "cpu",
|
boxClass: 'cpu',
|
||||||
showLabelBinding: label.bind("value"),
|
showLabelBinding: label.bind('value'),
|
||||||
props: {
|
props: {
|
||||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||||
inputHandler(self, {
|
inputHandler(self, {
|
||||||
@@ -72,9 +63,8 @@ export const Cpu = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return cpuModule;
|
return cpuModule;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
import { HyprctlDeviceLayout, HyprctlKeyboard, KbLabelType, LayoutKeys, LayoutValues } from "lib/types/customModules/kbLayout";
|
import {
|
||||||
import { layoutMap } from "./layouts";
|
HyprctlDeviceLayout,
|
||||||
|
HyprctlKeyboard,
|
||||||
|
KbLabelType,
|
||||||
|
LayoutKeys,
|
||||||
|
LayoutValues,
|
||||||
|
} from 'lib/types/customModules/kbLayout';
|
||||||
|
import { layoutMap } from './layouts';
|
||||||
|
|
||||||
export const getKeyboardLayout = (obj: string, format: KbLabelType) => {
|
export const getKeyboardLayout = (obj: string, format: KbLabelType): LayoutKeys | LayoutValues => {
|
||||||
let hyprctlDevices: HyprctlDeviceLayout = JSON.parse(obj);
|
const hyprctlDevices: HyprctlDeviceLayout = JSON.parse(obj);
|
||||||
let keyboards = hyprctlDevices['keyboards'];
|
const keyboards = hyprctlDevices['keyboards'];
|
||||||
|
|
||||||
if (keyboards.length === 0) {
|
if (keyboards.length === 0) {
|
||||||
return "No KB!"
|
return format === 'code' ? 'Unknown' : 'Unknown Layout';
|
||||||
}
|
}
|
||||||
|
|
||||||
let mainKb = keyboards.find((kb: HyprctlKeyboard) => kb.main);
|
let mainKb = keyboards.find((kb: HyprctlKeyboard) => kb.main);
|
||||||
@@ -15,8 +21,8 @@ export const getKeyboardLayout = (obj: string, format: KbLabelType) => {
|
|||||||
mainKb = keyboards[keyboards.length - 1];
|
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];
|
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 options from 'options';
|
||||||
import { module } from "../module"
|
import { module } from '../module';
|
||||||
|
|
||||||
import { inputHandler } from "customModules/utils";
|
import { inputHandler } from 'customModules/utils';
|
||||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||||
import Button from "types/widgets/button";
|
import Button from 'types/widgets/button';
|
||||||
import Label from "types/widgets/label";
|
import Label from 'types/widgets/label';
|
||||||
import { getKeyboardLayout } from "./getLayout";
|
import { getKeyboardLayout } from './getLayout';
|
||||||
|
import { Module } from 'lib/types/bar';
|
||||||
|
|
||||||
const {
|
const { label, labelType, icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } =
|
||||||
label,
|
options.bar.customModules.kbLayout;
|
||||||
labelType,
|
|
||||||
icon,
|
|
||||||
leftClick,
|
|
||||||
rightClick,
|
|
||||||
middleClick,
|
|
||||||
scrollUp,
|
|
||||||
scrollDown,
|
|
||||||
} = options.bar.customModules.kbLayout;
|
|
||||||
|
|
||||||
export const KbInput = () => {
|
export const KbInput = (): Module => {
|
||||||
const keyboardModule = module({
|
const keyboardModule = module({
|
||||||
textIcon: icon.bind("value"),
|
textIcon: icon.bind('value'),
|
||||||
tooltipText: "",
|
tooltipText: '',
|
||||||
labelHook: (self: Label<Gtk.Widget>): void => {
|
labelHook: (self: Label<Gtk.Widget>): void => {
|
||||||
self.hook(hyprland, () => {
|
self.hook(
|
||||||
|
hyprland,
|
||||||
|
() => {
|
||||||
Utils.execAsync('hyprctl devices -j')
|
Utils.execAsync('hyprctl devices -j')
|
||||||
.then((obj) => {
|
.then((obj) => {
|
||||||
self.label = getKeyboardLayout(obj, labelType.value);
|
self.label = getKeyboardLayout(obj, labelType.value);
|
||||||
})
|
})
|
||||||
.catch((err) => { console.error(err); });
|
.catch((err) => {
|
||||||
}, "keyboard-layout");
|
console.error(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'keyboard-layout',
|
||||||
|
);
|
||||||
|
|
||||||
self.hook(labelType, () => {
|
self.hook(labelType, () => {
|
||||||
Utils.execAsync('hyprctl devices -j')
|
Utils.execAsync('hyprctl devices -j')
|
||||||
.then((obj) => {
|
.then((obj) => {
|
||||||
self.label = getKeyboardLayout(obj, labelType.value);
|
self.label = getKeyboardLayout(obj, labelType.value);
|
||||||
})
|
})
|
||||||
.catch((err) => { console.error(err); });
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
boxClass: "kblayout",
|
boxClass: 'kblayout',
|
||||||
showLabelBinding: label.bind("value"),
|
showLabelBinding: label.bind('value'),
|
||||||
props: {
|
props: {
|
||||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||||
inputHandler(self, {
|
inputHandler(self, {
|
||||||
@@ -68,6 +69,4 @@ export const KbInput = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return keyboardModule;
|
return keyboardModule;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
|||||||
import { Module } from "lib/types/bar";
|
import { BarBoxChild, Module } from 'lib/types/bar';
|
||||||
import { BarButtonStyles } from "lib/types/options";
|
import { BarButtonStyles } from 'lib/types/options';
|
||||||
import options from "options";
|
import { Bind } from 'lib/types/variable';
|
||||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
import { GtkWidget } from 'lib/types/widget';
|
||||||
import { Binding } from "types/service";
|
import options from 'options';
|
||||||
import { Variable as VariableType } from "types/variable";
|
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||||
|
|
||||||
const { style } = options.theme.bar.buttons;
|
const { style } = options.theme.bar.buttons;
|
||||||
|
|
||||||
@@ -16,45 +16,46 @@ export const module = ({
|
|||||||
tooltipText,
|
tooltipText,
|
||||||
boxClass,
|
boxClass,
|
||||||
props = {},
|
props = {},
|
||||||
showLabelBinding = undefinedVar.bind("value"),
|
showLabelBinding = undefinedVar.bind('value'),
|
||||||
showLabel,
|
showLabel,
|
||||||
labelHook,
|
labelHook,
|
||||||
hook
|
hook,
|
||||||
}: Module) => {
|
}: Module): BarBoxChild => {
|
||||||
const getIconWidget = () => {
|
const getIconWidget = (): GtkWidget | undefined => {
|
||||||
let iconWidget: Gtk.Widget | undefined;
|
let iconWidget: Gtk.Widget | undefined;
|
||||||
|
|
||||||
if (icon !== undefined) {
|
if (icon !== undefined) {
|
||||||
iconWidget = Widget.Icon({
|
iconWidget = Widget.Icon({
|
||||||
class_name: `txt-icon bar-button-icon module-icon ${boxClass}`,
|
class_name: `txt-icon bar-button-icon module-icon ${boxClass}`,
|
||||||
icon: icon
|
icon: icon,
|
||||||
}) as unknown as Gtk.Widget;
|
}) as unknown as Gtk.Widget;
|
||||||
} else if (textIcon !== undefined) {
|
} else if (textIcon !== undefined) {
|
||||||
iconWidget = Widget.Label({
|
iconWidget = Widget.Label({
|
||||||
class_name: `txt-icon bar-button-icon module-icon ${boxClass}`,
|
class_name: `txt-icon bar-button-icon module-icon ${boxClass}`,
|
||||||
label: textIcon
|
label: textIcon,
|
||||||
}) as unknown as Gtk.Widget;
|
}) as unknown as Gtk.Widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
return iconWidget;
|
return iconWidget;
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
component: Widget.Box({
|
component: Widget.Box({
|
||||||
className: Utils.merge([style.bind("value"), showLabelBinding], (style: BarButtonStyles, shwLabel: boolean) => {
|
className: Utils.merge(
|
||||||
|
[style.bind('value'), showLabelBinding],
|
||||||
|
(style: BarButtonStyles, shwLabel: boolean) => {
|
||||||
const shouldShowLabel = shwLabel || showLabel;
|
const shouldShowLabel = shwLabel || showLabel;
|
||||||
const styleMap = {
|
const styleMap = {
|
||||||
default: "style1",
|
default: 'style1',
|
||||||
split: "style2",
|
split: 'style2',
|
||||||
wave: "style3",
|
wave: 'style3',
|
||||||
wave2: "style3",
|
wave2: 'style3',
|
||||||
};
|
};
|
||||||
return `${boxClass} ${styleMap[style]} ${!shouldShowLabel ? "no-label" : ""}`;
|
return `${boxClass} ${styleMap[style]} ${!shouldShowLabel ? 'no-label' : ''}`;
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
tooltip_text: tooltipText,
|
tooltip_text: tooltipText,
|
||||||
children: Utils.merge(
|
children: Utils.merge([showLabelBinding], (showLabelBinding): Gtk.Widget[] => {
|
||||||
[showLabelBinding],
|
|
||||||
(showLabelBinding): Gtk.Widget[] => {
|
|
||||||
const childrenArray: Gtk.Widget[] = [];
|
const childrenArray: Gtk.Widget[] = [];
|
||||||
const iconWidget = getIconWidget();
|
const iconWidget = getIconWidget();
|
||||||
|
|
||||||
@@ -68,17 +69,16 @@ export const module = ({
|
|||||||
class_name: `bar-button-label module-label ${boxClass}`,
|
class_name: `bar-button-label module-label ${boxClass}`,
|
||||||
label: label,
|
label: label,
|
||||||
setup: labelHook,
|
setup: labelHook,
|
||||||
}) as unknown as Gtk.Widget
|
}) as unknown as Gtk.Widget,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return childrenArray;
|
return childrenArray;
|
||||||
}
|
}) as Bind,
|
||||||
) as Binding<VariableType<Gtk.Widget[]>, any, Gtk.Widget[]>,
|
|
||||||
setup: hook,
|
setup: hook,
|
||||||
}),
|
}),
|
||||||
tooltip_text: tooltipText,
|
tooltip_text: tooltipText,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
boxClass,
|
boxClass,
|
||||||
props
|
props,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -71,7 +71,11 @@ const getNetworkUsage = (interfaceName: string = ''): NetworkUsage => {
|
|||||||
return { name: '', rx: 0, tx: 0 };
|
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 rateUnit = dataType.value;
|
||||||
const interfaceName = interfaceNameVar ? interfaceNameVar.value : '';
|
const interfaceName = interfaceNameVar ? interfaceNameVar.value : '';
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import options from 'options';
|
|||||||
import { module } from '../module';
|
import { module } from '../module';
|
||||||
import { inputHandler } from 'customModules/utils';
|
import { inputHandler } from 'customModules/utils';
|
||||||
import { computeNetwork } from './computeNetwork';
|
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 Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||||
import Button from 'types/widgets/button';
|
import Button from 'types/widgets/button';
|
||||||
import { NetworkResourceData } from 'lib/types/customModules/network';
|
import { NetworkResourceData } from 'lib/types/customModules/network';
|
||||||
@@ -23,9 +23,7 @@ const {
|
|||||||
pollingInterval,
|
pollingInterval,
|
||||||
} = options.bar.customModules.netstat;
|
} = options.bar.customModules.netstat;
|
||||||
|
|
||||||
export const networkUsage = Variable<NetworkResourceData>(
|
export const networkUsage = Variable<NetworkResourceData>(GET_DEFAULT_NETSTAT_DATA(rateUnit.value));
|
||||||
GET_DEFAULT_NETSTAT_DATA(rateUnit.value),
|
|
||||||
);
|
|
||||||
|
|
||||||
pollVariable(
|
pollVariable(
|
||||||
// Variable to poll and update with the result of the function passed in
|
// Variable to poll and update with the result of the function passed in
|
||||||
@@ -48,11 +46,8 @@ pollVariable(
|
|||||||
rateUnit,
|
rateUnit,
|
||||||
);
|
);
|
||||||
|
|
||||||
export const Netstat = () => {
|
export const Netstat = (): Module => {
|
||||||
const renderNetworkLabel = (
|
const renderNetworkLabel = (lblType: NetstatLabelType, network: NetworkResourceData): string => {
|
||||||
lblType: NetstatLabelType,
|
|
||||||
network: NetworkResourceData,
|
|
||||||
): string => {
|
|
||||||
switch (lblType) {
|
switch (lblType) {
|
||||||
case 'in':
|
case 'in':
|
||||||
return `↓ ${network.in}`;
|
return `↓ ${network.in}`;
|
||||||
@@ -88,16 +83,14 @@ export const Netstat = () => {
|
|||||||
},
|
},
|
||||||
onScrollUp: {
|
onScrollUp: {
|
||||||
fn: () => {
|
fn: () => {
|
||||||
labelType.value =
|
labelType.value = NETWORK_LABEL_TYPES[
|
||||||
NETWORK_LABEL_TYPES[
|
|
||||||
(NETWORK_LABEL_TYPES.indexOf(labelType.value) + 1) % NETWORK_LABEL_TYPES.length
|
(NETWORK_LABEL_TYPES.indexOf(labelType.value) + 1) % NETWORK_LABEL_TYPES.length
|
||||||
] as NetstatLabelType;
|
] as NetstatLabelType;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
onScrollDown: {
|
onScrollDown: {
|
||||||
fn: () => {
|
fn: () => {
|
||||||
labelType.value =
|
labelType.value = NETWORK_LABEL_TYPES[
|
||||||
NETWORK_LABEL_TYPES[
|
|
||||||
(NETWORK_LABEL_TYPES.indexOf(labelType.value) - 1 + NETWORK_LABEL_TYPES.length) %
|
(NETWORK_LABEL_TYPES.indexOf(labelType.value) - 1 + NETWORK_LABEL_TYPES.length) %
|
||||||
NETWORK_LABEL_TYPES.length
|
NETWORK_LABEL_TYPES.length
|
||||||
] as NetstatLabelType;
|
] as NetstatLabelType;
|
||||||
@@ -110,4 +103,3 @@ export const Netstat = () => {
|
|||||||
|
|
||||||
return netstatModule;
|
return netstatModule;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,18 @@
|
|||||||
import options from "options";
|
import options from 'options';
|
||||||
import { module } from "../module"
|
import { module } from '../module';
|
||||||
|
|
||||||
import { inputHandler } from "customModules/utils";
|
import { inputHandler } from 'customModules/utils';
|
||||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||||
import Button from "types/widgets/button";
|
import Button from 'types/widgets/button';
|
||||||
|
import { Module } from 'lib/types/bar';
|
||||||
|
|
||||||
const {
|
const { icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.power;
|
||||||
icon,
|
|
||||||
leftClick,
|
|
||||||
rightClick,
|
|
||||||
middleClick,
|
|
||||||
scrollUp,
|
|
||||||
scrollDown,
|
|
||||||
} = options.bar.customModules.power;
|
|
||||||
|
|
||||||
export const Power = () => {
|
export const Power = (): Module => {
|
||||||
const powerModule = module({
|
const powerModule = module({
|
||||||
tooltipText: "Power Menu",
|
tooltipText: 'Power Menu',
|
||||||
textIcon: icon.bind("value"),
|
textIcon: icon.bind('value'),
|
||||||
boxClass: "powermodule",
|
boxClass: 'powermodule',
|
||||||
props: {
|
props: {
|
||||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||||
inputHandler(self, {
|
inputHandler(self, {
|
||||||
@@ -43,4 +37,4 @@ export const Power = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return powerModule;
|
return powerModule;
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
|
|
||||||
import { divide } from 'customModules/utils';
|
import { divide } from 'customModules/utils';
|
||||||
|
import { GenericResourceData } from 'lib/types/customModules/generic';
|
||||||
import { Variable as VariableType } from 'types/variable';
|
import { Variable as VariableType } from 'types/variable';
|
||||||
|
|
||||||
export const calculateRamUsage = (round: VariableType<boolean>) => {
|
export const calculateRamUsage = (round: VariableType<boolean>): GenericResourceData => {
|
||||||
try {
|
try {
|
||||||
const [success, meminfoBytes] = GLib.file_get_contents('/proc/meminfo');
|
const [success, meminfoBytes] = GLib.file_get_contents('/proc/meminfo');
|
||||||
|
|
||||||
@@ -26,17 +27,14 @@ export const calculateRamUsage = (round: VariableType<boolean>) => {
|
|||||||
let usedRam = totalRamInBytes - availableRamInBytes;
|
let usedRam = totalRamInBytes - availableRamInBytes;
|
||||||
usedRam = isNaN(usedRam) || usedRam < 0 ? 0 : usedRam;
|
usedRam = isNaN(usedRam) || usedRam < 0 ? 0 : usedRam;
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
percentage: divide([totalRamInBytes, usedRam], round.value),
|
percentage: divide([totalRamInBytes, usedRam], round.value),
|
||||||
total: totalRamInBytes,
|
total: totalRamInBytes,
|
||||||
used: usedRam,
|
used: usedRam,
|
||||||
free: availableRamInBytes,
|
free: availableRamInBytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error calculating RAM usage:', 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
|
// Module initializer
|
||||||
import { module } from "../module"
|
import { module } from '../module';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { GenericResourceData } from "lib/types/customModules/generic";
|
import { GenericResourceData } from 'lib/types/customModules/generic';
|
||||||
import Button from "types/widgets/button";
|
import Button from 'types/widgets/button';
|
||||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||||
|
|
||||||
// Helper Methods
|
// Helper Methods
|
||||||
import { calculateRamUsage } from "./computeRam";
|
import { calculateRamUsage } from './computeRam';
|
||||||
|
|
||||||
// Utility Methods
|
// Utility Methods
|
||||||
import { formatTooltip, inputHandler, renderResourceLabel } from "customModules/utils";
|
import { formatTooltip, inputHandler, renderResourceLabel } from 'customModules/utils';
|
||||||
import { ResourceLabelType } from "lib/types/bar";
|
import { Module, ResourceLabelType } from 'lib/types/bar';
|
||||||
|
|
||||||
// Global Constants
|
// Global Constants
|
||||||
import { LABEL_TYPES } from "lib/types/defaults/bar";
|
import { LABEL_TYPES } from 'lib/types/defaults/bar';
|
||||||
import { pollVariable } from "customModules/PollVar";
|
import { pollVariable } from 'customModules/PollVar';
|
||||||
|
|
||||||
// All the user configurable options for the ram module that are needed
|
// All the user configurable options for the ram module that are needed
|
||||||
const {
|
const { label, labelType, round, leftClick, rightClick, middleClick, pollingInterval } = options.bar.customModules.ram;
|
||||||
label,
|
|
||||||
labelType,
|
|
||||||
round,
|
|
||||||
leftClick,
|
|
||||||
rightClick,
|
|
||||||
middleClick,
|
|
||||||
pollingInterval
|
|
||||||
} = options.bar.customModules.ram;
|
|
||||||
|
|
||||||
const defaultRamData: GenericResourceData = { total: 0, used: 0, percentage: 0, free: 0 };
|
const defaultRamData: GenericResourceData = { total: 0, used: 0, percentage: 0, free: 0 };
|
||||||
const ramUsage = Variable(defaultRamData);
|
const ramUsage = Variable<GenericResourceData>(defaultRamData);
|
||||||
|
|
||||||
pollVariable(
|
pollVariable(ramUsage, [round.bind('value')], pollingInterval.bind('value'), calculateRamUsage, round);
|
||||||
ramUsage,
|
|
||||||
[round.bind('value')],
|
|
||||||
pollingInterval.bind('value'),
|
|
||||||
calculateRamUsage,
|
|
||||||
round,
|
|
||||||
);
|
|
||||||
|
|
||||||
export const Ram = () => {
|
|
||||||
|
|
||||||
|
export const Ram = (): Module => {
|
||||||
const ramModule = module({
|
const ramModule = module({
|
||||||
textIcon: "",
|
textIcon: '',
|
||||||
label: Utils.merge(
|
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) => {
|
(rmUsg: GenericResourceData, lblTyp: ResourceLabelType, round: boolean) => {
|
||||||
const returnValue = renderResourceLabel(lblTyp, rmUsg, round);
|
const returnValue = renderResourceLabel(lblTyp, rmUsg, round);
|
||||||
|
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}),
|
},
|
||||||
tooltipText: labelType.bind("value").as(lblTyp => {
|
),
|
||||||
|
tooltipText: labelType.bind('value').as((lblTyp) => {
|
||||||
return formatTooltip('RAM', lblTyp);
|
return formatTooltip('RAM', lblTyp);
|
||||||
}),
|
}),
|
||||||
boxClass: "ram",
|
boxClass: 'ram',
|
||||||
showLabelBinding: label.bind("value"),
|
showLabelBinding: label.bind('value'),
|
||||||
props: {
|
props: {
|
||||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||||
inputHandler(self, {
|
inputHandler(self, {
|
||||||
@@ -71,18 +57,22 @@ export const Ram = () => {
|
|||||||
},
|
},
|
||||||
onScrollUp: {
|
onScrollUp: {
|
||||||
fn: () => {
|
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: {
|
onScrollDown: {
|
||||||
fn: () => {
|
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;
|
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 GTop from 'gi://GTop';
|
||||||
|
|
||||||
import { divide } from 'customModules/utils';
|
import { divide } from 'customModules/utils';
|
||||||
import { Variable as VariableType } from 'types/variable';
|
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>): GenericResourceData => {
|
||||||
|
|
||||||
export const computeStorage = (round: VariableType<boolean>) => {
|
|
||||||
try {
|
try {
|
||||||
const currentFsUsage = new GTop.glibtop_fsusage();
|
const currentFsUsage = new GTop.glibtop_fsusage();
|
||||||
|
|
||||||
GTop.glibtop_get_fsusage(currentFsUsage, "/");
|
GTop.glibtop_get_fsusage(currentFsUsage, '/');
|
||||||
|
|
||||||
const total = currentFsUsage.blocks * currentFsUsage.block_size;
|
const total = currentFsUsage.blocks * currentFsUsage.block_size;
|
||||||
const available = currentFsUsage.bavail * currentFsUsage.block_size;
|
const available = currentFsUsage.bavail * currentFsUsage.block_size;
|
||||||
const used = total - available;
|
const used = total - available;
|
||||||
|
|
||||||
previousFsUsage = currentFsUsage;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
total,
|
total,
|
||||||
used,
|
used,
|
||||||
@@ -26,7 +23,6 @@ export const computeStorage = (round: VariableType<boolean>) => {
|
|||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error calculating RAM usage:', 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 options from 'options';
|
||||||
import { module } from "../module"
|
import { module } from '../module';
|
||||||
|
|
||||||
import { formatTooltip, inputHandler, renderResourceLabel } from "customModules/utils";
|
import { formatTooltip, inputHandler, renderResourceLabel } from 'customModules/utils';
|
||||||
import { computeStorage } from "./computeStorage";
|
import { computeStorage } from './computeStorage';
|
||||||
import { ResourceLabelType } from "lib/types/bar";
|
import { Module, ResourceLabelType } from 'lib/types/bar';
|
||||||
import { GenericResourceData } from "lib/types/customModules/generic";
|
import { GenericResourceData } from 'lib/types/customModules/generic';
|
||||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||||
import Button from "types/widgets/button";
|
import Button from 'types/widgets/button';
|
||||||
import { LABEL_TYPES } from "lib/types/defaults/bar";
|
import { LABEL_TYPES } from 'lib/types/defaults/bar';
|
||||||
import { pollVariable } from "customModules/PollVar";
|
import { pollVariable } from 'customModules/PollVar';
|
||||||
|
|
||||||
const {
|
const { label, labelType, icon, round, leftClick, rightClick, middleClick, pollingInterval } =
|
||||||
label,
|
options.bar.customModules.storage;
|
||||||
labelType,
|
|
||||||
icon,
|
|
||||||
round,
|
|
||||||
leftClick,
|
|
||||||
rightClick,
|
|
||||||
middleClick,
|
|
||||||
pollingInterval
|
|
||||||
} = options.bar.customModules.storage;
|
|
||||||
|
|
||||||
const defaultStorageData = { total: 0, used: 0, percentage: 0, free: 0 };
|
const defaultStorageData = { total: 0, used: 0, percentage: 0, free: 0 };
|
||||||
|
|
||||||
const storageUsage = Variable(defaultStorageData);
|
const storageUsage = Variable<GenericResourceData>(defaultStorageData);
|
||||||
|
|
||||||
pollVariable(
|
pollVariable(storageUsage, [round.bind('value')], pollingInterval.bind('value'), computeStorage, round);
|
||||||
storageUsage,
|
|
||||||
[round.bind('value')],
|
|
||||||
pollingInterval.bind('value'),
|
|
||||||
computeStorage,
|
|
||||||
round,
|
|
||||||
);
|
|
||||||
|
|
||||||
export const Storage = () => {
|
export const Storage = (): Module => {
|
||||||
const storageModule = module({
|
const storageModule = module({
|
||||||
textIcon: icon.bind("value"),
|
textIcon: icon.bind('value'),
|
||||||
label: Utils.merge(
|
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) => {
|
(storage: GenericResourceData, lblTyp: ResourceLabelType, round: boolean) => {
|
||||||
return renderResourceLabel(lblTyp, storage, round);
|
return renderResourceLabel(lblTyp, storage, round);
|
||||||
}),
|
},
|
||||||
tooltipText: labelType.bind("value").as(lblTyp => {
|
),
|
||||||
|
tooltipText: labelType.bind('value').as((lblTyp) => {
|
||||||
return formatTooltip('Storage', lblTyp);
|
return formatTooltip('Storage', lblTyp);
|
||||||
|
|
||||||
}),
|
}),
|
||||||
boxClass: "storage",
|
boxClass: 'storage',
|
||||||
showLabelBinding: label.bind("value"),
|
showLabelBinding: label.bind('value'),
|
||||||
props: {
|
props: {
|
||||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||||
inputHandler(self, {
|
inputHandler(self, {
|
||||||
@@ -61,18 +47,22 @@ export const Storage = () => {
|
|||||||
},
|
},
|
||||||
onScrollUp: {
|
onScrollUp: {
|
||||||
fn: () => {
|
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: {
|
onScrollDown: {
|
||||||
fn: () => {
|
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;
|
return storageModule;
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,106 +1,146 @@
|
|||||||
import { Option } from "widget/settings/shared/Option";
|
import { Option } from 'widget/settings/shared/Option';
|
||||||
import { Header } from "widget/settings/shared/Header";
|
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({
|
return Widget.Scrollable({
|
||||||
vscroll: "automatic",
|
vscroll: 'automatic',
|
||||||
hscroll: "automatic",
|
hscroll: 'automatic',
|
||||||
class_name: "menu-theme-page customModules paged-container",
|
class_name: 'menu-theme-page customModules paged-container',
|
||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
class_name: "bar-theme-page paged-container",
|
class_name: 'bar-theme-page paged-container',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Header('RAM'),
|
Header('RAM'),
|
||||||
Option({ opt: options.theme.bar.buttons.modules.ram.text, title: 'Text', type: 'color' }),
|
Option({ opt: options.theme.bar.buttons.modules.ram.text, title: 'Text', type: 'color' }),
|
||||||
Option({ opt: options.theme.bar.buttons.modules.ram.icon, title: 'Icon', type: 'color' }),
|
Option({ opt: options.theme.bar.buttons.modules.ram.icon, title: 'Icon', type: 'color' }),
|
||||||
Option({ opt: options.theme.bar.buttons.modules.ram.background, title: 'Label Background', type: 'color' }),
|
Option({
|
||||||
|
opt: options.theme.bar.buttons.modules.ram.background,
|
||||||
|
title: 'Label Background',
|
||||||
|
type: 'color',
|
||||||
|
}),
|
||||||
Option({
|
Option({
|
||||||
opt: options.theme.bar.buttons.modules.ram.icon_background,
|
opt: options.theme.bar.buttons.modules.ram.icon_background,
|
||||||
title: 'Icon Background',
|
title: 'Icon Background',
|
||||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
subtitle:
|
||||||
type: 'color'
|
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||||
|
type: 'color',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Header('CPU'),
|
Header('CPU'),
|
||||||
Option({ opt: options.theme.bar.buttons.modules.cpu.text, title: 'Text', type: 'color' }),
|
Option({ opt: options.theme.bar.buttons.modules.cpu.text, title: 'Text', type: 'color' }),
|
||||||
Option({ opt: options.theme.bar.buttons.modules.cpu.icon, title: 'Icon', type: 'color' }),
|
Option({ opt: options.theme.bar.buttons.modules.cpu.icon, title: 'Icon', type: 'color' }),
|
||||||
Option({ opt: options.theme.bar.buttons.modules.cpu.background, title: 'Label Background', type: 'color' }),
|
Option({
|
||||||
|
opt: options.theme.bar.buttons.modules.cpu.background,
|
||||||
|
title: 'Label Background',
|
||||||
|
type: 'color',
|
||||||
|
}),
|
||||||
Option({
|
Option({
|
||||||
opt: options.theme.bar.buttons.modules.cpu.icon_background,
|
opt: options.theme.bar.buttons.modules.cpu.icon_background,
|
||||||
title: 'Icon Background',
|
title: 'Icon Background',
|
||||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
subtitle:
|
||||||
type: 'color'
|
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||||
|
type: 'color',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Header('Storage'),
|
Header('Storage'),
|
||||||
Option({ opt: options.theme.bar.buttons.modules.storage.text, title: 'Text', type: 'color' }),
|
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.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({
|
Option({
|
||||||
opt: options.theme.bar.buttons.modules.storage.icon_background,
|
opt: options.theme.bar.buttons.modules.storage.icon_background,
|
||||||
title: 'Icon Background',
|
title: 'Icon Background',
|
||||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
subtitle:
|
||||||
type: 'color'
|
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||||
|
type: 'color',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Header('Netstat'),
|
Header('Netstat'),
|
||||||
Option({ opt: options.theme.bar.buttons.modules.netstat.text, title: 'Text', type: 'color' }),
|
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.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({
|
Option({
|
||||||
opt: options.theme.bar.buttons.modules.netstat.icon_background,
|
opt: options.theme.bar.buttons.modules.netstat.icon_background,
|
||||||
title: 'Icon Background',
|
title: 'Icon Background',
|
||||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
subtitle:
|
||||||
type: 'color'
|
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||||
|
type: 'color',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Header('Keyboard Layout'),
|
Header('Keyboard Layout'),
|
||||||
Option({ opt: options.theme.bar.buttons.modules.kbLayout.text, title: 'Text', type: 'color' }),
|
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.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({
|
Option({
|
||||||
opt: options.theme.bar.buttons.modules.kbLayout.icon_background,
|
opt: options.theme.bar.buttons.modules.kbLayout.icon_background,
|
||||||
title: 'Icon Background',
|
title: 'Icon Background',
|
||||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
subtitle:
|
||||||
type: 'color'
|
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||||
|
type: 'color',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Header('Updates'),
|
Header('Updates'),
|
||||||
Option({ opt: options.theme.bar.buttons.modules.updates.text, title: 'Text', type: 'color' }),
|
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.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({
|
Option({
|
||||||
opt: options.theme.bar.buttons.modules.updates.icon_background,
|
opt: options.theme.bar.buttons.modules.updates.icon_background,
|
||||||
title: 'Icon Background',
|
title: 'Icon Background',
|
||||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
subtitle:
|
||||||
type: 'color'
|
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||||
|
type: 'color',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Header('Weather'),
|
Header('Weather'),
|
||||||
Option({ opt: options.theme.bar.buttons.modules.weather.icon, title: 'Icon', type: 'color' }),
|
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.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({
|
Option({
|
||||||
opt: options.theme.bar.buttons.modules.weather.icon_background,
|
opt: options.theme.bar.buttons.modules.weather.icon_background,
|
||||||
title: 'Icon Background',
|
title: 'Icon Background',
|
||||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
subtitle:
|
||||||
type: 'color'
|
"Applies a background color to the icon section of the button.\nRequires 'split' button styling.",
|
||||||
|
type: 'color',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Header('Power'),
|
Header('Power'),
|
||||||
Option({ opt: options.theme.bar.buttons.modules.power.icon, title: 'Icon', type: 'color' }),
|
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({
|
Option({
|
||||||
opt: options.theme.bar.buttons.modules.power.icon_background,
|
opt: options.theme.bar.buttons.modules.power.icon_background,
|
||||||
title: 'Icon Background',
|
title: 'Icon Background',
|
||||||
subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.',
|
subtitle:
|
||||||
type: 'color'
|
"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 options from 'options';
|
||||||
import { module } from "../module"
|
import { module } from '../module';
|
||||||
|
|
||||||
import { inputHandler } from "customModules/utils";
|
import { inputHandler } from 'customModules/utils';
|
||||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||||
import Button from "types/widgets/button";
|
import Button from 'types/widgets/button';
|
||||||
import { Variable as VariableType } from "types/variable";
|
import { Variable as VariableType } from 'types/variable';
|
||||||
import { pollVariableBash } from "customModules/PollVar";
|
import { pollVariableBash } from 'customModules/PollVar';
|
||||||
|
import { Module } from 'lib/types/bar';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
updateCommand,
|
updateCommand,
|
||||||
@@ -20,12 +21,12 @@ const {
|
|||||||
scrollDown,
|
scrollDown,
|
||||||
} = options.bar.customModules.updates;
|
} = 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;
|
if (!padZero.value) return updateCount;
|
||||||
return `${updateCount.padStart(2, '0')}`;
|
return `${updateCount.padStart(2, '0')}`;
|
||||||
}
|
};
|
||||||
|
|
||||||
pollVariableBash(
|
pollVariableBash(
|
||||||
pendingUpdates,
|
pendingUpdates,
|
||||||
@@ -35,13 +36,13 @@ pollVariableBash(
|
|||||||
processUpdateCount,
|
processUpdateCount,
|
||||||
);
|
);
|
||||||
|
|
||||||
export const Updates = () => {
|
export const Updates = (): Module => {
|
||||||
const updatesModule = module({
|
const updatesModule = module({
|
||||||
textIcon: icon.bind("value"),
|
textIcon: icon.bind('value'),
|
||||||
tooltipText: pendingUpdates.bind("value").as(v => `${v} updates available`),
|
tooltipText: pendingUpdates.bind('value').as((v) => `${v} updates available`),
|
||||||
boxClass: "updates",
|
boxClass: 'updates',
|
||||||
label: pendingUpdates.bind("value"),
|
label: pendingUpdates.bind('value'),
|
||||||
showLabelBinding: label.bind("value"),
|
showLabelBinding: label.bind('value'),
|
||||||
props: {
|
props: {
|
||||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||||
inputHandler(self, {
|
inputHandler(self, {
|
||||||
@@ -66,7 +67,4 @@ export const Updates = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return updatesModule;
|
return updatesModule;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { ResourceLabelType } from 'lib/types/bar';
|
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 { 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 { Binding } from 'lib/utils';
|
||||||
import { openMenu } from 'modules/bar/utils';
|
import { openMenu } from 'modules/bar/utils';
|
||||||
import options from 'options';
|
import options from 'options';
|
||||||
@@ -13,14 +15,11 @@ const { scrollSpeed } = options.bar.customModules;
|
|||||||
|
|
||||||
export const runAsyncCommand = (
|
export const runAsyncCommand = (
|
||||||
cmd: string,
|
cmd: string,
|
||||||
fn: Function,
|
fn: (output: string) => void,
|
||||||
events: { clicked: any; event: Gdk.Event }
|
events: { clicked: Button<GtkWidget, GtkWidget>; event: Gdk.Event },
|
||||||
): void => {
|
): void => {
|
||||||
if (cmd.startsWith('menu:')) {
|
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();
|
const menuName = cmd.split(':')[1].trim().toLowerCase();
|
||||||
|
|
||||||
openMenu(events.clicked, events.event, `${menuName}menu`);
|
openMenu(events.clicked, events.event, `${menuName}menu`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -32,15 +31,10 @@ export const runAsyncCommand = (
|
|||||||
fn(output);
|
fn(output);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) => console.error(`Error running command "${cmd}": ${err})`));
|
||||||
console.error(`Error running command "${cmd}": ${err})`)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function throttle<T extends (...args: any[]) => void>(
|
export function throttle<T extends ThrottleFn>(func: T, limit: number): T {
|
||||||
func: T,
|
|
||||||
limit: number
|
|
||||||
): T {
|
|
||||||
let inThrottle: boolean;
|
let inThrottle: boolean;
|
||||||
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
|
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
|
||||||
if (!inThrottle) {
|
if (!inThrottle) {
|
||||||
@@ -53,31 +47,23 @@ export function throttle<T extends (...args: any[]) => void>(
|
|||||||
} as T;
|
} as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const throttledScrollHandler = (interval: number) =>
|
export const throttledScrollHandler = (interval: number): ThrottleFn =>
|
||||||
throttle((cmd: string, fn: Function | undefined) => {
|
throttle((cmd: string, fn: ThrottleFnCallback) => {
|
||||||
Utils.execAsync(`bash -c "${cmd}"`)
|
Utils.execAsync(`bash -c "${cmd}"`)
|
||||||
.then((output) => {
|
.then((output) => {
|
||||||
if (fn !== undefined) {
|
if (fn !== undefined) {
|
||||||
fn(output);
|
fn(output);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) => console.error(`Error running command "${cmd}": ${err}`));
|
||||||
console.error(`Error running command "${cmd}": ${err}`)
|
|
||||||
);
|
|
||||||
}, 200 / interval);
|
}, 200 / interval);
|
||||||
|
|
||||||
const dummyVar = Variable('');
|
const dummyVar = Variable('');
|
||||||
|
|
||||||
export const inputHandler = (
|
export const inputHandler = (
|
||||||
self: Button<Gtk.Widget, Gtk.Widget>,
|
self: Button<Gtk.Widget, Gtk.Widget>,
|
||||||
{
|
{ onPrimaryClick, onSecondaryClick, onMiddleClick, onScrollUp, onScrollDown }: InputHandlerEvents,
|
||||||
onPrimaryClick,
|
): void => {
|
||||||
onSecondaryClick,
|
|
||||||
onMiddleClick,
|
|
||||||
onScrollUp,
|
|
||||||
onScrollDown,
|
|
||||||
}: InputHandlerEvents
|
|
||||||
) => {
|
|
||||||
const sanitizeInput = (input: VariableType<string>): string => {
|
const sanitizeInput = (input: VariableType<string>): string => {
|
||||||
if (input === undefined) {
|
if (input === undefined) {
|
||||||
return '';
|
return '';
|
||||||
@@ -89,46 +75,25 @@ export const inputHandler = (
|
|||||||
const interval = scrollSpeed.value;
|
const interval = scrollSpeed.value;
|
||||||
const throttledHandler = throttledScrollHandler(interval);
|
const throttledHandler = throttledScrollHandler(interval);
|
||||||
|
|
||||||
self.on_primary_click = (clicked: any, event: Gdk.Event) =>
|
self.on_primary_click = (clicked: Button<GtkWidget, GtkWidget>, event: Gdk.Event): void =>
|
||||||
runAsyncCommand(
|
runAsyncCommand(sanitizeInput(onPrimaryClick?.cmd || dummyVar), onPrimaryClick.fn, { clicked, event });
|
||||||
sanitizeInput(onPrimaryClick?.cmd || dummyVar),
|
|
||||||
onPrimaryClick.fn,
|
|
||||||
{ clicked, event }
|
|
||||||
);
|
|
||||||
|
|
||||||
self.on_secondary_click = (clicked: any, event: Gdk.Event) =>
|
self.on_secondary_click = (clicked: Button<GtkWidget, GtkWidget>, event: Gdk.Event): void =>
|
||||||
runAsyncCommand(
|
runAsyncCommand(sanitizeInput(onSecondaryClick?.cmd || dummyVar), onSecondaryClick.fn, { clicked, event });
|
||||||
sanitizeInput(onSecondaryClick?.cmd || dummyVar),
|
|
||||||
onSecondaryClick.fn,
|
|
||||||
{ clicked, event }
|
|
||||||
);
|
|
||||||
|
|
||||||
self.on_middle_click = (clicked: any, event: Gdk.Event) =>
|
self.on_middle_click = (clicked: Button<GtkWidget, GtkWidget>, event: Gdk.Event): void =>
|
||||||
runAsyncCommand(
|
runAsyncCommand(sanitizeInput(onMiddleClick?.cmd || dummyVar), onMiddleClick.fn, { clicked, event });
|
||||||
sanitizeInput(onMiddleClick?.cmd || dummyVar),
|
|
||||||
onMiddleClick.fn,
|
|
||||||
{ clicked, event }
|
|
||||||
);
|
|
||||||
|
|
||||||
self.on_scroll_up = () =>
|
self.on_scroll_up = (): void => throttledHandler(sanitizeInput(onScrollUp?.cmd || dummyVar), onScrollUp.fn);
|
||||||
throttledHandler(
|
|
||||||
sanitizeInput(onScrollUp?.cmd || dummyVar),
|
|
||||||
onScrollUp.fn
|
|
||||||
);
|
|
||||||
|
|
||||||
self.on_scroll_down = () =>
|
self.on_scroll_down = (): void =>
|
||||||
throttledHandler(
|
throttledHandler(sanitizeInput(onScrollDown?.cmd || dummyVar), onScrollDown.fn);
|
||||||
sanitizeInput(onScrollDown?.cmd || dummyVar),
|
|
||||||
onScrollDown.fn
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initial setup of event handlers
|
// Initial setup of event handlers
|
||||||
updateHandlers();
|
updateHandlers();
|
||||||
|
|
||||||
const sanitizeVariable = (
|
const sanitizeVariable = (someVar: VariableType<string> | undefined): Binding<string> => {
|
||||||
someVar: VariableType<string> | undefined
|
|
||||||
): Binding<string> => {
|
|
||||||
if (someVar === undefined || typeof someVar.bind !== 'function') {
|
if (someVar === undefined || typeof someVar.bind !== 'function') {
|
||||||
return dummyVar.bind('value');
|
return dummyVar.bind('value');
|
||||||
}
|
}
|
||||||
@@ -145,37 +110,36 @@ export const inputHandler = (
|
|||||||
sanitizeVariable(onScrollUp),
|
sanitizeVariable(onScrollUp),
|
||||||
sanitizeVariable(onScrollDown),
|
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;
|
const percentageTotal = (used / total) * 100;
|
||||||
if (round) {
|
if (round) {
|
||||||
return total > 0 ? Math.round(percentageTotal) : 0;
|
return total > 0 ? Math.round(percentageTotal) : 0;
|
||||||
}
|
}
|
||||||
return total > 0 ? parseFloat(percentageTotal.toFixed(2)) : 0;
|
return total > 0 ? parseFloat(percentageTotal.toFixed(2)) : 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const formatSizeInKiB = (sizeInBytes: number, round: boolean) => {
|
export const formatSizeInKiB = (sizeInBytes: number, round: boolean): number => {
|
||||||
const sizeInGiB = sizeInBytes / (1024 ** 1);
|
const sizeInGiB = sizeInBytes / 1024 ** 1;
|
||||||
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
||||||
};
|
};
|
||||||
export const formatSizeInMiB = (sizeInBytes: number, round: boolean) => {
|
export const formatSizeInMiB = (sizeInBytes: number, round: boolean): number => {
|
||||||
const sizeInGiB = sizeInBytes / (1024 ** 2);
|
const sizeInGiB = sizeInBytes / 1024 ** 2;
|
||||||
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
||||||
};
|
};
|
||||||
export const formatSizeInGiB = (sizeInBytes: number, round: boolean) => {
|
export const formatSizeInGiB = (sizeInBytes: number, round: boolean): number => {
|
||||||
const sizeInGiB = sizeInBytes / (1024 ** 3);
|
const sizeInGiB = sizeInBytes / 1024 ** 3;
|
||||||
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
||||||
};
|
};
|
||||||
export const formatSizeInTiB = (sizeInBytes: number, round: boolean) => {
|
export const formatSizeInTiB = (sizeInBytes: number, round: boolean): number => {
|
||||||
const sizeInGiB = sizeInBytes / (1024 ** 4);
|
const sizeInGiB = sizeInBytes / 1024 ** 4;
|
||||||
return round ? Math.round(sizeInGiB) : parseFloat(sizeInGiB.toFixed(2));
|
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
|
// auto convert to GiB, MiB, KiB, TiB, or bytes
|
||||||
if (sizeInBytes >= 1024 ** 4) return formatSizeInTiB(sizeInBytes, round);
|
if (sizeInBytes >= 1024 ** 4) return formatSizeInTiB(sizeInBytes, round);
|
||||||
if (sizeInBytes >= 1024 ** 3) return formatSizeInGiB(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);
|
if (sizeInBytes >= 1024 ** 1) return formatSizeInKiB(sizeInBytes, round);
|
||||||
|
|
||||||
return sizeInBytes;
|
return sizeInBytes;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getPostfix = (sizeInBytes: number) => {
|
export const getPostfix = (sizeInBytes: number): Postfix => {
|
||||||
if (sizeInBytes >= 1024 ** 4) return 'TiB';
|
if (sizeInBytes >= 1024 ** 4) return 'TiB';
|
||||||
if (sizeInBytes >= 1024 ** 3) return 'GiB';
|
if (sizeInBytes >= 1024 ** 3) return 'GiB';
|
||||||
if (sizeInBytes >= 1024 ** 2) return 'MiB';
|
if (sizeInBytes >= 1024 ** 2) return 'MiB';
|
||||||
if (sizeInBytes >= 1024 ** 1) return 'KiB';
|
if (sizeInBytes >= 1024 ** 1) return 'KiB';
|
||||||
|
|
||||||
return 'B';
|
return 'B';
|
||||||
}
|
};
|
||||||
|
|
||||||
export const renderResourceLabel = (
|
export const renderResourceLabel = (lblType: ResourceLabelType, rmUsg: GenericResourceData, round: boolean): string => {
|
||||||
lblType: ResourceLabelType,
|
|
||||||
rmUsg: GenericResourceData,
|
|
||||||
round: boolean
|
|
||||||
) => {
|
|
||||||
const { used, total, percentage, free } = rmUsg;
|
const { used, total, percentage, free } = rmUsg;
|
||||||
|
|
||||||
const formatFunctions = {
|
const formatFunctions = {
|
||||||
@@ -206,7 +166,7 @@ export const renderResourceLabel = (
|
|||||||
GiB: formatSizeInGiB,
|
GiB: formatSizeInGiB,
|
||||||
MiB: formatSizeInMiB,
|
MiB: formatSizeInMiB,
|
||||||
KiB: formatSizeInKiB,
|
KiB: formatSizeInKiB,
|
||||||
B: (size: number, _: boolean) => size
|
B: (size: number): number => size,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get them datas in proper GiB, MiB, KiB, TiB, or bytes
|
// 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 formatUsed = formatFunctions[postfix] || formatFunctions['B'];
|
||||||
const usedSizeFormatted = formatUsed(used, round);
|
const usedSizeFormatted = formatUsed(used, round);
|
||||||
|
|
||||||
if (lblType === "used/total") {
|
if (lblType === 'used/total') {
|
||||||
return `${usedSizeFormatted}/${totalSizeFormatted} ${postfix}`;
|
return `${usedSizeFormatted}/${totalSizeFormatted} ${postfix}`;
|
||||||
}
|
}
|
||||||
if (lblType === "used") {
|
if (lblType === 'used') {
|
||||||
return `${autoFormatSize(used, round)} ${getPostfix(used)}`;
|
return `${autoFormatSize(used, round)} ${getPostfix(used)}`;
|
||||||
}
|
}
|
||||||
if (lblType === "free") {
|
if (lblType === 'free') {
|
||||||
return `${autoFormatSize(free, round)} ${getPostfix(free)}`;
|
return `${autoFormatSize(free, round)} ${getPostfix(free)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${percentage}%`;
|
return `${percentage}%`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const formatTooltip = (dataType: string, lblTyp: ResourceLabelType) => {
|
export const formatTooltip = (dataType: string, lblTyp: ResourceLabelType): string => {
|
||||||
switch (lblTyp) {
|
switch (lblTyp) {
|
||||||
case 'used':
|
case 'used':
|
||||||
return `Used ${dataType}`;
|
return `Used ${dataType}`;
|
||||||
@@ -244,4 +204,4 @@ export const formatTooltip = (dataType: string, lblTyp: ResourceLabelType) => {
|
|||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,40 +1,30 @@
|
|||||||
import options from "options";
|
import options from 'options';
|
||||||
import { module } from "../module"
|
import { module } from '../module';
|
||||||
|
|
||||||
import { inputHandler } from "customModules/utils";
|
import { inputHandler } from 'customModules/utils';
|
||||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0";
|
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||||
import Button from "types/widgets/button";
|
import Button from 'types/widgets/button';
|
||||||
import { getWeatherStatusTextIcon, globalWeatherVar } from "globals/weather";
|
import { getWeatherStatusTextIcon, globalWeatherVar } from 'globals/weather';
|
||||||
|
import { Module } from 'lib/types/bar';
|
||||||
|
|
||||||
const {
|
const { label, unit, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.weather;
|
||||||
label,
|
|
||||||
unit,
|
|
||||||
leftClick,
|
|
||||||
rightClick,
|
|
||||||
middleClick,
|
|
||||||
scrollUp,
|
|
||||||
scrollDown,
|
|
||||||
} = options.bar.customModules.weather;
|
|
||||||
|
|
||||||
export const Weather = () => {
|
export const Weather = (): Module => {
|
||||||
const weatherModule = module({
|
const weatherModule = module({
|
||||||
textIcon: Utils.merge([globalWeatherVar.bind("value")], (wthr) => {
|
textIcon: Utils.merge([globalWeatherVar.bind('value')], (wthr) => {
|
||||||
const weatherStatusIcon = getWeatherStatusTextIcon(wthr);
|
const weatherStatusIcon = getWeatherStatusTextIcon(wthr);
|
||||||
return weatherStatusIcon;
|
return weatherStatusIcon;
|
||||||
}),
|
}),
|
||||||
tooltipText: globalWeatherVar.bind("value").as(v => `Weather Status: ${v.current.condition.text}`),
|
tooltipText: globalWeatherVar.bind('value').as((v) => `Weather Status: ${v.current.condition.text}`),
|
||||||
boxClass: "weather-custom",
|
boxClass: 'weather-custom',
|
||||||
label: Utils.merge(
|
label: Utils.merge([globalWeatherVar.bind('value'), unit.bind('value')], (wthr, unt) => {
|
||||||
[globalWeatherVar.bind("value"), unit.bind("value")],
|
if (unt === 'imperial') {
|
||||||
(wthr, unt) => {
|
|
||||||
if (unt === "imperial") {
|
|
||||||
return `${Math.ceil(wthr.current.temp_f)}° F`;
|
return `${Math.ceil(wthr.current.temp_f)}° F`;
|
||||||
} else {
|
} else {
|
||||||
return `${Math.ceil(wthr.current.temp_c)}° C`;
|
return `${Math.ceil(wthr.current.temp_c)}° C`;
|
||||||
}
|
}
|
||||||
},
|
}),
|
||||||
),
|
showLabelBinding: label.bind('value'),
|
||||||
showLabelBinding: label.bind("value"),
|
|
||||||
props: {
|
props: {
|
||||||
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
setup: (self: Button<Gtk.Widget, Gtk.Widget>) => {
|
||||||
inputHandler(self, {
|
inputHandler(self, {
|
||||||
@@ -59,8 +49,4 @@ export const Weather = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return weatherModule;
|
return weatherModule;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import Service from "resource:///com/github/Aylur/ags/service.js";
|
import Service from 'resource:///com/github/Aylur/ags/service.js';
|
||||||
import App from "resource:///com/github/Aylur/ags/app.js";
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
import { monitorFile } from "resource:///com/github/Aylur/ags/utils.js";
|
import { monitorFile } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
import Gio from "gi://Gio";
|
import Gio from 'gi://Gio';
|
||||||
import { FileInfo } from "types/@girs/gio-2.0/gio-2.0.cjs";
|
import { FileInfo } from 'types/@girs/gio-2.0/gio-2.0.cjs';
|
||||||
|
|
||||||
class DirectoryMonitorService extends Service {
|
class DirectoryMonitorService extends Service {
|
||||||
static {
|
static {
|
||||||
@@ -14,23 +14,19 @@ class DirectoryMonitorService extends Service {
|
|||||||
this.recursiveDirectoryMonitor(`${App.configDir}/scss`);
|
this.recursiveDirectoryMonitor(`${App.configDir}/scss`);
|
||||||
}
|
}
|
||||||
|
|
||||||
recursiveDirectoryMonitor(directoryPath: string) {
|
recursiveDirectoryMonitor(directoryPath: string): void {
|
||||||
monitorFile(directoryPath, (_, eventType) => {
|
monitorFile(directoryPath, (_, eventType) => {
|
||||||
if (eventType === Gio.FileMonitorEvent.CHANGES_DONE_HINT) {
|
if (eventType === Gio.FileMonitorEvent.CHANGES_DONE_HINT) {
|
||||||
this.emit("changed");
|
this.emit('changed');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const directory = Gio.File.new_for_path(directoryPath);
|
const directory = Gio.File.new_for_path(directoryPath);
|
||||||
const enumerator = directory.enumerate_children(
|
const enumerator = directory.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
|
||||||
"standard::*",
|
|
||||||
Gio.FileQueryInfoFlags.NONE,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
|
|
||||||
let fileInfo: FileInfo;
|
let fileInfo: FileInfo;
|
||||||
while ((fileInfo = enumerator.next_file(null) as FileInfo) !== null) {
|
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) {
|
if (fileInfo.get_file_type() === Gio.FileType.DIRECTORY) {
|
||||||
this.recursiveDirectoryMonitor(childPath);
|
this.recursiveDirectoryMonitor(childPath);
|
||||||
}
|
}
|
||||||
|
|||||||
7
globals.d.ts
vendored
7
globals.d.ts
vendored
@@ -1,12 +1,13 @@
|
|||||||
// globals.d.ts
|
// 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 {
|
declare global {
|
||||||
var globalMousePos: VariableType<number[]>;
|
var globalMousePos: VariableType<number[]>;
|
||||||
var useTheme: Function;
|
var useTheme: (filePath: string) => void;
|
||||||
var globalWeatherVar: VariableType<Weather>;
|
var globalWeatherVar: VariableType<Weather>;
|
||||||
var options: Options
|
var options: Options;
|
||||||
var removingNotifications: VariableType<boolean>;
|
var removingNotifications: VariableType<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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]);
|
const globalMousePosVar: VariableType<number[]> = Variable([0, 0]);
|
||||||
|
|
||||||
globalThis["globalMousePos"] = globalMousePosVar;
|
globalThis['globalMousePos'] = globalMousePosVar;
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
export const WIFI_STATUS_MAP = {
|
export const WIFI_STATUS_MAP = {
|
||||||
unknown: "Status Unknown",
|
unknown: 'Status Unknown',
|
||||||
unmanaged: "Unmanaged",
|
unmanaged: 'Unmanaged',
|
||||||
unavailable: "Unavailable",
|
unavailable: 'Unavailable',
|
||||||
disconnected: "Disconnected",
|
disconnected: 'Disconnected',
|
||||||
prepare: "Preparing Connecting",
|
prepare: 'Preparing Connecting',
|
||||||
config: "Connecting",
|
config: 'Connecting',
|
||||||
need_auth: "Needs Authentication",
|
need_auth: 'Needs Authentication',
|
||||||
ip_config: "Requesting IP",
|
ip_config: 'Requesting IP',
|
||||||
ip_check: "Checking Access",
|
ip_check: 'Checking Access',
|
||||||
secondaries: "Waiting on Secondaries",
|
secondaries: 'Waiting on Secondaries',
|
||||||
activated: "Connected",
|
activated: 'Connected',
|
||||||
deactivating: "Disconnecting",
|
deactivating: 'Disconnecting',
|
||||||
failed: "Connection Failed",
|
failed: 'Connection Failed',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +1,37 @@
|
|||||||
import icons from "modules/icons/index";
|
import icons from 'modules/icons/index';
|
||||||
import { Notification } from "types/service/notifications";
|
import { Notification } from 'types/service/notifications';
|
||||||
|
|
||||||
export const removingNotifications = Variable<boolean>(false);
|
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;
|
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)
|
icon = Utils.lookUpIcon(app_name)
|
||||||
? app_name
|
? app_name
|
||||||
: Utils.lookUpIcon(app_name.toLowerCase())
|
: 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;
|
icon = app_icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.lookUpIcon(app_entry || "") && icon === "") {
|
if (Utils.lookUpIcon(app_entry || '') && icon === '') {
|
||||||
icon = app_entry || "";
|
icon = app_entry || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return icon;
|
return icon;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const closeNotifications = async (notifications: Notification[]) => {
|
export const closeNotifications = async (notifications: Notification[]): Promise<void> => {
|
||||||
removingNotifications.value = true;
|
removingNotifications.value = true;
|
||||||
for (const notif of notifications) {
|
for (const notif of notifications) {
|
||||||
notif.close();
|
notif.close();
|
||||||
await new Promise(resolve => setTimeout(resolve, 100));
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||||
}
|
}
|
||||||
removingNotifications.value = false;
|
removingNotifications.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
globalThis["removingNotifications"] = removingNotifications;
|
globalThis['removingNotifications'] = removingNotifications;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import Gio from "gi://Gio"
|
import Gio from 'gi://Gio';
|
||||||
import { bash, Notify } from "lib/utils";
|
import { bash, Notify } from 'lib/utils';
|
||||||
import icons from "lib/icons"
|
import icons from 'lib/icons';
|
||||||
import { filterConfigForThemeOnly, loadJsonFile, saveConfigToFile } from "widget/settings/shared/FileChooser";
|
import { filterConfigForThemeOnly, loadJsonFile, saveConfigToFile } from 'widget/settings/shared/FileChooser';
|
||||||
|
|
||||||
export const hexColorPattern = /^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
|
export const hexColorPattern = /^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
|
||||||
|
|
||||||
globalThis.useTheme = (filePath: string): void => {
|
globalThis.useTheme = (filePath: string): void => {
|
||||||
let importedConfig = loadJsonFile(filePath);
|
const importedConfig = loadJsonFile(filePath);
|
||||||
|
|
||||||
if (!importedConfig) {
|
if (!importedConfig) {
|
||||||
return;
|
return;
|
||||||
@@ -16,22 +16,22 @@ globalThis.useTheme = (filePath: string): void => {
|
|||||||
summary: `Importing Theme`,
|
summary: `Importing Theme`,
|
||||||
body: `Importing: ${filePath}`,
|
body: `Importing: ${filePath}`,
|
||||||
iconName: icons.ui.info,
|
iconName: icons.ui.info,
|
||||||
timeout: 7000
|
timeout: 7000,
|
||||||
});
|
});
|
||||||
|
|
||||||
let tmpConfigFile = Gio.File.new_for_path(`${TMP}/config.json`);
|
const tmpConfigFile = Gio.File.new_for_path(`${TMP}/config.json`);
|
||||||
let optionsConfigFile = Gio.File.new_for_path(OPTIONS);
|
const optionsConfigFile = Gio.File.new_for_path(OPTIONS);
|
||||||
|
|
||||||
let [tmpSuccess, tmpContent] = tmpConfigFile.load_contents(null);
|
const [tmpSuccess, tmpContent] = tmpConfigFile.load_contents(null);
|
||||||
let [optionsSuccess, optionsContent] = optionsConfigFile.load_contents(null);
|
const [optionsSuccess, optionsContent] = optionsConfigFile.load_contents(null);
|
||||||
|
|
||||||
if (!tmpSuccess || !optionsSuccess) {
|
if (!tmpSuccess || !optionsSuccess) {
|
||||||
console.error("Failed to read existing configuration files.");
|
console.error('Failed to read existing configuration files.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let tmpConfig = JSON.parse(new TextDecoder("utf-8").decode(tmpContent));
|
let tmpConfig = JSON.parse(new TextDecoder('utf-8').decode(tmpContent));
|
||||||
let optionsConfig = JSON.parse(new TextDecoder("utf-8").decode(optionsContent));
|
let optionsConfig = JSON.parse(new TextDecoder('utf-8').decode(optionsContent));
|
||||||
|
|
||||||
const filteredConfig = filterConfigForThemeOnly(importedConfig);
|
const filteredConfig = filterConfigForThemeOnly(importedConfig);
|
||||||
tmpConfig = { ...tmpConfig, ...filteredConfig };
|
tmpConfig = { ...tmpConfig, ...filteredConfig };
|
||||||
@@ -39,6 +39,5 @@ globalThis.useTheme = (filePath: string): void => {
|
|||||||
|
|
||||||
saveConfigToFile(tmpConfig, `${TMP}/config.json`);
|
saveConfigToFile(tmpConfig, `${TMP}/config.json`);
|
||||||
saveConfigToFile(optionsConfig, OPTIONS);
|
saveConfigToFile(optionsConfig, OPTIONS);
|
||||||
bash("pkill ags && ags");
|
bash('pkill ags && ags');
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { Opt } from "lib/option";
|
import { Opt } from 'lib/option';
|
||||||
import { HexColor, RecursiveOptionsObject } from "lib/types/options";
|
import { HexColor, RecursiveOptionsObject } from 'lib/types/options';
|
||||||
|
|
||||||
export const isOpt = <T>(value: unknown): value is Opt<T> =>
|
export const isOpt = <T>(value: unknown): value is Opt<T> =>
|
||||||
typeof value === 'object' && value !== null && 'value' in value && value instanceof Opt;
|
typeof value === 'object' && value !== null && 'value' in value && value instanceof Opt;
|
||||||
|
|
||||||
export const isRecursiveOptionsObject = (value: unknown): value is RecursiveOptionsObject => {
|
export const isRecursiveOptionsObject = (value: unknown): value is RecursiveOptionsObject => {
|
||||||
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const isHexColor = (value: string): value is HexColor => {
|
export const isHexColor = (value: string): value is HexColor => {
|
||||||
return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value);
|
return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value);
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import options from "options";
|
import options from 'options';
|
||||||
import { UnitType, Weather, WeatherIconTitle, WeatherIcon } from "lib/types/weather.js";
|
import { UnitType, Weather, WeatherIconTitle, WeatherIcon } from 'lib/types/weather.js';
|
||||||
import { DEFAULT_WEATHER } from "lib/types/defaults/weather.js";
|
import { DEFAULT_WEATHER } from 'lib/types/defaults/weather.js';
|
||||||
import GLib from "gi://GLib?version=2.0";
|
import GLib from 'gi://GLib?version=2.0';
|
||||||
import { weatherIcons } from "modules/icons/weather.js";
|
import { weatherIcons } from 'modules/icons/weather.js';
|
||||||
|
|
||||||
const { key, interval, location } = options.menus.clock.weather;
|
const { key, interval, location } = options.menus.clock.weather;
|
||||||
|
|
||||||
@@ -10,12 +10,12 @@ export const globalWeatherVar = Variable<Weather>(DEFAULT_WEATHER);
|
|||||||
|
|
||||||
let weatherIntervalInstance: null | number = null;
|
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) {
|
if (weatherIntervalInstance !== null) {
|
||||||
GLib.source_remove(weatherIntervalInstance);
|
GLib.source_remove(weatherIntervalInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
const formattedLocation = loc.replace(" ", "%20");
|
const formattedLocation = loc.replace(' ', '%20');
|
||||||
|
|
||||||
weatherIntervalInstance = Utils.interval(weatherInterval, () => {
|
weatherIntervalInstance = Utils.interval(weatherInterval, () => {
|
||||||
Utils.execAsync(
|
Utils.execAsync(
|
||||||
@@ -23,13 +23,13 @@ const weatherIntervalFn = (weatherInterval: number, loc: string, weatherKey: str
|
|||||||
)
|
)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
try {
|
try {
|
||||||
if (typeof res !== "string") {
|
if (typeof res !== 'string') {
|
||||||
return (globalWeatherVar.value = DEFAULT_WEATHER);
|
return (globalWeatherVar.value = DEFAULT_WEATHER);
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedWeather = JSON.parse(res);
|
const parsedWeather = JSON.parse(res);
|
||||||
|
|
||||||
if (Object.keys(parsedWeather).includes("error")) {
|
if (Object.keys(parsedWeather).includes('error')) {
|
||||||
return (globalWeatherVar.value = DEFAULT_WEATHER);
|
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) {
|
if (!weatherKey) {
|
||||||
return (globalWeatherVar.value = DEFAULT_WEATHER);
|
return (globalWeatherVar.value = DEFAULT_WEATHER);
|
||||||
}
|
}
|
||||||
weatherIntervalFn(weatherInterval, loc, weatherKey);
|
weatherIntervalFn(weatherInterval, loc, weatherKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getTemperature = (wthr: Weather, unt: UnitType) => {
|
export const getTemperature = (wthr: Weather, unt: UnitType): string => {
|
||||||
if (unt === "imperial") {
|
if (unt === 'imperial') {
|
||||||
return `${Math.ceil(wthr.current.temp_f)}° F`;
|
return `${Math.ceil(wthr.current.temp_f)}° F`;
|
||||||
} else {
|
} else {
|
||||||
return `${Math.ceil(wthr.current.temp_c)}° C`;
|
return `${Math.ceil(wthr.current.temp_c)}° C`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getWeatherIcon = (fahren: number) => {
|
export const getWeatherIcon = (fahren: number): Record<string, string> => {
|
||||||
const icons = {
|
const icons = {
|
||||||
100: "",
|
100: '',
|
||||||
75: "",
|
75: '',
|
||||||
50: "",
|
50: '',
|
||||||
25: "",
|
25: '',
|
||||||
0: "",
|
0: '',
|
||||||
} as const;
|
} as const;
|
||||||
const colors = {
|
const colors = {
|
||||||
100: "weather-color red",
|
100: 'weather-color red',
|
||||||
75: "weather-color orange",
|
75: 'weather-color orange',
|
||||||
50: "weather-color lavender",
|
50: 'weather-color lavender',
|
||||||
25: "weather-color blue",
|
25: 'weather-color blue',
|
||||||
0: "weather-color sky",
|
0: 'weather-color sky',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
type IconKeys = keyof typeof icons;
|
type IconKeys = keyof typeof icons;
|
||||||
|
|
||||||
const threshold: IconKeys =
|
const threshold: IconKeys =
|
||||||
fahren < 0
|
fahren < 0 ? 0 : ([100, 75, 50, 25, 0] as IconKeys[]).find((threshold) => threshold <= fahren) || 0;
|
||||||
? 0
|
|
||||||
: ([100, 75, 50, 25, 0] as IconKeys[]).find((threshold) => threshold <= fahren) || 0;
|
|
||||||
|
|
||||||
const icon = icons[threshold || 50];
|
const icon = icons[threshold || 50];
|
||||||
const color = colors[threshold || 50];
|
const color = colors[threshold || 50];
|
||||||
@@ -93,35 +91,32 @@ export const getWeatherIcon = (fahren: number) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getWindConditions = (wthr: Weather, unt: UnitType) => {
|
export const getWindConditions = (wthr: Weather, unt: UnitType): string => {
|
||||||
if (unt === "imperial") {
|
if (unt === 'imperial') {
|
||||||
return `${Math.floor(wthr.current.wind_mph)} mph`;
|
return `${Math.floor(wthr.current.wind_mph)} mph`;
|
||||||
}
|
}
|
||||||
return `${Math.floor(wthr.current.wind_kph)} kph`;
|
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 => {
|
export const isValidWeatherIconTitle = (title: string): title is WeatherIconTitle => {
|
||||||
return title in weatherIcons;
|
return title in weatherIcons;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getWeatherStatusTextIcon = (wthr: Weather): WeatherIcon => {
|
export const getWeatherStatusTextIcon = (wthr: Weather): WeatherIcon => {
|
||||||
let iconQuery = wthr.current.condition.text
|
let iconQuery = wthr.current.condition.text.trim().toLowerCase().replaceAll(' ', '_');
|
||||||
.trim()
|
|
||||||
.toLowerCase()
|
|
||||||
.replaceAll(" ", "_");
|
|
||||||
|
|
||||||
if (!wthr.current.is_day && iconQuery === "partly_cloudy") {
|
if (!wthr.current.is_day && iconQuery === 'partly_cloudy') {
|
||||||
iconQuery = "partly_cloudy_night";
|
iconQuery = 'partly_cloudy_night';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isValidWeatherIconTitle(iconQuery)) {
|
if (isValidWeatherIconTitle(iconQuery)) {
|
||||||
return weatherIcons[iconQuery];
|
return weatherIcons[iconQuery];
|
||||||
} else {
|
} else {
|
||||||
console.warn(`Unknown weather icon title: ${iconQuery}`);
|
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',
|
'top-left',
|
||||||
'bottom-left',
|
'bottom-left',
|
||||||
'bottom-center',
|
'bottom-center',
|
||||||
'bottom-right'
|
'bottom-right',
|
||||||
];
|
];
|
||||||
|
|||||||
182
lib/icons.ts
182
lib/icons.ts
@@ -1,145 +1,145 @@
|
|||||||
export const substitutes = {
|
export const substitutes = {
|
||||||
"transmission-gtk": "transmission",
|
'transmission-gtk': 'transmission',
|
||||||
"blueberry.py": "blueberry",
|
'blueberry.py': 'blueberry',
|
||||||
"Caprine": "facebook-messenger",
|
Caprine: 'facebook-messenger',
|
||||||
"com.raggesilver.BlackBox-symbolic": "terminal-symbolic",
|
'com.raggesilver.BlackBox-symbolic': 'terminal-symbolic',
|
||||||
"org.wezfurlong.wezterm-symbolic": "terminal-symbolic",
|
'org.wezfurlong.wezterm-symbolic': 'terminal-symbolic',
|
||||||
"audio-headset-bluetooth": "audio-headphones-symbolic",
|
'audio-headset-bluetooth': 'audio-headphones-symbolic',
|
||||||
"audio-card-analog-usb": "audio-speakers-symbolic",
|
'audio-card-analog-usb': 'audio-speakers-symbolic',
|
||||||
"audio-card-analog-pci": "audio-card-symbolic",
|
'audio-card-analog-pci': 'audio-card-symbolic',
|
||||||
"preferences-system": "emblem-system-symbolic",
|
'preferences-system': 'emblem-system-symbolic',
|
||||||
"com.github.Aylur.ags-symbolic": "controls-symbolic",
|
'com.github.Aylur.ags-symbolic': 'controls-symbolic',
|
||||||
"com.github.Aylur.ags": "controls-symbolic",
|
'com.github.Aylur.ags': 'controls-symbolic',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
missing: "image-missing-symbolic",
|
missing: 'image-missing-symbolic',
|
||||||
nix: {
|
nix: {
|
||||||
nix: "nix-snowflake-symbolic",
|
nix: 'nix-snowflake-symbolic',
|
||||||
},
|
},
|
||||||
app: {
|
app: {
|
||||||
terminal: "terminal-symbolic",
|
terminal: 'terminal-symbolic',
|
||||||
},
|
},
|
||||||
fallback: {
|
fallback: {
|
||||||
executable: "application-x-executable",
|
executable: 'application-x-executable',
|
||||||
notification: "dialog-information-symbolic",
|
notification: 'dialog-information-symbolic',
|
||||||
video: "video-x-generic-symbolic",
|
video: 'video-x-generic-symbolic',
|
||||||
audio: "audio-x-generic-symbolic",
|
audio: 'audio-x-generic-symbolic',
|
||||||
},
|
},
|
||||||
ui: {
|
ui: {
|
||||||
close: "window-close-symbolic",
|
close: 'window-close-symbolic',
|
||||||
colorpicker: "color-select-symbolic",
|
colorpicker: 'color-select-symbolic',
|
||||||
info: "info-symbolic",
|
info: 'info-symbolic',
|
||||||
link: "external-link-symbolic",
|
link: 'external-link-symbolic',
|
||||||
lock: "system-lock-screen-symbolic",
|
lock: 'system-lock-screen-symbolic',
|
||||||
menu: "open-menu-symbolic",
|
menu: 'open-menu-symbolic',
|
||||||
refresh: "view-refresh-symbolic",
|
refresh: 'view-refresh-symbolic',
|
||||||
search: "system-search-symbolic",
|
search: 'system-search-symbolic',
|
||||||
settings: "emblem-system-symbolic",
|
settings: 'emblem-system-symbolic',
|
||||||
themes: "preferences-desktop-theme-symbolic",
|
themes: 'preferences-desktop-theme-symbolic',
|
||||||
tick: "object-select-symbolic",
|
tick: 'object-select-symbolic',
|
||||||
time: "hourglass-symbolic",
|
time: 'hourglass-symbolic',
|
||||||
toolbars: "toolbars-symbolic",
|
toolbars: 'toolbars-symbolic',
|
||||||
warning: "dialog-warning-symbolic",
|
warning: 'dialog-warning-symbolic',
|
||||||
avatar: "avatar-default-symbolic",
|
avatar: 'avatar-default-symbolic',
|
||||||
arrow: {
|
arrow: {
|
||||||
right: "pan-end-symbolic",
|
right: 'pan-end-symbolic',
|
||||||
left: "pan-start-symbolic",
|
left: 'pan-start-symbolic',
|
||||||
down: "pan-down-symbolic",
|
down: 'pan-down-symbolic',
|
||||||
up: "pan-up-symbolic",
|
up: 'pan-up-symbolic',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
audio: {
|
audio: {
|
||||||
mic: {
|
mic: {
|
||||||
muted: "microphone-disabled-symbolic",
|
muted: 'microphone-disabled-symbolic',
|
||||||
low: "microphone-sensitivity-low-symbolic",
|
low: 'microphone-sensitivity-low-symbolic',
|
||||||
medium: "microphone-sensitivity-medium-symbolic",
|
medium: 'microphone-sensitivity-medium-symbolic',
|
||||||
high: "microphone-sensitivity-high-symbolic",
|
high: 'microphone-sensitivity-high-symbolic',
|
||||||
},
|
},
|
||||||
volume: {
|
volume: {
|
||||||
muted: "audio-volume-muted-symbolic",
|
muted: 'audio-volume-muted-symbolic',
|
||||||
low: "audio-volume-low-symbolic",
|
low: 'audio-volume-low-symbolic',
|
||||||
medium: "audio-volume-medium-symbolic",
|
medium: 'audio-volume-medium-symbolic',
|
||||||
high: "audio-volume-high-symbolic",
|
high: 'audio-volume-high-symbolic',
|
||||||
overamplified: "audio-volume-overamplified-symbolic",
|
overamplified: 'audio-volume-overamplified-symbolic',
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
headset: "audio-headphones-symbolic",
|
headset: 'audio-headphones-symbolic',
|
||||||
speaker: "audio-speakers-symbolic",
|
speaker: 'audio-speakers-symbolic',
|
||||||
card: "audio-card-symbolic",
|
card: 'audio-card-symbolic',
|
||||||
},
|
},
|
||||||
mixer: "mixer-symbolic",
|
mixer: 'mixer-symbolic',
|
||||||
},
|
},
|
||||||
powerprofile: {
|
powerprofile: {
|
||||||
balanced: "power-profile-balanced-symbolic",
|
balanced: 'power-profile-balanced-symbolic',
|
||||||
"power-saver": "power-profile-power-saver-symbolic",
|
'power-saver': 'power-profile-power-saver-symbolic',
|
||||||
performance: "power-profile-performance-symbolic",
|
performance: 'power-profile-performance-symbolic',
|
||||||
},
|
},
|
||||||
asusctl: {
|
asusctl: {
|
||||||
profile: {
|
profile: {
|
||||||
Balanced: "power-profile-balanced-symbolic",
|
Balanced: 'power-profile-balanced-symbolic',
|
||||||
Quiet: "power-profile-power-saver-symbolic",
|
Quiet: 'power-profile-power-saver-symbolic',
|
||||||
Performance: "power-profile-performance-symbolic",
|
Performance: 'power-profile-performance-symbolic',
|
||||||
},
|
},
|
||||||
mode: {
|
mode: {
|
||||||
Integrated: "processor-symbolic",
|
Integrated: 'processor-symbolic',
|
||||||
Hybrid: "controller-symbolic",
|
Hybrid: 'controller-symbolic',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
battery: {
|
battery: {
|
||||||
charging: "battery-flash-symbolic",
|
charging: 'battery-flash-symbolic',
|
||||||
warning: "battery-empty-symbolic",
|
warning: 'battery-empty-symbolic',
|
||||||
},
|
},
|
||||||
bluetooth: {
|
bluetooth: {
|
||||||
enabled: "bluetooth-active-symbolic",
|
enabled: 'bluetooth-active-symbolic',
|
||||||
disabled: "bluetooth-disabled-symbolic",
|
disabled: 'bluetooth-disabled-symbolic',
|
||||||
},
|
},
|
||||||
brightness: {
|
brightness: {
|
||||||
indicator: "display-brightness-symbolic",
|
indicator: 'display-brightness-symbolic',
|
||||||
keyboard: "keyboard-brightness-symbolic",
|
keyboard: 'keyboard-brightness-symbolic',
|
||||||
screen: "display-brightness-symbolic",
|
screen: 'display-brightness-symbolic',
|
||||||
},
|
},
|
||||||
powermenu: {
|
powermenu: {
|
||||||
sleep: "weather-clear-night-symbolic",
|
sleep: 'weather-clear-night-symbolic',
|
||||||
reboot: "system-reboot-symbolic",
|
reboot: 'system-reboot-symbolic',
|
||||||
logout: "system-log-out-symbolic",
|
logout: 'system-log-out-symbolic',
|
||||||
shutdown: "system-shutdown-symbolic",
|
shutdown: 'system-shutdown-symbolic',
|
||||||
},
|
},
|
||||||
recorder: {
|
recorder: {
|
||||||
recording: "media-record-symbolic",
|
recording: 'media-record-symbolic',
|
||||||
},
|
},
|
||||||
notifications: {
|
notifications: {
|
||||||
noisy: "org.gnome.Settings-notifications-symbolic",
|
noisy: 'org.gnome.Settings-notifications-symbolic',
|
||||||
silent: "notifications-disabled-symbolic",
|
silent: 'notifications-disabled-symbolic',
|
||||||
message: "chat-bubbles-symbolic",
|
message: 'chat-bubbles-symbolic',
|
||||||
},
|
},
|
||||||
trash: {
|
trash: {
|
||||||
full: "user-trash-full-symbolic",
|
full: 'user-trash-full-symbolic',
|
||||||
empty: "user-trash-symbolic",
|
empty: 'user-trash-symbolic',
|
||||||
},
|
},
|
||||||
mpris: {
|
mpris: {
|
||||||
shuffle: {
|
shuffle: {
|
||||||
enabled: "media-playlist-shuffle-symbolic",
|
enabled: 'media-playlist-shuffle-symbolic',
|
||||||
disabled: "media-playlist-consecutive-symbolic",
|
disabled: 'media-playlist-consecutive-symbolic',
|
||||||
},
|
},
|
||||||
loop: {
|
loop: {
|
||||||
none: "media-playlist-repeat-symbolic",
|
none: 'media-playlist-repeat-symbolic',
|
||||||
track: "media-playlist-repeat-song-symbolic",
|
track: 'media-playlist-repeat-song-symbolic',
|
||||||
playlist: "media-playlist-repeat-symbolic",
|
playlist: 'media-playlist-repeat-symbolic',
|
||||||
},
|
},
|
||||||
playing: "media-playback-pause-symbolic",
|
playing: 'media-playback-pause-symbolic',
|
||||||
paused: "media-playback-start-symbolic",
|
paused: 'media-playback-start-symbolic',
|
||||||
stopped: "media-playback-start-symbolic",
|
stopped: 'media-playback-start-symbolic',
|
||||||
prev: "media-skip-backward-symbolic",
|
prev: 'media-skip-backward-symbolic',
|
||||||
next: "media-skip-forward-symbolic",
|
next: 'media-skip-forward-symbolic',
|
||||||
},
|
},
|
||||||
system: {
|
system: {
|
||||||
cpu: "org.gnome.SystemMonitor-symbolic",
|
cpu: 'org.gnome.SystemMonitor-symbolic',
|
||||||
ram: "drive-harddisk-solidstate-symbolic",
|
ram: 'drive-harddisk-solidstate-symbolic',
|
||||||
temp: "temperature-symbolic",
|
temp: 'temperature-symbolic',
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
dark: "dark-mode-symbolic",
|
dark: 'dark-mode-symbolic',
|
||||||
light: "light-mode-symbolic",
|
light: 'light-mode-symbolic',
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
150
lib/option.ts
150
lib/option.ts
@@ -1,70 +1,73 @@
|
|||||||
import { isHexColor } from "globals/variables"
|
import { isHexColor } from 'globals/variables';
|
||||||
import { Variable } from "resource:///com/github/Aylur/ags/variable.js"
|
import { Variable } from 'resource:///com/github/Aylur/ags/variable.js';
|
||||||
|
import { MkOptionsResult } from './types/options';
|
||||||
|
|
||||||
type OptProps = {
|
type OptProps = {
|
||||||
persistent?: boolean
|
persistent?: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
export class Opt<T = unknown> extends Variable<T> {
|
export class Opt<T = unknown> extends Variable<T> {
|
||||||
static { Service.register(this) }
|
static {
|
||||||
|
Service.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
constructor(initial: T, { persistent = false }: OptProps = {}) {
|
constructor(initial: T, { persistent = false }: OptProps = {}) {
|
||||||
super(initial)
|
super(initial);
|
||||||
this.initial = initial
|
this.initial = initial;
|
||||||
this.persistent = persistent
|
this.persistent = persistent;
|
||||||
}
|
}
|
||||||
|
|
||||||
initial: T
|
initial: T;
|
||||||
id = ""
|
id = '';
|
||||||
persistent: boolean
|
persistent: boolean;
|
||||||
toString() { return `${this.value}` }
|
toString(): string {
|
||||||
toJSON() { return `opt:${this.value}` }
|
return `${this.value}`;
|
||||||
|
}
|
||||||
|
toJSON(): string {
|
||||||
|
return `opt:${this.value}`;
|
||||||
|
}
|
||||||
|
|
||||||
getValue = (): T => {
|
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) {
|
reset(): string | undefined {
|
||||||
const cacheV = JSON.parse(Utils.readFile(cacheFile) || "{}")[this.id]
|
if (this.persistent) return;
|
||||||
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;
|
|
||||||
|
|
||||||
if (JSON.stringify(this.value) !== JSON.stringify(this.initial)) {
|
if (JSON.stringify(this.value) !== JSON.stringify(this.initial)) {
|
||||||
this.value = this.initial
|
this.value = this.initial;
|
||||||
return this.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doResetColor() {
|
doResetColor(): string | undefined {
|
||||||
if (this.persistent)
|
if (this.persistent) return;
|
||||||
return;
|
|
||||||
|
|
||||||
const isColor = isHexColor(this.value as string);
|
const isColor = isHexColor(this.value as string);
|
||||||
if ((JSON.stringify(this.value) !== JSON.stringify(this.initial)) && isColor) {
|
if (JSON.stringify(this.value) !== JSON.stringify(this.initial) && isColor) {
|
||||||
this.value = this.initial
|
this.value = this.initial;
|
||||||
return this.id
|
return this.id;
|
||||||
}
|
}
|
||||||
return;
|
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[] {
|
const getOptions = (object: Record<string, unknown>, path = ''): Opt[] => {
|
||||||
return Object.keys(object).flatMap(key => {
|
return Object.keys(object).flatMap((key) => {
|
||||||
const obj = object[key];
|
const obj = object[key];
|
||||||
const id = path ? path + "." + key : key;
|
const id = path ? path + '.' + key : key;
|
||||||
|
|
||||||
if (obj instanceof Variable) {
|
if (obj instanceof Variable) {
|
||||||
const optValue = obj as Opt;
|
const optValue = obj as Opt;
|
||||||
@@ -72,74 +75,73 @@ function getOptions(object: Record<string, unknown>, path = ""): Opt[] {
|
|||||||
return optValue;
|
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 getOptions(obj as Record<string, unknown>, id); // Recursively process nested objects
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function mkOptions<T extends object>(cacheFile: string, object: T, confFile: string = "config.json") {
|
export function mkOptions<T extends object>(
|
||||||
for (const opt of getOptions(object as Record<string, unknown>))
|
cacheFile: string,
|
||||||
opt.init(cacheFile)
|
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 configFile = `${TMP}/${confFile}`;
|
||||||
const values = getOptions(object as Record<string, unknown>).reduce((obj, { id, value }) => ({ [id]: value, ...obj }), {})
|
const values = getOptions(object as Record<string, unknown>).reduce(
|
||||||
Utils.writeFileSync(JSON.stringify(values, null, 2), configFile)
|
(obj, { id, value }) => ({ [id]: value, ...obj }),
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
Utils.writeFileSync(JSON.stringify(values, null, 2), configFile);
|
||||||
Utils.monitorFile(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>)) {
|
for (const opt of getOptions(object as Record<string, unknown>)) {
|
||||||
if (JSON.stringify(cache[opt.id]) !== JSON.stringify(opt.value))
|
if (JSON.stringify(cache[opt.id]) !== JSON.stringify(opt.value)) opt.value = cache[opt.id];
|
||||||
opt.value = cache[opt.id]
|
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
function sleep(ms = 0): Promise<T> {
|
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>),
|
[opt, ...list] = getOptions(object as Record<string, unknown>),
|
||||||
id = opt?.reset(),
|
id = opt?.reset(),
|
||||||
): Promise<Array<string>> {
|
): Promise<Array<string>> => {
|
||||||
if (!opt)
|
if (!opt) return sleep().then(() => []);
|
||||||
return sleep().then(() => [])
|
|
||||||
|
|
||||||
return id
|
return id ? [id, ...(await sleep(50).then(() => reset(list)))] : await sleep().then(() => reset(list));
|
||||||
? [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>),
|
[opt, ...list] = getOptions(object as Record<string, unknown>),
|
||||||
id = opt?.doResetColor(),
|
id = opt?.doResetColor(),
|
||||||
): Promise<Array<string>> {
|
): Promise<Array<string>> => {
|
||||||
if (!opt)
|
if (!opt) return sleep().then(() => []);
|
||||||
return sleep().then(() => [])
|
|
||||||
|
|
||||||
return id
|
return id
|
||||||
? [id, ...(await sleep(50).then(() => resetTheme(list)))]
|
? [id, ...(await sleep(50).then(() => resetTheme(list)))]
|
||||||
: await sleep().then(() => resetTheme(list))
|
: await sleep().then(() => resetTheme(list));
|
||||||
}
|
};
|
||||||
|
|
||||||
return Object.assign(object, {
|
return Object.assign(object, {
|
||||||
configFile,
|
configFile,
|
||||||
array: () => getOptions(object as Record<string, unknown>),
|
array: () => getOptions(object as Record<string, unknown>),
|
||||||
async reset() {
|
async reset() {
|
||||||
return (await reset()).join("\n")
|
return (await reset()).join('\n');
|
||||||
},
|
},
|
||||||
async resetTheme() {
|
async resetTheme() {
|
||||||
return (await resetTheme()).join("\n")
|
return (await resetTheme()).join('\n');
|
||||||
},
|
},
|
||||||
handler(deps: string[], callback: () => void) {
|
handler(deps: string[], callback: () => void) {
|
||||||
for (const opt of getOptions(object as Record<string, unknown>)) {
|
for (const opt of getOptions(object as Record<string, unknown>)) {
|
||||||
if (deps.some(i => opt.id.startsWith(i)))
|
if (deps.some((i) => opt.id.startsWith(i))) opt.connect('changed', callback);
|
||||||
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 {
|
declare global {
|
||||||
const OPTIONS: string
|
const OPTIONS: string;
|
||||||
const TMP: string
|
const TMP: string;
|
||||||
const USER: string
|
const USER: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(globalThis, {
|
Object.assign(globalThis, {
|
||||||
OPTIONS: `${GLib.get_user_cache_dir()}/ags/hyprpanel/options.json`,
|
OPTIONS: `${GLib.get_user_cache_dir()}/ags/hyprpanel/options.json`,
|
||||||
TMP: `${GLib.get_tmp_dir()}/ags/hyprpanel`,
|
TMP: `${GLib.get_tmp_dir()}/ags/hyprpanel`,
|
||||||
USER: GLib.get_user_name(),
|
USER: GLib.get_user_name(),
|
||||||
})
|
});
|
||||||
|
|
||||||
Utils.ensureDirectory(TMP)
|
Utils.ensureDirectory(TMP);
|
||||||
App.addIcons(`${App.configDir}/assets`)
|
App.addIcons(`${App.configDir}/assets`);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { MprisPlayer } from "types/service/mpris";
|
import { MprisPlayer } from 'types/service/mpris';
|
||||||
const mpris = await Service.import("mpris");
|
const mpris = await Service.import('mpris');
|
||||||
|
|
||||||
export const getCurrentPlayer = (activePlayer: MprisPlayer = mpris.players[0]): MprisPlayer => {
|
export const getCurrentPlayer = (activePlayer: MprisPlayer = mpris.players[0]): MprisPlayer => {
|
||||||
const statusOrder = {
|
const statusOrder = {
|
||||||
@@ -12,18 +12,12 @@ export const getCurrentPlayer = (activePlayer: MprisPlayer = mpris.players[0]):
|
|||||||
return mpris.players[0];
|
return mpris.players[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPlaying = mpris.players.some(
|
const isPlaying = mpris.players.some((p: MprisPlayer) => p.play_back_status === 'Playing');
|
||||||
(p: MprisPlayer) => p.play_back_status === "Playing",
|
|
||||||
);
|
|
||||||
|
|
||||||
const playerStillExists = mpris.players.some(
|
const playerStillExists = mpris.players.some((p) => activePlayer.bus_name === p.bus_name);
|
||||||
(p) => activePlayer.bus_name === p.bus_name
|
|
||||||
);
|
|
||||||
|
|
||||||
const nextPlayerUp = mpris.players.sort(
|
const nextPlayerUp = mpris.players.sort(
|
||||||
(a: MprisPlayer, b: MprisPlayer) =>
|
(a: MprisPlayer, b: MprisPlayer) => statusOrder[a.play_back_status] - statusOrder[b.play_back_status],
|
||||||
statusOrder[a.play_back_status] -
|
|
||||||
statusOrder[b.play_back_status],
|
|
||||||
)[0];
|
)[0];
|
||||||
|
|
||||||
if (isPlaying || !playerStillExists) {
|
if (isPlaying || !playerStillExists) {
|
||||||
@@ -31,4 +25,4 @@ export const getCurrentPlayer = (activePlayer: MprisPlayer = mpris.players[0]):
|
|||||||
}
|
}
|
||||||
|
|
||||||
return activePlayer;
|
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[] => {
|
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 filteredNotifications = notifications.filter((notif: Notification) => {
|
||||||
const normalizedAppName = notif.app_name.toLowerCase().replace(/\s+/g, '_');
|
const normalizedAppName = notif.app_name.toLowerCase().replace(/\s+/g, '_');
|
||||||
@@ -12,4 +9,4 @@ export const filterNotifications = (notifications: Notification[], filter: strin
|
|||||||
});
|
});
|
||||||
|
|
||||||
return filteredNotifications;
|
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 { Binding, Connectable } from 'types/service';
|
||||||
import { Variable } from "types/variable"
|
import { Variable } from 'types/variable';
|
||||||
import Box from "types/widgets/box";
|
import Box from 'types/widgets/box';
|
||||||
import Label from "types/widgets/label";
|
import Button from 'types/widgets/button';
|
||||||
import { Widget as WidgetType } from "types/widgets/widget"
|
import Label from 'types/widgets/label';
|
||||||
|
import { Attribute, Child } from './widget';
|
||||||
|
|
||||||
export type Child = {
|
export type BarBoxChild = {
|
||||||
component: Box<Gtk.Widget, unknown>;
|
component: Box<Gtk.Widget, unknown>;
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
isVis?: Variable<boolean>;
|
isVis?: Variable<boolean>;
|
||||||
boxClass: string;
|
boxClass: string;
|
||||||
props: ButtonProps;
|
} & ButtonProps;
|
||||||
};
|
|
||||||
|
export type SelfButton = Button<Child, Attribute>;
|
||||||
|
|
||||||
export type BoxHook = (self: Box<Gtk.Widget, Gtk.Widget>) => void;
|
export type BoxHook = (self: Box<Gtk.Widget, Gtk.Widget>) => void;
|
||||||
export type LabelHook = (self: Label<Gtk.Widget>) => void;
|
export type LabelHook = (self: Label<Gtk.Widget>) => void;
|
||||||
|
|
||||||
export type Module = {
|
export type Module = {
|
||||||
icon?: string | Binding<string>,
|
icon?: string | Binding<string>;
|
||||||
textIcon?: string | Binding<string>,
|
textIcon?: string | Binding<string>;
|
||||||
label?: string | Binding<string>,
|
label?: string | Binding<string>;
|
||||||
labelHook?: LabelHook,
|
labelHook?: LabelHook;
|
||||||
boundLabel?: string,
|
boundLabel?: string;
|
||||||
tooltipText?: string | Binding<string>,
|
tooltipText?: string | Binding<string>;
|
||||||
boxClass: string,
|
boxClass: string;
|
||||||
props?: ButtonProps,
|
props?: ButtonProps;
|
||||||
showLabel?: boolean,
|
showLabel?: boolean;
|
||||||
showLabelBinding?: Binding,
|
showLabelBinding?: Binding;
|
||||||
hook?: BoxHook,
|
hook?: BoxHook;
|
||||||
connection?: Binding<Connectable>
|
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 NetstatIcon = '' | '' | '' | '' | '' | '' | '' | '' | '';
|
||||||
export type NetstatLabelType = "full" | "in" | "out";
|
export type NetstatLabelType = 'full' | 'in' | 'out';
|
||||||
export type RateUnit = "GiB" | "MiB" | "KiB" | "auto";
|
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;
|
total: number;
|
||||||
used: number;
|
used: number;
|
||||||
free: number;
|
|
||||||
percentage: 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 KbLabelType = 'layout' | 'code';
|
||||||
export type KbIcon = "" | "" | "" | "" | "";
|
export type KbIcon = '' | '' | '' | '' | '';
|
||||||
|
|
||||||
export type HyprctlKeyboard = {
|
export type HyprctlKeyboard = {
|
||||||
address: string;
|
address: string;
|
||||||
@@ -24,10 +24,10 @@ export type HyprctlMouse = {
|
|||||||
export type HyprctlDeviceLayout = {
|
export type HyprctlDeviceLayout = {
|
||||||
mice: HyprctlMouse[];
|
mice: HyprctlMouse[];
|
||||||
keyboards: HyprctlKeyboard[];
|
keyboards: HyprctlKeyboard[];
|
||||||
tablets: any[];
|
tablets: unknown[];
|
||||||
touch: any[];
|
touch: unknown[];
|
||||||
switches: any[];
|
switches: unknown[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LayoutKeys = keyof typeof layoutMap;
|
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 = {
|
export type NetworkResourceData = {
|
||||||
in: string;
|
in: string;
|
||||||
out: 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 = {
|
export type InputHandlerEvents = {
|
||||||
onPrimaryClick?: Binding,
|
onPrimaryClick?: Binding;
|
||||||
onSecondaryClick?: Binding,
|
onSecondaryClick?: Binding;
|
||||||
onMiddleClick?: Binding,
|
onMiddleClick?: Binding;
|
||||||
onScrollUp?: Binding,
|
onScrollUp?: Binding;
|
||||||
onScrollDown?: 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 { RateUnit } from '../bar';
|
||||||
import { NetworkResourceData } from "../customModules/network";
|
import { NetworkResourceData } from '../customModules/network';
|
||||||
|
|
||||||
export const GET_DEFAULT_NETSTAT_DATA = (dataType: RateUnit): NetworkResourceData => {
|
export const GET_DEFAULT_NETSTAT_DATA = (dataType: RateUnit): NetworkResourceData => {
|
||||||
if (dataType === 'auto') {
|
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 = {
|
export const defaultColorMap = {
|
||||||
"rosewater": "#f5e0dc",
|
rosewater: '#f5e0dc',
|
||||||
"flamingo": "#f2cdcd",
|
flamingo: '#f2cdcd',
|
||||||
"pink": "#f5c2e7",
|
pink: '#f5c2e7',
|
||||||
"mauve": "#cba6f7",
|
mauve: '#cba6f7',
|
||||||
"red": "#f38ba8",
|
red: '#f38ba8',
|
||||||
"maroon": "#eba0ac",
|
maroon: '#eba0ac',
|
||||||
"peach": "#fab387",
|
peach: '#fab387',
|
||||||
"yellow": "#f9e2af",
|
yellow: '#f9e2af',
|
||||||
"green": "#a6e3a1",
|
green: '#a6e3a1',
|
||||||
"teal": "#94e2d5",
|
teal: '#94e2d5',
|
||||||
"sky": "#89dceb",
|
sky: '#89dceb',
|
||||||
"sapphire": "#74c7ec",
|
sapphire: '#74c7ec',
|
||||||
"blue": "#89b4fa",
|
blue: '#89b4fa',
|
||||||
"lavender": "#b4befe",
|
lavender: '#b4befe',
|
||||||
"text": "#cdd6f4",
|
text: '#cdd6f4',
|
||||||
"subtext1": "#bac2de",
|
subtext1: '#bac2de',
|
||||||
"subtext2": "#a6adc8",
|
subtext2: '#a6adc8',
|
||||||
"overlay2": "#9399b2",
|
overlay2: '#9399b2',
|
||||||
"overlay1": "#7f849c",
|
overlay1: '#7f849c',
|
||||||
"overlay0": "#6c7086",
|
overlay0: '#6c7086',
|
||||||
"surface2": "#585b70",
|
surface2: '#585b70',
|
||||||
"surface1": "#45475a",
|
surface1: '#45475a',
|
||||||
"surface0": "#313244",
|
surface0: '#313244',
|
||||||
"base2": "#242438",
|
base2: '#242438',
|
||||||
"base": "#1e1e2e",
|
base: '#1e1e2e',
|
||||||
"mantle": "#181825",
|
mantle: '#181825',
|
||||||
"crust": "#11111b",
|
crust: '#11111b',
|
||||||
"surface1_2": "#454759",
|
surface1_2: '#454759',
|
||||||
"text2": "#cdd6f3",
|
text2: '#cdd6f3',
|
||||||
"pink2": "#f5c2e6",
|
pink2: '#f5c2e6',
|
||||||
"red2": "#f38ba7",
|
red2: '#f38ba7',
|
||||||
"peach2": "#fab386",
|
peach2: '#fab386',
|
||||||
"mantle2": "#181824",
|
mantle2: '#181824',
|
||||||
"surface0_2": "#313243",
|
surface0_2: '#313243',
|
||||||
"surface2_2": "#585b69",
|
surface2_2: '#585b69',
|
||||||
"overlay1_2": "#7f849b",
|
overlay1_2: '#7f849b',
|
||||||
"lavender2": "#b4befd",
|
lavender2: '#b4befd',
|
||||||
"mauve2": "#cba6f6",
|
mauve2: '#cba6f6',
|
||||||
"green2": "#a6e3a0",
|
green2: '#a6e3a0',
|
||||||
"sky2": "#89dcea",
|
sky2: '#89dcea',
|
||||||
"teal2": "#94e2d4",
|
teal2: '#94e2d4',
|
||||||
"yellow2": "#f9e2ad",
|
yellow2: '#f9e2ad',
|
||||||
"maroon2": "#eba0ab",
|
maroon2: '#eba0ab',
|
||||||
"crust2": "#11111a",
|
crust2: '#11111a',
|
||||||
"pink3": "#f5c2e8",
|
pink3: '#f5c2e8',
|
||||||
"red3": "#f38ba9",
|
red3: '#f38ba9',
|
||||||
"mantle3": "#181826",
|
mantle3: '#181826',
|
||||||
"surface0_3": "#313245",
|
surface0_3: '#313245',
|
||||||
"surface2_3": "#585b71",
|
surface2_3: '#585b71',
|
||||||
"overlay1_3": "#7f849d",
|
overlay1_3: '#7f849d',
|
||||||
"lavender3": "#b4beff",
|
lavender3: '#b4beff',
|
||||||
"mauve3": "#cba6f8",
|
mauve3: '#cba6f8',
|
||||||
"green3": "#a6e3a2",
|
green3: '#a6e3a2',
|
||||||
"sky3": "#89dcec",
|
sky3: '#89dcec',
|
||||||
"teal3": "#94e2d6",
|
teal3: '#94e2d6',
|
||||||
"yellow3": "#f9e2ae",
|
yellow3: '#f9e2ae',
|
||||||
"maroon3": "#eba0ad",
|
maroon3: '#eba0ad',
|
||||||
"crust3": "#11111c",
|
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 = {
|
export type DropdownMenuProps = {
|
||||||
name: string;
|
name: string;
|
||||||
child: any;
|
child: GtkWidget;
|
||||||
layout?: string;
|
layout?: string;
|
||||||
transition?: any;
|
transition?: Transition;
|
||||||
exclusivity?: Exclusivity;
|
exclusivity?: Exclusivity;
|
||||||
fixed?: boolean;
|
fixed?: boolean;
|
||||||
} & WindowProps;
|
} & WindowProps;
|
||||||
|
|||||||
2
lib/types/filechooser.d.ts
vendored
2
lib/types/filechooser.d.ts
vendored
@@ -1,3 +1,3 @@
|
|||||||
export type Config = {
|
export type Config = {
|
||||||
[key: string]: string | number | boolean | object;
|
[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;
|
index: number;
|
||||||
uuid: string;
|
uuid: string;
|
||||||
name: string;
|
name: string;
|
||||||
"temperature.gpu": number;
|
'temperature.gpu': number;
|
||||||
"fan.speed": number;
|
'fan.speed': number;
|
||||||
"utilization.gpu": number;
|
'utilization.gpu': number;
|
||||||
"utilization.enc": number;
|
'utilization.enc': number;
|
||||||
"utilization.dec": number;
|
'utilization.dec': number;
|
||||||
"power.draw": number;
|
'power.draw': number;
|
||||||
"enforced.power.limit": number;
|
'enforced.power.limit': number;
|
||||||
"memory.used": number;
|
'memory.used': number;
|
||||||
"memory.total": number;
|
'memory.total': number;
|
||||||
processes: Process[];
|
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 LoopStatus = 'none' | 'track' | 'playlist';
|
||||||
export type PlaybackStatus = 'playing' | 'paused' | 'stopped';
|
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 = {
|
export type AccessPoint = {
|
||||||
bssid: string | null;
|
bssid: string | null;
|
||||||
@@ -9,6 +9,8 @@ export type AccessPoint = {
|
|||||||
strength: number;
|
strength: number;
|
||||||
frequency: number;
|
frequency: number;
|
||||||
iconName: string | undefined;
|
iconName: string | undefined;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type WifiStatus = keyof typeof WIFI_STATUS_MAP;
|
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 {
|
export interface NotificationArgs {
|
||||||
appName?: string;
|
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 { Opt } from 'lib/option';
|
||||||
import { Variable } from "types/variable";
|
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 = {
|
export type RecursiveOptionsObject = {
|
||||||
[key: string]: RecursiveOptionsObject | Opt<string | number | boolean> | Opt<any>;
|
[key: string]: RecursiveOptionsObject | Opt<string | number | boolean> | Opt<any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Unit = "imperial" | "metric";
|
export type Unit = 'imperial' | 'metric';
|
||||||
export type PowerOptions = "sleep" | "reboot" | "logout" | "shutdown";
|
export type PowerOptions = 'sleep' | 'reboot' | 'logout' | 'shutdown';
|
||||||
export type NotificationAnchor = "top" | "top right" | "top left" | "bottom" | "bottom right" | "bottom left" | "left" | "right";
|
export type NotificationAnchor =
|
||||||
export type OSDAnchor = "top left" | "top" | "top right" | "right" | "bottom right" | "bottom" | "bottom left" | "left";
|
| 'top'
|
||||||
export type BarButtonStyles = "default" | "split" | "wave" | "wave2";
|
| '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 = {
|
export type ThemeExportData = {
|
||||||
filePath: string,
|
filePath: string;
|
||||||
themeOnly: boolean
|
themeOnly: boolean;
|
||||||
}
|
};
|
||||||
export type RowProps<T> = {
|
export type RowProps<T> = {
|
||||||
opt: Opt<T>
|
opt: Opt<T>;
|
||||||
title: string
|
title: string;
|
||||||
note?: string
|
note?: string;
|
||||||
type?:
|
type?:
|
||||||
| "number"
|
| 'number'
|
||||||
| "color"
|
| 'color'
|
||||||
| "float"
|
| 'float'
|
||||||
| "object"
|
| 'object'
|
||||||
| "string"
|
| 'string'
|
||||||
| "enum"
|
| 'enum'
|
||||||
| "boolean"
|
| 'boolean'
|
||||||
| "img"
|
| 'img'
|
||||||
| "wallpaper"
|
| 'wallpaper'
|
||||||
| "export"
|
| 'export'
|
||||||
| "import"
|
| 'import'
|
||||||
| "config_import"
|
| 'config_import'
|
||||||
| "font"
|
| 'font';
|
||||||
enums?: string[]
|
enums?: T[];
|
||||||
max?: number
|
max?: number;
|
||||||
min?: number
|
min?: number;
|
||||||
disabledBinding?: Variable<boolean>
|
disabledBinding?: Variable<boolean>;
|
||||||
exportData?: ThemeExportData
|
exportData?: ThemeExportData;
|
||||||
subtitle?: string | VarType<any> | Opt,
|
subtitle?: string | VarType<any> | Opt;
|
||||||
subtitleLink?: string,
|
subtitleLink?: string;
|
||||||
dependencies?: string[],
|
dependencies?: string[];
|
||||||
increment?: number
|
increment?: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type OSDOrientation = "horizontal" | "vertical";
|
export type OSDOrientation = 'horizontal' | 'vertical';
|
||||||
|
|
||||||
export type HexColor = `#${string}`;
|
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 = {
|
export type MatugenColors = {
|
||||||
"background": HexColor,
|
background: HexColor;
|
||||||
"error": HexColor,
|
error: HexColor;
|
||||||
"error_container": HexColor,
|
error_container: HexColor;
|
||||||
"inverse_on_surface": HexColor,
|
inverse_on_surface: HexColor;
|
||||||
"inverse_primary": HexColor,
|
inverse_primary: HexColor;
|
||||||
"inverse_surface": HexColor,
|
inverse_surface: HexColor;
|
||||||
"on_background": HexColor,
|
on_background: HexColor;
|
||||||
"on_error": HexColor,
|
on_error: HexColor;
|
||||||
"on_error_container": HexColor,
|
on_error_container: HexColor;
|
||||||
"on_primary": HexColor,
|
on_primary: HexColor;
|
||||||
"on_primary_container": HexColor,
|
on_primary_container: HexColor;
|
||||||
"on_primary_fixed": HexColor,
|
on_primary_fixed: HexColor;
|
||||||
"on_primary_fixed_variant": HexColor,
|
on_primary_fixed_variant: HexColor;
|
||||||
"on_secondary": HexColor,
|
on_secondary: HexColor;
|
||||||
"on_secondary_container": HexColor,
|
on_secondary_container: HexColor;
|
||||||
"on_secondary_fixed": HexColor,
|
on_secondary_fixed: HexColor;
|
||||||
"on_secondary_fixed_variant": HexColor,
|
on_secondary_fixed_variant: HexColor;
|
||||||
"on_surface": HexColor,
|
on_surface: HexColor;
|
||||||
"on_surface_variant": HexColor,
|
on_surface_variant: HexColor;
|
||||||
"on_tertiary": HexColor,
|
on_tertiary: HexColor;
|
||||||
"on_tertiary_container": HexColor,
|
on_tertiary_container: HexColor;
|
||||||
"on_tertiary_fixed": HexColor,
|
on_tertiary_fixed: HexColor;
|
||||||
"on_tertiary_fixed_variant": HexColor,
|
on_tertiary_fixed_variant: HexColor;
|
||||||
"outline": HexColor,
|
outline: HexColor;
|
||||||
"outline_variant": HexColor,
|
outline_variant: HexColor;
|
||||||
"primary": HexColor,
|
primary: HexColor;
|
||||||
"primary_container": HexColor,
|
primary_container: HexColor;
|
||||||
"primary_fixed": HexColor,
|
primary_fixed: HexColor;
|
||||||
"primary_fixed_dim": HexColor,
|
primary_fixed_dim: HexColor;
|
||||||
"scrim": HexColor,
|
scrim: HexColor;
|
||||||
"secondary": HexColor,
|
secondary: HexColor;
|
||||||
"secondary_container": HexColor,
|
secondary_container: HexColor;
|
||||||
"secondary_fixed": HexColor,
|
secondary_fixed: HexColor;
|
||||||
"secondary_fixed_dim": HexColor,
|
secondary_fixed_dim: HexColor;
|
||||||
"shadow": HexColor,
|
shadow: HexColor;
|
||||||
"surface": HexColor,
|
surface: HexColor;
|
||||||
"surface_bright": HexColor,
|
surface_bright: HexColor;
|
||||||
"surface_container": HexColor,
|
surface_container: HexColor;
|
||||||
"surface_container_high": HexColor,
|
surface_container_high: HexColor;
|
||||||
"surface_container_highest": HexColor,
|
surface_container_highest: HexColor;
|
||||||
"surface_container_low": HexColor,
|
surface_container_low: HexColor;
|
||||||
"surface_container_lowest": HexColor,
|
surface_container_lowest: HexColor;
|
||||||
"surface_dim": HexColor,
|
surface_dim: HexColor;
|
||||||
"surface_variant": HexColor,
|
surface_variant: HexColor;
|
||||||
"tertiary": HexColor,
|
tertiary: HexColor;
|
||||||
"tertiary_container": HexColor,
|
tertiary_container: HexColor;
|
||||||
"tertiary_fixed": HexColor,
|
tertiary_fixed: HexColor;
|
||||||
"tertiary_fixed_dim": HexColor
|
tertiary_fixed_dim: HexColor;
|
||||||
}
|
};
|
||||||
|
|
||||||
type MatugenScheme =
|
export type MatugenVariation = {
|
||||||
| "content"
|
rosewater: HexColor;
|
||||||
| "expressive"
|
flamingo: HexColor;
|
||||||
| "fidelity"
|
pink: HexColor;
|
||||||
| "fruit-salad"
|
mauve: HexColor;
|
||||||
| "monochrome"
|
red: HexColor;
|
||||||
| "neutral"
|
maroon: HexColor;
|
||||||
| "rainbow"
|
peach: HexColor;
|
||||||
| "tonal-spot";
|
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 =
|
export type MatugenVariations =
|
||||||
| "standard_1"
|
| 'standard_1'
|
||||||
| "standard_2"
|
| 'standard_2'
|
||||||
| "standard_3"
|
| 'standard_3'
|
||||||
| "monochrome_1"
|
| 'monochrome_1'
|
||||||
| "monochrome_2"
|
| 'monochrome_2'
|
||||||
| "monochrome_3"
|
| 'monochrome_3'
|
||||||
| "vivid_1"
|
| 'vivid_1'
|
||||||
| "vivid_2"
|
| 'vivid_2'
|
||||||
| "vivid_3"
|
| '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 { Widget } from 'types/widgets/widget';
|
||||||
import { WindowProps } from "types/widgets/window";
|
import { WindowProps } from 'types/widgets/window';
|
||||||
import { Transition } from "./widget";
|
import { Transition } from './widget';
|
||||||
|
|
||||||
export type PopupWindowProps = {
|
export type PopupWindowProps = {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -13,15 +13,23 @@ export type PopupWindowProps = {
|
|||||||
export type LayoutFunction = (
|
export type LayoutFunction = (
|
||||||
name: string,
|
name: string,
|
||||||
child: Widget,
|
child: Widget,
|
||||||
transition: Transition
|
transition: Transition,
|
||||||
) => {
|
) => {
|
||||||
center: () => Widget;
|
center: () => Widget;
|
||||||
top: () => Widget;
|
top: () => Widget;
|
||||||
"top-right": () => Widget;
|
'top-right': () => Widget;
|
||||||
"top-center": () => Widget;
|
'top-center': () => Widget;
|
||||||
"top-left": () => Widget;
|
'top-left': () => Widget;
|
||||||
"bottom-left": () => Widget;
|
'bottom-left': () => Widget;
|
||||||
"bottom-center": () => Widget;
|
'bottom-center': () => Widget;
|
||||||
"bottom-right": () => 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 icons from 'modules/icons/index';
|
||||||
import PowerProfiles from "types/service/powerprofiles.js"
|
import PowerProfiles from 'types/service/powerprofiles.js';
|
||||||
|
|
||||||
export type PowerProfiles = InstanceType<typeof PowerProfiles>;
|
export type PowerProfiles = InstanceType<typeof PowerProfiles>;
|
||||||
export type PowerProfile = "power-saver" | "balanced" | "performance";
|
export type PowerProfile = 'power-saver' | 'balanced' | 'performance';
|
||||||
export type PowerProfileObject = {
|
export type PowerProfileObject = {
|
||||||
[key: string]: string;
|
[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;
|
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 = {
|
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 = {
|
export type Weather = {
|
||||||
location: Location;
|
location: Location;
|
||||||
current: Current;
|
current: Current;
|
||||||
forecast: Forecast;
|
forecast: Forecast;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Current = {
|
export type Current = {
|
||||||
last_updated_epoch?: number;
|
last_updated_epoch?: number;
|
||||||
@@ -45,17 +45,17 @@ export type Current = {
|
|||||||
chance_of_rain?: number;
|
chance_of_rain?: number;
|
||||||
will_it_snow?: number;
|
will_it_snow?: number;
|
||||||
chance_of_snow?: number;
|
chance_of_snow?: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Condition = {
|
export type Condition = {
|
||||||
text: string;
|
text: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
code: number;
|
code: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Forecast = {
|
export type Forecast = {
|
||||||
forecastday: Forecastday[];
|
forecastday: Forecastday[];
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Forecastday = {
|
export type Forecastday = {
|
||||||
date: string;
|
date: string;
|
||||||
@@ -63,7 +63,7 @@ export type Forecastday = {
|
|||||||
day: Day;
|
day: Day;
|
||||||
astro: Astro;
|
astro: Astro;
|
||||||
hour: Current[];
|
hour: Current[];
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Astro = {
|
export type Astro = {
|
||||||
sunrise: string;
|
sunrise: string;
|
||||||
@@ -74,7 +74,7 @@ export type Astro = {
|
|||||||
moon_illumination: number;
|
moon_illumination: number;
|
||||||
is_moon_up: number;
|
is_moon_up: number;
|
||||||
is_sun_up: number;
|
is_sun_up: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Day = {
|
export type Day = {
|
||||||
maxtemp_c: number;
|
maxtemp_c: number;
|
||||||
@@ -97,7 +97,7 @@ export type Day = {
|
|||||||
daily_chance_of_snow: number;
|
daily_chance_of_snow: number;
|
||||||
condition: Condition;
|
condition: Condition;
|
||||||
uv: number;
|
uv: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Location = {
|
export type Location = {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -108,11 +108,11 @@ export type Location = {
|
|||||||
tz_id: string;
|
tz_id: string;
|
||||||
localtime_epoch: number;
|
localtime_epoch: number;
|
||||||
localtime: string;
|
localtime: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type TemperatureIconColorMap = {
|
export type TemperatureIconColorMap = {
|
||||||
[key: number]: string;
|
[key: number]: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type WeatherIconTitle = keyof typeof weatherIcons;
|
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';
|
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0';
|
||||||
export type Anchor = "left" | "right" | "top" | "down";
|
import Box from 'types/widgets/box';
|
||||||
export type Transition = "none" | "crossfade" | "slide_right" | "slide_left" | "slide_up" | "slide_down";
|
|
||||||
|
|
||||||
// Window
|
export type Exclusivity = 'normal' | 'ignore' | 'exclusive';
|
||||||
export type Layouts = 'center' | 'top' | 'top-right' | 'top-center' | 'top-left' | 'bottom-left' | 'bottom-center' | 'bottom-right';
|
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 = {
|
export type WorkspaceRule = {
|
||||||
workspaceString: string,
|
workspaceString: string;
|
||||||
monitor: string,
|
monitor: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type WorkspaceMap = {
|
export type WorkspaceMap = {
|
||||||
[key: string]: number[],
|
[key: string]: number[];
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export type MonitorMap = {
|
||||||
|
[key: number]: string;
|
||||||
|
};
|
||||||
|
|||||||
153
lib/utils.ts
153
lib/utils.ts
@@ -1,29 +1,27 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { type Application } from "types/service/applications"
|
import { type Application } from 'types/service/applications';
|
||||||
import { NotificationAnchor } from "./types/options"
|
import { NotificationAnchor } from './types/options';
|
||||||
import { OSDAnchor } from "lib/types/options";
|
import { OSDAnchor } from 'lib/types/options';
|
||||||
import icons, { substitutes } from "./icons"
|
import icons, { substitutes } from './icons';
|
||||||
import Gtk from "gi://Gtk?version=3.0"
|
import Gtk from 'gi://Gtk?version=3.0';
|
||||||
import Gdk from "gi://Gdk"
|
import Gdk from 'gi://Gdk';
|
||||||
import GLib from "gi://GLib?version=2.0"
|
import GLib from 'gi://GLib?version=2.0';
|
||||||
import GdkPixbuf from "gi://GdkPixbuf";
|
import GdkPixbuf from 'gi://GdkPixbuf';
|
||||||
import { NotificationArgs } from "types/utils/notify"
|
import { NotificationArgs } from 'types/utils/notify';
|
||||||
import { SubstituteKeys } from "./types/utils";
|
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>
|
|
||||||
|
|
||||||
|
export type Binding<T> = import('types/service').Binding<any, any, T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns substitute icon || name || fallback icon
|
* @returns substitute icon || name || fallback icon
|
||||||
*/
|
*/
|
||||||
export function icon(name: string | null, fallback = icons.missing) {
|
export function icon(name: string | null, fallback = icons.missing): string {
|
||||||
const validateSubstitute = (name: string): name is SubstituteKeys => name in substitutes;
|
const validateSubstitute = (name: string): name is SubstituteKeys => name in substitutes;
|
||||||
|
|
||||||
if (!name)
|
if (!name) return fallback || '';
|
||||||
return fallback || ""
|
|
||||||
|
|
||||||
if (GLib.file_test(name, GLib.FileTest.EXISTS))
|
if (GLib.file_test(name, GLib.FileTest.EXISTS)) return name;
|
||||||
return name
|
|
||||||
|
|
||||||
let icon: string = name;
|
let icon: string = name;
|
||||||
|
|
||||||
@@ -31,38 +29,36 @@ export function icon(name: string | null, fallback = icons.missing) {
|
|||||||
icon = substitutes[name];
|
icon = substitutes[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.lookUpIcon(icon))
|
if (Utils.lookUpIcon(icon)) return icon;
|
||||||
return icon
|
|
||||||
|
|
||||||
print(`no icon substitute "${icon}" for "${name}", fallback: "${fallback}"`)
|
print(`no icon substitute "${icon}" for "${name}", fallback: "${fallback}"`);
|
||||||
return fallback
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns execAsync(["bash", "-c", cmd])
|
* @returns execAsync(["bash", "-c", cmd])
|
||||||
*/
|
*/
|
||||||
export async function bash(strings: TemplateStringsArray | string, ...values: unknown[]) {
|
export async function bash(strings: TemplateStringsArray | string, ...values: unknown[]): Promise<string> {
|
||||||
const cmd = typeof strings === "string" ? strings : strings
|
const cmd =
|
||||||
.flatMap((str, i) => str + `${values[i] ?? ""}`)
|
typeof strings === 'string' ? strings : strings.flatMap((str, i) => str + `${values[i] ?? ''}`).join('');
|
||||||
.join("")
|
|
||||||
|
|
||||||
return Utils.execAsync(["bash", "-c", cmd]).catch(err => {
|
return Utils.execAsync(['bash', '-c', cmd]).catch((err) => {
|
||||||
console.error(cmd, err)
|
console.error(cmd, err);
|
||||||
return ""
|
return '';
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns execAsync(cmd)
|
* @returns execAsync(cmd)
|
||||||
*/
|
*/
|
||||||
export async function sh(cmd: string | string[]) {
|
export async function sh(cmd: string | string[]): Promise<string> {
|
||||||
return Utils.execAsync(cmd).catch(err => {
|
return Utils.execAsync(cmd).catch((err) => {
|
||||||
console.error(typeof cmd === "string" ? cmd : cmd.join(" "), err)
|
console.error(typeof cmd === 'string' ? cmd : cmd.join(' '), err);
|
||||||
return ""
|
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;
|
const n = Gdk.Display.get_default()?.get_n_monitors() || 1;
|
||||||
return range(n, 0).flatMap(widget);
|
return range(n, 0).flatMap(widget);
|
||||||
}
|
}
|
||||||
@@ -70,64 +66,62 @@ export function forMonitors(widget: (monitor: number) => Gtk.Window) {
|
|||||||
/**
|
/**
|
||||||
* @returns [start...length]
|
* @returns [start...length]
|
||||||
*/
|
*/
|
||||||
export function range(length: number, start = 1) {
|
export function range(length: number, start = 1): number[] {
|
||||||
return Array.from({ length }, (_, i) => i + start)
|
return Array.from({ length }, (_, i) => i + start);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns true if all of the `bins` are found
|
* @returns true if all of the `bins` are found
|
||||||
*/
|
*/
|
||||||
export function dependencies(...bins: string[]) {
|
export function dependencies(...bins: string[]): boolean {
|
||||||
const missing = bins.filter(bin => Utils.exec({
|
const missing = bins.filter((bin) =>
|
||||||
|
Utils.exec({
|
||||||
cmd: `which ${bin}`,
|
cmd: `which ${bin}`,
|
||||||
out: () => false,
|
out: () => false,
|
||||||
err: () => true,
|
err: () => true,
|
||||||
}))
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
if (missing.length > 0) {
|
if (missing.length > 0) {
|
||||||
console.warn(Error(`missing dependencies: ${missing.join(", ")}`))
|
console.warn(Error(`missing dependencies: ${missing.join(', ')}`));
|
||||||
Notify({
|
Notify({
|
||||||
summary: "Dependencies not found!",
|
summary: 'Dependencies not found!',
|
||||||
body: `The following dependencies are missing: ${missing.join(", ")}`,
|
body: `The following dependencies are missing: ${missing.join(', ')}`,
|
||||||
iconName: icons.ui.warning,
|
iconName: icons.ui.warning,
|
||||||
timeout: 7000
|
timeout: 7000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return missing.length === 0
|
return missing.length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* run app detached
|
* run app detached
|
||||||
*/
|
*/
|
||||||
export function launchApp(app: Application) {
|
export function launchApp(app: Application): void {
|
||||||
const exe = app.executable
|
const exe = app.executable
|
||||||
.split(/\s+/)
|
.split(/\s+/)
|
||||||
.filter(str => !str.startsWith("%") && !str.startsWith("@"))
|
.filter((str) => !str.startsWith('%') && !str.startsWith('@'))
|
||||||
.join(" ")
|
.join(' ');
|
||||||
|
|
||||||
bash(`${exe} &`)
|
bash(`${exe} &`);
|
||||||
app.frequency += 1
|
app.frequency += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* to use with drag and drop
|
* 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
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const cairo = imports.gi.cairo as any
|
const cairo = imports.gi.cairo as any;
|
||||||
const alloc = widget.get_allocation()
|
const alloc = widget.get_allocation();
|
||||||
const surface = new cairo.ImageSurface(
|
const surface = new cairo.ImageSurface(cairo.Format.ARGB32, alloc.width, alloc.height);
|
||||||
cairo.Format.ARGB32,
|
const cr = new cairo.Context(surface);
|
||||||
alloc.width,
|
cr.setSourceRGBA(255, 255, 255, 0);
|
||||||
alloc.height,
|
cr.rectangle(0, 0, alloc.width, alloc.height);
|
||||||
)
|
cr.fill();
|
||||||
const cr = new cairo.Context(surface)
|
widget.draw(cr);
|
||||||
cr.setSourceRGBA(255, 255, 255, 0)
|
return surface;
|
||||||
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);
|
GdkPixbuf.Pixbuf.new_from_file(imgFilePath);
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export const Notify = (notifPayload: NotificationArgs): void => {
|
export const Notify = (notifPayload: NotificationArgs): void => {
|
||||||
let command = 'notify-send';
|
let command = 'notify-send';
|
||||||
@@ -154,20 +149,20 @@ export const Notify = (notifPayload: NotificationArgs): void => {
|
|||||||
if (notifPayload.transient) command += ` -e`;
|
if (notifPayload.transient) command += ` -e`;
|
||||||
if (notifPayload.id !== undefined) command += ` -r ${notifPayload.id}`;
|
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"],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return positionMap[pos] || ["top"];
|
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'];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(), {
|
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, {
|
export const uptime = Variable(0, {
|
||||||
poll: [60_000, "cat /proc/uptime", line =>
|
poll: [60_000, 'cat /proc/uptime', (line): number => Number.parseInt(line.split('.')[0]) / 60],
|
||||||
Number.parseInt(line.split(".")[0]) / 60,
|
});
|
||||||
],
|
|
||||||
})
|
|
||||||
|
|
||||||
export const distro = {
|
export const distro = {
|
||||||
id: GLib.get_os_info("ID"),
|
id: GLib.get_os_info('ID'),
|
||||||
logo: GLib.get_os_info("LOGO"),
|
logo: GLib.get_os_info('LOGO'),
|
||||||
}
|
};
|
||||||
|
|||||||
30
main.ts
30
main.ts
@@ -1,27 +1,21 @@
|
|||||||
import "lib/session";
|
import 'lib/session';
|
||||||
import "scss/style";
|
import 'scss/style';
|
||||||
import "globals/useTheme";
|
import 'globals/useTheme';
|
||||||
import "globals/mousePos";
|
import 'globals/mousePos';
|
||||||
|
|
||||||
import { Bar } from "modules/bar/Bar";
|
import { Bar } from 'modules/bar/Bar';
|
||||||
import MenuWindows from "./modules/menus/main.js";
|
import MenuWindows from './modules/menus/main.js';
|
||||||
import SettingsDialog from "widget/settings/SettingsDialog";
|
import SettingsDialog from 'widget/settings/SettingsDialog';
|
||||||
import Notifications from "./modules/notifications/index.js";
|
import Notifications from './modules/notifications/index.js';
|
||||||
import { forMonitors } from "lib/utils";
|
import { forMonitors } from 'lib/utils';
|
||||||
import OSD from "modules/osd/index";
|
import OSD from 'modules/osd/index';
|
||||||
|
|
||||||
App.config({
|
App.config({
|
||||||
onConfigParsed: () => Utils.execAsync(`python3 ${App.configDir}/services/bluetooth.py`),
|
onConfigParsed: () => Utils.execAsync(`python3 ${App.configDir}/services/bluetooth.py`),
|
||||||
windows: [
|
windows: [...MenuWindows, Notifications(), SettingsDialog(), ...forMonitors(Bar), OSD()],
|
||||||
...MenuWindows,
|
|
||||||
Notifications(),
|
|
||||||
SettingsDialog(),
|
|
||||||
...forMonitors(Bar),
|
|
||||||
OSD(),
|
|
||||||
],
|
|
||||||
closeWindowDelay: {
|
closeWindowDelay: {
|
||||||
sideright: 350,
|
sideright: 350,
|
||||||
launcher: 350,
|
launcher: 350,
|
||||||
bar0: 350,
|
bar0: 350,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
const hyprland = await Service.import("hyprland");
|
const hyprland = await Service.import('hyprland');
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Menu,
|
Menu,
|
||||||
Workspaces, ClientTitle, Media,
|
Workspaces,
|
||||||
|
ClientTitle,
|
||||||
|
Media,
|
||||||
Notifications,
|
Notifications,
|
||||||
Volume,
|
Volume,
|
||||||
Network,
|
Network,
|
||||||
@@ -20,54 +22,57 @@ import {
|
|||||||
Updates,
|
Updates,
|
||||||
Weather,
|
Weather,
|
||||||
Power,
|
Power,
|
||||||
} from "./Exports"
|
} from './Exports';
|
||||||
|
|
||||||
import { BarItemBox as WidgetContainer } from "../shared/barItemBox.js";
|
import { BarItemBox as WidgetContainer } from '../shared/barItemBox.js';
|
||||||
import options from "options";
|
import options from 'options';
|
||||||
import Gdk from "gi://Gdk?version=3.0";
|
import Gdk from 'gi://Gdk?version=3.0';
|
||||||
import Button from "types/widgets/button.js";
|
import Button from 'types/widgets/button.js';
|
||||||
import Gtk from "types/@girs/gtk-3.0/gtk-3.0.js";
|
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0.js';
|
||||||
|
|
||||||
import './SideEffects';
|
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;
|
const { layouts } = options.bar;
|
||||||
|
|
||||||
export type BarWidget = keyof typeof widget;
|
export type BarWidget = keyof typeof widget;
|
||||||
|
|
||||||
type Section = "battery"
|
type Section =
|
||||||
| "dashboard"
|
| 'battery'
|
||||||
| "workspaces"
|
| 'dashboard'
|
||||||
| "windowtitle"
|
| 'workspaces'
|
||||||
| "media"
|
| 'windowtitle'
|
||||||
| "notifications"
|
| 'media'
|
||||||
| "volume"
|
| 'notifications'
|
||||||
| "network"
|
| 'volume'
|
||||||
| "bluetooth"
|
| 'network'
|
||||||
| "clock"
|
| 'bluetooth'
|
||||||
| "ram"
|
| 'clock'
|
||||||
| "cpu"
|
| 'ram'
|
||||||
| "storage"
|
| 'cpu'
|
||||||
| "netstat"
|
| 'storage'
|
||||||
| "kbinput"
|
| 'netstat'
|
||||||
| "updates"
|
| 'kbinput'
|
||||||
| "weather"
|
| 'updates'
|
||||||
| "power"
|
| 'weather'
|
||||||
| "systray";
|
| 'power'
|
||||||
|
| 'systray';
|
||||||
|
|
||||||
type Layout = {
|
type Layout = {
|
||||||
left: Section[],
|
left: Section[];
|
||||||
middle: Section[],
|
middle: Section[];
|
||||||
right: Section[],
|
right: Section[];
|
||||||
}
|
};
|
||||||
|
|
||||||
type BarLayout = {
|
type BarLayout = {
|
||||||
[key: string]: Layout
|
[key: string]: Layout;
|
||||||
}
|
};
|
||||||
|
|
||||||
const getLayoutForMonitor = (monitor: number, layouts: BarLayout): Layout => {
|
const getLayoutForMonitor = (monitor: number, layouts: BarLayout): Layout => {
|
||||||
const matchingKey = Object.keys(layouts).find(key => key === monitor.toString());
|
const matchingKey = Object.keys(layouts).find((key) => key === monitor.toString());
|
||||||
const wildcard = Object.keys(layouts).find(key => key === "*");
|
const wildcard = Object.keys(layouts).find((key) => key === '*');
|
||||||
|
|
||||||
if (matchingKey) {
|
if (matchingKey) {
|
||||||
return layouts[matchingKey];
|
return layouts[matchingKey];
|
||||||
@@ -78,61 +83,47 @@ const getLayoutForMonitor = (monitor: number, layouts: BarLayout): Layout => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
left: [
|
left: ['dashboard', 'workspaces', 'windowtitle'],
|
||||||
"dashboard",
|
middle: ['media'],
|
||||||
"workspaces",
|
right: ['volume', 'network', 'bluetooth', 'battery', 'systray', 'clock', 'notifications'],
|
||||||
"windowtitle"
|
};
|
||||||
],
|
|
||||||
middle: [
|
|
||||||
"media"
|
|
||||||
],
|
|
||||||
right: [
|
|
||||||
"volume",
|
|
||||||
"network",
|
|
||||||
"bluetooth",
|
|
||||||
"battery",
|
|
||||||
"systray",
|
|
||||||
"clock",
|
|
||||||
"notifications"
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const widget = {
|
const widget = {
|
||||||
battery: () => WidgetContainer(BatteryLabel()),
|
battery: (): Button<Child, Attribute> => WidgetContainer(BatteryLabel()),
|
||||||
dashboard: () => WidgetContainer(Menu()),
|
dashboard: (): Button<Child, Attribute> => WidgetContainer(Menu()),
|
||||||
workspaces: (monitor: number) => WidgetContainer(Workspaces(monitor)),
|
workspaces: (monitor: number): Button<Child, Attribute> => WidgetContainer(Workspaces(monitor)),
|
||||||
windowtitle: () => WidgetContainer(ClientTitle()),
|
windowtitle: (): Button<Child, Attribute> => WidgetContainer(ClientTitle()),
|
||||||
media: () => WidgetContainer(Media()),
|
media: (): Button<Child, Attribute> => WidgetContainer(Media()),
|
||||||
notifications: () => WidgetContainer(Notifications()),
|
notifications: (): Button<Child, Attribute> => WidgetContainer(Notifications()),
|
||||||
volume: () => WidgetContainer(Volume()),
|
volume: (): Button<Child, Attribute> => WidgetContainer(Volume()),
|
||||||
network: () => WidgetContainer(Network()),
|
network: (): Button<Child, Attribute> => WidgetContainer(Network()),
|
||||||
bluetooth: () => WidgetContainer(Bluetooth()),
|
bluetooth: (): Button<Child, Attribute> => WidgetContainer(Bluetooth()),
|
||||||
clock: () => WidgetContainer(Clock()),
|
clock: (): Button<Child, Attribute> => WidgetContainer(Clock()),
|
||||||
systray: () => WidgetContainer(SysTray()),
|
systray: (): Button<Child, Attribute> => WidgetContainer(SysTray()),
|
||||||
ram: () => WidgetContainer(Ram()),
|
ram: (): Button<Child, Attribute> => WidgetContainer(Ram()),
|
||||||
cpu: () => WidgetContainer(Cpu()),
|
cpu: (): Button<Child, Attribute> => WidgetContainer(Cpu()),
|
||||||
storage: () => WidgetContainer(Storage()),
|
storage: (): Button<Child, Attribute> => WidgetContainer(Storage()),
|
||||||
netstat: () => WidgetContainer(Netstat()),
|
netstat: (): Button<Child, Attribute> => WidgetContainer(Netstat()),
|
||||||
kbinput: () => WidgetContainer(KbInput()),
|
kbinput: (): Button<Child, Attribute> => WidgetContainer(KbInput()),
|
||||||
updates: () => WidgetContainer(Updates()),
|
updates: (): Button<Child, Attribute> => WidgetContainer(Updates()),
|
||||||
weather: () => WidgetContainer(Weather()),
|
weather: (): Button<Child, Attribute> => WidgetContainer(Weather()),
|
||||||
power: () => WidgetContainer(Power()),
|
power: (): Button<Child, Attribute> => WidgetContainer(Power()),
|
||||||
};
|
};
|
||||||
|
|
||||||
type GdkMonitors = {
|
type GdkMonitors = {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
key: string,
|
key: string;
|
||||||
model: string,
|
model: string;
|
||||||
used: boolean
|
used: boolean;
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function getGdkMonitors(): GdkMonitors {
|
function getGdkMonitors(): GdkMonitors {
|
||||||
const display = Gdk.Display.get_default();
|
const display = Gdk.Display.get_default();
|
||||||
|
|
||||||
if (display === null) {
|
if (display === null) {
|
||||||
console.error("Failed to get Gdk display.");
|
console.error('Failed to get Gdk display.');
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +191,7 @@ const gdkMonitorIdToHyprlandId = (monitor: number, usedHyprlandMonitors: Set<num
|
|||||||
const gdkMonitors = getGdkMonitors();
|
const gdkMonitors = getGdkMonitors();
|
||||||
|
|
||||||
if (Object.keys(gdkMonitors).length === 0) {
|
if (Object.keys(gdkMonitors).length === 0) {
|
||||||
console.error("No GDK monitors were found.");
|
console.error('No GDK monitors were found.');
|
||||||
return monitor;
|
return monitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +199,7 @@ const gdkMonitorIdToHyprlandId = (monitor: number, usedHyprlandMonitors: Set<num
|
|||||||
const gdkMonitor = gdkMonitors[monitor];
|
const gdkMonitor = gdkMonitors[monitor];
|
||||||
|
|
||||||
// First pass: Strict matching including the monitor index (i.e., hypMon.id === monitor + resolution+scale criteria)
|
// 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}`;
|
const hyprlandKey = `${hypMon.model}_${hypMon.width}x${hypMon.height}_${hypMon.scale}`;
|
||||||
return gdkMonitor.key.startsWith(hyprlandKey) && !usedHyprlandMonitors.has(hypMon.id) && hypMon.id === monitor;
|
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
|
// 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}`;
|
const hyprlandKey = `${hypMon.model}_${hypMon.width}x${hypMon.height}_${hypMon.scale}`;
|
||||||
return gdkMonitor.key.startsWith(hyprlandKey) && !usedHyprlandMonitors.has(hypMon.id);
|
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
|
// 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) {
|
if (fallbackMonitor) {
|
||||||
usedHyprlandMonitors.add(fallbackMonitor.id);
|
usedHyprlandMonitors.add(fallbackMonitor.id);
|
||||||
@@ -253,62 +244,63 @@ const gdkMonitorIdToHyprlandId = (monitor: number, usedHyprlandMonitors: Set<num
|
|||||||
export const Bar = (() => {
|
export const Bar = (() => {
|
||||||
const usedHyprlandMonitors = new Set<number>();
|
const usedHyprlandMonitors = new Set<number>();
|
||||||
|
|
||||||
return (monitor: number) => {
|
return (monitor: number): Window<Child, Attribute> => {
|
||||||
const hyprlandMonitor = gdkMonitorIdToHyprlandId(monitor, usedHyprlandMonitors);
|
const hyprlandMonitor = gdkMonitorIdToHyprlandId(monitor, usedHyprlandMonitors);
|
||||||
|
|
||||||
return Widget.Window({
|
return Widget.Window({
|
||||||
name: `bar-${hyprlandMonitor}`,
|
name: `bar-${hyprlandMonitor}`,
|
||||||
class_name: "bar",
|
class_name: 'bar',
|
||||||
monitor,
|
monitor,
|
||||||
visible: true,
|
visible: true,
|
||||||
anchor: ["top", "left", "right"],
|
anchor: ['top', 'left', 'right'],
|
||||||
exclusivity: "exclusive",
|
exclusivity: 'exclusive',
|
||||||
layer: Utils.merge(
|
layer: Utils.merge(
|
||||||
[
|
[options.theme.bar.layer.bind('value'), options.tear.bind('value')],
|
||||||
options.theme.bar.layer.bind("value"),
|
(barLayer: WindowLayer, tear: boolean) => {
|
||||||
options.tear.bind("value")
|
if (tear && barLayer === 'overlay') {
|
||||||
],
|
return 'top';
|
||||||
(
|
|
||||||
barLayer: WindowLayer,
|
|
||||||
tear: boolean
|
|
||||||
) => {
|
|
||||||
if (tear && barLayer === "overlay") {
|
|
||||||
return "top";
|
|
||||||
}
|
}
|
||||||
return barLayer;
|
return barLayer;
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
class_name: 'bar-panel-container',
|
class_name: 'bar-panel-container',
|
||||||
child: Widget.CenterBox({
|
child: Widget.CenterBox({
|
||||||
class_name: 'bar-panel',
|
class_name: 'bar-panel',
|
||||||
css: 'padding: 1px',
|
css: 'padding: 1px',
|
||||||
startWidget: Widget.Box({
|
startWidget: Widget.Box({
|
||||||
class_name: "box-left",
|
class_name: 'box-left',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
setup: self => {
|
setup: (self) => {
|
||||||
self.hook(layouts, (self) => {
|
self.hook(layouts, (self) => {
|
||||||
const foundLayout = getLayoutForMonitor(hyprlandMonitor, layouts.value as BarLayout);
|
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({
|
centerWidget: Widget.Box({
|
||||||
class_name: "box-center",
|
class_name: 'box-center',
|
||||||
hpack: "center",
|
hpack: 'center',
|
||||||
setup: self => {
|
setup: (self) => {
|
||||||
self.hook(layouts, (self) => {
|
self.hook(layouts, (self) => {
|
||||||
const foundLayout = getLayoutForMonitor(hyprlandMonitor, layouts.value as BarLayout);
|
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({
|
endWidget: Widget.Box({
|
||||||
class_name: "box-right",
|
class_name: 'box-right',
|
||||||
hpack: "end",
|
hpack: 'end',
|
||||||
setup: self => {
|
setup: (self) => {
|
||||||
self.hook(layouts, (self) => {
|
self.hook(layouts, (self) => {
|
||||||
const foundLayout = getLayoutForMonitor(hyprlandMonitor, layouts.value as BarLayout);
|
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 { Menu } from './menu/index';
|
||||||
import { Workspaces } from "./workspaces/index";
|
import { Workspaces } from './workspaces/index';
|
||||||
import { ClientTitle } from "./window_title/index";
|
import { ClientTitle } from './window_title/index';
|
||||||
import { Media } from "./media/index";
|
import { Media } from './media/index';
|
||||||
import { Notifications } from "./notifications/index";
|
import { Notifications } from './notifications/index';
|
||||||
import { Volume } from "./volume/index";
|
import { Volume } from './volume/index';
|
||||||
import { Network } from "./network/index";
|
import { Network } from './network/index';
|
||||||
import { Bluetooth } from "./bluetooth/index";
|
import { Bluetooth } from './bluetooth/index';
|
||||||
import { BatteryLabel } from "./battery/index";
|
import { BatteryLabel } from './battery/index';
|
||||||
import { Clock } from "./clock/index";
|
import { Clock } from './clock/index';
|
||||||
import { SysTray } from "./systray/index";
|
import { SysTray } from './systray/index';
|
||||||
|
|
||||||
// Custom Modules
|
// Custom Modules
|
||||||
import { Ram } from "../../customModules/ram/index";
|
import { Ram } from '../../customModules/ram/index';
|
||||||
import { Cpu } from "../../customModules/cpu/index";
|
import { Cpu } from '../../customModules/cpu/index';
|
||||||
import { Storage } from "customModules/storage/index";
|
import { Storage } from 'customModules/storage/index';
|
||||||
import { Netstat } from "customModules/netstat/index";
|
import { Netstat } from 'customModules/netstat/index';
|
||||||
import { KbInput } from "customModules/kblayout/index";
|
import { KbInput } from 'customModules/kblayout/index';
|
||||||
import { Updates } from "customModules/updates/index";
|
import { Updates } from 'customModules/updates/index';
|
||||||
import { Weather } from "customModules/weather/index";
|
import { Weather } from 'customModules/weather/index';
|
||||||
import { Power } from "customModules/power/index";
|
import { Power } from 'customModules/power/index';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Menu,
|
Menu,
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import options from "options";
|
import options from 'options';
|
||||||
|
|
||||||
const { showIcon, showTime } = options.bar.clock;
|
const { showIcon, showTime } = options.bar.clock;
|
||||||
|
|
||||||
showIcon.connect("changed", () => {
|
showIcon.connect('changed', () => {
|
||||||
if (!showTime.value && !showIcon.value) {
|
if (!showTime.value && !showIcon.value) {
|
||||||
showTime.value = true;
|
showTime.value = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
showTime.connect("changed", () => {
|
showTime.connect('changed', () => {
|
||||||
if (!showTime.value && !showIcon.value) {
|
if (!showTime.value && !showIcon.value) {
|
||||||
showIcon.value = true;
|
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 Gdk from 'gi://Gdk?version=3.0';
|
||||||
import { openMenu } from "../utils.js";
|
import { openMenu } from '../utils.js';
|
||||||
import options from "options";
|
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 { label: show_label } = options.bar.battery;
|
||||||
|
|
||||||
const BatteryLabel = () => {
|
const BatteryLabel = (): BarBoxChild => {
|
||||||
const isVis = Variable(battery.available);
|
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) => {
|
(batPercent: number, batCharging, batCharged) => {
|
||||||
if (batCharged)
|
if (batCharged) return `battery-level-100-charged-symbolic`;
|
||||||
return `battery-level-100-charged-symbolic`;
|
else return `battery-level-${Math.floor(batPercent / 10) * 10}${batCharging ? '-charging' : ''}-symbolic`;
|
||||||
else
|
},
|
||||||
return `battery-level-${Math.floor(batPercent / 10) * 10}${batCharging ? '-charging' : ''}-symbolic`;
|
);
|
||||||
});
|
|
||||||
|
|
||||||
battery.connect("changed", ({ available }) => {
|
battery.connect('changed', ({ available }) => {
|
||||||
isVis.value = available;
|
isVis.value = available;
|
||||||
});
|
});
|
||||||
|
|
||||||
const formatTime = (seconds: number) => {
|
const formatTime = (seconds: number): Record<string, number> => {
|
||||||
const hours = Math.floor(seconds / 3600);
|
const hours = Math.floor(seconds / 3600);
|
||||||
const minutes = Math.floor((seconds % 3600) / 60);
|
const minutes = Math.floor((seconds % 3600) / 60);
|
||||||
return { hours, minutes };
|
return { hours, minutes };
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateTooltip = (timeSeconds: number, isCharging: boolean, isCharged: boolean) => {
|
const generateTooltip = (timeSeconds: number, isCharging: boolean, isCharged: boolean): string => {
|
||||||
if (isCharged) {
|
if (isCharged) {
|
||||||
return "Fully Charged!!!";
|
return 'Fully Charged!!!';
|
||||||
}
|
}
|
||||||
|
|
||||||
const { hours, minutes } = formatTime(timeSeconds);
|
const { hours, minutes } = formatTime(timeSeconds);
|
||||||
@@ -41,60 +44,56 @@ const BatteryLabel = () => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
component: Widget.Box({
|
component: Widget.Box({
|
||||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value"), show_label.bind("value")], (style, showLabel) => {
|
className: Utils.merge(
|
||||||
|
[options.theme.bar.buttons.style.bind('value'), show_label.bind('value')],
|
||||||
|
(style, showLabel) => {
|
||||||
const styleMap = {
|
const styleMap = {
|
||||||
default: "style1",
|
default: 'style1',
|
||||||
split: "style2",
|
split: 'style2',
|
||||||
wave: "style3",
|
wave: 'style3',
|
||||||
wave2: "style3",
|
wave2: 'style3',
|
||||||
};
|
};
|
||||||
return `battery ${styleMap[style]} ${!showLabel ? "no-label" : ""}`;
|
return `battery ${styleMap[style]} ${!showLabel ? 'no-label' : ''}`;
|
||||||
}),
|
},
|
||||||
visible: battery.bind("available"),
|
),
|
||||||
tooltip_text: battery.bind("time_remaining").as((t) => t.toString()),
|
visible: battery.bind('available'),
|
||||||
children: Utils.merge(
|
tooltip_text: battery.bind('time_remaining').as((t) => t.toString()),
|
||||||
[battery.bind("available"), show_label.bind("value")],
|
children: Utils.merge([battery.bind('available'), show_label.bind('value')], (batAvail, showLabel) => {
|
||||||
(batAvail, showLabel) => {
|
|
||||||
if (batAvail && showLabel) {
|
if (batAvail && showLabel) {
|
||||||
return [
|
return [
|
||||||
Widget.Icon({
|
Widget.Icon({
|
||||||
class_name: "bar-button-icon battery",
|
class_name: 'bar-button-icon battery',
|
||||||
icon: batIcon
|
icon: batIcon,
|
||||||
}),
|
}),
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
class_name: "bar-button-label battery",
|
class_name: 'bar-button-label battery',
|
||||||
label: battery.bind("percent").as((p) => `${Math.floor(p)}%`),
|
label: battery.bind('percent').as((p) => `${Math.floor(p)}%`),
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
} else if (batAvail && !showLabel) {
|
} else if (batAvail && !showLabel) {
|
||||||
return [
|
return [
|
||||||
Widget.Icon({
|
Widget.Icon({
|
||||||
class_name: "bar-button-icon battery",
|
class_name: 'bar-button-icon battery',
|
||||||
icon: batIcon
|
icon: batIcon,
|
||||||
})
|
}),
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
self.hook(battery, () => {
|
self.hook(battery, () => {
|
||||||
if (battery.available) {
|
if (battery.available) {
|
||||||
self.tooltip_text = generateTooltip(
|
self.tooltip_text = generateTooltip(battery.time_remaining, battery.charging, battery.charged);
|
||||||
battery.time_remaining,
|
|
||||||
battery.charging,
|
|
||||||
battery.charged,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
isVis,
|
isVis,
|
||||||
boxClass: "battery",
|
boxClass: 'battery',
|
||||||
props: {
|
props: {
|
||||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||||
openMenu(clicked, event, "energymenu");
|
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 Gdk from 'gi://Gdk?version=3.0';
|
||||||
import options from "options";
|
import options from 'options';
|
||||||
import { openMenu } from "../utils.js";
|
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 { label } = options.bar.bluetooth;
|
||||||
|
|
||||||
const Bluetooth = () => {
|
const Bluetooth = (): BarBoxChild => {
|
||||||
const btIcon = Widget.Label({
|
const btIcon = Widget.Label({
|
||||||
label: bluetooth.bind("enabled").as((v) => v ? "" : ""),
|
label: bluetooth.bind('enabled').as((v) => (v ? '' : '')),
|
||||||
class_name: "bar-button-icon bluetooth txt-icon bar",
|
class_name: 'bar-button-icon bluetooth txt-icon bar',
|
||||||
});
|
});
|
||||||
|
|
||||||
const btText = Widget.Label({
|
const btText = Widget.Label({
|
||||||
label: Utils.merge([
|
label: Utils.merge([bluetooth.bind('enabled'), bluetooth.bind('connected_devices')], (btEnabled, btDevices) => {
|
||||||
bluetooth.bind("enabled"),
|
return btEnabled && btDevices.length ? ` Connected (${btDevices.length})` : btEnabled ? 'On' : 'Off';
|
||||||
bluetooth.bind("connected_devices"),
|
|
||||||
],
|
|
||||||
(btEnabled, btDevices) => {
|
|
||||||
return btEnabled && btDevices.length ? ` Connected (${btDevices.length})`
|
|
||||||
: btEnabled ? "On"
|
|
||||||
: "Off"
|
|
||||||
|
|
||||||
}),
|
}),
|
||||||
class_name: "bar-button-label bluetooth",
|
class_name: 'bar-button-label bluetooth',
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
component: Widget.Box({
|
component: Widget.Box({
|
||||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value"), label.bind("value")], (style, showLabel) => {
|
className: Utils.merge(
|
||||||
|
[options.theme.bar.buttons.style.bind('value'), label.bind('value')],
|
||||||
|
(style, showLabel) => {
|
||||||
const styleMap = {
|
const styleMap = {
|
||||||
default: "style1",
|
default: 'style1',
|
||||||
split: "style2",
|
split: 'style2',
|
||||||
wave: "style3",
|
wave: 'style3',
|
||||||
wave2: "style3",
|
wave2: 'style3',
|
||||||
};
|
};
|
||||||
return `bluetooth ${styleMap[style]} ${!showLabel ? "no-label" : ""}`;
|
return `bluetooth ${styleMap[style]} ${!showLabel ? 'no-label' : ''}`;
|
||||||
}),
|
},
|
||||||
children: options.bar.bluetooth.label.bind("value").as((showLabel) => {
|
),
|
||||||
|
children: options.bar.bluetooth.label.bind('value').as((showLabel) => {
|
||||||
if (showLabel) {
|
if (showLabel) {
|
||||||
return [btIcon, btText];
|
return [btIcon, btText];
|
||||||
}
|
}
|
||||||
@@ -44,14 +43,13 @@ const Bluetooth = () => {
|
|||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
boxClass: "bluetooth",
|
boxClass: 'bluetooth',
|
||||||
props: {
|
props: {
|
||||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||||
openMenu(clicked, event, "bluetoothmenu");
|
openMenu(clicked, event, 'bluetoothmenu');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
}
|
export { Bluetooth };
|
||||||
|
|
||||||
export { Bluetooth }
|
|
||||||
|
|||||||
@@ -1,45 +1,46 @@
|
|||||||
import Gdk from 'gi://Gdk?version=3.0';
|
import Gdk from 'gi://Gdk?version=3.0';
|
||||||
import GLib from "gi://GLib";
|
import GLib from 'gi://GLib';
|
||||||
import { openMenu } from "../utils.js";
|
import { openMenu } from '../utils.js';
|
||||||
import options from "options";
|
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 { format, icon, showIcon, showTime } = options.bar.clock;
|
||||||
const { style } = options.theme.bar.buttons;
|
const { style } = options.theme.bar.buttons;
|
||||||
|
|
||||||
|
|
||||||
const date = Variable(GLib.DateTime.new_now_local(), {
|
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 time = Utils.derive([date, format], (c, f) => c.format(f) || '');
|
||||||
|
|
||||||
const Clock = () => {
|
|
||||||
|
|
||||||
|
const Clock = (): BarBoxChild => {
|
||||||
const clockTime = Widget.Label({
|
const clockTime = Widget.Label({
|
||||||
class_name: "bar-button-label clock bar",
|
class_name: 'bar-button-label clock bar',
|
||||||
label: time.bind(),
|
label: time.bind(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const clockIcon = Widget.Label({
|
const clockIcon = Widget.Label({
|
||||||
label: icon.bind("value"),
|
label: icon.bind('value'),
|
||||||
class_name: "bar-button-icon clock txt-icon bar",
|
class_name: 'bar-button-icon clock txt-icon bar',
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
component: Widget.Box({
|
component: Widget.Box({
|
||||||
className: Utils.merge([
|
className: Utils.merge(
|
||||||
style.bind("value"),
|
[style.bind('value'), showIcon.bind('value'), showTime.bind('value')],
|
||||||
showIcon.bind("value"), showTime.bind("value")
|
(btnStyle, shwIcn, shwLbl) => {
|
||||||
], (btnStyle, shwIcn, shwLbl) => {
|
|
||||||
const styleMap = {
|
const styleMap = {
|
||||||
default: "style1",
|
default: 'style1',
|
||||||
split: "style2",
|
split: 'style2',
|
||||||
wave: "style3",
|
wave: 'style3',
|
||||||
wave2: "style3",
|
wave2: 'style3',
|
||||||
};
|
};
|
||||||
|
|
||||||
return `bluetooth ${styleMap[btnStyle]} ${!shwLbl ? "no-label" : ""} ${!shwIcn ? "no-icon" : ""}`;
|
return `bluetooth ${styleMap[btnStyle]} ${!shwLbl ? 'no-label' : ''} ${!shwIcn ? 'no-icon' : ''}`;
|
||||||
}),
|
},
|
||||||
children: Utils.merge([showIcon.bind("value"), showTime.bind("value")], (shIcn, shTm) => {
|
),
|
||||||
|
children: Utils.merge([showIcon.bind('value'), showTime.bind('value')], (shIcn, shTm) => {
|
||||||
if (shIcn && !shTm) {
|
if (shIcn && !shTm) {
|
||||||
return [clockIcon];
|
return [clockIcon];
|
||||||
} else if (shTm && !shIcn) {
|
} else if (shTm && !shIcn) {
|
||||||
@@ -47,13 +48,13 @@ const Clock = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return [clockIcon, clockTime];
|
return [clockIcon, clockTime];
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
boxClass: "clock",
|
boxClass: 'clock',
|
||||||
props: {
|
props: {
|
||||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||||
openMenu(clicked, event, "calendarmenu");
|
openMenu(clicked, event, 'calendarmenu');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
import Gdk from 'gi://Gdk?version=3.0';
|
import Gdk from 'gi://Gdk?version=3.0';
|
||||||
const mpris = await Service.import("mpris");
|
const mpris = await Service.import('mpris');
|
||||||
import { openMenu } from "../utils.js";
|
import { openMenu } from '../utils.js';
|
||||||
import options from "options";
|
import options from 'options';
|
||||||
import { getCurrentPlayer } from 'lib/shared/media.js';
|
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 { 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 activePlayer = Variable(mpris.players[0]);
|
||||||
const isVis = Variable(!show_active_only.value);
|
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;
|
isVis.value = !show_active_only.value || mpris.players.length > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
mpris.connect("changed", () => {
|
mpris.connect('changed', () => {
|
||||||
const curPlayer = getCurrentPlayer(activePlayer.value);
|
const curPlayer = getCurrentPlayer(activePlayer.value);
|
||||||
activePlayer.value = curPlayer;
|
activePlayer.value = curPlayer;
|
||||||
isVis.value = !show_active_only.value || mpris.players.length > 0;
|
isVis.value = !show_active_only.value || mpris.players.length > 0;
|
||||||
@@ -22,41 +25,37 @@ const Media = () => {
|
|||||||
|
|
||||||
const getIconForPlayer = (playerName: string): string => {
|
const getIconForPlayer = (playerName: string): string => {
|
||||||
const windowTitleMap = [
|
const windowTitleMap = [
|
||||||
["Firefox", ""],
|
['Firefox', ''],
|
||||||
["Microsoft Edge", ""],
|
['Microsoft Edge', ''],
|
||||||
["Discord", ""],
|
['Discord', ''],
|
||||||
["Plex", ""],
|
['Plex', ''],
|
||||||
["Spotify", ""],
|
['Spotify', ''],
|
||||||
["(.*)", ""],
|
['(.*)', ''],
|
||||||
];
|
];
|
||||||
|
|
||||||
const foundMatch = windowTitleMap.find((wt) =>
|
const foundMatch = windowTitleMap.find((wt) => RegExp(wt[0], 'i').test(playerName));
|
||||||
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) {
|
if (activePlayer.value && show_label.value) {
|
||||||
const { track_title, identity, track_artists } = activePlayer.value;
|
const { track_title, identity, track_artists } = activePlayer.value;
|
||||||
songIcon.value = getIconForPlayer(identity);
|
songIcon.value = getIconForPlayer(identity);
|
||||||
const trackArtist = show_artist.value
|
const trackArtist = show_artist.value ? ` - ${track_artists.join(', ')}` : ``;
|
||||||
? ` - ${track_artists.join(', ')}`
|
|
||||||
: ``;
|
|
||||||
const truncatedLabel = truncation.value
|
const truncatedLabel = truncation.value
|
||||||
? `${track_title + trackArtist}`.substring(0, truncation_size.value)
|
? `${track_title + trackArtist}`.substring(0, truncation_size.value)
|
||||||
: `${track_title + trackArtist}`;
|
: `${track_title + trackArtist}`;
|
||||||
|
|
||||||
return track_title.length === 0
|
return track_title.length === 0
|
||||||
? `No media playing...`
|
? `No media playing...`
|
||||||
: ((truncatedLabel.length < truncation_size.value) || !truncation.value)
|
: truncatedLabel.length < truncation_size.value || !truncation.value
|
||||||
? `${truncatedLabel}`
|
? `${truncatedLabel}`
|
||||||
: `${truncatedLabel.substring(0, truncatedLabel.length - 3)}...`;
|
: `${truncatedLabel.substring(0, truncatedLabel.length - 3)}...`;
|
||||||
} else {
|
} else {
|
||||||
songIcon.value = getIconForPlayer(activePlayer.value?.identity || "");
|
songIcon.value = getIconForPlayer(activePlayer.value?.identity || '');
|
||||||
return `Media`;
|
return `Media`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -65,23 +64,26 @@ const Media = () => {
|
|||||||
component: Widget.Box({
|
component: Widget.Box({
|
||||||
visible: false,
|
visible: false,
|
||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value"), show_label.bind("value")], (style, showLabel) => {
|
className: Utils.merge(
|
||||||
|
[options.theme.bar.buttons.style.bind('value'), show_label.bind('value')],
|
||||||
|
(style) => {
|
||||||
const styleMap = {
|
const styleMap = {
|
||||||
default: "style1",
|
default: 'style1',
|
||||||
split: "style2",
|
split: 'style2',
|
||||||
wave: "style3",
|
wave: 'style3',
|
||||||
wave2: "style3",
|
wave2: 'style3',
|
||||||
};
|
};
|
||||||
return `media ${styleMap[style]}`;
|
return `media ${styleMap[style]}`;
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
children: [
|
children: [
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
class_name: "bar-button-icon media txt-icon bar",
|
class_name: 'bar-button-icon media txt-icon bar',
|
||||||
label: songIcon.bind("value").as(v => v || ""),
|
label: songIcon.bind('value').as((v) => v || ''),
|
||||||
}),
|
}),
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
class_name: "bar-button-label media",
|
class_name: 'bar-button-label media',
|
||||||
label: mediaLabel,
|
label: mediaLabel,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -89,13 +91,13 @@ const Media = () => {
|
|||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
isVis,
|
isVis,
|
||||||
boxClass: "media",
|
boxClass: 'media',
|
||||||
name: "media",
|
name: 'media',
|
||||||
props: {
|
props: {
|
||||||
on_scroll_up: () => activePlayer.value?.next(),
|
on_scroll_up: () => activePlayer.value?.next(),
|
||||||
on_scroll_down: () => activePlayer.value?.previous(),
|
on_scroll_down: () => activePlayer.value?.previous(),
|
||||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||||
openMenu(clicked, event, "mediamenu");
|
openMenu(clicked, event, 'mediamenu');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,29 +1,32 @@
|
|||||||
import Gdk from 'gi://Gdk?version=3.0';
|
import Gdk from 'gi://Gdk?version=3.0';
|
||||||
import { openMenu } from "../utils.js";
|
import { openMenu } from '../utils.js';
|
||||||
import options from "options";
|
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 {
|
return {
|
||||||
component: Widget.Box({
|
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 = {
|
const styleMap = {
|
||||||
default: "style1",
|
default: 'style1',
|
||||||
split: "style2",
|
split: 'style2',
|
||||||
wave: "style3",
|
wave: 'style3',
|
||||||
wave2: "style3",
|
wave2: 'style3',
|
||||||
};
|
};
|
||||||
return `dashboard ${styleMap[style]}`;
|
return `dashboard ${styleMap[style]}`;
|
||||||
}),
|
}),
|
||||||
child: Widget.Label({
|
child: Widget.Label({
|
||||||
class_name: "bar-menu_label bar-button_icon txt-icon bar",
|
class_name: 'bar-menu_label bar-button_icon txt-icon bar',
|
||||||
label: options.bar.launcher.icon.bind("value"),
|
label: options.bar.launcher.icon.bind('value'),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
boxClass: "dashboard",
|
boxClass: 'dashboard',
|
||||||
props: {
|
props: {
|
||||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||||
openMenu(clicked, event, "dashboardmenu");
|
openMenu(clicked, event, 'dashboardmenu');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,70 +1,77 @@
|
|||||||
import Gdk from 'gi://Gdk?version=3.0';
|
import Gdk from 'gi://Gdk?version=3.0';
|
||||||
const network = await Service.import("network");
|
const network = await Service.import('network');
|
||||||
import options from "options";
|
import options from 'options';
|
||||||
import { openMenu } from "../utils.js";
|
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 { label: networkLabel, truncation, truncation_size } = options.bar.network;
|
||||||
|
|
||||||
const Network = () => {
|
const Network = (): BarBoxChild => {
|
||||||
return {
|
return {
|
||||||
component: Widget.Box({
|
component: Widget.Box({
|
||||||
vpack: "fill",
|
vpack: 'fill',
|
||||||
vexpand: true,
|
vexpand: true,
|
||||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value"), networkLabel.bind("value")], (style, showLabel) => {
|
className: Utils.merge(
|
||||||
|
[options.theme.bar.buttons.style.bind('value'), networkLabel.bind('value')],
|
||||||
|
(style, showLabel) => {
|
||||||
const styleMap = {
|
const styleMap = {
|
||||||
default: "style1",
|
default: 'style1',
|
||||||
split: "style2",
|
split: 'style2',
|
||||||
wave: "style3",
|
wave: 'style3',
|
||||||
wave2: "style3",
|
wave2: 'style3',
|
||||||
};
|
};
|
||||||
return `network ${styleMap[style]}${!showLabel ? " no-label" : ""}`;
|
return `network ${styleMap[style]}${!showLabel ? ' no-label' : ''}`;
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
children: [
|
children: [
|
||||||
Widget.Icon({
|
Widget.Icon({
|
||||||
class_name: "bar-button-icon network",
|
class_name: 'bar-button-icon network',
|
||||||
icon: Utils.merge([
|
icon: Utils.merge(
|
||||||
network.bind("primary"),
|
[network.bind('primary'), network.bind('wifi'), network.bind('wired')],
|
||||||
network.bind("wifi"),
|
(pmry, wfi, wrd) => {
|
||||||
network.bind("wired")
|
if (pmry === 'wired') {
|
||||||
], (pmry, wfi, wrd) => {
|
|
||||||
if (pmry === "wired") {
|
|
||||||
return wrd.icon_name;
|
return wrd.icon_name;
|
||||||
}
|
}
|
||||||
return wfi.icon_name;
|
return wfi.icon_name;
|
||||||
})
|
},
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
vpack: "center",
|
vpack: 'center',
|
||||||
child: Utils.merge([
|
child: Utils.merge(
|
||||||
network.bind("primary"),
|
[
|
||||||
network.bind("wifi"),
|
network.bind('primary'),
|
||||||
networkLabel.bind("value"),
|
network.bind('wifi'),
|
||||||
truncation.bind("value"),
|
networkLabel.bind('value'),
|
||||||
truncation_size.bind("value")
|
truncation.bind('value'),
|
||||||
], (pmry, wfi, showLbl, trunc, tSize) => {
|
truncation_size.bind('value'),
|
||||||
|
],
|
||||||
|
(pmry, wfi, showLbl, trunc, tSize) => {
|
||||||
if (!showLbl) {
|
if (!showLbl) {
|
||||||
return Widget.Box();
|
return Widget.Box();
|
||||||
}
|
}
|
||||||
if (pmry === "wired") {
|
if (pmry === 'wired') {
|
||||||
return Widget.Label({
|
return Widget.Label({
|
||||||
class_name: "bar-button-label network",
|
class_name: 'bar-button-label network',
|
||||||
label: "Wired".substring(0, tSize),
|
label: 'Wired'.substring(0, tSize),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
return Widget.Label({
|
return Widget.Label({
|
||||||
class_name: "bar-button-label network",
|
class_name: 'bar-button-label network',
|
||||||
label: wfi.ssid ? `${trunc ? wfi.ssid.substring(0, tSize) : wfi.ssid}` : "--",
|
label: wfi.ssid ? `${trunc ? wfi.ssid.substring(0, tSize) : wfi.ssid}` : '--',
|
||||||
})
|
});
|
||||||
|
},
|
||||||
})
|
),
|
||||||
}),
|
}),
|
||||||
]
|
],
|
||||||
}),
|
}),
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
boxClass: "network",
|
boxClass: 'network',
|
||||||
props: {
|
props: {
|
||||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||||
openMenu(clicked, event, "networkmenu");
|
openMenu(clicked, event, 'networkmenu');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,51 +1,49 @@
|
|||||||
import Gdk from 'gi://Gdk?version=3.0';
|
import Gdk from 'gi://Gdk?version=3.0';
|
||||||
import { openMenu } from "../utils.js";
|
import { openMenu } from '../utils.js';
|
||||||
import options from "options";
|
import options from 'options';
|
||||||
import { filterNotifications } from 'lib/shared/notifications.js';
|
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 { show_total } = options.bar.notifications;
|
||||||
const { ignore } = options.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 {
|
return {
|
||||||
component: Widget.Box({
|
component: Widget.Box({
|
||||||
hpack: "start",
|
hpack: 'start',
|
||||||
className: Utils.merge(
|
className: Utils.merge(
|
||||||
[
|
[options.theme.bar.buttons.style.bind('value'), show_total.bind('value')],
|
||||||
options.theme.bar.buttons.style.bind("value"),
|
(style, showTotal) => {
|
||||||
show_total.bind("value")
|
|
||||||
],
|
|
||||||
(
|
|
||||||
style,
|
|
||||||
showTotal
|
|
||||||
) => {
|
|
||||||
const styleMap = {
|
const styleMap = {
|
||||||
default: "style1",
|
default: 'style1',
|
||||||
split: "style2",
|
split: 'style2',
|
||||||
wave: "style3",
|
wave: 'style3',
|
||||||
wave2: "style3",
|
wave2: 'style3',
|
||||||
};
|
};
|
||||||
return `notifications ${styleMap[style]} ${!showTotal ? "no-label" : ""}`;
|
return `notifications ${styleMap[style]} ${!showTotal ? 'no-label' : ''}`;
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
hpack: "start",
|
hpack: 'start',
|
||||||
class_name: "bar-notifications",
|
class_name: 'bar-notifications',
|
||||||
children: Utils.merge(
|
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) => {
|
(notif, dnd, showTotal, ignoredNotifs) => {
|
||||||
const filteredNotifications = filterNotifications(notif, ignoredNotifs);
|
const filteredNotifications = filterNotifications(notif, ignoredNotifs);
|
||||||
|
|
||||||
const notifIcon = Widget.Label({
|
const notifIcon = Widget.Label({
|
||||||
hpack: "center",
|
hpack: 'center',
|
||||||
class_name: "bar-button-icon notifications txt-icon bar",
|
class_name: 'bar-button-icon notifications txt-icon bar',
|
||||||
label: dnd ? "" : filteredNotifications.length > 0 ? "" : "",
|
label: dnd ? '' : filteredNotifications.length > 0 ? '' : '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const notifLabel = Widget.Label({
|
const notifLabel = Widget.Label({
|
||||||
hpack: "center",
|
hpack: 'center',
|
||||||
class_name: "bar-button-label notifications",
|
class_name: 'bar-button-label notifications',
|
||||||
label: filteredNotifications.length.toString(),
|
label: filteredNotifications.length.toString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -58,10 +56,10 @@ export const Notifications = () => {
|
|||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
boxClass: "notifications",
|
boxClass: 'notifications',
|
||||||
props: {
|
props: {
|
||||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||||
openMenu(clicked, event, "notificationsmenu");
|
openMenu(clicked, event, 'notificationsmenu');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,49 +1,43 @@
|
|||||||
import Gdk from 'gi://Gdk?version=3.0';
|
import Gdk from 'gi://Gdk?version=3.0';
|
||||||
|
import { BarBoxChild, SelfButton } from 'lib/types/bar';
|
||||||
import { Notify } from 'lib/utils';
|
import { Notify } from 'lib/utils';
|
||||||
const systemtray = await Service.import("systemtray");
|
const systemtray = await Service.import('systemtray');
|
||||||
import options from "options";
|
import options from 'options';
|
||||||
|
|
||||||
const { ignore } = options.bar.systray;
|
const { ignore } = options.bar.systray;
|
||||||
|
|
||||||
const SysTray = () => {
|
const SysTray = (): BarBoxChild => {
|
||||||
const isVis = Variable(false);
|
const isVis = Variable(false);
|
||||||
|
|
||||||
const items = Utils.merge(
|
const items = Utils.merge([systemtray.bind('items'), ignore.bind('value')], (items, ignored) => {
|
||||||
[systemtray.bind("items"), ignore.bind("value")],
|
|
||||||
(items, ignored) => {
|
|
||||||
const filteredTray = items.filter(({ id }) => !ignored.includes(id));
|
const filteredTray = items.filter(({ id }) => !ignored.includes(id));
|
||||||
|
|
||||||
isVis.value = filteredTray.length > 0;
|
isVis.value = filteredTray.length > 0;
|
||||||
|
|
||||||
return filteredTray.map((item) => {
|
return filteredTray.map((item) => {
|
||||||
if (item.menu !== undefined) {
|
|
||||||
item.menu["class_name"] = "systray-menu";
|
|
||||||
}
|
|
||||||
|
|
||||||
return Widget.Button({
|
return Widget.Button({
|
||||||
cursor: "pointer",
|
cursor: 'pointer',
|
||||||
child: Widget.Icon({
|
child: Widget.Icon({
|
||||||
class_name: "systray-icon",
|
class_name: 'systray-icon',
|
||||||
icon: item.bind("icon"),
|
icon: item.bind('icon'),
|
||||||
}),
|
}),
|
||||||
on_primary_click: (_: any, event: Gdk.Event) => item.activate(event),
|
on_primary_click: (_: SelfButton, event: Gdk.Event) => item.activate(event),
|
||||||
on_secondary_click: (_, event) => item.openMenu(event),
|
on_secondary_click: (_, event) => item.openMenu(event),
|
||||||
onMiddleClick: () => Notify({ summary: "App Name", body: item.id }),
|
onMiddleClick: () => Notify({ summary: 'App Name', body: item.id }),
|
||||||
tooltip_markup: item.bind("tooltip_markup"),
|
tooltip_markup: item.bind('tooltip_markup'),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
component: Widget.Box({
|
component: Widget.Box({
|
||||||
class_name: "systray",
|
class_name: 'systray',
|
||||||
children: items,
|
children: items,
|
||||||
}),
|
}),
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
boxClass: "systray",
|
boxClass: 'systray',
|
||||||
isVis,
|
isVis,
|
||||||
props: {}
|
props: {},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import Gdk from 'gi://Gdk?version=3.0';
|
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
|
const menuWindows = App.windows
|
||||||
.filter((w) => {
|
.filter((w) => {
|
||||||
if (w.name) {
|
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
|
* 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
|
* 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';
|
import Gdk from 'gi://Gdk?version=3.0';
|
||||||
const audio = await Service.import("audio");
|
const audio = await Service.import('audio');
|
||||||
import { openMenu } from "../utils.js";
|
import { openMenu } from '../utils.js';
|
||||||
import options from "options";
|
import options from 'options';
|
||||||
import { Binding } from 'lib/utils.js';
|
import { Binding } from 'lib/utils.js';
|
||||||
import { VolumeIcons } from 'lib/types/volume.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 = {
|
const icons: VolumeIcons = {
|
||||||
101: "",
|
101: '',
|
||||||
66: "",
|
66: '',
|
||||||
34: "",
|
34: '',
|
||||||
1: "",
|
1: '',
|
||||||
0: "",
|
0: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const getIcon = () => {
|
const getIcon = (): Bind => {
|
||||||
const icon: Binding<number> = Utils.merge(
|
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) => {
|
(isMuted, vol) => {
|
||||||
return isMuted
|
return isMuted ? 0 : [101, 66, 34, 1, 0].find((threshold) => threshold <= vol * 100) || 101;
|
||||||
? 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({
|
const volIcn = Widget.Label({
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
label: getIcon(),
|
label: getIcon(),
|
||||||
class_name: "bar-button-icon volume txt-icon bar",
|
class_name: 'bar-button-icon volume txt-icon bar',
|
||||||
});
|
});
|
||||||
|
|
||||||
const volPct = Widget.Label({
|
const volPct = Widget.Label({
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
label: audio.speaker.bind("volume").as((v) => `${Math.round(v * 100)}%`),
|
label: audio.speaker.bind('volume').as((v) => `${Math.round(v * 100)}%`),
|
||||||
class_name: "bar-button-label volume",
|
class_name: 'bar-button-label volume',
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
component: Widget.Box({
|
component: Widget.Box({
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
vexpand: true,
|
vexpand: true,
|
||||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value"), options.bar.volume.label.bind("value")], (style, showLabel) => {
|
className: Utils.merge(
|
||||||
|
[options.theme.bar.buttons.style.bind('value'), options.bar.volume.label.bind('value')],
|
||||||
|
(style, showLabel) => {
|
||||||
const styleMap = {
|
const styleMap = {
|
||||||
default: "style1",
|
default: 'style1',
|
||||||
split: "style2",
|
split: 'style2',
|
||||||
wave: "style3",
|
wave: 'style3',
|
||||||
wave2: "style3",
|
wave2: 'style3',
|
||||||
};
|
};
|
||||||
|
return `volume ${styleMap[style]} ${!showLabel ? 'no-label' : ''}`;
|
||||||
return `volume ${styleMap[style]} ${!showLabel ? "no-label" : ""}`;
|
},
|
||||||
}),
|
),
|
||||||
children: options.bar.volume.label.bind("value").as((showLabel) => {
|
children: options.bar.volume.label.bind('value').as((showLabel) => {
|
||||||
if (showLabel) {
|
if (showLabel) {
|
||||||
return [volIcn, volPct];
|
return [volIcn, volPct];
|
||||||
}
|
}
|
||||||
@@ -61,10 +65,10 @@ const Volume = () => {
|
|||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
boxClass: "volume",
|
boxClass: 'volume',
|
||||||
props: {
|
props: {
|
||||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
on_primary_click: (clicked: Button<Child, Child>, event: Gdk.Event): void => {
|
||||||
openMenu(clicked, event, "audiomenu");
|
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 options from 'options';
|
||||||
import { ActiveClient } from 'types/service/hyprland'
|
import { ActiveClient } from 'types/service/hyprland';
|
||||||
import Label from "types/widgets/label";
|
|
||||||
|
|
||||||
const filterTitle = (windowtitle: ActiveClient) => {
|
const filterTitle = (windowtitle: ActiveClient): Record<string, string> => {
|
||||||
const windowTitleMap = [
|
const windowTitleMap = [
|
||||||
// user provided values
|
// user provided values
|
||||||
...options.bar.windowtitle.title_map.value,
|
...options.bar.windowtitle.title_map.value,
|
||||||
// Original Entries
|
// Original Entries
|
||||||
["kitty", "", "Kitty Terminal"],
|
['kitty', '', 'Kitty Terminal'],
|
||||||
["firefox", "", "Firefox"],
|
['firefox', '', 'Firefox'],
|
||||||
["microsoft-edge", "", "Edge"],
|
['microsoft-edge', '', 'Edge'],
|
||||||
["discord", "", "Discord"],
|
['discord', '', 'Discord'],
|
||||||
["vesktop", "", "Vesktop"],
|
['vesktop', '', 'Vesktop'],
|
||||||
["org.kde.dolphin", "", "Dolphin"],
|
['org.kde.dolphin', '', 'Dolphin'],
|
||||||
["plex", "", "Plex"],
|
['plex', '', 'Plex'],
|
||||||
["steam", "", "Steam"],
|
['steam', '', 'Steam'],
|
||||||
["spotify", "", "Spotify"],
|
['spotify', '', 'Spotify'],
|
||||||
["ristretto", "", "Ristretto"],
|
['ristretto', '', 'Ristretto'],
|
||||||
["obsidian", "", "Obsidian"],
|
['obsidian', '', 'Obsidian'],
|
||||||
|
|
||||||
// Browsers
|
// Browsers
|
||||||
["google-chrome", "", "Google Chrome"],
|
['google-chrome', '', 'Google Chrome'],
|
||||||
["brave-browser", "", "Brave Browser"],
|
['brave-browser', '', 'Brave Browser'],
|
||||||
["chromium", "", "Chromium"],
|
['chromium', '', 'Chromium'],
|
||||||
["opera", "", "Opera"],
|
['opera', '', 'Opera'],
|
||||||
["vivaldi", "", "Vivaldi"],
|
['vivaldi', '', 'Vivaldi'],
|
||||||
["waterfox", "", "Waterfox"],
|
['waterfox', '', 'Waterfox'],
|
||||||
["thorium", "", "Waterfox"],
|
['thorium', '', 'Waterfox'],
|
||||||
["tor-browser", "", "Tor Browser"],
|
['tor-browser', '', 'Tor Browser'],
|
||||||
["floorp", "", "Floorp"],
|
['floorp', '', 'Floorp'],
|
||||||
|
|
||||||
// Terminals
|
// Terminals
|
||||||
["gnome-terminal", "", "GNOME Terminal"],
|
['gnome-terminal', '', 'GNOME Terminal'],
|
||||||
["konsole", "", "Konsole"],
|
['konsole', '', 'Konsole'],
|
||||||
["alacritty", "", "Alacritty"],
|
['alacritty', '', 'Alacritty'],
|
||||||
["wezterm", "", "Wezterm"],
|
['wezterm', '', 'Wezterm'],
|
||||||
["foot", "", "Foot Terminal"],
|
['foot', '', 'Foot Terminal'],
|
||||||
["tilix", "", "Tilix"],
|
['tilix', '', 'Tilix'],
|
||||||
["xterm", "", "XTerm"],
|
['xterm', '', 'XTerm'],
|
||||||
["urxvt", "", "URxvt"],
|
['urxvt', '', 'URxvt'],
|
||||||
["st", "", "st Terminal"],
|
['st', '', 'st Terminal'],
|
||||||
|
|
||||||
// Development Tools
|
// Development Tools
|
||||||
["code", "", "Visual Studio Code"],
|
['code', '', 'Visual Studio Code'],
|
||||||
["vscode", "", "VS Code"],
|
['vscode', '', 'VS Code'],
|
||||||
["sublime-text", "", "Sublime Text"],
|
['sublime-text', '', 'Sublime Text'],
|
||||||
["atom", "", "Atom"],
|
['atom', '', 'Atom'],
|
||||||
["android-studio", "", "Android Studio"],
|
['android-studio', '', 'Android Studio'],
|
||||||
["intellij-idea", "", "IntelliJ IDEA"],
|
['intellij-idea', '', 'IntelliJ IDEA'],
|
||||||
["pycharm", "", "PyCharm"],
|
['pycharm', '', 'PyCharm'],
|
||||||
["webstorm", "", "WebStorm"],
|
['webstorm', '', 'WebStorm'],
|
||||||
["phpstorm", "", "PhpStorm"],
|
['phpstorm', '', 'PhpStorm'],
|
||||||
["eclipse", "", "Eclipse"],
|
['eclipse', '', 'Eclipse'],
|
||||||
["netbeans", "", "NetBeans"],
|
['netbeans', '', 'NetBeans'],
|
||||||
["docker", "", "Docker"],
|
['docker', '', 'Docker'],
|
||||||
["vim", "", "Vim"],
|
['vim', '', 'Vim'],
|
||||||
["neovim", "", "Neovim"],
|
['neovim', '', 'Neovim'],
|
||||||
["neovide", "", "Neovide"],
|
['neovide', '', 'Neovide'],
|
||||||
["emacs", "", "Emacs"],
|
['emacs', '', 'Emacs'],
|
||||||
|
|
||||||
// Communication Tools
|
// Communication Tools
|
||||||
["slack", "", "Slack"],
|
['slack', '', 'Slack'],
|
||||||
["telegram-desktop", "", "Telegram"],
|
['telegram-desktop', '', 'Telegram'],
|
||||||
["org.telegram.desktop", "", "Telegram"],
|
['org.telegram.desktop', '', 'Telegram'],
|
||||||
["whatsapp", "", "WhatsApp"],
|
['whatsapp', '', 'WhatsApp'],
|
||||||
["teams", "", "Microsoft Teams"],
|
['teams', '', 'Microsoft Teams'],
|
||||||
["skype", "", "Skype"],
|
['skype', '', 'Skype'],
|
||||||
["thunderbird", "", "Thunderbird"],
|
['thunderbird', '', 'Thunderbird'],
|
||||||
|
|
||||||
// File Managers
|
// File Managers
|
||||||
["nautilus", "", "Files (Nautilus)"],
|
['nautilus', '', 'Files (Nautilus)'],
|
||||||
["thunar", "", "Thunar"],
|
['thunar', '', 'Thunar'],
|
||||||
["pcmanfm", "", "PCManFM"],
|
['pcmanfm', '', 'PCManFM'],
|
||||||
["nemo", "", "Nemo"],
|
['nemo', '', 'Nemo'],
|
||||||
["ranger", "", "Ranger"],
|
['ranger', '', 'Ranger'],
|
||||||
["doublecmd", "", "Double Commander"],
|
['doublecmd', '', 'Double Commander'],
|
||||||
["krusader", "", "Krusader"],
|
['krusader', '', 'Krusader'],
|
||||||
|
|
||||||
// Media Players
|
// Media Players
|
||||||
["vlc", "", "VLC Media Player"],
|
['vlc', '', 'VLC Media Player'],
|
||||||
["mpv", "", "MPV"],
|
['mpv', '', 'MPV'],
|
||||||
["rhythmbox", "", "Rhythmbox"],
|
['rhythmbox', '', 'Rhythmbox'],
|
||||||
|
|
||||||
// Graphics Tools
|
// Graphics Tools
|
||||||
["gimp", "", "GIMP"],
|
['gimp', '', 'GIMP'],
|
||||||
["inkscape", "", "Inkscape"],
|
['inkscape', '', 'Inkscape'],
|
||||||
["krita", "", "Krita"],
|
['krita', '', 'Krita'],
|
||||||
["blender", "", "Blender"],
|
['blender', '', 'Blender'],
|
||||||
|
|
||||||
// Video Editing
|
// Video Editing
|
||||||
["kdenlive", "", "Kdenlive"],
|
['kdenlive', '', 'Kdenlive'],
|
||||||
|
|
||||||
// Games and Gaming Platforms
|
// Games and Gaming Platforms
|
||||||
["lutris", "", "Lutris"],
|
['lutris', '', 'Lutris'],
|
||||||
["heroic", "", "Heroic Games Launcher"],
|
['heroic', '', 'Heroic Games Launcher'],
|
||||||
["minecraft", "", "Minecraft"],
|
['minecraft', '', 'Minecraft'],
|
||||||
["csgo", "", "CS:GO"],
|
['csgo', '', 'CS:GO'],
|
||||||
["dota2", "", "Dota 2"],
|
['dota2', '', 'Dota 2'],
|
||||||
|
|
||||||
// Office and Productivity
|
// Office and Productivity
|
||||||
["evernote", "", "Evernote"],
|
['evernote', '', 'Evernote'],
|
||||||
["sioyek", "", "Sioyek"],
|
['sioyek', '', 'Sioyek'],
|
||||||
|
|
||||||
|
|
||||||
// Cloud Services and Sync
|
// Cloud Services and Sync
|
||||||
["dropbox", "", "Dropbox"],
|
['dropbox', '', 'Dropbox'],
|
||||||
|
|
||||||
// Desktop
|
// Desktop
|
||||||
["^$", "", "Desktop"],
|
['^$', '', 'Desktop'],
|
||||||
|
|
||||||
// Fallback icon
|
// 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) =>
|
const foundMatch = windowTitleMap.find((wt) => RegExp(wt[0]).test(windowtitle.class.toLowerCase()));
|
||||||
RegExp(wt[0]).test(windowtitle.class.toLowerCase()),
|
|
||||||
);
|
|
||||||
|
|
||||||
// return the default icon if no match is found or
|
// return the default icon if no match is found or
|
||||||
// if the array element matched is not of size 3
|
// if the array element matched is not of size 3
|
||||||
@@ -129,15 +126,15 @@ const filterTitle = (windowtitle: ActiveClient) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
icon: foundMatch[1],
|
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 (useCustomTitle) return filterTitle(client).label;
|
||||||
if (useClassName) return client.class;
|
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 the title is empty or only filled with spaces, fallback to the class name
|
||||||
if (title.length === 0 || title.match(/^ *$/)) {
|
if (title.length === 0 || title.match(/^ *$/)) {
|
||||||
return client.class;
|
return client.class;
|
||||||
@@ -145,51 +142,76 @@ const getTitle = (client: ActiveClient, useCustomTitle: boolean, useClassName: b
|
|||||||
return title;
|
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) {
|
if (max_size > 0 && title.length > max_size) {
|
||||||
return title.substring(0, max_size).trim() + "...";
|
return title.substring(0, max_size).trim() + '...';
|
||||||
}
|
}
|
||||||
return title;
|
return title;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ClientTitle = () => {
|
const ClientTitle = (): BarBoxChild => {
|
||||||
const { custom_title, class_name, label, icon, truncation, truncation_size } = options.bar.windowtitle;
|
const { custom_title, class_name, label, icon, truncation, truncation_size } = options.bar.windowtitle;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
component: Widget.Box({
|
component: Widget.Box({
|
||||||
className: Utils.merge([options.theme.bar.buttons.style.bind("value"), label.bind("value")], (style, showLabel) => {
|
className: Utils.merge(
|
||||||
|
[options.theme.bar.buttons.style.bind('value'), label.bind('value')],
|
||||||
|
(style, showLabel) => {
|
||||||
const styleMap = {
|
const styleMap = {
|
||||||
default: "style1",
|
default: 'style1',
|
||||||
split: "style2",
|
split: 'style2',
|
||||||
wave: "style3",
|
wave: 'style3',
|
||||||
wave2: "style3",
|
wave2: 'style3',
|
||||||
};
|
};
|
||||||
return `windowtitle ${styleMap[style]} ${!showLabel ? "no-label" : ""}`;
|
return `windowtitle ${styleMap[style]} ${!showLabel ? 'no-label' : ''}`;
|
||||||
}),
|
},
|
||||||
children:
|
),
|
||||||
Utils.merge(
|
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")],
|
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) => {
|
(client, useCustomTitle, useClassName, showLabel, showIcon, truncate, truncationSize) => {
|
||||||
const children: Label<any>[] = [];
|
|
||||||
if (showIcon) {
|
if (showIcon) {
|
||||||
children.push(Widget.Label({
|
return [
|
||||||
class_name: "bar-button-icon windowtitle txt-icon bar",
|
Widget.Label({
|
||||||
|
class_name: 'bar-button-icon windowtitle txt-icon bar',
|
||||||
label: filterTitle(client).icon,
|
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,
|
isVisible: true,
|
||||||
boxClass: "windowtitle",
|
boxClass: 'windowtitle',
|
||||||
props: {}
|
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 { MonitorMap, WorkspaceMap, WorkspaceRule } from 'lib/types/workspace';
|
||||||
import options from "options";
|
import options from 'options';
|
||||||
import { Variable } from "types/variable";
|
import { Variable } from 'types/variable';
|
||||||
|
|
||||||
const {
|
|
||||||
workspaces,
|
|
||||||
reverse_scroll,
|
|
||||||
} = options.bar.workspaces;
|
|
||||||
|
|
||||||
|
const { workspaces, reverse_scroll } = options.bar.workspaces;
|
||||||
|
|
||||||
export const getWorkspacesForMonitor = (curWs: number, wsRules: WorkspaceMap, monitor: number): boolean => {
|
export const getWorkspacesForMonitor = (curWs: number, wsRules: WorkspaceMap, monitor: number): boolean => {
|
||||||
if (!wsRules || !Object.keys(wsRules).length) {
|
if (!wsRules || !Object.keys(wsRules).length) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const monitorMap = {};
|
const monitorMap: MonitorMap = {};
|
||||||
const workspaceMonitorList = hyprland?.workspaces?.map(m => ({ id: m.monitorID, name: m.monitor }));
|
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 monitors = [
|
||||||
|
...new Map([...workspaceMonitorList, ...hyprland.monitors].map((item) => [item.id, item])).values(),
|
||||||
|
];
|
||||||
|
|
||||||
monitors.forEach((m) => (monitorMap[m.id] = m.name));
|
monitors.forEach((m) => (monitorMap[m.id] = m.name));
|
||||||
|
|
||||||
@@ -32,9 +30,9 @@ export const getWorkspacesForMonitor = (curWs: number, wsRules: WorkspaceMap, mo
|
|||||||
|
|
||||||
export const getWorkspaceRules = (): WorkspaceMap => {
|
export const getWorkspaceRules = (): WorkspaceMap => {
|
||||||
try {
|
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) => {
|
JSON.parse(rules).forEach((rule: WorkspaceRule, index: number) => {
|
||||||
if (Object.hasOwnProperty.call(workspaceRules, rule.monitor)) {
|
if (Object.hasOwnProperty.call(workspaceRules, rule.monitor)) {
|
||||||
@@ -60,13 +58,13 @@ export const getCurrentMonitorWorkspaces = (monitor: number): number[] => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const monitorWorkspaces = getWorkspaceRules();
|
const monitorWorkspaces = getWorkspaceRules();
|
||||||
const monitorMap = {};
|
const monitorMap: MonitorMap = {};
|
||||||
hyprland.monitors.forEach((m) => (monitorMap[m.id] = m.name));
|
hyprland.monitors.forEach((m) => (monitorMap[m.id] = m.name));
|
||||||
|
|
||||||
const currentMonitorName = monitorMap[monitor];
|
const currentMonitorName = monitorMap[monitor];
|
||||||
|
|
||||||
return monitorWorkspaces[currentMonitorName];
|
return monitorWorkspaces[currentMonitorName];
|
||||||
}
|
};
|
||||||
|
|
||||||
export const goToNextWS = (currentMonitorWorkspaces: Variable<number[]>, activeWorkspaces: boolean): void => {
|
export const goToNextWS = (currentMonitorWorkspaces: Variable<number[]>, activeWorkspaces: boolean): void => {
|
||||||
if (activeWorkspaces === true) {
|
if (activeWorkspaces === true) {
|
||||||
@@ -74,18 +72,17 @@ export const goToNextWS = (currentMonitorWorkspaces: Variable<number[]>, activeW
|
|||||||
|
|
||||||
let nextIndex = hyprland.active.workspace.id + 1;
|
let nextIndex = hyprland.active.workspace.id + 1;
|
||||||
if (nextIndex > activeWses[activeWses.length - 1].id) {
|
if (nextIndex > activeWses[activeWses.length - 1].id) {
|
||||||
|
|
||||||
nextIndex = activeWses[0].id;
|
nextIndex = activeWses[0].id;
|
||||||
}
|
}
|
||||||
|
|
||||||
hyprland.messageAsync(`dispatch workspace ${nextIndex}`)
|
hyprland.messageAsync(`dispatch workspace ${nextIndex}`);
|
||||||
} else if (currentMonitorWorkspaces.value === undefined) {
|
} else if (currentMonitorWorkspaces.value === undefined) {
|
||||||
let nextIndex = hyprland.active.workspace.id + 1;
|
let nextIndex = hyprland.active.workspace.id + 1;
|
||||||
if (nextIndex > workspaces.value) {
|
if (nextIndex > workspaces.value) {
|
||||||
nextIndex = 0;
|
nextIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
hyprland.messageAsync(`dispatch workspace ${nextIndex}`)
|
hyprland.messageAsync(`dispatch workspace ${nextIndex}`);
|
||||||
} else {
|
} else {
|
||||||
const curWorkspace = hyprland.active.workspace.id;
|
const curWorkspace = hyprland.active.workspace.id;
|
||||||
const indexOfWs = currentMonitorWorkspaces.value.indexOf(curWorkspace);
|
const indexOfWs = currentMonitorWorkspaces.value.indexOf(curWorkspace);
|
||||||
@@ -94,9 +91,9 @@ export const goToNextWS = (currentMonitorWorkspaces: Variable<number[]>, activeW
|
|||||||
nextIndex = 0;
|
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 => {
|
export const goToPrevWS = (currentMonitorWorkspaces: Variable<number[]>, activeWorkspaces: boolean): void => {
|
||||||
if (activeWorkspaces === true) {
|
if (activeWorkspaces === true) {
|
||||||
@@ -104,11 +101,10 @@ export const goToPrevWS = (currentMonitorWorkspaces: Variable<number[]>, activeW
|
|||||||
|
|
||||||
let prevIndex = hyprland.active.workspace.id - 1;
|
let prevIndex = hyprland.active.workspace.id - 1;
|
||||||
if (prevIndex < activeWses[0].id) {
|
if (prevIndex < activeWses[0].id) {
|
||||||
|
|
||||||
prevIndex = activeWses[activeWses.length - 1].id;
|
prevIndex = activeWses[activeWses.length - 1].id;
|
||||||
}
|
}
|
||||||
|
|
||||||
hyprland.messageAsync(`dispatch workspace ${prevIndex}`)
|
hyprland.messageAsync(`dispatch workspace ${prevIndex}`);
|
||||||
} else if (currentMonitorWorkspaces.value === undefined) {
|
} else if (currentMonitorWorkspaces.value === undefined) {
|
||||||
let prevIndex = hyprland.active.workspace.id - 1;
|
let prevIndex = hyprland.active.workspace.id - 1;
|
||||||
|
|
||||||
@@ -116,7 +112,7 @@ export const goToPrevWS = (currentMonitorWorkspaces: Variable<number[]>, activeW
|
|||||||
prevIndex = workspaces.value;
|
prevIndex = workspaces.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
hyprland.messageAsync(`dispatch workspace ${prevIndex}`)
|
hyprland.messageAsync(`dispatch workspace ${prevIndex}`);
|
||||||
} else {
|
} else {
|
||||||
const curWorkspace = hyprland.active.workspace.id;
|
const curWorkspace = hyprland.active.workspace.id;
|
||||||
const indexOfWs = currentMonitorWorkspaces.value.indexOf(curWorkspace);
|
const indexOfWs = currentMonitorWorkspaces.value.indexOf(curWorkspace);
|
||||||
@@ -125,11 +121,11 @@ export const goToPrevWS = (currentMonitorWorkspaces: Variable<number[]>, activeW
|
|||||||
prevIndex = currentMonitorWorkspaces.value.length - 1;
|
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;
|
let inThrottle: boolean;
|
||||||
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
|
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
|
||||||
if (!inThrottle) {
|
if (!inThrottle) {
|
||||||
@@ -147,7 +143,11 @@ type ThrottledScrollHandlers = {
|
|||||||
throttledScrollDown: () => void;
|
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(() => {
|
const throttledScrollUp = throttle(() => {
|
||||||
if (reverse_scroll.value === true) {
|
if (reverse_scroll.value === true) {
|
||||||
goToPrevWS(currentMonitorWorkspaces, activeWorkspaces);
|
goToPrevWS(currentMonitorWorkspaces, activeWorkspaces);
|
||||||
@@ -165,4 +165,4 @@ export const createThrottledScrollHandlers = (scrollSpeed: number, currentMonito
|
|||||||
}, 200 / scrollSpeed);
|
}, 200 / scrollSpeed);
|
||||||
|
|
||||||
return { throttledScrollUp, throttledScrollDown };
|
return { throttledScrollUp, throttledScrollDown };
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,42 +1,54 @@
|
|||||||
const hyprland = await Service.import("hyprland");
|
const hyprland = await Service.import('hyprland');
|
||||||
import options from "options";
|
import options from 'options';
|
||||||
import { createThrottledScrollHandlers, getCurrentMonitorWorkspaces, getWorkspaceRules, getWorkspacesForMonitor } from "./helpers";
|
import {
|
||||||
import { Workspace } from "types/service/hyprland";
|
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 {
|
const { workspaces, monitorSpecific, workspaceMask, scroll_speed, spacing } = options.bar.workspaces;
|
||||||
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);
|
return Array.from({ length }, (_, i) => i + start);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Workspaces = (monitor = -1) => {
|
const Workspaces = (monitor = -1): BarBoxChild => {
|
||||||
const currentMonitorWorkspaces = Variable(getCurrentMonitorWorkspaces(monitor));
|
const currentMonitorWorkspaces = Variable(getCurrentMonitorWorkspaces(monitor));
|
||||||
|
|
||||||
workspaces.connect("changed", () => {
|
workspaces.connect('changed', () => {
|
||||||
currentMonitorWorkspaces.value = getCurrentMonitorWorkspaces(monitor)
|
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) {
|
if (showIcons) {
|
||||||
return `workspace-icon txt-icon bar`;
|
return `workspace-icon txt-icon bar`;
|
||||||
}
|
}
|
||||||
if (showNumbered) {
|
if (showNumbered) {
|
||||||
const numActiveInd = hyprland.active.workspace.id === i
|
const numActiveInd = hyprland.active.workspace.id === i ? numberedActiveIndicator : '';
|
||||||
? numberedActiveIndicator
|
|
||||||
: "";
|
|
||||||
|
|
||||||
return `workspace-number can_${numberedActiveIndicator} ${numActiveInd}`;
|
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 (showIcons) {
|
||||||
if (hyprland.active.workspace.id === i) {
|
if (hyprland.active.workspace.id === i) {
|
||||||
return active;
|
return active;
|
||||||
@@ -44,20 +56,16 @@ const Workspaces = (monitor = -1) => {
|
|||||||
if ((hyprland.getWorkspace(i)?.windows || 0) > 0) {
|
if ((hyprland.getWorkspace(i)?.windows || 0) > 0) {
|
||||||
return occupied;
|
return occupied;
|
||||||
}
|
}
|
||||||
if (
|
if (monitor !== -1) {
|
||||||
monitor !== -1
|
|
||||||
) {
|
|
||||||
return available;
|
return available;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return workspaceMask
|
return workspaceMask ? `${index + 1}` : `${i}`;
|
||||||
? `${index + 1}`
|
};
|
||||||
: `${i}`;
|
const defaultWses = (): BoxWidget => {
|
||||||
}
|
|
||||||
const defaultWses = () => {
|
|
||||||
return Widget.Box({
|
return Widget.Box({
|
||||||
children: Utils.merge(
|
children: Utils.merge(
|
||||||
[workspaces.bind("value"), monitorSpecific.bind()],
|
[workspaces.bind('value'), monitorSpecific.bind()],
|
||||||
(workspaces: number, monitorSpecific: boolean) => {
|
(workspaces: number, monitorSpecific: boolean) => {
|
||||||
return range(workspaces || 8)
|
return range(workspaces || 8)
|
||||||
.filter((i) => {
|
.filter((i) => {
|
||||||
@@ -72,49 +80,57 @@ const Workspaces = (monitor = -1) => {
|
|||||||
})
|
})
|
||||||
.map((i, index) => {
|
.map((i, index) => {
|
||||||
return Widget.Button({
|
return Widget.Button({
|
||||||
class_name: "workspace-button",
|
class_name: 'workspace-button',
|
||||||
on_primary_click: () => {
|
on_primary_click: () => {
|
||||||
hyprland.messageAsync(`dispatch workspace ${i}`)
|
hyprland.messageAsync(`dispatch workspace ${i}`);
|
||||||
|
|
||||||
},
|
},
|
||||||
child: Widget.Label({
|
child: Widget.Label({
|
||||||
attribute: i,
|
attribute: i,
|
||||||
vpack: "center",
|
vpack: 'center',
|
||||||
css: spacing.bind("value").as(sp => `margin: 0rem ${0.375 * sp}rem;`),
|
css: spacing.bind('value').as((sp) => `margin: 0rem ${0.375 * sp}rem;`),
|
||||||
class_name: Utils.merge(
|
class_name: Utils.merge(
|
||||||
[
|
[
|
||||||
options.bar.workspaces.show_icons.bind("value"),
|
options.bar.workspaces.show_icons.bind('value'),
|
||||||
options.bar.workspaces.show_numbered.bind("value"),
|
options.bar.workspaces.show_numbered.bind('value'),
|
||||||
options.bar.workspaces.numbered_active_indicator.bind("value"),
|
options.bar.workspaces.numbered_active_indicator.bind('value'),
|
||||||
options.bar.workspaces.icons.available.bind("value"),
|
options.bar.workspaces.icons.available.bind('value'),
|
||||||
options.bar.workspaces.icons.active.bind("value"),
|
options.bar.workspaces.icons.active.bind('value'),
|
||||||
options.bar.workspaces.icons.occupied.bind("value"),
|
options.bar.workspaces.icons.occupied.bind('value'),
|
||||||
hyprland.active.workspace.bind("id")
|
hyprland.active.workspace.bind('id'),
|
||||||
],
|
],
|
||||||
(showIcons: boolean, showNumbered: boolean, numberedActiveIndicator: string) => {
|
(
|
||||||
|
showIcons: boolean,
|
||||||
|
showNumbered: boolean,
|
||||||
|
numberedActiveIndicator: string,
|
||||||
|
) => {
|
||||||
if (showIcons) {
|
if (showIcons) {
|
||||||
return `workspace-icon txt-icon bar`;
|
return `workspace-icon txt-icon bar`;
|
||||||
}
|
}
|
||||||
if (showNumbered) {
|
if (showNumbered) {
|
||||||
const numActiveInd = hyprland.active.workspace.id === i
|
const numActiveInd =
|
||||||
? numberedActiveIndicator
|
hyprland.active.workspace.id === i ? numberedActiveIndicator : '';
|
||||||
: "";
|
|
||||||
|
|
||||||
return `workspace-number can_${numberedActiveIndicator} ${numActiveInd}`;
|
return `workspace-number can_${numberedActiveIndicator} ${numActiveInd}`;
|
||||||
}
|
}
|
||||||
return "default";
|
return 'default';
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
label: Utils.merge(
|
label: Utils.merge(
|
||||||
[
|
[
|
||||||
options.bar.workspaces.show_icons.bind("value"),
|
options.bar.workspaces.show_icons.bind('value'),
|
||||||
options.bar.workspaces.icons.available.bind("value"),
|
options.bar.workspaces.icons.available.bind('value'),
|
||||||
options.bar.workspaces.icons.active.bind("value"),
|
options.bar.workspaces.icons.active.bind('value'),
|
||||||
options.bar.workspaces.icons.occupied.bind("value"),
|
options.bar.workspaces.icons.occupied.bind('value'),
|
||||||
workspaceMask.bind("value"),
|
workspaceMask.bind('value'),
|
||||||
hyprland.active.workspace.bind("id")
|
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 (showIcons) {
|
||||||
if (hyprland.active.workspace.id === i) {
|
if (hyprland.active.workspace.id === i) {
|
||||||
return active;
|
return active;
|
||||||
@@ -122,52 +138,45 @@ const Workspaces = (monitor = -1) => {
|
|||||||
if ((hyprland.getWorkspace(i)?.windows || 0) > 0) {
|
if ((hyprland.getWorkspace(i)?.windows || 0) > 0) {
|
||||||
return occupied;
|
return occupied;
|
||||||
}
|
}
|
||||||
if (
|
if (monitor !== -1) {
|
||||||
monitor !== -1
|
|
||||||
) {
|
|
||||||
return available;
|
return available;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return workspaceMask
|
return workspaceMask ? `${index + 1}` : `${i}`;
|
||||||
? `${index + 1}`
|
|
||||||
: `${i}`;
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
self.hook(hyprland, () => {
|
self.hook(hyprland, () => {
|
||||||
|
self.toggleClassName('active', hyprland.active.workspace.id === i);
|
||||||
self.toggleClassName(
|
self.toggleClassName(
|
||||||
"active",
|
'occupied',
|
||||||
hyprland.active.workspace.id === i,
|
|
||||||
);
|
|
||||||
self.toggleClassName(
|
|
||||||
"occupied",
|
|
||||||
(hyprland.getWorkspace(i)?.windows || 0) > 0,
|
(hyprland.getWorkspace(i)?.windows || 0) > 0,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
const occupiedWses = () => {
|
const occupiedWses = (): BoxWidget => {
|
||||||
return Widget.Box({
|
return Widget.Box({
|
||||||
children: Utils.merge(
|
children: Utils.merge(
|
||||||
[
|
[
|
||||||
monitorSpecific.bind("value"),
|
monitorSpecific.bind('value'),
|
||||||
hyprland.bind("workspaces"),
|
hyprland.bind('workspaces'),
|
||||||
workspaceMask.bind("value"),
|
workspaceMask.bind('value'),
|
||||||
workspaces.bind("value"),
|
workspaces.bind('value'),
|
||||||
options.bar.workspaces.show_icons.bind("value"),
|
options.bar.workspaces.show_icons.bind('value'),
|
||||||
options.bar.workspaces.icons.available.bind("value"),
|
options.bar.workspaces.icons.available.bind('value'),
|
||||||
options.bar.workspaces.icons.active.bind("value"),
|
options.bar.workspaces.icons.active.bind('value'),
|
||||||
options.bar.workspaces.icons.occupied.bind("value"),
|
options.bar.workspaces.icons.occupied.bind('value'),
|
||||||
options.bar.workspaces.show_numbered.bind("value"),
|
options.bar.workspaces.show_numbered.bind('value'),
|
||||||
options.bar.workspaces.numbered_active_indicator.bind("value"),
|
options.bar.workspaces.numbered_active_indicator.bind('value'),
|
||||||
spacing.bind("value"),
|
spacing.bind('value'),
|
||||||
hyprland.active.workspace.bind("id"),
|
hyprland.active.workspace.bind('id'),
|
||||||
],
|
],
|
||||||
(
|
(
|
||||||
monitorSpecific: boolean,
|
monitorSpecific: boolean,
|
||||||
@@ -185,29 +194,37 @@ const Workspaces = (monitor = -1) => {
|
|||||||
) => {
|
) => {
|
||||||
let allWkspcs = range(totalWkspcs || 8);
|
let allWkspcs = range(totalWkspcs || 8);
|
||||||
|
|
||||||
const activeWorkspaces = wkSpaces.map(w => w.id);
|
const activeWorkspaces = wkSpaces.map((w) => w.id);
|
||||||
const workspaceRules = getWorkspaceRules();
|
const workspaceRules = getWorkspaceRules();
|
||||||
|
|
||||||
// Sometimes hyprland doesn't have all the monitors in the list
|
// Sometimes hyprland doesn't have all the monitors in the list
|
||||||
// so we complement it with monitors from the workspace list
|
// so we complement it with monitors from the workspace list
|
||||||
const workspaceMonitorList = hyprland?.workspaces?.map(m => ({ id: m.monitorID, name: m.monitor }));
|
const workspaceMonitorList = hyprland?.workspaces?.map((m) => ({
|
||||||
const curMonitor = hyprland.monitors.find(m => m.id === monitor)
|
id: m.monitorID,
|
||||||
|| workspaceMonitorList.find(m => m.id === monitor);
|
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
|
// go through each key in workspaceRules and flatten the array
|
||||||
const workspacesWithRules = Object.keys(workspaceRules).reduce((acc: number[], k: string) => {
|
const workspacesWithRules = Object.keys(workspaceRules).reduce((acc: number[], k: string) => {
|
||||||
return [...acc, ...workspaceRules[k]];
|
return [...acc, ...workspaceRules[k]];
|
||||||
}, [] as number[]);
|
}, [] as number[]);
|
||||||
|
|
||||||
const activesForMonitor = activeWorkspaces.filter(w => {
|
const activesForMonitor = activeWorkspaces.filter((w) => {
|
||||||
if (curMonitor && Object.hasOwnProperty.call(workspaceRules, curMonitor.name) && workspacesWithRules.includes(w)) {
|
if (
|
||||||
|
curMonitor &&
|
||||||
|
Object.hasOwnProperty.call(workspaceRules, curMonitor.name) &&
|
||||||
|
workspacesWithRules.includes(w)
|
||||||
|
) {
|
||||||
return workspaceRules[curMonitor.name].includes(w);
|
return workspaceRules[curMonitor.name].includes(w);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (monitorSpecific) {
|
if (monitorSpecific) {
|
||||||
const wrkspcsInRange = range(totalWkspcs).filter(w => {
|
const wrkspcsInRange = range(totalWkspcs).filter((w) => {
|
||||||
return getWorkspacesForMonitor(w, workspaceRules, monitor);
|
return getWorkspacesForMonitor(w, workspaceRules, monitor);
|
||||||
});
|
});
|
||||||
allWkspcs = [...new Set([...activesForMonitor, ...wrkspcsInRange])];
|
allWkspcs = [...new Set([...activesForMonitor, ...wrkspcsInRange])];
|
||||||
@@ -221,51 +238,53 @@ const Workspaces = (monitor = -1) => {
|
|||||||
})
|
})
|
||||||
.map((i, index) => {
|
.map((i, index) => {
|
||||||
return Widget.Button({
|
return Widget.Button({
|
||||||
class_name: "workspace-button",
|
class_name: 'workspace-button',
|
||||||
on_primary_click: () => {
|
on_primary_click: () => {
|
||||||
hyprland.messageAsync(`dispatch workspace ${i}`)
|
hyprland.messageAsync(`dispatch workspace ${i}`);
|
||||||
|
|
||||||
},
|
},
|
||||||
child: Widget.Label({
|
child: Widget.Label({
|
||||||
attribute: i,
|
attribute: i,
|
||||||
vpack: "center",
|
vpack: 'center',
|
||||||
css: `margin: 0rem ${0.375 * spacing}rem;`,
|
css: `margin: 0rem ${0.375 * spacing}rem;`,
|
||||||
class_name: renderClassnames(showIcons, showNumbered, numberedActiveIndicator, i),
|
class_name: renderClassnames(showIcons, showNumbered, numberedActiveIndicator, i),
|
||||||
label: renderLabel(showIcons, available, active, occupied, workspaceMask, i, index),
|
label: renderLabel(showIcons, available, active, occupied, workspaceMask, i, index),
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
self.toggleClassName(
|
self.toggleClassName('active', activeId === i);
|
||||||
"active",
|
self.toggleClassName('occupied', (hyprland.getWorkspace(i)?.windows || 0) > 0);
|
||||||
activeId === i,
|
|
||||||
);
|
|
||||||
self.toggleClassName(
|
|
||||||
"occupied",
|
|
||||||
(hyprland.getWorkspace(i)?.windows || 0) > 0,
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
component: Widget.Box({
|
component: Widget.Box({
|
||||||
class_name: "workspaces",
|
class_name: 'workspaces',
|
||||||
child: options.bar.workspaces.hideUnoccupied.bind("value").as(hideUnoccupied => hideUnoccupied ? occupiedWses() : defaultWses()),
|
child: options.bar.workspaces.hideUnoccupied
|
||||||
|
.bind('value')
|
||||||
|
.as((hideUnoccupied) => (hideUnoccupied ? occupiedWses() : defaultWses())),
|
||||||
}),
|
}),
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
boxClass: "workspaces",
|
boxClass: 'workspaces',
|
||||||
props: {
|
props: {
|
||||||
setup: (self: any) => {
|
setup: (self: SelfButton): void => {
|
||||||
Utils.merge([scroll_speed.bind("value"), options.bar.workspaces.hideUnoccupied.bind("value")], (scroll_speed, hideUnoccupied) => {
|
Utils.merge(
|
||||||
const { throttledScrollUp, throttledScrollDown } = createThrottledScrollHandlers(scroll_speed, currentMonitorWorkspaces, hideUnoccupied)
|
[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_up = throttledScrollUp;
|
||||||
self.on_scroll_down = throttledScrollDown;
|
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 = {
|
export const substitutes = {
|
||||||
"transmission-gtk": "transmission",
|
'transmission-gtk': 'transmission',
|
||||||
"blueberry.py": "blueberry",
|
'blueberry.py': 'blueberry',
|
||||||
Caprine: "facebook-messenger",
|
Caprine: 'facebook-messenger',
|
||||||
"com.raggesilver.BlackBox-symbolic": "terminal-symbolic",
|
'com.raggesilver.BlackBox-symbolic': 'terminal-symbolic',
|
||||||
"org.wezfurlong.wezterm-symbolic": "terminal-symbolic",
|
'org.wezfurlong.wezterm-symbolic': 'terminal-symbolic',
|
||||||
"audio-headset-bluetooth": "audio-headphones-symbolic",
|
'audio-headset-bluetooth': 'audio-headphones-symbolic',
|
||||||
"audio-card-analog-usb": "audio-speakers-symbolic",
|
'audio-card-analog-usb': 'audio-speakers-symbolic',
|
||||||
"audio-card-analog-pci": "audio-card-symbolic",
|
'audio-card-analog-pci': 'audio-card-symbolic',
|
||||||
"preferences-system": "emblem-system-symbolic",
|
'preferences-system': 'emblem-system-symbolic',
|
||||||
"com.github.Aylur.ags-symbolic": "controls-symbolic",
|
'com.github.Aylur.ags-symbolic': 'controls-symbolic',
|
||||||
"com.github.Aylur.ags": "controls-symbolic",
|
'com.github.Aylur.ags': 'controls-symbolic',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
missing: "image-missing-symbolic",
|
missing: 'image-missing-symbolic',
|
||||||
nix: {
|
nix: {
|
||||||
nix: "nix-snowflake-symbolic",
|
nix: 'nix-snowflake-symbolic',
|
||||||
},
|
},
|
||||||
app: {
|
app: {
|
||||||
terminal: "terminal-symbolic",
|
terminal: 'terminal-symbolic',
|
||||||
},
|
},
|
||||||
fallback: {
|
fallback: {
|
||||||
executable: "application-x-executable",
|
executable: 'application-x-executable',
|
||||||
notification: "dialog-information-symbolic",
|
notification: 'dialog-information-symbolic',
|
||||||
video: "video-x-generic-symbolic",
|
video: 'video-x-generic-symbolic',
|
||||||
audio: "audio-x-generic-symbolic",
|
audio: 'audio-x-generic-symbolic',
|
||||||
},
|
},
|
||||||
ui: {
|
ui: {
|
||||||
close: "window-close-symbolic",
|
close: 'window-close-symbolic',
|
||||||
colorpicker: "color-select-symbolic",
|
colorpicker: 'color-select-symbolic',
|
||||||
info: "info-symbolic",
|
info: 'info-symbolic',
|
||||||
link: "external-link-symbolic",
|
link: 'external-link-symbolic',
|
||||||
lock: "system-lock-screen-symbolic",
|
lock: 'system-lock-screen-symbolic',
|
||||||
menu: "open-menu-symbolic",
|
menu: 'open-menu-symbolic',
|
||||||
refresh: "view-refresh-symbolic",
|
refresh: 'view-refresh-symbolic',
|
||||||
search: "system-search-symbolic",
|
search: 'system-search-symbolic',
|
||||||
settings: "emblem-system-symbolic",
|
settings: 'emblem-system-symbolic',
|
||||||
themes: "preferences-desktop-theme-symbolic",
|
themes: 'preferences-desktop-theme-symbolic',
|
||||||
tick: "object-select-symbolic",
|
tick: 'object-select-symbolic',
|
||||||
time: "hourglass-symbolic",
|
time: 'hourglass-symbolic',
|
||||||
toolbars: "toolbars-symbolic",
|
toolbars: 'toolbars-symbolic',
|
||||||
warning: "dialog-warning-symbolic",
|
warning: 'dialog-warning-symbolic',
|
||||||
avatar: "avatar-default-symbolic",
|
avatar: 'avatar-default-symbolic',
|
||||||
arrow: {
|
arrow: {
|
||||||
right: "pan-end-symbolic",
|
right: 'pan-end-symbolic',
|
||||||
left: "pan-start-symbolic",
|
left: 'pan-start-symbolic',
|
||||||
down: "pan-down-symbolic",
|
down: 'pan-down-symbolic',
|
||||||
up: "pan-up-symbolic",
|
up: 'pan-up-symbolic',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
audio: {
|
audio: {
|
||||||
mic: {
|
mic: {
|
||||||
muted: "microphone-disabled-symbolic",
|
muted: 'microphone-disabled-symbolic',
|
||||||
low: "microphone-sensitivity-low-symbolic",
|
low: 'microphone-sensitivity-low-symbolic',
|
||||||
medium: "microphone-sensitivity-medium-symbolic",
|
medium: 'microphone-sensitivity-medium-symbolic',
|
||||||
high: "microphone-sensitivity-high-symbolic",
|
high: 'microphone-sensitivity-high-symbolic',
|
||||||
},
|
},
|
||||||
volume: {
|
volume: {
|
||||||
muted: "audio-volume-muted-symbolic",
|
muted: 'audio-volume-muted-symbolic',
|
||||||
low: "audio-volume-low-symbolic",
|
low: 'audio-volume-low-symbolic',
|
||||||
medium: "audio-volume-medium-symbolic",
|
medium: 'audio-volume-medium-symbolic',
|
||||||
high: "audio-volume-high-symbolic",
|
high: 'audio-volume-high-symbolic',
|
||||||
overamplified: "audio-volume-overamplified-symbolic",
|
overamplified: 'audio-volume-overamplified-symbolic',
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
headset: "audio-headphones-symbolic",
|
headset: 'audio-headphones-symbolic',
|
||||||
speaker: "audio-speakers-symbolic",
|
speaker: 'audio-speakers-symbolic',
|
||||||
card: "audio-card-symbolic",
|
card: 'audio-card-symbolic',
|
||||||
},
|
},
|
||||||
mixer: "mixer-symbolic",
|
mixer: 'mixer-symbolic',
|
||||||
},
|
},
|
||||||
powerprofile: {
|
powerprofile: {
|
||||||
balanced: "power-profile-balanced-symbolic",
|
balanced: 'power-profile-balanced-symbolic',
|
||||||
"power-saver": "power-profile-power-saver-symbolic",
|
'power-saver': 'power-profile-power-saver-symbolic',
|
||||||
performance: "power-profile-performance-symbolic",
|
performance: 'power-profile-performance-symbolic',
|
||||||
},
|
},
|
||||||
asusctl: {
|
asusctl: {
|
||||||
profile: {
|
profile: {
|
||||||
Balanced: "power-profile-balanced-symbolic",
|
Balanced: 'power-profile-balanced-symbolic',
|
||||||
Quiet: "power-profile-power-saver-symbolic",
|
Quiet: 'power-profile-power-saver-symbolic',
|
||||||
Performance: "power-profile-performance-symbolic",
|
Performance: 'power-profile-performance-symbolic',
|
||||||
},
|
},
|
||||||
mode: {
|
mode: {
|
||||||
Integrated: "processor-symbolic",
|
Integrated: 'processor-symbolic',
|
||||||
Hybrid: "controller-symbolic",
|
Hybrid: 'controller-symbolic',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
battery: {
|
battery: {
|
||||||
charging: "battery-flash-symbolic",
|
charging: 'battery-flash-symbolic',
|
||||||
warning: "battery-empty-symbolic",
|
warning: 'battery-empty-symbolic',
|
||||||
},
|
},
|
||||||
bluetooth: {
|
bluetooth: {
|
||||||
enabled: "bluetooth-active-symbolic",
|
enabled: 'bluetooth-active-symbolic',
|
||||||
disabled: "bluetooth-disabled-symbolic",
|
disabled: 'bluetooth-disabled-symbolic',
|
||||||
},
|
},
|
||||||
brightness: {
|
brightness: {
|
||||||
indicator: "display-brightness-symbolic",
|
indicator: 'display-brightness-symbolic',
|
||||||
keyboard: "keyboard-brightness-symbolic",
|
keyboard: 'keyboard-brightness-symbolic',
|
||||||
screen: "display-brightness-symbolic",
|
screen: 'display-brightness-symbolic',
|
||||||
},
|
},
|
||||||
powermenu: {
|
powermenu: {
|
||||||
sleep: "weather-clear-night-symbolic",
|
sleep: 'weather-clear-night-symbolic',
|
||||||
reboot: "system-reboot-symbolic",
|
reboot: 'system-reboot-symbolic',
|
||||||
logout: "system-log-out-symbolic",
|
logout: 'system-log-out-symbolic',
|
||||||
shutdown: "system-shutdown-symbolic",
|
shutdown: 'system-shutdown-symbolic',
|
||||||
},
|
},
|
||||||
recorder: {
|
recorder: {
|
||||||
recording: "media-record-symbolic",
|
recording: 'media-record-symbolic',
|
||||||
},
|
},
|
||||||
notifications: {
|
notifications: {
|
||||||
noisy: "org.gnome.Settings-notifications-symbolic",
|
noisy: 'org.gnome.Settings-notifications-symbolic',
|
||||||
silent: "notifications-disabled-symbolic",
|
silent: 'notifications-disabled-symbolic',
|
||||||
message: "chat-bubbles-symbolic",
|
message: 'chat-bubbles-symbolic',
|
||||||
},
|
},
|
||||||
trash: {
|
trash: {
|
||||||
full: "user-trash-full-symbolic",
|
full: 'user-trash-full-symbolic',
|
||||||
empty: "user-trash-symbolic",
|
empty: 'user-trash-symbolic',
|
||||||
},
|
},
|
||||||
mpris: {
|
mpris: {
|
||||||
shuffle: {
|
shuffle: {
|
||||||
enabled: "media-playlist-shuffle-symbolic",
|
enabled: 'media-playlist-shuffle-symbolic',
|
||||||
disabled: "media-playlist-consecutive-symbolic",
|
disabled: 'media-playlist-consecutive-symbolic',
|
||||||
},
|
},
|
||||||
loop: {
|
loop: {
|
||||||
none: "media-playlist-repeat-symbolic",
|
none: 'media-playlist-repeat-symbolic',
|
||||||
track: "media-playlist-repeat-song-symbolic",
|
track: 'media-playlist-repeat-song-symbolic',
|
||||||
playlist: "media-playlist-repeat-symbolic",
|
playlist: 'media-playlist-repeat-symbolic',
|
||||||
},
|
},
|
||||||
playing: "media-playback-pause-symbolic",
|
playing: 'media-playback-pause-symbolic',
|
||||||
paused: "media-playback-start-symbolic",
|
paused: 'media-playback-start-symbolic',
|
||||||
stopped: "media-playback-start-symbolic",
|
stopped: 'media-playback-start-symbolic',
|
||||||
prev: "media-skip-backward-symbolic",
|
prev: 'media-skip-backward-symbolic',
|
||||||
next: "media-skip-forward-symbolic",
|
next: 'media-skip-forward-symbolic',
|
||||||
},
|
},
|
||||||
system: {
|
system: {
|
||||||
cpu: "org.gnome.SystemMonitor-symbolic",
|
cpu: 'org.gnome.SystemMonitor-symbolic',
|
||||||
ram: "drive-harddisk-solidstate-symbolic",
|
ram: 'drive-harddisk-solidstate-symbolic',
|
||||||
temp: "temperature-symbolic",
|
temp: 'temperature-symbolic',
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
dark: "dark-mode-symbolic",
|
dark: 'dark-mode-symbolic',
|
||||||
light: "light-mode-symbolic",
|
light: 'light-mode-symbolic',
|
||||||
},
|
},
|
||||||
weather: {
|
weather: {
|
||||||
warning: "dialog-warning-symbolic",
|
warning: 'dialog-warning-symbolic',
|
||||||
sunny: "weather-clear-symbolic",
|
sunny: 'weather-clear-symbolic',
|
||||||
clear: "weather-clear-night-symbolic",
|
clear: 'weather-clear-night-symbolic',
|
||||||
partly_cloudy: "weather-few-clouds-symbolic",
|
partly_cloudy: 'weather-few-clouds-symbolic',
|
||||||
partly_cloudy_night: "weather-few-clouds-night-symbolic",
|
partly_cloudy_night: 'weather-few-clouds-night-symbolic',
|
||||||
cloudy: "weather-overcast-symbolic",
|
cloudy: 'weather-overcast-symbolic',
|
||||||
overcast: "weather-overcast-symbolic",
|
overcast: 'weather-overcast-symbolic',
|
||||||
mist: "weather-overcast-symbolic",
|
mist: 'weather-overcast-symbolic',
|
||||||
patchy_rain_nearby: "weather-showers-scattered-symbolic",
|
patchy_rain_nearby: 'weather-showers-scattered-symbolic',
|
||||||
patchy_rain_possible: "weather-showers-scattered-symbolic",
|
patchy_rain_possible: 'weather-showers-scattered-symbolic',
|
||||||
patchy_snow_possible: "weather-snow-symbolic",
|
patchy_snow_possible: 'weather-snow-symbolic',
|
||||||
patchy_sleet_possible: "weather-snow-symbolic",
|
patchy_sleet_possible: 'weather-snow-symbolic',
|
||||||
patchy_freezing_drizzle_possible: "weather-showers-scattered-symbolic",
|
patchy_freezing_drizzle_possible: 'weather-showers-scattered-symbolic',
|
||||||
thundery_outbreaks_possible: "weather-overcast-symbolic",
|
thundery_outbreaks_possible: 'weather-overcast-symbolic',
|
||||||
blowing_snow: "weather-snow-symbolic",
|
blowing_snow: 'weather-snow-symbolic',
|
||||||
blizzard: "weather-snow-symbolic",
|
blizzard: 'weather-snow-symbolic',
|
||||||
fog: "weather-fog-symbolic",
|
fog: 'weather-fog-symbolic',
|
||||||
freezing_fog: "weather-fog-symbolic",
|
freezing_fog: 'weather-fog-symbolic',
|
||||||
patchy_light_drizzle: "weather-showers-scattered-symbolic",
|
patchy_light_drizzle: 'weather-showers-scattered-symbolic',
|
||||||
light_drizzle: "weather-showers-symbolic",
|
light_drizzle: 'weather-showers-symbolic',
|
||||||
freezing_drizzle: "weather-showers-symbolic",
|
freezing_drizzle: 'weather-showers-symbolic',
|
||||||
heavy_freezing_drizzle: "weather-showers-symbolic",
|
heavy_freezing_drizzle: 'weather-showers-symbolic',
|
||||||
patchy_light_rain: "weather-showers-scattered-symbolic",
|
patchy_light_rain: 'weather-showers-scattered-symbolic',
|
||||||
light_rain: "weather-showers-symbolic",
|
light_rain: 'weather-showers-symbolic',
|
||||||
moderate_rain_at_times: "weather-showers-symbolic",
|
moderate_rain_at_times: 'weather-showers-symbolic',
|
||||||
moderate_rain: "weather-showers-symbolic",
|
moderate_rain: 'weather-showers-symbolic',
|
||||||
heavy_rain_at_times: "weather-showers-symbolic",
|
heavy_rain_at_times: 'weather-showers-symbolic',
|
||||||
heavy_rain: "weather-showers-symbolic",
|
heavy_rain: 'weather-showers-symbolic',
|
||||||
light_freezing_rain: "weather-showers-symbolic",
|
light_freezing_rain: 'weather-showers-symbolic',
|
||||||
moderate_or_heavy_freezing_rain: "weather-showers-symbolic",
|
moderate_or_heavy_freezing_rain: 'weather-showers-symbolic',
|
||||||
light_sleet: "weather-snow-symbolic",
|
light_sleet: 'weather-snow-symbolic',
|
||||||
moderate_or_heavy_sleet: "weather-snow-symbolic",
|
moderate_or_heavy_sleet: 'weather-snow-symbolic',
|
||||||
patchy_light_snow: "weather-snow-symbolic",
|
patchy_light_snow: 'weather-snow-symbolic',
|
||||||
light_snow: "weather-snow-symbolic",
|
light_snow: 'weather-snow-symbolic',
|
||||||
patchy_moderate_snow: "weather-snow-symbolic",
|
patchy_moderate_snow: 'weather-snow-symbolic',
|
||||||
moderate_snow: "weather-snow-symbolic",
|
moderate_snow: 'weather-snow-symbolic',
|
||||||
patchy_heavy_snow: "weather-snow-symbolic",
|
patchy_heavy_snow: 'weather-snow-symbolic',
|
||||||
heavy_snow: "weather-snow-symbolic",
|
heavy_snow: 'weather-snow-symbolic',
|
||||||
ice_pellets: "weather-showers-symbolic",
|
ice_pellets: 'weather-showers-symbolic',
|
||||||
light_rain_shower: "weather-showers-symbolic",
|
light_rain_shower: 'weather-showers-symbolic',
|
||||||
moderate_or_heavy_rain_shower: "weather-showers-symbolic",
|
moderate_or_heavy_rain_shower: 'weather-showers-symbolic',
|
||||||
torrential_rain_shower: "weather-showers-symbolic",
|
torrential_rain_shower: 'weather-showers-symbolic',
|
||||||
light_sleet_showers: "weather-showers-symbolic",
|
light_sleet_showers: 'weather-showers-symbolic',
|
||||||
moderate_or_heavy_sleet_showers: "weather-showers-symbolic",
|
moderate_or_heavy_sleet_showers: 'weather-showers-symbolic',
|
||||||
light_snow_showers: "weather-snow-symbolic",
|
light_snow_showers: 'weather-snow-symbolic',
|
||||||
moderate_or_heavy_snow_showers: "weather-snow-symbolic",
|
moderate_or_heavy_snow_showers: 'weather-snow-symbolic',
|
||||||
light_showers_of_ice_pellets: "weather-showers-symbolic",
|
light_showers_of_ice_pellets: 'weather-showers-symbolic',
|
||||||
moderate_or_heavy_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",
|
patchy_light_rain_with_thunder: 'weather-showers-scattered-symbolic',
|
||||||
moderate_or_heavy_rain_with_thunder: "weather-showers-symbolic",
|
moderate_or_heavy_rain_with_thunder: 'weather-showers-symbolic',
|
||||||
patchy_light_snow_with_thunder: "weather-snow-symbolic",
|
patchy_light_snow_with_thunder: 'weather-snow-symbolic',
|
||||||
moderate_or_heavy_snow_with_thunder: "weather-snow-symbolic",
|
moderate_or_heavy_snow_with_thunder: 'weather-snow-symbolic',
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -1,54 +1,54 @@
|
|||||||
export const weatherIcons = {
|
export const weatherIcons = {
|
||||||
warning: "",
|
warning: '',
|
||||||
sunny: "",
|
sunny: '',
|
||||||
clear: "",
|
clear: '',
|
||||||
partly_cloudy: "",
|
partly_cloudy: '',
|
||||||
partly_cloudy_night: "",
|
partly_cloudy_night: '',
|
||||||
cloudy: "",
|
cloudy: '',
|
||||||
overcast: "",
|
overcast: '',
|
||||||
mist: "",
|
mist: '',
|
||||||
patchy_rain_nearby: "",
|
patchy_rain_nearby: '',
|
||||||
patchy_rain_possible: "",
|
patchy_rain_possible: '',
|
||||||
patchy_snow_possible: "",
|
patchy_snow_possible: '',
|
||||||
patchy_sleet_possible: "",
|
patchy_sleet_possible: '',
|
||||||
patchy_freezing_drizzle_possible: "",
|
patchy_freezing_drizzle_possible: '',
|
||||||
thundery_outbreaks_possible: "",
|
thundery_outbreaks_possible: '',
|
||||||
blowing_snow: "",
|
blowing_snow: '',
|
||||||
blizzard: "",
|
blizzard: '',
|
||||||
fog: "",
|
fog: '',
|
||||||
freezing_fog: "",
|
freezing_fog: '',
|
||||||
patchy_light_drizzle: "",
|
patchy_light_drizzle: '',
|
||||||
light_drizzle: "",
|
light_drizzle: '',
|
||||||
freezing_drizzle: "",
|
freezing_drizzle: '',
|
||||||
heavy_freezing_drizzle: "",
|
heavy_freezing_drizzle: '',
|
||||||
patchy_light_rain: "",
|
patchy_light_rain: '',
|
||||||
light_rain: "",
|
light_rain: '',
|
||||||
moderate_rain_at_times: "",
|
moderate_rain_at_times: '',
|
||||||
moderate_rain: "",
|
moderate_rain: '',
|
||||||
heavy_rain_at_times: "",
|
heavy_rain_at_times: '',
|
||||||
heavy_rain: "",
|
heavy_rain: '',
|
||||||
light_freezing_rain: "",
|
light_freezing_rain: '',
|
||||||
moderate_or_heavy_freezing_rain: "",
|
moderate_or_heavy_freezing_rain: '',
|
||||||
light_sleet: "",
|
light_sleet: '',
|
||||||
moderate_or_heavy_sleet: "",
|
moderate_or_heavy_sleet: '',
|
||||||
patchy_light_snow: "",
|
patchy_light_snow: '',
|
||||||
light_snow: "",
|
light_snow: '',
|
||||||
patchy_moderate_snow: "",
|
patchy_moderate_snow: '',
|
||||||
moderate_snow: "",
|
moderate_snow: '',
|
||||||
patchy_heavy_snow: "",
|
patchy_heavy_snow: '',
|
||||||
heavy_snow: "",
|
heavy_snow: '',
|
||||||
ice_pellets: "",
|
ice_pellets: '',
|
||||||
light_rain_shower: "",
|
light_rain_shower: '',
|
||||||
moderate_or_heavy_rain_shower: "",
|
moderate_or_heavy_rain_shower: '',
|
||||||
torrential_rain_shower: "",
|
torrential_rain_shower: '',
|
||||||
light_sleet_showers: "",
|
light_sleet_showers: '',
|
||||||
moderate_or_heavy_sleet_showers: "",
|
moderate_or_heavy_sleet_showers: '',
|
||||||
light_snow_showers: "",
|
light_snow_showers: '',
|
||||||
moderate_or_heavy_snow_showers: "",
|
moderate_or_heavy_snow_showers: '',
|
||||||
light_showers_of_ice_pellets: "",
|
light_showers_of_ice_pellets: '',
|
||||||
moderate_or_heavy_showers_of_ice_pellets: "",
|
moderate_or_heavy_showers_of_ice_pellets: '',
|
||||||
patchy_light_rain_with_thunder: "",
|
patchy_light_rain_with_thunder: '',
|
||||||
moderate_or_heavy_rain_with_thunder: "",
|
moderate_or_heavy_rain_with_thunder: '',
|
||||||
patchy_light_snow_with_thunder: "",
|
patchy_light_snow_with_thunder: '',
|
||||||
moderate_or_heavy_snow_with_thunder: "",
|
moderate_or_heavy_snow_with_thunder: '',
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -1,25 +1,34 @@
|
|||||||
const hyprland = await Service.import("hyprland");
|
const hyprland = await Service.import('hyprland');
|
||||||
import { DropdownMenuProps } from "lib/types/dropdownmenu";
|
import { DropdownMenuProps } from 'lib/types/dropdownmenu';
|
||||||
import { Exclusivity } from "lib/types/widget";
|
import { Attribute, Child, Exclusivity, GtkWidget } from 'lib/types/widget';
|
||||||
import { bash } from "lib/utils";
|
import { bash } from 'lib/utils';
|
||||||
import { Monitor } from "types/service/hyprland";
|
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({
|
Widget.EventBox({
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
vexpand: true,
|
vexpand: true,
|
||||||
can_focus: true,
|
can_focus: true,
|
||||||
child: Widget.Box(),
|
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) {
|
if (fixed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
globalMousePos.connect("changed", async ({ value }) => {
|
globalMousePos.connect('changed', async ({ value }) => {
|
||||||
const curHyprlandMonitor = hyprland.monitors.find(m => m.id === hyprland.active.monitor.id);
|
const curHyprlandMonitor = hyprland.monitors.find((m) => m.id === hyprland.active.monitor.id);
|
||||||
const dropdownWidth = self.child.get_allocation().width;
|
const dropdownWidth = self.child.get_allocation().width;
|
||||||
|
|
||||||
let hyprScaling = 1;
|
let hyprScaling = 1;
|
||||||
@@ -27,8 +36,8 @@ const moveBoxToCursor = (self: any, fixed: boolean) => {
|
|||||||
const monitorInfo = await bash('hyprctl monitors -j');
|
const monitorInfo = await bash('hyprctl monitors -j');
|
||||||
const parsedMonitorInfo = JSON.parse(monitorInfo);
|
const parsedMonitorInfo = JSON.parse(monitorInfo);
|
||||||
|
|
||||||
const foundMonitor = parsedMonitorInfo.find((monitor: Monitor) =>
|
const foundMonitor = parsedMonitorInfo.find(
|
||||||
monitor.id === hyprland.active.monitor.id
|
(monitor: Monitor) => monitor.id === hyprland.active.monitor.id,
|
||||||
);
|
);
|
||||||
hyprScaling = foundMonitor?.scale || 1;
|
hyprScaling = foundMonitor?.scale || 1;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -58,9 +67,7 @@ const moveBoxToCursor = (self: any, fixed: boolean) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If monitor is vertical (transform = 1 || 3) swap height and width
|
// If monitor is vertical (transform = 1 || 3) swap height and width
|
||||||
const isVertical = curHyprlandMonitor?.transform !== undefined
|
const isVertical = curHyprlandMonitor?.transform !== undefined ? curHyprlandMonitor.transform % 2 !== 0 : false;
|
||||||
? curHyprlandMonitor.transform % 2 !== 0
|
|
||||||
: false;
|
|
||||||
|
|
||||||
if (isVertical) {
|
if (isVertical) {
|
||||||
[monWidth, monHeight] = [monHeight, monWidth];
|
[monWidth, monHeight] = [monHeight, monWidth];
|
||||||
@@ -100,58 +107,55 @@ setTimeout(() => {
|
|||||||
initRender.value = false;
|
initRender.value = false;
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
export default (
|
export default ({
|
||||||
{
|
|
||||||
name,
|
name,
|
||||||
child,
|
child,
|
||||||
layout = "center",
|
|
||||||
transition,
|
transition,
|
||||||
exclusivity = "ignore" as Exclusivity,
|
exclusivity = 'ignore' as Exclusivity,
|
||||||
fixed = false,
|
fixed = false,
|
||||||
...props
|
...props
|
||||||
}: DropdownMenuProps
|
}: DropdownMenuProps): Window<Child, Attribute> =>
|
||||||
) =>
|
|
||||||
Widget.Window({
|
Widget.Window({
|
||||||
name,
|
name,
|
||||||
class_names: [name, "dropdown-menu"],
|
class_names: [name, 'dropdown-menu'],
|
||||||
setup: (w) => w.keybind("Escape", () => App.closeWindow(name)),
|
setup: (w) => w.keybind('Escape', () => App.closeWindow(name)),
|
||||||
visible: initRender.bind("value"),
|
visible: initRender.bind('value'),
|
||||||
keymode: "on-demand",
|
keymode: 'on-demand',
|
||||||
exclusivity,
|
exclusivity,
|
||||||
layer: "top",
|
layer: 'top',
|
||||||
anchor: ["top", "left"],
|
anchor: ['top', 'left'],
|
||||||
child: Widget.EventBox({
|
child: Widget.EventBox({
|
||||||
class_name: "parent-event",
|
class_name: 'parent-event',
|
||||||
on_primary_click: () => App.closeWindow(name),
|
on_primary_click: () => App.closeWindow(name),
|
||||||
on_secondary_click: () => App.closeWindow(name),
|
on_secondary_click: () => App.closeWindow(name),
|
||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
class_name: "top-eb",
|
class_name: 'top-eb',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Widget.EventBox({
|
Widget.EventBox({
|
||||||
class_name: "mid-eb event-top-padding-static",
|
class_name: 'mid-eb event-top-padding-static',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
vexpand: false,
|
vexpand: false,
|
||||||
can_focus: false,
|
can_focus: false,
|
||||||
child: Widget.Box(),
|
child: Widget.Box(),
|
||||||
setup: (w) => {
|
setup: (w) => {
|
||||||
w.on("button-press-event", () => App.toggleWindow(name));
|
w.on('button-press-event', () => App.toggleWindow(name));
|
||||||
w.set_margin_top(1);
|
w.set_margin_top(1);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Widget.EventBox({
|
Widget.EventBox({
|
||||||
class_name: "mid-eb event-top-padding",
|
class_name: 'mid-eb event-top-padding',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
vexpand: false,
|
vexpand: false,
|
||||||
can_focus: false,
|
can_focus: false,
|
||||||
child: Widget.Box(),
|
child: Widget.Box(),
|
||||||
setup: (w) => {
|
setup: (w) => {
|
||||||
w.on("button-press-event", () => App.toggleWindow(name));
|
w.on('button-press-event', () => App.toggleWindow(name));
|
||||||
w.set_margin_top(1);
|
w.set_margin_top(1);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Widget.EventBox({
|
Widget.EventBox({
|
||||||
class_name: "in-eb menu-event-box",
|
class_name: 'in-eb menu-event-box',
|
||||||
on_primary_click: () => {
|
on_primary_click: () => {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@@ -162,18 +166,18 @@ export default (
|
|||||||
moveBoxToCursor(self, fixed);
|
moveBoxToCursor(self, fixed);
|
||||||
},
|
},
|
||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
class_name: "dropdown-menu-container",
|
class_name: 'dropdown-menu-container',
|
||||||
css: "padding: 1px; margin: -1px;",
|
css: 'padding: 1px; margin: -1px;',
|
||||||
child: Widget.Revealer({
|
child: Widget.Revealer({
|
||||||
revealChild: false,
|
revealChild: false,
|
||||||
setup: (self) =>
|
setup: (self) =>
|
||||||
self.hook(App, (_, wname, visible) => {
|
self.hook(App, (_, wname, visible) => {
|
||||||
if (wname === name) self.reveal_child = visible;
|
if (wname === name) self.reveal_child = visible;
|
||||||
}),
|
}),
|
||||||
transition: "crossfade",
|
transition,
|
||||||
transitionDuration: 350,
|
transitionDuration: 350,
|
||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
class_name: "dropdown-menu-container",
|
class_name: 'dropdown-menu-container',
|
||||||
can_focus: true,
|
can_focus: true,
|
||||||
children: [child],
|
children: [child],
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,25 +1,32 @@
|
|||||||
import { WINDOW_LAYOUTS } from "globals/window";
|
import { WINDOW_LAYOUTS } from 'globals/window';
|
||||||
import { LayoutFunction, Layouts, PopupWindowProps } from "lib/types/popupwindow";
|
import { LayoutFunction, Layouts, PopupWindowProps } from 'lib/types/popupwindow';
|
||||||
import { Exclusivity, Transition } from "lib/types/widget";
|
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 = {
|
type Opts = {
|
||||||
className: string
|
className: string;
|
||||||
vexpand: boolean
|
vexpand: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const Padding = (name: string, opts: Opts) =>
|
export const Padding = (name: string, opts: Opts): EventBox<Box<GtkWidget, Attribute>, unknown> =>
|
||||||
Widget.EventBox({
|
Widget.EventBox({
|
||||||
class_name: opts?.className || "",
|
class_name: opts?.className || '',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
vexpand: typeof opts?.vexpand === "boolean" ? opts.vexpand : true,
|
vexpand: typeof opts?.vexpand === 'boolean' ? opts.vexpand : true,
|
||||||
can_focus: false,
|
can_focus: false,
|
||||||
child: Widget.Box(),
|
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(
|
Widget.Box(
|
||||||
{ css: "padding: 1px;" },
|
{ css: 'padding: 1px;' },
|
||||||
Widget.Revealer({
|
Widget.Revealer({
|
||||||
transition,
|
transition,
|
||||||
child: Widget.Box({
|
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: () =>
|
center: () =>
|
||||||
Widget.CenterBox(
|
Widget.CenterBox(
|
||||||
{},
|
{},
|
||||||
@@ -51,14 +58,10 @@ const Layout: LayoutFunction = (name: string, child: any, transition: Transition
|
|||||||
Widget.CenterBox(
|
Widget.CenterBox(
|
||||||
{},
|
{},
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
Widget.Box(
|
Widget.Box({ vertical: true }, PopupRevealer(name, child, transition), Padding(name, {} as Opts)),
|
||||||
{ vertical: true },
|
|
||||||
PopupRevealer(name, child, transition),
|
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
),
|
),
|
||||||
Padding(name, {} as Opts),
|
'top-right': () =>
|
||||||
),
|
|
||||||
"top-right": () =>
|
|
||||||
Widget.Box(
|
Widget.Box(
|
||||||
{},
|
{},
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
@@ -69,13 +72,13 @@ const Layout: LayoutFunction = (name: string, child: any, transition: Transition
|
|||||||
},
|
},
|
||||||
Padding(name, {
|
Padding(name, {
|
||||||
vexpand: false,
|
vexpand: false,
|
||||||
className: "event-top-padding",
|
className: 'event-top-padding',
|
||||||
}),
|
}),
|
||||||
PopupRevealer(name, child, transition),
|
PopupRevealer(name, child, transition),
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
"top-center": () =>
|
'top-center': () =>
|
||||||
Widget.Box(
|
Widget.Box(
|
||||||
{},
|
{},
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
@@ -86,14 +89,14 @@ const Layout: LayoutFunction = (name: string, child: any, transition: Transition
|
|||||||
},
|
},
|
||||||
Padding(name, {
|
Padding(name, {
|
||||||
vexpand: false,
|
vexpand: false,
|
||||||
className: "event-top-padding",
|
className: 'event-top-padding',
|
||||||
}),
|
}),
|
||||||
PopupRevealer(name, child, transition),
|
PopupRevealer(name, child, transition),
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
),
|
),
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
),
|
),
|
||||||
"top-left": () =>
|
'top-left': () =>
|
||||||
Widget.Box(
|
Widget.Box(
|
||||||
{},
|
{},
|
||||||
Widget.Box(
|
Widget.Box(
|
||||||
@@ -103,14 +106,14 @@ const Layout: LayoutFunction = (name: string, child: any, transition: Transition
|
|||||||
},
|
},
|
||||||
Padding(name, {
|
Padding(name, {
|
||||||
vexpand: false,
|
vexpand: false,
|
||||||
className: "event-top-padding",
|
className: 'event-top-padding',
|
||||||
}),
|
}),
|
||||||
PopupRevealer(name, child, transition),
|
PopupRevealer(name, child, transition),
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
),
|
),
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
),
|
),
|
||||||
"bottom-left": () =>
|
'bottom-left': () =>
|
||||||
Widget.Box(
|
Widget.Box(
|
||||||
{},
|
{},
|
||||||
Widget.Box(
|
Widget.Box(
|
||||||
@@ -123,7 +126,7 @@ const Layout: LayoutFunction = (name: string, child: any, transition: Transition
|
|||||||
),
|
),
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
),
|
),
|
||||||
"bottom-center": () =>
|
'bottom-center': () =>
|
||||||
Widget.Box(
|
Widget.Box(
|
||||||
{},
|
{},
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
@@ -137,7 +140,7 @@ const Layout: LayoutFunction = (name: string, child: any, transition: Transition
|
|||||||
),
|
),
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
),
|
),
|
||||||
"bottom-right": () =>
|
'bottom-right': () =>
|
||||||
Widget.Box(
|
Widget.Box(
|
||||||
{},
|
{},
|
||||||
Padding(name, {} as Opts),
|
Padding(name, {} as Opts),
|
||||||
@@ -159,25 +162,25 @@ const isValidLayout = (layout: string): layout is Layouts => {
|
|||||||
export default ({
|
export default ({
|
||||||
name,
|
name,
|
||||||
child,
|
child,
|
||||||
layout = "center",
|
layout = 'center',
|
||||||
transition,
|
transition,
|
||||||
exclusivity = "ignore" as Exclusivity,
|
exclusivity = 'ignore' as Exclusivity,
|
||||||
...props
|
...props
|
||||||
}: PopupWindowProps) => {
|
}: PopupWindowProps): Window<Child, Attribute> => {
|
||||||
const layoutFn = isValidLayout(layout) ? layout : "center";
|
const layoutFn = isValidLayout(layout) ? layout : 'center';
|
||||||
|
|
||||||
const layoutWidget = Layout(name, child, transition)[layoutFn]();
|
const layoutWidget = Layout(name, child, transition)[layoutFn]();
|
||||||
|
|
||||||
return Widget.Window({
|
return Widget.Window({
|
||||||
name,
|
name,
|
||||||
class_names: [name, "popup-window"],
|
class_names: [name, 'popup-window'],
|
||||||
setup: (w) => w.keybind("Escape", () => App.closeWindow(name)),
|
setup: (w) => w.keybind('Escape', () => App.closeWindow(name)),
|
||||||
visible: false,
|
visible: false,
|
||||||
keymode: "on-demand",
|
keymode: 'on-demand',
|
||||||
exclusivity,
|
exclusivity,
|
||||||
layer: "top",
|
layer: 'top',
|
||||||
anchor: ["top", "bottom", "right", "left"],
|
anchor: ['top', 'bottom', 'right', 'left'],
|
||||||
child: layoutWidget,
|
child: layoutWidget,
|
||||||
...props,
|
...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';
|
import { getIcon } from '../utils.js';
|
||||||
|
|
||||||
const renderActiveInput = () => {
|
const renderActiveInput = (): BarBoxChild => {
|
||||||
return [
|
return [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-slider-container input",
|
class_name: 'menu-slider-container input',
|
||||||
children: [
|
children: [
|
||||||
Widget.Button({
|
Widget.Button({
|
||||||
vexpand: false,
|
vexpand: false,
|
||||||
vpack: "end",
|
vpack: 'end',
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
self.hook(audio, () => {
|
self.hook(audio, () => {
|
||||||
const mic = audio.microphone;
|
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);
|
return (self.class_name = className);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
on_primary_click: () =>
|
on_primary_click: () => (audio.microphone.is_muted = !audio.microphone.is_muted),
|
||||||
(audio.microphone.is_muted = !audio.microphone.is_muted),
|
|
||||||
child: Widget.Icon({
|
child: Widget.Icon({
|
||||||
class_name: "menu-active-icon input",
|
class_name: 'menu-active-icon input',
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
self.hook(audio, () => {
|
self.hook(audio, () => {
|
||||||
self.icon = getIcon(
|
const isMicMuted =
|
||||||
audio.microphone.volume,
|
audio.microphone.is_muted !== null ? audio.microphone.is_muted : true;
|
||||||
audio.microphone.is_muted,
|
|
||||||
)["mic"];
|
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,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
class_name: "menu-active input",
|
class_name: 'menu-active input',
|
||||||
hpack: "start",
|
hpack: 'start',
|
||||||
truncate: "end",
|
truncate: 'end',
|
||||||
wrap: true,
|
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({
|
Widget.Slider({
|
||||||
value: audio.microphone.bind("volume").as((v) => v),
|
value: audio.microphone.bind('volume').as((v) => v),
|
||||||
class_name: "menu-active-slider menu-slider inputs",
|
class_name: 'menu-active-slider menu-slider inputs',
|
||||||
draw_value: false,
|
draw_value: false,
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
min: 0,
|
min: 0,
|
||||||
@@ -52,11 +59,9 @@ const renderActiveInput = () => {
|
|||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
class_name: "menu-active-percentage input",
|
class_name: 'menu-active-percentage input',
|
||||||
vpack: "end",
|
vpack: 'end',
|
||||||
label: audio.microphone
|
label: audio.microphone.bind('volume').as((v) => `${Math.round(v * 100)}%`),
|
||||||
.bind("volume")
|
|
||||||
.as((v) => `${Math.round(v * 100)}%`),
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,31 +1,29 @@
|
|||||||
const audio = await Service.import("audio");
|
const audio = await Service.import('audio');
|
||||||
import { getIcon } from "../utils.js";
|
import { BarBoxChild } from 'lib/types/bar.js';
|
||||||
|
import { getIcon } from '../utils.js';
|
||||||
|
|
||||||
const renderActivePlayback = () => {
|
const renderActivePlayback = (): BarBoxChild => {
|
||||||
return [
|
return [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-slider-container playback",
|
class_name: 'menu-slider-container playback',
|
||||||
children: [
|
children: [
|
||||||
Widget.Button({
|
Widget.Button({
|
||||||
vexpand: false,
|
vexpand: false,
|
||||||
vpack: "end",
|
vpack: 'end',
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
self.hook(audio, () => {
|
self.hook(audio, () => {
|
||||||
const spkr = audio.speaker;
|
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);
|
return (self.class_name = className);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
on_primary_click: () =>
|
on_primary_click: () => (audio.speaker.is_muted = !audio.speaker.is_muted),
|
||||||
(audio.speaker.is_muted = !audio.speaker.is_muted),
|
|
||||||
child: Widget.Icon({
|
child: Widget.Icon({
|
||||||
class_name: "menu-active-icon playback",
|
class_name: 'menu-active-icon playback',
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
self.hook(audio, () => {
|
self.hook(audio, () => {
|
||||||
self.icon = getIcon(
|
const isSpeakerMuted = audio.speaker.is_muted !== null ? audio.speaker.is_muted : true;
|
||||||
audio.speaker.volume,
|
self.icon = getIcon(audio.speaker.volume, isSpeakerMuted)['spkr'];
|
||||||
audio.speaker.is_muted,
|
|
||||||
)["spkr"];
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -34,16 +32,16 @@ const renderActivePlayback = () => {
|
|||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
class_name: "menu-active playback",
|
class_name: 'menu-active playback',
|
||||||
hpack: "start",
|
hpack: 'start',
|
||||||
truncate: "end",
|
truncate: 'end',
|
||||||
expand: true,
|
expand: true,
|
||||||
wrap: true,
|
wrap: true,
|
||||||
label: audio.bind("speaker").as((v) => v.description || ""),
|
label: audio.bind('speaker').as((v) => v.description || ''),
|
||||||
}),
|
}),
|
||||||
Widget.Slider({
|
Widget.Slider({
|
||||||
value: audio["speaker"].bind("volume"),
|
value: audio['speaker'].bind('volume'),
|
||||||
class_name: "menu-active-slider menu-slider playback",
|
class_name: 'menu-active-slider menu-slider playback',
|
||||||
draw_value: false,
|
draw_value: false,
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
min: 0,
|
min: 0,
|
||||||
@@ -53,11 +51,9 @@ const renderActivePlayback = () => {
|
|||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
vpack: "end",
|
vpack: 'end',
|
||||||
class_name: "menu-active-percentage playback",
|
class_name: 'menu-active-percentage playback',
|
||||||
label: audio.speaker
|
label: audio.speaker.bind('volume').as((v) => `${Math.round(v * 100)}%`),
|
||||||
.bind("volume")
|
|
||||||
.as((v) => `${Math.round(v * 100)}%`),
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,32 +1,33 @@
|
|||||||
import { renderActiveInput } from "./SelectedInput.js";
|
import { BarBoxChild } from 'lib/types/bar.js';
|
||||||
import { renderActivePlayback } from "./SelectedPlayback.js";
|
import { renderActiveInput } from './SelectedInput.js';
|
||||||
|
import { renderActivePlayback } from './SelectedPlayback.js';
|
||||||
|
|
||||||
const activeDevices = () => {
|
const activeDevices = (): BarBoxChild => {
|
||||||
return Widget.Box({
|
return Widget.Box({
|
||||||
class_name: "menu-section-container volume",
|
class_name: 'menu-section-container volume',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-label-container volume selected",
|
class_name: 'menu-label-container volume selected',
|
||||||
hpack: "fill",
|
hpack: 'fill',
|
||||||
child: Widget.Label({
|
child: Widget.Label({
|
||||||
class_name: "menu-label audio volume",
|
class_name: 'menu-label audio volume',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
hpack: "start",
|
hpack: 'start',
|
||||||
label: "Volume",
|
label: 'Volume',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-items-section selected",
|
class_name: 'menu-items-section selected',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-active-container playback",
|
class_name: 'menu-active-container playback',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: renderActivePlayback(),
|
children: renderActivePlayback(),
|
||||||
}),
|
}),
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-active-container input",
|
class_name: 'menu-active-container input',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: renderActiveInput(),
|
children: renderActiveInput(),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
const audio = await Service.import("audio");
|
const audio = await Service.import('audio');
|
||||||
import { Stream } from "types/service/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) {
|
if (inputDevices.length === 0) {
|
||||||
return [
|
return [
|
||||||
Widget.Button({
|
Widget.Button({
|
||||||
@@ -9,11 +10,11 @@ const renderInputDevices = (inputDevices: Stream[]) => {
|
|||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
children: [
|
children: [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
hpack: "start",
|
hpack: 'start',
|
||||||
children: [
|
children: [
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
class_name: "menu-button-name input",
|
class_name: 'menu-button-name input',
|
||||||
label: "No input devices found...",
|
label: 'No input devices found...',
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@@ -29,28 +30,28 @@ const renderInputDevices = (inputDevices: Stream[]) => {
|
|||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
children: [
|
children: [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
hpack: "start",
|
hpack: 'start',
|
||||||
children: [
|
children: [
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
wrap: true,
|
wrap: true,
|
||||||
class_name: audio.microphone
|
class_name: audio.microphone
|
||||||
.bind("description")
|
.bind('description')
|
||||||
.as((v) =>
|
.as((v) =>
|
||||||
device.description === v
|
device.description === v
|
||||||
? "menu-button-icon active input txt-icon"
|
? 'menu-button-icon active input txt-icon'
|
||||||
: "menu-button-icon input txt-icon",
|
: 'menu-button-icon input txt-icon',
|
||||||
),
|
),
|
||||||
label: "",
|
label: '',
|
||||||
}),
|
}),
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
truncate: "end",
|
truncate: 'end',
|
||||||
wrap: true,
|
wrap: true,
|
||||||
class_name: audio.microphone
|
class_name: audio.microphone
|
||||||
.bind("description")
|
.bind('description')
|
||||||
.as((v) =>
|
.as((v) =>
|
||||||
device.description === v
|
device.description === v
|
||||||
? "menu-button-name active input"
|
? 'menu-button-name active input'
|
||||||
: "menu-button-name input",
|
: 'menu-button-name input',
|
||||||
),
|
),
|
||||||
label: device.description,
|
label: device.description,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
const audio = await Service.import("audio");
|
const audio = await Service.import('audio');
|
||||||
import { Stream } from "types/service/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) => {
|
return playbackDevices.map((device) => {
|
||||||
if (device.description === "Dummy Output") {
|
if (device.description === 'Dummy Output') {
|
||||||
return Widget.Box({
|
return Widget.Box({
|
||||||
class_name: "menu-unfound-button playback",
|
class_name: 'menu-unfound-button playback',
|
||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
children: [
|
children: [
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
class_name: "menu-button-name playback",
|
class_name: 'menu-button-name playback',
|
||||||
label: "No playback devices found...",
|
label: 'No playback devices found...',
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@@ -22,29 +23,29 @@ const renderPlaybacks = (playbackDevices: Stream[]) => {
|
|||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
children: [
|
children: [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
hpack: "start",
|
hpack: 'start',
|
||||||
children: [
|
children: [
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
truncate: "end",
|
truncate: 'end',
|
||||||
wrap: true,
|
wrap: true,
|
||||||
class_name: audio.speaker
|
class_name: audio.speaker
|
||||||
.bind("description")
|
.bind('description')
|
||||||
.as((v) =>
|
.as((v) =>
|
||||||
device.description === v
|
device.description === v
|
||||||
? "menu-button-icon active playback txt-icon"
|
? 'menu-button-icon active playback txt-icon'
|
||||||
: "menu-button-icon playback txt-icon",
|
: 'menu-button-icon playback txt-icon',
|
||||||
),
|
),
|
||||||
label: "",
|
label: '',
|
||||||
}),
|
}),
|
||||||
Widget.Label({
|
Widget.Label({
|
||||||
truncate: "end",
|
truncate: 'end',
|
||||||
wrap: true,
|
wrap: true,
|
||||||
class_name: audio.speaker
|
class_name: audio.speaker
|
||||||
.bind("description")
|
.bind('description')
|
||||||
.as((v) =>
|
.as((v) =>
|
||||||
device.description === v
|
device.description === v
|
||||||
? "menu-button-name active playback"
|
? 'menu-button-name active playback'
|
||||||
: "menu-button-name playback",
|
: 'menu-button-name playback',
|
||||||
),
|
),
|
||||||
label: device.description,
|
label: device.description,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,66 +1,63 @@
|
|||||||
const audio = await Service.import("audio");
|
const audio = await Service.import('audio');
|
||||||
import { renderInputDevices } from "./InputDevices.js";
|
import { BoxWidget } from 'lib/types/widget.js';
|
||||||
import { renderPlaybacks } from "./PlaybackDevices.js";
|
import { renderInputDevices } from './InputDevices.js';
|
||||||
|
import { renderPlaybacks } from './PlaybackDevices.js';
|
||||||
|
|
||||||
const availableDevices = () => {
|
const availableDevices = (): BoxWidget => {
|
||||||
return Widget.Box({
|
return Widget.Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-section-container playback",
|
class_name: 'menu-section-container playback',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-label-container playback",
|
class_name: 'menu-label-container playback',
|
||||||
hpack: "fill",
|
hpack: 'fill',
|
||||||
child: Widget.Label({
|
child: Widget.Label({
|
||||||
class_name: "menu-label audio playback",
|
class_name: 'menu-label audio playback',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
hpack: "start",
|
hpack: 'start',
|
||||||
label: "Playback Devices",
|
label: 'Playback Devices',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-items-section playback",
|
class_name: 'menu-items-section playback',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-container playback",
|
class_name: 'menu-container playback',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: audio
|
children: audio.bind('speakers').as((v) => renderPlaybacks(v)),
|
||||||
.bind("speakers")
|
|
||||||
.as((v) => renderPlaybacks(v)),
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-label-container input",
|
class_name: 'menu-label-container input',
|
||||||
hpack: "fill",
|
hpack: 'fill',
|
||||||
child: Widget.Label({
|
child: Widget.Label({
|
||||||
class_name: "menu-label audio input",
|
class_name: 'menu-label audio input',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
hpack: "start",
|
hpack: 'start',
|
||||||
label: "Input Devices",
|
label: 'Input Devices',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-items-section input",
|
class_name: 'menu-items-section input',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "menu-container input",
|
class_name: 'menu-container input',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: audio
|
children: audio.bind('microphones').as((v) => renderInputDevices(v)),
|
||||||
.bind("microphones")
|
|
||||||
.as((v) => renderInputDevices(v)),
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,24 +1,23 @@
|
|||||||
import DropdownMenu from "../DropdownMenu.js";
|
import Window from 'types/widgets/window.js';
|
||||||
import { activeDevices } from "./active/index.js";
|
import DropdownMenu from '../DropdownMenu.js';
|
||||||
import { availableDevices } from "./available/index.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({
|
return DropdownMenu({
|
||||||
name: "audiomenu",
|
name: 'audiomenu',
|
||||||
transition: "crossfade",
|
transition: 'crossfade',
|
||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
class_name: "menu-items audio",
|
class_name: 'menu-items audio',
|
||||||
hpack: "fill",
|
hpack: 'fill',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
child: Widget.Box({
|
child: Widget.Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
hpack: "fill",
|
hpack: 'fill',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
class_name: "menu-items-container audio",
|
class_name: 'menu-items-container audio',
|
||||||
children: [
|
children: [activeDevices(), availableDevices()],
|
||||||
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